Actual source code: mtr.c


  2: /*
  3:      Interface to malloc() and free(). This code allows for logging of memory usage and some error checking
  4: */
  5: #include <petsc/private/petscimpl.h>
  6: #include <petscviewer.h>
  7: #if defined(PETSC_HAVE_MALLOC_H)
  8: #include <malloc.h>
  9: #endif

 11: /*
 12:      These are defined in mal.c and ensure that malloced space is PetscScalar aligned
 13: */
 14: PETSC_EXTERN PetscErrorCode PetscMallocAlign(size_t,PetscBool,int,const char[],const char[],void**);
 15: PETSC_EXTERN PetscErrorCode PetscFreeAlign(void*,int,const char[],const char[]);
 16: PETSC_EXTERN PetscErrorCode PetscReallocAlign(size_t,int,const char[],const char[],void**);

 18: #define CLASSID_VALUE  ((PetscClassId) 0xf0e0d0c9)
 19: #define ALREADY_FREED  ((PetscClassId) 0x0f0e0d9c)

 21: /*  this is the header put at the beginning of each malloc() using for tracking allocated space and checking of allocated space heap */
 22: typedef struct _trSPACE {
 23:   size_t          size, rsize; /* Aligned size and requested size */
 24:   int             id;
 25:   int             lineno;
 26:   const char      *filename;
 27:   const char      *functionname;
 28:   PetscClassId    classid;
 29: #if defined(PETSC_USE_DEBUG)
 30:   PetscStack      stack;
 31: #endif
 32:   struct _trSPACE *next,*prev;
 33: } TRSPACE;

 35: /* HEADER_BYTES is the number of bytes in a PetscMalloc() header.
 36:    It is sizeof(trSPACE) padded to be a multiple of PETSC_MEMALIGN.
 37: */
 38: #define HEADER_BYTES  ((sizeof(TRSPACE)+(PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1))

 40: /* This union is used to insure that the block passed to the user retains
 41:    a minimum alignment of PETSC_MEMALIGN.
 42: */
 43: typedef union {
 44:   TRSPACE sp;
 45:   char    v[HEADER_BYTES];
 46: } TrSPACE;

 48: #define MAXTRMAXMEMS 50
 49: static size_t    TRallocated          = 0;
 50: static int       TRfrags              = 0;
 51: static TRSPACE   *TRhead              = NULL;
 52: static int       TRid                 = 0;
 53: static PetscBool TRdebugLevel         = PETSC_FALSE;
 54: static PetscBool TRdebugIinitializenan= PETSC_FALSE;
 55: static PetscBool TRrequestedSize      = PETSC_FALSE;
 56: static size_t    TRMaxMem             = 0;
 57: static int       NumTRMaxMems         = 0;
 58: static size_t    TRMaxMems[MAXTRMAXMEMS];
 59: static int       TRMaxMemsEvents[MAXTRMAXMEMS];
 60: /*
 61:       Arrays to log information on mallocs for PetscMallocView()
 62: */
 63: static int        PetscLogMallocMax       = 10000;
 64: static int        PetscLogMalloc          = -1;
 65: static size_t     PetscLogMallocThreshold = 0;
 66: static size_t     *PetscLogMallocLength;
 67: static const char **PetscLogMallocFile,**PetscLogMallocFunction;
 68: static int        PetscLogMallocTrace          = -1;
 69: static size_t     PetscLogMallocTraceThreshold = 0;
 70: static PetscViewer PetscLogMallocTraceViewer   = NULL;

 72: /*@C
 73:    PetscMallocValidate - Test the memory for corruption.  This can be called at any time between PetscInitialize() and PetscFinalize()

 75:    Input Parameters:
 76: +  line - line number where call originated.
 77: .  function - name of function calling
 78: -  file - file where function is

 80:    Return value:
 81:    The number of errors detected.

 83:    Options Database:.
 84: +  -malloc_test - turns this feature on when PETSc was not configured with --with-debugging=0
 85: -  -malloc_debug - turns this feature on anytime

 87:    Output Effect:
 88:    Error messages are written to stdout.

 90:    Level: advanced

 92:    Notes:
 93:     This is only run if PetscMallocSetDebug() has been called which is set by -malloc_test (if debugging is turned on) or -malloc_debug (any time)

 95:     You should generally use CHKMEMQ as a short cut for calling this  routine.

 97:     The Fortran calling sequence is simply PetscMallocValidate(ierr)

 99:    No output is generated if there are no problems detected.

101:    Developers Note:
102:      Uses the flg TRdebugLevel (set as the first argument to PetscMallocSetDebug()) to determine if it should run

104: .seealso: CHKMEMQ

106: @*/
107: PetscErrorCode  PetscMallocValidate(int line,const char function[],const char file[])
108: {
109:   TRSPACE      *head,*lasthead;
110:   char         *a;
111:   PetscClassId *nend;

113:   if (!TRdebugLevel) return 0;
114:   head = TRhead; lasthead = NULL;
115:   if (head && head->prev) {
116:     (*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n",function,file,line);
117:     (*PetscErrorPrintf)("Root memory header %p has invalid back pointer %p\n",head,head->prev);
118:     return PETSC_ERR_MEMC;
119:   }
120:   while (head) {
121:     if (head->classid != CLASSID_VALUE) {
122:       (*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n",function,file,line);
123:       (*PetscErrorPrintf)("Memory at address %p is corrupted\n",head);
124:       (*PetscErrorPrintf)("Probably write before beginning of or past end of array\n");
125:       if (lasthead) {
126:         a    = (char*)(((TrSPACE*)head) + 1);
127:         (*PetscErrorPrintf)("Last intact block [id=%d(%.0f)] at address %p allocated in %s() at %s:%d\n",lasthead->id,(PetscLogDouble)lasthead->size,a,lasthead->functionname,lasthead->filename,lasthead->lineno);
128:       }
129:       abort();
130:       return PETSC_ERR_MEMC;
131:     }
132:     a    = (char*)(((TrSPACE*)head) + 1);
133:     nend = (PetscClassId*)(a + head->size);
134:     if (*nend != CLASSID_VALUE) {
135:       (*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n",function,file,line);
136:       if (*nend == ALREADY_FREED) {
137:         (*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p already freed\n",head->id,(PetscLogDouble)head->size,a);
138:         return PETSC_ERR_MEMC;
139:       } else {
140:         (*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
141:         (*PetscErrorPrintf)("Memory originally allocated in %s() at %s:%d\n",head->functionname,head->filename,head->lineno);
142:         return PETSC_ERR_MEMC;
143:       }
144:     }
145:     if (head->prev && head->prev != lasthead) {
146:       (*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n",function,file,line);
147:       (*PetscErrorPrintf)("Backpointer %p is invalid, should be %p\n",head->prev,lasthead);
148:       (*PetscErrorPrintf)("Previous memory originally allocated in %s() at %s:%d\n",lasthead->functionname,lasthead->filename,lasthead->lineno);
149:       (*PetscErrorPrintf)("Memory originally allocated in %s() at %s:%d\n",head->functionname,head->filename,head->lineno);
150:       return PETSC_ERR_MEMC;
151:     }
152:     lasthead = head;
153:     head     = head->next;
154:   }
155:   return 0;
156: }

158: /*
159:     PetscTrMallocDefault - Malloc with tracing.

161:     Input Parameters:
162: +   a   - number of bytes to allocate
163: .   lineno - line number where used.  Use __LINE__ for this
164: -   filename  - file name where used.  Use __FILE__ for this

166:     Returns:
167:     double aligned pointer to requested storage, or null if not  available.
168:  */
169: PetscErrorCode  PetscTrMallocDefault(size_t a,PetscBool clear,int lineno,const char function[],const char filename[],void **result)
170: {
171:   TRSPACE        *head;
172:   char           *inew;
173:   size_t         nsize;

177:   /* Do not try to handle empty blocks */
178:   if (!a) { *result = NULL; return(0); }

180:   PetscMallocValidate(lineno,function,filename); if (ierr) PetscFunctionReturn(ierr);

182:   nsize = (a + (PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1);
183:   PetscMallocAlign(nsize+sizeof(TrSPACE)+sizeof(PetscClassId),clear,lineno,function,filename,(void**)&inew);

185:   head  = (TRSPACE*)inew;
186:   inew += sizeof(TrSPACE);

188:   if (TRhead) TRhead->prev = head;
189:   head->next   = TRhead;
190:   TRhead       = head;
191:   head->prev   = NULL;
192:   head->size   = nsize;
193:   head->rsize  = a;
194:   head->id     = TRid++;
195:   head->lineno = lineno;

197:   head->filename                 = filename;
198:   head->functionname             = function;
199:   head->classid                  = CLASSID_VALUE;
200:   *(PetscClassId*)(inew + nsize) = CLASSID_VALUE;

202:   TRallocated += TRrequestedSize ? head->rsize : head->size;
203:   if (TRallocated > TRMaxMem) TRMaxMem = TRallocated;
204:   if (PetscLogMemory) {
205:     PetscInt i;
206:     for (i=0; i<NumTRMaxMems; i++) {
207:       if (TRallocated > TRMaxMems[i]) TRMaxMems[i] = TRallocated;
208:     }
209:   }
210:   TRfrags++;

212: #if defined(PETSC_USE_DEBUG)
213:   PetscStackCopy(&petscstack,&head->stack);
215:   head->stack.line[head->stack.currentsize-2] = lineno;
216: #if defined(PETSC_USE_REAL_SINGLE) || defined(PETSC_USE_REAL_DOUBLE)
217:   if (!clear && TRdebugIinitializenan) {
218:     size_t     i, n = a/sizeof(PetscReal);
219:     PetscReal *s = (PetscReal*) inew;
220:     /* from https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html */
221: #if defined(PETSC_USE_REAL_SINGLE)
222:     int        nas = 0x7F800002;
223: #else
224:     PetscInt64 nas = 0x7FF0000000000002;
225: #endif
226:     for (i=0; i<n; i++) {
227:       memcpy(s+i,&nas,sizeof(PetscReal));
228:     }
229:   }
230: #endif
231: #endif

233:   /*
234:          Allow logging of all mallocs made.
235:          TODO: Currently this memory is never freed, it should be freed during PetscFinalize()
236:   */
237:   if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax && a >= PetscLogMallocThreshold) {
238:     if (!PetscLogMalloc) {
239:       PetscLogMallocLength = (size_t*)malloc(PetscLogMallocMax*sizeof(size_t));
240:       if (!PetscLogMallocLength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");

242:       PetscLogMallocFile = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
243:       if (!PetscLogMallocFile) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");

245:       PetscLogMallocFunction = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
246:       if (!PetscLogMallocFunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
247:     }
248:     PetscLogMallocLength[PetscLogMalloc]     = nsize;
249:     PetscLogMallocFile[PetscLogMalloc]       = filename;
250:     PetscLogMallocFunction[PetscLogMalloc++] = function;
251:   }
252:   if (PetscLogMallocTrace > -1 && a >= PetscLogMallocTraceThreshold) {
253:     PetscViewerASCIIPrintf(PetscLogMallocTraceViewer,"Alloc %zu %s:%d (%s)\n", a, filename ? filename : "null", lineno, function ? function : "null");
254:   }
255:   *result = (void*)inew;
256:   return(0);
257: }

259: /*
260:    PetscTrFreeDefault - Free with tracing.

262:    Input Parameters:
263: .   a    - pointer to a block allocated with PetscTrMalloc
264: .   lineno - line number where used.  Use __LINE__ for this
265: .   filename  - file name where used.  Use __FILE__ for this
266:  */
267: PetscErrorCode  PetscTrFreeDefault(void *aa,int lineno,const char function[],const char filename[])
268: {
269:   char           *a = (char*)aa;
270:   TRSPACE        *head;
271:   char           *ahead;
272:   size_t         asize;
274:   PetscClassId   *nend;

277:   /* Do not try to handle empty blocks */
278:   if (!a) return(0);

280:   PetscMallocValidate(lineno,function,filename);

282:   ahead = a;
283:   a     = a - sizeof(TrSPACE);
284:   head  = (TRSPACE*)a;

286:   if (head->classid != CLASSID_VALUE) {
287:     (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() at %s:%d\n",function,filename,lineno);
288:     (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\nmay be block not allocated with PetscMalloc()\n",a);
289:     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Bad location or corrupted memory");
290:   }
291:   nend = (PetscClassId*)(ahead + head->size);
292:   if (*nend != CLASSID_VALUE) {
293:     if (*nend == ALREADY_FREED) {
294:       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() at %s:%d\n",function,filename,lineno);
295:       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p was already freed\n",head->id,(PetscLogDouble)head->size,a + sizeof(TrSPACE));
296:       if (head->lineno > 0 && head->lineno < 50000 /* sanity check */) {
297:         (*PetscErrorPrintf)("Block freed in %s() at %s:%d\n",head->functionname,head->filename,head->lineno);
298:       } else {
299:         (*PetscErrorPrintf)("Block allocated in %s() at %s:%d\n",head->functionname,head->filename,-head->lineno);
300:       }
301:       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Memory already freed");
302:     } else {
303:       /* Damaged tail */
304:       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() at %s:%d\n",function,filename,lineno);
305:       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
306:       (*PetscErrorPrintf)("Block allocated in %s() at %s:%d\n",head->functionname,head->filename,head->lineno);
307:       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Corrupted memory");
308:     }
309:   }
310:   if (PetscLogMallocTrace > -1 && head->rsize >= PetscLogMallocTraceThreshold) {
311:     PetscViewerASCIIPrintf(PetscLogMallocTraceViewer, "Free  %zu %s:%d (%s)\n", head->rsize, filename ? filename : "null", lineno, function ? function : "null");
312:   }
313:   /* Mark the location freed */
314:   *nend = ALREADY_FREED;
315:   /* Save location where freed.  If we suspect the line number, mark as  allocated location */
316:   if (lineno > 0 && lineno < 50000) {
317:     head->lineno       = lineno;
318:     head->filename     = filename;
319:     head->functionname = function;
320:   } else {
321:     head->lineno = -head->lineno;
322:   }
323:   asize = TRrequestedSize ? head->rsize : head->size;
324:   if (TRallocated < asize) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"TRallocate is smaller than memory just freed");
325:   TRallocated -= asize;
326:   TRfrags--;
327:   if (head->prev) head->prev->next = head->next;
328:   else TRhead = head->next;

330:   if (head->next) head->next->prev = head->prev;
331:   PetscFreeAlign(a,lineno,function,filename);
332:   return(0);
333: }

335: /*
336:   PetscTrReallocDefault - Realloc with tracing.

338:   Input Parameters:
339: + len      - number of bytes to allocate
340: . lineno   - line number where used.  Use __LINE__ for this
341: . filename - file name where used.  Use __FILE__ for this
342: - result - original memory

344:   Output Parameter:
345: . result - double aligned pointer to requested storage, or null if not available.

347:   Level: developer

349: .seealso: PetscTrMallocDefault(), PetscTrFreeDefault()
350: */
351: PetscErrorCode PetscTrReallocDefault(size_t len, int lineno, const char function[], const char filename[], void **result)
352: {
353:   char           *a = (char *) *result;
354:   TRSPACE        *head;
355:   char           *ahead, *inew;
356:   PetscClassId   *nend;
357:   size_t         nsize;

361:   /* Realloc requests zero space so just free the current space */
362:   if (!len) {
363:     PetscTrFreeDefault(*result,lineno,function,filename);
364:     *result = NULL;
365:     return(0);
366:   }
367:   /* If the orginal space was NULL just use the regular malloc() */
368:   if (!*result) {
369:     PetscTrMallocDefault(len,PETSC_FALSE,lineno,function,filename,result);
370:     return(0);
371:   }

373:   PetscMallocValidate(lineno,function,filename); if (ierr) PetscFunctionReturn(ierr);

375:   ahead = a;
376:   a     = a - sizeof(TrSPACE);
377:   head  = (TRSPACE *) a;
378:   inew  = a;

380:   if (head->classid != CLASSID_VALUE) {
381:     (*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() at %s:%d\n",function,filename,lineno);
382:     (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\nmay be block not allocated with PetscMalloc()\n",a);
383:     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Bad location or corrupted memory");
384:   }
385:   nend = (PetscClassId *)(ahead + head->size);
386:   if (*nend != CLASSID_VALUE) {
387:     if (*nend == ALREADY_FREED) {
388:       (*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() at %s:%d\n",function,filename,lineno);
389:       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p was already freed\n",head->id,(PetscLogDouble)head->size,a + sizeof(TrSPACE));
390:       if (head->lineno > 0 && head->lineno < 50000 /* sanity check */) {
391:         (*PetscErrorPrintf)("Block freed in %s() at %s:%d\n",head->functionname,head->filename,head->lineno);
392:       } else {
393:         (*PetscErrorPrintf)("Block allocated in %s() at %s:%d\n",head->functionname,head->filename,-head->lineno);
394:       }
395:       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Memory already freed");
396:     } else {
397:       /* Damaged tail */
398:       (*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() at %s:%d\n",function,filename,lineno);
399:       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
400:       (*PetscErrorPrintf)("Block allocated in %s() at %s:%d\n",head->functionname,head->filename,head->lineno);
401:       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Corrupted memory");
402:     }
403:   }

405:   /* remove original reference to the memory allocated from the PETSc debugging heap */
406:   TRallocated -= TRrequestedSize ? head->rsize : head->size;
407:   TRfrags--;
408:   if (head->prev) head->prev->next = head->next;
409:   else TRhead = head->next;
410:   if (head->next) head->next->prev = head->prev;

412:   nsize = (len + (PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1);
413:   PetscReallocAlign(nsize+sizeof(TrSPACE)+sizeof(PetscClassId),lineno,function,filename,(void**)&inew);

415:   head  = (TRSPACE*)inew;
416:   inew += sizeof(TrSPACE);

418:   if (TRhead) TRhead->prev = head;
419:   head->next   = TRhead;
420:   TRhead       = head;
421:   head->prev   = NULL;
422:   head->size   = nsize;
423:   head->rsize  = len;
424:   head->id     = TRid++;
425:   head->lineno = lineno;

427:   head->filename                 = filename;
428:   head->functionname             = function;
429:   head->classid                  = CLASSID_VALUE;
430:   *(PetscClassId*)(inew + nsize) = CLASSID_VALUE;

432:   TRallocated += TRrequestedSize ? head->rsize : head->size;
433:   if (TRallocated > TRMaxMem) TRMaxMem = TRallocated;
434:   if (PetscLogMemory) {
435:     PetscInt i;
436:     for (i=0; i<NumTRMaxMems; i++) {
437:       if (TRallocated > TRMaxMems[i]) TRMaxMems[i] = TRallocated;
438:     }
439:   }
440:   TRfrags++;

442: #if defined(PETSC_USE_DEBUG)
443:   PetscStackCopy(&petscstack,&head->stack);
445:   head->stack.line[head->stack.currentsize-2] = lineno;
446: #endif

448:   /*
449:          Allow logging of all mallocs made. This adds a new entry to the list of allocated memory
450:          and does not remove the previous entry to the list hence this memory is "double counted" in PetscMallocView()
451:   */
452:   if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax && len >= PetscLogMallocThreshold) {
453:     if (!PetscLogMalloc) {
454:       PetscLogMallocLength = (size_t*)malloc(PetscLogMallocMax*sizeof(size_t));
455:       if (!PetscLogMallocLength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");

457:       PetscLogMallocFile = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
458:       if (!PetscLogMallocFile) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");

460:       PetscLogMallocFunction = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
461:       if (!PetscLogMallocFunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
462:     }
463:     PetscLogMallocLength[PetscLogMalloc]     = nsize;
464:     PetscLogMallocFile[PetscLogMalloc]       = filename;
465:     PetscLogMallocFunction[PetscLogMalloc++] = function;
466:   }
467:   *result = (void*)inew;
468:   return(0);
469: }

471: /*@C
472:     PetscMemoryView - Shows the amount of memory currently being used in a communicator.

474:     Collective on PetscViewer

476:     Input Parameters:
477: +    viewer - the viewer that defines the communicator
478: -    message - string printed before values

480:     Options Database:
481: +    -malloc_debug - have PETSc track how much memory it has allocated
482: -    -memory_view - during PetscFinalize() have this routine called

484:     Level: intermediate

486: .seealso: PetscMallocDump(), PetscMemoryGetCurrentUsage(), PetscMemorySetGetMaximumUsage(), PetscMallocView()
487:  @*/
488: PetscErrorCode  PetscMemoryView(PetscViewer viewer,const char message[])
489: {
490:   PetscLogDouble allocated,allocatedmax,resident,residentmax,gallocated,gallocatedmax,gresident,gresidentmax,maxgallocated,maxgallocatedmax,maxgresident,maxgresidentmax;
491:   PetscLogDouble mingallocated,mingallocatedmax,mingresident,mingresidentmax;
493:   MPI_Comm       comm;

496:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_WORLD;
497:   PetscMallocGetCurrentUsage(&allocated);
498:   PetscMallocGetMaximumUsage(&allocatedmax);
499:   PetscMemoryGetCurrentUsage(&resident);
500:   PetscMemoryGetMaximumUsage(&residentmax);
501:   if (residentmax > 0) residentmax = PetscMax(resident,residentmax);
502:   PetscObjectGetComm((PetscObject)viewer,&comm);
503:   PetscViewerASCIIPrintf(viewer,message);
504:   if (resident && residentmax && allocated) {
505:     MPI_Reduce(&residentmax,&gresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);
506:     MPI_Reduce(&residentmax,&maxgresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);
507:     MPI_Reduce(&residentmax,&mingresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);
508:     PetscViewerASCIIPrintf(viewer,"Maximum (over computational time) process memory:        total %5.4e max %5.4e min %5.4e\n",gresidentmax,maxgresidentmax,mingresidentmax);
509:     MPI_Reduce(&resident,&gresident,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);
510:     MPI_Reduce(&resident,&maxgresident,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);
511:     MPI_Reduce(&resident,&mingresident,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);
512:     PetscViewerASCIIPrintf(viewer,"Current process memory:                                  total %5.4e max %5.4e min %5.4e\n",gresident,maxgresident,mingresident);
513:     MPI_Reduce(&allocatedmax,&gallocatedmax,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);
514:     MPI_Reduce(&allocatedmax,&maxgallocatedmax,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);
515:     MPI_Reduce(&allocatedmax,&mingallocatedmax,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);
516:     PetscViewerASCIIPrintf(viewer,"Maximum (over computational time) space PetscMalloc()ed: total %5.4e max %5.4e min %5.4e\n",gallocatedmax,maxgallocatedmax,mingallocatedmax);
517:     MPI_Reduce(&allocated,&gallocated,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);
518:     MPI_Reduce(&allocated,&maxgallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);
519:     MPI_Reduce(&allocated,&mingallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);
520:     PetscViewerASCIIPrintf(viewer,"Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n",gallocated,maxgallocated,mingallocated);
521:   } else if (resident && residentmax) {
522:     MPI_Reduce(&residentmax,&gresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);
523:     MPI_Reduce(&residentmax,&maxgresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);
524:     MPI_Reduce(&residentmax,&mingresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);
525:     PetscViewerASCIIPrintf(viewer,"Maximum (over computational time) process memory:        total %5.4e max %5.4e min %5.4e\n",gresidentmax,maxgresidentmax,mingresidentmax);
526:     MPI_Reduce(&resident,&gresident,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);
527:     MPI_Reduce(&resident,&maxgresident,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);
528:     MPI_Reduce(&resident,&mingresident,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);
529:     PetscViewerASCIIPrintf(viewer,"Current process memory:                                  total %5.4e max %5.4e min %5.4e\n",gresident,maxgresident,mingresident);
530:   } else if (resident && allocated) {
531:     MPI_Reduce(&resident,&gresident,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);
532:     MPI_Reduce(&resident,&maxgresident,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);
533:     MPI_Reduce(&resident,&mingresident,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);
534:     PetscViewerASCIIPrintf(viewer,"Current process memory:                                  total %5.4e max %5.4e min %5.4e\n",gresident,maxgresident,mingresident);
535:     MPI_Reduce(&allocated,&gallocated,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);
536:     MPI_Reduce(&allocated,&maxgallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);
537:     MPI_Reduce(&allocated,&mingallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);
538:     PetscViewerASCIIPrintf(viewer,"Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n",gallocated,maxgallocated,mingallocated);
539:     PetscViewerASCIIPrintf(viewer,"Run with -memory_view to get maximum memory usage\n");
540:   } else if (allocated) {
541:     MPI_Reduce(&allocated,&gallocated,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);
542:     MPI_Reduce(&allocated,&maxgallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);
543:     MPI_Reduce(&allocated,&mingallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);
544:     PetscViewerASCIIPrintf(viewer,"Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n",gallocated,maxgallocated,mingallocated);
545:     PetscViewerASCIIPrintf(viewer,"Run with -memory_view to get maximum memory usage\n");
546:     PetscViewerASCIIPrintf(viewer,"OS cannot compute process memory\n");
547:   } else {
548:     PetscViewerASCIIPrintf(viewer,"Run with -malloc_debug to get statistics on PetscMalloc() calls\nOS cannot compute process memory\n");
549:   }
550:   PetscViewerFlush(viewer);
551:   return(0);
552: }

554: /*@
555:     PetscMallocGetCurrentUsage - gets the current amount of memory used that was PetscMalloc()ed

557:     Not Collective

559:     Output Parameters:
560: .   space - number of bytes currently allocated

562:     Level: intermediate

564: .seealso: PetscMallocDump(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
565:           PetscMemoryGetMaximumUsage()
566:  @*/
567: PetscErrorCode  PetscMallocGetCurrentUsage(PetscLogDouble *space)
568: {
570:   *space = (PetscLogDouble) TRallocated;
571:   return(0);
572: }

574: /*@
575:     PetscMallocGetMaximumUsage - gets the maximum amount of memory used that was PetscMalloc()ed at any time
576:         during this run.

578:     Not Collective

580:     Output Parameters:
581: .   space - maximum number of bytes ever allocated at one time

583:     Level: intermediate

585: .seealso: PetscMallocDump(), PetscMallocView(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
586:           PetscMallocPushMaximumUsage()
587:  @*/
588: PetscErrorCode  PetscMallocGetMaximumUsage(PetscLogDouble *space)
589: {
591:   *space = (PetscLogDouble) TRMaxMem;
592:   return(0);
593: }

595: /*@
596:     PetscMallocPushMaximumUsage - Adds another event to collect the maximum memory usage over an event

598:     Not Collective

600:     Input Parameter:
601: .   event - an event id; this is just for error checking

603:     Level: developer

605: .seealso: PetscMallocDump(), PetscMallocView(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
606:           PetscMallocPopMaximumUsage()
607:  @*/
608: PetscErrorCode  PetscMallocPushMaximumUsage(int event)
609: {
611:   if (++NumTRMaxMems > MAXTRMAXMEMS) return(0);
612:   TRMaxMems[NumTRMaxMems-1]       = TRallocated;
613:   TRMaxMemsEvents[NumTRMaxMems-1] = event;
614:   return(0);
615: }

617: /*@
618:     PetscMallocPopMaximumUsage - collect the maximum memory usage over an event

620:     Not Collective

622:     Input Parameter:
623: .   event - an event id; this is just for error checking

625:     Output Parameter:
626: .   mu - maximum amount of memory malloced during this event; high water mark relative to the beginning of the event

628:     Level: developer

630: .seealso: PetscMallocDump(), PetscMallocView(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
631:           PetscMallocPushMaximumUsage()
632:  @*/
633: PetscErrorCode  PetscMallocPopMaximumUsage(int event,PetscLogDouble *mu)
634: {
636:   *mu = 0;
637:   if (NumTRMaxMems-- > MAXTRMAXMEMS) return(0);
638:   if (TRMaxMemsEvents[NumTRMaxMems] != event) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"PetscMallocPush/PopMaximumUsage() are not nested");
639:   *mu = TRMaxMems[NumTRMaxMems];
640:   return(0);
641: }

643: #if defined(PETSC_USE_DEBUG)
644: /*@C
645:    PetscMallocGetStack - returns a pointer to the stack for the location in the program a call to PetscMalloc() was used to obtain that memory

647:    Collective on PETSC_COMM_WORLD

649:    Input Parameter:
650: .    ptr - the memory location

652:    Output Parameter:
653: .    stack - the stack indicating where the program allocated this memory

655:    Level: intermediate

657: .seealso:  PetscMallocGetCurrentUsage(), PetscMallocView()
658: @*/
659: PetscErrorCode  PetscMallocGetStack(void *ptr,PetscStack **stack)
660: {
661:   TRSPACE *head;

664:   head   = (TRSPACE*) (((char*)ptr) - HEADER_BYTES);
665:   *stack = &head->stack;
666:   return(0);
667: }
668: #else
669: PetscErrorCode  PetscMallocGetStack(void *ptr,void **stack)
670: {
672:   *stack = NULL;
673:   return(0);
674: }
675: #endif

677: /*@C
678:    PetscMallocDump - Dumps the currently allocated memory blocks to a file. The information
679:    printed is: size of space (in bytes), address of space, id of space,
680:    file in which space was allocated, and line number at which it was
681:    allocated.

683:    Not Collective

685:    Input Parameter:
686: .  fp  - file pointer.  If fp is NULL, stdout is assumed.

688:    Options Database Key:
689: .  -malloc_dump <optional filename> - Dumps unfreed memory during call to PetscFinalize()

691:    Level: intermediate

693:    Fortran Note:
694:    The calling sequence in Fortran is PetscMallocDump(integer ierr)
695:    The fp defaults to stdout.

697:    Notes:
698:      Uses MPI_COMM_WORLD to display rank, because this may be called in PetscFinalize() after PETSC_COMM_WORLD has been freed.

700:      When called in PetscFinalize() dumps only the allocations that have not been properly freed

702:      PetscMallocView() prints a list of all memory ever allocated

704: .seealso:  PetscMallocGetCurrentUsage(), PetscMallocView(), PetscMallocViewSet(), PetscMallocValidate()
705: @*/
706: PetscErrorCode  PetscMallocDump(FILE *fp)
707: {
708:   TRSPACE        *head;
709:   size_t         libAlloc = 0;
711:   PetscMPIInt    rank;

714:   MPI_Comm_rank(MPI_COMM_WORLD,&rank);
715:   if (!fp) fp = PETSC_STDOUT;
716:   head = TRhead;
717:   while (head) {
718:     libAlloc += TRrequestedSize ? head->rsize : head->size;
719:     head = head->next;
720:   }
721:   if (TRallocated - libAlloc > 0) fprintf(fp,"[%d]Total space allocated %.0f bytes\n",rank,(PetscLogDouble)TRallocated);
722:   head = TRhead;
723:   while (head) {
724:     PetscBool isLib;

726:     PetscStrcmp(head->functionname, "PetscDLLibraryOpen", &isLib);
727:     if (!isLib) {
728:       fprintf(fp,"[%2d] %.0f bytes %s() at %s:%d\n",rank,(PetscLogDouble) (TRrequestedSize ? head->rsize : head->size),head->functionname,head->filename,head->lineno);
729: #if defined(PETSC_USE_DEBUG)
730:       PetscStackPrint(&head->stack,fp);
731: #endif
732:     }
733:     head = head->next;
734:   }
735:   return(0);
736: }

738: /*@
739:     PetscMallocViewSet - Activates logging of all calls to PetscMalloc() with a minimum size to view

741:     Not Collective

743:     Input Parameter:
744: .   logmin - minimum allocation size to log, or PETSC_DEFAULT

746:     Options Database Key:
747: +  -malloc_view <optional filename> - Activates PetscMallocView() in PetscFinalize()
748: .  -malloc_view_threshold <min> - Sets a minimum size if -malloc_view is used
749: -  -log_view_memory - view the memory usage also with the -log_view option

751:     Level: advanced

753:     Notes: Must be called after PetscMallocSetDebug()

755:     Uses MPI_COMM_WORLD to determine rank because PETSc communicators may not be available

757: .seealso: PetscMallocDump(), PetscMallocView(), PetscMallocViewSet(), PetscMallocTraceSet(), PetscMallocValidate()
758: @*/
759: PetscErrorCode PetscMallocViewSet(PetscLogDouble logmin)
760: {

764:   PetscLogMalloc = 0;
765:   PetscMemorySetGetMaximumUsage();
766:   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
767:   PetscLogMallocThreshold = (size_t)logmin;
768:   return(0);
769: }

771: /*@
772:     PetscMallocViewGet - Determine whether all calls to PetscMalloc() are being logged

774:     Not Collective

776:     Output Parameter
777: .   logging - PETSC_TRUE if logging is active

779:     Options Database Key:
780: .  -malloc_view <optional filename> - Activates PetscMallocView()

782:     Level: advanced

784: .seealso: PetscMallocDump(), PetscMallocView(), PetscMallocTraceGet()
785: @*/
786: PetscErrorCode PetscMallocViewGet(PetscBool *logging)
787: {

790:   *logging = (PetscBool)(PetscLogMalloc >= 0);
791:   return(0);
792: }

794: /*@
795:   PetscMallocTraceSet - Trace all calls to PetscMalloc()

797:   Not Collective

799:   Input Parameters:
800: + viewer - The viewer to use for tracing, or NULL to use stdout
801: . active - Flag to activate or deactivate tracing
802: - logmin - The smallest memory size that will be logged

804:   Note:
805:   The viewer should not be collective.

807:   Level: advanced

809: .seealso: PetscMallocTraceGet(), PetscMallocViewGet(), PetscMallocDump(), PetscMallocView()
810: @*/
811: PetscErrorCode PetscMallocTraceSet(PetscViewer viewer, PetscBool active, PetscLogDouble logmin)
812: {

816:   if (!active) {PetscLogMallocTrace = -1; return(0);}
817:   PetscLogMallocTraceViewer = !viewer ? PETSC_VIEWER_STDOUT_SELF : viewer;
818:   PetscLogMallocTrace = 0;
819:   PetscMemorySetGetMaximumUsage();
820:   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
821:   PetscLogMallocTraceThreshold = (size_t) logmin;
822:   return(0);
823: }

825: /*@
826:   PetscMallocTraceGet - Determine whether all calls to PetscMalloc() are being traced

828:   Not Collective

830:   Output Parameter:
831: . logging - PETSC_TRUE if logging is active

833:   Options Database Key:
834: . -malloc_view <optional filename> - Activates PetscMallocView()

836:   Level: advanced

838: .seealso: PetscMallocTraceSet(), PetscMallocViewGet(), PetscMallocDump(), PetscMallocView()
839: @*/
840: PetscErrorCode PetscMallocTraceGet(PetscBool *logging)
841: {

844:   *logging = (PetscBool) (PetscLogMallocTrace >= 0);
845:   return(0);
846: }

848: /*@C
849:     PetscMallocView - Saves the log of all calls to PetscMalloc(); also calls
850:        PetscMemoryGetMaximumUsage()

852:     Not Collective

854:     Input Parameter:
855: .   fp - file pointer; or NULL

857:     Options Database Key:
858: .  -malloc_view <optional filename> - Activates PetscMallocView() in PetscFinalize()

860:     Level: advanced

862:    Fortran Note:
863:    The calling sequence in Fortran is PetscMallocView(integer ierr)
864:    The fp defaults to stdout.

866:    Notes:
867:      PetscMallocDump() dumps only the currently unfreed memory, this dumps all memory ever allocated

869:      PetscMemoryView() gives a brief summary of current memory usage

871: .seealso: PetscMallocGetCurrentUsage(), PetscMallocDump(), PetscMallocViewSet(), PetscMemoryView()
872: @*/
873: PetscErrorCode  PetscMallocView(FILE *fp)
874: {
875:   PetscInt       i,j,n,*perm;
876:   size_t         *shortlength;
877:   int            *shortcount,err;
878:   PetscMPIInt    rank;
879:   PetscBool      match;
880:   const char     **shortfunction;
881:   PetscLogDouble rss;

885:   MPI_Comm_rank(MPI_COMM_WORLD,&rank);
886:   err = fflush(fp);
887:   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");

889:   if (PetscLogMalloc < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"PetscMallocView() called without call to PetscMallocViewSet() this is often due to\n                      setting the option -malloc_view AFTER PetscInitialize() with PetscOptionsInsert() or PetscOptionsInsertFile()");

891:   if (!fp) fp = PETSC_STDOUT;
892:   PetscMemoryGetMaximumUsage(&rss);
893:   if (rss) {
894:     (void) fprintf(fp,"[%d] Maximum memory PetscMalloc()ed %.0f maximum size of entire process %.0f\n",rank,(PetscLogDouble)TRMaxMem,rss);
895:   } else {
896:     (void) fprintf(fp,"[%d] Maximum memory PetscMalloc()ed %.0f OS cannot compute size of entire process\n",rank,(PetscLogDouble)TRMaxMem);
897:   }
898:   shortcount    = (int*)malloc(PetscLogMalloc*sizeof(int));if (!shortcount) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
899:   shortlength   = (size_t*)malloc(PetscLogMalloc*sizeof(size_t));if (!shortlength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
900:   shortfunction = (const char**)malloc(PetscLogMalloc*sizeof(char*));if (!shortfunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
901:   for (i=0,n=0; i<PetscLogMalloc; i++) {
902:     for (j=0; j<n; j++) {
903:       PetscStrcmp(shortfunction[j],PetscLogMallocFunction[i],&match);
904:       if (match) {
905:         shortlength[j] += PetscLogMallocLength[i];
906:         shortcount[j]++;
907:         goto foundit;
908:       }
909:     }
910:     shortfunction[n] = PetscLogMallocFunction[i];
911:     shortlength[n]   = PetscLogMallocLength[i];
912:     shortcount[n]    = 1;
913:     n++;
914: foundit:;
915:   }

917:   perm = (PetscInt*)malloc(n*sizeof(PetscInt));if (!perm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
918:   for (i=0; i<n; i++) perm[i] = i;
919:   PetscSortStrWithPermutation(n,(const char**)shortfunction,perm);

921:   (void) fprintf(fp,"[%d] Memory usage sorted by function\n",rank);
922:   for (i=0; i<n; i++) {
923:     (void) fprintf(fp,"[%d] %d %.0f %s()\n",rank,shortcount[perm[i]],(PetscLogDouble)shortlength[perm[i]],shortfunction[perm[i]]);
924:   }
925:   free(perm);
926:   free(shortlength);
927:   free(shortcount);
928:   free((char**)shortfunction);
929:   err = fflush(fp);
930:   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
931:   return(0);
932: }

934: /* ---------------------------------------------------------------------------- */

936: /*@
937:     PetscMallocSetDebug - Set's PETSc memory debugging

939:     Not Collective

941:     Input Parameters:
942: +   eachcall - checks the entire heap of allocated memory for issues on each call to PetscMalloc() and PetscFree()
943: -   initializenan - initializes all memory with NaN to catch use of uninitialized floating point arrays

945:     Options Database:
946: +   -malloc_debug <true or false> - turns on or off debugging
947: .   -malloc_test - turns on all debugging if PETSc was configured with debugging including -malloc_dump, otherwise ignored
948: .   -malloc_view_threshold t - log only allocations larger than t
949: .   -malloc_dump <filename> - print a list of all memory that has not been freed
950: .   -malloc no - (deprecated) same as -malloc_debug no
951: -   -malloc_log - (deprecated) same as -malloc_view

953:    Level: developer

955:     Notes: This is called in PetscInitialize() and should not be called elsewhere

957: .seealso: CHKMEMQ(), PetscMallocValidate(), PetscMallocGetDebug()
958: @*/
959: PetscErrorCode PetscMallocSetDebug(PetscBool eachcall, PetscBool initializenan)
960: {

964:   if (PetscTrMalloc == PetscTrMallocDefault) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Cannot call this routine more than once, it can only be called in PetscInitialize()");
965:   PetscMallocSet(PetscTrMallocDefault,PetscTrFreeDefault,PetscTrReallocDefault);

967:   TRallocated         = 0;
968:   TRfrags             = 0;
969:   TRhead              = NULL;
970:   TRid                = 0;
971:   TRdebugLevel        = eachcall;
972:   TRMaxMem            = 0;
973:   PetscLogMallocMax   = 10000;
974:   PetscLogMalloc      = -1;
975:   TRdebugIinitializenan = initializenan;
976:   return(0);
977: }

979: /*@
980:     PetscMallocGetDebug - Indicates what PETSc memory debugging it is doing.

982:     Not Collective

984:     Output Parameters:
985: +    basic - doing basic debugging
986: .    eachcall - checks the entire memory heap at each PetscMalloc()/PetscFree()
987: -    initializenan - initializes memory with NaN

989:    Level: intermediate

991:    Notes:
992:      By default, the debug version always does some debugging unless you run with -malloc_debug no

994: .seealso: CHKMEMQ(), PetscMallocValidate(), PetscMallocSetDebug()
995: @*/
996: PetscErrorCode PetscMallocGetDebug(PetscBool *basic, PetscBool *eachcall, PetscBool *initializenan)
997: {
999:   if (basic) *basic = (PetscTrMalloc == PetscTrMallocDefault) ? PETSC_TRUE : PETSC_FALSE;
1000:   if (eachcall) *eachcall           = TRdebugLevel;
1001:   if (initializenan) *initializenan = TRdebugIinitializenan;
1002:   return(0);
1003: }

1005: /*@
1006:   PetscMallocLogRequestedSizeSet - Whether to log the requested or aligned memory size

1008:   Not Collective

1010:   Input Parameter:
1011: . flg - PETSC_TRUE to log the requested memory size

1013:   Options Database:
1014: . -malloc_requested_size <bool> - Sets this flag

1016:   Level: developer

1018: .seealso: PetscMallocLogRequestedSizeGet(), PetscMallocViewSet()
1019: @*/
1020: PetscErrorCode PetscMallocLogRequestedSizeSet(PetscBool flg)
1021: {
1023:   TRrequestedSize = flg;
1024:   return(0);
1025: }

1027: /*@
1028:   PetscMallocLogRequestedSizeGet - Whether to log the requested or aligned memory size

1030:   Not Collective

1032:   Output Parameter:
1033: . flg - PETSC_TRUE if we log the requested memory size

1035:   Level: developer

1037: .seealso: PetscMallocLogRequestedSizeSetinalSizeSet(), PetscMallocViewSet()
1038: @*/
1039: PetscErrorCode PetscMallocLogRequestedSizeGet(PetscBool *flg)
1040: {
1042:   *flg = TRrequestedSize;
1043:   return(0);
1044: }