Actual source code: mtr.c
1: /*
2: Interface to malloc() and free(). This code allows for
3: logging of memory usage and some error checking
4: */
5: #include petsc.h
6: #include petscsys.h
7: #if defined(PETSC_HAVE_STDLIB_H)
8: #include <stdlib.h>
9: #endif
10: #if defined(PETSC_HAVE_MALLOC_H) && !defined(__cplusplus)
11: #include <malloc.h>
12: #endif
13: #include "petscfix.h"
16: /*
17: These are defined in mal.c and ensure that malloced space is PetscScalar aligned
18: */
19: EXTERN PetscErrorCode PetscMallocAlign(size_t,int,const char[],const char[],const char[],void**);
20: EXTERN PetscErrorCode PetscFreeAlign(void*,int,const char[],const char[],const char[]);
21: EXTERN PetscErrorCode PetscTrMallocDefault(size_t,int,const char[],const char[],const char[],void**);
22: EXTERN PetscErrorCode PetscTrFreeDefault(void*,int,const char[],const char[],const char[]);
24: /*
25: Code for checking if a pointer is out of the range
26: of malloced memory. This will only work on flat memory models and
27: even then is suspicious.
28: */
29: #if (PETSC_SIZEOF_VOID_P == 8)
30: void *PetscLow = (void*)0x0 ,*PetscHigh = (void*)0xEEEEEEEEEEEEEEEE;
31: #else
32: void *PetscLow = (void*)0x0,*PetscHigh = (void*)0xEEEEEEEE;
33: #endif
37: PetscErrorCode PetscSetUseTrMalloc_Private(void)
38: {
42: #if (PETSC_SIZEOF_VOID_P == 8)
43: PetscLow = (void*)0xEEEEEEEEEEEEEEEE;
44: #else
45: PetscLow = (void*)0xEEEEEEEE;
46: #endif
47: PetscHigh = (void*)0x0;
48: PetscSetMalloc(PetscTrMallocDefault,PetscTrFreeDefault);
49: return(0);
50: }
52: /*
53: PetscTrSpace - Routines for tracing space usage.
55: Description:
56: PetscTrMalloc replaces malloc and PetscTrFree replaces free. These routines
57: have the same syntax and semantics as the routines that they replace,
58: In addition, there are routines to report statistics on the memory
59: usage, and to report the currently allocated space. These routines
60: are built on top of malloc and free, and can be used together with
61: them as long as any space allocated with PetscTrMalloc is only freed with
62: PetscTrFree.
63: */
66: #if (PETSC_SIZEOF_VOID_P == 8)
67: #define TR_ALIGN_BYTES 8
68: #define TR_ALIGN_MASK 0x7
69: #else
70: #define TR_ALIGN_BYTES 4
71: #define TR_ALIGN_MASK 0x3
72: #endif
74: #define COOKIE_VALUE 0xf0e0d0c9
75: #define ALREADY_FREED 0x0f0e0d9c
76: #define MAX_TR_STACK 20
77: #define TR_MALLOC 0x1
78: #define TR_FREE 0x2
80: typedef struct _trSPACE {
81: unsigned long size;
82: int id;
83: int lineno;
84: const char *filename;
85: const char *functionname;
86: const char *dirname;
87: unsigned long cookie;
88: #if defined(PETSC_USE_STACK)
89: PetscStack stack;
90: #endif
91: struct _trSPACE *next,*prev;
92: } TRSPACE;
94: /* HEADER_DOUBLES is the number of doubles in a PetscTrSpace header */
95: /* We have to be careful about alignment rules here */
97: #define HEADER_DOUBLES sizeof(TRSPACE)/sizeof(double)+1
100: /* This union is used to insure that the block passed to the user is
101: aligned on a double boundary */
102: typedef union {
103: TRSPACE sp;
104: double v[HEADER_DOUBLES];
105: } TrSPACE;
107: static long TRallocated = 0,TRfrags = 0;
108: static TRSPACE *TRhead = 0;
109: static int TRid = 0;
110: static PetscTruth TRdebugLevel = PETSC_FALSE;
111: static long TRMaxMem = 0;
112: /*
113: Arrays to log information on all Mallocs
114: */
115: static int PetscLogMallocMax = 10000,PetscLogMalloc = -1,*PetscLogMallocLength;
116: static const char **PetscLogMallocDirectory,**PetscLogMallocFile,**PetscLogMallocFunction;
120: /*@C
121: PetscTrValid - Test the memory for corruption. This can be used to
122: check for memory overwrites.
124: Input Parameter:
125: + line - line number where call originated.
126: . function - name of function calling
127: . file - file where function is
128: - dir - directory where function is
130: Return value:
131: The number of errors detected.
132:
133: Output Effect:
134: Error messages are written to stdout.
136: Level: advanced
138: Notes:
139: You should generally use CHKMEMQ as a short cut for calling this
140: routine.
142: The line, function, file and dir are given by the C preprocessor as
143: __LINE__, __FUNCT__, __FILE__, and __DIR__
145: The Fortran calling sequence is simply PetscTrValid(ierr)
147: No output is generated if there are no problems detected.
149: .seealso: CHKMEMQ
151: @*/
152: PetscErrorCode PetscTrValid(int line,const char function[],const char file[],const char dir[])
153: {
154: TRSPACE *head;
155: char *a;
156: unsigned long *nend;
159: head = TRhead;
160: while (head) {
161: if (head->cookie != COOKIE_VALUE) {
162: (*PetscErrorPrintf)("PetscTRValid: error detected at %s() line %d in %s%s\n",function,line,dir,file);
163: (*PetscErrorPrintf)("Memory at address %p is corrupted\n",head);
164: (*PetscErrorPrintf)("Probably write past beginning or end of array\n");
165: SETERRQ(PETSC_ERR_MEMC," ");
166: }
167: if (head->size <=0) {
168: (*PetscErrorPrintf)("PetscTRValid: error detected at %s() line %d in %s%s\n",function,line,dir,file);
169: (*PetscErrorPrintf)("Memory at address %p is corrupted\n",head);
170: (*PetscErrorPrintf)("Probably write past beginning or end of array\n");
171: SETERRQ(PETSC_ERR_MEMC," ");
172: }
173: a = (char *)(((TrSPACE*)head) + 1);
174: nend = (unsigned long *)(a + head->size);
175: if (nend[0] != COOKIE_VALUE) {
176: (*PetscErrorPrintf)("PetscTRValid: error detected at %s() line %d in %s%s\n",function,line,dir,file);
177: if (nend[0] == ALREADY_FREED) {
178: (*PetscErrorPrintf)("Memory [id=%d(%lx)] at address %p already freed\n",head->id,head->size,a);
179: SETERRQ(PETSC_ERR_MEMC," ");
180: } else {
181: (*PetscErrorPrintf)("Memory [id=%d(%lx)] at address %p is corrupted (probably write past end)\n",
182: head->id,head->size,a);
183: (*PetscErrorPrintf)("Memory originally allocated in %s() line %d in %s%s\n",head->functionname,
184: head->lineno,head->dirname,head->filename);
185: SETERRQ(PETSC_ERR_MEMC," ");
186: }
187: }
188: head = head->next;
189: }
190: return(0);
191: }
195: /*
196: PetscTrMallocDefault - Malloc with tracing.
198: Input Parameters:
199: + a - number of bytes to allocate
200: . lineno - line number where used. Use __LINE__ for this
201: . function - function calling routine. Use __FUNCT__ for this
202: . filename - file name where used. Use __FILE__ for this
203: - dir - directory where file is. Use __SDIR__ for this
205: Returns:
206: double aligned pointer to requested storage, or null if not
207: available.
208: */
209: PetscErrorCode PetscTrMallocDefault(size_t a,int lineno,const char function[],const char filename[],const char dir[],void**result)
210: {
211: TRSPACE *head;
212: char *inew;
213: unsigned long *nend;
214: size_t nsize;
218: if (TRdebugLevel) {
219: PetscTrValid(lineno,function,filename,dir); if (ierr) PetscFunctionReturn(ierr);
220: }
221: if (!a) SETERRQ(PETSC_ERR_MEM_MALLOC_0,"Cannot malloc size zero");
223: nsize = a;
224: if (nsize & TR_ALIGN_MASK) nsize += (TR_ALIGN_BYTES - (nsize & TR_ALIGN_MASK));
225: PetscMallocAlign(nsize+sizeof(TrSPACE)+sizeof(PetscScalar),lineno,function,filename,dir,(void**)&inew);
228: /*
229: Keep track of range of memory locations we have malloced in
230: */
231: if (PetscLow > (void*)inew) PetscLow = (void*)inew;
232: if (PetscHigh < (void*)(inew+nsize+sizeof(TrSPACE)+sizeof(unsigned long))) {
233: PetscHigh = (void*)(inew+nsize+sizeof(TrSPACE)+sizeof(unsigned long));
234: }
236: head = (TRSPACE *)inew;
237: inew += sizeof(TrSPACE);
239: if (TRhead) TRhead->prev = head;
240: head->next = TRhead;
241: TRhead = head;
242: head->prev = 0;
243: head->size = nsize;
244: head->id = TRid;
245: head->lineno = lineno;
247: head->filename = filename;
248: head->functionname = function;
249: head->dirname = dir;
250: head->cookie = COOKIE_VALUE;
251: nend = (unsigned long *)(inew + nsize);
252: nend[0] = COOKIE_VALUE;
254: TRallocated += nsize;
255: if (TRallocated > TRMaxMem) {
256: TRMaxMem = TRallocated;
257: }
258: TRfrags++;
260: #if defined(PETSC_USE_STACK)
261: PetscStackCopy(petscstack,&head->stack);
262: #endif
264: /*
265: Allow logging of all mallocs made
266: */
267: if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax) {
268: if (!PetscLogMalloc) {
269: PetscLogMallocLength = (int*)malloc(PetscLogMallocMax*sizeof(int));
270: if (!PetscLogMallocLength) SETERRQ(PETSC_ERR_MEM," ");
271: PetscLogMallocDirectory = (const char**)malloc(PetscLogMallocMax*sizeof(char**));
272: if (!PetscLogMallocDirectory) SETERRQ(PETSC_ERR_MEM," ");
273: PetscLogMallocFile = (const char**)malloc(PetscLogMallocMax*sizeof(char**));
274: if (!PetscLogMallocFile) SETERRQ(PETSC_ERR_MEM," ");
275: PetscLogMallocFunction = (const char**)malloc(PetscLogMallocMax*sizeof(char**));
276: if (!PetscLogMallocFunction) SETERRQ(PETSC_ERR_MEM," ");
277: }
278: PetscLogMallocLength[PetscLogMalloc] = nsize;
279: PetscLogMallocDirectory[PetscLogMalloc] = dir;
280: PetscLogMallocFile[PetscLogMalloc] = filename;
281: PetscLogMallocFunction[PetscLogMalloc++] = function;
282: }
283: *result = (void*)inew;
284: return(0);
285: }
290: /*
291: PetscTrFreeDefault - Free with tracing.
293: Input Parameters:
294: . a - pointer to a block allocated with PetscTrMalloc
295: . lineno - line number where used. Use __LINE__ for this
296: . function - function calling routine. Use __FUNCT__ for this
297: . file - file name where used. Use __FILE__ for this
298: . dir - directory where file is. Use __SDIR__ for this
299: */
300: PetscErrorCode PetscTrFreeDefault(void *aa,int line,const char function[],const char file[],const char dir[])
301: {
302: char *a = (char*)aa;
303: TRSPACE *head;
304: char *ahead;
306: unsigned long *nend;
307:
309: /* Do not try to handle empty blocks */
310: if (!a) {
311: (*PetscErrorPrintf)("PetscTrFreeDefault called from %s() line %d in %s%s\n",function,line,dir,file);
312: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Trying to free null block");
313: }
314:
315: if (TRdebugLevel) {
316: PetscTrValid(line,function,file,dir);
317: }
318:
319: if (PetscLow > aa || PetscHigh < aa){
320: (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s%s\n",function,line,dir,file);
321: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"PetscTrFreeDefault() called with address not allocated by PetscTrMallocDefault()");
322: }
323:
324: ahead = a;
325: a = a - sizeof(TrSPACE);
326: head = (TRSPACE *)a;
327:
328: if (head->cookie != COOKIE_VALUE) {
329: (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s%s\n",function,line,dir,file);
330: (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\n\
331: may be block not allocated with PetscTrMalloc or PetscMalloc\n",a);
332: SETERRQ(PETSC_ERR_MEMC,"Bad location or corrupted memory");
333: }
334: nend = (unsigned long *)(ahead + head->size);
335: if (*nend != COOKIE_VALUE) {
336: if (*nend == ALREADY_FREED) {
337: (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s%s\n",function,line,dir,file);
338: (*PetscErrorPrintf)("Block [id=%d(%lx)] at address %p was already freed\n",
339: head->id,head->size,a + sizeof(TrSPACE));
340: if (head->lineno > 0 && head->lineno < 5000 /* sanity check */) {
341: (*PetscErrorPrintf)("Block freed in %s() line %d in %s%s\n",head->functionname,
342: head->lineno,head->dirname,head->filename);
343: } else {
344: (*PetscErrorPrintf)("Block allocated in %s() line %d in %s%s\n",head->functionname,
345: -head->lineno,head->dirname,head->filename);
346: }
347: SETERRQ(PETSC_ERR_ARG_WRONG,"Memory already freed");
348: } else {
349: /* Damaged tail */
350: (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s%s\n",function,line,dir,file);
351: (*PetscErrorPrintf)("Block [id=%d(%lx)] at address %p is corrupted (probably write past end)\n",
352: head->id,head->size,a);
353: (*PetscErrorPrintf)("Block allocated in %s() line %d in %s%s\n",head->functionname,
354: head->lineno,head->dirname,head->filename);
355: SETERRQ(PETSC_ERR_MEMC,"Corrupted memory");
356: }
357: }
358: /* Mark the location freed */
359: *nend = ALREADY_FREED;
360: /* Save location where freed. If we suspect the line number, mark as
361: allocated location */
362: if (line > 0 && line < 50000) {
363: head->lineno = line;
364: head->filename = file;
365: head->functionname = function;
366: head->dirname = dir;
367: } else {
368: head->lineno = - head->lineno;
369: }
370: /* zero out memory - helps to find some reuse of already freed memory */
371: PetscMemzero(aa,(int)(head->size));
372:
373: TRallocated -= head->size;
374: TRfrags --;
375: if (head->prev) head->prev->next = head->next;
376: else TRhead = head->next;
377:
378: if (head->next) head->next->prev = head->prev;
379: PetscFreeAlign(a,line,function,file,dir);
380: return(0);
381: }
386: /*@
387: PetscShowMemoryUsage - Shows the amount of memory currently being used
388: in a communicator.
389:
390: Collective on PetscViewer
392: Input Parameter:
393: + viewer - the viewer that defines the communicator
394: - message - string printed before values
396: Level: intermediate
398: Concepts: memory usage
400: .seealso: PetscTrDump(),PetscTrSpace(), PetscGetResidentSetSize()
401: @*/
402: PetscErrorCode PetscShowMemoryUsage(PetscViewer viewer,const char message[])
403: {
404: PetscLogDouble allocated,maximum,resident;
406: PetscMPIInt rank;
407: MPI_Comm comm;
410: PetscTrSpace(&allocated,PETSC_NULL,&maximum);
411: PetscGetResidentSetSize(&resident);
412: PetscObjectGetComm((PetscObject)viewer,&comm);
413: MPI_Comm_rank(comm,&rank);
414: PetscViewerASCIIPrintf(viewer,message);
415: if (resident) {
416: PetscViewerASCIISynchronizedPrintf(viewer,"[%d]Space allocated %g, max space allocated %g, process memory %g\n",rank,allocated,maximum,resident);
417: } else {
418: PetscViewerASCIISynchronizedPrintf(viewer,"[%d]Space allocated %g, max space allocated %g, OS cannot compute process memory\n",rank,allocated,maximum);
419: }
420: PetscViewerFlush(viewer);
421: return(0);
422: }
426: /*@C
427: PetscTrSpace - Returns space statistics.
428:
429: Not Collective
431: Output Parameters:
432: + space - number of bytes currently allocated
433: . frags - number of blocks currently allocated
434: - maxs - maximum number of bytes ever allocated
436: Level: intermediate
438: Concepts: memory usage
440: .seealso: PetscTrDump()
441: @*/
442: PetscErrorCode PetscTrSpace(PetscLogDouble *space,PetscLogDouble *fr,PetscLogDouble *maxs)
443: {
446: if (space) *space = (PetscLogDouble) TRallocated;
447: if (fr) *fr = (PetscLogDouble) TRfrags;
448: if (maxs) *maxs = (PetscLogDouble) TRMaxMem;
449: return(0);
450: }
454: /*@C
455: PetscTrDump - Dumps the allocated memory blocks to a file. The information
456: printed is: size of space (in bytes), address of space, id of space,
457: file in which space was allocated, and line number at which it was
458: allocated.
460: Collective on PETSC_COMM_WORLD
462: Input Parameter:
463: . fp - file pointer. If fp is NULL, stdout is assumed.
465: Options Database Key:
466: . -trdump - Dumps unfreed memory during call to PetscFinalize()
468: Level: intermediate
470: Fortran Note:
471: The calling sequence in Fortran is PetscTrDump(integer ierr)
472: The fp defaults to stdout.
474: Notes: uses MPI_COMM_WORLD, because this may be called in PetscFinalize() after PETSC_COMM_WORLD
475: has been freed.
477: Concepts: memory usage
478: Concepts: memory bleeding
479: Concepts: bleeding memory
481: .seealso: PetscTrSpace(), PetscTrLogDump()
482: @*/
483: PetscErrorCode PetscTrDump(FILE *fp)
484: {
485: TRSPACE *head;
487: PetscMPIInt rank;
490: MPI_Comm_rank(MPI_COMM_WORLD,&rank);
491: if (!fp) fp = stdout;
492: if (TRallocated > 0) {
493: fprintf(fp,"[%d]Total space allocated %d bytes\n",rank,(int)TRallocated);
494: }
495: head = TRhead;
496: while (head) {
497: fprintf(fp,"[%2d]%d bytes %s() line %d in %s%s\n",rank,(int)head->size,
498: head->functionname,head->lineno,head->dirname,head->filename);
499: #if defined(PETSC_USE_STACK)
500: PetscStackPrint(&head->stack,fp);
501: #endif
502: head = head->next;
503: }
504: return(0);
505: }
507: /* ---------------------------------------------------------------------------- */
511: /*@C
512: PetscTrLog - Activates logging of all calls to malloc.
514: Not Collective
516: Options Database Key:
517: . -trmalloc_log - Activates PetscTrLog() and PetscTrLogDump()
519: Level: advanced
521: .seealso: PetscTrLogDump()
522: @*/
523: PetscErrorCode PetscTrLog(void)
524: {
527: PetscLogMalloc = 0;
528: return(0);
529: }
533: /*@C
534: PetscTrLogDump - Dumps the log of all calls to malloc; also calls
535: PetscGetResidentSetSize().
537: Collective on PETSC_COMM_WORLD
539: Input Parameter:
540: . fp - file pointer; or PETSC_NULL
542: Options Database Key:
543: . -trmalloc_log - Activates PetscTrLog() and PetscTrLogDump()
545: Level: advanced
547: Fortran Note:
548: The calling sequence in Fortran is PetscTrLogDump(integer ierr)
549: The fp defaults to stdout.
551: .seealso: PetscTrLog(), PetscTrDump()
552: @*/
553: PetscErrorCode PetscTrLogDump(FILE *fp)
554: {
555: PetscInt i,j,n,*shortlength,dummy,*perm;
556: PetscMPIInt rank,size,tag = 1212 /* very bad programming */;
557: PetscTruth match;
558: const char **shortfunction;
559: PetscLogDouble rss;
560: MPI_Status status;
564: MPI_Comm_rank(MPI_COMM_WORLD,&rank);
565: MPI_Comm_size(MPI_COMM_WORLD,&size);
566: /*
567: Try to get the data printed in order by processor. This will only sometimes work
568: */
569: fflush(fp);
570: MPI_Barrier(MPI_COMM_WORLD);
571: if (rank) {
572: MPI_Recv(&dummy,1,MPIU_INT,rank-1,tag,MPI_COMM_WORLD,&status);
573: }
575: if (!fp) fp = stdout;
576: PetscGetResidentSetSize(&rss);
577: if (rss) {
578: PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Maximum memory used %D Size of entire process %D\n",rank,(PetscInt)TRMaxMem,(PetscInt)rss);
579: } else {
580: PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Maximum memory used %D OS cannot compute size of entire process\n",rank,(PetscInt)TRMaxMem);
581: }
582: shortlength = (PetscInt*)malloc(PetscLogMalloc*sizeof(PetscInt));if (!shortlength) SETERRQ(PETSC_ERR_MEM,"Out of memory");
583: shortfunction = (const char**)malloc(PetscLogMalloc*sizeof(char *));if (!shortfunction) SETERRQ(PETSC_ERR_MEM,"Out of memory");
584: shortfunction[0] = PetscLogMallocFunction[0];
585: shortlength[0] = PetscLogMallocLength[0];
586: n = 1;
587: for (i=1; i<PetscLogMalloc; i++) {
588: for (j=0; j<n; j++) {
589: PetscStrcmp(shortfunction[j],PetscLogMallocFunction[i],&match);
590: if (match) {
591: shortlength[j] += PetscLogMallocLength[i];
592: goto foundit;
593: }
594: }
595: shortfunction[n] = PetscLogMallocFunction[i];
596: shortlength[n] = PetscLogMallocLength[i];
597: n++;
598: foundit:;
599: }
601: perm = (PetscInt*)malloc(n*sizeof(PetscInt));if (!perm) SETERRQ(PETSC_ERR_MEM,"Out of memory");
602: for (i=0; i<n; i++) perm[i] = i;
603: PetscSortStrWithPermutation(n,(const char **)shortfunction,perm);
605: PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Memory usage sorted by function\n",rank);
606: for (i=0; i<n; i++) {
607: PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] % 10d %s()\n",rank,shortlength[perm[i]],shortfunction[perm[i]]);
608: }
609: free(perm);
610: free(shortlength);
611: free((char **)shortfunction);
612: fflush(fp);
613: if (rank != size-1) {
614: MPI_Send(&dummy,1,MPIU_INT,rank+1,tag,MPI_COMM_WORLD);
615: }
617: return(0);
618: }
620: /* ---------------------------------------------------------------------------- */
624: /*@C
625: PetscTrDebug - Turns on/off debugging for the memory management routines.
627: Not Collective
629: Input Parameter:
630: . level - PETSC_TRUE or PETSC_FALSE
632: Level: intermediate
634: .seealso: CHKMEMQ(), PetscTrValid()
635: @*/
636: PetscErrorCode PetscTrDebug(PetscTruth level)
637: {
640: TRdebugLevel = level;
641: return(0);
642: }