testsuite: Add some vector performance tests

They're not very conclusive though, because the testing isn't
fine-grained enough for these microbenchmarks.
This commit is contained in:
Benjamin Otte
2020-07-05 20:11:50 +02:00
parent f6cdc491ad
commit c94d69473e
2 changed files with 444 additions and 0 deletions

View File

@@ -76,6 +76,7 @@ tests = [
['displayclose'],
['revealer-size'],
['vector'],
['vector-performance'],
['widgetorder'],
['widget-refcount'],
]

View File

@@ -0,0 +1,443 @@
#include <gtk/gtk.h>
#define GTK_VECTOR_ELEMENT_TYPE gpointer
#define GTK_VECTOR_NAME pointer_vector
#define GTK_VECTOR_TYPE_NAME PointerVector
#include "../../gtk/gtkvectorimpl.c"
#define GTK_VECTOR_ELEMENT_TYPE gpointer
#define GTK_VECTOR_NAME prealloc_vector
#define GTK_VECTOR_TYPE_NAME PreallocVector
#define GTK_VECTOR_PREALLOC 1024
#include "../../gtk/gtkvectorimpl.c"
static inline guint
quick_random (guint prev)
{
prev ^= prev << 13;
prev ^= prev >> 17;
prev ^= prev << 5;
return prev;
}
typedef struct {
const char *name;
gsize stack_space;
gpointer (* create) (gpointer space, gsize size);
void (* free) (gpointer array);
void (* reserve) (gpointer array, gsize size);
gpointer (* get) (gpointer array, gsize pos);
void (* append) (gpointer array, gpointer data);
void (* insert) (gpointer array, gsize pos, gpointer data);
} Array;
static gpointer
create_ptrarray (gpointer space,
gsize size)
{
return g_ptr_array_sized_new (size);
}
static void
free_ptrarray (gpointer array)
{
g_ptr_array_free (array, TRUE);
}
static void
reserve_ptrarray (gpointer array,
gsize size)
{
gsize length = ((GPtrArray *) array)->len;
if (length >= size)
return;
g_ptr_array_set_size (array, size);
g_ptr_array_set_size (array, length);
}
static gpointer
get_ptrarray (gpointer array,
gsize pos)
{
return g_ptr_array_index ((GPtrArray *) array, pos);
}
static void
append_ptrarray (gpointer array,
gpointer data)
{
g_ptr_array_add (array, data);
}
static void
insert_ptrarray (gpointer array,
gsize pos,
gpointer data)
{
g_ptr_array_insert (array, pos, data);
}
static gpointer
create_vector (gpointer space,
gsize size)
{
pointer_vector_init (space);
if (size)
pointer_vector_reserve ((PointerVector *) space, size);
return space;
}
static void
free_vector (gpointer array)
{
pointer_vector_clear (array);
}
static void
reserve_vector (gpointer array,
gsize size)
{
pointer_vector_reserve (array, size);
}
static gpointer
get_vector (gpointer array,
gsize pos)
{
return pointer_vector_get (array, pos);
}
static void
append_vector (gpointer array,
gpointer data)
{
pointer_vector_append (array, data);
}
static void
insert_vector (gpointer array,
gsize pos,
gpointer data)
{
pointer_vector_splice (array, pos, 0, &data, 1);
}
static gpointer
create_prealloc (gpointer space,
gsize size)
{
prealloc_vector_init (space);
if (size)
prealloc_vector_reserve ((PreallocVector *) space, size);
return space;
}
static void
free_prealloc (gpointer array)
{
prealloc_vector_clear (array);
}
static void
reserve_prealloc (gpointer array,
gsize size)
{
prealloc_vector_reserve (array, size);
}
static gpointer
get_prealloc (gpointer array,
gsize pos)
{
return prealloc_vector_get (array, pos);
}
static void
append_prealloc (gpointer array,
gpointer data)
{
prealloc_vector_append (array, data);
}
static void
insert_prealloc (gpointer array,
gsize pos,
gpointer data)
{
prealloc_vector_splice (array, pos, 0, &data, 1);
}
static void
do_random_access (const Array *klass,
guint random,
gsize size,
gsize max_size)
{
gpointer stack;
gpointer array;
guint i;
guint position;
gint64 start, end;
guint iterations = 10000000;
size = pow (100 * 100 * 100 * 100, (double) size / max_size);
if (klass->stack_space)
stack = g_alloca (klass->stack_space);
else
stack = NULL;
array = klass->create (stack, size);
for (i = 0; i < size; i++)
klass->append (array, GSIZE_TO_POINTER (i));
start = g_get_monotonic_time ();
for (i = 0; i < iterations; i++)
{
position = random % size;
random = quick_random (random);
g_assert_cmpint (position, ==, GPOINTER_TO_SIZE (klass->get (array, position)));
}
end = g_get_monotonic_time ();
g_print ("\"random access\",\"%s\", %zu, %g\n",
klass->name,
size,
((double)(end - start)) / iterations);
klass->free (array);
}
static void
do_linear_access (const Array *klass,
guint random,
gsize size,
gsize max_size)
{
gpointer stack;
gpointer array;
guint i;
gint64 start, end;
guint iterations = 1000000;
size = pow (100 * 100 * 100 * 100, (double) size / max_size);
if (klass->stack_space)
stack = g_alloca (klass->stack_space);
else
stack = NULL;
array = klass->create (stack, size);
for (i = 0; i < size; i++)
klass->append (array, GSIZE_TO_POINTER (i));
start = g_get_monotonic_time ();
for (i = 0; i < iterations; i++)
{
g_assert_cmpint (i % size, ==, GPOINTER_TO_SIZE (klass->get (array, i % size)));
}
end = g_get_monotonic_time ();
g_print ("\"linear access\", \"%s\", %zu, %g\n",
klass->name,
size,
((double)(end - start)) / iterations);
klass->free (array);
}
static void
do_append (const Array *klass,
guint random,
gsize size,
gsize max_size)
{
gpointer stack;
gpointer array;
guint i;
gint64 start, end;
int iterations = 10000;
size = pow (100 * 1000 * 1000, (double) size / max_size);
if (klass->stack_space)
stack = g_alloca (klass->stack_space);
else
stack = NULL;
array = klass->create (stack, size);
for (i = 0; i < size; i++)
klass->append (array, GSIZE_TO_POINTER (i));
start = g_get_monotonic_time ();
for (i = size; i < size + iterations; i++)
{
klass->append (array, GSIZE_TO_POINTER (i));
}
end = g_get_monotonic_time ();
klass->free (array);
g_print ("\"append\", \"%s\", %zu, %g\n",
klass->name,
size,
((double) (end - start)) / iterations);
}
static void
do_insert (const Array *klass,
guint random,
gsize size,
gsize max_size)
{
gpointer stack;
gpointer array;
guint i;
gint64 start, end;
int iterations = 10000;
size = pow (25 * 25 * 25 * 25, (double) size / max_size);
if (klass->stack_space)
stack = g_alloca (klass->stack_space);
else
stack = NULL;
array = klass->create (stack, size);
for (i = 0; i < size; i++)
klass->append (array, GSIZE_TO_POINTER (i));
start = g_get_monotonic_time ();
for (i = size; i < size + iterations; i++)
{
gsize position = random % size;
random = quick_random (random);
klass->insert (array, position, GSIZE_TO_POINTER (i));
}
end = g_get_monotonic_time ();
klass->free (array);
g_print ("\"insert\", \"%s\", %zu, %g\n",
klass->name,
size,
((double) (end - start)) / iterations);
}
static void
do_create (const Array *klass,
guint random,
gsize size,
gsize max_size)
{
gpointer stack;
gpointer array;
gsize i, j;
gint64 start, end;
gsize iterations = 100000;
size = pow (4 * 4 * 4 * 4, (double) size / max_size);
if (klass->stack_space)
stack = g_alloca (klass->stack_space);
else
stack = NULL;
start = g_get_monotonic_time ();
for (i = 0; i < iterations; i++)
{
gsize position = random % size;
random = quick_random (random);
array = klass->create (stack, size);
for (j = 0; j < size; j++)
klass->append (array, GSIZE_TO_POINTER (i));
klass->insert (array, position, GSIZE_TO_POINTER (i));
klass->free (array);
}
end = g_get_monotonic_time ();
g_print ("\"create\", \"%s\", %zu, %g\n",
klass->name,
size,
((double) (end - start)) / iterations);
}
const Array all_arrays[] = {
{
"ptrarray",
0,
create_ptrarray,
free_ptrarray,
reserve_ptrarray,
get_ptrarray,
append_ptrarray,
insert_ptrarray
},
{
"vector",
sizeof (PointerVector),
create_vector,
free_vector,
reserve_vector,
get_vector,
append_vector,
insert_vector
},
{
"preallocated-vector",
sizeof (PreallocVector),
create_prealloc,
free_prealloc,
reserve_prealloc,
get_prealloc,
append_prealloc,
insert_prealloc
}
};
static void
run_test (void (* test_func) (const Array *klass, guint random, gsize size, gsize max_size))
{
int max_size = 4;
int size;
int i;
guint random = g_random_int ();
for (i = 0; i < G_N_ELEMENTS (all_arrays); i++)
{
for (size = 1; size <= max_size; size++)
{
test_func (&all_arrays[i], random, size, max_size);
}
}
}
int
main (int argc, char *argv[])
{
gtk_test_init (&argc, &argv);
g_print ("\"test\",\"model\",\"model size\",\"time\"\n");
run_test (do_random_access);
run_test (do_linear_access);
run_test (do_append);
run_test (do_insert);
run_test (do_create);
return g_test_run ();
}