The ROme OpTimistic Simulator  2.0.0
A General-Purpose Multithreaded Parallel/Distributed Simulation Platform
dymelor.c
Go to the documentation of this file.
1 
34 #include <core/init.h>
35 #include <mm/mm.h>
36 #include <scheduler/scheduler.h>
37 
49 static void malloc_area_init(malloc_area * m_area, size_t size, int num_chunks)
50 {
51  m_area->chunk_size = size;
52  m_area->alloc_chunks = 0;
53  m_area->dirty_chunks = 0;
54  m_area->next_chunk = 0;
55  m_area->num_chunks = num_chunks;
56  m_area->state_changed = 0;
57  m_area->last_access = -1;
58  m_area->use_bitmap = NULL;
59  m_area->dirty_bitmap = NULL;
60  m_area->self_pointer = NULL;
61  m_area->area = NULL;
62 
63 #ifndef NDEBUG
64  atomic_set(&m_area->presence, 0);
65 #endif
66 
67  m_area->prev = -1;
68  m_area->next = -1;
69 
70  SET_AREA_LOCK_BIT(m_area);
71 
72 }
73 
78 {
79  int i, num_chunks;
80  size_t chunk_size;
81  malloc_state *state;
82 
83  state = rsalloc(sizeof(malloc_state));
84 
85  state->total_log_size = 0;
86  state->total_inc_size = 0;
87  state->busy_areas = 0;
88  state->dirty_areas = 0;
89  state->num_areas = NUM_AREAS;
90  state->max_num_areas = MAX_NUM_AREAS;
91  state->bitmap_size = 0;
92  state->dirty_bitmap_size = 0;
93  state->timestamp = -1;
94  state->is_incremental = false;
95 
96  state->areas = (malloc_area *) rsalloc(state->max_num_areas * sizeof(malloc_area));
97  if (unlikely(state->areas == NULL)) {
98  rootsim_error(true, "Unable to allocate memory.\n");
99  }
100 
101  chunk_size = MIN_CHUNK_SIZE;
102  num_chunks = MIN_NUM_CHUNKS;
103 
104  for (i = 0; i < NUM_AREAS; i++) {
105 
106  malloc_area_init(&state->areas[i], chunk_size, num_chunks);
107  state->areas[i].idx = i;
108  chunk_size = chunk_size << 1;
109  }
110 
111  return state;
112 }
113 
114 void malloc_state_wipe(malloc_state **state_ptr)
115 {
116  int i;
117  malloc_state *state = *state_ptr;
118 
119  for (i = 0; i < NUM_AREAS; i++) {
120  rsfree(state->areas[i].self_pointer); // TODO: when reintroducing the buddy, this must be changed
121  }
122 
123  rsfree(*state_ptr);
124  *state_ptr = NULL;
125 }
126 
136 static size_t compute_size(size_t size)
137 {
138  // Account for the space needed to keep the pointer to the malloc area
139  size += sizeof(long long);
140  size_t size_new;
141 
142  size_new = POWEROF2(size);
143  if (unlikely(size_new < MIN_CHUNK_SIZE))
144  size_new = MIN_CHUNK_SIZE;
145 
146  return size_new;
147 }
148 
159 static void find_next_free(malloc_area * m_area)
160 {
161  m_area->next_chunk++;
162 
163  while (m_area->next_chunk < m_area->num_chunks) {
164  if (!bitmap_check(m_area->use_bitmap, m_area->next_chunk))
165  break;
166 
167  m_area->next_chunk++;
168  }
169 
170 }
171 
172 void *do_malloc(struct lp_struct *lp, size_t size)
173 {
174  malloc_area *m_area, *prev_area = NULL;
175  void *ptr;
176  size_t area_size, bitmap_size;
177 
178  size = compute_size(size);
179 
180  if (unlikely(size > MAX_CHUNK_SIZE)) {
181  rootsim_error(false, "Requested a memory allocation of %d but the limit is %d. Reconfigure MAX_CHUNK_SIZE. Returning NULL.\n",
182  size, MAX_CHUNK_SIZE);
183  return NULL;
184  }
185 
186  m_area = &lp->mm->m_state->areas[(int)log2(size) -
187  (int)log2(MIN_CHUNK_SIZE)];
188 
189 #ifndef NDEBUG
190  atomic_inc(&m_area->presence);
191  assert(atomic_read(&m_area->presence) == 1);
192 #endif
193 
194  while (m_area != NULL && m_area->alloc_chunks == m_area->num_chunks) {
195  prev_area = m_area;
196  if (m_area->next == -1) {
197  m_area = NULL;
198  } else {
199  m_area = &(lp->mm->m_state->areas[m_area->next]);
200 #ifndef NDEBUG
201  atomic_inc(&m_area->presence);
202  assert(atomic_read(&m_area->presence) == 1);
203 #endif
204  }
205  }
206 
207 #ifndef NDEBUG
208  if (prev_area != NULL) {
209  atomic_dec(&prev_area->presence);
210  }
211 #endif
212 
213  if (m_area == NULL) {
214 
215  printf("Initializing an additional area\n");
216  fflush(stdout);
217 
218  if (lp->mm->m_state->num_areas == lp->mm->m_state->max_num_areas) {
219 
220  malloc_area *tmp = NULL;
221 
222  if ((lp->mm->m_state->max_num_areas << 1) > MAX_LIMIT_NUM_AREAS) {
223 #ifndef NDEBUG
224  atomic_dec(&m_area->presence);
225 #endif
226  return NULL;
227  }
228 
229  lp->mm->m_state->max_num_areas <<= 1;
230 
231  rootsim_error(true, "To reimplement\n");
232 // tmp = (malloc_area *)pool_realloc_memory(lp->mm->m_state->areas, lp->mm->m_state->max_num_areas * sizeof(malloc_area));
233  if (tmp == NULL) {
234 
238  rootsim_error(false,
239  "DyMeLoR: cannot reallocate the block of malloc_area.\n");
240  lp->mm->m_state->max_num_areas >>= 1;
241 
242 #ifndef NDEBUG
243  atomic_dec(&m_area->presence);
244 #endif
245  return NULL;
246  }
247 
248  lp->mm->m_state->areas = tmp;
249  }
250  // Allocate a new malloc area
251  m_area = &lp->mm->m_state->areas[lp->mm->m_state->num_areas];
252 
253  // The malloc area to be instantiated has twice the number of chunks wrt the last full malloc area for the same chunks size
254  malloc_area_init(m_area, size, prev_area->num_chunks << 1);
255 
256 #ifndef NDEBUG
257  atomic_inc(&m_area->presence);
258  assert(atomic_read(&m_area->presence) == 1);
259 #endif
260 
261  m_area->idx = lp->mm->m_state->num_areas;
262  lp->mm->m_state->num_areas++;
263  prev_area->next = m_area->idx;
264  m_area->prev = prev_area->idx;
265 
266  }
267 
268  if (m_area->area == NULL) {
269 
270  bitmap_size = bitmap_required_size(m_area->num_chunks);
271 
272  area_size = sizeof(malloc_area *) + bitmap_size * 2 + m_area->num_chunks * size;
273 
274 // m_area->self_pointer = (malloc_area *)allocate_lp_memory(lp, area_size);
275  m_area->self_pointer = rsalloc(area_size);
276  bzero(m_area->self_pointer, area_size);
277 
278  if (unlikely(m_area->self_pointer == NULL)) {
279  rootsim_error(true, "Error while allocating memory.\n");
280  }
281 
282  m_area->dirty_chunks = 0;
283  *(unsigned long long *)(m_area->self_pointer) =
284  (unsigned long long)m_area;
285 
286  m_area->use_bitmap =
287  ((unsigned char *)m_area->self_pointer +
288  sizeof(malloc_area *));
289 
290  m_area->dirty_bitmap =
291  ((unsigned char *)m_area->use_bitmap + bitmap_size);
292 
293  m_area->area =
294  (void *)((char *)m_area->dirty_bitmap + bitmap_size);
295  }
296 
297  if (unlikely(m_area->area == NULL)) {
298  rootsim_error(true, "Error while allocating memory.\n");
299  }
300 #ifndef NDEBUG
301  if (bitmap_check(m_area->use_bitmap, m_area->next_chunk)) {
302  rootsim_error(true, "Error: reallocating an already allocated chunk at %s:%d\n");
303  }
304 #endif
305 
306  ptr = (void *)((char *)m_area->area + (m_area->next_chunk * size));
307 
308  bitmap_set(m_area->use_bitmap, m_area->next_chunk);
309 
310  bitmap_size = bitmap_required_size(m_area->num_chunks);
311 
312  if (m_area->alloc_chunks == 0) {
313  lp->mm->m_state->bitmap_size += bitmap_size;
314  lp->mm->m_state->busy_areas++;
315  }
316 
317  if (m_area->state_changed == 0) {
318  lp->mm->m_state->dirty_bitmap_size += bitmap_size;
319  lp->mm->m_state->dirty_areas++;
320  }
321 
322  m_area->state_changed = 1;
323  m_area->last_access = lvt(current);
324 
325  if (!CHECK_LOG_MODE_BIT(m_area)) {
326  if ((double)m_area->alloc_chunks / (double)m_area->num_chunks > MAX_LOG_THRESHOLD) {
327  SET_LOG_MODE_BIT(m_area);
328  lp->mm->m_state->total_log_size += (m_area->num_chunks - (m_area->alloc_chunks - 1)) * size;
329  } else
330  lp->mm->m_state->total_log_size += size;
331  }
332  //~ int chk_size = m_area->chunk_size;
333  //~ RESET_BIT_AT(chk_size, 0);
334  //~ RESET_BIT_AT(chk_size, 1);
335 
336  m_area->alloc_chunks++;
337  find_next_free(m_area);
338 
339  // TODO: togliere
340  memset(ptr, 0xe8, size);
341 
342  // Keep track of the malloc_area which this chunk belongs to
343  *(unsigned long long *)ptr = (unsigned long long)m_area->self_pointer;
344 
345 #ifndef NDEBUG
346  atomic_dec(&m_area->presence);
347 #endif
348 
349  return (void *)((char *)ptr + sizeof(long long));
350 }
351 
352 void do_free(struct lp_struct *lp, void *ptr)
353 {
354  (void)lp;
355 
356  malloc_area *m_area = NULL;
357  int idx;
358  size_t chunk_size, bitmap_size;
359 
361  rsfree(ptr);
362  return;
363  }
364 
365  if (unlikely(ptr == NULL)) {
366  rootsim_error(false, "Invalid pointer during free\n");
367  return;
368  }
369 
370  m_area = get_area(ptr);
371  if (unlikely(m_area == NULL)) {
372  rootsim_error(false,
373  "Invalid pointer during free: malloc_area NULL\n");
374  return;
375  }
376 #ifndef NDEBUG
377  atomic_inc(&m_area->presence);
378  assert(atomic_read(&m_area->presence) == 1);
379 #endif
380 
381  chunk_size = UNTAGGED_CHUNK_SIZE(m_area);
382 
383  idx = (int)((char *)ptr - (char *)m_area->area) / chunk_size;
384 
385  if (!bitmap_check(m_area->use_bitmap, idx)) {
386  rootsim_error(false, "double free() corruption or address not malloc'd\n");
387  abort();
388  }
389  bitmap_reset(m_area->use_bitmap, idx);
390 
391  bitmap_size = bitmap_required_size(m_area->num_chunks);
392 
393  m_area->alloc_chunks--;
394 
395  if (m_area->alloc_chunks == 0) {
396  lp->mm->m_state->bitmap_size -= bitmap_size;
397  lp->mm->m_state->busy_areas--;
398  }
399 
400  if (m_area->state_changed == 0) {
401  lp->mm->m_state->dirty_bitmap_size += bitmap_size;
402  lp->mm->m_state->dirty_areas++;
403  }
404 
405  if (bitmap_check(m_area->dirty_bitmap, idx)) {
406  bitmap_reset(m_area->dirty_bitmap, idx);
407  m_area->dirty_chunks--;
408 
409  if (m_area->state_changed == 1 && m_area->dirty_chunks == 0)
410  lp->mm->m_state->dirty_bitmap_size -= bitmap_size;
411 
412  lp->mm->m_state->total_inc_size -= chunk_size;
413 
414  if (unlikely(m_area->dirty_chunks < 0)) {
415  rootsim_error(true, "negative number of chunks\n");
416  }
417  }
418 
419  m_area->state_changed = 1;
420 
421  m_area->last_access = lvt(current);
422 
423  if (CHECK_LOG_MODE_BIT(m_area)) {
424  if ((double)m_area->alloc_chunks / (double)m_area->num_chunks < MIN_LOG_THRESHOLD) {
425  RESET_LOG_MODE_BIT(m_area);
426  lp->mm->m_state->total_log_size -= (m_area->num_chunks - m_area->alloc_chunks) * chunk_size;
427  }
428  } else {
429  lp->mm->m_state->total_log_size -= chunk_size;
430  }
431 
432  if (idx < m_area->next_chunk)
433  m_area->next_chunk = idx;
434 
435 #ifndef NDEBUG
436  atomic_dec(&m_area->presence);
437 #endif
438  // TODO: when do we free unrecoverable areas?
439 }
440 
453 void dirty_mem(void *base, int size)
454 {
455 
456  // TODO: Quando reintegriamo l'incrementale questo qui deve ricomparire!
457  (void)base;
458  (void)size;
459 
460  return;
461 
462 #if 0
463 // unsigned long long current_cost;
464 
465  // Sanity check on passed address
466 /* if(base == NULL) {
467  rootsim_error(false, "Trying to access NULL. Memory interception aborted\n");
468  return;
469  }
470 */
471 /* if (rootsim_config.snapshot == AUTONOMIC_SNAPSHOT ||
472  rootsim_config.snapshot == AUTONOMIC_INC_SNAPSHOT ||
473  rootsim_config.snapshot == AUTONOMIC_FULL_SNAPSHOT)
474  add_counter++;
475 */
476  int first_chunk, last_chunk, i, chk_size;
477 
478  size_t bitmap_size;
479 
480  malloc_area *m_area = get_area(base);
481 
482  if (m_area != NULL) {
483 
484  chk_size = UNTAGGED_CHUNK_SIZE(m_area->chunk_size);
485 
486  // Compute the number of chunks affected by the write
487  first_chunk =
488  (int)(((char *)base - (char *)m_area->area) / chk_size);
489 
490  // If size == -1, then we adopt a conservative approach: dirty all the chunks from the base to the end
491  // of the actual malloc area base address belongs to.
492  // This has been inserted to support the wrapping of third-party libraries where the size of the
493  // update (or even the actual update) cannot be statically/dynamically determined.
494  if (size == -1)
495  last_chunk = m_area->num_chunks - 1;
496  else
497  last_chunk = (int)(((char *)base + size - 1 - (char *)m_area->area) / chk_size);
498 
499  bitmap_size = bitmap_required_size(m_area->num_chunks);
500 
501  if (m_area->state_changed == 1) {
502  if (m_area->dirty_chunks == 0)
503  lp->mm->m_state->dirty_bitmap_size += bitmap_size;
504  } else {
505  lp->mm->m_state->dirty_areas++;
506  lp->mm->m_state->dirty_bitmap_size += bitmap_size * 2;
507  m_area->state_changed = 1;
508  }
509 
510  for (i = first_chunk; i <= last_chunk; i++) {
511 
512  // If it is dirtied a clean chunk, set it dirty and increase dirty object count for the malloc_area
513  if (!bitmap_check(m_area->dirty_bitmap, i)) {
514  bitmap_set(m_area->dirty_bitmap, i);
515  lp->mm->m_state->total_inc_size += chk_size;
516 
517  m_area->dirty_chunks++;
518  }
519  }
520  }
521 #endif
522 }
523 
534 size_t get_log_size(malloc_state * logged_state)
535 {
536  if (unlikely(logged_state == NULL))
537  return 0;
538 
539  if (is_incremental(logged_state)) {
540  return sizeof(malloc_state) +
541  logged_state->dirty_areas * sizeof(malloc_area) +
542  logged_state->dirty_bitmap_size +
543  logged_state->total_inc_size;
544  } else {
545  return sizeof(malloc_state) +
546  logged_state->busy_areas * sizeof(malloc_area) +
547  logged_state->bitmap_size + logged_state->total_log_size;
548  }
549 }
550 
566 void *__wrap_malloc(size_t size)
567 {
568  void *ptr;
569 
570  switch_to_platform_mode();
571 
573  ptr = rsalloc(size);
574  goto out;
575  }
576 
577  ptr = do_malloc(current, size);
578 
579  out:
580  switch_to_application_mode();
581  return ptr;
582 }
583 
602 void __wrap_free(void *ptr)
603 {
604  switch_to_platform_mode();
605 
607  rsfree(ptr);
608  goto out;
609  }
610 
611  do_free(current, ptr);
612 
613  out:
614  switch_to_application_mode();
615 }
616 
628 void *__wrap_realloc(void *ptr, size_t size)
629 {
630  void *new_buffer;
631  size_t old_size;
632  size_t copy_size;
633  malloc_area *m_area;
634 
636  return rsrealloc(ptr, size);
637  }
638  // If ptr is NULL realloc is equivalent to the malloc
639  if (unlikely(ptr == NULL)) {
640  return __wrap_malloc(size);
641  }
642  // If ptr is not NULL and the size is 0 realloc is equivalent to the free
643  if (unlikely(size == 0)) {
644  __wrap_free(ptr);
645  return NULL;
646  }
647 
648  m_area = get_area(ptr);
649 
650  // The size could be greater than the real request, but it does not matter since the realloc specific requires that
651  // is copied at least the smaller buffer size between the new and the old one
652  old_size = UNTAGGED_CHUNK_SIZE(m_area);
653 
654  new_buffer = __wrap_malloc(size);
655 
656  if (unlikely(new_buffer == NULL))
657  return NULL;
658 
659  copy_size = min(size, old_size);
660  memcpy(new_buffer, ptr, copy_size);
661  __wrap_free(ptr);
662 
663  return new_buffer;
664 }
665 
677 void *__wrap_calloc(size_t nmemb, size_t size)
678 {
679  void *buffer;
680 
682  return rscalloc(nmemb, size);
683  }
684 
685  if (unlikely(nmemb == 0 || size == 0))
686  return NULL;
687 
688  buffer = __wrap_malloc(nmemb * size);
689  if (unlikely(buffer == NULL))
690  return NULL;
691 
692  bzero(buffer, nmemb * size);
693 
694  return buffer;
695 }
696 
697 void clean_buffers_on_gvt(struct lp_struct *lp, simtime_t time_barrier)
698 {
699  int i;
700  malloc_area *m_area;
701  malloc_state *state = lp->mm->m_state;
702 
703  // The first NUM_AREAS malloc_areas are placed according to their chunks' sizes. The exceeding malloc_areas can be compacted
704  for (i = NUM_AREAS; i < state->num_areas; i++) {
705  m_area = &state->areas[i];
706 
707  if (m_area->alloc_chunks == 0
708  && m_area->last_access < time_barrier
709  && !CHECK_AREA_LOCK_BIT(m_area)) {
710 
711  if (m_area->self_pointer != NULL) {
712 
713  //free_lp_memory(lp, m_area->self_pointer);
714  rsfree(m_area->self_pointer);
715 
716  m_area->use_bitmap = NULL;
717  m_area->dirty_bitmap = NULL;
718  m_area->self_pointer = NULL;
719  m_area->area = NULL;
720  m_area->state_changed = 0;
721 
722  // Set the pointers
723  if (m_area->prev != -1)
724  state->areas[m_area->prev].next = m_area->next;
725  if (m_area->next != -1)
726  state->areas[m_area->next].prev = m_area->prev;
727 
728  // Swap, if possible
729  if (i < state->num_areas - 1) {
730  memcpy(m_area, &state->areas[state->num_areas - 1], sizeof(malloc_area));
731  m_area->idx = i;
732  if (m_area->prev != -1)
733  state->areas[m_area->prev].next = m_area->idx;
734  if (m_area->next != -1)
735  state->areas[m_area->next].prev = m_area->idx;
736 
737  // Update the self pointer
738  *(long long *)m_area->self_pointer = (long long)m_area;
739 
740  // The swapped area will now be checked
741  i--;
742  }
743  // Decrement the expected number of areas
744  state->num_areas--;
745  }
746  }
747  }
748 }
#define lvt(lp)
Definition: process.h:168
Initialization routines.
#define bitmap_set(bitmap, bit_index)
This sets the bit with index bit_index of the bitmap bitmap.
Definition: bitmap.h:116
#define min(a, b)
Macro to find the minimum among two values.
Definition: core.h:115
static size_t compute_size(size_t size)
Definition: dymelor.c:136
void * do_malloc(struct lp_struct *lp, size_t size)
Definition: dymelor.c:172
#define atomic_read(v)
Read operation on an atomic counter.
Definition: atomic.h:66
#define bitmap_required_size(requested_bits)
Computes the required size of a bitmap with requested_bits entries.
Definition: bitmap.h:92
void dirty_mem(void *base, int size)
Definition: dymelor.c:453
void atomic_dec(atomic_t *)
Definition: x86.c:103
void * __wrap_calloc(size_t nmemb, size_t size)
Definition: dymelor.c:677
The ROOT-Sim scheduler main module header.
#define bitmap_reset(bitmap, bit_index)
This resets the bit with index bit_index of the bitmap bitmap.
Definition: bitmap.h:125
struct memory_map * mm
Memory map of the LP.
Definition: process.h:76
__thread struct lp_struct * current
This is a per-thread variable pointing to the block state of the LP currently scheduled.
Definition: scheduler.c:72
void __wrap_free(void *ptr)
Definition: dymelor.c:602
bool is_incremental
Tells if it is an incremental log or a full one (when used for logging)
Definition: dymelor.h:120
#define atomic_set(v, i)
Set operation on an atomic counter.
Definition: atomic.h:69
double simtime_t
This defines the type with whom timestamps are represented.
Definition: ROOT-Sim.h:55
simulation_configuration rootsim_config
This global variable holds the configuration for the current simulation.
Definition: core.c:70
static void malloc_area_init(malloc_area *m_area, size_t size, int num_chunks)
Definition: dymelor.c:49
Memory Manager main header.
static void find_next_free(malloc_area *m_area)
Definition: dymelor.c:159
#define bitmap_check(bitmap, bit_index)
This checks if the bit with index bit_index of the bitmap bitmap is set or unset. ...
Definition: bitmap.h:135
void * __wrap_realloc(void *ptr, size_t size)
Definition: dymelor.c:628
Definition of the memory map.
Definition: dymelor.h:119
size_t get_log_size(malloc_state *logged_state)
Definition: dymelor.c:534
malloc_state * malloc_state_init(void)
Definition: dymelor.c:77
void * __wrap_malloc(size_t size)
Definition: dymelor.c:566
bool serial
If the simulation must be run serially.
Definition: init.h:72
void atomic_inc(atomic_t *)
Definition: x86.c:90
#define unlikely(exp)
Optimize the branch as likely not taken.
Definition: core.h:74
This structure let DyMeLoR handle one malloc area (for serving given-size memory requests) ...
Definition: dymelor.h:96