Merge branch 'remove-gslice-allocator' into 'main'

gslice: remove slice allocator

Closes #1079

See merge request GNOME/glib!2935
This commit is contained in:
Philip Withnall 2023-01-25 14:09:58 +00:00
commit 0f7797d76d
14 changed files with 71 additions and 3434 deletions

7
NEWS
View File

@ -1,3 +1,10 @@
Overview of changes in GLib 2.75.3, UNRELEASED
==============================================
* Drop the implementation of GSlice, and make the API use the system `malloc()`
internally (#1079) (based on investigation work by multiple people)
Overview of changes in GLib 2.75.2, 2023-01-06
==============================================

View File

@ -165,53 +165,10 @@ How to run and debug your GLib application
<title><envar>G_SLICE</envar></title>
<para>
This environment variable allows reconfiguration of the GSlice
memory allocator.
<variablelist>
<varlistentry>
<term>always-malloc</term>
<listitem><para>This will cause all slices allocated through
g_slice_alloc() and released by g_slice_free1() to be actually
allocated via direct calls to g_malloc() and g_free().
This is most useful for memory checkers and similar programs that
use Boehm GC alike algorithms to produce more accurate results.
It can also be in conjunction with debugging features of the system's
malloc() implementation such as glibc's MALLOC_CHECK_=2 to debug
erroneous slice allocation code, although
<literal>debug-blocks</literal> is usually a better suited debugging
tool.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>debug-blocks</term>
<listitem><para>Using this option (present since GLib 2.13) engages
extra code which performs sanity checks on the released memory
slices. Invalid slice addresses or slice sizes will be reported and
lead to a program halt. This option is for debugging scenarios.
In particular, client packages sporting their own test suite should
<emphasis>always enable this option when running tests</emphasis>.
Global slice validation is ensured by storing size and address
information for each allocated chunk, and maintaining a global
hash table of that data. That way, multi-thread scalability is
given up, and memory consumption is increased. However, the
resulting code usually performs acceptably well, possibly better
than with comparable memory checking carried out using external
tools.</para>
<para>An example of a memory corruption scenario that cannot be
reproduced with <literal>G_SLICE=always-malloc</literal>, but will
be caught by <literal>G_SLICE=debug-blocks</literal> is as follows:
<programlisting>
/* void* gives up type-safety */
void *slist = g_slist_alloc ();
/* corruption: sizeof (GSList) != sizeof (GList) */
g_list_free (slist);
</programlisting></para>
</listitem>
</varlistentry>
</variablelist>
The special value <literal>all</literal> can be used to turn on all options.
The special value <literal>help</literal> can be used to print all available options.
This environment variable allowed reconfiguration of the GSlice
memory allocator. Since GLib 2.76, GSlice uses the system
<literal>malloc()</literal> implementation internally, so this variable is
ignored.
</para>
</formalpara>

File diff suppressed because it is too large Load Diff

View File

@ -1,603 +0,0 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* 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/>.
*/
/*
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GLib Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GLib at ftp://ftp.gtk.org/pub/gtk/.
*/
/*
* MT safe
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "glib.h"
/* notes on macros:
* if ENABLE_GC_FRIENDLY is defined, freed memory should be 0-wiped.
*/
#define MEM_PROFILE_TABLE_SIZE 4096
#define MEM_AREA_SIZE 4L
static guint mem_chunk_recursion = 0;
# define MEM_CHUNK_ROUTINE_COUNT() (mem_chunk_recursion)
# define ENTER_MEM_CHUNK_ROUTINE() (mem_chunk_recursion = MEM_CHUNK_ROUTINE_COUNT () + 1)
# define LEAVE_MEM_CHUNK_ROUTINE() (mem_chunk_recursion = MEM_CHUNK_ROUTINE_COUNT () - 1)
/* --- old memchunk prototypes --- */
GMemChunk* old_mem_chunk_new (const gchar *name,
gulong atom_size,
gulong area_size,
gint type);
void old_mem_chunk_destroy (GMemChunk *mem_chunk);
gpointer old_mem_chunk_alloc (GMemChunk *mem_chunk);
gpointer old_mem_chunk_alloc0 (GMemChunk *mem_chunk);
void old_mem_chunk_free (GMemChunk *mem_chunk,
gpointer mem);
void old_mem_chunk_clean (GMemChunk *mem_chunk);
void old_mem_chunk_reset (GMemChunk *mem_chunk);
void old_mem_chunk_print (GMemChunk *mem_chunk);
void old_mem_chunk_info (void);
/* --- MemChunks --- */
#ifndef G_ALLOC_AND_FREE
typedef struct _GAllocator GAllocator;
typedef struct _GMemChunk GMemChunk;
#define G_ALLOC_ONLY 1
#define G_ALLOC_AND_FREE 2
#endif
typedef struct _GFreeAtom GFreeAtom;
typedef struct _GMemArea GMemArea;
struct _GFreeAtom
{
GFreeAtom *next;
};
struct _GMemArea
{
GMemArea *next; /* the next mem area */
GMemArea *prev; /* the previous mem area */
gulong index; /* the current index into the "mem" array */
gulong free; /* the number of free bytes in this mem area */
gulong allocated; /* the number of atoms allocated from this area */
gulong mark; /* is this mem area marked for deletion */
gchar mem[MEM_AREA_SIZE]; /* the mem array from which atoms get allocated
* the actual size of this array is determined by
* the mem chunk "area_size". ANSI says that it
* must be declared to be the maximum size it
* can possibly be (even though the actual size
* may be less).
*/
};
struct _GMemChunk
{
const gchar *name; /* name of this MemChunk...used for debugging output */
gint type; /* the type of MemChunk: ALLOC_ONLY or ALLOC_AND_FREE */
gint num_mem_areas; /* the number of memory areas */
gint num_marked_areas; /* the number of areas marked for deletion */
guint atom_size; /* the size of an atom */
gulong area_size; /* the size of a memory area */
GMemArea *mem_area; /* the current memory area */
GMemArea *mem_areas; /* a list of all the mem areas owned by this chunk */
GMemArea *free_mem_area; /* the free area...which is about to be destroyed */
GFreeAtom *free_atoms; /* the free atoms list */
GTree *mem_tree; /* tree of mem areas sorted by memory address */
GMemChunk *next; /* pointer to the next chunk */
GMemChunk *prev; /* pointer to the previous chunk */
};
static gulong old_mem_chunk_compute_size (gulong size,
gulong min_size) G_GNUC_CONST;
static gint old_mem_chunk_area_compare (GMemArea *a,
GMemArea *b);
static gint old_mem_chunk_area_search (GMemArea *a,
gchar *addr);
/* here we can't use StaticMutexes, as they depend upon a working
* g_malloc, the same holds true for StaticPrivate
*/
static GMutex mem_chunks_lock;
static GMemChunk *mem_chunks = NULL;
GMemChunk*
old_mem_chunk_new (const gchar *name,
gulong atom_size,
gulong area_size,
gint type)
{
GMemChunk *mem_chunk;
gulong rarea_size;
g_return_val_if_fail (atom_size > 0, NULL);
g_return_val_if_fail (area_size >= atom_size, NULL);
ENTER_MEM_CHUNK_ROUTINE ();
area_size = (area_size + atom_size - 1) / atom_size;
area_size *= atom_size;
mem_chunk = g_new (GMemChunk, 1);
mem_chunk->name = name;
mem_chunk->type = type;
mem_chunk->num_mem_areas = 0;
mem_chunk->num_marked_areas = 0;
mem_chunk->mem_area = NULL;
mem_chunk->free_mem_area = NULL;
mem_chunk->free_atoms = NULL;
mem_chunk->mem_tree = NULL;
mem_chunk->mem_areas = NULL;
mem_chunk->atom_size = atom_size;
if (mem_chunk->type == G_ALLOC_AND_FREE)
mem_chunk->mem_tree = g_tree_new ((GCompareFunc) old_mem_chunk_area_compare);
if (mem_chunk->atom_size % G_MEM_ALIGN)
mem_chunk->atom_size += G_MEM_ALIGN - (mem_chunk->atom_size % G_MEM_ALIGN);
rarea_size = area_size + sizeof (GMemArea) - MEM_AREA_SIZE;
rarea_size = old_mem_chunk_compute_size (rarea_size, atom_size + sizeof (GMemArea) - MEM_AREA_SIZE);
mem_chunk->area_size = rarea_size - (sizeof (GMemArea) - MEM_AREA_SIZE);
g_mutex_lock (&mem_chunks_lock);
mem_chunk->next = mem_chunks;
mem_chunk->prev = NULL;
if (mem_chunks)
mem_chunks->prev = mem_chunk;
mem_chunks = mem_chunk;
g_mutex_unlock (&mem_chunks_lock);
LEAVE_MEM_CHUNK_ROUTINE ();
return mem_chunk;
}
void
old_mem_chunk_destroy (GMemChunk *mem_chunk)
{
GMemArea *mem_areas;
GMemArea *temp_area;
g_return_if_fail (mem_chunk != NULL);
ENTER_MEM_CHUNK_ROUTINE ();
mem_areas = mem_chunk->mem_areas;
while (mem_areas)
{
temp_area = mem_areas;
mem_areas = mem_areas->next;
g_free (temp_area);
}
g_mutex_lock (&mem_chunks_lock);
if (mem_chunk->next)
mem_chunk->next->prev = mem_chunk->prev;
if (mem_chunk->prev)
mem_chunk->prev->next = mem_chunk->next;
if (mem_chunk == mem_chunks)
mem_chunks = mem_chunks->next;
g_mutex_unlock (&mem_chunks_lock);
if (mem_chunk->type == G_ALLOC_AND_FREE)
g_tree_destroy (mem_chunk->mem_tree);
g_free (mem_chunk);
LEAVE_MEM_CHUNK_ROUTINE ();
}
gpointer
old_mem_chunk_alloc (GMemChunk *mem_chunk)
{
GMemArea *temp_area;
gpointer mem;
ENTER_MEM_CHUNK_ROUTINE ();
g_return_val_if_fail (mem_chunk != NULL, NULL);
while (mem_chunk->free_atoms)
{
/* Get the first piece of memory on the "free_atoms" list.
* We can go ahead and destroy the list node we used to keep
* track of it with and to update the "free_atoms" list to
* point to its next element.
*/
mem = mem_chunk->free_atoms;
mem_chunk->free_atoms = mem_chunk->free_atoms->next;
/* Determine which area this piece of memory is allocated from */
temp_area = g_tree_search (mem_chunk->mem_tree,
(GCompareFunc) old_mem_chunk_area_search,
mem);
/* If the area has been marked, then it is being destroyed.
* (ie marked to be destroyed).
* We check to see if all of the segments on the free list that
* reference this area have been removed. This occurs when
* the amount of free memory is less than the allocatable size.
* If the chunk should be freed, then we place it in the "free_mem_area".
* This is so we make sure not to free the mem area here and then
* allocate it again a few lines down.
* If we don't allocate a chunk a few lines down then the "free_mem_area"
* will be freed.
* If there is already a "free_mem_area" then we'll just free this mem area.
*/
if (temp_area->mark)
{
/* Update the "free" memory available in that area */
temp_area->free += mem_chunk->atom_size;
if (temp_area->free == mem_chunk->area_size)
{
if (temp_area == mem_chunk->mem_area)
mem_chunk->mem_area = NULL;
if (mem_chunk->free_mem_area)
{
mem_chunk->num_mem_areas -= 1;
if (temp_area->next)
temp_area->next->prev = temp_area->prev;
if (temp_area->prev)
temp_area->prev->next = temp_area->next;
if (temp_area == mem_chunk->mem_areas)
mem_chunk->mem_areas = mem_chunk->mem_areas->next;
if (mem_chunk->type == G_ALLOC_AND_FREE)
g_tree_remove (mem_chunk->mem_tree, temp_area);
g_free (temp_area);
}
else
mem_chunk->free_mem_area = temp_area;
mem_chunk->num_marked_areas -= 1;
}
}
else
{
/* Update the number of allocated atoms count.
*/
temp_area->allocated += 1;
/* The area wasn't marked...return the memory
*/
goto outa_here;
}
}
/* If there isn't a current mem area or the current mem area is out of space
* then allocate a new mem area. We'll first check and see if we can use
* the "free_mem_area". Otherwise we'll just malloc the mem area.
*/
if ((!mem_chunk->mem_area) ||
((mem_chunk->mem_area->index + mem_chunk->atom_size) > mem_chunk->area_size))
{
if (mem_chunk->free_mem_area)
{
mem_chunk->mem_area = mem_chunk->free_mem_area;
mem_chunk->free_mem_area = NULL;
}
else
{
#ifdef ENABLE_GC_FRIENDLY
mem_chunk->mem_area = (GMemArea*) g_malloc0 (sizeof (GMemArea) -
MEM_AREA_SIZE +
mem_chunk->area_size);
#else /* !ENABLE_GC_FRIENDLY */
mem_chunk->mem_area = (GMemArea*) g_malloc (sizeof (GMemArea) -
MEM_AREA_SIZE +
mem_chunk->area_size);
#endif /* ENABLE_GC_FRIENDLY */
mem_chunk->num_mem_areas += 1;
mem_chunk->mem_area->next = mem_chunk->mem_areas;
mem_chunk->mem_area->prev = NULL;
if (mem_chunk->mem_areas)
mem_chunk->mem_areas->prev = mem_chunk->mem_area;
mem_chunk->mem_areas = mem_chunk->mem_area;
if (mem_chunk->type == G_ALLOC_AND_FREE)
g_tree_insert (mem_chunk->mem_tree, mem_chunk->mem_area, mem_chunk->mem_area);
}
mem_chunk->mem_area->index = 0;
mem_chunk->mem_area->free = mem_chunk->area_size;
mem_chunk->mem_area->allocated = 0;
mem_chunk->mem_area->mark = 0;
}
/* Get the memory and modify the state variables appropriately.
*/
mem = (gpointer) &mem_chunk->mem_area->mem[mem_chunk->mem_area->index];
mem_chunk->mem_area->index += mem_chunk->atom_size;
mem_chunk->mem_area->free -= mem_chunk->atom_size;
mem_chunk->mem_area->allocated += 1;
outa_here:
LEAVE_MEM_CHUNK_ROUTINE ();
return mem;
}
gpointer
old_mem_chunk_alloc0 (GMemChunk *mem_chunk)
{
gpointer mem;
mem = old_mem_chunk_alloc (mem_chunk);
if (mem)
{
memset (mem, 0, mem_chunk->atom_size);
}
return mem;
}
void
old_mem_chunk_free (GMemChunk *mem_chunk,
gpointer mem)
{
GMemArea *temp_area;
GFreeAtom *free_atom;
g_return_if_fail (mem_chunk != NULL);
g_return_if_fail (mem != NULL);
ENTER_MEM_CHUNK_ROUTINE ();
#ifdef ENABLE_GC_FRIENDLY
memset (mem, 0, mem_chunk->atom_size);
#endif /* ENABLE_GC_FRIENDLY */
/* Don't do anything if this is an ALLOC_ONLY chunk
*/
if (mem_chunk->type == G_ALLOC_AND_FREE)
{
/* Place the memory on the "free_atoms" list
*/
free_atom = (GFreeAtom*) mem;
free_atom->next = mem_chunk->free_atoms;
mem_chunk->free_atoms = free_atom;
temp_area = g_tree_search (mem_chunk->mem_tree,
(GCompareFunc) old_mem_chunk_area_search,
mem);
temp_area->allocated -= 1;
if (temp_area->allocated == 0)
{
temp_area->mark = 1;
mem_chunk->num_marked_areas += 1;
}
}
LEAVE_MEM_CHUNK_ROUTINE ();
}
/* This doesn't free the free_area if there is one */
void
old_mem_chunk_clean (GMemChunk *mem_chunk)
{
GMemArea *mem_area;
GFreeAtom *prev_free_atom;
GFreeAtom *temp_free_atom;
gpointer mem;
g_return_if_fail (mem_chunk != NULL);
ENTER_MEM_CHUNK_ROUTINE ();
if (mem_chunk->type == G_ALLOC_AND_FREE)
{
prev_free_atom = NULL;
temp_free_atom = mem_chunk->free_atoms;
while (temp_free_atom)
{
mem = (gpointer) temp_free_atom;
mem_area = g_tree_search (mem_chunk->mem_tree,
(GCompareFunc) old_mem_chunk_area_search,
mem);
/* If this mem area is marked for destruction then delete the
* area and list node and decrement the free mem.
*/
if (mem_area->mark)
{
if (prev_free_atom)
prev_free_atom->next = temp_free_atom->next;
else
mem_chunk->free_atoms = temp_free_atom->next;
temp_free_atom = temp_free_atom->next;
mem_area->free += mem_chunk->atom_size;
if (mem_area->free == mem_chunk->area_size)
{
mem_chunk->num_mem_areas -= 1;
mem_chunk->num_marked_areas -= 1;
if (mem_area->next)
mem_area->next->prev = mem_area->prev;
if (mem_area->prev)
mem_area->prev->next = mem_area->next;
if (mem_area == mem_chunk->mem_areas)
mem_chunk->mem_areas = mem_chunk->mem_areas->next;
if (mem_area == mem_chunk->mem_area)
mem_chunk->mem_area = NULL;
if (mem_chunk->type == G_ALLOC_AND_FREE)
g_tree_remove (mem_chunk->mem_tree, mem_area);
g_free (mem_area);
}
}
else
{
prev_free_atom = temp_free_atom;
temp_free_atom = temp_free_atom->next;
}
}
}
LEAVE_MEM_CHUNK_ROUTINE ();
}
void
old_mem_chunk_reset (GMemChunk *mem_chunk)
{
GMemArea *mem_areas;
GMemArea *temp_area;
g_return_if_fail (mem_chunk != NULL);
ENTER_MEM_CHUNK_ROUTINE ();
mem_areas = mem_chunk->mem_areas;
mem_chunk->num_mem_areas = 0;
mem_chunk->mem_areas = NULL;
mem_chunk->mem_area = NULL;
while (mem_areas)
{
temp_area = mem_areas;
mem_areas = mem_areas->next;
g_free (temp_area);
}
mem_chunk->free_atoms = NULL;
if (mem_chunk->mem_tree)
{
g_tree_destroy (mem_chunk->mem_tree);
mem_chunk->mem_tree = g_tree_new ((GCompareFunc) old_mem_chunk_area_compare);
}
LEAVE_MEM_CHUNK_ROUTINE ();
}
void
old_mem_chunk_print (GMemChunk *mem_chunk)
{
GMemArea *mem_areas;
gulong mem;
g_return_if_fail (mem_chunk != NULL);
mem_areas = mem_chunk->mem_areas;
mem = 0;
while (mem_areas)
{
mem += mem_chunk->area_size - mem_areas->free;
mem_areas = mem_areas->next;
}
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO,
"%s: %ld bytes using %d mem areas",
mem_chunk->name, mem, mem_chunk->num_mem_areas);
}
void
old_mem_chunk_info (void)
{
GMemChunk *mem_chunk;
gint count;
count = 0;
g_mutex_lock (&mem_chunks_lock);
mem_chunk = mem_chunks;
while (mem_chunk)
{
count += 1;
mem_chunk = mem_chunk->next;
}
g_mutex_unlock (&mem_chunks_lock);
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%d mem chunks", count);
g_mutex_lock (&mem_chunks_lock);
mem_chunk = mem_chunks;
g_mutex_unlock (&mem_chunks_lock);
while (mem_chunk)
{
old_mem_chunk_print ((GMemChunk*) mem_chunk);
mem_chunk = mem_chunk->next;
}
}
static gulong
old_mem_chunk_compute_size (gulong size,
gulong min_size)
{
gulong power_of_2;
gulong lower, upper;
power_of_2 = 16;
while (power_of_2 < size)
power_of_2 <<= 1;
lower = power_of_2 >> 1;
upper = power_of_2;
if (size - lower < upper - size && lower >= min_size)
return lower;
else
return upper;
}
static gint
old_mem_chunk_area_compare (GMemArea *a,
GMemArea *b)
{
if (a->mem > b->mem)
return 1;
else if (a->mem < b->mem)
return -1;
return 0;
}
static gint
old_mem_chunk_area_search (GMemArea *a,
gchar *addr)
{
if (a->mem <= addr)
{
if (addr < &a->mem[a->index])
return 0;
return 1;
}
return -1;
}

View File

@ -103,16 +103,6 @@ glib_tests = {
},
'shell' : {},
'slice' : {},
'slice-color' : {},
'slice-concurrent' : {},
'slice-known-pages' : {'suite' : ['no-valgrind']},
'slice-glib' : {},
'slice-slab' : {},
'slice-malloc' : {},
'slice-memchunk' : {
'source' : ['slice-memchunk.c', 'memchunks.c'],
},
'slice-eager-freeing' : {},
'slist' : {},
'sort' : {},
'spawn-multithreaded' : {

View File

@ -1,135 +0,0 @@
/* GLIB sliced memory - fast threaded memory chunk allocator
* Copyright (C) 2005 Tim Janik
*
* 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/>.
*/
#include <glib.h>
#define ALIGN(size, base) \
((base) * (gsize) (((size) + (base) - 1) / (base)))
static void
fill_memory (guint **mem,
guint n,
guint val)
{
guint j;
for (j = 0; j < n; j++)
mem[j][0] = val;
}
static guint64
access_memory3 (guint **mema,
guint **memb,
guint **memd,
guint n,
guint64 repeats)
{
guint64 accu = 0, i, j;
for (i = 0; i < repeats; i++)
{
for (j = 1; j < n; j += 2)
memd[j][0] = mema[j][0] + memb[j][0];
}
for (i = 0; i < repeats; i++)
for (j = 0; j < n; j++)
accu += memd[j][0];
return accu;
}
static void
touch_mem (guint64 block_size,
guint64 n_blocks,
guint64 repeats)
{
GTimer *timer;
guint **mema, **memb, **memc;
guint64 j, accu, n = n_blocks;
mema = g_new (guint*, n);
for (j = 0; j < n; j++)
mema[j] = g_slice_alloc (block_size);
memb = g_new (guint*, n);
for (j = 0; j < n; j++)
memb[j] = g_slice_alloc (block_size);
memc = g_new (guint*, n);
for (j = 0; j < n; j++)
memc[j] = g_slice_alloc (block_size);
timer = g_timer_new();
fill_memory (mema, n, 2);
fill_memory (memb, n, 3);
fill_memory (memc, n, 4);
access_memory3 (mema, memb, memc, n, 3);
g_timer_start (timer);
accu = access_memory3 (mema, memb, memc, n, repeats);
g_timer_stop (timer);
g_test_message ("Access-time = %fs", g_timer_elapsed (timer, NULL));
g_assert_cmpuint (accu / repeats, ==, (2 + 3) * n / 2 + 4 * n / 2);
for (j = 0; j < n; j++)
{
g_slice_free1 (block_size, mema[j]);
g_slice_free1 (block_size, memb[j]);
g_slice_free1 (block_size, memc[j]);
}
g_timer_destroy (timer);
g_free (mema);
g_free (memb);
g_free (memc);
}
static void
test_slice_colors (void)
{
guint64 block_size = 512;
guint64 area_size = 1024 * 1024;
guint64 n_blocks, repeats = 1000000;
/* figure number of blocks from block and area size.
* divide area by 3 because touch_mem() allocates 3 areas */
n_blocks = area_size / 3 / ALIGN (block_size, sizeof (gsize) * 2);
g_test_message ("Allocate and touch %" G_GUINT64_FORMAT
" blocks of %" G_GUINT64_FORMAT " bytes"
" (= %" G_GUINT64_FORMAT " bytes) %" G_GUINT64_FORMAT
" times with color increment",
n_blocks, block_size, n_blocks * block_size, repeats);
touch_mem (block_size, n_blocks, repeats);
}
int
main (int argc, char **argv)
{
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/slice/colors", test_slice_colors);
return g_test_run ();
}

View File

@ -1,135 +0,0 @@
/* test for gslice cross thread allocation/free
* Copyright (C) 2006 Stefan Westerfeld
* Copyright (C) 2007 Tim Janik
*
* 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/>.
*/
#include <glib.h>
#include <stdlib.h>
#define N_THREADS 8
#define N_ALLOCS 50000
#define MAX_BLOCK_SIZE 64
struct ThreadData
{
int thread_id;
GThread* gthread;
GMutex to_free_mutex;
void* to_free [N_THREADS * N_ALLOCS];
int bytes_to_free [N_THREADS * N_ALLOCS];
int n_to_free;
int n_freed;
} tdata[N_THREADS];
static void *
thread_func (void *arg)
{
int i;
struct ThreadData *td = arg;
GRand *thread_rand = g_rand_new ();
for (i = 0; i < N_ALLOCS; i++)
{
int bytes, f, t;
char *mem;
if (g_rand_int_range (thread_rand, 0, N_ALLOCS / 20) == 0)
g_test_message ("%c", 'a' - 1 + td->thread_id);
/* allocate block of random size and randomly fill */
bytes = g_rand_int_range (thread_rand, 0, MAX_BLOCK_SIZE) + 1;
mem = g_slice_alloc (bytes);
for (f = 0; f < bytes; f++)
mem[f] = (char) g_rand_int (thread_rand);
/* associate block with random thread */
t = g_rand_int_range (thread_rand, 0, N_THREADS);
g_mutex_lock (&tdata[t].to_free_mutex);
tdata[t].to_free[tdata[t].n_to_free] = mem;
tdata[t].bytes_to_free[tdata[t].n_to_free] = bytes;
tdata[t].n_to_free++;
g_mutex_unlock (&tdata[t].to_free_mutex);
/* shuffle thread execution order every once in a while */
if (g_rand_int_range (thread_rand, 0, 97) == 0)
{
if (g_rand_boolean (thread_rand))
g_thread_yield(); /* concurrent shuffling for single core */
else
g_usleep (1000); /* concurrent shuffling for multi core */
}
/* free a block associated with this thread */
g_mutex_lock (&td->to_free_mutex);
if (td->n_to_free > 0)
{
td->n_to_free--;
g_slice_free1 (td->bytes_to_free[td->n_to_free],
td->to_free[td->n_to_free]);
td->n_freed++;
}
g_mutex_unlock (&td->to_free_mutex);
}
g_rand_free (thread_rand);
return NULL;
}
static void
test_concurrent_slice (void)
{
int t;
for (t = 0; t < N_THREADS; t++)
{
tdata[t].thread_id = t + 1;
tdata[t].n_to_free = 0;
tdata[t].n_freed = 0;
}
for (t = 0; t < N_THREADS; t++)
{
tdata[t].gthread = g_thread_new (NULL, thread_func, &tdata[t]);
g_assert_nonnull (tdata[t].gthread);
}
for (t = 0; t < N_THREADS; t++)
{
g_thread_join (tdata[t].gthread);
}
for (t = 0; t < N_THREADS; t++)
{
g_test_message ("Thread %d: %d blocks freed, %d blocks not freed",
tdata[t].thread_id, tdata[t].n_freed, tdata[t].n_to_free);
}
}
int
main (int argc, char **argv)
{
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/slice/concurrent", test_concurrent_slice);
return g_test_run ();
}

View File

@ -1,158 +0,0 @@
/* GLIB sliced memory - fast threaded memory chunk allocator
* Copyright (C) 2005 Tim Janik
*
* 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/>.
*/
/* We are testing some deprecated APIs here */
#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#endif
#include <glib.h>
#define quick_rand32() \
(rand_accu = 1664525 * rand_accu + 1013904223, rand_accu)
static guint prime_size = 1021; /* 769; 509 */
static gboolean clean_memchunks = FALSE;
static guint number_of_blocks = 10000; /* total number of blocks allocated */
static guint number_of_repetitions = 10000; /* number of alloc+free repetitions */
static gboolean want_corruption = FALSE;
/* --- old memchunk prototypes (memchunks.c) --- */
GMemChunk* old_mem_chunk_new (const gchar *name,
gulong atom_size,
gulong area_size,
gint type);
void old_mem_chunk_destroy (GMemChunk *mem_chunk);
gpointer old_mem_chunk_alloc (GMemChunk *mem_chunk);
gpointer old_mem_chunk_alloc0 (GMemChunk *mem_chunk);
void old_mem_chunk_free (GMemChunk *mem_chunk,
gpointer mem);
void old_mem_chunk_clean (GMemChunk *mem_chunk);
void old_mem_chunk_reset (GMemChunk *mem_chunk);
void old_mem_chunk_print (GMemChunk *mem_chunk);
void old_mem_chunk_info (void);
#ifndef G_ALLOC_AND_FREE
#define G_ALLOC_AND_FREE 2
#endif
/* --- functions --- */
static inline int
corruption (void)
{
if (G_UNLIKELY (want_corruption))
{
/* corruption per call likelyness is about 1:4000000 */
guint32 r = g_random_int() % 8000009;
return r == 277 ? +1 : r == 281 ? -1 : 0;
}
return 0;
}
static gpointer
test_sliced_mem_thread (gpointer data)
{
guint32 rand_accu = 2147483563;
guint i, j;
guint8 **ps;
guint *ss;
/* initialize random numbers */
if (data)
rand_accu = *(guint32*) data;
else
{
GTimeVal rand_tv;
g_get_current_time (&rand_tv);
rand_accu = rand_tv.tv_usec + (rand_tv.tv_sec << 16);
}
ps = g_new (guint8*, number_of_blocks);
ss = g_new (guint, number_of_blocks);
/* create number_of_blocks random sizes */
for (i = 0; i < number_of_blocks; i++)
ss[i] = quick_rand32() % prime_size;
/* allocate number_of_blocks blocks */
for (i = 0; i < number_of_blocks; i++)
ps[i] = g_slice_alloc (ss[i] + corruption());
for (j = 0; j < number_of_repetitions; j++)
{
/* free number_of_blocks/2 blocks */
for (i = 0; i < number_of_blocks; i += 2)
g_slice_free1 (ss[i] + corruption(), ps[i] + corruption());
/* allocate number_of_blocks/2 blocks with new sizes */
for (i = 0; i < number_of_blocks; i += 2)
{
ss[i] = quick_rand32() % prime_size;
ps[i] = g_slice_alloc (ss[i] + corruption());
}
}
/* free number_of_blocks blocks */
for (i = 0; i < number_of_blocks; i++)
g_slice_free1 (ss[i] + corruption(), ps[i] + corruption());
/* alloc and free many equally sized chunks in a row */
for (i = 0; i < number_of_repetitions; i++)
{
guint sz = quick_rand32() % prime_size;
guint k = number_of_blocks / 100;
for (j = 0; j < k; j++)
ps[j] = g_slice_alloc (sz + corruption());
for (j = 0; j < k; j++)
g_slice_free1 (sz + corruption(), ps[j] + corruption());
}
g_free (ps);
g_free (ss);
return NULL;
}
static void
test_slice_eager_freeing (void)
{
GThread **threads;
guint i, n_threads = 1;
clean_memchunks = TRUE;
g_test_message ("Starting %d threads allocating random blocks <= %u bytes",
n_threads, prime_size);
threads = g_alloca (sizeof(GThread*) * n_threads);
for (i = 0; i < n_threads; i++)
threads[i] = g_thread_create (test_sliced_mem_thread, NULL, TRUE, NULL);
for (i = 0; i < n_threads; i++)
g_thread_join (threads[i]);
clean_memchunks = FALSE;
}
int
main (int argc,
char *argv[])
{
g_slice_set_config (G_SLICE_CONFIG_WORKING_SET_MSECS, 0);
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/slice/eager-freeing", test_slice_eager_freeing);
return g_test_run ();
}

View File

@ -1,154 +0,0 @@
/* GLIB sliced memory - fast threaded memory chunk allocator
* Copyright (C) 2005 Tim Janik
*
* 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/>.
*/
/* We are testing some deprecated APIs here */
#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#endif
#include <glib.h>
#define quick_rand32() \
(rand_accu = 1664525 * rand_accu + 1013904223, rand_accu)
static guint prime_size = 1021; /* 769; 509 */
static guint number_of_blocks = 10000; /* total number of blocks allocated */
static guint number_of_repetitions = 10000; /* number of alloc+free repetitions */
static gboolean want_corruption = FALSE;
/* --- old memchunk prototypes (memchunks.c) --- */
GMemChunk* old_mem_chunk_new (const gchar *name,
gulong atom_size,
gulong area_size,
gint type);
void old_mem_chunk_destroy (GMemChunk *mem_chunk);
gpointer old_mem_chunk_alloc (GMemChunk *mem_chunk);
gpointer old_mem_chunk_alloc0 (GMemChunk *mem_chunk);
void old_mem_chunk_free (GMemChunk *mem_chunk,
gpointer mem);
void old_mem_chunk_clean (GMemChunk *mem_chunk);
void old_mem_chunk_reset (GMemChunk *mem_chunk);
void old_mem_chunk_print (GMemChunk *mem_chunk);
void old_mem_chunk_info (void);
#ifndef G_ALLOC_AND_FREE
#define G_ALLOC_AND_FREE 2
#endif
/* --- functions --- */
static inline int
corruption (void)
{
if (G_UNLIKELY (want_corruption))
{
/* corruption per call likelyness is about 1:4000000 */
guint32 r = g_random_int() % 8000009;
return r == 277 ? +1 : r == 281 ? -1 : 0;
}
return 0;
}
static gpointer
test_sliced_mem_thread (gpointer data)
{
guint32 rand_accu = 2147483563;
guint i, j;
guint8 **ps;
guint *ss;
/* initialize random numbers */
if (data)
rand_accu = *(guint32*) data;
else
{
GTimeVal rand_tv;
g_get_current_time (&rand_tv);
rand_accu = rand_tv.tv_usec + (rand_tv.tv_sec << 16);
}
ps = g_new (guint8*, number_of_blocks);
ss = g_new (guint, number_of_blocks);
/* create number_of_blocks random sizes */
for (i = 0; i < number_of_blocks; i++)
ss[i] = quick_rand32() % prime_size;
/* allocate number_of_blocks blocks */
for (i = 0; i < number_of_blocks; i++)
ps[i] = g_slice_alloc (ss[i] + corruption());
for (j = 0; j < number_of_repetitions; j++)
{
/* free number_of_blocks/2 blocks */
for (i = 0; i < number_of_blocks; i += 2)
g_slice_free1 (ss[i] + corruption(), ps[i] + corruption());
/* allocate number_of_blocks/2 blocks with new sizes */
for (i = 0; i < number_of_blocks; i += 2)
{
ss[i] = quick_rand32() % prime_size;
ps[i] = g_slice_alloc (ss[i] + corruption());
}
}
/* free number_of_blocks blocks */
for (i = 0; i < number_of_blocks; i++)
g_slice_free1 (ss[i] + corruption(), ps[i] + corruption());
/* alloc and free many equally sized chunks in a row */
for (i = 0; i < number_of_repetitions; i++)
{
guint sz = quick_rand32() % prime_size;
guint k = number_of_blocks / 100;
for (j = 0; j < k; j++)
ps[j] = g_slice_alloc (sz + corruption());
for (j = 0; j < k; j++)
g_slice_free1 (sz + corruption(), ps[j] + corruption());
}
g_free (ps);
g_free (ss);
return NULL;
}
static void
test_slice_glib (void)
{
GThread **threads;
guint i, n_threads = 1;
g_test_message ("Starting %d threads allocating random blocks <= %u bytes",
n_threads, prime_size);
threads = g_alloca (sizeof(GThread*) * n_threads);
for (i = 0; i < n_threads; i++)
threads[i] = g_thread_create (test_sliced_mem_thread, NULL, TRUE, NULL);
for (i = 0; i < n_threads; i++)
g_thread_join (threads[i]);
}
int
main (int argc,
char *argv[])
{
g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, FALSE);
g_slice_set_config (G_SLICE_CONFIG_BYPASS_MAGAZINES, FALSE);
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/slice/glib", test_slice_glib);
return g_test_run ();
}

View File

@ -1,175 +0,0 @@
/* slice-known-pages.c - test GSlice across known pages
* Copyright (C) 2007 Tim Janik
*
* SPDX-License-Identifier: LicenseRef-old-glib-tests
*
* This work is provided "as is"; redistribution and modification
* in whole or in part, in any medium, physical or electronic is
* permitted without restriction.
*
* This work 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.
*
* In no event shall the authors or contributors be liable for any
* direct, indirect, incidental, special, exemplary, or consequential
* damages (including, but not limited to, procurement of substitute
* goods or services; loss of use, data, or profits; or business
* interruption) however caused and on any theory of liability, whether
* in contract, strict liability, or tort (including negligence or
* otherwise) arising in any way out of the use of this software, even
* if advised of the possibility of such damage.
*/
#include <glib.h>
#define N_PAGES (101) /* number of pages to sample */
#define SAMPLE_SIZE (7)
#define PAGE_SIZE (128) /* must be <= minimum GSlice alignment block */
#define MAGAZINE_PROBES \
{ \
97, 265, 347 \
} /* block sizes hopefully unused */
#define MAX_PROBE_TRIALS (1031) /* must be >= maximum magazine size */
#define ALIGN(size, base) \
((base) * (gsize) (((size) + (base) - 1) / (base)))
static struct {
void *page;
void *sample;
} pages[N_PAGES] = { { NULL, NULL }, };
static const guint magazine_probes[] = MAGAZINE_PROBES;
#define N_MAGAZINE_PROBES G_N_ELEMENTS (magazine_probes)
static void
release_trash_list (GSList **trash_list,
gsize block_size)
{
while (*trash_list)
{
g_slice_free1 (block_size, (*trash_list)->data);
*trash_list = g_slist_delete_link (*trash_list, *trash_list);
}
}
static GSList *free_list = NULL;
static gboolean
allocate_from_known_page (void)
{
guint i, j, n_trials = N_PAGES * PAGE_SIZE / SAMPLE_SIZE; /* upper bound */
for (i = 0; i < n_trials; i++)
{
void *b = g_slice_alloc (SAMPLE_SIZE);
void *p = (void*) (PAGE_SIZE * ((gsize) b / PAGE_SIZE));
free_list = g_slist_prepend (free_list, b);
/* find page */
for (j = 0; j < N_PAGES; j++)
if (pages[j].page == p)
return TRUE;
}
return FALSE;
}
static void
test_slice_known_pages (void)
{
gsize j, n_pages = 0;
void *mps[N_MAGAZINE_PROBES];
/* probe some magazine sizes */
for (j = 0; j < N_MAGAZINE_PROBES; j++)
mps[j] = g_slice_alloc (magazine_probes[j]);
/* mps[*] now contains pointers to allocated slices */
/* allocate blocks from N_PAGES different pages */
while (n_pages < N_PAGES)
{
void *b = g_slice_alloc (SAMPLE_SIZE);
void *p = (void*) (PAGE_SIZE * ((gsize) b / PAGE_SIZE));
for (j = 0; j < N_PAGES; j++)
if (pages[j].page == p)
break;
if (j < N_PAGES) /* known page */
free_list = g_slist_prepend (free_list, b);
else /* new page */
{
j = n_pages++;
pages[j].page = p;
pages[j].sample = b;
}
}
/* release intermediate allocations */
release_trash_list (&free_list, SAMPLE_SIZE);
/* ensure that we can allocate from known pages */
g_assert_true (allocate_from_known_page());
/* release intermediate allocations */
release_trash_list (&free_list, SAMPLE_SIZE);
/* release magazine probes to be retained */
for (j = 0; j < N_MAGAZINE_PROBES; j++)
g_slice_free1 (magazine_probes[j], mps[j]);
/* mps[*] now contains pointers to released slices */
/* ensure probes were retained */
for (j = 0; j < N_MAGAZINE_PROBES; j++)
{
GSList *trash = NULL;
guint k;
for (k = 0; k < MAX_PROBE_TRIALS; k++)
{
void *mem = g_slice_alloc (magazine_probes[j]);
if (mem == mps[j])
break; /* reallocated previously freed slice */
trash = g_slist_prepend (trash, mem);
}
release_trash_list (&trash, magazine_probes[j]);
g_assert_cmpint (k, <, MAX_PROBE_TRIALS); /* failed to reallocate slice */
}
/* mps[*] now contains pointers to reallocated slices */
/* release magazine probes to be retained across known pages */
for (j = 0; j < N_MAGAZINE_PROBES; j++)
g_slice_free1 (magazine_probes[j], mps[j]);
/* mps[*] now contains pointers to released slices */
/* ensure probes were retained */
for (j = 0; j < N_MAGAZINE_PROBES; j++)
{
GSList *trash = NULL;
guint k;
for (k = 0; k < MAX_PROBE_TRIALS; k++)
{
void *mem = g_slice_alloc (magazine_probes[j]);
if (mem == mps[j])
break; /* reallocated previously freed slice */
trash = g_slist_prepend (trash, mem);
}
release_trash_list (&trash, magazine_probes[j]);
g_assert_cmpint (k, <, MAX_PROBE_TRIALS); /* failed to reallocate slice */
}
/* mps[*] now contains pointers to reallocated slices */
/* ensure that we can allocate from known pages */
g_assert_true (allocate_from_known_page());
/* some cleanups */
for (j = 0; j < N_MAGAZINE_PROBES; j++)
g_slice_free1 (magazine_probes[j], mps[j]);
release_trash_list (&free_list, SAMPLE_SIZE);
}
int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/slice/known_pages", test_slice_known_pages);
return g_test_run ();
}

View File

@ -1,153 +0,0 @@
/* GLIB sliced memory - fast threaded memory chunk allocator
* Copyright (C) 2005 Tim Janik
*
* 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/>.
*/
/* We are testing some deprecated APIs here */
#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#endif
#include <glib.h>
#define quick_rand32() \
(rand_accu = 1664525 * rand_accu + 1013904223, rand_accu)
static guint prime_size = 1021; /* 769; 509 */
static guint number_of_blocks = 10000; /* total number of blocks allocated */
static guint number_of_repetitions = 10000; /* number of alloc+free repetitions */
static gboolean want_corruption = FALSE;
/* --- old memchunk prototypes (memchunks.c) --- */
GMemChunk* old_mem_chunk_new (const gchar *name,
gulong atom_size,
gulong area_size,
gint type);
void old_mem_chunk_destroy (GMemChunk *mem_chunk);
gpointer old_mem_chunk_alloc (GMemChunk *mem_chunk);
gpointer old_mem_chunk_alloc0 (GMemChunk *mem_chunk);
void old_mem_chunk_free (GMemChunk *mem_chunk,
gpointer mem);
void old_mem_chunk_clean (GMemChunk *mem_chunk);
void old_mem_chunk_reset (GMemChunk *mem_chunk);
void old_mem_chunk_print (GMemChunk *mem_chunk);
void old_mem_chunk_info (void);
#ifndef G_ALLOC_AND_FREE
#define G_ALLOC_AND_FREE 2
#endif
/* --- functions --- */
static inline int
corruption (void)
{
if (G_UNLIKELY (want_corruption))
{
/* corruption per call likelyness is about 1:4000000 */
guint32 r = g_random_int() % 8000009;
return r == 277 ? +1 : r == 281 ? -1 : 0;
}
return 0;
}
static gpointer
test_sliced_mem_thread (gpointer data)
{
guint32 rand_accu = 2147483563;
guint i, j;
guint8 **ps;
guint *ss;
/* initialize random numbers */
if (data)
rand_accu = *(guint32*) data;
else
{
GTimeVal rand_tv;
g_get_current_time (&rand_tv);
rand_accu = rand_tv.tv_usec + (rand_tv.tv_sec << 16);
}
ps = g_new (guint8*, number_of_blocks);
ss = g_new (guint, number_of_blocks);
/* create number_of_blocks random sizes */
for (i = 0; i < number_of_blocks; i++)
ss[i] = quick_rand32() % prime_size;
/* allocate number_of_blocks blocks */
for (i = 0; i < number_of_blocks; i++)
ps[i] = g_slice_alloc (ss[i] + corruption());
for (j = 0; j < number_of_repetitions; j++)
{
/* free number_of_blocks/2 blocks */
for (i = 0; i < number_of_blocks; i += 2)
g_slice_free1 (ss[i] + corruption(), ps[i] + corruption());
/* allocate number_of_blocks/2 blocks with new sizes */
for (i = 0; i < number_of_blocks; i += 2)
{
ss[i] = quick_rand32() % prime_size;
ps[i] = g_slice_alloc (ss[i] + corruption());
}
}
/* free number_of_blocks blocks */
for (i = 0; i < number_of_blocks; i++)
g_slice_free1 (ss[i] + corruption(), ps[i] + corruption());
/* alloc and free many equally sized chunks in a row */
for (i = 0; i < number_of_repetitions; i++)
{
guint sz = quick_rand32() % prime_size;
guint k = number_of_blocks / 100;
for (j = 0; j < k; j++)
ps[j] = g_slice_alloc (sz + corruption());
for (j = 0; j < k; j++)
g_slice_free1 (sz + corruption(), ps[j] + corruption());
}
g_free (ps);
g_free (ss);
return NULL;
}
static void
test_slice_malloc (void)
{
GThread **threads;
guint i, n_threads = 1;
g_test_message ("Starting %d threads allocating random blocks <= %u bytes",
n_threads, prime_size);
threads = g_alloca (sizeof(GThread*) * n_threads);
for (i = 0; i < n_threads; i++)
threads[i] = g_thread_create (test_sliced_mem_thread, NULL, TRUE, NULL);
for (i = 0; i < n_threads; i++)
g_thread_join (threads[i]);
}
int
main (int argc,
char *argv[])
{
g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, TRUE);
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/slice/malloc", test_slice_malloc);
return g_test_run ();
}

View File

@ -1,167 +0,0 @@
/* GLIB sliced memory - fast threaded memory chunk allocator
* Copyright (C) 2005 Tim Janik
*
* 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/>.
*/
/* We are testing some deprecated APIs here */
#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#endif
#include <glib.h>
#define quick_rand32() \
(rand_accu = 1664525 * rand_accu + 1013904223, rand_accu)
static const guint prime_size = 1021; /* 769; 509 */
static const gboolean clean_memchunks = FALSE;
static const guint number_of_blocks = 10000; /* total number of blocks allocated */
static const guint number_of_repetitions = 10000; /* number of alloc+free repetitions */
/* --- old memchunk prototypes (memchunks.c) --- */
GMemChunk* old_mem_chunk_new (const gchar *name,
gulong atom_size,
gulong area_size,
gint type);
void old_mem_chunk_destroy (GMemChunk *mem_chunk);
gpointer old_mem_chunk_alloc (GMemChunk *mem_chunk);
gpointer old_mem_chunk_alloc0 (GMemChunk *mem_chunk);
void old_mem_chunk_free (GMemChunk *mem_chunk,
gpointer mem);
void old_mem_chunk_clean (GMemChunk *mem_chunk);
void old_mem_chunk_reset (GMemChunk *mem_chunk);
void old_mem_chunk_print (GMemChunk *mem_chunk);
void old_mem_chunk_info (void);
#ifndef G_ALLOC_AND_FREE
#define G_ALLOC_AND_FREE 2
#endif
/* --- functions --- */
static inline gpointer
memchunk_alloc (GMemChunk **memchunkp,
guint size)
{
size = MAX (size, 1);
if (G_UNLIKELY (!*memchunkp))
*memchunkp = old_mem_chunk_new ("", size, 4096, G_ALLOC_AND_FREE);
return old_mem_chunk_alloc (*memchunkp);
}
static inline void
memchunk_free (GMemChunk *memchunk,
gpointer chunk)
{
old_mem_chunk_free (memchunk, chunk);
if (clean_memchunks)
old_mem_chunk_clean (memchunk);
}
static gpointer
test_memchunk_thread (gpointer data)
{
GMemChunk **memchunks;
guint i, j;
guint8 **ps;
guint *ss;
guint32 rand_accu = 2147483563;
/* initialize random numbers */
if (data)
rand_accu = *(guint32*) data;
else
{
GTimeVal rand_tv;
g_get_current_time (&rand_tv);
rand_accu = rand_tv.tv_usec + (rand_tv.tv_sec << 16);
}
/* prepare for memchunk creation */
memchunks = g_newa0 (GMemChunk*, prime_size);
ps = g_new (guint8*, number_of_blocks);
ss = g_new (guint, number_of_blocks);
/* create number_of_blocks random sizes */
for (i = 0; i < number_of_blocks; i++)
ss[i] = quick_rand32() % prime_size;
/* allocate number_of_blocks blocks */
for (i = 0; i < number_of_blocks; i++)
ps[i] = memchunk_alloc (&memchunks[ss[i]], ss[i]);
for (j = 0; j < number_of_repetitions; j++)
{
/* free number_of_blocks/2 blocks */
for (i = 0; i < number_of_blocks; i += 2)
memchunk_free (memchunks[ss[i]], ps[i]);
/* allocate number_of_blocks/2 blocks with new sizes */
for (i = 0; i < number_of_blocks; i += 2)
{
ss[i] = quick_rand32() % prime_size;
ps[i] = memchunk_alloc (&memchunks[ss[i]], ss[i]);
}
}
/* free number_of_blocks blocks */
for (i = 0; i < number_of_blocks; i++)
memchunk_free (memchunks[ss[i]], ps[i]);
/* alloc and free many equally sized chunks in a row */
for (i = 0; i < number_of_repetitions; i++)
{
guint sz = quick_rand32() % prime_size;
guint k = number_of_blocks / 100;
for (j = 0; j < k; j++)
ps[j] = memchunk_alloc (&memchunks[sz], sz);
for (j = 0; j < k; j++)
memchunk_free (memchunks[sz], ps[j]);
}
/* cleanout memchunks */
for (i = 0; i < prime_size; i++)
if (memchunks[i])
old_mem_chunk_destroy (memchunks[i]);
g_free (ps);
g_free (ss);
return NULL;
}
static void
test_slice_memchunk (void)
{
GThread **threads;
guint i, n_threads = 1;
g_test_message ("Starting %d threads allocating random blocks <= %u bytes",
n_threads, prime_size);
threads = g_alloca (sizeof(GThread*) * n_threads);
for (i = 0; i < n_threads; i++)
threads[i] = g_thread_create (test_memchunk_thread, NULL, TRUE, NULL);
for (i = 0; i < n_threads; i++)
g_thread_join (threads[i]);
}
int
main (int argc,
char *argv[])
{
g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, TRUE);
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/slice/memchunk", test_slice_memchunk);
return g_test_run ();
}

View File

@ -1,154 +0,0 @@
/* GLIB sliced memory - fast threaded memory chunk allocator
* Copyright (C) 2005 Tim Janik
*
* 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/>.
*/
/* We are testing some deprecated APIs here */
#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#endif
#include <glib.h>
#define quick_rand32() \
(rand_accu = 1664525 * rand_accu + 1013904223, rand_accu)
static guint prime_size = 1021; /* 769; 509 */
static guint number_of_blocks = 10000; /* total number of blocks allocated */
static guint number_of_repetitions = 10000; /* number of alloc+free repetitions */
static gboolean want_corruption = FALSE;
/* --- old memchunk prototypes (memchunks.c) --- */
GMemChunk* old_mem_chunk_new (const gchar *name,
gulong atom_size,
gulong area_size,
gint type);
void old_mem_chunk_destroy (GMemChunk *mem_chunk);
gpointer old_mem_chunk_alloc (GMemChunk *mem_chunk);
gpointer old_mem_chunk_alloc0 (GMemChunk *mem_chunk);
void old_mem_chunk_free (GMemChunk *mem_chunk,
gpointer mem);
void old_mem_chunk_clean (GMemChunk *mem_chunk);
void old_mem_chunk_reset (GMemChunk *mem_chunk);
void old_mem_chunk_print (GMemChunk *mem_chunk);
void old_mem_chunk_info (void);
#ifndef G_ALLOC_AND_FREE
#define G_ALLOC_AND_FREE 2
#endif
/* --- functions --- */
static inline int
corruption (void)
{
if (G_UNLIKELY (want_corruption))
{
/* corruption per call likelyness is about 1:4000000 */
guint32 r = g_random_int() % 8000009;
return r == 277 ? +1 : r == 281 ? -1 : 0;
}
return 0;
}
static gpointer
test_sliced_mem_thread (gpointer data)
{
guint32 rand_accu = 2147483563;
guint i, j;
guint8 **ps;
guint *ss;
/* initialize random numbers */
if (data)
rand_accu = *(guint32*) data;
else
{
GTimeVal rand_tv;
g_get_current_time (&rand_tv);
rand_accu = rand_tv.tv_usec + (rand_tv.tv_sec << 16);
}
ps = g_new (guint8*, number_of_blocks);
ss = g_new (guint, number_of_blocks);
/* create number_of_blocks random sizes */
for (i = 0; i < number_of_blocks; i++)
ss[i] = quick_rand32() % prime_size;
/* allocate number_of_blocks blocks */
for (i = 0; i < number_of_blocks; i++)
ps[i] = g_slice_alloc (ss[i] + corruption());
for (j = 0; j < number_of_repetitions; j++)
{
/* free number_of_blocks/2 blocks */
for (i = 0; i < number_of_blocks; i += 2)
g_slice_free1 (ss[i] + corruption(), ps[i] + corruption());
/* allocate number_of_blocks/2 blocks with new sizes */
for (i = 0; i < number_of_blocks; i += 2)
{
ss[i] = quick_rand32() % prime_size;
ps[i] = g_slice_alloc (ss[i] + corruption());
}
}
/* free number_of_blocks blocks */
for (i = 0; i < number_of_blocks; i++)
g_slice_free1 (ss[i] + corruption(), ps[i] + corruption());
/* alloc and free many equally sized chunks in a row */
for (i = 0; i < number_of_repetitions; i++)
{
guint sz = quick_rand32() % prime_size;
guint k = number_of_blocks / 100;
for (j = 0; j < k; j++)
ps[j] = g_slice_alloc (sz + corruption());
for (j = 0; j < k; j++)
g_slice_free1 (sz + corruption(), ps[j] + corruption());
}
g_free (ps);
g_free (ss);
return NULL;
}
static void
test_slice_slab (void)
{
GThread **threads;
guint i, n_threads = 1;
g_test_message ("Starting %d threads allocating random blocks <= %u bytes",
n_threads, prime_size);
threads = g_alloca (sizeof(GThread*) * n_threads);
for (i = 0; i < n_threads; i++)
threads[i] = g_thread_create (test_sliced_mem_thread, NULL, TRUE, NULL);
for (i = 0; i < n_threads; i++)
g_thread_join (threads[i]);
}
int
main (int argc,
char *argv[])
{
g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, FALSE);
g_slice_set_config (G_SLICE_CONFIG_BYPASS_MAGAZINES, TRUE);
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/slice/slab", test_slice_slab);
return g_test_run ();
}

View File

@ -4,66 +4,6 @@
/* We test deprecated functionality here */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
#ifdef G_ENABLE_DEBUG
static void
test_slice_nodebug (void)
{
const gchar *oldval;
oldval = g_getenv ("G_SLICE");
g_unsetenv ("G_SLICE");
if (g_test_subprocess ())
{
gpointer p, q;
p = g_slice_alloc (237);
q = g_slice_alloc (259);
g_slice_free1 (237, p);
g_slice_free1 (259, q);
g_slice_debug_tree_statistics ();
return;
}
g_test_trap_subprocess (NULL, 1000000, G_TEST_SUBPROCESS_DEFAULT);
g_test_trap_assert_passed ();
g_test_trap_assert_stderr ("*GSlice: MemChecker: root=NULL*");
if (oldval)
g_setenv ("G_SLICE", oldval, TRUE);
}
static void
test_slice_debug (void)
{
const gchar *oldval;
oldval = g_getenv ("G_SLICE");
g_setenv ("G_SLICE", "debug-blocks:always-malloc", TRUE);
if (g_test_subprocess ())
{
gpointer p, q;
p = g_slice_alloc (237);
q = g_slice_alloc (259);
g_slice_free1 (237, p);
g_slice_free1 (259, q);
g_slice_debug_tree_statistics ();
return;
}
g_test_trap_subprocess (NULL, 1000000, G_TEST_SUBPROCESS_DEFAULT);
g_test_trap_assert_passed ();
g_test_trap_assert_stderr ("*GSlice: MemChecker: * trunks, * branches, * old branches*");
if (oldval)
g_setenv ("G_SLICE", oldval, TRUE);
else
g_unsetenv ("G_SLICE");
}
#endif
static void
test_slice_copy (void)
{
@ -155,10 +95,6 @@ main (int argc, char **argv)
{
g_test_init (&argc, &argv, NULL);
#ifdef G_ENABLE_DEBUG
g_test_add_func ("/slice/nodebug", test_slice_nodebug);
g_test_add_func ("/slice/debug", test_slice_debug);
#endif
g_test_add_func ("/slice/copy", test_slice_copy);
g_test_add_func ("/slice/chain", test_chain);
g_test_add_func ("/slice/allocate", test_allocate);