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(size_t,int,char*,char*,char*,void**);
20: EXTERN int PetscFreeAlign(void*,int,char*,char*,char*);
21: EXTERN int PetscTrMallocDefault(size_t,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: #undef __FUNCT__
37: int 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: ierr = 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: char *filename;
85: char *functionname;
86: 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 int TRdebugLevel = 0;
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 char **PetscLogMallocDirectory,**PetscLogMallocFile,**PetscLogMallocFunction;
118: #undef __FUNCT__
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 or CHKMEMA 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, CHKMEMA
151: @*/
152: int 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)("error detected at %s() line %d in %s%sn",function,line,dir,file);
163: (*PetscErrorPrintf)("Memory at address %p is corruptedn",head);
164: (*PetscErrorPrintf)("Probably write past beginning or end of arrayn");
165: SETERRQ(PETSC_ERR_MEMC," ");
166: }
167: if (head->size <=0) {
168: (*PetscErrorPrintf)("error detected at %s() line %d in %s%sn",function,line,dir,file);
169: (*PetscErrorPrintf)("Memory at address %p is corruptedn",head);
170: (*PetscErrorPrintf)("Probably write past beginning or end of arrayn");
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)("error detected at %s() line %d in %s%sn",function,line,dir,file);
177: if (nend[0] == ALREADY_FREED) {
178: (*PetscErrorPrintf)("Memory [id=%d(%lx)] at address %p already freedn",head->id,head->size,a);
179: } else {
180: (*PetscErrorPrintf)("Memory [id=%d(%lx)] at address %p is corrupted (probably write past end)n",
181: head->id,head->size,a);
182: (*PetscErrorPrintf)("Memory originally allocated in %s() line %d in %s%sn",head->functionname,
183: head->lineno,head->dirname,head->filename);
184: SETERRQ(PETSC_ERR_MEMC," ");
185: }
186: }
187: head = head->next;
188: }
190: return(0);
191: }
193: #undef __FUNCT__
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: int PetscTrMallocDefault(size_t a,int lineno,char *function,char *filename,char *dir,void**result)
210: {
211: TRSPACE *head;
212: char *inew;
213: unsigned long *nend;
214: size_t nsize;
215: int ierr;
218: if (TRdebugLevel > 0) {
219: PetscTrValid(lineno,function,filename,dir); if (ierr) PetscFunctionReturn(ierr);
220: }
221: if (a == 0) 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 == 0) {
269: PetscLogMallocLength = (int*)malloc(PetscLogMallocMax*sizeof(int));
270: if (!PetscLogMallocLength) SETERRQ(PETSC_ERR_MEM," ");
271: PetscLogMallocDirectory = (char**)malloc(PetscLogMallocMax*sizeof(char**));
272: if (!PetscLogMallocDirectory) SETERRQ(PETSC_ERR_MEM," ");
273: PetscLogMallocFile = (char**)malloc(PetscLogMallocMax*sizeof(char**));
274: if (!PetscLogMallocFile) SETERRQ(PETSC_ERR_MEM," ");
275: PetscLogMallocFunction = (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: }
288: #undef __FUNCT__
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: int PetscTrFreeDefault(void *aa,int line,char *function,char *file,char *dir)
301: {
302: char *a = (char*)aa;
303: TRSPACE *head;
304: char *ahead;
305: int ierr;
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%sn",function,line,dir,file);
312: SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Trying to free null block");
313: }
314:
315: if (TRdebugLevel > 0) {
316: PetscTrValid(line,function,file,dir);
317: }
318:
319: if (PetscLow > aa || PetscHigh < aa){
320: (*PetscErrorPrintf)("PetscTrFreeDefault called from %s() line %d in %s%sn",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%sn",function,line,dir,file);
330: (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;n
331: may be block not allocated with PetscTrMalloc or PetscMallocn",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%sn",function,line,dir,file);
338: (*PetscErrorPrintf)("Block [id=%d(%lx)] at address %p was already freedn",
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%sn",head->functionname,
342: head->lineno,head->dirname,head->filename);
343: } else {
344: (*PetscErrorPrintf)("Block allocated in %s() line %d in %s%sn",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%sn",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%sn",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: }
384: #undef __FUNCT__
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: int PetscShowMemoryUsage(PetscViewer viewer,char *message)
403: {
404: PetscLogDouble allocated,maximum,resident;
405: int ierr,rank;
406: MPI_Comm comm;
409: PetscTrSpace(&allocated,PETSC_NULL,&maximum);
410: PetscGetResidentSetSize(&resident);
411: PetscObjectGetComm((PetscObject)viewer,&comm);
412: MPI_Comm_rank(comm,&rank);
413: PetscViewerASCIIPrintf(viewer,message);
414: PetscViewerASCIISynchronizedPrintf(viewer,"[%d]Space allocated %g, max space allocated %g, process memory %gn",rank,allocated,maximum,resident);
415: PetscViewerFlush(viewer);
416: return(0);
417: }
419: #undef __FUNCT__
421: /*@C
422: PetscTrSpace - Returns space statistics.
423:
424: Not Collective
426: Output Parameters:
427: + space - number of bytes currently allocated
428: . frags - number of blocks currently allocated
429: - maxs - maximum number of bytes ever allocated
431: Level: intermediate
433: Concepts: memory usage
435: .seealso: PetscTrDump()
436: @*/
437: int PetscTrSpace(PetscLogDouble *space,PetscLogDouble *fr,PetscLogDouble *maxs)
438: {
441: if (space) *space = (PetscLogDouble) TRallocated;
442: if (fr) *fr = (PetscLogDouble) TRfrags;
443: if (maxs) *maxs = (PetscLogDouble) TRMaxMem;
444: return(0);
445: }
447: #undef __FUNCT__
449: /*@C
450: PetscTrDump - Dumps the allocated memory blocks to a file. The information
451: printed is: size of space (in bytes), address of space, id of space,
452: file in which space was allocated, and line number at which it was
453: allocated.
455: Collective on PETSC_COMM_WORLD
457: Input Parameter:
458: . fp - file pointer. If fp is NULL, stdout is assumed.
460: Options Database Key:
461: . -trdump - Dumps unfreed memory during call to PetscFinalize()
463: Level: intermediate
465: Fortran Note:
466: The calling sequence in Fortran is PetscTrDump(integer ierr)
467: The fp defaults to stdout.
469: Notes: uses MPI_COMM_WORLD, because this may be called in PetscFinalize() after PETSC_COMM_WORLD
470: has been freed.
472: Concepts: memory usage
473: Concepts: memory bleeding
474: Concepts: bleeding memory
476: .seealso: PetscTrSpace(), PetscTrLogDump()
477: @*/
478: int PetscTrDump(FILE *fp)
479: {
480: TRSPACE *head;
481: int rank,ierr;
484: MPI_Comm_rank(MPI_COMM_WORLD,&rank);
485: if (!fp) fp = stdout;
486: if (TRallocated > 0) {
487: PetscFPrintf(MPI_COMM_WORLD,fp,"[%d]Total space allocated %d bytesn",rank,(int)TRallocated);
488: }
489: head = TRhead;
490: while (head) {
491: PetscFPrintf(MPI_COMM_WORLD,fp,"[%2d]%8d bytes %s() line %d in %s%sn",rank,(int)head->size,
492: head->functionname,head->lineno,head->dirname,head->filename);
493: #if defined(PETSC_USE_STACK)
494: PetscStackPrint(&head->stack,fp);
495: #endif
496: head = head->next;
497: }
498: return(0);
499: }
501: /* ---------------------------------------------------------------------------- */
503: #undef __FUNCT__
505: /*@C
506: PetscTrLog - Activates logging of all calls to malloc.
508: Not Collective
510: Options Database Key:
511: . -trmalloc_log - Activates PetscTrLog() and PetscTrLogDump()
513: Level: advanced
515: .seealso: PetscTrLogDump()
516: @*/
517: int PetscTrLog(void)
518: {
521: PetscLogMalloc = 0;
522: return(0);
523: }
525: #undef __FUNCT__
527: /*@C
528: PetscTrLogDump - Dumps the log of all calls to malloc; also calls
529: PetscGetResidentSetSize().
531: Collective on PETSC_COMM_WORLD
533: Input Parameter:
534: . fp - file pointer; or PETSC_NULL
536: Options Database Key:
537: . -trmalloc_log - Activates PetscTrLog() and PetscTrLogDump()
539: Level: advanced
541: Fortran Note:
542: The calling sequence in Fortran is PetscTrLogDump(integer ierr)
543: The fp defaults to stdout.
545: .seealso: PetscTrLog(), PetscTrDump()
546: @*/
547: int PetscTrLogDump(FILE *fp)
548: {
549: int i,rank,j,n,*shortlength,ierr,dummy,size,tag = 1212 /* very bad programming */;
550: PetscTruth match;
551: char **shortfunction;
552: PetscLogDouble rss;
553: MPI_Status status;
556: MPI_Comm_rank(MPI_COMM_WORLD,&rank);
557: MPI_Comm_size(MPI_COMM_WORLD,&size);
558: /*
559: Try to get the data printed in order by processor. This will only sometimes work
560: */
561: fflush(fp);
562: MPI_Barrier(MPI_COMM_WORLD);
563: if (rank) {
564: MPI_Recv(&dummy,1,MPI_INT,rank-1,tag,MPI_COMM_WORLD,&status);
565: }
567: if (!fp) fp = stdout;
568: PetscGetResidentSetSize(&rss);
569: PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Maximum memory used %d Size of entire process %dn",rank,(int)TRMaxMem,(int)rss);
571: shortlength = (int*)malloc(PetscLogMalloc*sizeof(int));
572: shortfunction = (char**)malloc(PetscLogMalloc*sizeof(char *));
573: shortfunction[0] = PetscLogMallocFunction[0];
574: shortlength[0] = PetscLogMallocLength[0];
575: n = 1;
576: for (i=1; i<PetscLogMalloc; i++) {
577: for (j=0; j<n; j++) {
578: PetscStrcmp(shortfunction[j],PetscLogMallocFunction[i],&match);
579: if (match) {
580: shortlength[j] += PetscLogMallocLength[i];
581: goto foundit;
582: }
583: }
584: shortfunction[n] = PetscLogMallocFunction[i];
585: shortlength[n] = PetscLogMallocLength[i];
586: n++;
587: foundit:;
588: }
590: PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Memory usage sorted by functionn",rank);
591: for (i=0; i<n; i++) {
592: PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] % 9d %s()n",rank,shortlength[i],shortfunction[i]);
593: }
594: free(shortlength);
595: free(shortfunction);
596: fflush(fp);
597: if (rank != size-1) {
598: MPI_Send(&dummy,1,MPI_INT,rank+1,tag,MPI_COMM_WORLD);
599: }
601: return(0);
602: }
604: /* ---------------------------------------------------------------------------- */
606: #undef __FUNCT__
608: /*
609: PetscTrDebugLevel - Set the level of debugging for the space management
610: routines.
612: Input Parameter:
613: . level - level of debugging. Currently, either 0 (no checking) or 1
614: (use PetscTrValid at each PetscTrMalloc or PetscTrFree).
615: */
616: int PetscTrDebugLevel(int level)
617: {
620: TRdebugLevel = level;
621: return(0);
622: }