mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-23 10:42:11 +01:00
264 lines
15 KiB
C
264 lines
15 KiB
C
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Author: Marco Trevisan <marco.trevisan@canonical.com>
|
|
*/
|
|
|
|
#include <glib.h>
|
|
|
|
/* 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
|
|
|
|
static void
|
|
csv_report (const char *allocator, gint iterations, gdouble time_elapsed)
|
|
{
|
|
g_test_message ("CSV: %s/%s/%d,%f",
|
|
g_test_get_path (), allocator, iterations, time_elapsed);
|
|
}
|
|
|
|
#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); \
|
|
csv_report (#allocator, N, 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); \
|
|
csv_report (#allocator, N, 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); \
|
|
csv_report ("free", N, 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); \
|
|
\
|
|
csv_report (#allocator "+free", N, 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); \
|
|
csv_report (#allocator, N, 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_GNUC_BEGIN_IGNORE_DEPRECATIONS;
|
|
g_test_message ("GSlice will use a chunk size of %" G_GINT64_FORMAT,
|
|
g_slice_get_config (G_SLICE_CONFIG_CHUNK_SIZES));
|
|
G_GNUC_END_IGNORE_DEPRECATIONS;
|
|
|
|
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);
|
|
|
|
/* FIXME: Depending on the OS we should only test up to the size that the
|
|
* GSlice would support, otherwise we'd get system allocator anyways.
|
|
*/
|
|
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 ();
|
|
}
|