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