Pre-ci test passed git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4000 818b1a75-f10b-46b9-bf7c-635c3b92a50f
591 lines
15 KiB
C
591 lines
15 KiB
C
#include "internal.h"
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
void test_lfds611_stack( void )
|
|
{
|
|
printf( "\n"
|
|
"Stack Tests\n"
|
|
"===========\n" );
|
|
|
|
stack_test_internal_popping();
|
|
stack_test_internal_pushing();
|
|
stack_test_internal_popping_and_pushing();
|
|
stack_test_internal_rapid_popping_and_pushing();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
void stack_test_internal_popping( void )
|
|
{
|
|
unsigned int
|
|
loop,
|
|
*found_count,
|
|
cpu_count;
|
|
|
|
lfds611_atom_t
|
|
count;
|
|
|
|
thread_state_t
|
|
*thread_handles;
|
|
|
|
enum lfds611_data_structure_validity
|
|
dvs = LFDS611_VALIDITY_VALID;
|
|
|
|
struct lfds611_stack_state
|
|
*ss;
|
|
|
|
struct stack_test_popping_state
|
|
*stps;
|
|
|
|
/* TRD : we create a stack with 1,000,000 elements
|
|
|
|
we then populate the stack, where each element is
|
|
set to contain a void pointer which is its element number
|
|
|
|
we then run one thread per CPU
|
|
where each thread loops, popping as quickly as possible
|
|
each popped element is pushed onto a thread-local stack
|
|
|
|
the threads run till the source stack is empty
|
|
|
|
we then check the thread-local stacks
|
|
we should find we have every element
|
|
|
|
then tidy up
|
|
*/
|
|
|
|
internal_display_test_name( "Popping" );
|
|
|
|
cpu_count = abstraction_cpu_count();
|
|
|
|
lfds611_stack_new( &ss, 1000000 );
|
|
|
|
for( loop = 0 ; loop < 1000000 ; loop++ )
|
|
lfds611_stack_push( ss, (void *) (lfds611_atom_t) loop );
|
|
|
|
stps = malloc( sizeof(struct stack_test_popping_state) * cpu_count );
|
|
for( loop = 0 ; loop < cpu_count ; loop++ )
|
|
{
|
|
(stps+loop)->ss = ss;
|
|
lfds611_stack_new( &(stps+loop)->ss_thread_local, 1000000 );
|
|
}
|
|
|
|
thread_handles = malloc( sizeof(thread_state_t) * cpu_count );
|
|
|
|
for( loop = 0 ; loop < cpu_count ; loop++ )
|
|
abstraction_thread_start( &thread_handles[loop], loop, stack_test_internal_thread_popping, stps+loop );
|
|
|
|
for( loop = 0 ; loop < cpu_count ; loop++ )
|
|
abstraction_thread_wait( thread_handles[loop] );
|
|
|
|
free( thread_handles );
|
|
|
|
// TRD : now we check the thread-local stacks
|
|
found_count = malloc( sizeof(unsigned int) * 1000000 );
|
|
for( loop = 0 ; loop < 1000000 ; loop++ )
|
|
*(found_count+loop) = 0;
|
|
|
|
for( loop = 0 ; loop < cpu_count ; loop++ )
|
|
while( lfds611_stack_pop((stps+loop)->ss_thread_local, (void **) &count) )
|
|
(*(found_count+count))++;
|
|
|
|
for( loop = 0 ; loop < 1000000 and dvs == LFDS611_VALIDITY_VALID ; loop++ )
|
|
{
|
|
if( *(found_count+loop) == 0 )
|
|
dvs = LFDS611_VALIDITY_INVALID_MISSING_ELEMENTS;
|
|
|
|
if( *(found_count+loop) > 1 )
|
|
dvs = LFDS611_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;
|
|
}
|
|
|
|
// TRD : cleanup
|
|
free( found_count );
|
|
for( loop = 0 ; loop < cpu_count ; loop++ )
|
|
lfds611_stack_delete( (stps+loop)->ss_thread_local, NULL, NULL );
|
|
free( stps );
|
|
lfds611_stack_delete( ss, NULL, NULL );
|
|
|
|
// TRD : print the test result
|
|
internal_display_test_result( 1, "stack", dvs );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
thread_return_t CALLING_CONVENTION stack_test_internal_thread_popping( void *stack_test_popping_state )
|
|
{
|
|
struct stack_test_popping_state
|
|
*stps;
|
|
|
|
lfds611_atom_t
|
|
count;
|
|
|
|
assert( stack_test_popping_state != NULL );
|
|
|
|
stps = (struct stack_test_popping_state *) stack_test_popping_state;
|
|
|
|
lfds611_stack_use( stps->ss );
|
|
|
|
while( lfds611_stack_pop(stps->ss, (void **) &count) )
|
|
lfds611_stack_push( stps->ss_thread_local, (void *) count );
|
|
|
|
return( (thread_return_t) EXIT_SUCCESS );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
void stack_test_internal_pushing( void )
|
|
{
|
|
unsigned int
|
|
loop,
|
|
cpu_count;
|
|
|
|
thread_state_t
|
|
*thread_handles;
|
|
|
|
enum lfds611_data_structure_validity
|
|
dvs[2];
|
|
|
|
struct stack_test_pushing_state
|
|
*stps;
|
|
|
|
struct lfds611_stack_state
|
|
*ss;
|
|
|
|
lfds611_atom_t
|
|
user_data,
|
|
thread,
|
|
count,
|
|
*per_thread_counters;
|
|
|
|
struct lfds611_validation_info
|
|
vi = { 1000000, 1000000 };
|
|
|
|
/* TRD : we create a stack with 1,000,000 elements
|
|
|
|
we then create one thread per CPU, where each thread
|
|
pushes as quickly as possible to the stack
|
|
|
|
the data pushed is a counter and a thread ID
|
|
|
|
the threads exit when the stack is full
|
|
|
|
we then validate the stack;
|
|
|
|
checking that the counts increment on a per unique ID basis
|
|
and that the number of elements we pop equals 1,000,000
|
|
(since each element has an incrementing counter which is
|
|
unique on a per unique ID basis, we can know we didn't lose
|
|
any elements)
|
|
*/
|
|
|
|
internal_display_test_name( "Pushing" );
|
|
|
|
cpu_count = abstraction_cpu_count();
|
|
|
|
stps = malloc( sizeof(struct stack_test_pushing_state) * cpu_count );
|
|
|
|
// TRD : the main stack
|
|
lfds611_stack_new( &ss, 1000000 );
|
|
|
|
for( loop = 0 ; loop < cpu_count ; loop++ )
|
|
{
|
|
(stps+loop)->thread_number = (lfds611_atom_t) loop;
|
|
(stps+loop)->ss = ss;
|
|
}
|
|
|
|
thread_handles = malloc( sizeof(thread_state_t) * cpu_count );
|
|
|
|
for( loop = 0 ; loop < cpu_count ; loop++ )
|
|
abstraction_thread_start( &thread_handles[loop], loop, stack_test_internal_thread_pushing, stps+loop );
|
|
|
|
for( loop = 0 ; loop < cpu_count ; loop++ )
|
|
abstraction_thread_wait( thread_handles[loop] );
|
|
|
|
free( thread_handles );
|
|
|
|
// TRD : the stack is now fully pushed; time to verify
|
|
per_thread_counters = malloc( sizeof(lfds611_atom_t) * cpu_count );
|
|
|
|
for( loop = 0 ; loop < cpu_count ; loop++ )
|
|
*(per_thread_counters+loop) = 1000000;
|
|
|
|
lfds611_stack_query( ss, LFDS611_STACK_QUERY_VALIDATE, &vi, (void *) dvs );
|
|
|
|
while( dvs[0] == LFDS611_VALIDITY_VALID and lfds611_stack_pop(ss, (void **) &user_data) )
|
|
{
|
|
thread = user_data >> (sizeof(lfds611_atom_t)*8-8);
|
|
count = (user_data << 8) >> 8;
|
|
|
|
if( thread >= cpu_count )
|
|
{
|
|
dvs[0] = LFDS611_VALIDITY_INVALID_TEST_DATA;
|
|
break;
|
|
}
|
|
|
|
if( count > per_thread_counters[thread] )
|
|
dvs[0] = LFDS611_VALIDITY_INVALID_ADDITIONAL_ELEMENTS;
|
|
|
|
if( count < per_thread_counters[thread] )
|
|
per_thread_counters[thread] = count-1;
|
|
}
|
|
|
|
// TRD : clean up
|
|
free( per_thread_counters );
|
|
|
|
free( stps );
|
|
|
|
lfds611_stack_delete( ss, NULL, NULL );
|
|
|
|
// TRD : print the test result
|
|
internal_display_test_result( 2, "stack", dvs[0], "stack freelist", dvs[1] );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
thread_return_t CALLING_CONVENTION stack_test_internal_thread_pushing( void *stack_test_pushing_state )
|
|
{
|
|
struct stack_test_pushing_state
|
|
*stps;
|
|
|
|
lfds611_atom_t
|
|
counter = 0;
|
|
|
|
assert( stack_test_pushing_state != NULL );
|
|
|
|
stps = (struct stack_test_pushing_state *) stack_test_pushing_state;
|
|
|
|
lfds611_stack_use( stps->ss );
|
|
|
|
// TRD : we write (thread_number | counter), where thread_number is the top 8 bits of the lfds611_atom_t
|
|
while( lfds611_stack_push(stps->ss, (void **) ((stps->thread_number << (sizeof(lfds611_atom_t)*8-8)) | counter++)) );
|
|
|
|
return( (thread_return_t) EXIT_SUCCESS );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
void stack_test_internal_popping_and_pushing( void )
|
|
{
|
|
unsigned int
|
|
loop,
|
|
subloop,
|
|
cpu_count;
|
|
|
|
thread_state_t
|
|
*thread_handles;
|
|
|
|
enum lfds611_data_structure_validity
|
|
dvs[2];
|
|
|
|
struct lfds611_stack_state
|
|
*ss;
|
|
|
|
struct stack_test_popping_and_pushing_state
|
|
*stpps;
|
|
|
|
struct lfds611_validation_info
|
|
vi;
|
|
|
|
/* TRD : we have two threads per CPU
|
|
the threads loop for ten seconds
|
|
the first thread pushes 100000 elements then pops 100000 elements
|
|
the second thread pops 100000 elements then pushes 100000 elements
|
|
all pushes and pops go onto the single main stack
|
|
|
|
after time is up, all threads push what they have remaining onto
|
|
the main stack
|
|
|
|
we then validate the main stack
|
|
*/
|
|
|
|
internal_display_test_name( "Popping and pushing (10 seconds)" );
|
|
|
|
cpu_count = abstraction_cpu_count();
|
|
|
|
// TRD : just some initial elements so the pushing threads can start immediately
|
|
lfds611_stack_new( &ss, 100000 * cpu_count * 2 );
|
|
|
|
for( loop = 0 ; loop < 100000 * cpu_count ; loop++ )
|
|
lfds611_stack_push( ss, (void *) (lfds611_atom_t) loop );
|
|
|
|
stpps = malloc( sizeof(struct stack_test_popping_and_pushing_state) * cpu_count * 2 );
|
|
|
|
for( loop = 0 ; loop < cpu_count ; loop++ )
|
|
{
|
|
(stpps+loop)->ss = ss;
|
|
lfds611_stack_new( &(stpps+loop)->local_ss, 100000 );
|
|
|
|
(stpps+loop+cpu_count)->ss = ss;
|
|
lfds611_stack_new( &(stpps+loop+cpu_count)->local_ss, 100000 );
|
|
|
|
// TRD : fill the pushing thread stacks
|
|
for( subloop = 0 ; subloop < 100000 ; subloop++ )
|
|
lfds611_stack_push( (stpps+loop+cpu_count)->local_ss, (void *) (lfds611_atom_t) subloop );
|
|
}
|
|
|
|
thread_handles = malloc( sizeof(thread_state_t) * cpu_count * 2 );
|
|
|
|
for( loop = 0 ; loop < cpu_count ; loop++ )
|
|
{
|
|
abstraction_thread_start( &thread_handles[loop], loop, stack_test_internal_thread_popping_and_pushing_start_popping, stpps+loop );
|
|
abstraction_thread_start( &thread_handles[loop+cpu_count], loop, stack_test_internal_thread_popping_and_pushing_start_pushing, stpps+loop+cpu_count );
|
|
}
|
|
|
|
for( loop = 0 ; loop < cpu_count * 2 ; loop++ )
|
|
abstraction_thread_wait( thread_handles[loop] );
|
|
|
|
free( thread_handles );
|
|
|
|
for( loop = 0 ; loop < cpu_count * 2 ; loop++ )
|
|
lfds611_stack_delete( (stpps+loop)->local_ss, NULL, NULL );
|
|
|
|
free( stpps );
|
|
|
|
vi.min_elements = vi.max_elements = 100000 * cpu_count * 2;
|
|
|
|
lfds611_stack_query( ss, LFDS611_STACK_QUERY_VALIDATE, (void *) &vi, (void *) dvs );
|
|
|
|
lfds611_stack_delete( ss, NULL, NULL );
|
|
|
|
// TRD : print the test result
|
|
internal_display_test_result( 2, "stack", dvs[0], "stack freelist", dvs[1] );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
thread_return_t CALLING_CONVENTION stack_test_internal_thread_popping_and_pushing_start_popping( void *stack_test_popping_and_pushing_state )
|
|
{
|
|
struct stack_test_popping_and_pushing_state
|
|
*stpps;
|
|
|
|
void
|
|
*user_data;
|
|
|
|
time_t
|
|
start_time;
|
|
|
|
unsigned int
|
|
count;
|
|
|
|
assert( stack_test_popping_and_pushing_state != NULL );
|
|
|
|
stpps = (struct stack_test_popping_and_pushing_state *) stack_test_popping_and_pushing_state;
|
|
|
|
lfds611_stack_use( stpps->ss );
|
|
lfds611_stack_use( stpps->local_ss );
|
|
|
|
time( &start_time );
|
|
|
|
while( time(NULL) < start_time + 10 )
|
|
{
|
|
count = 0;
|
|
|
|
while( count < 100000 )
|
|
if( lfds611_stack_pop(stpps->ss, &user_data) )
|
|
{
|
|
lfds611_stack_push( stpps->local_ss, user_data );
|
|
count++;
|
|
}
|
|
|
|
// TRD : return our local stack to the main stack
|
|
while( lfds611_stack_pop(stpps->local_ss, &user_data) )
|
|
lfds611_stack_push( stpps->ss, user_data );
|
|
}
|
|
|
|
return( (thread_return_t) EXIT_SUCCESS );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
thread_return_t CALLING_CONVENTION stack_test_internal_thread_popping_and_pushing_start_pushing( void *stack_test_popping_and_pushing_state )
|
|
{
|
|
struct stack_test_popping_and_pushing_state
|
|
*stpps;
|
|
|
|
void
|
|
*user_data;
|
|
|
|
time_t
|
|
start_time;
|
|
|
|
unsigned int
|
|
count;
|
|
|
|
assert( stack_test_popping_and_pushing_state != NULL );
|
|
|
|
stpps = (struct stack_test_popping_and_pushing_state *) stack_test_popping_and_pushing_state;
|
|
|
|
lfds611_stack_use( stpps->ss );
|
|
lfds611_stack_use( stpps->local_ss );
|
|
|
|
time( &start_time );
|
|
|
|
while( time(NULL) < start_time + 10 )
|
|
{
|
|
// TRD : return our local stack to the main stack
|
|
while( lfds611_stack_pop(stpps->local_ss, &user_data) )
|
|
lfds611_stack_push( stpps->ss, user_data );
|
|
|
|
count = 0;
|
|
|
|
while( count < 100000 )
|
|
if( lfds611_stack_pop(stpps->ss, &user_data) )
|
|
{
|
|
lfds611_stack_push( stpps->local_ss, user_data );
|
|
count++;
|
|
}
|
|
}
|
|
|
|
// TRD : now push whatever we have in our local stack
|
|
while( lfds611_stack_pop(stpps->local_ss, &user_data) )
|
|
lfds611_stack_push( stpps->ss, user_data );
|
|
|
|
return( (thread_return_t) EXIT_SUCCESS );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
void stack_test_internal_rapid_popping_and_pushing( void )
|
|
{
|
|
unsigned int
|
|
loop,
|
|
cpu_count;
|
|
|
|
thread_state_t
|
|
*thread_handles;
|
|
|
|
struct lfds611_stack_state
|
|
*ss;
|
|
|
|
struct lfds611_validation_info
|
|
vi;
|
|
|
|
enum lfds611_data_structure_validity
|
|
dvs[2];
|
|
|
|
/* TRD : in these tests there is a fundamental antagonism between
|
|
how much checking/memory clean up that we do and the
|
|
likelyhood of collisions between threads in their lock-free
|
|
operations
|
|
|
|
the lock-free operations are very quick; if we do anything
|
|
much at all between operations, we greatly reduce the chance
|
|
of threads colliding
|
|
|
|
so we have some tests which do enough checking/clean up that
|
|
they can tell the stack is valid and don't leak memory
|
|
and here, this test now is one of those which does minimal
|
|
checking - in fact, the nature of the test is that you can't
|
|
do any real checking - but goes very quickly
|
|
|
|
what we do is create a small stack and then run one thread
|
|
per CPU, where each thread simply pushes and then immediately
|
|
pops
|
|
|
|
the test runs for ten seconds
|
|
|
|
after the test is done, the only check we do is to traverse
|
|
the stack, checking for loops and ensuring the number of
|
|
elements is correct
|
|
*/
|
|
|
|
internal_display_test_name( "Rapid popping and pushing (10 seconds)" );
|
|
|
|
cpu_count = abstraction_cpu_count();
|
|
|
|
lfds611_stack_new( &ss, cpu_count );
|
|
|
|
thread_handles = malloc( sizeof(thread_state_t) * cpu_count );
|
|
|
|
for( loop = 0 ; loop < cpu_count ; loop++ )
|
|
abstraction_thread_start( &thread_handles[loop], loop, stack_test_internal_thread_rapid_popping_and_pushing, ss );
|
|
|
|
for( loop = 0 ; loop < cpu_count ; loop++ )
|
|
abstraction_thread_wait( thread_handles[loop] );
|
|
|
|
free( thread_handles );
|
|
|
|
vi.min_elements = 0;
|
|
vi.max_elements = 0;
|
|
|
|
lfds611_stack_query( ss, LFDS611_STACK_QUERY_VALIDATE, (void *) &vi, (void *) dvs );
|
|
|
|
lfds611_stack_delete( ss, NULL, NULL );
|
|
|
|
// TRD : print the test result
|
|
internal_display_test_result( 2, "stack", dvs[0], "stack freelist", dvs[1] );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
thread_return_t CALLING_CONVENTION stack_test_internal_thread_rapid_popping_and_pushing( void *stack_state )
|
|
{
|
|
struct lfds611_stack_state
|
|
*ss;
|
|
|
|
void
|
|
*user_data = NULL;
|
|
|
|
time_t
|
|
start_time;
|
|
|
|
assert( stack_state != NULL );
|
|
|
|
ss = (struct lfds611_stack_state *) stack_state;
|
|
|
|
lfds611_stack_use( ss );
|
|
|
|
time( &start_time );
|
|
|
|
while( time(NULL) < start_time + 10 )
|
|
{
|
|
lfds611_stack_push( ss, user_data );
|
|
lfds611_stack_pop( ss, &user_data );
|
|
}
|
|
|
|
return( (thread_return_t) EXIT_SUCCESS );
|
|
}
|
|
|