glib/tsrc/BC/tests/threadpool-test.c
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 /* Portion Copyright © 2008-09 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.*/
       
     2 #undef G_DISABLE_ASSERT
       
     3 #undef G_LOG_DOMAIN
       
     4 
       
     5 #include <config.h>
       
     6 
       
     7 #include <glib.h>
       
     8 #include <stdio.h>
       
     9 
       
    10 #ifdef SYMBIAN
       
    11 #include <glib_global.h>
       
    12 #include "mrt2_glib2_test.h"
       
    13 #endif /*SYMBIAN*/
       
    14 
       
    15 #define DEBUG_MSG(x)  
       
    16 /* #define DEBUG_MSG(args) g_printerr args ; g_printerr ("\n");  */
       
    17 
       
    18 #define WAIT                5    /* seconds */
       
    19 #define MAX_THREADS         10
       
    20 
       
    21 /* if > 0 the test will run continously (since the test ends when
       
    22  * thread count is 0), if -1 it means no limit to unused threads  
       
    23  * if 0 then no unused threads are possible */
       
    24 #define MAX_UNUSED_THREADS -1    
       
    25 
       
    26 G_LOCK_DEFINE_STATIC (thread_counter_pools);
       
    27 
       
    28 static gulong abs_thread_counter = 0;
       
    29 static gulong running_thread_counter = 0;
       
    30 static gulong leftover_task_counter = 0;
       
    31 
       
    32 G_LOCK_DEFINE_STATIC (last_thread);
       
    33 
       
    34 static guint last_thread_id = 0;
       
    35 
       
    36 G_LOCK_DEFINE_STATIC (thread_counter_sort);
       
    37 
       
    38 static gulong sort_thread_counter = 0;
       
    39 
       
    40 static GThreadPool *idle_pool = NULL;
       
    41 
       
    42 static GMainLoop *main_loop = NULL;
       
    43 
       
    44 static void
       
    45 test_thread_functions (void)
       
    46 {
       
    47   gint max_unused_threads;
       
    48   guint max_idle_time;
       
    49 
       
    50 
       
    51 
       
    52   /* This function attempts to call functions which don't need a
       
    53    * threadpool to operate to make sure no uninitialised pointers
       
    54    * accessed and no errors occur.
       
    55    */
       
    56 
       
    57   max_unused_threads = 3;
       
    58 
       
    59   DEBUG_MSG (("[funcs] Setting max unused threads to %d", 
       
    60 	      max_unused_threads));
       
    61   g_thread_pool_set_max_unused_threads (max_unused_threads);
       
    62 
       
    63   DEBUG_MSG (("[funcs] Getting max unused threads = %d", 
       
    64 	     g_thread_pool_get_max_unused_threads ()));
       
    65   g_assert (g_thread_pool_get_max_unused_threads() == max_unused_threads);
       
    66 
       
    67   DEBUG_MSG (("[funcs] Getting num unused threads = %d", 
       
    68 	     g_thread_pool_get_num_unused_threads ()));
       
    69   g_assert (g_thread_pool_get_num_unused_threads () == 0);
       
    70 
       
    71   DEBUG_MSG (("[funcs] Stopping unused threads"));
       
    72   g_thread_pool_stop_unused_threads ();
       
    73 
       
    74   max_idle_time = 10 * G_USEC_PER_SEC;
       
    75 
       
    76   DEBUG_MSG (("[funcs] Setting max idle time to %d", 
       
    77 	      max_idle_time));
       
    78   g_thread_pool_set_max_idle_time (max_idle_time);
       
    79 
       
    80   DEBUG_MSG (("[funcs] Getting max idle time = %d", 
       
    81 	     g_thread_pool_get_max_idle_time ()));
       
    82   g_assert (g_thread_pool_get_max_idle_time () == max_idle_time);
       
    83 
       
    84   DEBUG_MSG (("[funcs] Setting max idle time to 0"));
       
    85   g_thread_pool_set_max_idle_time (0);
       
    86 
       
    87   DEBUG_MSG (("[funcs] Getting max idle time = %d", 
       
    88 	     g_thread_pool_get_max_idle_time ()));
       
    89   g_assert (g_thread_pool_get_max_idle_time () == 0);
       
    90 }
       
    91 
       
    92 static void
       
    93 test_count_threads_foreach (GThread *thread, 
       
    94 			    guint   *count)
       
    95 {
       
    96    ++*count;
       
    97 }
       
    98 
       
    99 static guint
       
   100 test_count_threads (void)
       
   101 {
       
   102   guint count = 0;
       
   103   
       
   104   g_thread_foreach ((GFunc) test_count_threads_foreach, &count);
       
   105   
       
   106   /* Exclude main thread */
       
   107   return count - 1;
       
   108 }
       
   109 
       
   110 static void
       
   111 test_thread_stop_unused (void)
       
   112 { 
       
   113    GThreadPool *pool;
       
   114    guint i;
       
   115    guint limit = 100;
       
   116    
       
   117    /* Spawn a few threads. */
       
   118    g_thread_pool_set_max_unused_threads (-1);
       
   119    pool = g_thread_pool_new ((GFunc) g_usleep, NULL, -1, FALSE, NULL);
       
   120    
       
   121    for (i = 0; i < limit; i++)
       
   122      g_thread_pool_push (pool, GUINT_TO_POINTER (1000), NULL);
       
   123 
       
   124    DEBUG_MSG (("[unused] ===> pushed %d threads onto the idle pool",
       
   125 	       limit));
       
   126    
       
   127    /* Wait for the threads to migrate. */
       
   128    g_usleep (G_USEC_PER_SEC); 
       
   129 
       
   130    DEBUG_MSG (("[unused] current threads %d",
       
   131 	       test_count_threads()));
       
   132 
       
   133    DEBUG_MSG (("[unused] stopping unused threads"));
       
   134    g_thread_pool_stop_unused_threads ();
       
   135 
       
   136    DEBUG_MSG (("[unused] waiting ONE second for threads to die"));
       
   137 
       
   138    /* Some time for threads to die. */
       
   139    g_usleep (G_USEC_PER_SEC); 
       
   140    
       
   141    DEBUG_MSG (("[unused] stopped idle threads, %d remain, %d threads still exist",
       
   142 	       g_thread_pool_get_num_unused_threads (), 
       
   143 	       test_count_threads ()));
       
   144    
       
   145    g_assert (g_thread_pool_get_num_unused_threads () == test_count_threads ());
       
   146    g_assert (g_thread_pool_get_num_unused_threads () == 0);
       
   147    
       
   148    g_thread_pool_set_max_unused_threads (MAX_THREADS);
       
   149 
       
   150    DEBUG_MSG (("[unused] cleaning up thread pool"));
       
   151    g_thread_pool_free (pool, FALSE, TRUE);
       
   152 }
       
   153 
       
   154 static void
       
   155 test_thread_pools_entry_func (gpointer data, gpointer user_data)
       
   156 {
       
   157   guint id = 0;
       
   158 
       
   159   id = GPOINTER_TO_UINT (data);
       
   160 
       
   161   DEBUG_MSG (("[pool] ---> [%3.3d] entered thread.", id));
       
   162 
       
   163   G_LOCK (thread_counter_pools);
       
   164   abs_thread_counter++;
       
   165   running_thread_counter++;
       
   166   G_UNLOCK (thread_counter_pools);
       
   167 
       
   168   g_usleep (g_random_int_range (0, 4000));
       
   169 
       
   170   G_LOCK (thread_counter_pools);
       
   171   running_thread_counter--;
       
   172   leftover_task_counter--;
       
   173 
       
   174   DEBUG_MSG (("[pool] ---> [%3.3d] exiting thread (abs count:%ld, "
       
   175 	      "running count:%ld, left over:%ld)", 
       
   176 	      id, abs_thread_counter, 
       
   177 	      running_thread_counter, leftover_task_counter)); 
       
   178   G_UNLOCK (thread_counter_pools);
       
   179 }
       
   180 
       
   181 static void
       
   182 test_thread_pools (void)
       
   183 {
       
   184   GThreadPool *pool1, *pool2, *pool3;
       
   185   guint runs;
       
   186   guint i;
       
   187   
       
   188   pool1 = g_thread_pool_new ((GFunc)test_thread_pools_entry_func, NULL, 3, FALSE, NULL);
       
   189   pool2 = g_thread_pool_new ((GFunc)test_thread_pools_entry_func, NULL, 5, TRUE, NULL);
       
   190   pool3 = g_thread_pool_new ((GFunc)test_thread_pools_entry_func, NULL, 7, TRUE, NULL);
       
   191 
       
   192   runs = 300;
       
   193   for (i = 0; i < runs; i++)
       
   194     {
       
   195       g_thread_pool_push (pool1, GUINT_TO_POINTER (i + 1), NULL);
       
   196       g_thread_pool_push (pool2, GUINT_TO_POINTER (i + 1), NULL);
       
   197       g_thread_pool_push (pool3, GUINT_TO_POINTER (i + 1), NULL);
       
   198       leftover_task_counter += 3;
       
   199     } 
       
   200   
       
   201   g_thread_pool_free (pool1, TRUE, TRUE);
       
   202   g_thread_pool_free (pool2, FALSE, TRUE);
       
   203   g_thread_pool_free (pool3, FALSE, TRUE);
       
   204 
       
   205   g_assert (runs * 3 == abs_thread_counter + leftover_task_counter);
       
   206   g_assert (running_thread_counter == 0);  
       
   207 }
       
   208 
       
   209 static gint
       
   210 test_thread_sort_compare_func (gconstpointer a, gconstpointer b, gpointer user_data)
       
   211 {
       
   212   guint32 id1, id2;
       
   213 
       
   214   id1 = GPOINTER_TO_UINT (a);
       
   215   id2 = GPOINTER_TO_UINT (b);
       
   216 
       
   217   return (id1 > id2 ? +1 : id1 == id2 ? 0 : -1); 
       
   218 }
       
   219 
       
   220 static void
       
   221 test_thread_sort_entry_func (gpointer data, gpointer user_data)
       
   222 {
       
   223   guint thread_id;
       
   224   gboolean is_sorted;
       
   225 
       
   226   G_LOCK (last_thread);
       
   227 
       
   228   thread_id = GPOINTER_TO_UINT (data);
       
   229   is_sorted = GPOINTER_TO_INT (user_data);
       
   230 
       
   231   DEBUG_MSG (("%s ---> entered thread:%2.2d, last thread:%2.2d", 
       
   232 	      is_sorted ? "[  sorted]" : "[unsorted]", 
       
   233 	      thread_id, last_thread_id));
       
   234 
       
   235   if (is_sorted) {
       
   236     static gboolean last_failed = FALSE;
       
   237 
       
   238     if (last_thread_id > thread_id) {
       
   239       if (last_failed) {
       
   240 	g_assert (last_thread_id <= thread_id);  
       
   241       }
       
   242 
       
   243       /* Here we remember one fail and if it concurrently fails, it
       
   244        * can not be sorted. the last thread id might be < this thread
       
   245        * id if something is added to the queue since threads were
       
   246        * created  
       
   247        */
       
   248       last_failed = TRUE;
       
   249     } else {
       
   250       last_failed = FALSE;
       
   251     }
       
   252 
       
   253     last_thread_id = thread_id;
       
   254   }
       
   255 
       
   256   G_UNLOCK (last_thread);
       
   257 
       
   258   g_usleep (WAIT * 1000);
       
   259 }
       
   260 
       
   261 static void
       
   262 test_thread_sort (gboolean sort)
       
   263 {
       
   264   GThreadPool *pool;
       
   265   guint limit;
       
   266   guint max_threads;
       
   267   gint i;
       
   268 
       
   269   limit = MAX_THREADS * 10;
       
   270 
       
   271   if (sort) {
       
   272     max_threads = 1;
       
   273   } else {
       
   274     max_threads = MAX_THREADS;
       
   275   }
       
   276 
       
   277   /* It is important that we only have a maximum of 1 thread for this
       
   278    * test since the results can not be guranteed to be sorted if > 1.
       
   279    * 
       
   280    * Threads are scheduled by the operating system and are executed at
       
   281    * random. It cannot be assumed that threads are executed in the
       
   282    * order they are created. This was discussed in bug #334943.
       
   283    */
       
   284   
       
   285   pool = g_thread_pool_new (test_thread_sort_entry_func, 
       
   286 			    GINT_TO_POINTER (sort), 
       
   287 			    max_threads, 
       
   288 			    FALSE,
       
   289 			    NULL);
       
   290 
       
   291   g_thread_pool_set_max_unused_threads (MAX_UNUSED_THREADS); 
       
   292 
       
   293   if (sort) {
       
   294     g_thread_pool_set_sort_function (pool, 
       
   295 				     test_thread_sort_compare_func,
       
   296 				     GUINT_TO_POINTER (69));
       
   297   }
       
   298   
       
   299   for (i = 0; i < limit; i++) {
       
   300     guint id;
       
   301 
       
   302     id = g_random_int_range (1, limit) + 1;
       
   303     g_thread_pool_push (pool, GUINT_TO_POINTER (id), NULL);
       
   304     DEBUG_MSG (("%s ===> pushed new thread with id:%d, number "
       
   305 		"of threads:%d, unprocessed:%d",
       
   306 		sort ? "[  sorted]" : "[unsorted]", 
       
   307 		id, 
       
   308 		g_thread_pool_get_num_threads (pool),
       
   309 		g_thread_pool_unprocessed (pool)));
       
   310   }
       
   311 
       
   312   g_assert (g_thread_pool_get_max_threads (pool) == max_threads);
       
   313   g_assert (g_thread_pool_get_num_threads (pool) == g_thread_pool_get_max_threads (pool));
       
   314 }
       
   315 
       
   316 static void
       
   317 test_thread_idle_time_entry_func (gpointer data, gpointer user_data)
       
   318 {
       
   319   guint thread_id;
       
   320   
       
   321   thread_id = GPOINTER_TO_UINT (data);
       
   322 
       
   323   DEBUG_MSG (("[idle] ---> entered thread:%2.2d", thread_id));
       
   324 
       
   325   g_usleep (WAIT * 1000);
       
   326 
       
   327   DEBUG_MSG (("[idle] <--- exiting thread:%2.2d", thread_id));
       
   328 }
       
   329 
       
   330 static gboolean 
       
   331 test_thread_idle_timeout (gpointer data)
       
   332 {
       
   333   guint interval;
       
   334   gint i;
       
   335 
       
   336   interval = GPOINTER_TO_UINT (data);
       
   337   
       
   338   for (i = 0; i < 2; i++) {
       
   339     g_thread_pool_push (idle_pool, GUINT_TO_POINTER (100 + i), NULL); 
       
   340     DEBUG_MSG (("[idle] ===> pushed new thread with id:%d, number "
       
   341 		"of threads:%d, unprocessed:%d",
       
   342 		100 + i, 
       
   343 		g_thread_pool_get_num_threads (idle_pool),
       
   344 		g_thread_pool_unprocessed (idle_pool)));
       
   345   }
       
   346   
       
   347 
       
   348   return FALSE;
       
   349 }
       
   350 
       
   351 static void
       
   352 test_thread_idle_time ()
       
   353 {
       
   354   guint limit = 50;
       
   355   guint interval = 10000;
       
   356   gint i;
       
   357 
       
   358   idle_pool = g_thread_pool_new (test_thread_idle_time_entry_func, 
       
   359 				 NULL, 
       
   360 				 MAX_THREADS,
       
   361 				 FALSE,
       
   362 				 NULL);
       
   363 
       
   364   g_thread_pool_set_max_unused_threads (MAX_UNUSED_THREADS);  
       
   365   g_thread_pool_set_max_idle_time (interval); 
       
   366 
       
   367   g_assert (g_thread_pool_get_max_unused_threads () == MAX_UNUSED_THREADS);   
       
   368   g_assert (g_thread_pool_get_max_idle_time () == interval);
       
   369 
       
   370   for (i = 0; i < limit; i++) {
       
   371     g_thread_pool_push (idle_pool, GUINT_TO_POINTER (i + 1), NULL); 
       
   372     DEBUG_MSG (("[idle] ===> pushed new thread with id:%d, "
       
   373 		"number of threads:%d, unprocessed:%d",
       
   374 		i,
       
   375 		g_thread_pool_get_num_threads (idle_pool),
       
   376 		g_thread_pool_unprocessed (idle_pool)));
       
   377   }
       
   378 
       
   379   g_timeout_add ((interval - 1000),
       
   380 		 test_thread_idle_timeout, 
       
   381 		 GUINT_TO_POINTER (interval));
       
   382 }
       
   383 
       
   384 static gboolean
       
   385 test_check_start_and_stop (gpointer user_data)
       
   386 {
       
   387   static guint test_number = 0;
       
   388   static gboolean run_next = FALSE;
       
   389   gboolean continue_timeout = TRUE;
       
   390   gboolean quit = TRUE;
       
   391 
       
   392   if (test_number == 0) {
       
   393     run_next = TRUE;
       
   394     DEBUG_MSG (("***** RUNNING TEST %2.2d *****", test_number)); 
       
   395   }
       
   396    
       
   397   if (run_next) {
       
   398     test_number++;
       
   399 
       
   400     switch (test_number) {
       
   401     case 1:
       
   402       test_thread_functions ();
       
   403       break;
       
   404     case 2:
       
   405       test_thread_stop_unused ();
       
   406       break;
       
   407     case 3:
       
   408       test_thread_pools ();   
       
   409       break;
       
   410     case 4:
       
   411       test_thread_sort (FALSE);  
       
   412       break;
       
   413     case 5:
       
   414       test_thread_sort (TRUE);  
       
   415       break;
       
   416     case 6:
       
   417       test_thread_idle_time ();   
       
   418       break;
       
   419     default:
       
   420       DEBUG_MSG (("***** END OF TESTS *****")); 
       
   421       g_main_loop_quit (main_loop);
       
   422       continue_timeout = FALSE;
       
   423       break;
       
   424     }
       
   425 
       
   426     run_next = FALSE;
       
   427     return TRUE;
       
   428   }
       
   429 
       
   430   if (test_number == 3) {
       
   431     G_LOCK (thread_counter_pools); 
       
   432     quit &= running_thread_counter <= 0;
       
   433     DEBUG_MSG (("***** POOL RUNNING THREAD COUNT:%ld", 
       
   434 		running_thread_counter)); 
       
   435     G_UNLOCK (thread_counter_pools); 
       
   436   }
       
   437 
       
   438   if (test_number == 4 || test_number == 5) {
       
   439     G_LOCK (thread_counter_sort);
       
   440     quit &= sort_thread_counter <= 0;
       
   441     DEBUG_MSG (("***** POOL SORT THREAD COUNT:%ld", 
       
   442 		sort_thread_counter)); 
       
   443     G_UNLOCK (thread_counter_sort); 
       
   444   }
       
   445 
       
   446   if (test_number == 6) {
       
   447     guint idle;
       
   448 
       
   449     idle = g_thread_pool_get_num_unused_threads ();
       
   450     quit &= idle < 1;
       
   451     DEBUG_MSG (("***** POOL IDLE THREAD COUNT:%d, UNPROCESSED JOBS:%d",
       
   452 		idle, g_thread_pool_unprocessed (idle_pool)));
       
   453   }    
       
   454 
       
   455   if (quit) {
       
   456     run_next = TRUE;
       
   457   }
       
   458 
       
   459   return continue_timeout;
       
   460 }
       
   461 
       
   462 int 
       
   463 main (int argc, char *argv[])
       
   464 {
       
   465   /* Only run the test, if threads are enabled and a default thread
       
   466      implementation is available */
       
   467   #ifdef SYMBIAN
       
   468   guint g_thread_pool_unprocessed_op = -1;
       
   469   guint res;
       
   470   #endif //SYMBIAN
       
   471 
       
   472 #if defined(G_THREADS_ENABLED) && ! defined(G_THREADS_IMPL_NONE)
       
   473   g_thread_init (NULL);
       
   474 
       
   475   DEBUG_MSG (("Starting... (in one second)"));
       
   476   g_timeout_add (1000, test_check_start_and_stop, NULL); 
       
   477   
       
   478   main_loop = g_main_loop_new (NULL, FALSE);
       
   479   g_main_loop_run (main_loop);
       
   480 #endif
       
   481 #ifdef SYMBIAN
       
   482   testResultXml("threadpool-test");
       
   483 #endif /* EMULATOR */
       
   484 
       
   485   return 0;
       
   486 }