doc: Add serial to list of ci file reserved words
[charm.git] / src / conv-core / memory.c
1
2
3 /**  
4  @defgroup MemoryModule Memory Allocation and Monitoring
5
6  This module provides the functions malloc, free, calloc, cfree,
7  realloc, valloc, memalign, and other functions for determining
8  the current and past memory usage. 
9
10  There are several possible implementations provided here-- the user
11  can link in whichever is best using the -malloc option with charmc.
12
13  The major possibilities here are empty (use the system's malloc),
14  GNU (use malloc-gnu.c), and meta (use malloc-cache.c or malloc-paranoid.c).
15  On machines without sbrk(), only the system's malloc is available.
16
17  The CMK_MEMORY_BUILD_* symbols come in from the compiler command line.
18
19  To determine how much memory your Charm++ program is using on a 
20  processor, call CmiMemoryUsage(). This function will return the 
21  number of bytes allocated, usually representing the heap size. 
22  It is possible that this measurement will not exactly represent
23  the heap size, but rather will reflect the total amount of 
24  memory used by the program.
25
26 */
27
28
29 /** 
30     @addtogroup MemoryModule
31     @{
32 */
33
34
35 /******************************************************************************
36  *
37  * This module provides the functions malloc, free, calloc, cfree,
38  * realloc, valloc, and memalign.
39  *
40  *
41  *****************************************************************************/
42
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h> /*For memset, memcpy*/
47 #ifndef WIN32
48 #  include <unistd.h> /*For getpagesize*/
49 #endif
50 #include "converse.h"
51
52 void * memory_stack_top; /*The higher end of the stack (approximation)*/
53 int cpdInSystem=1; /*Start inside the system (until we start executing user code)*/
54
55 /*Choose the proper default configuration*/
56 #if CMK_MEMORY_BUILD_DEFAULT
57
58 # if CMK_MALLOC_USE_OS_BUILTIN
59 /*Default to the system malloc-- perhaps the only possibility*/
60 #  define CMK_MEMORY_BUILD_OS 1
61
62 # elif CMK_MALLOC_USE_GNUOLD_MALLOC
63 #  define CMK_MEMORY_BUILD_GNUOLD  1
64 # else
65 /*Choose a good all-around default malloc*/
66 #  define CMK_MEMORY_BUILD_GNU 1
67 # endif
68
69 #endif
70
71 #if CMK_MEMORY_BUILD_OS_WRAPPED
72 #define CMK_MEMORY_BUILD_OS 1
73 #endif
74 #if CMK_MEMORY_BUILD_GNU_HOOKS
75 /*While in general on could build hooks on the GNU we have, for now the hooks
76  * are setup to work only with OS memory libraries --Filippo*/
77 #define CMK_MEMORY_BUILD_OS 1
78 #endif
79
80 #if CMK_MEMORY_BUILD_OS
81 #if CMK_MEMORY_BUILD_OS_WRAPPED
82
83 void initialize_memory_wrapper();
84 void * initialize_memory_wrapper_calloc(size_t nelem, size_t size);
85 void * initialize_memory_wrapper_malloc(size_t size);
86 void * initialize_memory_wrapper_realloc(void *ptr, size_t size);
87 void * initialize_memory_wrapper_memalign(size_t align, size_t size);
88 void * initialize_memory_wrapper_valloc(size_t size);
89 void initialize_memory_wrapper_free(void *ptr);
90 void initialize_memory_wrapper_cfree(void *ptr);
91
92 void * (*mm_malloc)(size_t) = initialize_memory_wrapper_malloc;
93 void * (*mm_calloc)(size_t,size_t) = initialize_memory_wrapper_calloc;
94 void * (*mm_realloc)(void*,size_t) = initialize_memory_wrapper_realloc;
95 void * (*mm_memalign)(size_t,size_t) = initialize_memory_wrapper_memalign;
96 void * (*mm_valloc)(size_t) = initialize_memory_wrapper_valloc;
97 void (*mm_free)(void*) = initialize_memory_wrapper_free;
98 void (*mm_cfree)(void*) = initialize_memory_wrapper_cfree;
99
100 void * initialize_memory_wrapper_calloc(size_t nelem, size_t size) {
101   static int calloc_wrapper = 0;
102   if (calloc_wrapper) return NULL;
103   calloc_wrapper = 1;
104   initialize_memory_wrapper();
105   return (*mm_calloc)(nelem,size);
106 }
107
108 void * initialize_memory_wrapper_malloc(size_t size) {
109   static int malloc_wrapper = 0;
110   if (malloc_wrapper) return NULL;
111   malloc_wrapper = 1;
112   initialize_memory_wrapper();
113   return (*mm_malloc)(size);
114 }
115
116 void * initialize_memory_wrapper_realloc(void *ptr, size_t size) {
117   initialize_memory_wrapper();
118   return (*mm_realloc)(ptr,size);
119 }
120
121 void * initialize_memory_wrapper_memalign(size_t align, size_t size) {
122   initialize_memory_wrapper();
123   return (*mm_memalign)(align,size);
124 }
125
126 void * initialize_memory_wrapper_valloc(size_t size) {
127   initialize_memory_wrapper();
128   return (*mm_valloc)(size);
129 }
130
131 void initialize_memory_wrapper_free(void *ptr) {
132   initialize_memory_wrapper();
133   (*mm_free)(ptr);
134 }
135
136 void initialize_memory_wrapper_cfree(void *ptr) {
137   initialize_memory_wrapper();
138   (*mm_cfree)(ptr);
139 }
140
141 #define mm_malloc   (*mm_malloc)
142 #define mm_free     (*mm_free)
143 #define mm_calloc   (*mm_calloc)
144 #define mm_cfree    (*mm_cfree)
145 #define mm_realloc  (*mm_realloc)
146 #define mm_memalign (*mm_memalign)
147 #define mm_valloc   (*mm_valloc)
148
149 #else
150 #define mm_malloc   malloc
151 #define mm_calloc   calloc
152 #define mm_memalign memalign
153 #define mm_free     free
154 #endif
155 #endif
156
157 CMK_TYPEDEF_UINT8 _memory_allocated = 0;
158 CMK_TYPEDEF_UINT8 _memory_allocated_max = 0; /* High-Water Mark */
159 CMK_TYPEDEF_UINT8 _memory_allocated_min = 0; /* Low-Water Mark */
160
161 /*Rank of the processor that's currently holding the CmiMemLock,
162 or -1 if nobody has it.  Only set when malloc might be reentered.
163 */
164 static int rank_holding_CmiMemLock=-1;
165
166 /* By default, there are no flags */
167 static int CmiMemoryIs_flag=0;
168
169 int CmiMemoryIs(int flag)
170 {
171         return (CmiMemoryIs_flag&flag)==flag;
172 }
173
174 /**
175  * memory_lifeRaft is a very small heap-allocated region.
176  * The lifeRaft is supposed to be just big enough to provide
177  * enough memory to cleanly shut down if we run out of memory.
178  */
179 static char *memory_lifeRaft=NULL;
180
181 void CmiOutOfMemoryInit(void);
182
183 void CmiOutOfMemory(int nBytes)
184 { /* We're out of memory: free up the liferaft memory and abort */
185   char errMsg[200];
186   if (memory_lifeRaft) free(memory_lifeRaft);
187   if (nBytes>0) sprintf(errMsg,"Could not malloc() %d bytes--are we out of memory? (used :%.3fMB)",nBytes,CmiMemoryUsage()/1000000.0);
188   else sprintf(errMsg,"Could not malloc()--are we out of memory? (used: %.3fMB)", CmiMemoryUsage()/1000000.0);
189   CmiAbort(errMsg);
190 }
191
192 /* Global variables keeping track of the status of the system (mostly used by charmdebug) */
193 int memory_status_info=0;
194 int memory_chare_id=0;
195
196 #if CMK_MEMORY_BUILD_OS
197 /* Just use the OS's built-in malloc.  All we provide is CmiMemoryInit.
198 */
199
200
201 #if CMK_MEMORY_BUILD_OS_WRAPPED || CMK_MEMORY_BUILD_GNU_HOOKS
202
203 #if CMK_MEMORY_BUILD_GNU_HOOKS
204
205 static void *meta_malloc(size_t);
206 static void *meta_realloc(void*,size_t);
207 static void *meta_memalign(size_t,size_t);
208 static void meta_free(void*);
209 static void *meta_malloc_hook(size_t s, const void* c) {return meta_malloc(s);}
210 static void *meta_realloc_hook(void* p,size_t s, const void* c) {return meta_realloc(p,s);}
211 static void *meta_memalign_hook(size_t s1,size_t s2, const void* c) {return meta_memalign(s1,s2);}
212 static void meta_free_hook(void* p, const void* c) {meta_free(p);}
213
214 #define BEFORE_MALLOC_CALL \
215   __malloc_hook = old_malloc_hook; \
216   __realloc_hook = old_realloc_hook; \
217   __memalign_hook = old_memalign_hook; \
218   __free_hook = old_free_hook;
219 #define AFTER_MALLOC_CALL \
220   old_malloc_hook = __malloc_hook; \
221   old_realloc_hook = __realloc_hook; \
222   old_memalign_hook = __memalign_hook; \
223   old_free_hook = __free_hook; \
224   __malloc_hook = meta_malloc_hook; \
225   __realloc_hook = meta_realloc_hook; \
226   __memalign_hook = meta_memalign_hook; \
227   __free_hook = meta_free_hook;
228
229 #if CMK_HAS_MALLOC_H
230 #include <malloc.h>
231 #endif
232 static void *(*old_malloc_hook) (size_t, const void*);
233 static void *(*old_realloc_hook) (void*,size_t, const void*);
234 static void *(*old_memalign_hook) (size_t,size_t, const void*);
235 static void (*old_free_hook) (void*, const void*);
236
237 #else /* CMK_MEMORY_BUILD_GNU_HOOKS */
238 #define BEFORE_MALLOC_CALL   /*empty*/
239 #define AFTER_MALLOC_CALL    /*empty*/
240 #endif
241
242 #if CMK_MEMORY_BUILD_VERBOSE
243 #include "memory-verbose.c"
244 #endif
245
246 #if CMK_MEMORY_BUILD_PARANOID
247 #include "memory-paranoid.c"
248 #endif
249
250 #if CMK_MEMORY_BUILD_LEAK
251 #include "memory-leak.c"
252 #endif
253
254 #if CMK_MEMORY_BUILD_CACHE
255 #include "memory-cache.c"
256 #endif
257
258 #if CMK_MEMORY_BUILD_ISOMALLOC
259 #include "memory-isomalloc.c"
260 #endif
261
262 #if CMK_MEMORY_BUILD_LOCK
263 #include "memory-lock.c"
264 #endif
265
266 #if CMK_MEMORY_BUILD_CHARMDEBUG
267 #include "memory-charmdebug.c"
268 #endif
269
270 #if CMK_MEMORY_BUILD_GNU_HOOKS
271
272 static void
273 my_init_hook (void)
274 {
275   old_malloc_hook = __malloc_hook;
276   old_realloc_hook = __realloc_hook;
277   old_memalign_hook = __memalign_hook;
278   old_free_hook = __free_hook;
279   __malloc_hook = meta_malloc_hook;
280   __realloc_hook = meta_realloc_hook;
281   __memalign_hook = meta_memalign_hook;
282   __free_hook = meta_free_hook;
283 }
284 /* Override initializing hook from the C library. */
285 void (*__malloc_initialize_hook) (void) = my_init_hook;
286 #else
287 void *malloc(size_t size) { return meta_malloc(size); }
288 void free(void *ptr) { meta_free(ptr); }
289 void *calloc(size_t nelem, size_t size) { return meta_calloc(nelem,size); }
290 void cfree(void *ptr) { meta_cfree(ptr); }
291 void *realloc(void *ptr, size_t size) { return meta_realloc(ptr,size); }
292 void *memalign(size_t align, size_t size) { return meta_memalign(align,size); }
293 void *valloc(size_t size) { return meta_valloc(size); }
294 #endif
295
296 #endif
297
298 void CmiMemoryInit(argv)
299   char **argv;
300 {
301   CmiMemoryIs_flag |= CMI_MEMORY_IS_OS;
302 #if CMK_MEMORY_BUILD_OS_WRAPPED || CMK_MEMORY_BUILD_GNU_HOOKS
303   CmiArgGroup("Converse","Memory module");
304   meta_init(argv);
305 #endif
306   CmiOutOfMemoryInit();
307 }
308 void *malloc_reentrant(size_t size) { return malloc(size); }
309 void free_reentrant(void *mem) { free(mem); }
310
311 /******Start of a general way to get memory usage information*****/
312 /*CMK_TYPEDEF_UINT8 CmiMemoryUsage() { return 0; }*/
313
314 #if ! CMK_HAS_SBRK
315 int sbrk(int s) { return 0; }
316 #endif
317
318 #if CMK_HAS_MSTATS
319 #include <malloc/malloc.h>
320 #if CMK_C_INLINE
321 inline
322 #endif
323 static CMK_TYPEDEF_UINT8 MemusageMstats(){
324         struct mstats ms = mstats();
325         CMK_TYPEDEF_UINT8 memtotal = ms.bytes_used;
326         return memtotal;
327 }
328 #else
329 #if CMK_C_INLINE
330 inline
331 #endif
332 static CMK_TYPEDEF_UINT8 MemusageMstats() { return 0; }
333 #endif
334
335 static int MemusageInited = 0;
336 static CMK_TYPEDEF_UINT8 MemusageInitSbrkval = 0;
337 #if CMK_C_INLINE
338 inline
339 #endif
340 static CMK_TYPEDEF_UINT8 MemusageSbrk(){
341         CMK_TYPEDEF_UINT8 newval;
342         if(MemusageInited==0){
343                 MemusageInitSbrkval = (CMK_TYPEDEF_UINT8)sbrk(0);
344                 MemusageInited = 1;
345         }
346         newval = (CMK_TYPEDEF_UINT8)sbrk(0);
347         return (newval - MemusageInitSbrkval);
348 }
349
350 #if CMK_C_INLINE
351 inline
352 #endif
353 static CMK_TYPEDEF_UINT8 MemusageProcSelfStat(){
354     FILE *f;
355     int i, ret;
356     static int failed_once = 0;
357     CMK_TYPEDEF_UINT8 vsz = 0; /* should remain 0 on failure */
358
359     if(failed_once) return 0; /* no point in retrying */
360     
361     f = fopen("/proc/self/stat", "r");
362     if(!f) { failed_once = 1; return 0; }
363     for(i=0; i<22; i++) ret = fscanf(f, "%*s");
364     ret = fscanf(f, "%lu", &vsz);
365     fclose(f);
366     if(!vsz) failed_once=1;
367     return vsz;
368 }
369
370 #if ! CMK_HAS_MALLINFO || defined(CMK_MALLINFO_IS_BROKEN)
371 #if CMK_C_INLINE
372 inline
373 #endif
374 static CMK_TYPEDEF_UINT8 MemusageMallinfo(){ return 0;} 
375 #else
376 #if CMK_HAS_MALLOC_H
377 #include <malloc.h>
378 #endif
379 #if CMK_C_INLINE
380 inline
381 #endif
382 static CMK_TYPEDEF_UINT8 MemusageMallinfo(){
383     /* IA64 seems to ignore mi.uordblks, but updates mi.hblkhd correctly */
384     struct mallinfo mi = mallinfo();
385     CMK_TYPEDEF_UINT8 memtotal = (CMK_TYPEDEF_UINT8) mi.uordblks;   /* malloc */
386     CMK_TYPEDEF_UINT8 memtotal2 = (CMK_TYPEDEF_UINT8) mi.usmblks;   /* unused */
387     memtotal2 += (CMK_TYPEDEF_UINT8) mi.hblkhd;               /* mmap */
388     /* printf("%lld %lld %lld %lld %lld\n", mi.uordblks, mi.usmblks,mi.hblkhd,mi.arena,mi.keepcost); */
389 #if ! CMK_CRAYXT && ! CMK_CRAYXE
390     if(memtotal2 > memtotal) memtotal = memtotal2;
391 #endif
392     return memtotal;
393 }
394 #endif
395
396 #if CMK_C_INLINE
397 inline
398 #endif
399 static CMK_TYPEDEF_UINT8 MemusagePS(){
400 #if ! CMK_HAS_POPEN
401     return 0;
402 #else   
403     char pscmd[100];
404     CMK_TYPEDEF_UINT8 vsz=0;
405     FILE *p;
406     int ret;
407     sprintf(pscmd, "/bin/ps -o vsz= -p %d", getpid());
408     p = popen(pscmd, "r");
409     if(p){
410         ret = fscanf(p, "%ld", &vsz);
411         pclose(p);
412     }
413     return (vsz * (CMK_TYPEDEF_UINT8)1024);
414 #endif  
415 }
416
417 #if defined(_WIN32) && ! defined(__CYGWIN__)
418 #include <windows.h>
419 #include <psapi.h>
420
421 #if CMK_C_INLINE
422 inline
423 #endif
424 static CMK_TYPEDEF_UINT8 MemusageWindows(){
425     PROCESS_MEMORY_COUNTERS pmc;
426     if ( GetProcessMemoryInfo( GetCurrentProcess(), &pmc, sizeof(pmc)) )
427     {
428       /* return pmc.WorkingSetSize; */ 
429       return pmc.PagefileUsage;    /* total vm size, possibly not in memory */
430     }
431     return 0;
432 }
433 #else
434 static CMK_TYPEDEF_UINT8 MemusageWindows(){
435     return 0;
436 }
437 #endif
438
439 #if CMK_BLUEGENEP
440 /* Report the memory usage according to the following wiki page i
441 * https://wiki.alcf.anl.gov/index.php/Debugging#How_do_I_get_information_on_used.2Favailable_memory_in_my_code.3F
442 */
443 #include <malloc.h>
444 #if CMK_C_INLINE
445 inline
446 #endif
447 static CMK_TYPEDEF_UINT8 MemusageBGP(){
448     struct mallinfo m = mallinfo();
449     return m.hblkhd + m.uordblks;
450 }
451 #endif
452
453 CMK_TYPEDEF_UINT8 CmiMemoryUsage(){
454 #if CMK_BLUEGENEP
455     return MemusageBGP(); 
456 #else
457     CMK_TYPEDEF_UINT8 memtotal = 0;
458 #ifdef _WIN32
459     if(!memtotal) memtotal = MemusageWindows();
460 #endif
461     if(!memtotal) memtotal = MemusageMstats();
462     if(!memtotal) memtotal = MemusageMallinfo();
463     if(!memtotal) memtotal = MemusageProcSelfStat();
464     if(!memtotal) memtotal = MemusageSbrk();
465     if(!memtotal) memtotal = MemusagePS();
466     return memtotal;
467 #endif
468 }
469
470 /******End of a general way to get memory usage information*****/
471
472 CMK_TYPEDEF_UINT8 CmiMaxMemoryUsage() { return 0; }
473 void CmiResetMaxMemory() {}
474 CMK_TYPEDEF_UINT8 CmiMinMemoryUsage() { return 0; }
475 void CmiResetMinMemory() {}
476
477 #define MEM_LOCK_AROUND(code)   code
478
479 #else       /* of CMK_MEMORY_BUILD_OS */
480
481 /*************************************************************
482 *Not* using the system malloc-- first pick the implementation:
483 */
484
485 #if CMK_MEMORY_BUILD_GNU || CMK_MEMORY_BUILD_GNUOLD
486 #define meta_malloc   mm_malloc
487 #define meta_free     mm_free
488 #define meta_calloc   mm_calloc
489 #define meta_cfree    mm_cfree
490 #define meta_realloc  mm_realloc
491 #define meta_memalign mm_memalign
492 #define meta_valloc   mm_valloc
493
494 #if CMK_MEMORY_BUILD_GNU
495 #  include "memory-gnu.c"
496 static void meta_init(char **argv) {
497   CmiMemoryIs_flag |= CMI_MEMORY_IS_GNU;
498 }
499 #else
500 #  include "memory-gnuold.c"
501 static void meta_init(char **argv) {
502   CmiMemoryIs_flag |= CMI_MEMORY_IS_GNUOLD;
503 }
504 #endif
505
506 #endif /* CMK_MEMORY_BUILD_GNU or old*/
507
508 #define BEFORE_MALLOC_CALL   /*empty*/
509 #define AFTER_MALLOC_CALL    /*empty*/
510
511 #if CMK_MEMORY_BUILD_VERBOSE
512 #include "memory-verbose.c"
513 #endif
514
515 #if CMK_MEMORY_BUILD_PARANOID
516 #include "memory-paranoid.c"
517 #endif
518
519 #if CMK_MEMORY_BUILD_LEAK
520 #include "memory-leak.c"
521 #endif
522
523 #if CMK_MEMORY_BUILD_CACHE
524 #include "memory-cache.c"
525 #endif
526
527 #if CMK_MEMORY_BUILD_ISOMALLOC
528 #include "memory-isomalloc.c"
529 #endif
530
531 #if CMK_MEMORY_BUILD_CHARMDEBUG
532 #include "memory-charmdebug.c"
533 #endif
534
535 /*A trivial sample implementation of the meta_* calls:*/
536 #if 0
537 /* Use Gnumalloc as meta-meta malloc fallbacks (mm_*) */
538 #include "memory-gnu.c"
539 static void meta_init(char **argv)
540 {
541
542 }
543 static void *meta_malloc(size_t size)
544 {
545   return mm_malloc(size);
546 }
547 static void meta_free(void *mem)
548 {
549   mm_free(mem);
550 }
551 static void *meta_calloc(size_t nelem, size_t size)
552 {
553   return mm_calloc(nelem,size);
554 }
555 static void meta_cfree(void *mem)
556 {
557   mm_cfree(m);
558 }
559 static void *meta_realloc(void *mem, size_t size)
560 {
561   return mm_realloc(mem,size);
562 }
563 static void *meta_memalign(size_t align, size_t size)
564 {
565   return mm_memalign(align,size);
566 }
567 static void *meta_valloc(size_t size)
568 {
569   return mm_valloc(size);
570 }
571 #endif
572
573
574 /*******************************************************************
575 The locking code is common to all implementations except OS-builtin.
576 */
577
578 void CmiMemoryInit(char **argv)
579 {
580   CmiArgGroup("Converse","Memory module");
581   meta_init(argv);
582   CmiOutOfMemoryInit();
583 }
584
585 /* Wrap a CmiMemLock around this code */
586 #define MEM_LOCK_AROUND(code) \
587   CmiMemLock(); \
588   code; \
589   CmiMemUnlock();
590
591 /* Wrap a reentrant CmiMemLock around this code */
592 #define REENTRANT_MEM_LOCK_AROUND(code) \
593   int myRank=CmiMyRank(); \
594   if (myRank!=rank_holding_CmiMemLock) { \
595         CmiMemLock(); \
596         rank_holding_CmiMemLock=myRank; \
597         code; \
598         rank_holding_CmiMemLock=-1; \
599         CmiMemUnlock(); \
600   } \
601   else /* I'm already holding the memLock (reentrancy) */ { \
602         code; \
603   }
604
605 void *malloc(size_t size)
606 {
607   void *result;
608   MEM_LOCK_AROUND( result = meta_malloc(size); )
609   if (result==NULL) CmiOutOfMemory(size);
610   return result;
611 }
612
613 void free(void *mem)
614 {
615   MEM_LOCK_AROUND( meta_free(mem); )
616 }
617
618 void *calloc(size_t nelem, size_t size)
619 {
620   void *result;
621   MEM_LOCK_AROUND( result = meta_calloc(nelem, size); )
622   if (result==NULL) CmiOutOfMemory(size);
623   return result;
624 }
625
626 void cfree(void *mem)
627 {
628   MEM_LOCK_AROUND( meta_cfree(mem); )
629 }
630
631 void *realloc(void *mem, size_t size)
632 {
633   void *result;
634   MEM_LOCK_AROUND( result = meta_realloc(mem, size); )
635   return result;
636 }
637
638 void *memalign(size_t align, size_t size)
639 {
640   void *result;
641   MEM_LOCK_AROUND( result = meta_memalign(align, size); )
642   if (result==NULL) CmiOutOfMemory(align*size);
643   return result;
644 }
645
646 void *valloc(size_t size)
647 {
648   void *result;
649   MEM_LOCK_AROUND( result = meta_valloc(size); )
650   if (result==NULL) CmiOutOfMemory(size);
651   return result;
652 }
653
654 /*These are special "reentrant" versions of malloc,
655 for use from code that may be called from within malloc.
656 The only difference is that these versions check a global
657 flag to see if they already hold the memory lock before
658 actually trying the lock, which prevents a deadlock where
659 you try to aquire one of your own locks.
660 */
661
662 void *malloc_reentrant(size_t size) {
663   void *result;
664   REENTRANT_MEM_LOCK_AROUND( result = meta_malloc(size); )
665   return result;
666 }
667
668 void free_reentrant(void *mem)
669 {
670   REENTRANT_MEM_LOCK_AROUND( meta_free(mem); )
671 }
672
673 /** Return number of bytes currently allocated, if possible. */
674 CMK_TYPEDEF_UINT8 CmiMemoryUsage()
675 {
676   return _memory_allocated;
677 }
678
679 /** Return number of maximum number of bytes allocated since the last call to CmiResetMaxMemory(), if possible. */
680 CMK_TYPEDEF_UINT8 CmiMaxMemoryUsage()
681 {
682   return _memory_allocated_max;
683 }
684
685 /** Reset the mechanism that records the highest seen (high watermark) memory usage. */
686 void CmiResetMaxMemory() {
687   _memory_allocated_max=_memory_allocated;
688 }
689
690 CMK_TYPEDEF_UINT8 CmiMinMemoryUsage()
691 {
692   return _memory_allocated_min;
693 }
694
695 void CmiResetMinMemory() {
696   _memory_allocated_min=_memory_allocated;
697 }
698
699 #endif /* ! CMK_MEMORY_BUILD_BUILTIN*/
700
701 #ifndef CMK_MEMORY_HAS_NOMIGRATE
702 /*Default implementations of the nomigrate routines:*/
703 void *malloc_nomigrate(size_t size) { return malloc(size); }
704 void free_nomigrate(void *mem) { free(mem); }
705 #endif
706
707 #ifndef CMK_MEMORY_HAS_ISOMALLOC
708 #include "memory-isomalloc.h"
709 /*Not using isomalloc heaps, so forget about activating block list:*/
710 CmiIsomallocBlockList *CmiIsomallocBlockListActivate(CmiIsomallocBlockList *l)
711    {return l;}
712 CmiIsomallocBlockList *CmiIsomallocBlockListCurrent(){
713         return NULL;
714 }
715 void CmiEnableIsomalloc() {}
716 void CmiDisableIsomalloc() {}
717 #endif
718
719 #ifndef CMI_MEMORY_ROUTINES
720 void CmiMemoryMark(void) {}
721 void CmiMemoryMarkBlock(void *blk) {}
722 void CmiMemorySweep(const char *where) {}
723 void CmiMemoryCheck(void) {}
724 #endif
725
726 void memory_preallocate_hack()
727 {
728 #if CMK_MEMORY_PREALLOCATE_HACK
729   /* Work around problems with brk() on some systems (e.g., Blue Gene/L)
730      by grabbing a bunch of memory from the OS (which calls brk()),
731      then releasing the memory back to malloc(), except for one block
732      at the end, which is used to prevent malloc from moving brk() back down.
733   */
734 #define MEMORY_PREALLOCATE_MAX 4096
735   void *ptrs[MEMORY_PREALLOCATE_MAX];
736   int i,len=0;
737   for (i=0;i<MEMORY_PREALLOCATE_MAX;i++) {
738     ptrs[i] = mm_malloc(1024*1024);
739     if (ptrs[i]==NULL) break;
740     else len=i+1; /* this allocation worked */
741   }
742   /* we now own all the memory-- release all but the last meg. */
743   /* printf("CMK_MEMORY_PREALLOCATE_HACK claimed %d megs\n",len); */
744   for (i=len-2;i>=0;i--) {
745     mm_free(ptrs[i]);
746   }
747 #endif
748 }
749
750 void CmiOutOfMemoryInit(void) {
751   if (CmiMyRank() == 0) {
752 #if CMK_MEMORY_PREALLOCATE_HACK
753   memory_preallocate_hack();
754 #endif
755   MEM_LOCK_AROUND( memory_lifeRaft=(char *)mm_malloc(65536/2); )
756   }
757 }
758
759 #ifndef CMK_MEMORY_BUILD_CHARMDEBUG
760 /* declare the cpd_memory routines */
761 void CpdSetInitializeMemory(int v) { }
762 size_t  cpd_memory_length(void *lenParam) { return 0; }
763 void cpd_memory_pup(void *itemParam,pup_er p,CpdListItemsRequest *req) { }
764 void cpd_memory_leak(void *itemParam,pup_er p,CpdListItemsRequest *req) { }
765 void check_memory_leaks(LeakSearchInfo* i) { }
766 size_t  cpd_memory_getLength(void *lenParam) { return 0; }
767 void cpd_memory_get(void *itemParam,pup_er p,CpdListItemsRequest *req) { }
768 void CpdMemoryMarkClean(char *msg) { }
769 /* routine used by CthMemory{Protect,Unprotect} to specify that some region of
770    memory has been protected */
771 void setProtection(char *mem, char *ptr, int len, int flag) { }
772 /* Routines used to specify how the memory will the used */
773 #ifdef setMemoryTypeChare
774 #undef setMemoryTypeChare
775 #endif
776 void setMemoryTypeChare(void *ptr) { }
777 #ifdef setMemoryTypeMessage
778 #undef setMemoryTypeMessage
779 #endif
780 void setMemoryTypeMessage(void *ptr) { }
781 void CpdSystemEnter() { }
782 void CpdSystemExit() { }
783
784 void CpdResetMemory() { }
785 void CpdCheckMemory() { }
786
787 int get_memory_allocated_user_total() { return 0; }
788 void * MemoryToSlot(void *ptr) { return NULL; }
789 int Slot_ChareOwner(void *s) { return 0; }
790 int Slot_AllocatedSize(void *s) { return 0; }
791 int Slot_StackTrace(void *s, void ***stack) { return 0; }
792 #ifdef setMemoryChareIDFromPtr
793 #undef setMemoryChareIDFromPtr
794 #endif
795 int setMemoryChareIDFromPtr(void *ptr) { return 0; }
796 #ifdef setMemoryChareID
797 #undef setMemoryChareID
798 #endif
799 void setMemoryChareID(int id) { }
800 #ifdef setMemoryOwnedBy
801 #undef setMemoryOwnedBy
802 #endif
803 void setMemoryOwnedBy(void *ptr, int id) { }
804
805 #endif
806
807
808 /* Genearl functions for malloc'ing aligned buffers */
809
810 /* CmiMallocAligned: Allocates a memory buffer with the given byte alignment.
811      Additionally, the length of the returned buffer is also a multiple of
812      alignment and >= size.
813    NOTE: Memory allocated with CmiMallocAligned MUST be free'd with CmiFreeAligned()
814 */
815 void* CmiMallocAligned(const size_t size, const unsigned int alignment) {
816
817   void* rtn = NULL;
818   int tailPadding;
819   unsigned short offset = 0;
820
821   /* Verify the pararmeters */
822   if (size <= 0 || alignment <= 0) return NULL;
823
824   /* Malloc memory of size equal to size + alignment + (alignment - (size % alignment)).  The
825    *   last term 'alignment - (size % alignment)' ensures that there is enough tail padding
826    *   so a DMA can be performed based on the alignment.  (I.e. - Start and end the memory
827    *   region retured on an alignment boundry specified.)
828    * NOTE: Since we need a byte long header, even if we "get lucky" and the malloc
829    *   returns a pointer with the given alignment, we need to put in a byte
830    *   preamble anyway.
831    */
832   tailPadding = alignment - (size % alignment);
833   if (tailPadding == alignment)
834     tailPadding = 0;
835
836   /* Allocate the memory */
837   rtn = malloc(size + alignment + tailPadding);
838
839   /* Calculate the offset into the returned memory chunk that has the required alignment */
840   offset = (char)(((size_t)rtn) % alignment);
841   offset = alignment - offset;
842   if (offset == 0) offset = alignment;
843
844   /* Write the offset into the byte before the address to be returned */
845   *((char*)rtn + offset - 1) = offset;
846
847   /* Return the address with offset */
848   return (void*)((char*)rtn + offset);
849 }
850
851 void CmiFreeAligned(void* ptr) {
852
853   char offset;
854
855   /* Verify the parameter */
856   if (ptr == NULL) return;
857
858   /* Read the offset (byte before ptr) */
859   offset = *((char*)ptr - 1);
860
861   /* Free the memory */
862   free ((void*)((char*)ptr - offset));
863 }
864
865
866
867 /** @} */