cannam@167
|
1 /*
|
cannam@167
|
2 * Copyright (c) 2000 Matteo Frigo
|
cannam@167
|
3 * Copyright (c) 2000 Massachusetts Institute of Technology
|
cannam@167
|
4 *
|
cannam@167
|
5 * This program is free software; you can redistribute it and/or modify
|
cannam@167
|
6 * it under the terms of the GNU General Public License as published by
|
cannam@167
|
7 * the Free Software Foundation; either version 2 of the License, or
|
cannam@167
|
8 * (at your option) any later version.
|
cannam@167
|
9 *
|
cannam@167
|
10 * This program is distributed in the hope that it will be useful,
|
cannam@167
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
cannam@167
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
cannam@167
|
13 * GNU General Public License for more details.
|
cannam@167
|
14 *
|
cannam@167
|
15 * You should have received a copy of the GNU General Public License
|
cannam@167
|
16 * along with this program; if not, write to the Free Software
|
cannam@167
|
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
cannam@167
|
18 *
|
cannam@167
|
19 */
|
cannam@167
|
20
|
cannam@167
|
21 #include "libbench2/bench.h"
|
cannam@167
|
22 #include <stdlib.h>
|
cannam@167
|
23 #include <stdio.h>
|
cannam@167
|
24 #include <stddef.h>
|
cannam@167
|
25 #include <math.h>
|
cannam@167
|
26
|
cannam@167
|
27 #if defined(HAVE_MALLOC_H)
|
cannam@167
|
28 # include <malloc.h>
|
cannam@167
|
29 #endif
|
cannam@167
|
30
|
cannam@167
|
31 #if defined(HAVE_DECL_MEMALIGN) && !HAVE_DECL_MEMALIGN
|
cannam@167
|
32 extern void *memalign(size_t, size_t);
|
cannam@167
|
33 #endif
|
cannam@167
|
34
|
cannam@167
|
35 #if defined(HAVE_DECL_POSIX_MEMALIGN) && !HAVE_DECL_POSIX_MEMALIGN
|
cannam@167
|
36 extern int posix_memalign(void **, size_t, size_t);
|
cannam@167
|
37 #endif
|
cannam@167
|
38
|
cannam@167
|
39 void bench_assertion_failed(const char *s, int line, const char *file)
|
cannam@167
|
40 {
|
cannam@167
|
41 ovtpvt_err("bench: %s:%d: assertion failed: %s\n", file, line, s);
|
cannam@167
|
42 bench_exit(EXIT_FAILURE);
|
cannam@167
|
43 }
|
cannam@167
|
44
|
cannam@167
|
45 #ifdef HAVE_DRAND48
|
cannam@167
|
46 # if defined(HAVE_DECL_DRAND48) && !HAVE_DECL_DRAND48
|
cannam@167
|
47 extern double drand48(void);
|
cannam@167
|
48 # endif
|
cannam@167
|
49 double bench_drand(void)
|
cannam@167
|
50 {
|
cannam@167
|
51 return drand48() - 0.5;
|
cannam@167
|
52 }
|
cannam@167
|
53 # if defined(HAVE_DECL_SRAND48) && !HAVE_DECL_SRAND48
|
cannam@167
|
54 extern void srand48(long);
|
cannam@167
|
55 # endif
|
cannam@167
|
56 void bench_srand(int seed)
|
cannam@167
|
57 {
|
cannam@167
|
58 srand48(seed);
|
cannam@167
|
59 }
|
cannam@167
|
60 #else
|
cannam@167
|
61 double bench_drand(void)
|
cannam@167
|
62 {
|
cannam@167
|
63 double d = rand();
|
cannam@167
|
64 return (d / (double) RAND_MAX) - 0.5;
|
cannam@167
|
65 }
|
cannam@167
|
66 void bench_srand(int seed)
|
cannam@167
|
67 {
|
cannam@167
|
68 srand(seed);
|
cannam@167
|
69 }
|
cannam@167
|
70 #endif
|
cannam@167
|
71
|
cannam@167
|
72 /**********************************************************
|
cannam@167
|
73 * DEBUGGING CODE
|
cannam@167
|
74 **********************************************************/
|
cannam@167
|
75 #ifdef BENCH_DEBUG
|
cannam@167
|
76 static int bench_malloc_cnt = 0;
|
cannam@167
|
77
|
cannam@167
|
78 /*
|
cannam@167
|
79 * debugging malloc/free. Initialize every malloced and freed area to
|
cannam@167
|
80 * random values, just to make sure we are not using uninitialized
|
cannam@167
|
81 * pointers. Also check for writes past the ends of allocated blocks,
|
cannam@167
|
82 * and a couple of other things.
|
cannam@167
|
83 *
|
cannam@167
|
84 * This code is a quick and dirty hack -- use at your own risk.
|
cannam@167
|
85 */
|
cannam@167
|
86
|
cannam@167
|
87 static int bench_malloc_total = 0, bench_malloc_max = 0, bench_malloc_cnt_max = 0;
|
cannam@167
|
88
|
cannam@167
|
89 #define MAGIC ((size_t)0xABadCafe)
|
cannam@167
|
90 #define PAD_FACTOR 2
|
cannam@167
|
91 #define TWO_SIZE_T (2 * sizeof(size_t))
|
cannam@167
|
92
|
cannam@167
|
93 #define VERBOSE_ALLOCATION 0
|
cannam@167
|
94
|
cannam@167
|
95 #if VERBOSE_ALLOCATION
|
cannam@167
|
96 #define WHEN_VERBOSE(a) a
|
cannam@167
|
97 #else
|
cannam@167
|
98 #define WHEN_VERBOSE(a)
|
cannam@167
|
99 #endif
|
cannam@167
|
100
|
cannam@167
|
101 void *bench_malloc(size_t n)
|
cannam@167
|
102 {
|
cannam@167
|
103 char *p;
|
cannam@167
|
104 size_t i;
|
cannam@167
|
105
|
cannam@167
|
106 bench_malloc_total += n;
|
cannam@167
|
107
|
cannam@167
|
108 if (bench_malloc_total > bench_malloc_max)
|
cannam@167
|
109 bench_malloc_max = bench_malloc_total;
|
cannam@167
|
110
|
cannam@167
|
111 p = (char *) malloc(PAD_FACTOR * n + TWO_SIZE_T);
|
cannam@167
|
112 BENCH_ASSERT(p);
|
cannam@167
|
113
|
cannam@167
|
114 /* store the size in a known position */
|
cannam@167
|
115 ((size_t *) p)[0] = n;
|
cannam@167
|
116 ((size_t *) p)[1] = MAGIC;
|
cannam@167
|
117 for (i = 0; i < PAD_FACTOR * n; i++)
|
cannam@167
|
118 p[i + TWO_SIZE_T] = (char) (i ^ 0xDEADBEEF);
|
cannam@167
|
119
|
cannam@167
|
120 ++bench_malloc_cnt;
|
cannam@167
|
121
|
cannam@167
|
122 if (bench_malloc_cnt > bench_malloc_cnt_max)
|
cannam@167
|
123 bench_malloc_cnt_max = bench_malloc_cnt;
|
cannam@167
|
124
|
cannam@167
|
125 /* skip the size we stored previously */
|
cannam@167
|
126 return (void *) (p + TWO_SIZE_T);
|
cannam@167
|
127 }
|
cannam@167
|
128
|
cannam@167
|
129 void bench_free(void *p)
|
cannam@167
|
130 {
|
cannam@167
|
131 char *q;
|
cannam@167
|
132
|
cannam@167
|
133 BENCH_ASSERT(p);
|
cannam@167
|
134
|
cannam@167
|
135 q = ((char *) p) - TWO_SIZE_T;
|
cannam@167
|
136 BENCH_ASSERT(q);
|
cannam@167
|
137
|
cannam@167
|
138 {
|
cannam@167
|
139 size_t n = ((size_t *) q)[0];
|
cannam@167
|
140 size_t magic = ((size_t *) q)[1];
|
cannam@167
|
141 size_t i;
|
cannam@167
|
142
|
cannam@167
|
143 ((size_t *) q)[0] = 0; /* set to zero to detect duplicate free's */
|
cannam@167
|
144
|
cannam@167
|
145 BENCH_ASSERT(magic == MAGIC);
|
cannam@167
|
146 ((size_t *) q)[1] = ~MAGIC;
|
cannam@167
|
147
|
cannam@167
|
148 bench_malloc_total -= n;
|
cannam@167
|
149 BENCH_ASSERT(bench_malloc_total >= 0);
|
cannam@167
|
150
|
cannam@167
|
151 /* check for writing past end of array: */
|
cannam@167
|
152 for (i = n; i < PAD_FACTOR * n; ++i)
|
cannam@167
|
153 if (q[i + TWO_SIZE_T] != (char) (i ^ 0xDEADBEEF)) {
|
cannam@167
|
154 BENCH_ASSERT(0 /* array bounds overwritten */);
|
cannam@167
|
155 }
|
cannam@167
|
156 for (i = 0; i < PAD_FACTOR * n; ++i)
|
cannam@167
|
157 q[i + TWO_SIZE_T] = (char) (i ^ 0xBEEFDEAD);
|
cannam@167
|
158
|
cannam@167
|
159 --bench_malloc_cnt;
|
cannam@167
|
160
|
cannam@167
|
161 BENCH_ASSERT(bench_malloc_cnt >= 0);
|
cannam@167
|
162
|
cannam@167
|
163 BENCH_ASSERT(
|
cannam@167
|
164 (bench_malloc_cnt == 0 && bench_malloc_total == 0) ||
|
cannam@167
|
165 (bench_malloc_cnt > 0 && bench_malloc_total > 0));
|
cannam@167
|
166
|
cannam@167
|
167 free(q);
|
cannam@167
|
168 }
|
cannam@167
|
169 }
|
cannam@167
|
170
|
cannam@167
|
171 #else
|
cannam@167
|
172 /**********************************************************
|
cannam@167
|
173 * NON DEBUGGING CODE
|
cannam@167
|
174 **********************************************************/
|
cannam@167
|
175 /* production version, no hacks */
|
cannam@167
|
176
|
cannam@167
|
177 #define MIN_ALIGNMENT 128 /* must be power of two */
|
cannam@167
|
178
|
cannam@167
|
179 #define real_free free /* memalign and malloc use ordinary free */
|
cannam@167
|
180
|
cannam@167
|
181 void *bench_malloc(size_t n)
|
cannam@167
|
182 {
|
cannam@167
|
183 void *p;
|
cannam@167
|
184 if (n == 0) n = 1;
|
cannam@167
|
185
|
cannam@167
|
186 #if defined(WITH_OUR_MALLOC)
|
cannam@167
|
187 /* Our own aligned malloc/free. Assumes sizeof(void*) is
|
cannam@167
|
188 a power of two <= 8 and that malloc is at least
|
cannam@167
|
189 sizeof(void*)-aligned. Assumes size_t = uintptr_t. */
|
cannam@167
|
190 {
|
cannam@167
|
191 void *p0;
|
cannam@167
|
192 if ((p0 = malloc(n + MIN_ALIGNMENT))) {
|
cannam@167
|
193 p = (void *) (((size_t) p0 + MIN_ALIGNMENT) & (~((size_t) (MIN_ALIGNMENT - 1))));
|
cannam@167
|
194 *((void **) p - 1) = p0;
|
cannam@167
|
195 }
|
cannam@167
|
196 else
|
cannam@167
|
197 p = (void *) 0;
|
cannam@167
|
198 }
|
cannam@167
|
199 #elif defined(HAVE_MEMALIGN)
|
cannam@167
|
200 p = memalign(MIN_ALIGNMENT, n);
|
cannam@167
|
201 #elif defined(HAVE_POSIX_MEMALIGN)
|
cannam@167
|
202 /* note: posix_memalign is broken in glibc 2.2.5: it constrains
|
cannam@167
|
203 the size, not the alignment, to be (power of two) * sizeof(void*).
|
cannam@167
|
204 The bug seems to have been fixed as of glibc 2.3.1. */
|
cannam@167
|
205 if (posix_memalign(&p, MIN_ALIGNMENT, n))
|
cannam@167
|
206 p = (void*) 0;
|
cannam@167
|
207 #elif defined(__ICC) || defined(__INTEL_COMPILER) || defined(HAVE__MM_MALLOC)
|
cannam@167
|
208 /* Intel's C compiler defines _mm_malloc and _mm_free intrinsics */
|
cannam@167
|
209 p = (void *) _mm_malloc(n, MIN_ALIGNMENT);
|
cannam@167
|
210 # undef real_free
|
cannam@167
|
211 # define real_free _mm_free
|
cannam@167
|
212 #else
|
cannam@167
|
213 p = malloc(n);
|
cannam@167
|
214 #endif
|
cannam@167
|
215
|
cannam@167
|
216 BENCH_ASSERT(p);
|
cannam@167
|
217 return p;
|
cannam@167
|
218 }
|
cannam@167
|
219
|
cannam@167
|
220 void bench_free(void *p)
|
cannam@167
|
221 {
|
cannam@167
|
222 #ifdef WITH_OUR_MALLOC
|
cannam@167
|
223 if (p) free(*((void **) p - 1));
|
cannam@167
|
224 #else
|
cannam@167
|
225 real_free(p);
|
cannam@167
|
226 #endif
|
cannam@167
|
227 }
|
cannam@167
|
228
|
cannam@167
|
229 #endif
|
cannam@167
|
230
|
cannam@167
|
231 void bench_free0(void *p)
|
cannam@167
|
232 {
|
cannam@167
|
233 if (p) bench_free(p);
|
cannam@167
|
234 }
|