cannam@95
|
1 /*
|
cannam@95
|
2 * Copyright (c) 2003, 2007-11 Matteo Frigo
|
cannam@95
|
3 * Copyright (c) 2003, 2007-11 Massachusetts Institute of Technology
|
cannam@95
|
4 *
|
cannam@95
|
5 * This program is free software; you can redistribute it and/or modify
|
cannam@95
|
6 * it under the terms of the GNU General Public License as published by
|
cannam@95
|
7 * the Free Software Foundation; either version 2 of the License, or
|
cannam@95
|
8 * (at your option) any later version.
|
cannam@95
|
9 *
|
cannam@95
|
10 * This program is distributed in the hope that it will be useful,
|
cannam@95
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
cannam@95
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
cannam@95
|
13 * GNU General Public License for more details.
|
cannam@95
|
14 *
|
cannam@95
|
15 * You should have received a copy of the GNU General Public License
|
cannam@95
|
16 * along with this program; if not, write to the Free Software
|
cannam@95
|
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
cannam@95
|
18 *
|
cannam@95
|
19 */
|
cannam@95
|
20
|
cannam@95
|
21 #include "ifftw.h"
|
cannam@95
|
22
|
cannam@95
|
23 /**********************************************************
|
cannam@95
|
24 * DEBUGGING CODE
|
cannam@95
|
25 **********************************************************/
|
cannam@95
|
26 #if defined(FFTW_DEBUG_MALLOC)
|
cannam@95
|
27
|
cannam@95
|
28 #include <stdio.h>
|
cannam@95
|
29
|
cannam@95
|
30 /*
|
cannam@95
|
31 debugging malloc/free.
|
cannam@95
|
32
|
cannam@95
|
33 1) Initialize every malloced and freed area to random values, just
|
cannam@95
|
34 to make sure we are not using uninitialized pointers.
|
cannam@95
|
35
|
cannam@95
|
36 2) check for blocks freed twice.
|
cannam@95
|
37
|
cannam@95
|
38 3) Check for writes past the ends of allocated blocks
|
cannam@95
|
39
|
cannam@95
|
40 4) destroy contents of freed blocks in order to detect incorrect reuse.
|
cannam@95
|
41
|
cannam@95
|
42 5) keep track of who allocates what and report memory leaks
|
cannam@95
|
43
|
cannam@95
|
44 This code is a quick and dirty hack. May be nonportable.
|
cannam@95
|
45 Use at your own risk.
|
cannam@95
|
46
|
cannam@95
|
47 */
|
cannam@95
|
48
|
cannam@95
|
49 #define MAGIC ((size_t)0xABadCafe)
|
cannam@95
|
50 #define PAD_FACTOR 2
|
cannam@95
|
51 #define SZ_HEADER (4 * sizeof(size_t))
|
cannam@95
|
52 #define HASHSZ 1031
|
cannam@95
|
53
|
cannam@95
|
54 static unsigned int hashaddr(void *p)
|
cannam@95
|
55 {
|
cannam@95
|
56 return ((unsigned long)p) % HASHSZ;
|
cannam@95
|
57 }
|
cannam@95
|
58
|
cannam@95
|
59 struct mstat {
|
cannam@95
|
60 int siz;
|
cannam@95
|
61 int maxsiz;
|
cannam@95
|
62 int cnt;
|
cannam@95
|
63 int maxcnt;
|
cannam@95
|
64 };
|
cannam@95
|
65
|
cannam@95
|
66 static struct mstat mstat[MALLOC_WHAT_LAST];
|
cannam@95
|
67
|
cannam@95
|
68 struct minfo {
|
cannam@95
|
69 const char *file;
|
cannam@95
|
70 int line;
|
cannam@95
|
71 size_t n;
|
cannam@95
|
72 void *p;
|
cannam@95
|
73 struct minfo *next;
|
cannam@95
|
74 };
|
cannam@95
|
75
|
cannam@95
|
76 static struct minfo *minfo[HASHSZ] = {0};
|
cannam@95
|
77
|
cannam@95
|
78 #if defined(HAVE_THREADS) || defined(HAVE_OPENMP)
|
cannam@95
|
79 int X(in_thread) = 0;
|
cannam@95
|
80 #endif
|
cannam@95
|
81
|
cannam@95
|
82 void *X(malloc_debug)(size_t n, enum malloc_tag what,
|
cannam@95
|
83 const char *file, int line)
|
cannam@95
|
84 {
|
cannam@95
|
85 char *p;
|
cannam@95
|
86 size_t i;
|
cannam@95
|
87 struct minfo *info;
|
cannam@95
|
88 struct mstat *stat = mstat + what;
|
cannam@95
|
89 struct mstat *estat = mstat + EVERYTHING;
|
cannam@95
|
90
|
cannam@95
|
91 if (n == 0)
|
cannam@95
|
92 n = 1;
|
cannam@95
|
93
|
cannam@95
|
94 if (!IN_THREAD) {
|
cannam@95
|
95 stat->siz += n;
|
cannam@95
|
96 if (stat->siz > stat->maxsiz)
|
cannam@95
|
97 stat->maxsiz = stat->siz;
|
cannam@95
|
98 estat->siz += n;
|
cannam@95
|
99 if (estat->siz > estat->maxsiz)
|
cannam@95
|
100 estat->maxsiz = estat->siz;
|
cannam@95
|
101 }
|
cannam@95
|
102
|
cannam@95
|
103 p = (char *) X(kernel_malloc)(PAD_FACTOR * n + SZ_HEADER);
|
cannam@95
|
104 A(p);
|
cannam@95
|
105
|
cannam@95
|
106 /* store the sz in a known position */
|
cannam@95
|
107 ((size_t *) p)[0] = n;
|
cannam@95
|
108 ((size_t *) p)[1] = MAGIC;
|
cannam@95
|
109 ((size_t *) p)[2] = what;
|
cannam@95
|
110
|
cannam@95
|
111 /* fill with junk */
|
cannam@95
|
112 for (i = 0; i < PAD_FACTOR * n; i++)
|
cannam@95
|
113 p[i + SZ_HEADER] = (char) (i ^ 0xEF);
|
cannam@95
|
114
|
cannam@95
|
115 if (!IN_THREAD) {
|
cannam@95
|
116 ++stat->cnt;
|
cannam@95
|
117 ++estat->cnt;
|
cannam@95
|
118
|
cannam@95
|
119 if (stat->cnt > stat->maxcnt)
|
cannam@95
|
120 stat->maxcnt = stat->cnt;
|
cannam@95
|
121 if (estat->cnt > estat->maxcnt)
|
cannam@95
|
122 estat->maxcnt = estat->cnt;
|
cannam@95
|
123 }
|
cannam@95
|
124
|
cannam@95
|
125 /* skip the info we stored previously */
|
cannam@95
|
126 p = p + SZ_HEADER;
|
cannam@95
|
127
|
cannam@95
|
128 if (!IN_THREAD) {
|
cannam@95
|
129 unsigned int h = hashaddr(p);
|
cannam@95
|
130 /* record allocation in allocation list */
|
cannam@95
|
131 info = (struct minfo *) malloc(sizeof(struct minfo));
|
cannam@95
|
132 info->n = n;
|
cannam@95
|
133 info->file = file;
|
cannam@95
|
134 info->line = line;
|
cannam@95
|
135 info->p = p;
|
cannam@95
|
136 info->next = minfo[h];
|
cannam@95
|
137 minfo[h] = info;
|
cannam@95
|
138 }
|
cannam@95
|
139
|
cannam@95
|
140 return (void *) p;
|
cannam@95
|
141 }
|
cannam@95
|
142
|
cannam@95
|
143 void X(ifree)(void *p)
|
cannam@95
|
144 {
|
cannam@95
|
145 char *q;
|
cannam@95
|
146
|
cannam@95
|
147 A(p);
|
cannam@95
|
148
|
cannam@95
|
149 q = ((char *) p) - SZ_HEADER;
|
cannam@95
|
150 A(q);
|
cannam@95
|
151
|
cannam@95
|
152 {
|
cannam@95
|
153 size_t n = ((size_t *) q)[0];
|
cannam@95
|
154 size_t magic = ((size_t *) q)[1];
|
cannam@95
|
155 int what = ((size_t *) q)[2];
|
cannam@95
|
156 size_t i;
|
cannam@95
|
157 struct mstat *stat = mstat + what;
|
cannam@95
|
158 struct mstat *estat = mstat + EVERYTHING;
|
cannam@95
|
159
|
cannam@95
|
160 /* set to zero to detect duplicate free's */
|
cannam@95
|
161 ((size_t *) q)[0] = 0;
|
cannam@95
|
162
|
cannam@95
|
163 A(magic == MAGIC);
|
cannam@95
|
164 ((size_t *) q)[1] = ~MAGIC;
|
cannam@95
|
165
|
cannam@95
|
166 if (!IN_THREAD) {
|
cannam@95
|
167 stat->siz -= n;
|
cannam@95
|
168 A(stat->siz >= 0);
|
cannam@95
|
169 estat->siz -= n;
|
cannam@95
|
170 A(estat->siz >= 0);
|
cannam@95
|
171 }
|
cannam@95
|
172
|
cannam@95
|
173 /* check for writing past end of array: */
|
cannam@95
|
174 for (i = n; i < PAD_FACTOR * n; ++i)
|
cannam@95
|
175 if (q[i + SZ_HEADER] != (char) (i ^ 0xEF)) {
|
cannam@95
|
176 A(0 /* array bounds overwritten */ );
|
cannam@95
|
177 }
|
cannam@95
|
178 for (i = 0; i < PAD_FACTOR * n; ++i)
|
cannam@95
|
179 q[i + SZ_HEADER] = (char) (i ^ 0xAD);
|
cannam@95
|
180
|
cannam@95
|
181 if (!IN_THREAD) {
|
cannam@95
|
182 --stat->cnt;
|
cannam@95
|
183 --estat->cnt;
|
cannam@95
|
184
|
cannam@95
|
185 A(stat->cnt >= 0);
|
cannam@95
|
186 A((stat->cnt == 0 && stat->siz == 0) ||
|
cannam@95
|
187 (stat->cnt > 0 && stat->siz > 0));
|
cannam@95
|
188 A(estat->cnt >= 0);
|
cannam@95
|
189 A((estat->cnt == 0 && estat->siz == 0) ||
|
cannam@95
|
190 (estat->cnt > 0 && estat->siz > 0));
|
cannam@95
|
191 }
|
cannam@95
|
192
|
cannam@95
|
193 X(kernel_free)(q);
|
cannam@95
|
194 }
|
cannam@95
|
195
|
cannam@95
|
196 if (!IN_THREAD) {
|
cannam@95
|
197 /* delete minfo entry */
|
cannam@95
|
198 unsigned int h = hashaddr(p);
|
cannam@95
|
199 struct minfo **i;
|
cannam@95
|
200
|
cannam@95
|
201 for (i = minfo + h; *i; i = &((*i)->next)) {
|
cannam@95
|
202 if ((*i)->p == p) {
|
cannam@95
|
203 struct minfo *i0 = (*i)->next;
|
cannam@95
|
204 free(*i);
|
cannam@95
|
205 *i = i0;
|
cannam@95
|
206 return;
|
cannam@95
|
207 }
|
cannam@95
|
208 }
|
cannam@95
|
209
|
cannam@95
|
210 A(0 /* no entry in minfo list */ );
|
cannam@95
|
211 }
|
cannam@95
|
212 }
|
cannam@95
|
213
|
cannam@95
|
214 void X(malloc_print_minfo)(int verbose)
|
cannam@95
|
215 {
|
cannam@95
|
216 struct minfo *info;
|
cannam@95
|
217 int what;
|
cannam@95
|
218 unsigned int h;
|
cannam@95
|
219 int leak = 0;
|
cannam@95
|
220
|
cannam@95
|
221 if (verbose > 2) {
|
cannam@95
|
222 static const char *names[MALLOC_WHAT_LAST] = {
|
cannam@95
|
223 "EVERYTHING",
|
cannam@95
|
224 "PLANS", "SOLVERS", "PROBLEMS", "BUFFERS",
|
cannam@95
|
225 "HASHT", "TENSORS", "PLANNERS", "SLVDSC", "TWIDDLES",
|
cannam@95
|
226 "STRIDES", "OTHER"
|
cannam@95
|
227 };
|
cannam@95
|
228
|
cannam@95
|
229 printf("%12s %8s %8s %10s %10s\n",
|
cannam@95
|
230 "what", "cnt", "maxcnt", "siz", "maxsiz");
|
cannam@95
|
231
|
cannam@95
|
232 for (what = 0; what < MALLOC_WHAT_LAST; ++what) {
|
cannam@95
|
233 struct mstat *stat = mstat + what;
|
cannam@95
|
234 printf("%12s %8d %8d %10d %10d\n",
|
cannam@95
|
235 names[what], stat->cnt, stat->maxcnt,
|
cannam@95
|
236 stat->siz, stat->maxsiz);
|
cannam@95
|
237 }
|
cannam@95
|
238 }
|
cannam@95
|
239
|
cannam@95
|
240 for (h = 0; h < HASHSZ; ++h)
|
cannam@95
|
241 if (minfo[h]) {
|
cannam@95
|
242 printf("\nUnfreed allocations:\n");
|
cannam@95
|
243 break;
|
cannam@95
|
244 }
|
cannam@95
|
245
|
cannam@95
|
246 for (h = 0; h < HASHSZ; ++h)
|
cannam@95
|
247 for (info = minfo[h]; info; info = info->next) {
|
cannam@95
|
248 leak = 1;
|
cannam@95
|
249 printf("%s:%d: %zd bytes at %p\n",
|
cannam@95
|
250 info->file, info->line, info->n, info->p);
|
cannam@95
|
251 }
|
cannam@95
|
252
|
cannam@95
|
253 if (leak)
|
cannam@95
|
254 abort();
|
cannam@95
|
255 }
|
cannam@95
|
256
|
cannam@95
|
257 #else
|
cannam@95
|
258 /**********************************************************
|
cannam@95
|
259 * NON DEBUGGING CODE
|
cannam@95
|
260 **********************************************************/
|
cannam@95
|
261 /* production version, no hacks */
|
cannam@95
|
262
|
cannam@95
|
263 void *X(malloc_plain)(size_t n)
|
cannam@95
|
264 {
|
cannam@95
|
265 void *p;
|
cannam@95
|
266 if (n == 0)
|
cannam@95
|
267 n = 1;
|
cannam@95
|
268 p = X(kernel_malloc)(n);
|
cannam@95
|
269 CK(p);
|
cannam@95
|
270
|
cannam@95
|
271 #ifdef MIN_ALIGNMENT
|
cannam@95
|
272 A((((uintptr_t)p) % MIN_ALIGNMENT) == 0);
|
cannam@95
|
273 #endif
|
cannam@95
|
274
|
cannam@95
|
275 return p;
|
cannam@95
|
276 }
|
cannam@95
|
277
|
cannam@95
|
278 void X(ifree)(void *p)
|
cannam@95
|
279 {
|
cannam@95
|
280 X(kernel_free)(p);
|
cannam@95
|
281 }
|
cannam@95
|
282
|
cannam@95
|
283 #endif
|
cannam@95
|
284
|
cannam@95
|
285 void X(ifree0)(void *p)
|
cannam@95
|
286 {
|
cannam@95
|
287 /* common pattern */
|
cannam@95
|
288 if (p) X(ifree)(p);
|
cannam@95
|
289 }
|