fix compilation for gemini
[charm.git] / src / arch / util / mempool.c
1
2 /** 
3
4 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. 
5
6 Written by Yanhua Sun 08-27-2011
7 Generalized by Gengbin Zheng  10/5/2011
8
9 */
10
11 #define MEMPOOL_DEBUG   0
12
13 #define POOLS_NUM       2
14 #define MAX_INT        2147483647
15
16 #include "converse.h"
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stdint.h>
21 #include <string.h>
22 #if CMK_HAS_MALLOC_H
23 #include <malloc.h>
24 #endif
25
26 #include "mempool.h"
27
28 static      size_t     expand_mem = 1024ll*1024*16;
29
30 #ifndef  ALIGNBUF
31 #define ALIGNBUF                64
32 #endif
33
34 mempool_type *init_mempool(void *pool, size_t pool_size, gni_mem_handle_t mem_hndl)
35 {
36     mempool_type *mptr;
37     mempool_header *header;
38
39     mptr = (mempool_type*)pool;
40     mptr->mempools_head.mempool_ptr = pool;
41     mptr->mempools_head.mem_hndl = mem_hndl;
42     mptr->mempools_head.next = NULL;
43     header = (mempool_header *) ((char*)pool+sizeof(mempool_type));
44     mptr->freelist_head = sizeof(mempool_type);
45 //printf("[%d] pool: %p  free: %p\n", myrank, pool, header);
46     header->size = pool_size-sizeof(mempool_type)-sizeof(mempool_header);
47     header->mem_hndl = mem_hndl;
48     header->next_free = 0;
49     return mptr;
50 }
51
52 void kill_allmempool(mempool_type *mptr)
53 {
54     mempool_block *current, *mempools_head;
55
56     current = mempools_head = &(mptr->mempools_head);
57
58     while(mempools_head!= NULL)
59     {
60 #if CMK_CONVERSE_GEMINI_UGNI
61         gni_return_t status = GNI_MemDeregister(nic_hndl, &(mempools_head->mem_hndl));
62         GNI_RC_CHECK("Mempool de-register", status);
63 #endif
64         //printf("[%d] free mempool:%p\n", CmiMyPe(), mempools_head->mempool_ptr);
65         current=mempools_head;
66         mempools_head = mempools_head->next;
67         free(current->mempool_ptr);
68     }
69 }
70
71 // append size before the real memory buffer
72 void*  mempool_malloc(mempool_type *mptr, int size, int expand)
73 {
74     int     bestfit_size = MAX_INT; //most close size 
75     size_t    *freelist_head = &mptr->freelist_head;
76     mempool_header    *freelist_head_ptr = mptr->freelist_head?(mempool_header*)((char*)mptr+mptr->freelist_head):NULL;
77     mempool_header    *current = freelist_head_ptr;
78     mempool_header    *previous = NULL;
79     mempool_header    *bestfit = NULL;
80     mempool_header    *bestfit_previous = NULL;
81     mempool_block     *mempools_head = &(mptr->mempools_head);
82
83 #if  MEMPOOL_DEBUG
84     CmiPrintf("[%d] request malloc from pool: %p  free_head: %p %d for size %d, \n", CmiMyPe(), mptr, freelist_head_ptr, mptr->freelist_head, size);
85 #endif
86
87 #if 1
88     while(current!= NULL)     /* best fit */
89     {
90 #if  MEMPOOL_DEBUG
91         CmiPrintf("[%d] current=%p size:%d \n", CmiMyPe(), current, current->size);
92 #endif
93         if(current->size >= size && current->size < bestfit_size)
94         {
95             bestfit_size = current->size;
96             bestfit = current;
97             bestfit_previous = previous;
98         }
99         previous = current;
100         current = current->next_free?(mempool_header*)((char*)mptr + current->next_free):NULL;
101     }
102 #else
103     while(current!= NULL)             /*  first fit */
104     {
105 #if  MEMPOOL_DEBUG
106         CmiPrintf("[%d] current=%p size:%d ->%p \n", CmiMyPe(), current, current->size, (char*)current+current->size);
107 #endif
108         CmiAssert(current->size != 0);
109         if(current->size >= size)
110         {
111             bestfit_size = current->size;
112             bestfit = current;
113             bestfit_previous = previous;
114             break;
115         }
116         previous = current;
117         current = current->next_free?(mempool_header*)((char*)mptr + current->next_free):NULL;
118     }
119 #endif
120
121     if(bestfit == NULL)
122     {
123         mempool_block   *expand_pool;
124         size_t   expand_size;
125         void *pool;
126
127         if (!expand) return NULL;
128
129         expand_size = expand_mem>size ? expand_mem:2*size; 
130         pool = memalign(ALIGNBUF, expand_size);
131         expand_pool = (mempool_block*)pool;
132         expand_pool->mempool_ptr = pool;
133         printf("[%d] No memory has such free empty chunck of %d. expanding %p (%d)\n", CmiMyPe(), size, expand_pool->mempool_ptr, expand_size);
134 #if CMK_CONVERSE_GEMINI_UGNI
135         gni_return_t  status;
136         status = GNI_MemRegister(nic_hndl, (uint64_t)expand_pool->mempool_ptr, expand_size,  NULL, GNI_MEM_READWRITE, -1, &(expand_pool->mem_hndl));
137         GNI_RC_CHECK("Mempool register", status);
138 #endif
139         expand_pool->next = NULL;
140         while (mempools_head->next != NULL) mempools_head = mempools_head->next;
141         mempools_head->next = expand_pool;
142
143         bestfit = (mempool_header*)((char*)expand_pool->mempool_ptr + sizeof(mempool_block));
144         bestfit->size = expand_size-sizeof(mempool_block);
145         bestfit->mem_hndl = expand_pool->mem_hndl;
146         bestfit->next_free = 0;
147         bestfit_size = expand_size;
148 #if 0
149         current = freelist_head;
150         while(current!= NULL && current < bestfit )
151         {
152           previous = current;
153           current = current->next;
154         }
155 #else
156         CmiAssert(bestfit > previous);
157 #endif
158         bestfit_previous = previous;
159         if (previous == NULL)
160            *freelist_head = (char*)bestfit - (char*)mptr;
161         else
162            previous->next_free = (char*)bestfit-(char*)mptr;
163     }
164
165     bestfit->size = size;
166     if(bestfit_size > size) //deduct this entry 
167     {
168         mempool_header *ptr = (mempool_header *)((char*)bestfit + size);
169         ptr->size = bestfit_size - size;
170         ptr->mem_hndl = bestfit->mem_hndl;
171         ptr->next_free = bestfit->next_free;
172         if(bestfit == freelist_head_ptr)
173            *freelist_head = (char*)ptr - (char*)mptr;
174         if(bestfit_previous != NULL)
175            bestfit_previous->next_free = (char*)ptr - (char*)mptr;
176     }
177     else {  
178           //delete this free entry
179         if(bestfit == freelist_head_ptr)
180             *freelist_head = freelist_head_ptr->next_free;
181         else
182             bestfit_previous->next_free = bestfit->next_free;
183     }
184 #if  MEMPOOL_DEBUG
185     printf("[%d] ++MALLOC served: %d, ptr:%p\n", CmiMyPe(), size, bestfit);
186 printf("[%d] freelist_head in malloc  offset:%d free_head: %ld %ld %d %d\n", myrank, (char*)bestfit-(char*)mptr, *freelist_head, ((mempool_header*)((char*)mptr+*freelist_head))->next_free, bestfit_size, size);
187 #endif
188     CmiAssert(*freelist_head >= 0);
189     return (char*)bestfit;
190 }
191
192 //sorted free_list and merge it if it become continous 
193 void mempool_free(mempool_type *mptr, void *ptr_free)
194 {
195     int i;
196     int merged = 0;
197     int free_size;
198     void *free_lastbytes_pos;
199     mempool_block     *mempools_head;
200     size_t    *freelist_head;
201     mempool_header    *freelist_head_ptr;
202     mempool_header    *current;
203     mempool_header *previous = NULL;
204     mempool_header *to_free = (mempool_header *)ptr_free;
205
206     mempools_head = &(mptr->mempools_head);
207     freelist_head = &mptr->freelist_head;
208     freelist_head_ptr = mptr->freelist_head?(mempool_header*)((char*)mptr+mptr->freelist_head):NULL;
209     current = freelist_head_ptr;
210
211     free_size = to_free->size;
212     free_lastbytes_pos = (char*)ptr_free +free_size;
213
214 #if  MEMPOOL_DEBUG
215     printf("[%d] INSIDE FREE ptr=%p, size=%d freehead=%p mutex: %p\n", CmiMyPe(), ptr_free, free_size, freelist_head, mptr->mutex);
216 #endif
217     
218     while(current!= NULL && current < to_free )
219     {
220 #if  MEMPOOL_DEBUG
221         CmiPrintf("[%d] previous=%p, current=%p size:%d %p\n", CmiMyPe(), previous, current, current->size, (char*)current+current->size);
222 #endif
223         previous = current;
224         current = current->next_free?(mempool_header*)((char*)mptr + current->next_free):NULL;
225     }
226 #if  MEMPOOL_DEBUG
227     if (current) CmiPrintf("[%d] previous=%p, current=%p size:%d %p\n", CmiMyPe(), previous, current, current->size, free_lastbytes_pos);
228 #endif
229     //continuos with previous free space 
230     if(previous!= NULL && (char*)previous+previous->size == ptr_free &&  memcmp(&previous->mem_hndl, &to_free->mem_hndl, sizeof(gni_mem_handle_t))==0 )
231     {
232         previous->size +=  free_size;
233         merged = 1;
234     }
235     else if(current!= NULL && free_lastbytes_pos == current && memcmp(&current->mem_hndl, &to_free->mem_hndl, sizeof(gni_mem_handle_t))==0)
236     {
237         to_free->size += current->size;
238         to_free->next_free = current->next_free;
239         current = to_free;
240         merged = 1;
241         if(previous == NULL)
242             *freelist_head = (char*)current - (char*)mptr;
243         else
244             previous->next_free = (char*)to_free - (char*)mptr;
245     }
246     //continous, merge
247     if(merged) {
248        if (previous!= NULL && current!= NULL && (char*)previous + previous->size  == (char *)current && memcmp(&previous->mem_hndl, &current->mem_hndl, sizeof(gni_mem_handle_t))==0)
249       {
250          previous->size += current->size;
251          previous->next_free = current->next_free;
252       }
253     }
254     else {
255           // no merge to previous, current, create new entry
256         to_free->next_free = current?(char*)current - (char*)mptr: 0;
257         if(previous == NULL)
258             *freelist_head = (char*)to_free - (char*)mptr;
259         else
260             previous->next_free = (char*)to_free - (char*)mptr;
261     }
262 #if  MEMPOOL_DEBUG
263     printf("[%d] Memory free done %p, freelist_head=%p\n", CmiMyPe(), ptr_free,  freelist_head);
264 #endif
265
266     CmiAssert(*freelist_head >= 0);
267 }
268