/* * Copyright (c) 2000 Matteo Frigo * Copyright (c) 2000 Massachusetts Institute of Technology * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "bench.h" #include #include #include #include #if defined(HAVE_DECL_MEMALIGN) && !HAVE_DECL_MEMALIGN # if defined(HAVE_MALLOC_H) # include # else extern void *memalign(size_t, size_t); # endif #endif #if defined(HAVE_DECL_POSIX_MEMALIGN) && !HAVE_DECL_POSIX_MEMALIGN extern int posix_memalign(void **, size_t, size_t); #endif void bench_assertion_failed(const char *s, int line, const char *file) { fflush(stdout); fprintf(stderr, "bench: %s:%d: assertion failed: %s\n", file, line, s); exit(EXIT_FAILURE); } #ifdef HAVE_DRAND48 # if defined(HAVE_DECL_DRAND48) && !HAVE_DECL_DRAND48 extern double drand48(void); # endif double bench_drand(void) { return drand48() - 0.5; } void bench_srand(int seed) { srand48(seed); } #else double bench_drand(void) { double d = rand(); return (d / (double) RAND_MAX) - 0.5; } void bench_srand(int seed) { srand(seed); } #endif /********************************************************** * DEBUGGING CODE **********************************************************/ #ifdef BENCH_DEBUG static int bench_malloc_cnt = 0; /* * debugging malloc/free. Initialize every malloced and freed area to * random values, just to make sure we are not using uninitialized * pointers. Also check for writes past the ends of allocated blocks, * and a couple of other things. * * This code is a quick and dirty hack -- use at your own risk. */ static int bench_malloc_total = 0, bench_malloc_max = 0, bench_malloc_cnt_max = 0; #define MAGIC ((size_t)0xABadCafe) #define PAD_FACTOR 2 #define TWO_SIZE_T (2 * sizeof(size_t)) #define VERBOSE_ALLOCATION 0 #if VERBOSE_ALLOCATION #define WHEN_VERBOSE(a) a #else #define WHEN_VERBOSE(a) #endif void *bench_malloc(size_t n) { char *p; size_t i; bench_malloc_total += n; if (bench_malloc_total > bench_malloc_max) bench_malloc_max = bench_malloc_total; p = (char *) malloc(PAD_FACTOR * n + TWO_SIZE_T); BENCH_ASSERT(p); /* store the size in a known position */ ((size_t *) p)[0] = n; ((size_t *) p)[1] = MAGIC; for (i = 0; i < PAD_FACTOR * n; i++) p[i + TWO_SIZE_T] = (char) (i ^ 0xDEADBEEF); ++bench_malloc_cnt; if (bench_malloc_cnt > bench_malloc_cnt_max) bench_malloc_cnt_max = bench_malloc_cnt; /* skip the size we stored previously */ return (void *) (p + TWO_SIZE_T); } void bench_free(void *p) { char *q; BENCH_ASSERT(p); q = ((char *) p) - TWO_SIZE_T; BENCH_ASSERT(q); { size_t n = ((size_t *) q)[0]; size_t magic = ((size_t *) q)[1]; size_t i; ((size_t *) q)[0] = 0; /* set to zero to detect duplicate free's */ BENCH_ASSERT(magic == MAGIC); ((size_t *) q)[1] = ~MAGIC; bench_malloc_total -= n; BENCH_ASSERT(bench_malloc_total >= 0); /* check for writing past end of array: */ for (i = n; i < PAD_FACTOR * n; ++i) if (q[i + TWO_SIZE_T] != (char) (i ^ 0xDEADBEEF)) { BENCH_ASSERT(0 /* array bounds overwritten */); } for (i = 0; i < PAD_FACTOR * n; ++i) q[i + TWO_SIZE_T] = (char) (i ^ 0xBEEFDEAD); --bench_malloc_cnt; BENCH_ASSERT(bench_malloc_cnt >= 0); BENCH_ASSERT( (bench_malloc_cnt == 0 && bench_malloc_total == 0) || (bench_malloc_cnt > 0 && bench_malloc_total > 0)); free(q); } } #else /********************************************************** * NON DEBUGGING CODE **********************************************************/ /* production version, no hacks */ #define MIN_ALIGNMENT 16 /* must be power of two */ #define real_free free /* memalign and malloc use ordinary free */ void *bench_malloc(size_t n) { void *p; if (n == 0) n = 1; #if defined(WITH_OUR_MALLOC16) && (MIN_ALIGNMENT == 16) /* Our own 16-byte aligned malloc/free. Assumes sizeof(void*) is a power of two <= 8 and that malloc is at least sizeof(void*)-aligned. Assumes size_t = uintptr_t. */ { void *p0; if ((p0 = malloc(n + 16))) { p = (void *) (((size_t) p0 + 16) & (~((size_t) 15))); *((void **) p - 1) = p0; } else p = (void *) 0; } # define OUR_FREE16 #elif defined(HAVE_MEMALIGN) p = memalign(MIN_ALIGNMENT, n); #elif defined(HAVE_POSIX_MEMALIGN) /* note: posix_memalign is broken in glibc 2.2.5: it constrains the size, not the alignment, to be (power of two) * sizeof(void*). The bug seems to have been fixed as of glibc 2.3.1. */ if (posix_memalign(&p, MIN_ALIGNMENT, n)) p = (void*) 0; #elif defined(__ICC) || defined(__INTEL_COMPILER) || defined(HAVE__MM_MALLOC) /* Intel's C compiler defines _mm_malloc and _mm_free intrinsics */ p = (void *) _mm_malloc(n, MIN_ALIGNMENT); # undef real_free # define real_free _mm_free #else p = malloc(n); #endif BENCH_ASSERT(p); return p; } void bench_free(void *p) { #ifdef OUR_FREE16 if (p) free(*((void **) p - 1)); #else real_free(p); #endif } #endif void bench_free0(void *p) { if (p) bench_free(p); }