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 <stdio.h>
31 #include <stdlib.h>
32 #include <sys/mman.h>
33 #include <errno.h>
34 
35 #include <core/core.h>
36 #include <mm/mm.h>
37 #include <scheduler/process.h>
38 
39 static inline int left_child(int index)
40 {
41  /* index * 2 + 1 */
42  return ((index << 1) + 1);
43 }
44 
45 static inline int right_child(int index)
46 {
47  /* index * 2 + 2 */
48  return ((index << 1) + 2);
49 }
50 
51 static inline int parent(int index)
52 {
53  /* (index+1)/2 - 1 */
54  return (((index + 1) >> 1) - 1);
55 }
56 
57 static inline bool is_power_of_2(int index)
58 {
59  return !(index & (index - 1));
60 }
61 
62 static inline size_t next_power_of_2(size_t size)
63 {
64  /* depend on the fact that size < 2^32 */
65  size |= (size >> 1);
66  size |= (size >> 2);
67  size |= (size >> 4);
68  size |= (size >> 8);
69  size |= (size >> 16);
70  return size + 1;
71 }
72 
78 struct buddy *buddy_new(struct lp_struct *lp, size_t num_of_fragments)
79 {
80  struct buddy *self = NULL;
81  size_t node_size;
82  int i;
83 
84  if (num_of_fragments < 1 || !is_power_of_2(num_of_fragments)) {
85  return NULL;
86  }
87 
88  /* alloacte an array to represent a complete binary tree */
89  (void)lp;
90  //self = (struct buddy *)get_segment_memory(lp, sizeof(struct buddy) + 2 * num_of_fragments * sizeof(size_t));
91  self = (struct buddy *)rsalloc(sizeof(struct buddy) + 2 * num_of_fragments * sizeof(size_t));
92  bzero(self, sizeof(struct buddy) + 2 * num_of_fragments * sizeof(size_t)); // unnecessary, it is later initialized
93 
94  self->size = num_of_fragments;
95  node_size = num_of_fragments * 2;
96 
97  /* initialize *longest* array for buddy structure */
98  int iter_end = num_of_fragments * 2 - 1;
99  for (i = 0; i < iter_end; i++) {
100  if (is_power_of_2(i + 1)) {
101  node_size >>= 1;
102  }
103  self->longest[i] = node_size;
104  }
105 
106  spinlock_init(&self->lock);
107 
108  return self;
109 }
110 
111 void buddy_destroy(struct buddy *self)
112 {
113  rsfree(self);
114 }
115 
118 int buddy_alloc(struct buddy *self, size_t size)
119 {
120  if (self == NULL || self->size <= size) {
121  return -1;
122  }
123 
124  size = next_power_of_2(size);
125 
126  size_t index = 0;
127  if (self->longest[index] < size) {
128  return -1;
129  }
130 
131  /* search recursively for the child */
132  size_t node_size = 0;
133  for (node_size = self->size; node_size != size; node_size >>= 1) {
134  /* choose the child with smaller longest value which is still larger
135  * than *size* */
136  if (self->longest[left_child(index)] >= size) {
137  index = left_child(index);
138  } else {
139  index = right_child(index);
140  }
141  }
142 
143  /* update the *longest* value back */
144  self->longest[index] = 0;
145  int offset = (index + 1) * node_size - self->size;
146 
147  while (index) {
148  index = parent(index);
149  self->longest[index] = max(self->longest[left_child(index)], self->longest[right_child(index)]);
150  }
151 
152  return offset;
153 }
154 
155 void buddy_free(struct buddy *self, size_t offset)
156 {
157  if (self == NULL || offset >= self->size) {
158  return;
159  }
160 
161  size_t node_size;
162  size_t index;
163 
164  /* get the corresponding index from offset */
165  node_size = 1;
166  index = offset + self->size - 1;
167 
168  for (; self->longest[index] != 0; index = parent(index)) {
169  node_size <<= 1;
170 
171  if (index == 0) {
172  break;
173  }
174  }
175 
176  self->longest[index] = node_size;
177 
178  while (index) {
179  index = parent(index);
180  node_size <<= 1;
181 
182  size_t left_longest = self->longest[left_child(index)];
183  size_t right_longest = self->longest[right_child(index)];
184 
185  if (left_longest + right_longest == node_size) {
186  self->longest[index] = node_size;
187  } else {
188  self->longest[index] = max(left_longest, right_longest);
189  }
190  }
191 }
192 
193 void *allocate_lp_memory(struct lp_struct *lp, size_t size)
194 {
195  long long offset, displacement;
196  size_t fragments;
197 
198  if (size == 0)
199  return NULL;
200 
201  // Get a number of fragments to contain 'size' bytes
202  // The operation involves a fast positive integer round up.
203  // The buddy can be accessed by multiple threads, so lock it
204  fragments = 1 + ((size - 1) / BUDDY_GRANULARITY);
205  spin_lock(&lp->mm->buddy->lock);
206  offset = buddy_alloc(lp->mm->buddy, fragments);
207  spin_unlock(&lp->mm->buddy->lock);
208  displacement = offset * BUDDY_GRANULARITY;
209 
210  if (unlikely(offset == -1))
211  return NULL;
212 
213  return (void *)((char *)lp->mm->segment->base + displacement);
214 }
215 
216 void free_lp_memory(struct lp_struct *lp, void *ptr)
217 {
218  size_t displacement;
219 
220  displacement = (int)((char *)ptr - (char *)lp->mm->segment->base);
221  spin_lock(&lp->mm->buddy->lock);
222  buddy_free(lp->mm->buddy, displacement);
223  spin_unlock(&lp->mm->buddy->lock);
224 }
#define spinlock_init(s)
Spinlock initialization.
Definition: atomic.h:72
Core ROOT-Sim functionalities.
struct memory_map * mm
Memory map of the LP.
Definition: process.h:76
Definition: mm.h:44
Memory Manager main header.
void spin_lock(spinlock_t *s)
Definition: x86.c:135
struct buddy * buddy_new(struct lp_struct *lp, size_t num_of_fragments)
Definition: buddy.c:78
LP control blocks.
#define max(a, b)
Macro to find the maximum among two values.
Definition: core.h:106
int buddy_alloc(struct buddy *self, size_t size)
Definition: buddy.c:118
#define unlikely(exp)
Optimize the branch as likely not taken.
Definition: core.h:74
void spin_unlock(spinlock_t *s)
Definition: x86.c:161