Actual source code: mal.c
petsc-3.10.5 2019-03-28
Report Typos and Errors

      1: /*
      2:     Code that allows a user to dictate what malloc() PETSc uses.
      3: */
      4:  #include <petscsys.h>
      5: #include <stdarg.h>
      6: #if defined(PETSC_HAVE_MALLOC_H)
      7: #include <malloc.h>
      8: #endif
      9: #if defined(PETSC_HAVE_MEMKIND)
     10: #include <errno.h>
     11: #include <memkind.h>
     12: typedef enum {PETSC_MK_DEFAULT=0,PETSC_MK_HBW_PREFERRED=1} PetscMemkindType;
     13: PetscMemkindType currentmktype = PETSC_MK_HBW_PREFERRED;
     14: PetscMemkindType previousmktype = PETSC_MK_HBW_PREFERRED;
     15: #endif
     16: /*
     17:         We want to make sure that all mallocs of double or complex numbers are complex aligned.
     18:     1) on systems with memalign() we call that routine to get an aligned memory location
     19:     2) on systems without memalign() we
     20:        - allocate one sizeof(PetscScalar) extra space
     21:        - we shift the pointer up slightly if needed to get PetscScalar aligned
     22:        - if shifted we store at ptr[-1] the amount of shift (plus a classid)
     23: */
     24: #define SHIFT_CLASSID 456123

     26: PETSC_EXTERN PetscErrorCode PetscMallocAlign(size_t mem,int line,const char func[],const char file[],void **result)
     27: {
     28:   if (!mem) { *result = NULL; return 0; }
     29: #if defined(PETSC_HAVE_MEMKIND)
     30:   {
     31:     int ierr;
     32:     if (!currentmktype) memkind_posix_memalign(MEMKIND_DEFAULT,result,PETSC_MEMALIGN,mem);
     33:     else memkind_posix_memalign(MEMKIND_HBW_PREFERRED,result,PETSC_MEMALIGN,mem);
     34:     if (ierr == EINVAL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memkind: invalid 3rd or 4th argument of memkind_posix_memalign()");
     35:     if (ierr == ENOMEM) PetscInfo1(0,"Memkind: fail to request HBW memory %.0f, falling back to normal memory\n",(PetscLogDouble)mem);
     36:   }
     37: #else
     38: #  if defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)
     39:   *result = malloc(mem);
     40: #  elif defined(PETSC_HAVE_MEMALIGN)
     41:   *result = memalign(PETSC_MEMALIGN,mem);
     42: #  else
     43:   {
     44:     /*
     45:       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
     46:     */
     47:     int *ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN);
     48:     if (ptr) {
     49:       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
     50:       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
     51:       ptr[shift-1] = shift + SHIFT_CLASSID;
     52:       ptr         += shift;
     53:       *result      = (void*)ptr;
     54:     } else {
     55:       *result      = NULL;
     56:     }
     57:   }
     58: #  endif
     59: #endif
     60:   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
     61:   return 0;
     62: }

     64: PETSC_EXTERN PetscErrorCode PetscFreeAlign(void *ptr,int line,const char func[],const char file[])
     65: {
     66:   if (!ptr) return 0;
     67: #if defined(PETSC_HAVE_MEMKIND)
     68:   memkind_free(0,ptr); /* specify the kind to 0 so that memkind will look up for the right type */
     69: #else
     70: #  if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
     71:   {
     72:     /*
     73:       Previous int tells us how many ints the pointer has been shifted from
     74:       the original address provided by the system malloc().
     75:     */
     76:     int shift = *(((int*)ptr)-1) - SHIFT_CLASSID;
     77:     if (shift > PETSC_MEMALIGN-1) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
     78:     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
     79:     ptr = (void*)(((int*)ptr) - shift);
     80:   }
     81: #  endif

     83: #  if defined(PETSC_HAVE_FREE_RETURN_INT)
     84:   int err = free(ptr);
     85:   if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
     86: #  else
     87:   free(ptr);
     88: #  endif
     89: #endif
     90:   return 0;
     91: }

     93: PETSC_EXTERN PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result)
     94: {

     97:   if (!mem) {
     98:     PetscFreeAlign(*result, line, func, file);
     99:     if (ierr) return ierr;
    100:     *result = NULL;
    101:     return 0;
    102:   }
    103: #if defined(PETSC_HAVE_MEMKIND)
    104:   if (!currentmktype) *result = memkind_realloc(MEMKIND_DEFAULT,*result,mem);
    105:   else *result = memkind_realloc(MEMKIND_HBW_PREFERRED,*result,mem);
    106: #else
    107: #  if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
    108:   {
    109:     /*
    110:       Previous int tells us how many ints the pointer has been shifted from
    111:       the original address provided by the system malloc().
    112:     */
    113:     int shift = *(((int*)*result)-1) - SHIFT_CLASSID;
    114:     if (shift > PETSC_MEMALIGN-1) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
    115:     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
    116:     *result = (void*)(((int*)*result) - shift);
    117:   }
    118: #  endif

    120: #  if (defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || defined(PETSC_HAVE_MEMALIGN)
    121:   *result = realloc(*result, mem);
    122: #  else
    123:   {
    124:     /*
    125:       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
    126:     */
    127:     int *ptr = (int *) realloc(*result, mem + 2*PETSC_MEMALIGN);
    128:     if (ptr) {
    129:       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
    130:       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
    131:       ptr[shift-1] = shift + SHIFT_CLASSID;
    132:       ptr         += shift;
    133:       *result      = (void*)ptr;
    134:     } else {
    135:       *result      = NULL;
    136:     }
    137:   }
    138: #  endif
    139: #endif
    140:   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
    141: #if defined(PETSC_HAVE_MEMALIGN)
    142:   /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to
    143:    * realloc and, if the alignment is wrong, malloc/copy/free. */
    144:   if (((size_t) (*result)) % PETSC_MEMALIGN) {
    145:     void *newResult;
    146: #  if defined(PETSC_HAVE_MEMKIND)
    147:     {
    148:       int ierr;
    149:       if (!currentmktype) memkind_posix_memalign(MEMKIND_DEFAULT,&newResult,PETSC_MEMALIGN,mem);
    150:       else memkind_posix_memalign(MEMKIND_HBW_PREFERRED,&newResult,PETSC_MEMALIGN,mem);
    151:       if (ierr == EINVAL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memkind: invalid 3rd or 4th argument of memkind_posix_memalign()");
    152:       if (ierr == ENOMEM) PetscInfo1(0,"Memkind: fail to request HBW memory %.0f, falling back to normal memory\n",(PetscLogDouble)mem);
    153:     }
    154: #  else
    155:     newResult = memalign(PETSC_MEMALIGN,mem);
    156: #  endif
    157:     if (!newResult) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
    158:     PetscMemcpy(newResult,*result,mem);
    159:     if (ierr) return ierr;
    160: #  if defined(PETSC_HAVE_FREE_RETURN_INT)
    161:     {
    162:       int err = free(*result);
    163:       if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
    164:     }
    165: #  else
    166: #    if defined(PETSC_HAVE_MEMKIND)
    167:     memkind_free(0,*result);
    168: #    else
    169:     free(*result);
    170: #    endif
    171: #  endif
    172:     *result = newResult;
    173:   }
    174: #endif
    175:   return 0;
    176: }

    178: PetscErrorCode (*PetscTrMalloc)(size_t,int,const char[],const char[],void**) = PetscMallocAlign;
    179: PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[])           = PetscFreeAlign;
    180: PetscErrorCode (*PetscTrRealloc)(size_t,int,const char[],const char[],void**) = PetscReallocAlign;

    182: PETSC_INTERN PetscBool petscsetmallocvisited;
    183: PetscBool petscsetmallocvisited = PETSC_FALSE;

    185: /*@C
    186:    PetscMallocSet - Sets the routines used to do mallocs and frees.
    187:    This routine MUST be called before PetscInitialize() and may be
    188:    called only once.

    190:    Not Collective

    192:    Input Parameters:
    193: +  malloc - the malloc routine
    194: -  free - the free routine

    196:    Level: developer

    198:    Concepts: malloc
    199:    Concepts: memory^allocation

    201: @*/
    202: PetscErrorCode PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],void**),
    203:                               PetscErrorCode (*ifree)(void*,int,const char[],const char[]))
    204: {
    206:   if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times");
    207:   PetscTrMalloc         = imalloc;
    208:   PetscTrFree           = ifree;
    209:   petscsetmallocvisited = PETSC_TRUE;
    210:   return(0);
    211: }

    213: /*@C
    214:    PetscMallocClear - Resets the routines used to do mallocs and frees to the
    215:         defaults.

    217:    Not Collective

    219:    Level: developer

    221:    Notes:
    222:     In general one should never run a PETSc program with different malloc() and
    223:     free() settings for different parts; this is because one NEVER wants to
    224:     free() an address that was malloced by a different memory management system

    226: @*/
    227: PetscErrorCode PetscMallocClear(void)
    228: {
    230:   PetscTrMalloc         = PetscMallocAlign;
    231:   PetscTrFree           = PetscFreeAlign;
    232:   petscsetmallocvisited = PETSC_FALSE;
    233:   return(0);
    234: }

    236: PetscErrorCode PetscMemoryTrace(const char label[])
    237: {
    238:   PetscErrorCode        ierr;
    239:   PetscLogDouble        mem,mal;
    240:   static PetscLogDouble oldmem = 0,oldmal = 0;

    243:   PetscMemoryGetCurrentUsage(&mem);
    244:   PetscMallocGetCurrentUsage(&mal);

    246:   PetscPrintf(PETSC_COMM_WORLD,"%s High water  %8.3f MB increase %8.3f MB Current %8.3f MB increase %8.3f MB\n",label,mem*1e-6,(mem - oldmem)*1e-6,mal*1e-6,(mal - oldmal)*1e-6);
    247:   oldmem = mem;
    248:   oldmal = mal;
    249:   return(0);
    250: }

    252: static PetscErrorCode (*PetscTrMallocOld)(size_t,int,const char[],const char[],void**) = PetscMallocAlign;
    253: static PetscErrorCode (*PetscTrFreeOld)(void*,int,const char[],const char[])           = PetscFreeAlign;

    255: /*@C
    256:    PetscMallocSetDRAM - Set PetscMalloc to use DRAM.
    257:      If memkind is available, change the memkind type. Otherwise, switch the
    258:      current malloc and free routines to the PetscMallocAlign and
    259:      PetscFreeAlign (PETSc default).

    261:    Not Collective

    263:    Level: developer

    265:    Notes:
    266:      This provides a way to do the allocation on DRAM temporarily. One
    267:      can switch back to the previous choice by calling PetscMallocReset().

    269: .seealso: PetscMallocReset()
    270: @*/
    271: PetscErrorCode PetscMallocSetDRAM(void)
    272: {
    274:   if (PetscTrMalloc == PetscMallocAlign) {
    275: #if defined(PETSC_HAVE_MEMKIND)
    276:     previousmktype = currentmktype;
    277:     currentmktype  = PETSC_MK_DEFAULT;
    278: #endif
    279:   } else {
    280:     /* Save the previous choice */
    281:     PetscTrMallocOld = PetscTrMalloc;
    282:     PetscTrFreeOld   = PetscTrFree;
    283:     PetscTrMalloc    = PetscMallocAlign;
    284:     PetscTrFree      = PetscFreeAlign;
    285:   }
    286:   return(0);
    287: }

    289: /*@C
    290:    PetscMallocResetDRAM - Reset the changes made by PetscMallocSetDRAM

    292:    Not Collective

    294:    Level: developer

    296: .seealso: PetscMallocSetDRAM()
    297: @*/
    298: PetscErrorCode PetscMallocResetDRAM(void)
    299: {
    301:   if (PetscTrMalloc == PetscMallocAlign) {
    302: #if defined(PETSC_HAVE_MEMKIND)
    303:     currentmktype = previousmktype;
    304: #endif
    305:   } else {
    306:     /* Reset to the previous choice */
    307:     PetscTrMalloc = PetscTrMallocOld;
    308:     PetscTrFree   = PetscTrFreeOld;
    309:   }
    310:   return(0);
    311: }

    313: static PetscBool petscmalloccoalesce =
    314: #if defined(PETSC_USE_MALLOC_COALESCED)
    315:   PETSC_TRUE;
    316: #else
    317:   PETSC_FALSE;
    318: #endif

    320: /*@C
    321:    PetscMallocSetCoalesce - Use coalesced malloc when allocating groups of objects

    323:    Not Collective

    325:    Input Parameters:
    326: .  coalesce - PETSC_TRUE to use coalesced malloc for multi-object allocation.

    328:    Options Database Keys:
    329: .  -malloc_coalesce - turn coalesced malloc on or off

    331:    Note:
    332:    PETSc uses coalesced malloc by default for optimized builds and not for debugging builds.  This default can be changed via the command-line option -malloc_coalesce or by calling this function.

    334:    Level: developer

    336: .seealso: PetscMallocA()
    337: @*/
    338: PetscErrorCode PetscMallocSetCoalesce(PetscBool coalesce)
    339: {
    341:   petscmalloccoalesce = coalesce;
    342:   return(0);
    343: }

    345: /*@C
    346:    PetscMallocA - Allocate and optionally clear one or more objects, possibly using coalesced malloc

    348:    Not Collective

    350:    Input Parameters:
    351: +  n - number of objects to allocate (at least 1)
    352: .  clear - use calloc() to allocate space initialized to zero
    353: .  lineno - line number to attribute allocation (typically __LINE__)
    354: .  function - function to attribute allocation (typically PETSC_FUNCTION_NAME)
    355: .  filename - file name to attribute allocation (typically __FILE__)
    356: -  bytes0 - first of n object sizes

    358:    Output Parameters:
    359: .  ptr0 - first of n pointers to allocate

    361:    Notes:
    362:    This function is not normally called directly by users, but rather via the macros PetscMalloc1(), PetscMalloc2(), or PetscCalloc1(), etc.

    364:    Level: developer

    366: .seealso: PetscMallocAlign(), PetscMallocSet(), PetscMalloc1(), PetscMalloc2(), PetscMalloc3(), PetscMalloc4(), PetscMalloc5(), PetscMalloc6(), PetscMalloc7(), PetscCalloc1(), PetscCalloc2(), PetscCalloc3(), PetscCalloc4(), PetscCalloc5(), PetscCalloc6(), PetscCalloc7(), PetscFreeA()
    367: @*/
    368: PetscErrorCode PetscMallocA(int n,PetscBool clear,int lineno,const char *function,const char *filename,size_t bytes0,void *ptr0,...)
    369: {
    371:   va_list        Argp;
    372:   size_t         bytes[8],sumbytes;
    373:   void           **ptr[8];
    374:   int            i;

    377:   if (n > 8) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Attempt to allocate %d objects but only 8 supported",n);
    378:   bytes[0] = bytes0;
    379:   ptr[0] = (void**)ptr0;
    380:   sumbytes = (bytes0 + PETSC_MEMALIGN-1) & ~(PETSC_MEMALIGN-1);
    381:   va_start(Argp,ptr0);
    382:   for (i=1; i<n; i++) {
    383:     bytes[i] = va_arg(Argp,size_t);
    384:     ptr[i] = va_arg(Argp,void**);
    385:     sumbytes += (bytes[i] + PETSC_MEMALIGN-1) & ~(PETSC_MEMALIGN-1);
    386:   }
    387:   va_end(Argp);
    388:   if (petscmalloccoalesce) {
    389:     char *p;
    390:     (*PetscTrMalloc)(sumbytes,lineno,function,filename,(void**)&p);
    391:     for (i=0; i<n; i++) {
    392:       *ptr[i] = bytes[i] ? p : NULL;
    393:       p = (char*)PetscAddrAlign(p + bytes[i]);
    394:     }
    395:   } else {
    396:     for (i=0; i<n; i++) {
    397:       (*PetscTrMalloc)(bytes[i],lineno,function,filename,(void**)ptr[i]);
    398:     }
    399:   }
    400:   if (clear) {
    401:     for (i=0; i<n; i++) {
    402:       PetscMemzero(*ptr[i],bytes[i]);
    403:     }
    404:   }
    405:   return(0);
    406: }

    408: /*@C
    409:    PetscFreeA - Free one or more objects, possibly allocated using coalesced malloc

    411:    Not Collective

    413:    Input Parameters:
    414: +  n - number of objects to free (at least 1)
    415: .  lineno - line number to attribute deallocation (typically __LINE__)
    416: .  function - function to attribute deallocation (typically PETSC_FUNCTION_NAME)
    417: .  filename - file name to attribute deallocation (typically __FILE__)
    418: -  ptr0 ... - first of n pointers to free

    420:    Note:
    421:    This function is not normally called directly by users, but rather via the macros PetscFree1(), PetscFree2(), etc.

    423:    The pointers are zeroed to prevent users from accidently reusing space that has been freed.

    425:    Level: developer

    427: .seealso: PetscMallocAlign(), PetscMallocSet(), PetscMallocA(), PetscFree1(), PetscFree2(), PetscFree3(), PetscFree4(), PetscFree5(), PetscFree6(), PetscFree7()
    428: @*/
    429: PetscErrorCode PetscFreeA(int n,int lineno,const char *function,const char *filename,void *ptr0,...)
    430: {
    432:   va_list        Argp;
    433:   void           **ptr[8];
    434:   int            i;

    437:   if (n > 8) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Attempt to allocate %d objects but only up to 8 supported",n);
    438:   ptr[0] = (void**)ptr0;
    439:   va_start(Argp,ptr0);
    440:   for (i=1; i<n; i++) {
    441:     ptr[i] = va_arg(Argp,void**);
    442:   }
    443:   va_end(Argp);
    444:   if (petscmalloccoalesce) {
    445:     for (i=0; i<n; i++) {       /* Find first nonempty allocation */
    446:       if (*ptr[i]) break;
    447:     }
    448:     while (--n > i) {
    449:       *ptr[n] = NULL;
    450:     }
    451:     (*PetscTrFree)(*ptr[n],lineno,function,filename);
    452:     *ptr[n] = NULL;
    453:   } else {
    454:     while (--n >= 0) {
    455:       (*PetscTrFree)(*ptr[n],lineno,function,filename);
    456:       *ptr[n] = NULL;
    457:     }
    458:   }
    459:   return(0);
    460: }