[gtk/wip/otte/sortlistmodel: 2/3] testsuite: Support different models



commit 3ee6c368576419fb25eacd9190b2d67ee5d817cb
Author: Benjamin Otte <otte redhat com>
Date:   Sun Jul 19 01:02:38 2020 +0200

    testsuite: Support different models
    
    In particular, add a GtkTreeModel of GtkDirectoryList that enumerates
    the full tree of everything below G_TEST_SRCDIR.
    
    You can set it to ~ or / to get lots of files.
    
    Use this to test numeric sorting, string sorting, the treelistrow
    sorter and the multisorter.
    And while doing all of that, try to use something that is still
    realistic.

 testsuite/gtk/sort-performance.c | 384 ++++++++++++++++++++++++++++++---------
 1 file changed, 302 insertions(+), 82 deletions(-)
---
diff --git a/testsuite/gtk/sort-performance.c b/testsuite/gtk/sort-performance.c
index aadbf6ca3c..3bd48c5342 100644
--- a/testsuite/gtk/sort-performance.c
+++ b/testsuite/gtk/sort-performance.c
@@ -15,6 +15,16 @@ quick_random (guint prev)
 
 static guint comparisons = 0;
 
+static int
+count_comparisons (gconstpointer a,
+                   gconstpointer b,
+                   gpointer      unused)
+{
+  comparisons++;
+
+  return GTK_ORDERING_EQUAL;
+}
+
 static int
 compare_string_object (gconstpointer a,
                        gconstpointer b,
@@ -29,12 +39,6 @@ compare_string_object (gconstpointer a,
                                             gtk_string_object_get_string (sb)));
 }
 
-static GtkSorter *
-create_sorter (void)
-{
-  return gtk_custom_sorter_new (compare_string_object, NULL, NULL);
-}
-
 static void
 count_changed_cb (GListModel *model,
                   guint       position,
@@ -80,22 +84,20 @@ set_model (const char *testname,
            GType       type,
            gboolean    incremental,
            GListModel *source,
+           GtkSorter  *sorter,
            guint       random)
 {
   gint64 start, end, max, total;
   GtkSliceListModel *slice;
-  GtkSorter *sorter;
   GListModel *sort;
   guint n_changed, size = 1000;
 
   slice = gtk_slice_list_model_new (source, 0, size);
-  sorter = create_sorter ();
   sort = g_object_new (type,
                        "sorter", sorter,
                        incremental ? "incremental" : NULL, TRUE,
                        NULL);
   g_signal_connect (sort, "items-changed", G_CALLBACK (count_changed_cb), &n_changed);
-  g_object_unref (sorter);
 
   while (TRUE)
     {
@@ -118,12 +120,11 @@ set_model (const char *testname,
 
       print_result (testname, type, incremental, size, total, max, comparisons, n_changed);
 
-      if (total > MAX_TIME)
+      if (total > MAX_TIME ||
+          size >= g_list_model_get_n_items (source))
         break;
 
       size *= 2;
-      if (4 * total > 2 * MAX_TIME)
-        break;
 
       g_object_set (sort, "model", NULL, NULL);
       gtk_slice_list_model_set_size (slice, size);
@@ -138,24 +139,22 @@ append (const char *testname,
         GType       type,
         gboolean    incremental,
         GListModel *source,
+        GtkSorter  *sorter,
         guint       random,
         guint       fraction)
 {
   gint64 start, end, max, total;
   GtkSliceListModel *slice;
-  GtkSorter *sorter;
   GListModel *sort;
   guint n_changed, size = 1000;
 
   slice = gtk_slice_list_model_new (source, 0, (fraction - 1) * size / fraction);
-  sorter = create_sorter ();
   sort = g_object_new (type,
                        "model", slice,
                        "sorter", sorter,
                        incremental ? "incremental" : NULL, TRUE,
                        NULL);
   g_signal_connect (sort, "items-changed", G_CALLBACK (count_changed_cb), &n_changed);
-  g_object_unref (sorter);
 
   while (TRUE)
     {
@@ -179,13 +178,11 @@ append (const char *testname,
 
       print_result (testname, type, incremental, size, total, max, comparisons, n_changed);
 
-      if (total > MAX_TIME)
+      if (total > MAX_TIME ||
+          size >= g_list_model_get_n_items (source))
         break;
 
       size *= 2;
-      if (4 * total > 2 * MAX_TIME ||
-          size > MAX_SIZE)
-        break;
     }
 
   g_object_unref (sort);
@@ -197,9 +194,10 @@ append_half (const char *name,
              GType       type,
              gboolean    incremental,
              GListModel *source,
+             GtkSorter  *sorter,
              guint       random)
 {
-  append (name, type, incremental, source, random, 2);
+  append (name, type, incremental, source, sorter, random, 2);
 }
 
 static void
@@ -207,9 +205,10 @@ append_10th (const char *name,
              GType       type,
              gboolean    incremental,
              GListModel *source,
+             GtkSorter  *sorter,
              guint       random)
 {
-  append (name, type, incremental, source, random, 10);
+  append (name, type, incremental, source, sorter, random, 10);
 }
 
 static void
@@ -217,9 +216,10 @@ append_100th (const char *name,
               GType       type,
               gboolean    incremental,
               GListModel *source,
+              GtkSorter  *sorter,
               guint       random)
 {
-  append (name, type, incremental, source, random, 100);
+  append (name, type, incremental, source, sorter, random, 100);
 }
 
 static void
@@ -227,24 +227,22 @@ remove_test (const char *testname,
              GType       type,
              gboolean    incremental,
              GListModel *source,
+             GtkSorter  *sorter,
              guint       random,
              guint       fraction)
 {
   gint64 start, end, max, total;
   GtkSliceListModel *slice;
-  GtkSorter *sorter;
   GListModel *sort;
   guint n_changed, size = 1000;
 
   slice = gtk_slice_list_model_new (source, 0, size);
-  sorter = create_sorter ();
   sort = g_object_new (type,
                        "model", slice,
                        "sorter", sorter,
                        incremental ? "incremental" : NULL, TRUE,
                        NULL);
   g_signal_connect (sort, "items-changed", G_CALLBACK (count_changed_cb), &n_changed);
-  g_object_unref (sorter);
 
   while (TRUE)
     {
@@ -268,13 +266,11 @@ remove_test (const char *testname,
 
       print_result (testname, type, incremental, size, total, max, comparisons, n_changed);
 
-      if (total > MAX_TIME)
+      if (total > MAX_TIME ||
+          size >= g_list_model_get_n_items (source))
         break;
 
       size *= 2;
-      if (4 * total > 2 * MAX_TIME ||
-          size > MAX_SIZE)
-        break;
     }
 
   g_object_unref (sort);
@@ -286,9 +282,10 @@ remove_half (const char *name,
              GType       type,
              gboolean    incremental,
              GListModel *source,
+             GtkSorter  *sorter,
              guint       random)
 {
-  remove_test (name, type, incremental, source, random, 2);
+  remove_test (name, type, incremental, source, sorter, random, 2);
 }
 
 static void
@@ -296,9 +293,10 @@ remove_10th (const char *name,
              GType       type,
              gboolean    incremental,
              GListModel *source,
+             GtkSorter  *sorter,
              guint       random)
 {
-  remove_test (name, type, incremental, source, random, 10);
+  remove_test (name, type, incremental, source, sorter, random, 10);
 }
 
 static void
@@ -306,9 +304,10 @@ remove_100th (const char *name,
               GType       type,
               gboolean    incremental,
               GListModel *source,
+              GtkSorter  *sorter,
               guint       random)
 {
-  remove_test (name, type, incremental, source, random, 100);
+  remove_test (name, type, incremental, source, sorter, random, 100);
 }
 
 static void
@@ -316,24 +315,22 @@ append_n (const char *testname,
           GType       type,
           gboolean    incremental,
           GListModel *source,
+          GtkSorter  *sorter,
           guint       random,
           guint       n)
 {
   gint64 start, end, max, total;
   GtkSliceListModel *slice;
-  GtkSorter *sorter;
   GListModel *sort;
   guint i, n_changed, size = 1000;
 
   slice = gtk_slice_list_model_new (source, 0, size);
-  sorter = create_sorter ();
   sort = g_object_new (type,
                        "model", slice,
                        "sorter", sorter,
                        incremental ? "incremental" : NULL, TRUE,
                        NULL);
   g_signal_connect (sort, "items-changed", G_CALLBACK (count_changed_cb), &n_changed);
-  g_object_unref (sorter);
 
   while (TRUE)
     {
@@ -360,13 +357,11 @@ append_n (const char *testname,
 
       print_result (testname, type, incremental, size, total, max, comparisons, n_changed);
 
-      if (total > MAX_TIME)
+      if (total > MAX_TIME ||
+          size >= g_list_model_get_n_items (source))
         break;
 
       size *= 2;
-      if (4 * total > 2 * MAX_TIME ||
-          size > MAX_SIZE)
-        break;
     }
 
   g_object_unref (sort);
@@ -378,9 +373,10 @@ append_1 (const char *name,
           GType       type,
           gboolean    incremental,
           GListModel *source,
+          GtkSorter  *sorter,
           guint       random)
 {
-  append_n (name, type, incremental, source, random, 1);
+  append_n (name, type, incremental, source, sorter, random, 1);
 }
 
 static void
@@ -388,9 +384,10 @@ append_2 (const char *name,
           GType       type,
           gboolean    incremental,
           GListModel *source,
+          GtkSorter  *sorter,
           guint       random)
 {
-  append_n (name, type, incremental, source, random, 2);
+  append_n (name, type, incremental, source, sorter, random, 2);
 }
 
 static void
@@ -398,9 +395,10 @@ append_10 (const char *name,
            GType       type,
            gboolean    incremental,
            GListModel *source,
+           GtkSorter  *sorter,
            guint       random)
 {
-  append_n (name, type, incremental, source, random, 10);
+  append_n (name, type, incremental, source, sorter, random, 10);
 }
 
 static void
@@ -408,24 +406,22 @@ remove_n (const char *testname,
           GType       type,
           gboolean    incremental,
           GListModel *source,
+          GtkSorter  *sorter,
           guint       random,
           guint       n)
 {
   gint64 start, end, max, total;
   GtkSliceListModel *slice;
-  GtkSorter *sorter;
   GListModel *sort;
   guint i, n_changed, size = 1000;
 
   slice = gtk_slice_list_model_new (source, 0, size);
-  sorter = create_sorter ();
   sort = g_object_new (type,
                        "model", slice,
                        "sorter", sorter,
                        incremental ? "incremental" : NULL, TRUE,
                        NULL);
   g_signal_connect (sort, "items-changed", G_CALLBACK (count_changed_cb), &n_changed);
-  g_object_unref (sorter);
 
   while (TRUE)
     {
@@ -452,13 +448,11 @@ remove_n (const char *testname,
 
       print_result (testname, type, incremental, size, total, max, comparisons, n_changed);
 
-      if (total > MAX_TIME)
+      if (total > MAX_TIME ||
+          size >= g_list_model_get_n_items (source))
         break;
 
       size *= 2;
-      if (4 * total > 2 * MAX_TIME ||
-          size > MAX_SIZE)
-        break;
     }
 
   g_object_unref (sort);
@@ -470,9 +464,10 @@ remove_1 (const char *name,
           GType       type,
           gboolean    incremental,
           GListModel *source,
+          GtkSorter  *sorter,
           guint       random)
 {
-  remove_n (name, type, incremental, source, random, 1);
+  remove_n (name, type, incremental, source, sorter, random, 1);
 }
 
 static void
@@ -480,26 +475,158 @@ remove_2 (const char *name,
           GType       type,
           gboolean    incremental,
           GListModel *source,
+          GtkSorter  *sorter,
           guint       random)
 {
-  remove_n (name, type, incremental, source, random, 2);
+  remove_n (name, type, incremental, source, sorter, random, 2);
 }
 
 static void
 remove_10 (const char *name,
            GType       type,
-          gboolean    incremental,
+           gboolean    incremental,
            GListModel *source,
+           GtkSorter  *sorter,
            guint       random)
 {
-  remove_n (name, type, incremental, source, random, 10);
+  remove_n (name, type, incremental, source, sorter, random, 10);
+}
+
+static void
+done_loading_directory (GtkDirectoryList *dir,
+                        GParamSpec       *pspec,
+                        gpointer          data)
+{
+  /* When we get G_IO_ERROR_TOO_MANY_OPEN_FILES we enqueue directories here for reloading
+   * as more file descriptors get available
+   */
+  static GSList *too_many = NULL;
+
+  const GError *error;
+  guint *counters = data;
+
+  /* happens when restarting the load below */
+  if (gtk_directory_list_is_loading (dir))
+    return;
+
+  error = gtk_directory_list_get_error (dir);
+  if (error)
+    {
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TOO_MANY_OPEN_FILES))
+        {
+          too_many = g_slist_prepend (too_many, g_object_ref (dir));
+          return;
+        }
+    }
+  counters[1]++;
+  if (too_many)
+    {
+      GtkDirectoryList *reload = too_many->data;
+      GFile *file;
+
+      too_many = g_slist_remove (too_many, reload);
+      file = g_object_ref (gtk_directory_list_get_file (reload));
+      gtk_directory_list_set_file (reload, NULL);
+      gtk_directory_list_set_file (reload, file);
+      g_object_unref (file);
+    }
+}
+
+static gboolean
+file_info_is_directory (GFileInfo *file_info)
+{
+  if (g_file_info_get_is_symlink (file_info))
+    return FALSE;
+
+  return g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY;
+}
+
+static GListModel *
+create_directory_list (gpointer item,
+                       gpointer data)
+{
+  GFileInfo *file_info = G_FILE_INFO (item);
+  guint *counters = data;
+  GtkDirectoryList *dir;
+  GFile *file;
+
+  if (!file_info_is_directory (file_info))
+    return NULL;
+  file = G_FILE (g_file_info_get_attribute_object (file_info, "standard::file"));
+  if (file == NULL)
+    return NULL;
+
+  dir = gtk_directory_list_new (G_FILE_ATTRIBUTE_STANDARD_TYPE
+                                "," G_FILE_ATTRIBUTE_STANDARD_NAME
+                                "," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME
+                                "," G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK,
+                                NULL);
+  gtk_directory_list_set_io_priority (dir, G_PRIORITY_DEFAULT + g_random_int_range (-5, 5));
+  gtk_directory_list_set_monitored (dir, FALSE);
+  gtk_directory_list_set_file (dir, file);
+  counters[0]++;
+  g_signal_connect (dir, "notify::loading", G_CALLBACK (done_loading_directory), counters);
+  g_assert (gtk_directory_list_is_loading (dir));
+
+  return G_LIST_MODEL (dir);
+}
+
+static GListModel *
+get_file_infos (void)
+{
+  static GtkTreeListModel *tree = NULL;
+  gint64 start, end, max;
+  GtkDirectoryList *dir;
+  GFile *root;
+  guint counters[2] = { 1, 0 };
+
+  if (tree)
+    return G_LIST_MODEL (g_object_ref (tree));
+
+  if (g_getenv ("G_TEST_SRCDIR"))
+    root = g_file_new_for_path (g_getenv ("G_TEST_SRCDIR"));
+  else
+    root = g_file_new_for_path (g_get_home_dir ());
+
+  start = end = g_get_monotonic_time ();
+  max = 0;
+  dir = gtk_directory_list_new (G_FILE_ATTRIBUTE_STANDARD_TYPE
+                                "," G_FILE_ATTRIBUTE_STANDARD_NAME
+                                "," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME
+                                "," G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK,
+                                NULL);
+  gtk_directory_list_set_monitored (dir, FALSE);
+  gtk_directory_list_set_file (dir, root);
+  tree = gtk_tree_list_model_new (FALSE,
+                                  G_LIST_MODEL (dir),
+                                  TRUE,
+                                  create_directory_list,
+                                  counters, NULL);
+  g_signal_connect (dir, "notify::loading", G_CALLBACK (done_loading_directory), counters);
+  end = snapshot_time (end, &max);
+  while (counters[0] != counters[1])
+    {
+      g_main_context_iteration (NULL, TRUE);
+      end = snapshot_time (end, &max);
+    }
+  //g_print ("%u/%u\n", counters[0], counters[1]);
+
+  end = snapshot_time (end, &max);
+
+  print_result ("load-directory", GTK_TYPE_DIRECTORY_LIST, FALSE, g_list_model_get_n_items (G_LIST_MODEL 
(tree)), end - start, max, 0, counters[0]);
+
+  g_object_unref (dir);
+  g_object_unref (root);
+
+  return G_LIST_MODEL (g_object_ref (tree));
 }
 
 static void
-run_test (GtkStringList      *source,
+run_test (GListModel         *source,
+          GtkSorter          *sorter,
           const char * const *tests,
           const char         *test_name,
-          void (* test_func) (const char *name, GType type, gboolean incremental, GListModel *source, guint 
random))
+          void (* test_func) (const char *name, GType type, gboolean incremental, GListModel *source, 
GtkSorter *sorter, guint random))
 {
   struct {
     GType type;
@@ -524,51 +651,144 @@ run_test (GtkStringList      *source,
   guint random = g_random_int ();
   guint i;
 
-  if (tests != NULL && !g_strv_contains (tests, test_name))
-    return;
-
   for (i = 0; i < G_N_ELEMENTS (types); i++)
     {
-      test_func (test_name, types[i].type, types[i].incremental, G_LIST_MODEL (source), random);
+      test_func (test_name, types[i].type, types[i].incremental, source, sorter, random);
+    }
+}
+
+static GListModel *
+get_string_list (void)
+{
+  static GtkStringList *string_list = NULL;
+
+  if (string_list == NULL)
+    {
+      guint i, random;
+      random = g_test_rand_int ();
+      string_list = gtk_string_list_new (NULL);
+      for (i = 0; i < MAX_SIZE; i++)
+        {
+          gtk_string_list_take (string_list, g_strdup_printf ("%u", random));
+          random = quick_random  (random);
+        }
+    }
+
+  return G_LIST_MODEL (g_object_ref (string_list));
+}
+
+static void
+run_tests (const char * const *tests,
+           const char         *test_name,
+           void (* test_func) (const char *name, GType type, gboolean incremental, GListModel *source, 
GtkSorter *sorter, guint random))
+{
+  const char *suffixes[] = { "string", "tree", "filename" };
+  gsize i;
+
+  for (i = 0; i < G_N_ELEMENTS(suffixes); i++)
+    {
+      GListModel *source;
+      GtkSorter *sorter;
+      char *name;
+
+      name = g_strdup_printf ("%s-%s", test_name, suffixes[i]);
+      if (tests != NULL && !g_strv_contains (tests, name))
+        {
+          g_free (name);
+          continue;
+        }
+
+      switch (i)
+        {
+        case 0:
+          source = get_string_list ();
+          sorter = gtk_custom_sorter_new (compare_string_object, NULL, NULL);
+          break;
+
+        case 1:
+          source = get_file_infos ();
+          sorter = gtk_multi_sorter_new ();
+          gtk_multi_sorter_append (GTK_MULTI_SORTER (sorter), gtk_custom_sorter_new (count_comparisons, 
NULL, NULL));
+          gtk_multi_sorter_append (GTK_MULTI_SORTER (sorter),
+                                   gtk_numeric_sorter_new (gtk_cclosure_expression_new (G_TYPE_BOOLEAN,
+                                                                                        NULL,
+                                                                                        0,
+                                                                                        NULL,
+                                                                                        (GCallback) 
file_info_is_directory,
+                                                                                        NULL, NULL)));
+          gtk_multi_sorter_append (GTK_MULTI_SORTER (sorter),
+                                   gtk_numeric_sorter_new (gtk_cclosure_expression_new (G_TYPE_UINT64,
+                                                                                        NULL,
+                                                                                        1,
+                                                                                        (GtkExpression *[1]) 
{
+                                                                                          
gtk_constant_expression_new (G_TYPE_STRING, G_FILE_ATTRIBUTE_STANDARD_SIZE)
+                                                                                        },
+                                                                                        (GCallback) 
g_file_info_get_attribute_uint64,
+                                                                                        NULL, NULL)));
+          sorter = gtk_tree_list_row_sorter_new (sorter);
+          break;
+
+        case 2:
+          {
+            GListModel *infos = get_file_infos ();
+            source = G_LIST_MODEL (gtk_map_list_model_new (infos,
+                                                           (GtkMapListModelMapFunc) 
gtk_tree_list_row_get_item,
+                                                           NULL, NULL));
+            sorter = gtk_string_sorter_new (
+                         gtk_cclosure_expression_new (G_TYPE_STRING,
+                                                      NULL,
+                                                      1,
+                                                      (GtkExpression *[1]) {
+                                                        gtk_constant_expression_new (G_TYPE_STRING, 
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME)
+                                                      },
+                                                      (GCallback) g_file_info_get_attribute_as_string,
+                                                      NULL,
+                                                      NULL));
+            g_object_unref (infos);
+          }
+          break;
+
+        default:
+          g_assert_not_reached ();
+          return;
+        }
+
+      run_test (source, sorter, tests, name, test_func);
+
+      g_free (name);
+      g_object_unref (sorter);
+      g_object_unref (source);
     }
 }
 
 int
 main (int argc, char *argv[])
 {
-  GtkStringList *source;
-  guint random = g_random_int ();
-  guint i;
   const char * const *tests;
 
   gtk_test_init (&argc, &argv);
 
-  source = gtk_string_list_new (NULL);
-  for (i = 0; i < MAX_SIZE; i++)
-    {
-      gtk_string_list_take (source, g_strdup_printf ("%u", random));
-      random = quick_random  (random);
-    }
-
   if (argc < 2)
     tests = NULL;
   else
     tests = (const char **) argv + 1;
 
   g_print ("# \"test\",\"model\",\"model size\",\"time\",\"max time\",\"comparisons\",\"changes\"\n");
-  run_test (source, tests, "set-model", set_model);
-  run_test (source, tests, "append-half", append_half);
-  run_test (source, tests, "append-10th", append_10th);
-  run_test (source, tests, "append-100th", append_100th);
-  run_test (source, tests, "remove-half", remove_half);
-  run_test (source, tests, "remove-10th", remove_10th);
-  run_test (source, tests, "remove-100th", remove_100th);
-  run_test (source, tests, "append-1", append_1);
-  run_test (source, tests, "append-2", append_2);
-  run_test (source, tests, "append-10", append_10);
-  run_test (source, tests, "remove-1", remove_1);
-  run_test (source, tests, "remove-2", remove_2);
-  run_test (source, tests, "remove-10", remove_10);
+  run_tests (tests, "set-model", set_model);
+  run_tests (tests, "append-half", append_half);
+  run_tests (tests, "append-10th", append_10th);
+  run_tests (tests, "append-100th", append_100th);
+  run_tests (tests, "remove-half", remove_half);
+  run_tests (tests, "remove-10th", remove_10th);
+  run_tests (tests, "remove-100th", remove_100th);
+  run_tests (tests, "append-1", append_1);
+  run_tests (tests, "append-2", append_2);
+  run_tests (tests, "append-10", append_10);
+  run_tests (tests, "remove-1", remove_1);
+  run_tests (tests, "remove-2", remove_2);
+  run_tests (tests, "remove-10", remove_10);
+  run_tests (tests, "remove-10", remove_10);
+
 
   return g_test_run ();
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]