From 8f50feb4ef0c8b69cf630351823af048b20b94d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 7 Jul 2022 16:46:47 +0200 Subject: [PATCH] tests: Add simple allocating benchmark with both system and slice allocator --- meson.build | 25 ++++ tests/allocators-tests.c | 241 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 266 insertions(+) create mode 100644 tests/allocators-tests.c diff --git a/meson.build b/meson.build index 0edbc2bf0..4b38007fd 100644 --- a/meson.build +++ b/meson.build @@ -2389,5 +2389,30 @@ if get_option('man') man1_dir = join_paths(glib_prefix, get_option('mandir'), 'man1') endif + +allocate_system = executable('allocators-test-system', + 'tests/allocators-tests.c', + c_args: [ + '-DG_LOG_DOMAIN="GLib-Benchmark"', + '-UG_DISABLE_ASSERT', + '-DG_USE_SYSTEM_ALLOCATOR', + ], + dependencies: libglib_dep, + install: false +) + +allocate_gslice = executable('allocators-test-gslice', + 'tests/allocators-tests.c', + c_args: [ + '-DG_LOG_DOMAIN="GLib-Benchmark"', + '-UG_DISABLE_ASSERT', + ], + dependencies: [libglib_dep], + install: false +) + +benchmark('allocate-system', allocate_system, timeout: 1000) +benchmark('allocate-gslice', allocate_gslice, timeout: 1000) + gnome = import('gnome') subdir('docs/reference') diff --git a/tests/allocators-tests.c b/tests/allocators-tests.c new file mode 100644 index 000000000..f17dfa785 --- /dev/null +++ b/tests/allocators-tests.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2022 Canonical Ltd. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + * + * Author: Marco Trevisan + */ + +#include + +/* These are to please CI, should be adjusted smartly */ +#define SIMPLE_TYPE_ITERATIONS 100000000 +#if defined(G_OS_UNIX) && !__APPLE__ +#define POINTERS_ARRAY_SIZE 1000000 +#elif defined(__APPLE__) +#define POINTERS_ARRAY_SIZE 100000 +#else +#define POINTERS_ARRAY_SIZE 10000 +#endif +#define MAX_ALLOCATED_SIZE (POINTERS_ARRAY_SIZE * 512) + +#ifdef G_USE_SYSTEM_ALLOCATOR +#define instance_alloc(s) g_malloc ((s)) +#define instance_alloc0(s) g_malloc0 ((s)) +#define instance_free(s, p) g_free ((p)) +#else +#define instance_alloc(s) g_slice_alloc ((s)) +#define instance_alloc0(s) g_slice_alloc0 ((s)) +#define instance_free(s, p) g_slice_free1 ((s), (p)) +#endif + +#define allocate_and_free_many(type, type_size, allocator, N) \ + { \ + guint i; \ + \ + for (i = 0; i < N; i++) \ + { \ + gpointer ptr = allocator (type_size); \ + instance_free (type_size, ptr); \ + } \ + } + +#define test_alloc_and_free(type, type_size, allocator, N) \ + { \ + gdouble time_elapsed; \ + \ + g_test_timer_start (); \ + \ + allocate_and_free_many (type, type_size, allocator, N); \ + \ + time_elapsed = g_test_timer_elapsed (); \ + g_test_minimized_result (time_elapsed, \ + "Allocated and free'd %u instances of %s " \ + "(size: %" G_GSIZE_FORMAT " using %s in %6.5f seconds", \ + N, #type, (gsize) type_size, #allocator, time_elapsed); \ + } + +#define test_alloc_many_and_free(type, type_size, allocator, N) \ + { \ + guint i; \ + gdouble time_elapsed; \ + gpointer *ptrs[N] = { 0 }; \ + gdouble total_time = 0; \ + \ + g_test_timer_start (); \ + \ + for (i = 0; i < N; i++) \ + ptrs[i] = allocator (type_size); \ + \ + time_elapsed = g_test_timer_elapsed (); \ + total_time += time_elapsed; \ + \ + g_test_minimized_result (time_elapsed, \ + "Allocated %u instances of %s (size: %" G_GSIZE_FORMAT \ + ") using %s in %6.5f seconds", \ + N, #type, (gsize) type_size, #allocator, time_elapsed); \ + \ + g_test_timer_start (); \ + \ + for (i = 0; i < N; i++) \ + instance_free (type_size, ptrs[i]); \ + \ + time_elapsed = g_test_timer_elapsed (); \ + total_time += time_elapsed; \ + \ + g_test_minimized_result (time_elapsed, \ + "Free'd %u instances of %s in %6.5f seconds", \ + N, #type, time_elapsed); \ + g_test_minimized_result (total_time, \ + "Allocated and Free'd %u instances of %s using %s " \ + "in %6.5f seconds", \ + N, #type, #allocator, total_time); \ + } + +#define test_allocation_simple_type(type) \ + static void \ + test_allocation_##type (void) \ + { \ + test_alloc_and_free (type, sizeof (type), instance_alloc, SIMPLE_TYPE_ITERATIONS); \ + test_alloc_and_free (type, sizeof (type), instance_alloc0, SIMPLE_TYPE_ITERATIONS); \ + \ + test_alloc_many_and_free (type, sizeof (type), instance_alloc, POINTERS_ARRAY_SIZE); \ + test_alloc_many_and_free (type, sizeof (type), instance_alloc0, POINTERS_ARRAY_SIZE); \ + } + +#define test_allocation_sized(size) \ + static void \ + test_allocation_sized_##size (void) \ + { \ + test_alloc_and_free ("struct" #size, size, instance_alloc, SIMPLE_TYPE_ITERATIONS); \ + test_alloc_and_free ("struct" #size, size, instance_alloc0, SIMPLE_TYPE_ITERATIONS); \ + \ + test_alloc_many_and_free ("struct" #size, size, instance_alloc, \ + MIN (POINTERS_ARRAY_SIZE, MAX_ALLOCATED_SIZE / size)); \ + test_alloc_many_and_free ("struct" #size, size, instance_alloc0, \ + MIN (POINTERS_ARRAY_SIZE, MAX_ALLOCATED_SIZE / size)); \ + } + +#define test_allocate_and_free_many_mixed(max_steps, allocator, N) \ + { \ + guint i; \ + gdouble time_elapsed; \ + GArray *steps_size = g_array_sized_new (FALSE, FALSE, sizeof (gsize), max_steps); \ + \ + for (i = 0; i < max_steps; i++) \ + { \ + gsize size = 1 << (i + 1); \ + if (g_test_verbose ()) \ + g_test_message ("Step allocation size %" G_GSIZE_FORMAT, size); \ + g_array_insert_val (steps_size, i, size); \ + } \ + \ + g_test_timer_start (); \ + \ + for (i = 0; i < N; i++) \ + { \ + gsize element_size = g_array_index (steps_size, gsize, (i % max_steps)); \ + gpointer ptr = allocator (element_size); \ + instance_free (element_size, ptr); \ + } \ + \ + time_elapsed = g_test_timer_elapsed (); \ + g_test_minimized_result (time_elapsed, \ + "Allocated and free'd %u instances of mixed types " \ + "(step: %s) using %s in %6.5f seconds", \ + N, #max_steps, #allocator, time_elapsed); \ + } + +#define test_allocation_mixed_sizes(max_steps) \ + static void \ + test_allocation_mixed_step_##max_steps (void) \ + { \ + gsize step_size = 0; \ + gint i; \ + \ + for (i = 0; i < max_steps; i++) \ + step_size += 1 << (i + 1); \ + (void) step_size; \ + \ + test_allocate_and_free_many_mixed (max_steps, instance_alloc, \ + SIMPLE_TYPE_ITERATIONS); \ + test_allocate_and_free_many_mixed (max_steps, instance_alloc0, \ + SIMPLE_TYPE_ITERATIONS); \ + } + +test_allocation_simple_type (gchar); +test_allocation_simple_type (gshort); +test_allocation_simple_type (glong); +test_allocation_simple_type (gint); +test_allocation_simple_type (gboolean); +test_allocation_simple_type (guchar); +test_allocation_simple_type (gushort); +test_allocation_simple_type (gulong); +test_allocation_simple_type (guint); +test_allocation_simple_type (gfloat); +test_allocation_simple_type (gdouble); +test_allocation_simple_type (gpointer); + +test_allocation_sized (32); +test_allocation_sized (64); +test_allocation_sized (128); +test_allocation_sized (256); +test_allocation_sized (512); +test_allocation_sized (1024); +test_allocation_sized (2048); +test_allocation_sized (4096); + +test_allocation_mixed_sizes (8); +test_allocation_mixed_sizes (12); + +#ifdef G_USE_SYSTEM_ALLOCATOR +#define TEST_BASENAME "/allocation/system" +#else +#define TEST_BASENAME "/allocation/gslice" +#endif + +int +main (int argc, char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func (TEST_BASENAME "/simple-type/gchar", test_allocation_gchar); + g_test_add_func (TEST_BASENAME "/simple-type/gshort", test_allocation_gshort); + g_test_add_func (TEST_BASENAME "/simple-type/glong", test_allocation_glong); + g_test_add_func (TEST_BASENAME "/simple-type/gint", test_allocation_gint); + g_test_add_func (TEST_BASENAME "/simple-type/gboolean", test_allocation_gboolean); + g_test_add_func (TEST_BASENAME "/simple-type/guchar", test_allocation_guchar); + g_test_add_func (TEST_BASENAME "/simple-type/gushort", test_allocation_gushort); + g_test_add_func (TEST_BASENAME "/simple-type/gulong", test_allocation_gulong); + g_test_add_func (TEST_BASENAME "/simple-type/guint", test_allocation_guint); + g_test_add_func (TEST_BASENAME "/simple-type/gfloat", test_allocation_gfloat); + g_test_add_func (TEST_BASENAME "/simple-type/gdouble", test_allocation_gdouble); + g_test_add_func (TEST_BASENAME "/simple-type/gpointer", test_allocation_gpointer); + + g_test_add_func (TEST_BASENAME "/sized/32", test_allocation_sized_32); + g_test_add_func (TEST_BASENAME "/sized/64", test_allocation_sized_64); + g_test_add_func (TEST_BASENAME "/sized/128", test_allocation_sized_128); + g_test_add_func (TEST_BASENAME "/sized/256", test_allocation_sized_256); + g_test_add_func (TEST_BASENAME "/sized/512", test_allocation_sized_512); + g_test_add_func (TEST_BASENAME "/sized/1024", test_allocation_sized_1024); + g_test_add_func (TEST_BASENAME "/sized/2048", test_allocation_sized_2048); + g_test_add_func (TEST_BASENAME "/sized/4096", test_allocation_sized_4096); + + g_test_add_func (TEST_BASENAME "/mixed/8", test_allocation_mixed_step_8); + g_test_add_func (TEST_BASENAME "/mixed/12", test_allocation_mixed_step_12); + + return g_test_run (); +}