mem_mgr.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /**
  2. * \file mem_mgr.cpp
  3. * \author Dhairya Malhotra, dhairya.malhotra@gmail.com
  4. * \date 9-21-2014
  5. * \brief This file contains the definition of a simple memory manager which
  6. * uses a pre-allocated buffer of size defined in call to the constructor.
  7. */
  8. #include <mem_mgr.hpp>
  9. #include <omp.h>
  10. #include <iostream>
  11. #include <cassert>
  12. namespace pvfmm{
  13. namespace mem{
  14. #define PVFMMDefinePOD(type) template<> bool TypeTraits<type>::IsPOD(){return true;};
  15. PVFMMDefinePOD(char);
  16. PVFMMDefinePOD(float);
  17. PVFMMDefinePOD(double);
  18. PVFMMDefinePOD(int);
  19. PVFMMDefinePOD(long long);
  20. PVFMMDefinePOD(unsigned long);
  21. PVFMMDefinePOD(char*);
  22. PVFMMDefinePOD(float*);
  23. PVFMMDefinePOD(double*);
  24. #undef PVFMMDefinePOD
  25. MemoryManager::MemoryManager(size_t N){
  26. buff_size=N;
  27. { // Allocate buff
  28. assert(MEM_ALIGN <= 0x8000);
  29. size_t alignment=MEM_ALIGN-1;
  30. char* base_ptr=(char*)::malloc(N+2+alignment); assert(base_ptr);
  31. buff=(char*)((uintptr_t)(base_ptr+2+alignment) & ~(uintptr_t)alignment);
  32. ((uint16_t*)buff)[-1] = (uint16_t)(buff-base_ptr);
  33. }
  34. { // Initialize to init_mem_val
  35. #ifndef NDEBUG
  36. #pragma omp parallel for
  37. for(size_t i=0;i<buff_size;i++){
  38. buff[i]=init_mem_val;
  39. }
  40. #endif
  41. }
  42. n_dummy_indx=new_node();
  43. size_t n_indx=new_node();
  44. MemNode& n_dummy=node_buff[n_dummy_indx-1];
  45. MemNode& n=node_buff[n_indx-1];
  46. n_dummy.size=0;
  47. n_dummy.free=false;
  48. n_dummy.prev=0;
  49. n_dummy.next=n_indx;
  50. n_dummy.mem_ptr=&buff[0];
  51. assert(n_indx);
  52. n.size=N;
  53. n.free=true;
  54. n.prev=n_dummy_indx;
  55. n.next=0;
  56. n.mem_ptr=&buff[0];
  57. n.it=free_map.insert(std::make_pair(N,n_indx));
  58. omp_init_lock(&omp_lock);
  59. }
  60. MemoryManager::~MemoryManager(){
  61. MemNode* n_dummy=&node_buff[n_dummy_indx-1];
  62. MemNode* n=&node_buff[n_dummy->next-1];
  63. if(!n->free || n->size!=buff_size ||
  64. node_stack.size()!=node_buff.size()-2){
  65. std::cout<<"\nWarning: memory leak detected.\n";
  66. }
  67. omp_destroy_lock(&omp_lock);
  68. { // Check out-of-bounds write
  69. #ifndef NDEBUG
  70. #pragma omp parallel for
  71. for(size_t i=0;i<buff_size;i++){
  72. assert(buff[i]==init_mem_val);
  73. }
  74. #endif
  75. }
  76. { // free buff
  77. assert(buff);
  78. ::free(buff-((uint16_t*)buff)[-1]);
  79. }
  80. }
  81. void MemoryManager::print() const{
  82. if(!buff_size) return;
  83. omp_set_lock(&omp_lock);
  84. size_t size=0;
  85. size_t largest_size=0;
  86. MemNode* n=&node_buff[n_dummy_indx-1];
  87. std::cout<<"\n|";
  88. while(n->next){
  89. n=&node_buff[n->next-1];
  90. if(n->free){
  91. std::cout<<' ';
  92. largest_size=std::max(largest_size,n->size);
  93. }
  94. else{
  95. std::cout<<'#';
  96. size+=n->size;
  97. }
  98. }
  99. std::cout<<"| allocated="<<round(size*1000.0/buff_size)/10<<"%";
  100. std::cout<<" largest_free="<<round(largest_size*1000.0/buff_size)/10<<"%\n";
  101. omp_unset_lock(&omp_lock);
  102. }
  103. void MemoryManager::test(){
  104. size_t M=2000000000;
  105. { // With memory manager
  106. size_t N=M*sizeof(double)*1.1;
  107. double tt;
  108. double* tmp;
  109. std::cout<<"With memory manager: ";
  110. MemoryManager memgr(N);
  111. for(size_t j=0;j<3;j++){
  112. tmp=(double*)memgr.malloc(M*sizeof(double)); assert(tmp);
  113. tt=omp_get_wtime();
  114. #pragma omp parallel for
  115. for(size_t i=0;i<M;i+=64) tmp[i]=i;
  116. tt=omp_get_wtime()-tt;
  117. std::cout<<tt<<' ';
  118. memgr.free(tmp);
  119. }
  120. std::cout<<'\n';
  121. }
  122. { // Without memory manager
  123. double tt;
  124. double* tmp;
  125. std::cout<<"Without memory manager: ";
  126. for(size_t j=0;j<3;j++){
  127. tmp=(double*)::malloc(M*sizeof(double)); assert(tmp);
  128. tt=omp_get_wtime();
  129. #pragma omp parallel for
  130. for(size_t i=0;i<M;i+=64) tmp[i]=i;
  131. tt=omp_get_wtime()-tt;
  132. std::cout<<tt<<' ';
  133. ::free(tmp);
  134. }
  135. std::cout<<'\n';
  136. }
  137. }
  138. }//end namespace
  139. }//end namespace