Actual source code: mtr.c
1: /*$Id: mtr.c,v 1.157 2001/08/07 03:02:00 balay Exp $*/
2: /*
3: Interface to malloc() and free(). This code allows for
4: logging of memory usage and some error checking
5: */
6: #include petsc.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 int PetscMallocAlign(int,int,char*,char*,char*,void**);
20: EXTERN int PetscFreeAlign(void*,int,char*,char*,char*);
21: EXTERN int PetscTrMallocDefault(int,int,char*,char*,char*,void**);
22: EXTERN int PetscTrFreeDefault(void*,int,char*,char*,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
35: int PetscSetUseTrMalloc_Private(void)
36: {
40: #if (PETSC_SIZEOF_VOID_P == 8)
41: PetscLow = (void*)0xEEEEEEEEEEEEEEEE;
42: #else
43: PetscLow = (void*)0xEEEEEEEE;
44: #endif
45: PetscHigh = (void*)0x0;
46: ierr = PetscSetMalloc(PetscTrMallocDefault,PetscTrFreeDefault);
47: return(0);
48: }
50: /*
51: PetscTrSpace - Routines for tracing space usage.
53: Description:
54: PetscTrMalloc replaces malloc and PetscTrFree replaces free. These routines
55: have the same syntax and semantics as the routines that they replace,
56: In addition, there are routines to report statistics on the memory
57: usage, and to report the currently allocated space. These routines
58: are built on top of malloc and free, and can be used together with
59: them as long as any space allocated with PetscTrMalloc is only freed with
60: PetscTrFree.
61: */
64: #if (PETSC_SIZEOF_VOID_P == 8)
65: #define TR_ALIGN_BYTES 8
66: #define TR_ALIGN_MASK 0x7
67: #else
68: #define TR_ALIGN_BYTES 4
69: #define TR_ALIGN_MASK 0x3
70: #endif
72: #define COOKIE_VALUE 0xf0e0d0c9
73: #define ALREADY_FREED 0x0f0e0d9c
74: #define MAX_TR_STACK 20
75: #define TR_MALLOC 0x1
76: #define TR_FREE 0x2
78: typedef struct _trSPACE {
79: unsigned long size;
80: int id;
81: int lineno;
82: char *filename;
83: char *functionname;
84: char *dirname;
85: unsigned long cookie;
86: #if defined(PETSC_USE_STACK)
87: PetscStack stack;
88: #endif
89: struct _trSPACE *next,*prev;
90: } TRSPACE;
92: /* HEADER_DOUBLES is the number of doubles in a PetscTrSpace header */
93: /* We have to be careful about alignment rules here */
95: #define HEADER_DOUBLES sizeof(TRSPACE)/sizeof(double)+1
98: /* This union is used to insure that the block passed to the user is
99: aligned on a double boundary */
100: typedef union {
101: TRSPACE sp;
102: double v[HEADER_DOUBLES];
103: } TrSPACE;
105: static long TRallocated = 0,TRfrags = 0;
106: static TRSPACE *TRhead = 0;
107: static int TRid = 0;
108: static int TRdebugLevel = 0;
109: static long TRMaxMem = 0;
110: /*
111: Arrays to log information on all Mallocs
112: */
113: static int PetscLogMallocMax = 10000,PetscLogMalloc = -1,*PetscLogMallocLength;
114: static char **PetscLogMallocDirectory,**PetscLogMallocFile,**PetscLogMallocFunction;
116: /*@C
117: PetscTrValid - Test the memory for corruption. This can be used to
118: check for memory overwrites.
120: Input Parameter:
121: + line - line number where call originated.
122: . function - name of function calling
123: . file - file where function is
124: - dir - directory where function is
126: Return value:
127: The number of errors detected.
128:
129: Output Effect:
130: Error messages are written to stdout.
132: Level: advanced
134: Notes:
135: You should generally use CHKMEMQ or CHKMEMA as a short cut for calling this
136: routine.
138: The line, function, file and dir are given by the C preprocessor as
140: The Fortran calling sequence is simply PetscTrValid(ierr)
142: No output is generated if there are no problems detected.
144: .seealso: CHKMEMQ, CHKMEMA
146: @*/
147: int PetscTrValid(int line,const char function[],const char file[],const char dir[])
148: {
149: TRSPACE *head;
150: char *a;
151: unsigned long *nend;
154: head = TRhead;
155: while (head) {
156: if (head->cookie != COOKIE_VALUE) {
157: (*PetscErrorPrintf)("error detected at %s() line %d in %s%sn",function,line,dir,file);
158: (*PetscErrorPrintf)("Memory at address %p is corruptedn",head);
159: (*PetscErrorPrintf)("Probably write past beginning or end of arrayn");
160: SETERRQ(PETSC_ERR_MEMC," ");
161: }
162: if (head->size <=0) {
163: (*PetscErrorPrintf)("error detected at %s() line %d in %s%sn",function,line,dir,file);
164: (*PetscErrorPrintf)("Memory at address %p is corruptedn",head);
165: (*PetscErrorPrintf)("Probably write past beginning or end of arrayn");
166: SETERRQ(PETSC_ERR_MEMC," ");
167: }
168: a = (char *)(((TrSPACE*)head) + 1);
169: nend = (unsigned long *)(a + head->size);
170: if (nend[0] != COOKIE_VALUE) {
171: (*PetscErrorPrintf)("error detected at %s() line %d in %s%sn",function,line,dir,file);
172: if (nend[0] == ALREADY_FREED) {
173: (*PetscErrorPrintf)("Memory [id=%d(%lx)] at address %p already freedn",head->id,head->size,a);
174: } else {
175: (*PetscErrorPrintf)("Memory [id=%d(%lx)] at address %p is corrupted (probably write past end)n",
176: head->id,head->size,a);
177: (*PetscErrorPrintf)("Memory originally allocated in %s() line %d in %s%sn",head->functionname,
178: head->lineno,head->dirname,head->filename);
179: SETERRQ(PETSC_ERR_MEMC," ");
180: }
181: }
182: head = head->next;
183: }
185: return(0);
186: }
188: /*
189: PetscTrMallocDefault - Malloc with tracing.
191: Input Parameters:
192: + a - number of bytes to allocate
193: . lineno - line number where used. Use __LINE__ for this
194: . filename - file name where used. Use __FILE__ for this
195: - dir - directory where file is. Use __SDIR__ for this
197: Returns:
198: double aligned pointer to requested storage, or null if not
199: available.
200: */
201: int PetscTrMallocDefault(int a,int lineno,char *function,char *filename,char *dir,void**result)
202: {
203: TRSPACE *head;
204: char *inew;
205: unsigned long *nend;
206: unsigned int nsize;
207: int ierr;
210: if (TRdebugLevel > 0) {
211: PetscTrValid(lineno,function,filename,dir); if (ierr) PetscFunctionReturn(ierr);
212: }
214: if (!a) {
215: (*PetscErrorPrintf)("PETSC ERROR: PetscTrMalloc: malloc zero length, this is illegal!n");
216: PetscFunctionReturn(1);
217: }
218: if (a < 0) {
219: (*PetscErrorPrintf)("PETSC ERROR: PetscTrMalloc: malloc negative length, this is illegal!n");
220: PetscFunctionReturn(1);
221: }
222: nsize = a;
223: if (nsize & TR_ALIGN_MASK) nsize += (TR_ALIGN_BYTES - (nsize & TR_ALIGN_MASK));
224: PetscMallocAlign((unsigned)(nsize+sizeof(TrSPACE)+sizeof(PetscScalar)),lineno,function,filename,dir,(void**)&inew);
227: /*
228: Keep track of range of memory locations we have malloced in
229: */
230: if (PetscLow > (void*)inew) PetscLow = (void*)inew;
231: if (PetscHigh < (void*)(inew+nsize+sizeof(TrSPACE)+sizeof(unsigned long))) {
232: PetscHigh = (void*)(inew+nsize+sizeof(TrSPACE)+sizeof(unsigned long));
233: }
235: head = (TRSPACE *)inew;
236: inew += sizeof(TrSPACE);
238: if (TRhead) TRhead->prev = head;
239: head->next = TRhead;
240: TRhead = head;
241: head->prev = 0;
242: head->size = nsize;
243: head->id = TRid;
244: head->lineno = lineno;
246: head->filename = filename;
247: head->functionname = function;
248: head->dirname = dir;
249: head->cookie = COOKIE_VALUE;
250: nend = (unsigned long *)(inew + nsize);
251: nend[0] = COOKIE_VALUE;
253: TRallocated += nsize;
254: if (TRallocated > TRMaxMem) {
255: TRMaxMem = TRallocated;
256: }
257: TRfrags++;
259: #if defined(PETSC_USE_STACK)
260: PetscStackCopy(petscstack,&head->stack);
261: #endif
263: /*
264: Allow logging of all mallocs made
265: */
266: if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax) {
267: if (PetscLogMalloc == 0) {
268: PetscLogMallocLength = (int*)malloc(PetscLogMallocMax*sizeof(int));
269: if (!PetscLogMallocLength) SETERRQ(PETSC_ERR_MEM," ");
270: PetscLogMallocDirectory = (char**)malloc(PetscLogMallocMax*sizeof(char**));
271: if (!PetscLogMallocDirectory) SETERRQ(PETSC_ERR_MEM," ");
272: PetscLogMallocFile = (char**)malloc(PetscLogMallocMax*sizeof(char**));
273: if (!PetscLogMallocFile) SETERRQ(PETSC_ERR_MEM," ");
274: PetscLogMallocFunction = (char**)malloc(PetscLogMallocMax*sizeof(char**));
275: if (!PetscLogMallocFunction) SETERRQ(PETSC_ERR_MEM," ");
276: }
277: PetscLogMallocLength[PetscLogMalloc] = nsize;
278: PetscLogMallocDirectory[PetscLogMalloc] = dir;
279: PetscLogMallocFile[PetscLogMalloc] = filename;
280: PetscLogMallocFunction[PetscLogMalloc++] = function;
281: }
282: *result = (void*)inew;
283: return(0);
284: }
287: /*
288: PetscTrFreeDefault - Free with tracing.
290: Input Parameters:
291: . a - pointer to a block allocated with PetscTrMalloc
292: . lineno - line number where used. Use __LINE__ for this
293: . file - file name where used. Use __FILE__ for this
294: . dir - directory where file is. Use __SDIR__ for this
295: */
296: int PetscTrFreeDefault(void *aa,int line,char *function,char *file,char *dir)
297: {
298: char *a = (char*)aa;
299: TRSPACE *head;
300: char *ahead;
301: int ierr;
302: unsigned long *nend;
303:
305: /* Do not try to handle empty blocks */
306: if (!a) {
307: (*PetscErrorPrintf)("PetscTrFreeDefault called from %s() line %d in %s%sn",function,line,dir,file);
308: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Trying to free null block");
309: }
310:
311: if (TRdebugLevel > 0) {
312: PetscTrValid(line,function,file,dir);
313: }
314:
315: if (PetscLow > aa || PetscHigh < aa){
316: (*PetscErrorPrintf)("PetscTrFreeDefault called from %s() line %d in %s%sn",function,line,dir,file);
317: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"PetscTrFreeDefault called with address not allocated by PetscTrMallocDefault");
318: }
319:
320: ahead = a;
321: a = a - sizeof(TrSPACE);
322: head = (TRSPACE *)a;
323:
324: if (head->cookie != COOKIE_VALUE) {
325: (*PetscErrorPrintf)("PetscTrFreeDefault called from %s() line %d in %s%sn",function,line,dir,file);
326: (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;n
327: may be block not allocated with PetscTrMalloc or PetscMallocn",a);
328: SETERRQ(PETSC_ERR_MEMC,"Bad location or corrupted memory");
329: }
330: nend = (unsigned long *)(ahead + head->size);
331: if (*nend != COOKIE_VALUE) {
332: if (*nend == ALREADY_FREED) {
333: (*PetscErrorPrintf)("PetscTrFreeDefault called from %s() line %d in %s%sn",function,line,dir,file);
334: (*PetscErrorPrintf)("Block [id=%d(%lx)] at address %p was already freedn",
335: head->id,head->size,a + sizeof(TrSPACE));
336: if (head->lineno > 0 && head->lineno < 5000 /* sanity check */) {
337: (*PetscErrorPrintf)("Block freed in %s() line %d in %s%sn",head->functionname,
338: head->lineno,head->dirname,head->filename);
339: } else {
340: (*PetscErrorPrintf)("Block allocated in %s() line %d in %s%sn",head->functionname,
341: -head->lineno,head->dirname,head->filename);
342: }
343: SETERRQ(PETSC_ERR_ARG_WRONG,"Memory already freed");
344: } else {
345: /* Damaged tail */
346: (*PetscErrorPrintf)("PetscTrFreeDefault called from %s() line %d in %s%sn",function,line,dir,file);
347: (*PetscErrorPrintf)("Block [id=%d(%lx)] at address %p is corrupted (probably write past end)n",
348: head->id,head->size,a);
349: (*PetscErrorPrintf)("Block allocated in %s() line %d in %s%sn",head->functionname,
350: head->lineno,head->dirname,head->filename);
351: SETERRQ(PETSC_ERR_MEMC,"Corrupted memory");
352: }
353: }
354: /* Mark the location freed */
355: *nend = ALREADY_FREED;
356: /* Save location where freed. If we suspect the line number, mark as
357: allocated location */
358: if (line > 0 && line < 50000) {
359: head->lineno = line;
360: head->filename = file;
361: head->functionname = function;
362: head->dirname = dir;
363: } else {
364: head->lineno = - head->lineno;
365: }
366: /* zero out memory - helps to find some reuse of already freed memory */
367: PetscMemzero(aa,(int)(head->size));
368:
369: TRallocated -= head->size;
370: TRfrags --;
371: if (head->prev) head->prev->next = head->next;
372: else TRhead = head->next;
373:
374: if (head->next) head->next->prev = head->prev;
375: PetscFreeAlign(a,line,function,file,dir);
376: return(0);
377: }
380: /*@
381: PetscShowMemoryUsage - Shows the amount of memory currently being used
382: in a communicator.
383:
384: Collective on PetscViewer
386: Input Parameter:
387: + viewer - the viewer that defines the communicator
388: - message - string printed before values
390: Level: intermediate
392: Concepts: memory usage
394: .seealso: PetscTrDump(),PetscTrSpace(), PetscGetResidentSetSize()
395: @*/
396: int PetscShowMemoryUsage(PetscViewer viewer,char *message)
397: {
398: PetscLogDouble allocated,maximum,resident;
399: int ierr,rank;
400: MPI_Comm comm;
403: PetscTrSpace(&allocated,PETSC_NULL,&maximum);
404: PetscGetResidentSetSize(&resident);
405: PetscObjectGetComm((PetscObject)viewer,&comm);
406: MPI_Comm_rank(comm,&rank);
407: PetscViewerASCIIPrintf(viewer,message);
408: PetscViewerASCIISynchronizedPrintf(viewer,"[%d]Space allocated %g, max space allocated %g, process memory %gn",rank,allocated,maximum,resident);
409: PetscViewerFlush(viewer);
410: return(0);
411: }
413: /*@C
414: PetscTrSpace - Returns space statistics.
415:
416: Not Collective
418: Output Parameters:
419: + space - number of bytes currently allocated
420: . frags - number of blocks currently allocated
421: - maxs - maximum number of bytes ever allocated
423: Level: intermediate
425: Concepts: memory usage
427: .seealso: PetscTrDump()
428: @*/
429: int PetscTrSpace(PetscLogDouble *space,PetscLogDouble *fr,PetscLogDouble *maxs)
430: {
433: if (space) *space = (PetscLogDouble) TRallocated;
434: if (fr) *fr = (PetscLogDouble) TRfrags;
435: if (maxs) *maxs = (PetscLogDouble) TRMaxMem;
436: return(0);
437: }
439: /*@C
440: PetscTrDump - Dumps the allocated memory blocks to a file. The information
441: printed is: size of space (in bytes), address of space, id of space,
442: file in which space was allocated, and line number at which it was
443: allocated.
445: Collective on PETSC_COMM_WORLD
447: Input Parameter:
448: . fp - file pointer. If fp is NULL, stdout is assumed.
450: Options Database Key:
451: . -trdump - Dumps unfreed memory during call to PetscFinalize()
453: Level: intermediate
455: Fortran Note:
456: The calling sequence in Fortran is PetscTrDump(integer ierr)
457: The fp defaults to stdout.
459: Notes: uses MPI_COMM_WORLD, because this may be called in PetscFinalize() after PETSC_COMM_WORLD
460: has been freed.
462: Concepts: memory usage
463: Concepts: memory bleeding
464: Concepts: bleeding memory
466: .seealso: PetscTrSpace(), PetscTrLogDump()
467: @*/
468: int PetscTrDump(FILE *fp)
469: {
470: TRSPACE *head;
471: int rank,ierr;
474: MPI_Comm_rank(MPI_COMM_WORLD,&rank);
475: if (!fp) fp = stdout;
476: if (TRallocated > 0) {
477: PetscFPrintf(MPI_COMM_WORLD,fp,"[%d]Total space allocated %d bytesn",rank,(int)TRallocated);
478: }
479: head = TRhead;
480: while (head) {
481: PetscFPrintf(MPI_COMM_WORLD,fp,"[%2d]%8d bytes %s() line %d in %s%sn",rank,(int)head->size,
482: head->functionname,head->lineno,head->dirname,head->filename);
483: #if defined(PETSC_USE_STACK)
484: PetscStackPrint(&head->stack,fp);
485: #endif
486: head = head->next;
487: }
488: return(0);
489: }
491: /* ---------------------------------------------------------------------------- */
493: /*@C
494: PetscTrLog - Activates logging of all calls to malloc.
496: Not Collective
498: Options Database Key:
499: . -trmalloc_log - Activates PetscTrLog() and PetscTrLogDump()
501: Level: advanced
503: .seealso: PetscTrLogDump()
504: @*/
505: int PetscTrLog(void)
506: {
509: PetscLogMalloc = 0;
510: return(0);
511: }
513: /*@C
514: PetscTrLogDump - Dumps the log of all calls to malloc; also calls
515: PetscGetResidentSetSize().
517: Collective on PETSC_COMM_WORLD
519: Input Parameter:
520: . fp - file pointer; or PETSC_NULL
522: Options Database Key:
523: . -trmalloc_log - Activates PetscTrLog() and PetscTrLogDump()
525: Level: advanced
527: Fortran Note:
528: The calling sequence in Fortran is PetscTrLogDump(integer ierr)
529: The fp defaults to stdout.
531: .seealso: PetscTrLog(), PetscTrDump()
532: @*/
533: int PetscTrLogDump(FILE *fp)
534: {
535: int i,rank,j,n,*shortlength,ierr,dummy,size,tag = 1212 /* very bad programming */;
536: PetscTruth match;
537: char **shortfunction;
538: PetscLogDouble rss;
539: MPI_Status status;
542: MPI_Comm_rank(MPI_COMM_WORLD,&rank);
543: MPI_Comm_size(MPI_COMM_WORLD,&size);
544: /*
545: Try to get the data printed in order by processor. This will only sometimes work
546: */
547: fflush(fp);
548: MPI_Barrier(MPI_COMM_WORLD);
549: if (rank) {
550: MPI_Recv(&dummy,1,MPI_INT,rank-1,tag,MPI_COMM_WORLD,&status);
551: }
553: if (!fp) fp = stdout;
554: PetscGetResidentSetSize(&rss);
555: PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Maximum memory used %d Size of entire process %dn",rank,(int)TRMaxMem,(int)rss);
557: shortlength = (int*)malloc(PetscLogMalloc*sizeof(int));
558: shortfunction = (char**)malloc(PetscLogMalloc*sizeof(char *));
559: shortfunction[0] = PetscLogMallocFunction[0];
560: shortlength[0] = PetscLogMallocLength[0];
561: n = 1;
562: for (i=1; i<PetscLogMalloc; i++) {
563: for (j=0; j<n; j++) {
564: PetscStrcmp(shortfunction[j],PetscLogMallocFunction[i],&match);
565: if (match) {
566: shortlength[j] += PetscLogMallocLength[i];
567: goto foundit;
568: }
569: }
570: shortfunction[n] = PetscLogMallocFunction[i];
571: shortlength[n] = PetscLogMallocLength[i];
572: n++;
573: foundit:;
574: }
576: PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Memory usage sorted by functionn",rank);
577: for (i=0; i<n; i++) {
578: PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] % 9d %s()n",rank,shortlength[i],shortfunction[i]);
579: }
580: free(shortlength);
581: free(shortfunction);
582: fflush(fp);
583: if (rank != size-1) {
584: MPI_Send(&dummy,1,MPI_INT,rank+1,tag,MPI_COMM_WORLD);
585: }
587: return(0);
588: }
590: /* ---------------------------------------------------------------------------- */
592: /*
593: PetscTrDebugLevel - Set the level of debugging for the space management
594: routines.
596: Input Parameter:
597: . level - level of debugging. Currently, either 0 (no checking) or 1
598: (use PetscTrValid at each PetscTrMalloc or PetscTrFree).
599: */
600: int PetscTrDebugLevel(int level)
601: {
604: TRdebugLevel = level;
605: return(0);
606: }