Chris@10: /* Chris@10: * Copyright (c) 2003, 2007-11 Matteo Frigo Chris@10: * Copyright (c) 2003, 2007-11 Massachusetts Institute of Technology Chris@10: * Chris@10: * This program is free software; you can redistribute it and/or modify Chris@10: * it under the terms of the GNU General Public License as published by Chris@10: * the Free Software Foundation; either version 2 of the License, or Chris@10: * (at your option) any later version. Chris@10: * Chris@10: * This program is distributed in the hope that it will be useful, Chris@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@10: * GNU General Public License for more details. Chris@10: * Chris@10: * You should have received a copy of the GNU General Public License Chris@10: * along with this program; if not, write to the Free Software Chris@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Chris@10: * Chris@10: */ Chris@10: Chris@10: #include "ifftw.h" Chris@10: Chris@10: /********************************************************** Chris@10: * DEBUGGING CODE Chris@10: **********************************************************/ Chris@10: #if defined(FFTW_DEBUG_MALLOC) Chris@10: Chris@10: #include Chris@10: Chris@10: /* Chris@10: debugging malloc/free. Chris@10: Chris@10: 1) Initialize every malloced and freed area to random values, just Chris@10: to make sure we are not using uninitialized pointers. Chris@10: Chris@10: 2) check for blocks freed twice. Chris@10: Chris@10: 3) Check for writes past the ends of allocated blocks Chris@10: Chris@10: 4) destroy contents of freed blocks in order to detect incorrect reuse. Chris@10: Chris@10: 5) keep track of who allocates what and report memory leaks Chris@10: Chris@10: This code is a quick and dirty hack. May be nonportable. Chris@10: Use at your own risk. Chris@10: Chris@10: */ Chris@10: Chris@10: #define MAGIC ((size_t)0xABadCafe) Chris@10: #define PAD_FACTOR 2 Chris@10: #define SZ_HEADER (4 * sizeof(size_t)) Chris@10: #define HASHSZ 1031 Chris@10: Chris@10: static unsigned int hashaddr(void *p) Chris@10: { Chris@10: return ((unsigned long)p) % HASHSZ; Chris@10: } Chris@10: Chris@10: struct mstat { Chris@10: int siz; Chris@10: int maxsiz; Chris@10: int cnt; Chris@10: int maxcnt; Chris@10: }; Chris@10: Chris@10: static struct mstat mstat[MALLOC_WHAT_LAST]; Chris@10: Chris@10: struct minfo { Chris@10: const char *file; Chris@10: int line; Chris@10: size_t n; Chris@10: void *p; Chris@10: struct minfo *next; Chris@10: }; Chris@10: Chris@10: static struct minfo *minfo[HASHSZ] = {0}; Chris@10: Chris@10: #if defined(HAVE_THREADS) || defined(HAVE_OPENMP) Chris@10: int X(in_thread) = 0; Chris@10: #endif Chris@10: Chris@10: void *X(malloc_debug)(size_t n, enum malloc_tag what, Chris@10: const char *file, int line) Chris@10: { Chris@10: char *p; Chris@10: size_t i; Chris@10: struct minfo *info; Chris@10: struct mstat *stat = mstat + what; Chris@10: struct mstat *estat = mstat + EVERYTHING; Chris@10: Chris@10: if (n == 0) Chris@10: n = 1; Chris@10: Chris@10: if (!IN_THREAD) { Chris@10: stat->siz += n; Chris@10: if (stat->siz > stat->maxsiz) Chris@10: stat->maxsiz = stat->siz; Chris@10: estat->siz += n; Chris@10: if (estat->siz > estat->maxsiz) Chris@10: estat->maxsiz = estat->siz; Chris@10: } Chris@10: Chris@10: p = (char *) X(kernel_malloc)(PAD_FACTOR * n + SZ_HEADER); Chris@10: A(p); Chris@10: Chris@10: /* store the sz in a known position */ Chris@10: ((size_t *) p)[0] = n; Chris@10: ((size_t *) p)[1] = MAGIC; Chris@10: ((size_t *) p)[2] = what; Chris@10: Chris@10: /* fill with junk */ Chris@10: for (i = 0; i < PAD_FACTOR * n; i++) Chris@10: p[i + SZ_HEADER] = (char) (i ^ 0xEF); Chris@10: Chris@10: if (!IN_THREAD) { Chris@10: ++stat->cnt; Chris@10: ++estat->cnt; Chris@10: Chris@10: if (stat->cnt > stat->maxcnt) Chris@10: stat->maxcnt = stat->cnt; Chris@10: if (estat->cnt > estat->maxcnt) Chris@10: estat->maxcnt = estat->cnt; Chris@10: } Chris@10: Chris@10: /* skip the info we stored previously */ Chris@10: p = p + SZ_HEADER; Chris@10: Chris@10: if (!IN_THREAD) { Chris@10: unsigned int h = hashaddr(p); Chris@10: /* record allocation in allocation list */ Chris@10: info = (struct minfo *) malloc(sizeof(struct minfo)); Chris@10: info->n = n; Chris@10: info->file = file; Chris@10: info->line = line; Chris@10: info->p = p; Chris@10: info->next = minfo[h]; Chris@10: minfo[h] = info; Chris@10: } Chris@10: Chris@10: return (void *) p; Chris@10: } Chris@10: Chris@10: void X(ifree)(void *p) Chris@10: { Chris@10: char *q; Chris@10: Chris@10: A(p); Chris@10: Chris@10: q = ((char *) p) - SZ_HEADER; Chris@10: A(q); Chris@10: Chris@10: { Chris@10: size_t n = ((size_t *) q)[0]; Chris@10: size_t magic = ((size_t *) q)[1]; Chris@10: int what = ((size_t *) q)[2]; Chris@10: size_t i; Chris@10: struct mstat *stat = mstat + what; Chris@10: struct mstat *estat = mstat + EVERYTHING; Chris@10: Chris@10: /* set to zero to detect duplicate free's */ Chris@10: ((size_t *) q)[0] = 0; Chris@10: Chris@10: A(magic == MAGIC); Chris@10: ((size_t *) q)[1] = ~MAGIC; Chris@10: Chris@10: if (!IN_THREAD) { Chris@10: stat->siz -= n; Chris@10: A(stat->siz >= 0); Chris@10: estat->siz -= n; Chris@10: A(estat->siz >= 0); Chris@10: } Chris@10: Chris@10: /* check for writing past end of array: */ Chris@10: for (i = n; i < PAD_FACTOR * n; ++i) Chris@10: if (q[i + SZ_HEADER] != (char) (i ^ 0xEF)) { Chris@10: A(0 /* array bounds overwritten */ ); Chris@10: } Chris@10: for (i = 0; i < PAD_FACTOR * n; ++i) Chris@10: q[i + SZ_HEADER] = (char) (i ^ 0xAD); Chris@10: Chris@10: if (!IN_THREAD) { Chris@10: --stat->cnt; Chris@10: --estat->cnt; Chris@10: Chris@10: A(stat->cnt >= 0); Chris@10: A((stat->cnt == 0 && stat->siz == 0) || Chris@10: (stat->cnt > 0 && stat->siz > 0)); Chris@10: A(estat->cnt >= 0); Chris@10: A((estat->cnt == 0 && estat->siz == 0) || Chris@10: (estat->cnt > 0 && estat->siz > 0)); Chris@10: } Chris@10: Chris@10: X(kernel_free)(q); Chris@10: } Chris@10: Chris@10: if (!IN_THREAD) { Chris@10: /* delete minfo entry */ Chris@10: unsigned int h = hashaddr(p); Chris@10: struct minfo **i; Chris@10: Chris@10: for (i = minfo + h; *i; i = &((*i)->next)) { Chris@10: if ((*i)->p == p) { Chris@10: struct minfo *i0 = (*i)->next; Chris@10: free(*i); Chris@10: *i = i0; Chris@10: return; Chris@10: } Chris@10: } Chris@10: Chris@10: A(0 /* no entry in minfo list */ ); Chris@10: } Chris@10: } Chris@10: Chris@10: void X(malloc_print_minfo)(int verbose) Chris@10: { Chris@10: struct minfo *info; Chris@10: int what; Chris@10: unsigned int h; Chris@10: int leak = 0; Chris@10: Chris@10: if (verbose > 2) { Chris@10: static const char *names[MALLOC_WHAT_LAST] = { Chris@10: "EVERYTHING", Chris@10: "PLANS", "SOLVERS", "PROBLEMS", "BUFFERS", Chris@10: "HASHT", "TENSORS", "PLANNERS", "SLVDSC", "TWIDDLES", Chris@10: "STRIDES", "OTHER" Chris@10: }; Chris@10: Chris@10: printf("%12s %8s %8s %10s %10s\n", Chris@10: "what", "cnt", "maxcnt", "siz", "maxsiz"); Chris@10: Chris@10: for (what = 0; what < MALLOC_WHAT_LAST; ++what) { Chris@10: struct mstat *stat = mstat + what; Chris@10: printf("%12s %8d %8d %10d %10d\n", Chris@10: names[what], stat->cnt, stat->maxcnt, Chris@10: stat->siz, stat->maxsiz); Chris@10: } Chris@10: } Chris@10: Chris@10: for (h = 0; h < HASHSZ; ++h) Chris@10: if (minfo[h]) { Chris@10: printf("\nUnfreed allocations:\n"); Chris@10: break; Chris@10: } Chris@10: Chris@10: for (h = 0; h < HASHSZ; ++h) Chris@10: for (info = minfo[h]; info; info = info->next) { Chris@10: leak = 1; Chris@10: printf("%s:%d: %zd bytes at %p\n", Chris@10: info->file, info->line, info->n, info->p); Chris@10: } Chris@10: Chris@10: if (leak) Chris@10: abort(); Chris@10: } Chris@10: Chris@10: #else Chris@10: /********************************************************** Chris@10: * NON DEBUGGING CODE Chris@10: **********************************************************/ Chris@10: /* production version, no hacks */ Chris@10: Chris@10: void *X(malloc_plain)(size_t n) Chris@10: { Chris@10: void *p; Chris@10: if (n == 0) Chris@10: n = 1; Chris@10: p = X(kernel_malloc)(n); Chris@10: CK(p); Chris@10: Chris@10: #ifdef MIN_ALIGNMENT Chris@10: A((((uintptr_t)p) % MIN_ALIGNMENT) == 0); Chris@10: #endif Chris@10: Chris@10: return p; Chris@10: } Chris@10: Chris@10: void X(ifree)(void *p) Chris@10: { Chris@10: X(kernel_free)(p); Chris@10: } Chris@10: Chris@10: #endif Chris@10: Chris@10: void X(ifree0)(void *p) Chris@10: { Chris@10: /* common pattern */ Chris@10: if (p) X(ifree)(p); Chris@10: }