diff options
author | Jakub Zawadzki <darkjames@darkjames.pl> | 2014-04-29 08:57:40 +0200 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2014-05-02 21:07:07 +0000 |
commit | 5f239013e744de640cd37462e067a495912b9e65 (patch) | |
tree | 7cce61afb931680c1b8d606b98c9082ace3a4de3 /epan | |
parent | fa84054dc7c8a381d9665ddb2c6d22e0e96094b1 (diff) | |
download | wireshark-5f239013e744de640cd37462e067a495912b9e65.tar.gz |
wmem: add new simple block allocator, use it in packet-scope.
For packet-scope allocation, there's no need to support realloc(), free()
cause memory will be garbage collected after packet dissection.
(and this allocator is much faster than full block allocator).
Change-Id: I73fdf708c3077f48f55bdcc71f4fa859e4ac2335
Reviewed-on: https://code.wireshark.org/review/1428
Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'epan')
-rw-r--r-- | epan/CMakeLists.txt | 1 | ||||
-rw-r--r-- | epan/epan.c | 2 | ||||
-rw-r--r-- | epan/wmem/Makefile.common | 2 | ||||
-rw-r--r-- | epan/wmem/wmem_allocator_block_fast.c | 243 | ||||
-rw-r--r-- | epan/wmem/wmem_allocator_block_fast.h | 52 | ||||
-rw-r--r-- | epan/wmem/wmem_core.c | 7 | ||||
-rw-r--r-- | epan/wmem/wmem_core.h | 13 | ||||
-rw-r--r-- | epan/wmem/wmem_scopes.c | 2 | ||||
-rw-r--r-- | epan/wmem/wmem_test.c | 91 |
9 files changed, 377 insertions, 36 deletions
diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index 41bd9d05e7..721a1fcfb0 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -1464,6 +1464,7 @@ set(WMEM_FILES wmem/wmem_array.c wmem/wmem_core.c wmem/wmem_allocator_block.c + wmem/wmem_allocator_block_fast.c wmem/wmem_allocator_simple.c wmem/wmem_allocator_strict.c wmem/wmem_list.c diff --git a/epan/epan.c b/epan/epan.c index f24a341fd9..30b5dd94a8 100644 --- a/epan/epan.c +++ b/epan/epan.c @@ -261,7 +261,7 @@ epan_dissect_init(epan_dissect_t *edt, epan_t *session, const gboolean create_pr pinfo_pool_cache = NULL; } else { - edt->pi.pool = wmem_allocator_new(WMEM_ALLOCATOR_BLOCK); + edt->pi.pool = wmem_allocator_new(WMEM_ALLOCATOR_BLOCK_FAST); } if (create_proto_tree) { diff --git a/epan/wmem/Makefile.common b/epan/wmem/Makefile.common index 6f6b4b0375..4c2b8317a1 100644 --- a/epan/wmem/Makefile.common +++ b/epan/wmem/Makefile.common @@ -25,6 +25,7 @@ LIBWMEM_SRC = \ wmem_array.c \ wmem_core.c \ wmem_allocator_block.c \ + wmem_allocator_block_fast.c \ wmem_allocator_simple.c \ wmem_allocator_strict.c \ wmem_list.c \ @@ -43,6 +44,7 @@ LIBWMEM_INCLUDES = \ wmem_core.h \ wmem_allocator.h \ wmem_allocator_block.h \ + wmem_allocator_block_fast.h \ wmem_allocator_simple.h \ wmem_allocator_strict.h \ wmem_list.h \ diff --git a/epan/wmem/wmem_allocator_block_fast.c b/epan/wmem/wmem_allocator_block_fast.c new file mode 100644 index 0000000000..c6ff565087 --- /dev/null +++ b/epan/wmem/wmem_allocator_block_fast.c @@ -0,0 +1,243 @@ +/* wmem_allocator_block.c + * Wireshark Memory Manager Fast Large-Block Allocator + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <stdio.h> +#include <string.h> + +#include <glib.h> + +#include "wmem_core.h" +#include "wmem_allocator.h" +#include "wmem_allocator_block_fast.h" + +/* https://mail.gnome.org/archives/gtk-devel-list/2004-December/msg00091.html + * The 2*sizeof(size_t) alignment here is borrowed from GNU libc, so it should + * be good most everywhere. It is more conservative than is needed on some + * 64-bit platforms, but ia64 does require a 16-byte alignment. The SIMD + * extensions for x86 and ppc32 would want a larger alignment than this, but + * we don't need to do better than malloc. + */ +#define WMEM_ALIGN_AMOUNT (2 * sizeof (gsize)) +#define WMEM_ALIGN_SIZE(SIZE) ((~(WMEM_ALIGN_AMOUNT-1)) & \ + ((SIZE) + (WMEM_ALIGN_AMOUNT-1))) + +#define WMEM_CHUNK_TO_DATA(CHUNK) ((void*)((guint8*)(CHUNK) + WMEM_CHUNK_HEADER_SIZE)) +#define WMEM_DATA_TO_CHUNK(DATA) ((wmem_block_fast_chunk_t*)((guint8*)(DATA) - WMEM_CHUNK_HEADER_SIZE)) + +#define WMEM_BLOCK_MAX_ALLOC_SIZE (WMEM_BLOCK_SIZE - (WMEM_BLOCK_HEADER_SIZE + WMEM_CHUNK_HEADER_SIZE)) + +/* When required, allocate more memory from the OS in chunks of this size. + * 2MB is a pretty arbitrary value - it's big enough that it should last a while + * and small enough that a mostly-unused one doesn't waste *too* much. It's + * also a nice power of two, of course. */ +#define WMEM_BLOCK_SIZE (2 * 1024 * 1024) + +/* The header for an entire OS-level 'block' of memory */ +typedef struct _wmem_block_fast_hdr { + struct _wmem_block_fast_hdr *prev, *next; + + gint32 pos; +} wmem_block_fast_hdr_t; +#define WMEM_BLOCK_HEADER_SIZE WMEM_ALIGN_SIZE(sizeof(wmem_block_fast_hdr_t)) + +typedef struct { + guint32 len; +} wmem_block_fast_chunk_t; +#define WMEM_CHUNK_HEADER_SIZE WMEM_ALIGN_SIZE(sizeof(wmem_block_fast_chunk_t)) + +typedef struct { + wmem_block_fast_hdr_t *block_list; +} wmem_block_fast_allocator_t; + +/* Add a block to the allocator's embedded doubly-linked list of OS-level blocks + * that it owns. */ +static inline void +wmem_block_fast_add_to_block_list(wmem_block_fast_allocator_t *allocator, + wmem_block_fast_hdr_t *block) +{ + block->prev = NULL; + block->next = allocator->block_list; + if (block->next) + block->next->prev = block; + allocator->block_list = block; +} + +/* Creates a new block, and initializes it. */ +static void +wmem_block_fast_new_block(wmem_block_fast_allocator_t *allocator) +{ + wmem_block_fast_hdr_t *block; + + /* allocate the new block and add it to the block list */ + block = (wmem_block_fast_hdr_t *)wmem_alloc(NULL, WMEM_BLOCK_SIZE); + wmem_block_fast_add_to_block_list(allocator, block); + + /* initialize it */ + block->pos = WMEM_BLOCK_HEADER_SIZE; +} + +/* API */ + +static void * +wmem_block_fast_alloc(void *private_data, const size_t size) +{ + wmem_block_fast_allocator_t *allocator = (wmem_block_fast_allocator_t*) private_data; + wmem_block_fast_chunk_t *chunk; + gint32 real_size; + + g_assert(size <= WMEM_BLOCK_MAX_ALLOC_SIZE); + + real_size = (gint32)(WMEM_ALIGN_SIZE(size) + WMEM_CHUNK_HEADER_SIZE); + + /* Allocate a new block if necessary. */ + if (!allocator->block_list || + (WMEM_BLOCK_SIZE - allocator->block_list->pos) < real_size) { + wmem_block_fast_new_block(allocator); + } + + chunk = (wmem_block_fast_chunk_t *) ((guint8 *) allocator->block_list + allocator->block_list->pos); + /* safe to cast, size smaller than WMEM_BLOCK_MAX_ALLOC_SIZE */ + chunk->len = (guint32) size; + + allocator->block_list->pos += real_size; + + /* and return the user's pointer */ + return WMEM_CHUNK_TO_DATA(chunk); +} + +static void +wmem_block_fast_free(void *private_data _U_, void *ptr _U_) +{ + /* free is NOP */ +} + +static void * +wmem_block_fast_realloc(void *private_data, void *ptr, const size_t size) +{ + wmem_block_fast_chunk_t *chunk; + + chunk = WMEM_DATA_TO_CHUNK(ptr); + + /* grow */ + if (chunk->len < size) { + void *newptr; + + /* need to alloc and copy; free is no-op, so don't call it */ + newptr = wmem_block_fast_alloc(private_data, size); + memcpy(newptr, ptr, chunk->len); + + return newptr; + } + + /* shrink or same space - great we can do nothing */ + return ptr; +} + +static void +wmem_block_fast_free_all(void *private_data) +{ + wmem_block_fast_allocator_t *allocator = (wmem_block_fast_allocator_t*) private_data; + wmem_block_fast_hdr_t *cur; + + /* iterate through the blocks, reinitializing each one */ + cur = allocator->block_list; + + while (cur) { + cur->pos = WMEM_BLOCK_HEADER_SIZE; + cur = cur->next; + } +} + +static void +wmem_block_fast_gc(void *private_data) +{ + wmem_block_fast_allocator_t *allocator = (wmem_block_fast_allocator_t*) private_data; + wmem_block_fast_hdr_t *cur, *next; + + /* Walk through the blocks, adding used blocks to the new list and + * completely destroying unused blocks. */ + cur = allocator->block_list; + allocator->block_list = NULL; + + while (cur) { + next = cur->next; + + if (cur->pos == WMEM_BLOCK_HEADER_SIZE) + { + /* unused block -> really free */ + wmem_free(NULL, cur); + } + else + { + /* part of this block is used, so add it to the new block list */ + wmem_block_fast_add_to_block_list(allocator, cur); + } + + cur = next; + } +} + +static void +wmem_block_fast_allocator_cleanup(void *private_data) +{ + /* wmem guarantees that free_all() is called directly before this, so + * calling gc will return all our blocks to the OS automatically */ + wmem_block_fast_gc(private_data); + + /* then just free the allocator structs */ + wmem_free(NULL, private_data); +} + +void +wmem_block_fast_allocator_init(wmem_allocator_t *allocator) +{ + wmem_block_fast_allocator_t *block_allocator; + + block_allocator = wmem_new(NULL, wmem_block_fast_allocator_t); + + allocator->alloc = &wmem_block_fast_alloc; + allocator->realloc = &wmem_block_fast_realloc; + allocator->free = &wmem_block_fast_free; + + allocator->free_all = &wmem_block_fast_free_all; + allocator->gc = &wmem_block_fast_gc; + allocator->cleanup = &wmem_block_fast_allocator_cleanup; + + allocator->private_data = (void*) block_allocator; + + block_allocator->block_list = NULL; +} + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/epan/wmem/wmem_allocator_block_fast.h b/epan/wmem/wmem_allocator_block_fast.h new file mode 100644 index 0000000000..8df1f2f63f --- /dev/null +++ b/epan/wmem/wmem_allocator_block_fast.h @@ -0,0 +1,52 @@ +/* wmem_allocator_block_fast.h + * Definitions for the Wireshark Memory Manager Fast Large-Block Allocator + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __WMEM_ALLOCATOR_BLOCK_FAST_H__ +#define __WMEM_ALLOCATOR_BLOCK_FAST_H__ + +#include "wmem_core.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void +wmem_block_fast_allocator_init(wmem_allocator_t *allocator); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __WMEM_ALLOCATOR_BLOCK_FAST_H__ */ + +/* + * Editor modelines - http://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/epan/wmem/wmem_core.c b/epan/wmem/wmem_core.c index bcec1f78ad..5215ece1e8 100644 --- a/epan/wmem/wmem_core.c +++ b/epan/wmem/wmem_core.c @@ -32,6 +32,7 @@ #include "wmem_allocator.h" #include "wmem_allocator_simple.h" #include "wmem_allocator_block.h" +#include "wmem_allocator_block_fast.h" #include "wmem_allocator_strict.h" /* Set according to the WIRESHARK_DEBUG_WMEM_OVERRIDE environment variable in @@ -161,6 +162,9 @@ wmem_allocator_new(const wmem_allocator_type_t type) case WMEM_ALLOCATOR_BLOCK: wmem_block_allocator_init(allocator); break; + case WMEM_ALLOCATOR_BLOCK_FAST: + wmem_block_fast_allocator_init(allocator); + break; case WMEM_ALLOCATOR_STRICT: wmem_strict_allocator_init(allocator); break; @@ -200,6 +204,9 @@ wmem_init(void) else if (strncmp(override_env, "strict", strlen("strict")) == 0) { override_type = WMEM_ALLOCATOR_STRICT; } + else if (strncmp(override_env, "block_fast", strlen("block_fast")) == 0) { + override_type = WMEM_ALLOCATOR_BLOCK_FAST; + } else { g_warning("Unrecognized wmem override"); do_override = FALSE; diff --git a/epan/wmem/wmem_core.h b/epan/wmem/wmem_core.h index eb3159f9ec..a3007965cf 100644 --- a/epan/wmem/wmem_core.h +++ b/epan/wmem/wmem_core.h @@ -50,17 +50,22 @@ typedef struct _wmem_allocator_t wmem_allocator_t; /** An enumeration of the different types of available allocators. */ typedef enum _wmem_allocator_type_t { WMEM_ALLOCATOR_SIMPLE, /**< A trivial allocator that mallocs requested - memory and tracks allocations via a hash table. As simple as - possible, intended more as a demo than for practical usage. Also - has the benefit of being friendly to tools like valgrind. */ + memory and tracks allocations via a hash table. As simple as + possible, intended more as a demo than for practical usage. Also + has the benefit of being friendly to tools like valgrind. */ WMEM_ALLOCATOR_BLOCK, /**< A block allocator that grabs large chunks of memory at a time (8 MB currently) and serves allocations out of those chunks. Designed for efficiency, especially in the free_all operation. */ - WMEM_ALLOCATOR_STRICT /**< An allocator that does its best to find invalid + WMEM_ALLOCATOR_STRICT, /**< An allocator that does its best to find invalid memory usage via things like canaries and scrubbing freed memory. Valgrind is the better choice on platforms that support it. */ + WMEM_ALLOCATOR_BLOCK_FAST /**< A block allocator like WMEM_ALLOCATOR_BLOCK + but even faster by tracking absolutely minimal metadata and + making 'free' a no-op. Useful only for very short-lived scopes + where there's no reason to free individual allocations because + the next free_all is always just around the corner. */ } wmem_allocator_type_t; /** Allocate the requested amount of memory in the given pool. diff --git a/epan/wmem/wmem_scopes.c b/epan/wmem/wmem_scopes.c index 15bb2b63cc..7ff17870e1 100644 --- a/epan/wmem/wmem_scopes.c +++ b/epan/wmem/wmem_scopes.c @@ -135,7 +135,7 @@ wmem_init_scopes(void) g_assert(file_scope == NULL); g_assert(epan_scope == NULL); - packet_scope = wmem_allocator_new(WMEM_ALLOCATOR_BLOCK); + packet_scope = wmem_allocator_new(WMEM_ALLOCATOR_BLOCK_FAST); file_scope = wmem_allocator_new(WMEM_ALLOCATOR_BLOCK); epan_scope = wmem_allocator_new(WMEM_ALLOCATOR_SIMPLE); diff --git a/epan/wmem/wmem_test.c b/epan/wmem/wmem_test.c index 423b46666c..e8606f4c63 100644 --- a/epan/wmem/wmem_test.c +++ b/epan/wmem/wmem_test.c @@ -29,6 +29,7 @@ #include "wmem.h" #include "wmem_allocator.h" #include "wmem_allocator_block.h" +#include "wmem_allocator_block_fast.h" #include "wmem_allocator_simple.h" #include "wmem_allocator_strict.h" @@ -58,6 +59,9 @@ wmem_allocator_force_new(const wmem_allocator_type_t type) case WMEM_ALLOCATOR_BLOCK: wmem_block_allocator_init(allocator); break; + case WMEM_ALLOCATOR_BLOCK_FAST: + wmem_block_fast_allocator_init(allocator); + break; case WMEM_ALLOCATOR_STRICT: wmem_strict_allocator_init(allocator); break; @@ -228,6 +232,42 @@ wmem_test_allocator_det(wmem_allocator_t *allocator, wmem_verify_func verify, } static void +wmem_test_allocator_jumbo(wmem_allocator_type_t type, wmem_verify_func verify) +{ + wmem_allocator_t *allocator; + char *ptr, *ptr1; + + allocator = wmem_allocator_force_new(type); + + ptr = (char*)wmem_alloc0(allocator, 4*1024*1024); + wmem_free(allocator, ptr); + wmem_gc(allocator); + ptr = (char*)wmem_alloc0(allocator, 4*1024*1024); + + if (verify) (*verify)(allocator); + wmem_free_all(allocator); + wmem_gc(allocator); + if (verify) (*verify)(allocator); + + ptr = (char *)wmem_alloc0(allocator, 10*1024*1024); + ptr1 = (char *)wmem_alloc0(allocator, 13*1024*1024); + ptr1 = (char *)wmem_realloc(allocator, ptr1, 10*1024*1024); + memset(ptr1, 0, 10*1024*1024); + ptr = (char *)wmem_realloc(allocator, ptr, 13*1024*1024); + memset(ptr, 0, 13*1024*1024); + if (verify) (*verify)(allocator); + wmem_gc(allocator); + if (verify) (*verify)(allocator); + wmem_free(allocator, ptr1); + if (verify) (*verify)(allocator); + wmem_free_all(allocator); + wmem_gc(allocator); + if (verify) (*verify)(allocator); + + wmem_destroy_allocator(allocator); +} + +static void wmem_test_allocator(wmem_allocator_type_t type, wmem_verify_func verify) { int i; @@ -255,32 +295,6 @@ wmem_test_allocator(wmem_allocator_type_t type, wmem_verify_func verify) wmem_gc(allocator); if (verify) (*verify)(allocator); - ptrs[0] = (char*)wmem_alloc0(allocator, 4*1024*1024); - wmem_free(allocator, ptrs[0]); - wmem_gc(allocator); - ptrs[0] = (char*)wmem_alloc0(allocator, 4*1024*1024); - - if (verify) (*verify)(allocator); - wmem_free_all(allocator); - wmem_gc(allocator); - if (verify) (*verify)(allocator); - - /* test jumbo allocations and frees */ - ptrs[0] = (char *)wmem_alloc0(allocator, 10*1024*1024); - ptrs[1] = (char *)wmem_alloc0(allocator, 13*1024*1024); - ptrs[1] = (char *)wmem_realloc(allocator, ptrs[1], 10*1024*1024); - memset(ptrs[1], 0, 10*1024*1024); - ptrs[0] = (char *)wmem_realloc(allocator, ptrs[0], 13*1024*1024); - memset(ptrs[0], 0, 13*1024*1024); - if (verify) (*verify)(allocator); - wmem_gc(allocator); - if (verify) (*verify)(allocator); - wmem_free(allocator, ptrs[1]); - if (verify) (*verify)(allocator); - wmem_free_all(allocator); - wmem_gc(allocator); - if (verify) (*verify)(allocator); - /* now do some random fuzz-like tests */ /* reset our ptr array */ @@ -288,8 +302,8 @@ wmem_test_allocator(wmem_allocator_type_t type, wmem_verify_func verify) ptrs[i] = NULL; } - /* Run enough iterations to fill the array 64 times */ - for (i=0; i<MAX_SIMULTANEOUS_ALLOCS*64; i++) { + /* Run enough iterations to fill the array 32 times */ + for (i=0; i<MAX_SIMULTANEOUS_ALLOCS*32; i++) { gint ptrs_index; gint new_size; @@ -359,7 +373,7 @@ wmem_time_allocator(wmem_allocator_type_t type) static void wmem_time_allocators(void) { - double simple_time, block_time; + double simple_time, block_time, fast_time; g_test_timer_start(); wmem_time_allocator(WMEM_ALLOCATOR_SIMPLE); @@ -369,26 +383,42 @@ wmem_time_allocators(void) wmem_time_allocator(WMEM_ALLOCATOR_BLOCK); block_time = g_test_timer_elapsed(); - printf("(simple: %f; block: %f) ", simple_time, block_time); + g_test_timer_start(); + wmem_time_allocator(WMEM_ALLOCATOR_BLOCK_FAST); + fast_time = g_test_timer_elapsed(); + + printf("(simple: %f; block: %f; fast: %f) ", + simple_time, block_time, fast_time); + g_assert(simple_time > block_time); + g_assert(block_time > fast_time); } static void wmem_test_allocator_block(void) { wmem_test_allocator(WMEM_ALLOCATOR_BLOCK, &wmem_block_verify); + wmem_test_allocator_jumbo(WMEM_ALLOCATOR_BLOCK, &wmem_block_verify); +} + +static void +wmem_test_allocator_block_fast(void) +{ + wmem_test_allocator(WMEM_ALLOCATOR_BLOCK_FAST, NULL); } static void wmem_test_allocator_simple(void) { wmem_test_allocator(WMEM_ALLOCATOR_SIMPLE, NULL); + wmem_test_allocator_jumbo(WMEM_ALLOCATOR_SIMPLE, NULL); } static void wmem_test_allocator_strict(void) { wmem_test_allocator(WMEM_ALLOCATOR_STRICT, &wmem_strict_check_canaries); + wmem_test_allocator_jumbo(WMEM_ALLOCATOR_STRICT, &wmem_strict_check_canaries); } /* UTILITY TESTING FUNCTIONS (/wmem/utils/) */ @@ -1004,6 +1034,7 @@ main(int argc, char **argv) g_test_init(&argc, &argv, NULL); g_test_add_func("/wmem/allocator/block", wmem_test_allocator_block); + g_test_add_func("/wmem/allocator/blk_fast", wmem_test_allocator_block_fast); g_test_add_func("/wmem/allocator/simple", wmem_test_allocator_simple); g_test_add_func("/wmem/allocator/strict", wmem_test_allocator_strict); g_test_add_func("/wmem/allocator/callbacks", wmem_test_allocator_callbacks); |