DECLARE_TEST(profile, initialize) { error_t err = error(); _test_profile_offset = 0; atomic_store32(&_test_profile_output_counter, 0); profile_initialize(STRING_CONST("test_profile"), _test_profile_buffer, TEST_PROFILE_BUFFER_SIZE); profile_enable(true); profile_log(STRING_CONST("testing")); thread_sleep(1000); profile_enable(false); profile_finalize(); #if BUILD_ENABLE_PROFILE EXPECT_GT(atomic_load32(&_test_profile_output_counter), 0); #else EXPECT_EQ(atomic_load32(&_test_profile_output_counter), 0); #endif err = error(); EXPECT_EQ(err, ERROR_NONE); return 0; }
DECLARE_TEST( profile, initialize ) { error_t err = error(); _test_profile_offset = 0; atomic_store32( &_test_profile_output_counter, 0 ); profile_initialize( "test_profile", _test_profile_buffer, _test_profile_buffer_size ); profile_enable( true ); profile_log( "testing" ); thread_sleep( 1000 ); profile_enable( false ); profile_shutdown(); #if BUILD_ENABLE_PROFILE EXPECT_GT( atomic_load32( &_test_profile_output_counter ), 0 ); #else EXPECT_EQ( atomic_load32( &_test_profile_output_counter ), 0 ); #endif err = error(); EXPECT_EQ( err, ERROR_NONE ); return 0; }
DECLARE_TEST( profile, thread ) { object_t thread[32]; int ith; int frame; error_t err = error(); _test_profile_offset = 0; atomic_store32( &_test_profile_output_counter, 0 ); profile_initialize( "test_profile", _test_profile_buffer, 30000/*_test_profile_buffer_size*/ ); profile_enable( true ); profile_set_output_wait( 1 ); log_info( HASH_TEST, "This test will intentionally run out of memory in profiling system" ); for( ith = 0; ith < 32; ++ith ) { thread[ith] = thread_create( _profile_fail_thread, "profile_thread", THREAD_PRIORITY_NORMAL, 0 ); thread_start( thread[ith], 0 ); } test_wait_for_threads_startup( thread, 32 ); for( frame = 0; frame < 1000; ++frame ) { thread_sleep( 16 ); profile_end_frame( frame ); } for( ith = 0; ith < 32; ++ith ) { thread_terminate( thread[ith] ); thread_destroy( thread[ith] ); thread_yield(); } test_wait_for_threads_exit( thread, 32 ); thread_sleep( 1000 ); profile_enable( false ); profile_shutdown(); err = error(); #if BUILD_ENABLE_PROFILE EXPECT_GT( atomic_load32( &_test_profile_output_counter ), 0 ); //TODO: Implement parsing output results #else EXPECT_EQ( atomic_load32( &_test_profile_output_counter ), 0 ); #endif EXPECT_EQ( err, ERROR_NONE ); return 0; }
DECLARE_TEST(profile, thread) { thread_t thread[32]; int ith; uint64_t frame; error_t err = error(); _test_profile_offset = 0; atomic_store32(&_test_profile_output_counter, 0); profile_initialize(STRING_CONST("test_profile"), _test_profile_buffer, 30000); profile_enable(true); profile_set_output_wait(1); log_enable_stdout(false); for (ith = 0; ith < 32; ++ith) thread_initialize(&thread[ith], _profile_fail_thread, 0, STRING_CONST("profile_thread"), THREAD_PRIORITY_NORMAL, 0); for (ith = 0; ith < 32; ++ith) thread_start(&thread[ith]); test_wait_for_threads_startup(thread, 32); for (frame = 0; frame < 1000; ++frame) { thread_sleep(16); profile_end_frame(frame); } for (ith = 0; ith < 32; ++ith) thread_signal(&thread[ith]); test_wait_for_threads_finish(thread, 32); for (ith = 0; ith < 32; ++ith) thread_finalize(&thread[ith]); log_enable_stdout(true); err = error(); thread_sleep(1000); profile_enable(false); profile_finalize(); #if BUILD_ENABLE_PROFILE EXPECT_INTGT(atomic_load32(&_test_profile_output_counter), 0); //TODO: Implement parsing output results #else EXPECT_INTEQ(atomic_load32(&_test_profile_output_counter), 0); #endif EXPECT_INTEQ(err, ERROR_NONE); return 0; }
void profile_shutdown( void ) { profile_enable( 0 ); while( thread_is_thread( _profile_io_thread ) ) thread_sleep( 1 ); _profile_io_thread = 0; //Discard and free up blocks remaining in queue _profile_thread_finalize(); if( atomic_load32( &_profile_root ) ) _profile_process_root_block(); //Sanity checks { uint64_t num_blocks = 0; uint32_t free_block = atomic_load32( &_profile_free ) & 0xffff; if( atomic_load32( &_profile_root ) ) log_error( 0, ERROR_INTERNAL_FAILURE, "Profile module state inconsistent on shutdown, at least one root block still allocated/active" ); while( free_block ) { profile_block_t* block = GET_BLOCK( free_block ); if( block->sibling ) log_errorf( 0, ERROR_INTERNAL_FAILURE, "Profile module state inconsistent on shutdown, block %d has sibling set", free_block ); ++num_blocks; free_block = GET_BLOCK( free_block )->child; } if( _profile_num_blocks ) ++num_blocks; //Include the wasted block 0 if( num_blocks != _profile_num_blocks ) { //If profile output function (user) crashed, this will probably trigger since at least one block will be lost in space log_errorf( 0, ERROR_INTERNAL_FAILURE, "Profile module state inconsistent on shutdown, lost blocks (found %llu of %llu)", num_blocks, _profile_num_blocks ); } } atomic_store32( &_profile_root, 0 ); atomic_store32( &_profile_free, 0 ); _profile_num_blocks = 0; _profile_identifier = 0; }
DECLARE_TEST( profile, stream ) { object_t thread[32]; int ith; int frame; char* filename; error(); filename = path_merge( environment_temporary_directory(), "test.profile" ); log_infof( HASH_TEST, "Output to profile file: %s", filename ); fs_make_directory( environment_temporary_directory() ); _profile_stream = fs_open_file( filename, STREAM_OUT | STREAM_BINARY ); string_deallocate( filename ); profile_initialize( "test_profile", _test_profile_buffer, _test_profile_buffer_size ); profile_set_output( _profile_file_writer ); profile_set_output_wait( 10 ); profile_enable( true ); for( ith = 0; ith < 32; ++ith ) { thread[ith] = thread_create( _profile_stream_thread, "profile_thread", THREAD_PRIORITY_NORMAL, 0 ); thread_start( thread[ith], 0 ); } test_wait_for_threads_startup( thread, 32 ); for( frame = 0; frame < 1000; ++frame ) { thread_sleep( 16 ); profile_log( "This is a really long profile log line that should break into multiple profile blocks automatically without causing any issues whatsoever if everything works as expected which it should or the code needs to be fixed" ); profile_end_frame( frame++ ); if( ( frame % 30 ) == 0 ) { profile_enable( false ); thread_sleep( 10 ); profile_enable( true ); } } for( ith = 0; ith < 32; ++ith ) { thread_terminate( thread[ith] ); thread_destroy( thread[ith] ); thread_yield(); } test_wait_for_threads_exit( thread, 32 ); profile_end_frame( frame++ ); profile_set_output_wait( 100 ); thread_sleep( 1000 ); profile_enable( false ); profile_shutdown(); error(); stream_deallocate( _profile_stream ); //TODO: Validate that output is sane log_debugf( HASH_TEST, "Generated %lld blocks", atomic_load64( &_profile_generated_blocks ) ); return 0; }
DECLARE_TEST(profile, stream) { thread_t thread[32]; int ith; uint64_t frame; string_t filename; error(); //Clear error filename = path_allocate_concat(STRING_ARGS(environment_temporary_directory()), STRING_CONST("test.profile")); //log_infof(HASH_TEST, STRING_CONST("Output to profile file: %.*s"), STRING_FORMAT(filename)); fs_make_directory(STRING_ARGS(environment_temporary_directory())); _profile_stream = fs_open_file(STRING_ARGS(filename), STREAM_OUT | STREAM_BINARY); string_deallocate(filename.str); profile_initialize(STRING_CONST("test_profile"), _test_profile_buffer, TEST_PROFILE_BUFFER_SIZE); profile_set_output(_profile_file_writer); profile_set_output_wait(10); profile_enable(true); for (ith = 0; ith < 32; ++ith) thread_initialize(&thread[ith], _profile_stream_thread, 0, STRING_CONST("profile_thread"), THREAD_PRIORITY_NORMAL, 0); for (ith = 0; ith < 32; ++ith) thread_start(&thread[ith]); test_wait_for_threads_startup(thread, 32); for (frame = 0; frame < 1000; ++frame) { thread_sleep(16); profile_log( STRING_CONST("This is a really long profile log line that should break into multiple profile blocks automatically without causing any issues whatsoever if everything works as expected which it should or the code needs to be fixed")); profile_end_frame(frame++); if ((frame % 30) == 0) { profile_enable(false); thread_sleep(10); profile_enable(true); } } for (ith = 0; ith < 32; ++ith) thread_signal(&thread[ith]); test_wait_for_threads_finish(thread, 32); for (ith = 0; ith < 32; ++ith) thread_finalize(&thread[ith]); profile_end_frame(frame++); profile_set_output_wait(10000); thread_sleep(1000); profile_begin_block(STRING_CONST("Should be cleaned up")); profile_end_block(); profile_enable(false); profile_finalize(); error(); stream_deallocate(_profile_stream); //TODO: Validate that output is sane log_debugf(HASH_TEST, STRING_CONST("Generated %" PRId64 " blocks"), atomic_load64(&_profile_generated_blocks)); return 0; }