(root)/
glib-2.79.0/
gobject/
tests/
performance/
performance-threaded.c
       1  /* GObject - GLib Type, Object, Parameter and Signal Library
       2   * Copyright (C) 2009 Red Hat, Inc.
       3   *
       4   * This library is free software; you can redistribute it and/or
       5   * modify it under the terms of the GNU Lesser General Public
       6   * License as published by the Free Software Foundation; either
       7   * version 2.1 of the License, or (at your option) any later version.
       8   *
       9   * This library is distributed in the hope that it will be useful,
      10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12   * Lesser General Public License for more details.
      13   *
      14   * You should have received a copy of the GNU Lesser General
      15   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      16   */
      17  
      18  #include <math.h>
      19  #include <string.h>
      20  #include <glib-object.h>
      21  #include "../testcommon.h"
      22  
      23  #define DEFAULT_TEST_TIME 2 /* seconds */
      24  
      25  static GType
      26  simple_register_class (const char *name, GType parent, ...)
      27  {
      28    GInterfaceInfo interface_info = { NULL, NULL, NULL };
      29    va_list args;
      30    GType type, interface;
      31  
      32    va_start (args, parent);
      33    type = g_type_register_static_simple (parent, name, sizeof (GObjectClass),
      34        NULL, parent == G_TYPE_INTERFACE ? 0 : sizeof (GObject), NULL, 0);
      35    for (;;)
      36      {
      37        interface = va_arg (args, GType);
      38        if (interface == 0)
      39          break;
      40        g_type_add_interface_static (type, interface, &interface_info);
      41      }
      42    va_end (args);
      43  
      44    return type;
      45  }
      46  
      47  /* test emulating liststore behavior for interface lookups */
      48  
      49  static GType liststore;
      50  static GType liststore_interfaces[6];
      51  
      52  static gpointer 
      53  register_types (void)
      54  {
      55    static gsize inited = 0;
      56    if (g_once_init_enter (&inited))
      57      {
      58        liststore_interfaces[0] = simple_register_class ("GtkBuildable", G_TYPE_INTERFACE, 0);
      59        liststore_interfaces[1] = simple_register_class ("GtkTreeDragDest", G_TYPE_INTERFACE, 0);
      60        liststore_interfaces[2] = simple_register_class ("GtkTreeModel", G_TYPE_INTERFACE, 0);
      61        liststore_interfaces[3] = simple_register_class ("GtkTreeDragSource", G_TYPE_INTERFACE, 0);
      62        liststore_interfaces[4] = simple_register_class ("GtkTreeSortable", G_TYPE_INTERFACE, 0);
      63        liststore_interfaces[5] = simple_register_class ("UnrelatedInterface", G_TYPE_INTERFACE, 0);
      64  
      65        liststore = simple_register_class ("GtkListStore", G_TYPE_OBJECT, 
      66            liststore_interfaces[0], liststore_interfaces[1], liststore_interfaces[2],
      67            liststore_interfaces[3], liststore_interfaces[4], (GType) 0);
      68  
      69        g_once_init_leave (&inited, 1);
      70      }
      71    return NULL;
      72  }
      73  
      74  static void 
      75  liststore_is_a_run (gpointer data)
      76  {
      77    guint i;
      78  
      79    for (i = 0; i < 1000; i++)
      80      {
      81        g_assert (g_type_is_a (liststore, liststore_interfaces[0]));
      82        g_assert (g_type_is_a (liststore, liststore_interfaces[1]));
      83        g_assert (g_type_is_a (liststore, liststore_interfaces[2]));
      84        g_assert (g_type_is_a (liststore, liststore_interfaces[3]));
      85        g_assert (g_type_is_a (liststore, liststore_interfaces[4]));
      86        g_assert (!g_type_is_a (liststore, liststore_interfaces[5]));
      87      }
      88  }
      89  
      90  static gpointer
      91  liststore_get_class (void)
      92  {
      93    register_types ();
      94    return g_type_class_ref (liststore);
      95  }
      96  
      97  static void 
      98  liststore_interface_peek_run (gpointer klass)
      99  {
     100    guint i;
     101    gpointer iface;
     102  
     103    for (i = 0; i < 1000; i++)
     104      {
     105        iface = g_type_interface_peek (klass, liststore_interfaces[0]);
     106        g_assert (iface);
     107        iface = g_type_interface_peek (klass, liststore_interfaces[1]);
     108        g_assert (iface);
     109        iface = g_type_interface_peek (klass, liststore_interfaces[2]);
     110        g_assert (iface);
     111        iface = g_type_interface_peek (klass, liststore_interfaces[3]);
     112        g_assert (iface);
     113        iface = g_type_interface_peek (klass, liststore_interfaces[4]);
     114        g_assert (iface);
     115      }
     116  }
     117  
     118  static void 
     119  liststore_interface_peek_same_run (gpointer klass)
     120  {
     121    guint i;
     122    gpointer iface;
     123  
     124    for (i = 0; i < 1000; i++)
     125      {
     126        iface = g_type_interface_peek (klass, liststore_interfaces[0]);
     127        g_assert (iface);
     128        iface = g_type_interface_peek (klass, liststore_interfaces[0]);
     129        g_assert (iface);
     130        iface = g_type_interface_peek (klass, liststore_interfaces[0]);
     131        g_assert (iface);
     132        iface = g_type_interface_peek (klass, liststore_interfaces[0]);
     133        g_assert (iface);
     134        iface = g_type_interface_peek (klass, liststore_interfaces[0]);
     135        g_assert (iface);
     136      }
     137  }
     138  
     139  #if 0
     140  /* DUMB test doing nothing */
     141  
     142  static gpointer 
     143  no_setup (void)
     144  {
     145    return NULL;
     146  }
     147  
     148  static void 
     149  no_run (gpointer data)
     150  {
     151  }
     152  #endif
     153  
     154  static void 
     155  no_reset (gpointer data)
     156  {
     157  }
     158  
     159  static void 
     160  no_teardown (gpointer data)
     161  {
     162  }
     163  
     164  typedef struct _PerformanceTest PerformanceTest;
     165  struct _PerformanceTest {
     166    const char *name;
     167  
     168    gpointer (*setup) (void);
     169    void (*run) (gpointer data);
     170    void (*reset) (gpointer data);
     171    void (*teardown) (gpointer data);
     172  };
     173  
     174  static const PerformanceTest tests[] = {
     175    { "liststore-is-a",
     176      register_types,
     177      liststore_is_a_run,
     178      no_reset,
     179      no_teardown },
     180    { "liststore-interface-peek",
     181      liststore_get_class,
     182      liststore_interface_peek_run,
     183      no_reset,
     184      g_type_class_unref },
     185    { "liststore-interface-peek-same",
     186      liststore_get_class,
     187      liststore_interface_peek_same_run,
     188      no_reset,
     189      g_type_class_unref },
     190  #if 0
     191    { "nothing",
     192      no_setup,
     193      no_run,
     194      no_reset,
     195      no_teardown }
     196  #endif
     197  };
     198  
     199  static gboolean verbose = FALSE;
     200  static guint n_threads = 0;
     201  static gboolean list = FALSE;
     202  static int test_length = DEFAULT_TEST_TIME;
     203  
     204  static GOptionEntry cmd_entries[] = {
     205    {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
     206     "Print extra information", NULL},
     207    {"threads", 't', 0, G_OPTION_ARG_INT, &n_threads,
     208     "number of threads to run in parallel", NULL},
     209    {"seconds", 's', 0, G_OPTION_ARG_INT, &test_length,
     210     "Time to run each test in seconds", NULL},
     211    {"list", 'l', 0, G_OPTION_ARG_NONE, &list, 
     212     "List all available tests and exit", NULL},
     213    G_OPTION_ENTRY_NULL
     214  };
     215  
     216  static gpointer
     217  run_test_thread (gpointer user_data)
     218  {
     219    const PerformanceTest *test = user_data;
     220    gpointer data;
     221    double elapsed;
     222    GTimer *timer, *total;
     223    GArray *results;
     224  
     225    total = g_timer_new ();
     226    g_timer_start (total);
     227  
     228    /* Set up test */
     229    timer = g_timer_new ();
     230    data = test->setup ();
     231    results = g_array_new (FALSE, FALSE, sizeof (double));
     232  
     233    /* Run the test */
     234    do
     235      {
     236        g_timer_reset (timer);
     237        g_timer_start (timer);
     238        test->run (data);
     239        g_timer_stop (timer);
     240        elapsed = g_timer_elapsed (timer, NULL);
     241        g_array_append_val (results, elapsed);
     242        test->reset (data);
     243      }
     244    while (g_timer_elapsed (total, NULL) < test_length);
     245  
     246    /* Tear down */
     247    test->teardown (data);
     248    g_timer_destroy (timer);
     249    g_timer_destroy (total);
     250  
     251    return results;
     252  }
     253  
     254  static int
     255  compare_doubles (gconstpointer a, gconstpointer b)
     256  {
     257    double d = *(double *) a - *(double *) b;
     258  
     259    if (d < 0)
     260      return -1;
     261    if (d > 0)
     262      return 1;
     263    return 0;
     264  }
     265  
     266  static void
     267  print_results (GArray *array)
     268  {
     269    double min, max, avg;
     270    guint i;
     271  
     272    g_array_sort (array, compare_doubles);
     273  
     274    /* FIXME: discard outliers */
     275  
     276    min = g_array_index (array, double, 0) * 1000;
     277    max = g_array_index (array, double, array->len - 1) * 1000;
     278    avg = 0;
     279    for (i = 0; i < array->len; i++)
     280      {
     281        avg += g_array_index (array, double, i);
     282      }
     283    avg = avg / array->len * 1000;
     284  
     285    g_print ("  %u runs, min/avg/max = %.3f/%.3f/%.3f ms\n", array->len, min, avg, max);
     286  }
     287  
     288  static void
     289  run_test (const PerformanceTest *test)
     290  {
     291    GArray *results;
     292  
     293    g_print ("Running test \"%s\"\n", test->name);
     294  
     295    if (n_threads == 0) {
     296      results = run_test_thread ((gpointer) test);
     297    } else {
     298      guint i;
     299      GThread **threads;
     300      GArray *thread_results;
     301        
     302      threads = g_new (GThread *, n_threads);
     303      for (i = 0; i < n_threads; i++) {
     304        threads[i] = g_thread_new (NULL, run_test_thread, (gpointer) test);
     305        g_assert (threads[i] != NULL);
     306      }
     307  
     308      results = g_array_new (FALSE, FALSE, sizeof (double));
     309      for (i = 0; i < n_threads; i++) {
     310        thread_results = g_thread_join (threads[i]);
     311        g_array_append_vals (results, thread_results->data, thread_results->len);
     312        g_array_free (thread_results, TRUE);
     313      }
     314      g_free (threads);
     315    }
     316  
     317    print_results (results);
     318    g_array_free (results, TRUE);
     319  }
     320  
     321  static const PerformanceTest *
     322  find_test (const char *name)
     323  {
     324    gsize i;
     325    for (i = 0; i < G_N_ELEMENTS (tests); i++)
     326      {
     327        if (strcmp (tests[i].name, name) == 0)
     328  	return &tests[i];
     329      }
     330    return NULL;
     331  }
     332  
     333  int
     334  main (int   argc,
     335        char *argv[])
     336  {
     337    const PerformanceTest *test;
     338    GOptionContext *context;
     339    GError *error = NULL;
     340    gsize i;
     341  
     342    context = g_option_context_new ("GObject performance tests");
     343    g_option_context_add_main_entries (context, cmd_entries, NULL);
     344    if (!g_option_context_parse (context, &argc, &argv, &error))
     345      {
     346        g_printerr ("%s: %s\n", argv[0], error->message);
     347        return 1;
     348      }
     349  
     350    if (list)
     351      {
     352        for (i = 0; i < G_N_ELEMENTS (tests); i++)
     353          {
     354            g_print ("%s\n", tests[i].name);
     355          }
     356        return 0;
     357      }
     358  
     359    if (argc > 1)
     360      {
     361        int k;
     362        for (k = 1; k < argc; k++)
     363  	{
     364  	  test = find_test (argv[k]);
     365  	  if (test)
     366  	    run_test (test);
     367  	}
     368      }
     369    else
     370      {
     371        for (i = 0; i < G_N_ELEMENTS (tests); i++)
     372  	run_test (&tests[i]);
     373      }
     374  
     375    g_option_context_free (context);
     376    return 0;
     377  }