235 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			235 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "libbench2/bench.h"
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <stddef.h>
							 | 
						||
| 
								 | 
							
								#include <math.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if defined(HAVE_MALLOC_H)
							 | 
						||
| 
								 | 
							
								#  include <malloc.h>
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if defined(HAVE_DECL_MEMALIGN) && !HAVE_DECL_MEMALIGN
							 | 
						||
| 
								 | 
							
								extern void *memalign(size_t, size_t);
							 | 
						||
| 
								 | 
							
								#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)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								     ovtpvt_err("bench: %s:%d: assertion failed: %s\n", file, line, s);
							 | 
						||
| 
								 | 
							
								     bench_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;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#  if defined(HAVE_DECL_SRAND48) && !HAVE_DECL_SRAND48
							 | 
						||
| 
								 | 
							
								extern void srand48(long);
							 | 
						||
| 
								 | 
							
								#  endif
							 | 
						||
| 
								 | 
							
								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 128    /* 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_MALLOC)
							 | 
						||
| 
								 | 
							
								     /* Our own 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 + MIN_ALIGNMENT))) {
							 | 
						||
| 
								 | 
							
									       p = (void *) (((size_t) p0 + MIN_ALIGNMENT) & (~((size_t) (MIN_ALIGNMENT - 1))));
							 | 
						||
| 
								 | 
							
									       *((void **) p - 1) = p0;
							 | 
						||
| 
								 | 
							
									  }
							 | 
						||
| 
								 | 
							
									  else
							 | 
						||
| 
								 | 
							
									       p = (void *) 0;
							 | 
						||
| 
								 | 
							
								     }
							 | 
						||
| 
								 | 
							
								#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 WITH_OUR_MALLOC
							 | 
						||
| 
								 | 
							
								     if (p) free(*((void **) p - 1));
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								     real_free(p);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void bench_free0(void *p)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								     if (p) bench_free(p);
							 | 
						||
| 
								 | 
							
								}
							 |