DECLARE_TEST( semaphore, postwait ) { semaphore_t sem; tick_t start, end; semaphore_initialize( &sem, 0 ); EXPECT_FALSE( semaphore_try_wait( &sem, 100 ) ); semaphore_post( &sem ); EXPECT_TRUE( semaphore_wait( &sem ) ); EXPECT_FALSE( semaphore_try_wait( &sem, 100 ) ); semaphore_post( &sem ); semaphore_post( &sem ); EXPECT_TRUE( semaphore_wait( &sem ) ); EXPECT_TRUE( semaphore_try_wait( &sem, 100 ) ); EXPECT_FALSE( semaphore_try_wait( &sem, 100 ) ); start = time_current(); semaphore_try_wait( &sem, 0 ); end = time_current(); EXPECT_LT( end - start, time_ticks_per_second() / 1000 ); start = time_current(); semaphore_try_wait( &sem, 500 ); end = time_current(); EXPECT_GE( end - start, time_ticks_per_second() / 2 ); semaphore_destroy( &sem ); return 0; }
static log_timestamp_t _log_make_timestamp( void ) { tick_t elapsed; tick_t ticks_per_sec; uint64_t milliseconds; uint64_t seconds; uint64_t minutes; log_timestamp_t timestamp = {0}; ticks_per_sec = time_ticks_per_second(); if( !ticks_per_sec ) return timestamp; elapsed = time_current() - time_startup(); milliseconds = ( ( elapsed % ticks_per_sec ) * 1000ULL ) / ticks_per_sec; seconds = elapsed / ticks_per_sec; minutes = seconds / 60ULL; timestamp.milliseconds = (unsigned int)( milliseconds % 1000ULL ); timestamp.seconds = (unsigned int)( seconds % 60ULL ); timestamp.minutes = (unsigned int)( minutes % 60ULL ); timestamp.hours = (unsigned int)( minutes / 24ULL ); return timestamp; }
static void* _profile_io( object_t thread, void* arg ) { unsigned int system_info_counter = 0; profile_block_t system_info; FOUNDATION_UNUSED( arg ); memset( &system_info, 0, sizeof( profile_block_t ) ); system_info.data.id = PROFILE_ID_SYSTEMINFO; system_info.data.start = time_ticks_per_second(); string_copy( system_info.data.name, "sysinfo", 7 ); while( !thread_should_terminate( thread ) ) { thread_sleep( _profile_wait ); if( !atomic_load32( &_profile_root ) ) continue; profile_begin_block( "profile_io" ); if( atomic_load32( &_profile_root ) ) { profile_begin_block( "process" ); //This is thread safe in the sense that only completely closed and ended //blocks will be put as children to root block, so no additional blocks //will ever be added to child subtrees while we process it here _profile_process_root_block(); profile_end_block(); } if( system_info_counter++ > 10 ) { if( _profile_write ) _profile_write( &system_info, sizeof( profile_block_t ) ); system_info_counter = 0; } profile_end_block(); } if( atomic_load32( &_profile_root ) ) _profile_process_root_block(); if( _profile_write ) { profile_block_t terminate; memset( &terminate, 0, sizeof( profile_block_t ) ); terminate.data.id = PROFILE_ID_ENDOFSTREAM; _profile_write( &terminate, sizeof( profile_block_t ) ); } return 0; }
DECLARE_TEST(time, builtin) { tick_t tick, newtick, tps; deltatime_t dt; tps = time_ticks_per_second(); EXPECT_GT(tps, 0); tick = time_current(); thread_sleep(30); newtick = time_current(); EXPECT_TICKNE(tick, 0); EXPECT_TICKGT(newtick, tick); EXPECT_TICKGT(time_diff(tick, newtick), 0); EXPECT_GT_MSGFORMAT(time_diff(tick, newtick), (tps / 100LL), "time elapsed not more than 10ms: %" PRId64 " (%" PRId64 ")", time_diff(tick, newtick), (tps / 100)); //more than 10 ms EXPECT_LT_MSGFORMAT(time_diff(tick, newtick), (tps / 20LL), "time elapsed not less than 50ms: %" PRId64 " (%" PRId64 ")", time_diff(tick, newtick), (tps / 33)); //less than 30 ms EXPECT_REALGT(time_elapsed(tick), 0); EXPECT_REALGT(time_elapsed(tick), 0.01f); //more than 10 ms EXPECT_TICKGT(time_elapsed_ticks(tick), 0); EXPECT_TICKGT(time_elapsed_ticks(tick), (tps / 100)); //more than 10 ms EXPECT_TICKLT(time_elapsed_ticks(tick), (tps / 20)); //less than 50 ms dt = time_ticks_to_seconds(newtick - tick); EXPECT_REALGT(dt, 0); EXPECT_GT_MSGFORMAT(dt, 0.01f, "time elapsed in seconds not more than 10ms: %.5f", dt); //more than 10 ms EXPECT_LT_MSGFORMAT(dt, 0.05f, "time elapsed in seconds not less than 30ms: %.5f", dt); //less than 30 ms tick = time_startup(); EXPECT_TICKGT(tick, 0); EXPECT_TICKLT(tick, newtick); EXPECT_TICKEQ(tick, time_startup()); tick = time_system(); thread_sleep(100); newtick = time_system(); EXPECT_TICKGT(tick, 0); EXPECT_TICKGT(newtick, 0); EXPECT_TICKGT(newtick, tick); EXPECT_GT_MSGFORMAT(newtick - tick, 50, "Elapsed system time less than 50ms, expected 100ms, got %" PRId64 "ms", newtick - tick); EXPECT_LT_MSGFORMAT(newtick - tick, 200, "Elapsed system time more than 200ms, expected 100ms, got %" PRId64 "ms", newtick - tick); return 0; }
DECLARE_TEST( time, builtin ) { tick_t tick, newtick, tps; deltatime_t dt; tps = time_ticks_per_second(); EXPECT_GT( tps, 0 ); tick = time_current(); thread_sleep( 20 ); newtick = time_current(); EXPECT_NE( tick, 0 ); EXPECT_GT( newtick, tick ); EXPECT_GT( time_diff( tick, newtick ), 0 ); EXPECT_GT_MSGFORMAT( time_diff( tick, newtick ), ( tps / 100LL ), "time elapsed not more than 10ms: %lld (%lld)", time_diff( tick, newtick ), ( tps / 100LL ) ); //more than 10 ms EXPECT_LT_MSGFORMAT( time_diff( tick, newtick ), ( tps / 30LL ), "time elapsed not less than 30ms: %lld (%lld)", time_diff( tick, newtick ), ( tps / 33LL ) ); //less than 30 ms EXPECT_GT( time_elapsed( tick ), 0 ); EXPECT_GT( time_elapsed( tick ), 0.01f ); //more than 10 ms EXPECT_GT( time_elapsed_ticks( tick ), 0 ); EXPECT_GT( time_elapsed_ticks( tick ), ( tps / 100 ) ); //more than 10 ms dt = time_ticks_to_seconds( newtick - tick ); EXPECT_GT( dt, 0 ); EXPECT_GT_MSGFORMAT( dt, 0.01f, "time elapsed in seconds not more than 10ms: %.5f", dt ); //more than 10 ms EXPECT_LT_MSGFORMAT( dt, 0.03f, "time elapsed in seconds not less than 30ms: %.5f", dt ); //less than 30 ms tick = time_startup(); EXPECT_GT( tick, 0 ); EXPECT_LT( tick, newtick ); EXPECT_EQ( tick, time_startup() ); tick = time_system(); EXPECT_GT( tick, 0 ); thread_sleep( 100 ); newtick = time_system(); EXPECT_GT( newtick, 0 ); EXPECT_GT( newtick, tick ); EXPECT_GT( newtick - tick, 50 ); //more than 50 ms EXPECT_LT( newtick - tick, 200 ); //less than 200 ms return 0; }
static tick_t blast_time_elapsed_ms(const tick_t since) { const tick_t elapsed = time_elapsed_ticks(since); return (elapsed * 1000LL) / time_ticks_per_second(); }
DECLARE_TEST( event, delay_threaded ) { object_t thread[32]; producer_thread_arg_t args[32] = {0}; event_stream_t* stream; event_block_t* block; event_t* event; tick_t endtime, curtime, payloadtime, begintime, prevtime; unsigned int read[32]; int i; bool running = true; int num_threads = math_clamp( system_hardware_threads() * 4, 4, 32 ); stream = event_stream_allocate( 0 ); begintime = time_current(); for( i = 0; i < num_threads; ++i ) { args[i].stream = stream; args[i].end_time = time_current() + ( time_ticks_per_second() * 5 ); args[i].max_delay = time_ticks_per_second() * 5; args[i].sleep_time = 50; args[i].id = i; read[i] = 0; thread[i] = thread_create( producer_thread, "event_producer", THREAD_PRIORITY_NORMAL, 0 ); thread_start( thread[i], &args[i] ); } test_wait_for_threads_startup( thread, num_threads ); while( running ) { running = false; for( i = 0; i < num_threads; ++i ) { if( thread_is_running( thread[i] ) ) { running = true; break; } } thread_yield(); prevtime = begintime; begintime = time_current(); block = event_stream_process( stream ); event = event_next( block, 0 ); curtime = time_current(); while( event ) { running = true; ++read[ event->object ]; memcpy( &payloadtime, event->payload, sizeof( tick_t ) ); EXPECT_GE( event_payload_size( event ), 8 ); EXPECT_LE( event_payload_size( event ), 256 ); EXPECT_GE( payloadtime, prevtime ); EXPECT_GE( curtime, payloadtime ); event = event_next( block, event ); curtime = time_current(); } } endtime = time_current() + ( time_ticks_per_second() * 6 ); do { prevtime = begintime; begintime = time_current(); block = event_stream_process( stream ); event = event_next( block, 0 ); curtime = time_current(); while( event ) { ++read[ event->object ]; memcpy( &payloadtime, event->payload, sizeof( tick_t ) ); EXPECT_GE( event_payload_size( event ), 8 ); EXPECT_LE( event_payload_size( event ), 256 ); EXPECT_GE( payloadtime, prevtime ); EXPECT_GE( curtime, payloadtime ); event = event_next( block, event ); curtime = time_current(); } thread_sleep( 10 ); } while( time_current() < endtime ); for( i = 0; i < num_threads; ++i ) { unsigned int should_have_read = (unsigned int)((uintptr_t)thread_result( thread[i] )); EXPECT_EQ( read[i], should_have_read ); thread_terminate( thread[i] ); thread_destroy( thread[i] ); } test_wait_for_threads_exit( thread, num_threads ); event_stream_deallocate( stream ); return 0; }
DECLARE_TEST( event, delay ) { event_stream_t* stream; event_block_t* block; event_t* event; tick_t delivery = 0; tick_t limit = 0; tick_t current = 0; uint8_t expect_event = FOUNDATIONEVENT_TERMINATE; stream = event_stream_allocate( 0 ); current = time_current(); delivery = current + ( time_ticks_per_second() / 2 ); limit = current + ( time_ticks_per_second() * 20 ); event_post( stream, expect_event, 0, 0, 0, current + ( time_ticks_per_second() / 2 ) ); event_post( stream, expect_event + 1, 0, 0, 0, current + (tick_t)((real)time_ticks_per_second() * REAL_C( 0.51 )) ); do { block = event_stream_process( stream ); event = event_next( block, 0 ); current = time_current(); if( ( expect_event == FOUNDATIONEVENT_TERMINATE ) && event ) { EXPECT_EQ( event->id, expect_event ); EXPECT_EQ( event->size, sizeof( event_t ) + 8 ); //8 bytes for additional timestamp payload EXPECT_EQ( event->object, 0 ); EXPECT_EQ( event->flags, EVENTFLAG_DELAY ); EXPECT_EQ( event_payload_size( event ), 0 ); EXPECT_GE( current, delivery ); EXPECT_GE( current, delivery ); ++expect_event; event = event_next( block, event ); } if( ( expect_event == FOUNDATIONEVENT_TERMINATE + 1 ) && event ) { EXPECT_EQ( event->id, expect_event ); EXPECT_EQ( event->size, sizeof( event_t ) + 8 ); //8 bytes for additional timestamp payload EXPECT_EQ( event->object, 0 ); EXPECT_EQ( event->flags, EVENTFLAG_DELAY ); EXPECT_EQ( event_payload_size( event ), 0 ); EXPECT_GE( current, delivery ); EXPECT_GE( current, delivery ); ++expect_event; event = event_next( block, event ); EXPECT_EQ( event, 0 ); } if( ( expect_event > FOUNDATIONEVENT_TERMINATE + 1 ) && !event ) break; thread_yield(); } while( time_current() < limit ); EXPECT_EQ( event, 0 ); EXPECT_EQ( expect_event, FOUNDATIONEVENT_TERMINATE + 2 ); EXPECT_LE( time_current(), limit ); //Reverse order of delivery current = time_current(); delivery = current + ( time_ticks_per_second() / 2 ); limit = current + ( time_ticks_per_second() * 20 ); event_post( stream, expect_event, 0, 0, 0, current + ( time_ticks_per_second() / 2 ) ); event_post( stream, expect_event + 1, 0, 0, 0, current + (tick_t)((real)time_ticks_per_second() * REAL_C( 0.41 )) ); do { block = event_stream_process( stream ); event = event_next( block, 0 ); current = time_current(); if( ( expect_event == FOUNDATIONEVENT_TERMINATE ) && event ) { EXPECT_EQ( event->id, expect_event ); EXPECT_EQ( event->size, sizeof( event_t ) + 8 ); //8 bytes for additional timestamp payload EXPECT_EQ( event->object, 0 ); EXPECT_EQ( event->flags, EVENTFLAG_DELAY ); EXPECT_EQ( event_payload_size( event ), 0 ); EXPECT_GE( current, delivery ); EXPECT_GE( current, delivery ); ++expect_event; event = event_next( block, event ); } if( ( expect_event == FOUNDATIONEVENT_TERMINATE + 1 ) && event ) { EXPECT_EQ( event->id, expect_event ); EXPECT_EQ( event->size, sizeof( event_t ) + 8 ); //8 bytes for additional timestamp payload EXPECT_EQ( event->object, 0 ); EXPECT_EQ( event->flags, EVENTFLAG_DELAY ); EXPECT_EQ( event_payload_size( event ), 0 ); EXPECT_GE( current, delivery ); EXPECT_GE( current, delivery ); ++expect_event; event = event_next( block, event ); EXPECT_EQ( event, 0 ); } if( ( expect_event > FOUNDATIONEVENT_TERMINATE + 1 ) && !event ) break; thread_yield(); } while( time_current() < limit ); EXPECT_EQ( event, 0 ); EXPECT_EQ( expect_event, FOUNDATIONEVENT_TERMINATE + 2 ); EXPECT_LE( time_current(), limit ); event_stream_deallocate( stream ); return 0; }