NVMLib  very early alpha
A library to optimally use a Hybrid RAM setup.
malloc.c
Go to the documentation of this file.
1 #include "malloc.h"
2 #include "types.h"
3 #include "algo.h"
4 #include "math.h"
5 #include <stdint.h>
6 #include <libiberty/splay-tree.h>
7 // #include <splay-tree.h>
8 #include "object_maintainance.h"
9 #include <uv.h>
10 
11 // MEMoid __memalloc(size_t size) {
12 // MEMoid new_obj;
13 
14 // if (decide_allocation(size) - NVRAM_HEAP == 0) {
15 // // allocate in NVRAM
16 // new_obj.pool_id = get_current_poolid();
17 // new_obj.offset = get_first_free_offset(size);
18 
19 // } else if (decide_allocation(size) - DRAM_HEAP == 0) {
20 // // allocate in DRAM
21 // new_obj.offset = (uint64_t)(malloc(size));
22 // new_obj.pool_id = POOL_ID_MALLOC_OBJ;
23 // }
24 // new_obj.size = size;
25 
26 // // new_obj.access_bitmap = (uint64_t*)malloc((ceil((double)size/64));
27 // return new_obj;
28 // }
29 splay_tree addr2MemOID_read;
30 splay_tree addr2MemOID_write;
31 
33  return D_RO(slot)->end_b - D_RO(slot)->start_b + 1;
34 }
35 
49  // LOG shit
50  pool_free_slot_val temp;
51  pool_free_slot_val* temp_ptr = &temp;
52  temp.key = pool_id;
53 #ifdef DEBUG
54  printf("allot_free_slot_offset_pool temp_ptr->pool_id %d\n", temp_ptr->key);
55 #endif
56  int hmret = HASH_MAP_FIND(pool_free_slot_val)(pool_free_slot_map, &temp_ptr);
57 #ifdef DEBUG
58  printf("affop find = %d\n", hmret);
59 #endif
60  pool_free_slot_head *f_head = temp_ptr->head;
61 #ifdef DEBUG
62  printf("fhead value is %p\n", f_head);
63 #endif
64  uint64_t ret = -1;
65  int flag = 0;
66  TOID(struct pool_free_slot) node;
67  POBJ_TAILQ_FOREACH (node, f_head, fnd) {
68  if (free_slot_size(node) == size) {
69  ret = D_RO(node)->start_b;
70  flag = 1;
71  break;
72  } else if (free_slot_size(node) > size) {
73  ret = D_RO(node)->start_b;
74  uint64_t new_start = D_RO(node)->start_b + size;
75  #ifdef DEBUG
76  printf("Allot flag 2\n");
77  #endif
78  TX_BEGIN(temp_ptr->pool) {
79  D_RW(node)->start_b = new_start;
80  } TX_END
81  break;
82  }
83  }
84 
85  if (flag == 1) {
86  TX_BEGIN(temp_ptr->pool) {
87  POBJ_TAILQ_REMOVE_FREE(f_head, node, fnd);
88  } TX_END
89  }
90  return ret;
91 }
92 
93 
105 #ifdef DEBUG
106  printf("allot_frst_free_offset num_pools = %d\n", num_pools);
107 #endif
108  for (int i = 1; i <= num_pools; i++) {
109  uint64_t ret = allot_first_free_offset_pool(i, size);
110  if (ret >= 0) {
111  MEMoid m;
112  m.pool_id = i;
113  m.offset = ret;
114  m.size = size;
115  return m;
116  }
117  }
118  create_new_pool(size);
120  MEMoid m;
121  m.pool_id = num_pools;
122  m.offset = ret;
123  m.size = size;
124  return m;
125 }
126 
127 
138 MEMoid __memalloc(size_t size, int which_ram) {
139  MEMoid new_obj;
140 
141  switch(which_ram) {
142  case ANY_RAM:
143  if (decide_allocation(size) - NVRAM_HEAP == 0) {
144  // allocate in NVRAM
145  //new_obj.pool_id = get_current_poolid();
146  //new_obj.offset = get_first_free_offset(size);
147  new_obj = allot_first_free_offset(size);
148 
149  } else if (decide_allocation(size) - DRAM_HEAP == 0) {
150  // allocate in DRAM
151  new_obj.offset = (uint64_t)(malloc(size));
152  new_obj.pool_id = POOL_ID_MALLOC_OBJ;
153  }
154  break;
155 
156  case NVRAM_HEAP:
157  // allocate in NVRAM
158  //new_obj.pool_id = get_current_poolid();
159  //new_obj.offset = get_first_free_offset(size);
160  new_obj = allot_first_free_offset(size);
161  break;
162 
163  case DRAM_HEAP:
164  // allocate in DRAM
165  new_obj.offset = (uint64_t)(malloc(size));
166  new_obj.pool_id = POOL_ID_MALLOC_OBJ;
167  break;
168 
169  default:
170  break;
171  }
172  new_obj.size = size;
173 
174  // new_obj.access_bitmap = (uint64_t*)malloc((ceil((double)size/64));
175  return new_obj;
176 }
177 
178 uint64_t string_hash(const char *str) {
179  uint64_t hash = 5381;
180  int c;
181  while ((c = *str++))
182  hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
183 
184  return hash;
185 }
186 
202 MEMoidKey _memalloc(size_t size, const char *file, const char *func, const int line, int num_args, ...) {
203  // Can be made faster ... but thats an after thought as of now xD
204  MEMoidKey key = (((string_hash(file) + string_hash(func)) % __UINT64_MAX__)
205  + line) % __UINT64_MAX__;
206 
207  int which_ram = ANY_RAM;
208  va_list arg_list;
209  va_start(arg_list, num_args);
210  while(num_args--) {
211  which_ram = va_arg(arg_list, int);
212  }
213 
214  // Check if the element is already in NVRAM
215  MEMoid oid = get_MEMoid(key);
216 #ifdef DEBUG
217  printf("\n------------------------------------\nmemalloc: oid->pool_id = %ld, oid->offset = %ld\n------------------------------------------------\n", oid.pool_id, oid.offset);
218 #endif
219 
220  if ((oid.offset == MEMOID_NULL.offset && oid.pool_id == MEMOID_NULL.pool_id) || oid.pool_id == POOL_ID_MALLOC_OBJ){
221  // Need to create the new object
222 
223  #ifdef DEBUG
224  printf("memalloc: Creating new object or it was previously in DRAM\n");
225  #endif
226 
227  oid = __memalloc(size, which_ram);
228 
229  // Get the hashmap mutex first to ensure there are no leftover accesses
230  uv_mutex_lock(&object_maintainence_hashmap_mutex);
231  // need to replace the value
232  remove_object_from_hashmap(key); // This is done because there is chance that the object remains after free
233  insert_object_to_hashmap(key, oid);
234  uv_mutex_unlock(&object_maintainence_hashmap_mutex);
235 
236  // Insert into the object maintainance table for logistics
239  uv_mutex_unlock(&object_maintainence_maintain_map_mutex);
240  } else {
241  // obj is already present in the map
242 
243  #ifdef DEBUG
244  printf("memalloc: Object already existing and is from NVRAM\n");
245  #endif
246 
247  //DRAM variables in the table need to be replaced
248  // Get the hashmap mutex first to ensure there are no leftover accesses
249  // uv_mutex_lock(&object_maintainence_hashmap_mutex);
250  // if(oid.pool_id == POOL_ID_MALLOC_OBJ) {
251  // // dram object
252  // oid = __memalloc(size, DRAM);
253  // // need to replace the value
254  // remove_object_from_hashmap(key);
255  // // Insert in the main types table
256  // insert_object_to_hashmap(key, oid);
257  // }
258  // uv_mutex_unlock(&object_maintainence_hashmap_mutex);
259 
260  // Insert into the object maintainance table for logistics
261  uv_mutex_lock(&object_maintainence_addtion_mutex);
263 
264  to_add->key = key;
265  to_add->oid = oid;
266  to_add->can_be_moved = which_ram==ANY_RAM ? true:false;
268  TAILQ_INSERT_TAIL(&addition_queue_head, to_add, list);
269 
270  // insert_into_maintainance_map(create_new_maintainance_map_entry(key, oid, oid.pool_id==POOL_ID_MALLOC_OBJ?DRAM:NVRAM, true));
271  uv_mutex_unlock(&object_maintainence_addtion_mutex);
272  }
273 
274  struct addr2memoid_key* new_key = (struct addr2memoid_key*)malloc(sizeof(addr2memoid_key));
275  new_key->comp = cmp_node;
276  new_key->key = key;
277 
278  struct addr2memoid_key* new_key1 = (struct addr2memoid_key*)malloc(sizeof(addr2memoid_key));
279  new_key1->comp = cmp_node;
280  new_key1->key = key;
281 
282  uv_mutex_lock(&write_splay_tree_mutex);
283  splay_tree_insert(addr2MemOID_write, (uintptr_t)new_key, NULL);
284  uv_mutex_unlock(&write_splay_tree_mutex);
285 
286  uv_mutex_lock(&read_splay_tree_mutex);
287  splay_tree_insert(addr2MemOID_read, (uintptr_t)new_key1, NULL);
288  uv_mutex_unlock(&read_splay_tree_mutex);
289 
290  return key;
291 }
292 
293 // MEMoidKey _memalloc(size_t size, uint8_t which_ram, const char *file, const char *func, const int line) {
294 // // Can be made faster ... but thats an after thought as of now xD
295 // MEMoidKey key = (((string_hash(file) + string_hash(func)) % __UINT64_MAX__)
296 // + line) % __UINT64_MAX__;
297 // MEMoid oid = __memalloc(size);
298 // // Insert in the main types table
299 // insert_object_to_hashmap(key, oid);
300 // // Insert into the object maintainance table for logistics
301 // insert_into_maintainance_map(create_new_maintainance_map_entry(key, oid, oid.pool_id==POOL_ID_MALLOC_OBJ?DRAM:NVRAM, false));
302 // struct addr2memoid_key* new_key = (struct addr2memoid_key*)malloc(sizeof(addr2memoid_key));
303 // new_key->comp = cmp_node;
304 // new_key->key = key;
305 // splay_tree_insert(addr2MemOID, new_key, NULL);
306 // return key;
307 // }
308 
309 
317  if (oid.offset == 0 && oid.pool_id == POOL_ID_MALLOC_OBJ){
318  return NULL;
319  }
320 
321  switch(oid.pool_id){
322  case POOL_ID_MALLOC_OBJ:
323  // It is a malloc object
324  return (void *)((uintptr_t)oid.offset);
325 
326  default:
327  // It is a nvm object
328  return (void *)((uintptr_t)get_pool_from_poolid(oid.pool_id) + oid.offset);
329  }
330 }
331 
332 // static inline void _memfree(MEMoidKey oidkey, size_t size) {
333 // MEMoid oid = get_MEMoid(oidkey);
334 // if(oid.offset == MEMOID_NULL.offset && oid.pool_id == MEMOID_NULL.pool_id) {
335 // switch(oid.pool_id) {
336 // case POOL_ID_MALLOC_OBJ:
337 // free(oid.offset);
338 // break;
339 
340 // default:
341 // nvm_free(oid.pool_id, oid.offset, size);
342 // }
343 // }
344 
345 // // remove the entry from the HashTable
346 // remove_object_from_hashmap(oidkey);
347 // }
348 
358 void _memfree(MEMoidKey oidkey) {
359  // Just hand over the task to `Deletion thread`
360 
361  object_maintainance *found_obj = find_in_maintainance_map(oidkey);
362  if (!found_obj)
363  return;
364 
365  uv_mutex_lock(&object_maintainence_addtion_mutex);
367 
368  to_del->key = found_obj->key;
369  to_del->oid = found_obj->oid;
370  to_del->can_be_moved = found_obj->can_be_moved;
371  to_del->which_ram = NO_RAM;
372  TAILQ_INSERT_TAIL(&deletion_queue_head, to_del, list);
373  // insert_into_maintainance_map(create_new_maintainance_map_entry(key, oid, oid.pool_id==POOL_ID_MALLOC_OBJ?DRAM:NVRAM, true));
374  uv_mutex_unlock(&object_maintainence_addtion_mutex);
375 
376  // found_obj->which_ram = NO_RAM; // Delete the object
377 }
378 
379 
380 
381 #define MEMOID_FIRST(m) (get_pool_from_poolid(m.pool_id) + m.offset) //need to use this in object_maintenence.c also, move to malloc.h?
382 #define MEMOID_LAST(m) (get_pool_from_poolid(m.pool_id) + m.offset + m.size)
383 
385  MEMoid m = get_MEMoid(key);
386  if (m.offset == MEMOID_NULL.offset && m.pool_id == MEMOID_NULL.pool_id) {
387  return NULL;
388  }
389  return (void *)MEMOID_FIRST(m);
390 }
391 
393  MEMoid m = get_MEMoid(key);
394  if (m.offset == MEMOID_NULL.offset && m.pool_id == MEMOID_NULL.pool_id) {
395  return NULL;
396  }
397  return (void *)MEMOID_FIRST(m) + m.size;
398 }
399 
409 int addr2memoid_cmp(splay_tree_key key1, splay_tree_key key2) {
410  if (((addr2memoid_key*)key2)->comp == cmp_node && ((addr2memoid_key*)key1)->comp == cmp_node) {
411  //printf("splay tree comp node key1addr = %p key2addr = %p\n", KEY_FIRST(((addr2memoid_key*)key1)->key), KEY_FIRST(((addr2memoid_key*)key2)->key));
412  if (((addr2memoid_key*)key1)->key == ((addr2memoid_key*)key2)->key)
413  return 0;
414  else
415  return KEY_FIRST(((addr2memoid_key*)key1)->key) > KEY_FIRST(((addr2memoid_key*)key2)->key)?1:-1;
416 
417  } else if (((addr2memoid_key*)key2)->comp == cmp_addr) {
418  //printf("splay tree comp addr key1addr = %p key2addr = %p\n", KEY_FIRST(((addr2memoid_key*)key1)->key), ((addr2memoid_key*)key2)->addr);
419  if (((addr2memoid_key*)key2)->addr >= KEY_FIRST(((addr2memoid_key*)key1)->key) &&
420  ((addr2memoid_key*)key2)->addr < KEY_LAST(((addr2memoid_key*)key1)->key))
421  return 0;
422  else
423  return KEY_FIRST(((addr2memoid_key*)key1)->key) > ((addr2memoid_key*)key2)->addr?1:-1;
424  } else if (((addr2memoid_key*)key1)->comp == cmp_addr) {
425  //printf("splay tree comp addr key1addr = %p key2addr = %p\n", ((addr2memoid_key*)key1)->addr, KEY_FIRST(((addr2memoid_key*)key2)->key));
426  if (((addr2memoid_key*)key1)->addr >= KEY_FIRST(((addr2memoid_key*)key2)->key) &&
427  ((addr2memoid_key*)key1)->addr < KEY_LAST(((addr2memoid_key*)key2)->key))
428  return 0;
429  else
430  return KEY_FIRST(((addr2memoid_key*)key2)->key) > ((addr2memoid_key*)key1)->addr?-1:1;
431  }
432  printf("Something wrong.\n");
433  return 0;
434 }
435 
436 void addr2memoid_del(splay_tree_key key) {
437  free((void*)key);
438 }
439 
440 // The splay tree is used for reverse mapping
441 // from address to MemOiD
442 void init_splay() {
445 }
get_memobj_direct
void * get_memobj_direct(MEMoid oid)
The function to return the actual memptr for a given MEMoid object.
Definition: malloc.c:316
POBJ_TAILQ_REMOVE_FREE
#define POBJ_TAILQ_REMOVE_FREE(head, elm, field)
Definition: free_slot_list.h:288
_key_get_last
void * _key_get_last(MEMoidKey key)
Definition: malloc.c:392
MEMoid_st::offset
uint64_t offset
Definition: malloc.h:31
cmp_addr
@ cmp_addr
Definition: malloc.h:112
pool_free_slot_val_st::head
pool_free_slot_head * head
Definition: pool.h:40
types.h
get_pool_from_poolid
uintptr_t get_pool_from_poolid(uint64_t pool_id)
Definition: pool.c:79
insert_object_to_hashmap
void insert_object_to_hashmap(MEMoidKey key, MEMoid oid)
Definition: types.c:70
object_maintainance_st::can_be_moved
bool can_be_moved
Definition: object_maintainance.h:65
object_maintainance_st::oid
MEMoid oid
Definition: object_maintainance.h:41
_memfree
void _memfree(MEMoidKey oidkey)
The fucntion to free the allocated memory location.
Definition: malloc.c:358
init_splay
void init_splay()
Definition: malloc.c:442
NO_RAM
@ NO_RAM
Definition: object_maintainance.h:34
_key_get_first
void * _key_get_first(MEMoidKey key)
Definition: malloc.c:384
object_maintainance_addition::which_ram
where_t which_ram
Definition: object_maintainance.h:73
MEMoid_st
The struct that stores the memptr for the object.
Definition: malloc.h:29
algo.h
addr2MemOID_write
splay_tree addr2MemOID_write
Definition: malloc.c:30
MEMoidKey
uint64_t MEMoidKey
The key of the HashTable that contains <MEMoidKey, MEMoid>.
Definition: malloc.h:49
MEMoid_st::size
size_t size
Definition: malloc.h:32
allot_first_free_offset
MEMoid allot_first_free_offset(size_t size)
Allocates the first free memory chunk of the given size.
Definition: malloc.c:104
_memalloc
MEMoidKey _memalloc(size_t size, const char *file, const char *func, const int line, int num_args,...)
Allocates the memory requested and returns a MEMoidKey.
Definition: malloc.c:202
pool_free_slot_val_st
Definition: pool.h:37
DRAM
@ DRAM
Definition: object_maintainance.h:32
string_hash
uint64_t string_hash(const char *str)
Definition: malloc.c:178
object_maintainance_addition
Definition: object_maintainance.h:69
ANY_RAM
#define ANY_RAM
Types of allocation.
Definition: globals.h:48
NVRAM
@ NVRAM
Definition: object_maintainance.h:33
object_maintainance_st::key
MEMoidKey key
Definition: object_maintainance.h:40
free_slot_size
uint64_t free_slot_size(TOID(struct pool_free_slot) slot)
Definition: malloc.c:32
object_maintainance_deletion::oid
MEMoid oid
Definition: object_maintainance.h:82
addr2MemOID_read
splay_tree addr2MemOID_read
Definition: malloc.c:29
KEY_LAST
#define KEY_LAST(key)
Definition: malloc.h:89
addr2memoid_key::key
MEMoidKey key
Definition: malloc.h:120
object_maintainance.h
remove_object_from_hashmap
void remove_object_from_hashmap(MEMoidKey key)
Definition: types.c:74
uint64_t
__uint64_t uint64_t
Definition: globals.h:51
addr2memoid_cmp
int addr2memoid_cmp(splay_tree_key key1, splay_tree_key key2)
The compare function used by the splay_tree.
Definition: malloc.c:409
create_new_maintainance_map_entry
object_maintainance * create_new_maintainance_map_entry(MEMoidKey key, MEMoid oid, where_t which_ram, bool can_be_moved)
Definition: object_maintainance.c:570
addr2memoid_key::comp
enum splay_comp comp
Definition: malloc.h:117
cmp_node
@ cmp_node
Definition: malloc.h:111
object_maintainance_deletion::key
MEMoidKey key
Definition: object_maintainance.h:81
find_in_maintainance_map
object_maintainance * find_in_maintainance_map(MEMoidKey key)
Definition: object_maintainance.c:602
KEY_FIRST
#define KEY_FIRST(key)
Definition: malloc.h:88
malloc.h
hash
static uint64_t hash(const TOID(struct hashmap_tx) *hashmap, const TOID(struct buckets) *buckets, uint64_t value)
The hash function.
Definition: hashmap_tx.c:76
object_maintainance_deletion::which_ram
where_t which_ram
Definition: object_maintainance.h:84
pool_free_slot_val_st::pool
PMEMobjpool * pool
Definition: pool.h:39
read_splay_tree_mutex
uv_mutex_t read_splay_tree_mutex
The mutex used during manupulation of read splay tree
Definition: object_maintainance.c:18
pool_free_slot_head
struct pool_free_slot_head pool_free_slot_head
Definition: pool.h:26
create_new_pool
void create_new_pool(size_t size)
Definition: pool.c:94
insert_into_maintainance_map
void insert_into_maintainance_map(object_maintainance *obj)
Definition: object_maintainance.c:594
pool_free_slot
Definition: pool.h:20
addr2memoid_key::addr
void * addr
Definition: malloc.h:119
object_maintainance_deletion
Definition: object_maintainance.h:80
TOID
TOID(struct hashmap_tx)
Definition: types.c:11
object_maintainence_maintain_map_mutex
uv_mutex_t object_maintainence_maintain_map_mutex
The mutex used during manupulation of maintainance map
Definition: object_maintainance.c:15
NULL
#define NULL
Definition: list.h:13
MEMOID_NULL
static const MEMoid MEMOID_NULL
Just a dummy obj.
Definition: malloc.h:52
object_maintainance_st
The structure used by the logistics thread for keeping track of the object state in order to make dif...
Definition: object_maintainance.h:39
object_maintainance_addition::can_be_moved
bool can_be_moved
Definition: object_maintainance.h:74
object_maintainance_deletion::can_be_moved
bool can_be_moved
Definition: object_maintainance.h:85
write_splay_tree_mutex
uv_mutex_t write_splay_tree_mutex
The mutex used during manupulation of read splay tree
Definition: object_maintainance.c:19
NVRAM_HEAP
#define NVRAM_HEAP
Types of allocation.
Definition: globals.h:40
MEMoid_st::pool_id
uint64_t pool_id
Definition: malloc.h:30
uintptr_t
unsigned long int uintptr_t
Definition: globals.h:56
addr2memoid_del
void addr2memoid_del(splay_tree_key key)
Definition: malloc.c:436
MEMOID_FIRST
#define MEMOID_FIRST(m)
Definition: malloc.c:381
object_maintainance_addition::key
MEMoidKey key
Definition: object_maintainance.h:70
object_maintainence_addtion_mutex
uv_mutex_t object_maintainence_addtion_mutex
The mutex used during manupulation of maintainance map
Definition: object_maintainance.c:16
POBJ_TAILQ_FOREACH
#define POBJ_TAILQ_FOREACH(var, head, field)
Definition: free_slot_list.h:166
DRAM_HEAP
#define DRAM_HEAP
Types of allocation.
Definition: globals.h:33
__memalloc
MEMoid __memalloc(size_t size, int which_ram)
Allocates the memory requested and returns a MEMoid.
Definition: malloc.c:138
object_maintainance_addition::oid
MEMoid oid
Definition: object_maintainance.h:71
allot_first_free_offset_pool
uint64_t allot_first_free_offset_pool(uint64_t pool_id, size_t size)
Allocates first free memory chunk of the given size in the given pool specified by pool_id.
Definition: malloc.c:48
POOL_ID_MALLOC_OBJ
#define POOL_ID_MALLOC_OBJ
Definition: pool.h:9
addr2memoid_key
The structure used in spaly_tree which used for getting MEMoid from the memory address.
Definition: malloc.h:116
HASH_MAP_FIND
#define HASH_MAP_FIND(VALUE_TYPE)
Definition: hashmap.h:33
get_MEMoid
MEMoid get_MEMoid(MEMoidKey key)
The function to obtain the MEMoid object given the MEMoidKey
Definition: types.c:64
num_pools
uint32_t num_pools
Definition: pool.h:13
decide_allocation
int decide_allocation(size_t size)
Function to decide the initial allocation of object.
Definition: algo.h:23
pool_free_slot_val_st::key
uint16_t key
Definition: pool.h:38
object_maintainence_hashmap_mutex
uv_mutex_t object_maintainence_hashmap_mutex
The mutex used during manupulation of types map
Definition: object_maintainance.c:13