The ROme OpTimistic Simulator  2.0.0
A General-Purpose Multithreaded Parallel/Distributed Simulation Platform
buddy.c
Go to the documentation of this file.
1 
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <limits.h>
32 
33 #include <mm/dymelor.h>
34 #include <mm/mm.h>
35 #include <datatypes/bitmap.h>
36 
37 static inline int left_child(int i)
38 {
39  return ((i << 1) + 1);
40 }
41 
42 static inline int right_child(int i)
43 {
44  return ((i << 1) + 2);
45 }
46 
47 static inline int parent(int i)
48 {
49  return (((i + 1) >> 1) - 1);
50 }
51 
52 static inline bool is_power_of_2(size_t i)
53 {
54  return !(i & (i - 1));
55 }
56 
57 static inline size_t next_power_of_2(size_t size)
58 {
59  size--;
60  size |= (size >> 1);
61  size |= (size >> 2);
62  size |= (size >> 4);
63  size |= (size >> 8);
64  size |= (size >> 16);
65  size |= (size >> 32);
66  return size + 1;
67 }
68 
69 
75 struct buddy *buddy_new(size_t requested_size)
76 {
77  if (!requested_size) {
78  return NULL;
79  }
80 
81  size_t fragments = (requested_size >> BUDDY_BLOCK_SIZE_EXP) + (B_CTZ(requested_size) < BUDDY_BLOCK_SIZE_EXP);
82  size_t nodes = 2 * fragments - 1;
83  struct buddy *self = rsalloc(sizeof(struct buddy) + nodes * sizeof(size_t));
84 
85  spinlock_init(&self->lock);
86  self->size = fragments;
87 
88  size_t i, node_size = fragments << 1; // little hack to have a correct iteration at i == 0
89  for (i = 0; i < nodes; i++) {
90  if (is_power_of_2(i + 1)) {
91  node_size >>= 1;
92  }
93  self->longest[i] = node_size;
94  }
95  return self;
96 }
97 
98 void buddy_destroy(struct buddy *self)
99 {
100  rsfree(self);
101 }
102 
105 static size_t buddy_alloc(struct buddy *self, size_t requested_blocks)
106 {
107  // some sanity checks are run in the parent function allocate_buddy_memory()
108  requested_blocks = next_power_of_2(requested_blocks);
109  spin_lock(&self->lock);
110 
111  if (self->longest[0] < requested_blocks) {
112  spin_unlock(&self->lock);
113  return SIZE_MAX;
114  }
115 
116  /* search recursively for the child */
117  int i = 0;
118  size_t node_size;
119  for (node_size = self->size; node_size > requested_blocks; node_size >>= 1) {
120  /* choose the child with smaller longest value which is still large at least *size* */
121  if (self->longest[left_child(i)] >= requested_blocks) {
122  i = left_child(i);
123  } else {
124  i = right_child(i);
125  }
126  }
127 
128  /* update the *longest* value back */
129  self->longest[i] = 0;
130 
131  size_t offset = (i + 1) * node_size - self->size;
132 
133  while (i) {
134  i = parent(i);
135  self->longest[i] = max(self->longest[left_child(i)], self->longest[right_child(i)]);
136  }
137  spin_unlock(&self->lock);
138  return offset;
139 }
140 
141 static void buddy_free(struct buddy *self, size_t offset)
142 {
143  // some sanity checks are run in the parent function free_buddy_memory()
144  size_t node_size = 1;
145  int i = offset + self->size - 1;
146 
147  spin_lock(&self->lock);
148 
149  for (; i && self->longest[i]; i = parent(i)) {
150  node_size <<= 1;
151  }
152 
153  self->longest[i] = node_size;
154 
155  while (i) {
156  i = parent(i);
157  node_size <<= 1;
158 
159  size_t left_longest = self->longest[left_child(i)];
160  size_t right_longest = self->longest[right_child(i)];
161 
162  if (left_longest + right_longest == node_size) {
163  self->longest[i] = node_size;
164  } else {
165  self->longest[i] = max(left_longest, right_longest);
166  }
167  }
168  spin_unlock(&self->lock);
169 }
170 
171 void* allocate_buddy_memory(struct buddy* self, void* base_mem, size_t requested_size)
172 {
173  if (unlikely(!requested_size || self == NULL))
174  return NULL;
175 
176  size_t requested_blocks = (requested_size >> BUDDY_BLOCK_SIZE_EXP) + (B_CTZ(requested_size) < BUDDY_BLOCK_SIZE_EXP);
177  if (unlikely(requested_blocks > self->size))
178  return NULL;
179 
180  size_t offset = buddy_alloc(self, requested_blocks);
181  if(unlikely(offset == SIZE_MAX))
182  return NULL;
183 
184  return (char *)base_mem + (offset << BUDDY_BLOCK_SIZE_EXP);
185 }
186 
187 void free_buddy_memory(struct buddy *self, void *base_mem, void *ptr)
188 {
189  if (unlikely(self == NULL))
190  return;
191 
192  size_t offset = ((char *)ptr - (char *)base_mem) >> BUDDY_BLOCK_SIZE_EXP;
193  if(unlikely(offset >= self->size))
194  return;
195 
196  buddy_free(self, offset);
197 }
#define spinlock_init(s)
Spinlock initialization.
Definition: atomic.h:72
static size_t buddy_alloc(struct buddy *self, size_t requested_blocks)
Definition: buddy.c:105
Dynamic Memory Logger and Restorer (DyMeLoR)
Definition: dymelor.h:208
Memory Manager main header.
void spin_lock(spinlock_t *s)
Definition: x86.c:135
#define max(a, b)
Macro to find the maximum among two values.
Definition: core.h:106
Bitmap data type.
#define unlikely(exp)
Optimize the branch as likely not taken.
Definition: core.h:74
struct buddy * buddy_new(size_t requested_size)
Definition: buddy.c:75
void spin_unlock(spinlock_t *s)
Definition: x86.c:161