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: }