fixed a bug that caused memory leak when free
[charm.git] / src / arch / gemini_gni / mempool.c
1 /*****************************************************************************
2  * $Source$
3  * $Author$ Yanhua Sun 
4  * $Date$   08-27-2011
5  * $Revision$
6  *****************************************************************************/
7
8 /** Memory pool implementation , It is only good for Charm++ usage. The first 64 bytes provides additional information. sizeof(int)- size of this block(free or allocated), next gni_mem_handle_t, then void** point to the next available block, */
9 #define MEMPOOL_DEBUG   0
10
11 #define POOLS_NUM       2
12 #define MAX_INT        2147483647
13
14 #define  GetMemHndl(x)  ((mempool_header*)((char*)x-ALIGNBUF))->mem_hndl
15
16 static      size_t     expand_mem = 1024ll*1024*16;
17
18 // multiple mempool for different size allocation
19 typedef struct mempool_block_t
20 {
21     void                *mempool_ptr;
22     gni_mem_handle_t    mem_hndl;
23     struct              mempool_block_t *next;
24 } mempool_block;
25
26 mempool_block       *mempools_head = 0;
27
28 typedef struct mempool_header
29 {
30   int size;
31   gni_mem_handle_t  mem_hndl;
32   struct mempool_header *next;
33 } mempool_header;
34
35 mempool_header    *freelist_head = NULL;
36
37 void init_mempool(size_t pool_size)
38 {
39     gni_return_t status;
40     mempool_header *header;
41     //CmiPrintf("[%d] mempool ask for init size %d\n", CmiMyPe(), pool_size);
42     mempools_head = (mempool_block*)malloc(sizeof(mempool_block));
43     mempools_head->mempool_ptr = memalign(ALIGNBUF, pool_size);
44     freelist_head = header = (mempool_header *) mempools_head->mempool_ptr;
45     status = MEMORY_REGISTER(onesided_hnd, nic_hndl, header, pool_size,  &(mempools_head->mem_hndl), &omdh);
46     mempools_head->next = NULL;
47     GNI_RC_CHECK("Mempool register", status);
48     header->size = pool_size;
49     header->mem_hndl = mempools_head->mem_hndl;
50     header->next = NULL;
51
52 #if  MEMPOOL_DEBUG
53     CmiPrintf("[%d] mempool init, MEM:%p, next=%p\n", CmiMyPe(), freelist_head, freelist_head->next);
54 #endif
55 }
56
57 void kill_allmempool()
58 {
59     gni_return_t status;
60     
61     mempool_block *current = mempools_head;
62     while(mempools_head!= NULL)
63     {
64         status = GNI_MemDeregister(nic_hndl, &(mempools_head->mem_hndl));
65         GNI_RC_CHECK("Mempool de-register", status);
66         //printf("[%d] free mempool:%p\n", CmiMyPe(), mempools_head->mempool_ptr);
67         free( mempools_head->mempool_ptr);
68         current=mempools_head;
69         mempools_head = mempools_head->next;
70         free(current);
71     }
72 }
73
74 // append size before the real memory buffer
75 void*  syh_mempool_malloc(int size)
76 {
77     int     bestfit_size = MAX_INT; //most close size 
78     mempool_block   *expand_pool;
79     gni_return_t    status;
80     mempool_header    *current = freelist_head;
81     mempool_header    *previous = NULL;
82     mempool_header    *bestfit = NULL;
83     mempool_header    *bestfit_previous = NULL;
84     int     expand_size;
85
86 #if  MEMPOOL_DEBUG
87     CmiPrintf("[%d] request malloc for size %d, freelist:%p\n", CmiMyPe(), size, freelist_head);
88 #endif
89 #if 1
90     while(current!= NULL)     /* best fit */
91     {
92 #if  MEMPOOL_DEBUG
93         CmiPrintf("[%d] current=%p size:%d \n", CmiMyPe(), current, current->size);
94 #endif
95         if(current->size >= size && current->size < bestfit_size)
96         {
97             bestfit_size = current->size;
98             bestfit = current;
99             bestfit_previous = previous;
100         }
101         previous = current;
102         current = current->next;
103     }
104 #else
105     while(current!= NULL)             /*  first fit */
106     {
107 #if  MEMPOOL_DEBUG
108         CmiPrintf("[%d] current=%p size:%d ->%p \n", CmiMyPe(), current, current->size, (char*)current+current->size);
109 #endif
110         if(current->size >= size)
111         {
112             bestfit_size = current->size;
113             bestfit = current;
114             bestfit_previous = previous;
115             break;
116         }
117         previous = current;
118         current = current->next;
119     }
120 #endif
121
122     if(bestfit == NULL)
123     {
124         expand_size = expand_mem>size ? expand_mem:2*size; 
125         expand_pool         = (mempool_block*)malloc(sizeof(mempool_block));
126         expand_pool->mempool_ptr = memalign(ALIGNBUF, expand_size);
127         printf("[%d] No memory has such free empty chunck of %d. expanding %p (%d)\n", CmiMyPe(), size, expand_pool->mempool_ptr, expand_size);
128         status = MEMORY_REGISTER(onesided_hnd, nic_hndl, expand_pool->mempool_ptr, expand_size,  &(expand_pool->mem_hndl), &omdh);
129         GNI_RC_CHECK("Mempool register", status);
130         expand_pool->next = mempools_head;
131         mempools_head = expand_pool;
132         
133         bestfit = expand_pool->mempool_ptr;
134         bestfit->size = expand_size;
135         bestfit->mem_hndl = expand_pool->mem_hndl;
136         bestfit->next = NULL;
137         bestfit_size = expand_size;
138 #if 0
139         current = freelist_head;
140         while(current!= NULL && current < bestfit )
141         {
142           previous = current;
143           current = current->next;
144         }
145 #else
146         CmiAssert(bestfit > previous);
147 #endif
148         bestfit_previous = previous;
149         if (previous == NULL)
150            freelist_head = bestfit;
151         else
152            previous->next = bestfit;
153     }
154
155     bestfit->size = size;
156     if(bestfit_size > size) //deduct this entry 
157     {
158         mempool_header *ptr = (mempool_header *)((char*)bestfit + size);
159         ptr->size = bestfit_size - size;
160         ptr->mem_hndl = bestfit->mem_hndl;
161         ptr->next = bestfit->next;
162         if(bestfit == freelist_head)
163             freelist_head = ptr;
164         if(bestfit_previous != NULL)
165             bestfit_previous->next= ptr;
166     }
167     else {  
168           //delete this free entry
169         if(bestfit == freelist_head)
170             freelist_head = freelist_head->next;
171         else
172             bestfit_previous->next = bestfit->next;
173     }
174 #if  MEMPOOL_DEBUG
175     printf("[%d] ++MALLOC served: %d, ptr:%p\n", CmiMyPe(), size, bestfit);
176 #endif
177     return (char*)bestfit;
178 }
179
180 //sorted free_list and merge it if it become continous 
181 void syh_mempool_free(void *ptr_free)
182 {
183     int i;
184     int merged = 0;
185     int free_size;
186     void *free_lastbytes_pos;
187     mempool_header *current = freelist_head;
188     mempool_header *previous = NULL;
189     mempool_header *to_free = (mempool_header *)ptr_free;
190
191     free_size = to_free->size;
192     free_lastbytes_pos = (char*)ptr_free +free_size;
193 #if  MEMPOOL_DEBUG
194     printf("[%d] INSIDE FREE ptr=%p, size=%d freehead=%p\n", CmiMyPe(), ptr_free, free_size, freelist_head);
195 #endif
196     
197     while(current!= NULL && current < to_free )
198     {
199 #if  MEMPOOL_DEBUG
200         CmiPrintf("[%d] previous=%p, current=%p size:%d %p\n", CmiMyPe(), previous, current, current->size, (char*)current+current->size);
201 #endif
202         previous = current;
203         current = current->next;
204     }
205 #if  MEMPOOL_DEBUG
206     if (current) CmiPrintf("[%d] previous=%p, current=%p size:%d %p\n", CmiMyPe(), previous, current, current->size, free_lastbytes_pos);
207 #endif
208     //continuos with previous free space 
209     if(previous!= NULL && (char*)previous+previous->size == ptr_free &&  memcmp(&previous->mem_hndl, &to_free->mem_hndl, sizeof(gni_mem_handle_t))==0 )
210     {
211         previous->size +=  free_size;
212         merged = 1;
213     }
214     else if(current!= NULL && free_lastbytes_pos == current && memcmp(&current->mem_hndl, &to_free->mem_hndl, sizeof(gni_mem_handle_t))==0)
215     {
216         to_free->size += current->size;
217         to_free->next = current->next;
218         current = to_free;
219         merged = 1;
220         if(previous == NULL)
221             freelist_head = current;
222         else
223             previous->next = to_free;
224     }
225     //continous, merge
226     if(merged) {
227        if (previous!= NULL && current!= NULL && (char*)previous + previous->size  == (char *)current && memcmp(&previous->mem_hndl, &current->mem_hndl, sizeof(gni_mem_handle_t))==0)
228       {
229          previous->size += current->size;
230          previous->next = current->next;
231       }
232     }
233     else {
234           // no merge to previous, current, create new entry
235         to_free->next = current;
236         if(previous == NULL)
237             freelist_head = to_free;
238         else
239             previous->next = to_free;
240     }
241 #if  MEMPOOL_DEBUG
242     printf("[%d] Memory free done %p, freelist_head=%p\n", CmiMyPe(), ptr_free,  freelist_head);
243 #endif
244 }
245