1
2
3
4
5
6
7
8
9
10
11
12#include <string.h>
13#include <glib.h>
14#include <assert.h>
15#include "qemu/osdep.h"
16#include "qemu/hbitmap.h"
17#include "qemu/host-utils.h"
18#include "trace.h"
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57struct HBitmap {
58
59 uint64_t size;
60
61
62 uint64_t count;
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 int granularity;
83
84
85
86
87
88
89
90
91
92 unsigned long *levels[HBITMAP_LEVELS];
93};
94
95static inline int popcountl(unsigned long l)
96{
97 return BITS_PER_LONG == 32 ? ctpop32(l) : ctpop64(l);
98}
99
100
101
102
103unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi)
104{
105 size_t pos = hbi->pos;
106 const HBitmap *hb = hbi->hb;
107 unsigned i = HBITMAP_LEVELS - 1;
108
109 unsigned long cur;
110 do {
111 cur = hbi->cur[--i];
112 pos >>= BITS_PER_LEVEL;
113 } while (cur == 0);
114
115
116
117
118
119
120
121 if (i == 0 && cur == (1UL << (BITS_PER_LONG - 1))) {
122 return 0;
123 }
124 for (; i < HBITMAP_LEVELS - 1; i++) {
125
126
127
128
129 assert(cur);
130 pos = (pos << BITS_PER_LEVEL) + ctzl(cur);
131 hbi->cur[i] = cur & (cur - 1);
132
133
134 cur = hb->levels[i + 1][pos];
135 }
136
137 hbi->pos = pos;
138 trace_hbitmap_iter_skip_words(hbi->hb, hbi, pos, cur);
139
140 assert(cur);
141 return cur;
142}
143
144void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first)
145{
146 unsigned i, bit;
147 uint64_t pos;
148
149 hbi->hb = hb;
150 pos = first >> hb->granularity;
151 assert(pos < hb->size);
152 hbi->pos = pos >> BITS_PER_LEVEL;
153 hbi->granularity = hb->granularity;
154
155 for (i = HBITMAP_LEVELS; i-- > 0; ) {
156 bit = pos & (BITS_PER_LONG - 1);
157 pos >>= BITS_PER_LEVEL;
158
159
160 hbi->cur[i] = hb->levels[i][pos] & ~((1UL << bit) - 1);
161
162
163
164
165 if (i != HBITMAP_LEVELS - 1) {
166 hbi->cur[i] &= ~(1UL << bit);
167 }
168 }
169}
170
171bool hbitmap_empty(const HBitmap *hb)
172{
173 return hb->count == 0;
174}
175
176int hbitmap_granularity(const HBitmap *hb)
177{
178 return hb->granularity;
179}
180
181uint64_t hbitmap_count(const HBitmap *hb)
182{
183 return hb->count << hb->granularity;
184}
185
186
187
188
189static uint64_t hb_count_between(HBitmap *hb, uint64_t start, uint64_t last)
190{
191 HBitmapIter hbi;
192 uint64_t count = 0;
193 uint64_t end = last + 1;
194 unsigned long cur;
195 size_t pos;
196
197 hbitmap_iter_init(&hbi, hb, start << hb->granularity);
198 for (;;) {
199 pos = hbitmap_iter_next_word(&hbi, &cur);
200 if (pos >= (end >> BITS_PER_LEVEL)) {
201 break;
202 }
203 count += popcountl(cur);
204 }
205
206 if (pos == (end >> BITS_PER_LEVEL)) {
207
208 int bit = end & (BITS_PER_LONG - 1);
209 cur &= (1UL << bit) - 1;
210 count += popcountl(cur);
211 }
212
213 return count;
214}
215
216
217
218
219static inline bool hb_set_elem(unsigned long *elem, uint64_t start, uint64_t last)
220{
221 unsigned long mask;
222 bool changed;
223
224 assert((last >> BITS_PER_LEVEL) == (start >> BITS_PER_LEVEL));
225 assert(start <= last);
226
227 mask = 2UL << (last & (BITS_PER_LONG - 1));
228 mask -= 1UL << (start & (BITS_PER_LONG - 1));
229 changed = (*elem == 0);
230 *elem |= mask;
231 return changed;
232}
233
234
235static void hb_set_between(HBitmap *hb, int level, uint64_t start, uint64_t last)
236{
237 size_t pos = start >> BITS_PER_LEVEL;
238 size_t lastpos = last >> BITS_PER_LEVEL;
239 bool changed = false;
240 size_t i;
241
242 i = pos;
243 if (i < lastpos) {
244 uint64_t next = (start | (BITS_PER_LONG - 1)) + 1;
245 changed |= hb_set_elem(&hb->levels[level][i], start, next - 1);
246 for (;;) {
247 start = next;
248 next += BITS_PER_LONG;
249 if (++i == lastpos) {
250 break;
251 }
252 changed |= (hb->levels[level][i] == 0);
253 hb->levels[level][i] = ~0UL;
254 }
255 }
256 changed |= hb_set_elem(&hb->levels[level][i], start, last);
257
258
259
260
261 if (level > 0 && changed) {
262 hb_set_between(hb, level - 1, pos, lastpos);
263 }
264}
265
266void hbitmap_set(HBitmap *hb, uint64_t start, uint64_t count)
267{
268
269 uint64_t last = start + count - 1;
270
271 trace_hbitmap_set(hb, start, count,
272 start >> hb->granularity, last >> hb->granularity);
273
274 start >>= hb->granularity;
275 last >>= hb->granularity;
276 count = last - start + 1;
277
278 hb->count += count - hb_count_between(hb, start, last);
279 hb_set_between(hb, HBITMAP_LEVELS - 1, start, last);
280}
281
282
283
284
285static inline bool hb_reset_elem(unsigned long *elem, uint64_t start, uint64_t last)
286{
287 unsigned long mask;
288 bool blanked;
289
290 assert((last >> BITS_PER_LEVEL) == (start >> BITS_PER_LEVEL));
291 assert(start <= last);
292
293 mask = 2UL << (last & (BITS_PER_LONG - 1));
294 mask -= 1UL << (start & (BITS_PER_LONG - 1));
295 blanked = *elem != 0 && ((*elem & ~mask) == 0);
296 *elem &= ~mask;
297 return blanked;
298}
299
300
301static void hb_reset_between(HBitmap *hb, int level, uint64_t start, uint64_t last)
302{
303 size_t pos = start >> BITS_PER_LEVEL;
304 size_t lastpos = last >> BITS_PER_LEVEL;
305 bool changed = false;
306 size_t i;
307
308 i = pos;
309 if (i < lastpos) {
310 uint64_t next = (start | (BITS_PER_LONG - 1)) + 1;
311
312
313
314
315
316
317 if (hb_reset_elem(&hb->levels[level][i], start, next - 1)) {
318 changed = true;
319 } else {
320 pos++;
321 }
322
323 for (;;) {
324 start = next;
325 next += BITS_PER_LONG;
326 if (++i == lastpos) {
327 break;
328 }
329 changed |= (hb->levels[level][i] != 0);
330 hb->levels[level][i] = 0UL;
331 }
332 }
333
334
335 if (hb_reset_elem(&hb->levels[level][i], start, last)) {
336 changed = true;
337 } else {
338 lastpos--;
339 }
340
341 if (level > 0 && changed) {
342 hb_reset_between(hb, level - 1, pos, lastpos);
343 }
344}
345
346void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count)
347{
348
349 uint64_t last = start + count - 1;
350
351 trace_hbitmap_reset(hb, start, count,
352 start >> hb->granularity, last >> hb->granularity);
353
354 start >>= hb->granularity;
355 last >>= hb->granularity;
356
357 hb->count -= hb_count_between(hb, start, last);
358 hb_reset_between(hb, HBITMAP_LEVELS - 1, start, last);
359}
360
361bool hbitmap_get(const HBitmap *hb, uint64_t item)
362{
363
364 uint64_t pos = item >> hb->granularity;
365 unsigned long bit = 1UL << (pos & (BITS_PER_LONG - 1));
366
367 return (hb->levels[HBITMAP_LEVELS - 1][pos >> BITS_PER_LEVEL] & bit) != 0;
368}
369
370void hbitmap_free(HBitmap *hb)
371{
372 unsigned i;
373 for (i = HBITMAP_LEVELS; i-- > 0; ) {
374 g_free(hb->levels[i]);
375 }
376 g_free(hb);
377}
378
379HBitmap *hbitmap_alloc(uint64_t size, int granularity)
380{
381 HBitmap *hb = g_malloc0(sizeof (struct HBitmap));
382 unsigned i;
383
384 assert(granularity >= 0 && granularity < 64);
385 size = (size + (1ULL << granularity) - 1) >> granularity;
386 assert(size <= ((uint64_t)1 << HBITMAP_LOG_MAX_SIZE));
387
388 hb->size = size;
389 hb->granularity = granularity;
390 for (i = HBITMAP_LEVELS; i-- > 0; ) {
391 size = MAX((size + BITS_PER_LONG - 1) >> BITS_PER_LEVEL, 1);
392 hb->levels[i] = g_malloc0(size * sizeof(unsigned long));
393 }
394
395
396
397
398
399 assert(size == 1);
400 hb->levels[0][0] |= 1UL << (BITS_PER_LONG - 1);
401 return hb;
402}
403