From daa5dfa3be0b8ba1578a64debfe7bdaa4f34ab4a Mon Sep 17 00:00:00 2001 From: dryman Date: Sun, 26 Mar 2017 19:28:05 -0700 Subject: [PATCH] OPIC-34 massive malloc/free on opic malloc --- Makefile.am | 2 +- benchmark/LICENSE | 26 +++++ benchmark/Makefile.am | 5 + benchmark/lran2.h | 44 +++++++ benchmark/malloc_bench.c | 240 ++++++++++++++++++++++++++++++++++++++ configure.ac | 1 + opic/malloc/allocator.c | 2 + opic/malloc/init_helper.c | 1 + opic/malloc/inline_aux.h | 14 ++- 9 files changed, 329 insertions(+), 6 deletions(-) create mode 100644 benchmark/LICENSE create mode 100644 benchmark/Makefile.am create mode 100644 benchmark/lran2.h create mode 100644 benchmark/malloc_bench.c diff --git a/Makefile.am b/Makefile.am index 4c7605a..3903731 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = opic +SUBDIRS = opic benchmark nobase_include_HEADERS = \ opic/op_malloc.h \ diff --git a/benchmark/LICENSE b/benchmark/LICENSE new file mode 100644 index 0000000..afbf19d --- /dev/null +++ b/benchmark/LICENSE @@ -0,0 +1,26 @@ +TLSF-BSD is freely redistributable under the two-clause BSD License: + +Copyright (c) 2016 National Cheng Kung University, Taiwan. +Copyright (c) 2006-2008, 2011, 2014 Matthew Conte. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. \ No newline at end of file diff --git a/benchmark/Makefile.am b/benchmark/Makefile.am new file mode 100644 index 0000000..a9ac7a1 --- /dev/null +++ b/benchmark/Makefile.am @@ -0,0 +1,5 @@ +bin_PROGRAMS = malloc_bench + +malloc_bench_SOURCES = malloc_bench.c +malloc_bench_LDADD = $(top_builddir)/opic/libdemomalloc.la @PTHREAD_LIBS@ @atomic_LIBS@ +malloc_bench_LDFLAGS = -static diff --git a/benchmark/lran2.h b/benchmark/lran2.h new file mode 100644 index 0000000..a4b9b4b --- /dev/null +++ b/benchmark/lran2.h @@ -0,0 +1,44 @@ +/* Copyright (c) 1996 Wolfram Gloger. + * A small, portable pseudo-random number generator. + */ + +#ifndef _LRAN2_H +#define _LRAN2_H + +#define LRAN2_MAX 714025l /* constants for portable */ +#define IA 1366l /* random number generator */ +#define IC 150889l /* (see e.g. `Numerical Recipes') */ + +struct lran2_st { + long x, y, v[97]; +}; + +static inline +void lran2_init(struct lran2_st *d, long seed) +{ + long x = (IC - seed) % LRAN2_MAX; + if (x < 0) + x = -x; + for (int j = 0; j < 97; j++) { + x = (IA * x + IC) % LRAN2_MAX; + d->v[j] = x; + } + d->x = (IA * x + IC) % LRAN2_MAX; + d->y = d->x; +} + +static inline +long lran2(struct lran2_st *d) +{ + int j = (d->y % 97); + + d->y = d->v[j]; + d->x = (IA * d->x + IC) % LRAN2_MAX; + d->v[j] = d->x; + return d->y; +} + +#undef IA +#undef IC + +#endif \ No newline at end of file diff --git a/benchmark/malloc_bench.c b/benchmark/malloc_bench.c new file mode 100644 index 0000000..3af576f --- /dev/null +++ b/benchmark/malloc_bench.c @@ -0,0 +1,240 @@ +/* Copyright (c) 2016 National Cheng Kung University, Taiwan. + * All rights reserved. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE +#endif +#define _POSIX_C_SOURCE 199309L + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lran2.h" +#include "opic/op_malloc.h" + +static OPHeap* heap; +#ifdef DEBUG +static int counter; +#endif + +static void usage(const char *name) +{ + printf("run a malloc benchmark.\n" + "usage: %s [-s blk-size|blk-min:blk-max] [-l loop-count] " + "[-n num-blocks] [-c]\n", + name); + exit(-1); +} + +/* Parse an integer argument. */ +static int parse_int_arg(const char *arg, const char *exe_name) +{ + long int ret; + + errno = 0; + ret = strtol(arg, NULL, 0); + if (ret == 0) + usage(exe_name); + + return (int) ret; +} + +/* Parse a size argument, which is either an integer or two integers + separated by a colon, denoting a range. */ +static void +parse_size_arg(const char *arg, const char *exe_name, + size_t *blk_min, size_t *blk_max) +{ + long int ret; + char *endptr; + + ret = strtol(arg, &endptr, 0); + + if (ret == 0) + usage(exe_name); + + *blk_min = ret; + + if (endptr && *endptr == ':') { + ret = strtol(endptr + 1, NULL, 0); + + if (ret == 0) + usage(exe_name); + } + + *blk_max = ret; + + if (*blk_min > *blk_max) + usage(exe_name); +} + +/* Get a random block size between blk_min and blk_max. */ +static size_t +get_random_block_size(size_t blk_min, size_t blk_max, + struct lran2_st *lran2_state) +{ + size_t blk_size; + + if (blk_max > blk_min) { + blk_size = blk_min + (lran2(lran2_state) % (blk_max - blk_min)); + } else + blk_size = blk_min; + + return blk_size; +} + +static void +run_alloc_benchmark(int loops, size_t blk_min, size_t blk_max, + void **blk_array, size_t num_blks, bool clear, + struct lran2_st *lran2_state) +{ + while (loops--) { + int next_idx = lran2(lran2_state) % num_blks; + size_t blk_size = get_random_block_size(blk_min, blk_max, lran2_state); + +#ifdef DEBUG + printf("%06d malloc size %zu ", counter++, blk_size); +#endif + if (blk_array[next_idx]) { +#ifdef DEBUG + printf("free addr %p ", blk_array[next_idx]); +#endif + OPDealloc(blk_array[next_idx]); + } + + /* Insert the newly alloced block into the array at a random point. */ + blk_array[next_idx] = OPMallocRaw(heap, blk_size); +#ifdef DEBUG + printf("got addr %p\n", blk_array[next_idx]); +#endif + if (clear) + memset(blk_array[next_idx], 0, blk_size); + } + + /* Free up all allocated blocks. */ + for (size_t i = 0; i < num_blks; i++) { + if (blk_array[i]) + OPDealloc(blk_array[i]); + } +} + +struct alloc_desc { + /* Generic fields. */ + int loops; + size_t blk_min; + size_t blk_max; + void **blk_array; + size_t num_blks; + bool clear; +}; + +static void start_bench(void *arg) +{ + struct alloc_desc *desc = arg; + struct lran2_st lran2_state; + + lran2_init(&lran2_state, time(NULL) ^ getpid()); + + run_alloc_benchmark(desc->loops, desc->blk_min, desc->blk_max, + desc->blk_array, desc->num_blks, desc->clear, + &lran2_state); +} + +static void stop_bench(void *arg) +{ + struct alloc_desc *desc = arg; + if (!desc) return; + free(desc->blk_array); +} + +int main(int argc, char **argv) +{ + size_t blk_min = 512, blk_max = 512, num_blks = 10000; + int loops = 10000000; + bool clear = false; + int opt; + + while ((opt = getopt(argc, argv, "s:l:r:t:n:b:ch")) > 0) { + switch (opt) { + case 's': + parse_size_arg(optarg, argv[0], &blk_min, &blk_max); + break; + case 'l': + loops = parse_int_arg(optarg, argv[0]); + break; + case 'n': + num_blks = parse_int_arg(optarg, argv[0]); + break; + case 'c': + clear = true; + break; + case 'h': + usage(argv[0]); + break; + default: + usage(argv[0]); + break; + } + } + + + struct alloc_desc desc = { + .loops = loops, + .blk_min = blk_min, + .blk_max = blk_max, + .blk_array = malloc(num_blks * sizeof(unsigned char *)), + .num_blks = num_blks, + .clear = clear, + }; + assert(desc.blk_array != NULL); + memset(desc.blk_array, 0, num_blks * sizeof(unsigned char *)); + + assert(OPHeapNew(&heap)); + + start_bench(&desc); + stop_bench(&desc); + + OPHeapDestroy(heap); + /* +TODO: create a cross platform high resolution timer. + struct timespec start, end; + + int err = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); + assert(err == 0); + + err = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end); + assert(err == 0); + + double elapsed = (end.tv_sec - start.tv_sec) + + (end.tv_nsec - start.tv_nsec) * 1e-9; + + struct rusage usage; + err = getrusage(RUSAGE_SELF, &usage); + assert(err == 0); + */ + + + /* Dump both machine and human readable versions */ + /* + printf("%u:%u:%u:%u:%u:%.6f: took %.6f s for %u malloc/free\n" + "benchmark loops of %u-%u bytes. ~%.3f us per loop\n", + blk_min, blk_max, loops, + (int)clear, usage.ru_maxrss, elapsed, elapsed, loops, blk_min, + blk_max, (double)(elapsed / loops) * 1e6); + */ + + return 0; +} diff --git a/configure.ac b/configure.ac index 5eea126..65a6014 100644 --- a/configure.ac +++ b/configure.ac @@ -48,6 +48,7 @@ AC_CONFIG_FILES([ Makefile opic/Makefile opic/malloc/Makefile + benchmark/Makefile ]) AC_OUTPUT diff --git a/opic/malloc/allocator.c b/opic/malloc/allocator.c index 06c6838..8ae0a67 100644 --- a/opic/malloc/allocator.c +++ b/opic/malloc/allocator.c @@ -184,6 +184,7 @@ DispatchUSpanForAddr(OPHeapCtx* ctx, Magic uspan_magic, void** addr) UnarySpan** it = &ctx->uqueue->uspan; while (*it) { + ctx->sspan.uspan = *it; switch(USpanObtainAddr(ctx, addr)) { case QOP_SUCCESS: @@ -252,6 +253,7 @@ DispatchHPageForSSpan(OPHeapCtx* ctx, Magic magic, unsigned int spage_cnt, HugePage** it = &ctx->hqueue->hpage; while (*it) { + ctx->hspan.hpage = *it; switch(HPageObtainSSpan(ctx, spage_cnt, use_full_span)) { case QOP_SUCCESS: diff --git a/opic/malloc/init_helper.c b/opic/malloc/init_helper.c index 9bf31a5..2efd5f5 100644 --- a/opic/malloc/init_helper.c +++ b/opic/malloc/init_helper.c @@ -94,6 +94,7 @@ HPageInit(HugePage* hpage, Magic magic) { hpage->magic = magic; hpage->pcard = 0; + hpage->next = NULL; HPageEmptiedBMaps(hpage, hpage->occupy_bmap, hpage->header_bmap); diff --git a/opic/malloc/inline_aux.h b/opic/malloc/inline_aux.h index dbbad7b..e8a6415 100644 --- a/opic/malloc/inline_aux.h +++ b/opic/malloc/inline_aux.h @@ -83,10 +83,11 @@ DequeueUSpan(UnarySpanQueue* uspan_queue, UnarySpan* uspan) { UnarySpan** it = &uspan_queue->uspan; - while (*it != uspan) + while (*it != uspan && *it) it = &(*it)->next; - *it = (*it)->next; + if (*it) + *it = (*it)->next; atomic_store_explicit(&uspan->state, SPAN_DEQUEUED, memory_order_release); } @@ -99,10 +100,13 @@ EnqueueHPage(HugePageQueue* hpage_queue, HugePage* hpage) while (*it && (*it) < hpage) it = &(*it)->next; - if (*it > hpage) - hpage->next = *it; + if (*it != hpage) + { + if (*it > hpage) + hpage->next = *it; - *it = hpage; + *it = hpage; + } atomic_store_explicit(&hpage->state, SPAN_ENQUEUED, memory_order_release); }