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