No optimizations, but after cleaning the code up somewhat the bit-by-bit approach was twice as fast as before, but still much slower than the lookup table. Here's a crude test program that should be easy to compile:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define array_size( array ) ( sizeof( array ) / sizeof( array[ 0 ] ) )
int initialize_table( unsigned char table[ 256 ] )
{
table[ 0 ] = 0;
int
min = 1;
for( int index = min; index < 9; index++ )
{
int
max = 1 << index;
for( int j = min; j < max; j++ )
{
table[ j ] = 9 - index;
}
min = max;
}
}
int get_first_available_channel_table_lookup( unsigned channels )
{
static unsigned char
table[ 256 ];
static int
unused = initialize_table( table );
return
channels == 0 ? 0
: channels < 0x100 ? table[ channels & 0xff ] + 24
: channels < 0x10000 ? table[ ( channels >> 8 ) & 0xff ] + 16
: channels < 0x1000000 ? table[ ( channels >> 16 ) & 0xff ] + 8
: table[ ( channels >> 24 ) & 0xff ];
}
int get_first_available_channel_ceil_log( unsigned channels )
{
int
index = ( int )ceil( log2( channels + 1 ) );
return index ? 33 - index : 0;
}
int get_first_available_channel_bit_by_bit( unsigned channels )
{
for( unsigned index = 1, mask = 0x80000000; mask; mask >>= 1, index++ )
{
if( channels & mask )
return index;
}
return 0;
}
typedef int ( * get_first_available_channel_function )( unsigned );
void test( unsigned* values, size_t length, const char* name, get_first_available_channel_function function, size_t repetitions )
{
size_t
iterations = repetitions * length;
unsigned
* v,
* e = values + length;
clock_t
elapsed,
stop,
start = clock( );
while( repetitions-- )
{
v = values;
while( v != e )
{
function( *v++ );
}
}
stop = clock( );
elapsed = ( clock_t )( ( ( double ) ( stop - start ) / ( double )CLK_TCK ) * 1000 );
printf( "%s : %d iterations performed in %d milliseconds\n", name, iterations, ( size_t )elapsed );
}
int main( void )
{
srand( time( 0 ) );
unsigned
data[ 256 ];
size_t
repetitions = 30000,
tests = 10;
struct
{
char*
name;
get_first_available_channel_function
function;
}
functions[ ] =
{
{ "ceil_log", get_first_available_channel_ceil_log },
{ "table_lookup", get_first_available_channel_table_lookup },
{ "bit_by_bit", get_first_available_channel_bit_by_bit }
};
while( tests-- )
{
for( int index = 0; index < array_size( data ); ++index )
{
data[ index ] = rand( );
}
for( int index = 0; index < array_size( functions ); ++index )
{
test( data, array_size( data ), functions[ index ].name, functions[ index ].function, repetitions );
}
}
return 0;
}