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