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