tech-userlevel archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: 64-bit masks
On Fri, 27 Nov 2009 16:00:43 -0000, Robert Elz <kre%munnari.oz.au@localhost>
wrote:
Whether this is really an appropriate algorithm depends on just what you
need to know all the free objects for - if you just want to find the
first
free object, there are easier (faster) ways, but if you really need to
find all of them, this might be OK.
Hi, well I really need to find the first free object, not all the free
objects at once. The faster I can do it, the better. I looked at ffs()
function to find first set bit, but it operates on integers, which I think
might be problematic because:
1. On different platforms integer could be 16, 32, or even 64-bits wide
2. If I need to keep track of 64 or more objects, I would need an array of
integers. Calling ffs() function several times might slow things down. But
if ffs() is implemented via fast assembly instruction, I guess it should
be OK.
It also needs to be portable to at least BSD, Linux and Solaris.
My code assumes bit 1 is busy, and bit 0 is free. So I came up with the
following function (attached) to look for the first unset (0) bit. If
anyone knows faster algorithms, I'd be interested to know.
PS. I ran a quick benchmark on Sparc Solaris, a loop of 10_000_000
iterations calling ffs() on 32-bit int, and a loop for my function on
64-bit int.
/opt/SUNWspro/bin/cc -xO3 find_bit.c
This is my function:
rom@ultra10 ptime ./a.out
real 0.561
user 0.542
sys 0.009
This is Solaris ffs():
rom@ultra10 ptime ./a.out
real 0.680
user 0.626
sys 0.009
I suppose it's a good start.
/*
ffu_bit - find first unset bit
Return:
index of first unset bit (0 to 63)
-1 if there were no unset bits
Pre:
bit_str is a 64-bit unsigned integer
Post:
none
The function uses binary search algorithm to find 8-bit byte inside a 64-bit
integer, which contains an unset bit.
The function divides 64-bit integer into two 32-bit halves. It then divides
each 32-bit half into two 16-bit halves. Each of the 16-bit halves is then
divided into two 8-bit halves.
aaaaaaaaaaaaaaaaaaaaaaa -> 1 64-bit
bbbbbbbbbbb bbbbbbbbbbb -> 2 32-bit segments
ccccc ccccc ccccc ccccc -> 4 16-bit segments
dd dd dd dd dd dd dd dd -> 8 8-bit segments
-----------------------
7 6 5 4 3 2 1 0 -> 8-bit index
*/
int ffu_bit(uint64_t bit_str)
{
int index, i;
uint64_t tmp;
const uint64_t mask64 = UINT64_C(0xffffffffffffffff);
const uint64_t mask32 = UINT64_C(0x00000000ffffffff);
const uint64_t mask16 = UINT64_C(0x000000000000ffff);
const uint64_t mask8 = UINT64_C(0x00000000000000ff);
/* If all bits are 1, return -1 */
if(bit_str == mask64)
return -1;
/* If bits 0-31 are not all 1s */
if((bit_str & mask32) != mask32)
{
/* If bits 0-15 are not all 1s */
if((bit_str & mask16) != mask16)
{
/* If bits 0-7 are not all 1s */
if((bit_str & mask8) != mask8)
index = 0;
else /* bits 8-15 */
index = 1;
}
else /* Must be bits 16-31 */
{
/* If bits 16-23 are not all 1s */
if(((bit_str >> 16) & mask8) != mask8)
index = 2;
else /* bits 24-32 */
index = 3;
}
}
/* Must be bits 32-63 */
else
{
/* If bits 32-47 are not all 1s */
if(((bit_str >> 32) & mask16) != mask16)
{
/* If bits 32-39 are not all 1s */
if(((bit_str >> 32) & mask8) != mask8)
index = 4;
else /* bits 40-47 */
index = 5;
}
else /* Must be bits 48-63 */
{
/* If bits 48-55 are not all 1s */
if(((bit_str >> 48) & mask8) != mask8)
index = 6;
else /* bits 56-63 */
index = 7;
}
}
index *= 8; /* scale index by 8-bits in a byte */
/*
Shift the 8-bit byte containing first unset bit to the far right so we
can
find out the exact bit index within the byte.
*/
tmp = bit_str >> index;
for(i = 0; i < 8; i++)
{
if(((tmp >> i) & 0x1) == 0)
break; /* found first bit set to 0 */
}
index += i;
return index;
}
Home |
Main Index |
Thread Index |
Old Index