Reputation: 49329
I am writing an memory allocator that is backed by a bit map (array of uint8_t
) currently when an allocation request comes along I scan the bitmap sequential from 0 to n bits and search for a space that can fulfill the request. (a bit 1 denotes page used a 0 denoted page is free) Now instead of searching for a space one bit at a time is there technique to scan the whole array faster? i.e if a request for 3 page memory arrives I would like to search for 000
pattern in the array in one go ideally without looping?
PS: I am not using std::bitset
as it is not available for the compiler I am using. AFAIK that does not let me search for multiple bits also.
EDIT: Bits are packed into bytes one uint8_t
has 8 pages (1 per bit) encoded in it.
Upvotes: 2
Views: 449
Reputation: 66200
Not a full answer to your question (I suppose) but I hope that the following function can help.
template <typename I>
bool scan_n_zeros (I iVal, std::size_t num)
{
while ( --num )
iVal |= ((iVal << 1) | I{1});
return iVal != I(-1);
}
It return (if I've written it correctly) true
if (not where) there are at least num
consecutive zero bit in iVal
.
The following is a full working example when T
is uint8_t
#include <iostream>
template <typename I>
bool scan_n_zeros (I iVal, std::size_t num)
{
while ( --num )
iVal |= ((iVal << 1) | I{1});
return iVal != I(-1);
}
int main()
{
uint8_t u0 { 0b00100100 };
uint8_t u1 { 0b00001111 };
uint8_t u2 { 0b10000111 };
uint8_t u3 { 0b11000011 };
uint8_t u4 { 0b11100001 };
uint8_t u5 { 0b11110000 };
std::cout << scan_n_zeros(u0, 2U) << std::endl; // print 1
std::cout << scan_n_zeros(u0, 3U) << std::endl; // print 0
std::cout << scan_n_zeros(u1, 4U) << std::endl; // print 1
std::cout << scan_n_zeros(u1, 5U) << std::endl; // print 0
std::cout << scan_n_zeros(u2, 4U) << std::endl; // print 1
std::cout << scan_n_zeros(u2, 5U) << std::endl; // print 0
std::cout << scan_n_zeros(u3, 4U) << std::endl; // print 1
std::cout << scan_n_zeros(u3, 5U) << std::endl; // print 0
std::cout << scan_n_zeros(u4, 4U) << std::endl; // print 1
std::cout << scan_n_zeros(u4, 5U) << std::endl; // print 0
std::cout << scan_n_zeros(u5, 4U) << std::endl; // print 1
std::cout << scan_n_zeros(u5, 5U) << std::endl; // print 0
}
Upvotes: 1
Reputation: 11406
To scan for one empty page, you could loop through the bit array one full byte at a time and check if it is smaller than 255. If it is smaller, there is at least one zero bit. Even better would be to scan 32 or 64 bit (unsigned ints) at a time, and then narrow the search inside the uint.
To optimize a bit, you could keep track of the first byte with a zero bit (and update that position when freeing a page). This could give a false positive once you allocate that free page, but at least the next time the scan can start there instead of at the beginning.
A scan for multiple pages could be optimized if you're willing to align larger blocks on a power of 2 (depending on your data structures). For example, to allocate 8 pages, you would only scan for a full byte being zero:
1 page: scan for any zero bit (up to 64 bits at a time)
2 pages: scan for 2 zero bits at bit position 0,2,4,6
3-4 pages: scan for zero nibble (for 3 pages, the fourth would be available for 1 page then)
5-8 pages: scan for an empty byte
for each of the above, you could first scan 64 bits at a time.
This way, you don't have to worry about (or check) overlapping zero ranges at byte/uint32/uint64 boundaries.
For each type a starting position with the first free block could be kept/updated.
Upvotes: 1