From 48e4a81b05f2ad6541d72e819cd4f638055f13d5 Mon Sep 17 00:00:00 2001 From: Soheil Hassas Yeganeh Date: Fri, 2 Nov 2018 15:20:02 -0400 Subject: Remeve memset(0) from arena allocated memory. Callers are updated to properly initialize the memory. This behavior can be overridden using GRPC_ARENA_INIT_STRATEGY environment variable. --- src/core/lib/gpr/arena.cc | 121 ++++++++++++++++++++++++++++++++-------------- src/core/lib/gpr/arena.h | 2 + 2 files changed, 86 insertions(+), 37 deletions(-) (limited to 'src/core/lib/gpr') diff --git a/src/core/lib/gpr/arena.cc b/src/core/lib/gpr/arena.cc index 77f9357146..836a7ca793 100644 --- a/src/core/lib/gpr/arena.cc +++ b/src/core/lib/gpr/arena.cc @@ -21,6 +21,7 @@ #include "src/core/lib/gpr/arena.h" #include +#include #include #include @@ -28,34 +29,79 @@ #include #include "src/core/lib/gpr/alloc.h" +#include "src/core/lib/gpr/env.h" +#include "src/core/lib/gprpp/memory.h" + +namespace { +enum init_strategy { + NO_INIT, // Do not initialize the arena blocks. + ZERO_INIT, // Initialize arena blocks with 0. + NON_ZERO_INIT, // Initialize arena blocks with a non-zero value. +}; + +gpr_once g_init_strategy_once = GPR_ONCE_INIT; +init_strategy g_init_strategy = NO_INIT; +} // namespace + +static void set_strategy_from_env() { + char* str = gpr_getenv("GRPC_ARENA_INIT_STRATEGY"); + if (str == nullptr) { + g_init_strategy = NO_INIT; + } else if (strcmp(str, "zero_init") == 0) { + g_init_strategy = ZERO_INIT; + } else if (strcmp(str, "non_zero_init") == 0) { + g_init_strategy = NON_ZERO_INIT; + } else { + g_init_strategy = NO_INIT; + } + gpr_free(str); +} + +static void* gpr_arena_alloc_maybe_init(size_t size) { + void* mem = gpr_malloc_aligned(size, GPR_MAX_ALIGNMENT); + gpr_once_init(&g_init_strategy_once, set_strategy_from_env); + if (GPR_UNLIKELY(g_init_strategy != NO_INIT)) { + if (g_init_strategy == ZERO_INIT) { + memset(mem, 0, size); + } else { // NON_ZERO_INIT. + memset(mem, 0xFE, size); + } + } + return mem; +} + +void gpr_arena_init() { + gpr_once_init(&g_init_strategy_once, set_strategy_from_env); +} // Uncomment this to use a simple arena that simply allocates the // requested amount of memory for each call to gpr_arena_alloc(). This // effectively eliminates the efficiency gain of using an arena, but it // may be useful for debugging purposes. //#define SIMPLE_ARENA_FOR_DEBUGGING - #ifdef SIMPLE_ARENA_FOR_DEBUGGING struct gpr_arena { + gpr_arena() { gpr_mu_init(&mu); } + ~gpr_arena() { + gpr_mu_destroy(&mu); + for (size_t i = 0; i < num_ptrs; ++i) { + gpr_free_aligned(ptrs[i]); + } + gpr_free(ptrs); + } + gpr_mu mu; - void** ptrs; - size_t num_ptrs; + void** ptrs = nullptr; + size_t num_ptrs = 0; }; gpr_arena* gpr_arena_create(size_t ignored_initial_size) { - gpr_arena* arena = (gpr_arena*)gpr_zalloc(sizeof(*arena)); - gpr_mu_init(&arena->mu); - return arena; + return grpc_core::New(); } size_t gpr_arena_destroy(gpr_arena* arena) { - gpr_mu_destroy(&arena->mu); - for (size_t i = 0; i < arena->num_ptrs; ++i) { - gpr_free(arena->ptrs[i]); - } - gpr_free(arena->ptrs); - gpr_free(arena); + grpc_core::Delete(arena); return 1; // Value doesn't matter, since it won't be used. } @@ -63,7 +109,8 @@ void* gpr_arena_alloc(gpr_arena* arena, size_t size) { gpr_mu_lock(&arena->mu); arena->ptrs = (void**)gpr_realloc(arena->ptrs, sizeof(void*) * (arena->num_ptrs + 1)); - void* retval = arena->ptrs[arena->num_ptrs++] = gpr_zalloc(size); + void* retval = arena->ptrs[arena->num_ptrs++] = + gpr_arena_alloc_maybe_init(size); gpr_mu_unlock(&arena->mu); return retval; } @@ -77,45 +124,45 @@ void* gpr_arena_alloc(gpr_arena* arena, size_t size) { // would allow us to use the alignment actually needed by the caller. typedef struct zone { - zone* next; + zone* next = nullptr; } zone; struct gpr_arena { + gpr_arena(size_t initial_size) + : initial_zone_size(initial_size), last_zone(&initial_zone) { + gpr_mu_init(&arena_growth_mutex); + } + ~gpr_arena() { + gpr_mu_destroy(&arena_growth_mutex); + zone* z = initial_zone.next; + while (z) { + zone* next_z = z->next; + z->~zone(); + gpr_free_aligned(z); + z = next_z; + } + } + // Keep track of the total used size. We use this in our call sizing // historesis. - gpr_atm total_used; + gpr_atm total_used = 0; size_t initial_zone_size; zone initial_zone; zone* last_zone; gpr_mu arena_growth_mutex; }; -static void* zalloc_aligned(size_t size) { - void* ptr = gpr_malloc_aligned(size, GPR_MAX_ALIGNMENT); - memset(ptr, 0, size); - return ptr; -} - gpr_arena* gpr_arena_create(size_t initial_size) { initial_size = GPR_ROUND_UP_TO_ALIGNMENT_SIZE(initial_size); - gpr_arena* a = static_cast(zalloc_aligned( - GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + initial_size)); - a->initial_zone_size = initial_size; - a->last_zone = &a->initial_zone; - gpr_mu_init(&a->arena_growth_mutex); - return a; + return new (gpr_arena_alloc_maybe_init( + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(gpr_arena)) + initial_size)) + gpr_arena(initial_size); } size_t gpr_arena_destroy(gpr_arena* arena) { - gpr_mu_destroy(&arena->arena_growth_mutex); - gpr_atm size = gpr_atm_no_barrier_load(&arena->total_used); - zone* z = arena->initial_zone.next; + const gpr_atm size = gpr_atm_no_barrier_load(&arena->total_used); + arena->~gpr_arena(); gpr_free_aligned(arena); - while (z) { - zone* next_z = z->next; - gpr_free_aligned(z); - z = next_z; - } return static_cast(size); } @@ -132,8 +179,8 @@ void* gpr_arena_alloc(gpr_arena* arena, size_t size) { // sizing historesis (that is, most calls should have a large enough initial // zone and will not need to grow the arena). gpr_mu_lock(&arena->arena_growth_mutex); - zone* z = static_cast( - zalloc_aligned(GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)) + size)); + zone* z = new (gpr_arena_alloc_maybe_init( + GPR_ROUND_UP_TO_ALIGNMENT_SIZE(sizeof(zone)) + size)) zone(); arena->last_zone->next = z; arena->last_zone = z; gpr_mu_unlock(&arena->arena_growth_mutex); diff --git a/src/core/lib/gpr/arena.h b/src/core/lib/gpr/arena.h index 6d2a073dd5..069892b228 100644 --- a/src/core/lib/gpr/arena.h +++ b/src/core/lib/gpr/arena.h @@ -37,5 +37,7 @@ gpr_arena* gpr_arena_create(size_t initial_size); void* gpr_arena_alloc(gpr_arena* arena, size_t size); // Destroy an arena, returning the total number of bytes allocated size_t gpr_arena_destroy(gpr_arena* arena); +// Initializes the Arena component. +void gpr_arena_init(); #endif /* GRPC_CORE_LIB_GPR_ARENA_H */ -- cgit v1.2.3