Cyclops Tensor Framework
parallel arithmetic on multidimensional arrays
memcontrol.cxx
Go to the documentation of this file.
1 /*Copyright (c) 2011, Edgar Solomonik, all rights reserved.*/
2 
3 #ifdef __MACH__
4 #include "sys/malloc.h"
5 #include "sys/types.h"
6 #include "sys/sysctl.h"
7 #else
8 #include "malloc.h"
9 #include "sys/resource.h"
10 #endif
11 #include <stdint.h>
12 #include <iostream>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <list>
16 #include <algorithm>
17 #ifdef BGP
18 #include <spi/kernel_interface.h>
19 #include <common/bgp_personality.h>
20 #include <common/bgp_personality_inlines.h>
21 #endif
22 #ifdef BGQ
23 #include <spi/include/kernel/memory.h>
24 #endif
25 
26 
27 #include "../interface/common.h"
28 #include "util.h"
29 #ifdef USE_OMP
30 #include "omp.h"
31 #endif
32 #include "memcontrol.h"
33 #include <iostream>
34 #include <fstream>
35 using namespace std;
36 //#include "../dist_tensor/cyclopstf.hpp"
37 
38 //struct mallinfo mallinfo(void);
39 namespace CTF_int {
40 
41 // Thanks, http://stackoverflow.com/questions/1558402/memory-usage-of-current-process-in-c
42 /*typedef struct {
43  unsigned long size,resident,share,text,lib,data,dt;
44 } statm_t;
45 
46 void read_off_memory_status(statm_t& result)
47 {
48  unsigned long dummy;
49  const char* statm_path = "/proc/self/statm";
50 
51  FILE *f = fopen(statm_path,"r");
52  if(!f){
53  perror(statm_path);
54  abort();
55  }
56  if(7 != fscanf(f,"%ld %ld %ld %ld %ld %ld %ld",
57  &result.size,&result.resident,&result.share,&result.text,&result.lib,&result.data,&result.dt))
58  {
59  perror(statm_path);
60  abort();
61  }
62  fclose(f);
63 }*/
64 
65  struct mem_loc {
66  void * ptr;
67  int64_t len;
68  };
69 
70  /* fraction of total memory which can be saturated */
71  double memcap = 0.5;
72  int64_t mem_size = 0;
73  #define MAX_THREADS 256
77  int64_t tot_mem_used;
78  int64_t tot_mem_available = -1;
79 
80  void inc_tot_mem_used(int64_t a){
81  tot_mem_used += a;
82  ASSERT(tot_mem_used >= 0);
83  //int rank;
84  // MPI_Comm_rank(MPI_COMM_WORLD, &rank);
85 // if (rank == 0)
86  //printf("INCREMENTING MEMUSAGE BY %ld to %ld\n",a,tot_mem_used);
87  // printf("CTF used memory = %1.5E, Total used memory = %1.5E, available memory via malloc_info is = %1.5E\n", (double)tot_mem_used, (double)proc_bytes_used(), (double)proc_bytes_available());
88  }
89  #ifndef PRODUCTION
90  std::list<mem_loc> mem_stacks[MAX_THREADS];
91  #endif
92 
93  //application memory stack
94  void * mst_buffer = 0;
95  //size of memory stack
96  int64_t mst_buffer_size = 0;
97  //amount of data stored on stack
98  int64_t mst_buffer_used = 0;
99  //the current offset of the top of the stack
100  int64_t mst_buffer_ptr = 0;
101  //stack of memory locations
102  std::list<mem_loc> mst;
103  //copy buffer for contraction of stack with low memory usage
104  #define CPY_BUFFER_SIZE 1000
106 
110  void set_mem_size(int64_t size){
111  mem_size = size;
112  }
113 
118  void set_memcap(double cap){
119  memcap = cap;
120  }
121 
125  std::list<mem_transfer> contract_mst(){
126  std::list<mem_transfer> transfers;
127  int64_t i;
128  if (mst_buffer_ptr > .80*mst_buffer_size &&
129  mst_buffer_used < .40*mst_buffer_size){
131  std::list<mem_loc> old_mst = mst;
132  mst_buffer_ptr = 0;
133  mst_buffer_used = 0;
134 
135  mst.clear();
136 
137  std::list<mem_loc>::iterator it;
138  for (it=old_mst.begin(); it!=old_mst.end(); it++){
139  mem_transfer t;
140  t.old_ptr = it->ptr;
141  t.new_ptr = mst_alloc(it->len);
142  if (t.old_ptr != t.new_ptr){
143  if ((int64_t)((char*)t.old_ptr - (char*)t.new_ptr) < it->len){
144  for (i=0; i<it->len; i+=CPY_BUFFER_SIZE){
145  memcpy(cpy_buffer, (char*)t.old_ptr+i, MIN(it->len-i, CPY_BUFFER_SIZE));
146  memcpy((char*)t.new_ptr+i, cpy_buffer, MIN(it->len-i, CPY_BUFFER_SIZE));
147  }
148  } else
149  memcpy(t.new_ptr, t.old_ptr, it->len);
150  } else
151  transfers.push_back(t);
152  }
153  printf("Contracted MST\n");
154  // from size " PRId64 " to size " PRId64 "\n",
155  //DPRINTF(1,"Contracted MST from size " PRId64 " to size " PRId64 "\n",
156  // old_mst_buffer_ptr, mst_buffer_ptr);
157  old_mst.clear();
159  }
160  return transfers;
161  }
162 
163  std::list<mem_loc> * get_mst(){
164  return &mst;
165  }
166 
170  void mst_create(int64_t size){
171  int pm;
172  void * new_mst_buffer;
173  if (size > mst_buffer_size){
174  pm = posix_memalign((void**)&new_mst_buffer, ALIGN_BYTES, size);
175  ASSERT(pm == 0);
176  if (mst_buffer != NULL){
177  memcpy(new_mst_buffer, mst_buffer, mst_buffer_ptr);
178  }
179  mst_buffer = new_mst_buffer;
180  mst_buffer_size = size;
181  }
182  }
183 
187  void mem_create(){
188  instance_counter++;
189  if (instance_counter == 1){
190  #ifdef USE_OMP
191  max_threads = omp_get_max_threads();
192  #else
193  max_threads = 1;
194  #endif
195  int i;
196  for (i=0; i<max_threads; i++){
197  mem_used[i] = 0;
198  }
199  tot_mem_used = 0;
200  }
201  }
202 
207  void mem_exit(int rank){
208  instance_counter--;
209  //assert(instance_counter >= 0);
210  #ifndef PRODUCTION
211  if (instance_counter == 0){
212  for (int i=0; i<max_threads; i++){
213  if (mem_used[i] > 0){
214  if (rank == 0){
215  printf("Warning: memory leak in CTF on thread %d, %ld bytes of memory in use at termination",
216  i, mem_used[i]);
217  printf(" in %zu unfreed items\n",
218  mem_stacks[i].size());
219  }
220  }
221  if (mst.size() > 0){
222  printf("Warning: %zu items not deallocated from custom stack, consuming %ld bytes of memory\n",
223  mst.size(), mst_buffer_ptr);
224  }
225  }
226  }
227  #endif
228  }
229 
234  int mst_free(void * ptr){
235  ASSERT((int64_t)((char*)ptr-(char*)mst_buffer)<mst_buffer_size);
236 
237  std::list<mem_loc>::iterator it;
238  for (it=--mst.end(); it!=mst.begin(); it--){
239  if (it->ptr == ptr){
240  mst_buffer_used = mst_buffer_used - it->len;
241  mst.erase(it);
242  break;
243  }
244  }
245  if (it == mst.begin()){
246  if (it->ptr == ptr){
247  mst_buffer_used = mst_buffer_used - it->len;
248  mst.erase(it);
249  } else {
250  printf("CTF CTF_int::ERROR: Invalid mst free of pointer %p\n", ptr);
251  // free(ptr);
252  ABORT;
253  return CTF_int::ERROR;
254  }
255  }
256  if (mst.size() > 0)
257  mst_buffer_ptr = (int64_t)((char*)mst.back().ptr - (char*)mst_buffer)+mst.back().len;
258  else
259  mst_buffer_ptr = 0;
260  //printf("freed block, mst_buffer_ptr = " PRId64 "\n", mst_buffer_ptr);
261  return CTF_int::SUCCESS;
262  }
263 
269  int mst_alloc_ptr(int64_t const len, void ** const ptr){
270  int pm = posix_memalign(ptr, ALIGN_BYTES, len);
271  ASSERT(pm==0);
272 #if 0
273  if (mst_buffer_size == 0)
274  return alloc_ptr(len, ptr);
275  else {
276  int64_t plen, off;
277  off = len % MST_ALIGN_BYTES;
278  if (off > 0)
279  plen = len + MST_ALIGN_BYTES - off;
280  else
281  plen = len;
282 
283  mem_loc m;
284  //printf("ptr = " PRId64 " plen = %d, size = " PRId64 "\n", mst_buffer_ptr, plen, mst_buffer_size);
285  if (mst_buffer_ptr + plen < mst_buffer_size){
286  *ptr = (void*)((char*)mst_buffer+mst_buffer_ptr);
287  m.ptr = *ptr;
288  m.len = plen;
289  mst.push_back(m);
290  mst_buffer_ptr = mst_buffer_ptr+plen;
291  mst_buffer_used += plen;
292  } else {
293  DPRINTF(2,"Exceeded mst buffer size (" PRId64 "), current ptr is " PRId64 ", composed of %d items of size " PRId64 "\n",
294  mst_buffer_size, mst_buffer_ptr, (int)mst.size(), mst_buffer_used);
295  alloc_ptr(len, ptr);
296  }
297  return CTF_int::SUCCESS;
298  }
299 #endif
300  return CTF_int::SUCCESS;
301  }
302 
307  void * mst_alloc(int64_t const len){
308  void * ptr;
309  int ret = mst_alloc_ptr(len, &ptr);
310  ASSERT(ret == CTF_int::SUCCESS);
311  return ptr;
312  }
313 
314 
320  int alloc_ptr(int64_t const len_, void ** const ptr){
321  int64_t len = MAX(4,len_);
322 /*#if DEBUG >= 2
323  if (len_ >= 1E8){
324  int rank;
325  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
326  if (rank == 0)
327  printf("allocating block of size %ld bytes, padding %ld bytes\n", len, (int64_t)ALIGN_BYTES);
328  }
329 #endif*/
330  int pm = posix_memalign(ptr, (int64_t)ALIGN_BYTES, len);
331  ASSERT(pm==0);
332 #if 0
333  #ifndef PRODUCTION
334  int tid;
335  #ifdef USE_OMP
336  if (max_threads == 1) tid = 0;
337  else tid = omp_get_thread_num();
338  #else
339  tid = 0;
340  #endif
341  mem_loc m;
342  mem_used[tid] += len;
343  std::list<mem_loc> * mem_stack;
344  mem_stack = &mem_stacks[tid];
345  m.ptr = *ptr;
346  m.len = len;
347  mem_stack->push_back(m);
348  // printf("mem_used up to " PRId64 " stack to %d\n",mem_used,mem_stack->size());
349  // printf("pushed pointer %p to stack %d\n", *ptr, tid);
350  #endif
351  if (pm){
352  printf("CTF CTF_int::ERROR: posix memalign returned an error, " PRId64 " memory alloced on this process, wanted to alloc " PRId64 " more\n",
353  mem_used[0], len);
354  }
355  ASSERT(pm == 0);
356 #endif
357  return CTF_int::SUCCESS;
358 
359  }
360 
365  void * alloc(int64_t const len){
366  void * ptr;
367  int ret = alloc_ptr(len, &ptr);
368  ASSERT(ret == CTF_int::SUCCESS);
369  return ptr;
370  }
371 
376  int untag_mem(void * ptr){
377  #if 0 //ndef PRODUCTION
378  int64_t len;
379  int found;
380  std::list<mem_loc> * mem_stack;
381 
382  mem_stack = &mem_stacks[0];
383 
384  std::list<mem_loc>::reverse_iterator it;
385  found = 0;
386  for (it=mem_stack->rbegin(); it!=mem_stack->rend(); it++){
387  if ((*it).ptr == ptr){
388  len = (*it).len;
389  mem_stack->erase((++it).base());
390  found = 1;
391  break;
392  }
393  }
394  if (!found){
395  printf("CTF CTF_int::ERROR: failed memory untag\n");
396  ABORT;
397  return CTF_int::ERROR;
398  }
399  mem_used[0] -= len;
400  #endif
401  return CTF_int::SUCCESS;
402  }
403 
404 
410  int cdealloc(void * ptr, int const tid){
411  free(ptr);
412 #if 0
413  if ((int64_t)((char*)ptr-(char*)mst_buffer) < mst_buffer_size &&
414  (int64_t)((char*)ptr-(char*)mst_buffer) >= 0){
415  return mst_free(ptr);
416  }
417  #ifndef PRODUCTION
418  int len, found;
419  std::list<mem_loc> * mem_stack;
420 
421  mem_stack = &mem_stacks[tid];
422 
423  std::list<mem_loc>::reverse_iterator it;
424  found = 0;
425  for (it=mem_stack->rbegin(); it!=mem_stack->rend(); it++){
426  if ((*it).ptr == ptr){
427  len = (*it).len;
428  mem_stack->erase((++it).base());
429  found = 1;
430  break;
431  }
432  }
433  if (!found){
434  return CTF_int::NEGATIVE;
435  }
436  mem_used[tid] -= len;
437  #endif
438  //printf("mem_used down to " PRId64 " stack to %d\n",mem_used,mem_stack->size());
439  free(ptr);
440 #endif
441  return CTF_int::SUCCESS;
442  }
443 
448  int cdealloc_cond(void * ptr){
449  //#ifdef PRODUCTION
450  return CTF_int::SUCCESS; //FIXME This function is not to be trusted due to potential allocations of 0 bytes!!!@
451  //#endif
452  int ret, tid, i;
453  #ifdef USE_OMP
454  if (max_threads == 1) tid = 0;
455  else tid = omp_get_thread_num();
456  #else
457  tid = 0;
458  #endif
459 
460  ret = cdealloc(ptr, tid);
461  if (ret == CTF_int::NEGATIVE){
462  if (tid == 0){
463  for (i=1; i<max_threads; i++){
464  ret = cdealloc(ptr, i);
465  if (ret == CTF_int::SUCCESS){
466  return CTF_int::SUCCESS;
467  break;
468  }
469  }
470  }
471  }
472  // if (ret == CTF_int::NEGATIVE) free(ptr);
473  return CTF_int::SUCCESS;
474  }
475 
480  int cdealloc(void * ptr){
481  free(ptr);
482  return CTF_int::SUCCESS;
483  }
484 #if 0
485  int cdealloc(void * ptr){
486  if ((int64_t)((char*)ptr-(char*)mst_buffer) < mst_buffer_size &&
487  (int64_t)((char*)ptr-(char*)mst_buffer) >= 0){
488  return mst_free(ptr);
489  }
490  #ifdef PRODUCTION
491  free(ptr);
492  return CTF_int::SUCCESS;
493  #else
494  int ret, tid, i;
495  #ifdef USE_OMP
496  if (max_threads == 1) tid = 0;
497  else tid = omp_get_thread_num();
498  #else
499  tid = 0;
500  #endif
501 
502 
503  ret = cdealloc(ptr, tid);
504  if (ret == CTF_int::NEGATIVE){
505  if (tid != 0 || max_threads == 1){
506  printf("CTF CTF_int::ERROR: Invalid free of pointer %p by thread %d\n", ptr, tid);
507  ABORT;
508  return CTF_int::ERROR;
509  } else {
510  for (i=1; i<max_threads; i++){
511  ret = cdealloc(ptr, i);
512  if (ret == CTF_int::SUCCESS){
513  return CTF_int::SUCCESS;
514  break;
515  }
516  }
517  if (i==max_threads){
518  printf("CTF CTF_int::ERROR: Invalid free of pointer %p by zeroth thread\n", ptr);
519  ABORT;
520  return CTF_int::ERROR;
521  }
522  }
523  }
524  #endif
525  return CTF_int::SUCCESS;
526 
527  }
528 #endif
529 
530 
532  return instance_counter;
533  }
534 
538  int64_t proc_bytes_used(){
539  /*statm_t smt;
540  read_off_memory_status(smt);
541  printf("CTF %ld\n", tot_mem_used);
542  printf("%lu %lu %lu %lu %lu %lu %lu\n", smt.size, smt.resident, smt.share, smt.text, smt.lib, smt.data, smt.dt);
543  rusage ru;
544  getrusage(RUSAGE_SELF, &ru);
545  return ru.ru_maxrss;*/
546  /*size_t size = 10000;
547  char ombuf[size];
548 
549  ombuf[0] = 'a';
550  ombuf[1] = 'b';
551  ombuf[2] = 'c';
552  ombuf[3] = '\0';
553 
554  FILE * f = fmemopen(ombuf, size, "w");
555  malloc_info(0,f);
556  fclose(f);
557  f = fmemopen(ombuf, size, "r");
558  char * buffer;
559  long length;
560  fseek (f, 0, SEEK_END);
561  length = ftell(f);
562  fseek (f, 0, SEEK_SET);
563  buffer = (char*)malloc(length+1);
564  if (buffer){
565  fread(buffer, 1, length, f);
566  }
567  buffer[length] = '\0';
568  fclose (f);
569  stringstream strs(buffer);
570  string sbuf = strs.str();
571  size_t s_st, s_end;
572  //printf("str = %s\n",sbuf.c_str());
573  s_st = sbuf.rfind("total");
574  assert(s_st != -1);
575  s_end = s_st;
576  while (sbuf[s_end] != '"'){ s_end++; ASSERT(s_end-s_st<20); }
577  s_end++;
578  while (sbuf[s_end] != '"'){ s_end++; ASSERT(s_end-s_st<20); }
579  s_end++;
580  s_st = s_end;
581  while (sbuf[s_end] != '"'){ s_end++; ASSERT(s_end-s_st<20); }
582  sbuf[s_end]='\0';
583  long long bused = atoll(&sbuf[s_st]);
584  ASSERT(bused >= 0);
585  //printf("bused = %ld s_st = %ld, s_end = %ld, size = %ld\n", (long)bused, (long)s_st, (long)s_end, (long)size);
586  return (int64_t)bused;
587  */
588 /* struct mallinfo info;
589  info = mallinfo();
590  return (int64_t)(info.usmblks + info.uordblks + info.hblkhd);*/
591  /*int64_t ms = 0;
592  int i;
593  for (i=0; i<max_threads; i++){
594  ms += mem_used[i];
595  }
596  return ms + mst_buffer_used;// + (int64_t)mst_buffer_size;*/
597  return tot_mem_used;
598  }
599 
600  /* FIXME: only correct for 1 process per node */
604  int64_t proc_bytes_total() {
605 #ifdef BGQ
606  uint64_t total;
607  int node_config;
608 
609  Kernel_GetMemorySize(KERNEL_MEMSIZE_HEAP, &total);
610  if (mem_size > 0){
611  return MIN(total,uint64_t(mem_size));
612  } else {
613  return total;
614  }
615 #else
616  #ifdef BGP
617  int64_t total;
618  int node_config;
619  _BGP_Personality_t personality;
620 
621  Kernel_GetPersonality(&personality, sizeof(personality));
622  total = (int64_t)BGP_Personality_DDRSizeMB(&personality);
623 
624  node_config = BGP_Personality_processConfig(&personality);
625  if (node_config == _BGP_PERS_PROCESSCONFIG_VNM) total /= 4;
626  else if (node_config == _BGP_PERS_PROCESSCONFIG_2x2) total /= 2;
627  total *= 1024*1024;
628 
629  return total;
630  #else
631  if (tot_mem_available == -1){
632  #ifdef __MACH__
633  int mib[] = {CTL_HW,HW_MEMSIZE};
634  int64_t mem;
635  size_t len = 8;
636  sysctl(mib, 2, &mem, &len, NULL, 0);
637  tot_mem_available = mem;
638  #else
639  int64_t pages = (int64_t)sysconf(_SC_PHYS_PAGES);
640  int64_t page_size = (int64_t)sysconf(_SC_PAGE_SIZE);
641  if (mem_size != 0)
642  tot_mem_available = MIN((int64_t)(pages * page_size), (int64_t)mem_size);
643  else
644  tot_mem_available = pages * page_size;
645  #endif
646  }
647  return tot_mem_available;
648  #endif
649 #endif
650  }
651 
656 #ifdef BGQ
657  uint64_t mem_avail;
658  Kernel_GetMemorySize(KERNEL_MEMSIZE_HEAPAVAIL, &mem_avail);
659 // mem_avail = std::min(mem_avail*memcap,proc_bytes_total()*memcap-tot_mem_use);
660  mem_avail*= memcap;
661  //mem_avail += mst_buffer_size-mst_buffer_used;
662  /* printf("HEAPAVIL = %llu, TOTAL HEAP - mallinfo used = %llu\n",
663  mem_avail, proc_bytes_total() - proc_bytes_used());*/
664 
665  return mem_avail;
666 #else
667  int64_t pused = proc_bytes_used();
668  int64_t ptotal = proc_bytes_total();
669  if (pused > memcap*ptotal){ printf("CTF ERROR: less than %lf percent of local memory remaining, ensuing segfault likely.\n", (100.*(1.-memcap))); }
670  return memcap*ptotal-pused;
671 #endif
672  }
673 }
674 
675 
676 
void inc_tot_mem_used(int64_t a)
Definition: memcontrol.cxx:80
int64_t mem_size
Definition: memcontrol.cxx:72
double memcap
Definition: memcontrol.cxx:71
int64_t tot_mem_available
Definition: memcontrol.cxx:78
#define DPRINTF(...)
Definition: util.h:235
std::list< mem_transfer > contract_mst()
gets rid of empty space on the stack
Definition: memcontrol.cxx:125
int64_t mst_buffer_used
Definition: memcontrol.cxx:98
def rank(self)
Definition: core.pyx:312
void mst_create(int64_t size)
initializes stack buffer
Definition: memcontrol.cxx:170
int mst_free(void *ptr)
frees buffer allocated on stack
Definition: memcontrol.cxx:234
void * mst_alloc(int64_t len)
mst_alloc allocates buffer on the specialized memory stack
Definition: memcontrol.cxx:307
#define ASSERT(...)
Definition: util.h:88
int64_t mst_buffer_ptr
Definition: memcontrol.cxx:100
void * alloc(int64_t len)
alloc abstraction
Definition: memcontrol.cxx:365
char * cpy_buffer[CPY_BUFFER_SIZE]
Definition: memcontrol.cxx:105
int64_t tot_mem_used
Definition: memcontrol.cxx:77
void mem_exit(int rank)
exit instance of memory manager
Definition: memcontrol.cxx:207
void * mst_buffer
Definition: memcontrol.cxx:94
int untag_mem(void *ptr)
stops tracking memory allocated by CTF, so user doesn&#39;t have to call free
Definition: memcontrol.cxx:376
#define MAX(a, b)
Definition: util.h:180
int cdealloc(void *ptr, int const tid)
free abstraction
Definition: memcontrol.cxx:410
int mst_alloc_ptr(int64_t len, void **const ptr)
mst_alloc abstraction
Definition: memcontrol.cxx:269
int64_t mst_buffer_size
Definition: memcontrol.cxx:96
int instance_counter
Definition: memcontrol.cxx:75
int alloc_ptr(int64_t len, void **const ptr)
alloc abstraction
Definition: memcontrol.cxx:320
int max_threads
Definition: memcontrol.cxx:74
#define ALIGN_BYTES
Definition: util.h:172
std::list< mem_loc > mst
Definition: memcontrol.cxx:102
#define TAU_FSTOP(ARG)
Definition: util.h:281
#define TAU_FSTART(ARG)
Definition: util.h:280
#define MST_ALIGN_BYTES
Definition: util.h:284
int64_t proc_bytes_used()
gives total memory used on this MPI process
Definition: memcontrol.cxx:538
#define MAX_THREADS
Definition: memcontrol.cxx:73
void set_memcap(double cap)
sets what fraction of the memory capacity CTF can use
Definition: memcontrol.cxx:118
void mem_create()
create instance of memory manager
Definition: memcontrol.cxx:187
int64_t proc_bytes_available()
gives total memory available on this MPI process
Definition: memcontrol.cxx:655
int64_t proc_bytes_total()
gives total memory size per MPI process
Definition: memcontrol.cxx:604
#define CPY_BUFFER_SIZE
Definition: memcontrol.cxx:104
#define MIN(a, b)
Definition: util.h:176
int64_t mem_used[MAX_THREADS]
Definition: memcontrol.cxx:76
std::list< mem_loc > * get_mst()
Definition: memcontrol.cxx:163
void set_mem_size(int64_t size)
sets what fraction of the memory capacity CTF can use
Definition: memcontrol.cxx:110
#define ABORT
Definition: util.h:162
int get_num_instances()
Definition: memcontrol.cxx:531
std::list< mem_loc > mem_stacks[MAX_THREADS]
Definition: memcontrol.cxx:90
int cdealloc_cond(void *ptr)
free abstraction (conditional (no error if not found))
Definition: memcontrol.cxx:448