source: mainline/kernel/generic/src/adt/bitmap.c@ 64f3d3b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 64f3d3b was 64f3d3b, checked in by Martin Decky <martin@…>, 12 years ago

basic optimizations of the bitmap allocator
(still not using the 2nd level bitmap)

  • Property mode set to 100644
File size: 10.8 KB
RevLine 
[97a7eff]1/*
[df4ed85]2 * Copyright (c) 2006 Jakub Jermar
[97a7eff]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[cc73a8a1]29/** @addtogroup genericadt
[b45c443]30 * @{
31 */
[9179d0a]32/**
[7257021e]33 * @file
[da88a079]34 * @brief Implementation of bitmap ADT.
[9179d0a]35 *
36 * This file implements bitmap ADT and provides functions for
[7de18418]37 * setting and clearing ranges of bits and for finding ranges
38 * of unset bits.
39 *
40 * The bitmap ADT can optionally implement a two-level hierarchy
41 * for faster range searches. The second level bitmap (of blocks)
42 * is not precise, but conservative. This means that if the block
43 * bit is set, it guarantees that all bits in the block are set.
44 * But if the block bit is unset, nothing can be said about the
45 * bits in the block.
46 *
[9179d0a]47 */
48
[97a7eff]49#include <adt/bitmap.h>
[d99c1d2]50#include <typedefs.h>
[97a7eff]51#include <align.h>
52#include <debug.h>
[4fd61ba]53#include <macros.h>
[97a7eff]54
[7de18418]55#define ALL_ONES 0xff
56#define ALL_ZEROES 0x00
[97a7eff]57
[64f3d3b]58/** Compute the size of a bitmap
59 *
60 * Compute the size of a bitmap that can store given number
61 * of elements.
62 *
63 * @param elements Number of elements to store.
64 *
65 * @return Size of the bitmap (in units of BITMAP_ELEMENT bits).
66 *
67 */
68static size_t bitmap_bytes(size_t elements)
69{
70 size_t bytes = elements / BITMAP_ELEMENT;
71
72 if ((elements % BITMAP_ELEMENT) != 0)
73 bytes++;
74
75 return bytes;
76}
77
78/** Compute the number of 2nd level blocks
79 *
80 * Compute the number of 2nd level blocks for a given number
81 * of elements.
82 *
83 * @param elements Number of elements.
84 * @param block_size Number of elements in one block.
85 *
86 * @return Number of 2nd level blocks.
87 * @return Zero if block_size is zero.
88 *
89 */
90static size_t bitmap_blocks(size_t elements, size_t block_size)
91{
92 if (block_size == 0)
93 return 0;
94
95 size_t blocks = elements / block_size;
96
97 if ((elements % block_size) != 0)
98 blocks++;
99
100 return blocks;
101}
102
103/** Unchecked version of bitmap_get()
104 *
105 * This version of bitmap_get() does not do any boundary checks.
106 *
107 * @param bitmap Bitmap to access.
108 * @param element Element to access.
109 *
110 * @return Bit value of the element in the bitmap.
111 *
112 */
113static unsigned int bitmap_get_fast(bitmap_t *bitmap, size_t element)
114{
115 return !!((bitmap->bits)[element / BITMAP_ELEMENT] &
116 (1 << (element & BITMAP_REMAINER)));
117}
118
[7de18418]119/** Get bitmap size
[97a7eff]120 *
[7de18418]121 * Return the size (in bytes) required for the bitmap.
122 *
123 * @param elements Number bits stored in bitmap.
124 * @param block_size Block size of the 2nd level bitmap.
125 * If set to zero, no 2nd level is used.
126 *
127 * @return Size (in bytes) required for the bitmap.
[97a7eff]128 *
129 */
[7de18418]130size_t bitmap_size(size_t elements, size_t block_size)
[97a7eff]131{
[64f3d3b]132 size_t blocks = bitmap_blocks(elements, block_size);
[7de18418]133
[64f3d3b]134 return (bitmap_bytes(elements) + bitmap_bytes(blocks));
[97a7eff]135}
136
[7de18418]137/** Initialize bitmap.
138 *
139 * No portion of the bitmap is set or cleared by this function.
140 *
141 * @param bitmap Bitmap structure.
142 * @param elements Number of bits stored in bitmap.
143 * @param block_size Block size of the 2nd level bitmap.
144 * If set to zero, no 2nd level is used.
145 * @param data Address of the memory used to hold the map.
146 * The optional 2nd level bitmap follows the 1st
147 * level bitmap.
[97a7eff]148 *
149 */
[7de18418]150void bitmap_initialize(bitmap_t *bitmap, size_t elements, size_t block_size,
151 void *data)
[97a7eff]152{
[7de18418]153 bitmap->elements = elements;
154 bitmap->bits = (uint8_t *) data;
[97a7eff]155
[7de18418]156 if (block_size > 0) {
157 bitmap->block_size = block_size;
158 bitmap->blocks = bitmap->bits +
159 bitmap_size(elements, 0);
160 } else {
161 bitmap->block_size = 0;
162 bitmap->blocks = NULL;
163 }
164}
165
166static void bitmap_set_range_internal(uint8_t *bits, size_t start, size_t count)
167{
168 if (count == 0)
169 return;
[97a7eff]170
[7de18418]171 size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
[97a7eff]172
[7de18418]173 /* Leading unaligned bits */
174 size_t lub = min(aligned_start - start, count);
175
176 /* Aligned middle bits */
177 size_t amb = (count > lub) ? (count - lub) : 0;
178
179 /* Trailing aligned bits */
180 size_t tab = amb % BITMAP_ELEMENT;
181
182 if (start + count < aligned_start) {
[10285ad]183 /* Set bits in the middle of byte. */
[7de18418]184 bits[start / BITMAP_ELEMENT] |=
185 ((1 << lub) - 1) << (start & BITMAP_REMAINER);
[10285ad]186 return;
187 }
188
[97a7eff]189 if (lub) {
[da88a079]190 /* Make sure to set any leading unaligned bits. */
[7de18418]191 bits[start / BITMAP_ELEMENT] |=
192 ~((1 << (BITMAP_ELEMENT - lub)) - 1);
[97a7eff]193 }
[7de18418]194
195 size_t i;
196
197 for (i = 0; i < amb / BITMAP_ELEMENT; i++) {
[da88a079]198 /* The middle bits can be set byte by byte. */
[7de18418]199 bits[aligned_start / BITMAP_ELEMENT + i] = ALL_ONES;
[97a7eff]200 }
[7de18418]201
[4fd61ba]202 if (tab) {
[da88a079]203 /* Make sure to set any trailing aligned bits. */
[7de18418]204 bits[aligned_start / BITMAP_ELEMENT + i] |= (1 << tab) - 1;
[97a7eff]205 }
206}
207
[7de18418]208/** Set range of bits.
209 *
210 * @param bitmap Bitmap structure.
211 * @param start Starting bit.
212 * @param count Number of bits to set.
[97a7eff]213 *
214 */
[7de18418]215void bitmap_set_range(bitmap_t *bitmap, size_t start, size_t count)
[97a7eff]216{
[7de18418]217 ASSERT(start + count <= bitmap->elements);
218
219 bitmap_set_range_internal(bitmap->bits, start, count);
220
221 if (bitmap->block_size > 0) {
222 size_t aligned_start = ALIGN_UP(start, bitmap->block_size);
223
224 /* Leading unaligned bits */
225 size_t lub = min(aligned_start - start, count);
226
227 /* Aligned middle bits */
228 size_t amb = (count > lub) ? (count - lub) : 0;
229
230 size_t aligned_size = amb / bitmap->block_size;
231
232 bitmap_set_range_internal(bitmap->blocks, aligned_start,
233 aligned_size);
234 }
235}
[4fd61ba]236
[7de18418]237static void bitmap_clear_range_internal(uint8_t *bits, size_t start,
238 size_t count)
239{
240 if (count == 0)
[4fe18151]241 return;
[7de18418]242
243 size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
244
245 /* Leading unaligned bits */
246 size_t lub = min(aligned_start - start, count);
247
248 /* Aligned middle bits */
249 size_t amb = (count > lub) ? (count - lub) : 0;
250
251 /* Trailing aligned bits */
252 size_t tab = amb % BITMAP_ELEMENT;
253
254 if (start + count < aligned_start) {
[10285ad]255 /* Set bits in the middle of byte */
[7de18418]256 bits[start / BITMAP_ELEMENT] &=
257 ~(((1 << lub) - 1) << (start & BITMAP_REMAINER));
[10285ad]258 return;
259 }
[7de18418]260
[97a7eff]261 if (lub) {
[da88a079]262 /* Make sure to clear any leading unaligned bits. */
[7de18418]263 bits[start / BITMAP_ELEMENT] &=
264 (1 << (BITMAP_ELEMENT - lub)) - 1;
[97a7eff]265 }
[7de18418]266
267 size_t i;
268
269 for (i = 0; i < amb / BITMAP_ELEMENT; i++) {
[da88a079]270 /* The middle bits can be cleared byte by byte. */
[7de18418]271 bits[aligned_start / BITMAP_ELEMENT + i] = ALL_ZEROES;
[97a7eff]272 }
[7de18418]273
[4fd61ba]274 if (tab) {
[da88a079]275 /* Make sure to clear any trailing aligned bits. */
[7de18418]276 bits[aligned_start / BITMAP_ELEMENT + i] &= ~((1 << tab) - 1);
[97a7eff]277 }
[7de18418]278}
[4fd61ba]279
[7de18418]280/** Clear range of bits.
281 *
282 * @param bitmap Bitmap structure.
283 * @param start Starting bit.
284 * @param count Number of bits to clear.
285 *
286 */
287void bitmap_clear_range(bitmap_t *bitmap, size_t start, size_t count)
288{
289 ASSERT(start + count <= bitmap->elements);
290
291 bitmap_clear_range_internal(bitmap->bits, start, count);
292
293 if (bitmap->block_size > 0) {
294 size_t aligned_start = start / bitmap->block_size;
295
296 size_t aligned_end = (start + count) / bitmap->block_size;
297
298 if (((start + count) % bitmap->block_size) != 0)
299 aligned_end++;
300
301 size_t aligned_size = aligned_end - aligned_start;
302
303 bitmap_clear_range_internal(bitmap->blocks, aligned_start,
304 aligned_size);
305 }
[97a7eff]306}
307
308/** Copy portion of one bitmap into another bitmap.
309 *
[7de18418]310 * @param dst Destination bitmap.
311 * @param src Source bitmap.
312 * @param count Number of bits to copy.
313 *
[97a7eff]314 */
[7de18418]315void bitmap_copy(bitmap_t *dst, bitmap_t *src, size_t count)
[97a7eff]316{
[7de18418]317 ASSERT(count <= dst->elements);
318 ASSERT(count <= src->elements);
[97a7eff]319
[7de18418]320 size_t i;
[97a7eff]321
[7de18418]322 for (i = 0; i < count / BITMAP_ELEMENT; i++)
323 dst->bits[i] = src->bits[i];
[97a7eff]324
[7de18418]325 if (count % BITMAP_ELEMENT) {
326 bitmap_clear_range(dst, i * BITMAP_ELEMENT,
327 count % BITMAP_ELEMENT);
328 dst->bits[i] |= src->bits[i] &
329 ((1 << (count % BITMAP_ELEMENT)) - 1);
[97a7eff]330 }
331}
[b45c443]332
[86733f3]333static int constraint_satisfy(size_t index, size_t base, size_t constraint)
334{
335 return (((base + index) & constraint) == 0);
336}
337
338/** Find a continuous zero bit range
339 *
340 * Find a continuous zero bit range in the bitmap. The address
341 * computed as the sum of the index of the first zero bit and
342 * the base argument needs to be compliant with the constraint
343 * (those bits that are set in the constraint cannot be set in
344 * the address).
345 *
346 * If the index argument is non-NULL, the continuous zero range
347 * is set and the index of the first bit is stored to index.
348 * Otherwise the bitmap stays untouched.
349 *
350 * @param bitmap Bitmap structure.
351 * @param count Number of continuous zero bits to find.
352 * @param base Address of the first bit in the bitmap.
353 * @param constraint Constraint for the address of the first zero bit.
354 * @param index Place to store the index of the first zero
355 * bit. Can be NULL (in which case the bitmap
356 * is not modified).
357 *
358 * @return Non-zero if a continuous range of zero bits satisfying
359 * the constraint has been found.
360 * @return Zero otherwise.
361 *
362 */
363int bitmap_allocate_range(bitmap_t *bitmap, size_t count, size_t base,
364 size_t constraint, size_t *index)
365{
[d5f774f6]366 if (count == 0)
[86733f3]367 return false;
368
[64f3d3b]369 size_t bytes = bitmap_bytes(bitmap->elements);
[86733f3]370
[64f3d3b]371 for (size_t byte = 0; byte < bytes; byte++) {
372 /* Skip if the current byte has all bits set */
373 if (bitmap->bits[byte] == ALL_ONES)
[86733f3]374 continue;
375
[64f3d3b]376 size_t byte_bit = byte * BITMAP_ELEMENT;
377
378 for (size_t bit = 0; bit < BITMAP_ELEMENT; bit++) {
379 size_t i = byte_bit + bit;
[86733f3]380
[64f3d3b]381 if (i >= bitmap->elements)
382 break;
[86733f3]383
[64f3d3b]384 if (!constraint_satisfy(i, base, constraint))
385 continue;
386
387 if (!bitmap_get_fast(bitmap, i)) {
388 bool continuous = true;
389
390 for (size_t j = 1; j < count; j++) {
391 if ((i + j >= bitmap->elements) ||
392 (bitmap_get_fast(bitmap, i + j))) {
393 continuous = false;
394 break;
395 }
[86733f3]396 }
397
[64f3d3b]398 if (continuous) {
399 if (index != NULL) {
400 bitmap_set_range(bitmap, i, count);
401 *index = i;
402 }
403
404 return true;
405 }
[86733f3]406 }
407 }
408 }
409
410 return false;
411}
412
[cc73a8a1]413/** @}
[b45c443]414 */
Note: See TracBrowser for help on using the repository browser.