Beispiel #1
0
static void*
_profile_stream_thread(void* arg) {
	FOUNDATION_UNUSED(arg);
	thread_yield();

	while (!thread_try_wait(4)) {
		profile_log(STRING_CONST("Thread message"));

		profile_begin_block(STRING_CONST("Thread block"));
		{
			profile_update_block();

			profile_begin_block(STRING_CONST("Thread subblock"));
			{
				profile_log(STRING_CONST("Sub message"));

				profile_trylock(STRING_CONST("Trylock"));
				profile_lock(STRING_CONST("Trylock"));

				profile_wait(STRING_CONST("Wait"));
				profile_signal(STRING_CONST("Signal"));

				thread_sleep(2);

				profile_unlock(STRING_CONST("Trylock"));

				profile_log(STRING_CONST("End sub"));
			}
			profile_end_block();

			profile_begin_block(STRING_CONST("Thread second subblock"));
			{
				profile_update_block();

				profile_begin_block(STRING_CONST("Thread subblock"));
				{
				}
				profile_end_block();
			}
			profile_end_block();

			profile_trylock(STRING_CONST("Trylock"));
			thread_sleep(1);

			profile_lock(STRING_CONST("Trylock"));
			thread_sleep(4);

			profile_unlock(STRING_CONST("Trylock"));
		}
		profile_end_block();

		atomic_add64(&_profile_generated_blocks, 14);
	}

	return 0;
}
Beispiel #2
0
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;
}
Beispiel #3
0
static void* _profile_stream_thread( object_t thread, void* arg )
{
	FOUNDATION_UNUSED( arg );
	thread_yield();

	while( !thread_should_terminate( thread ) )
	{
		profile_log( "Thread message" );

		profile_begin_block( "Thread block" );
		{
			profile_update_block();

			profile_begin_block( "Thread subblock" );
			{
				profile_log( "Sub message" );

				profile_trylock( "Trylock" );
				profile_lock( "Trylock" );

				profile_wait( "Wait" );
				profile_signal( "Signal" );

				thread_sleep( 2 );

				profile_unlock( "Trylock" );

				profile_log( "End sub" );
			}
			profile_end_block();

			profile_trylock( "Trylock" );
			thread_sleep( 1 );

			profile_lock( "Trylock" );
			thread_sleep( 4 );

			profile_unlock( "Trylock" );
		}
		profile_end_block();

		thread_sleep( 4 );

		atomic_add64( &_profile_generated_blocks, 12 );
	}

	return 0;
}
Beispiel #4
0
void profile_end_block( void )
{
	uint32_t block_index = get_thread_profile_block();
	profile_block_t* block;
	if( !_profile_enable || !block_index )
		return;

	block = GET_BLOCK( block_index );
	block->data.end = time_current() - _profile_ground_time;

	if( block->previous )
	{
		unsigned int processor;
		profile_block_t* current = block;
		profile_block_t* previous = GET_BLOCK( block->previous );
		profile_block_t* parent;
		unsigned int current_index = block_index;
		unsigned int parent_index;
		while( previous->child != current_index )
		{
			current_index = current->previous; //Walk sibling list backwards
			current = GET_BLOCK( current_index );
			previous = GET_BLOCK( current->previous );
#if PROFILE_ENABLE_SANITY_CHECKS
			FOUNDATION_ASSERT( current_index != 0 );
			FOUNDATION_ASSERT( current->previous != 0 );
#endif
		}
		parent_index = current->previous; //Previous now points to parent
		parent = GET_BLOCK( parent_index );
#if PROFILE_ENABLE_SANITY_CHECKS
		FOUNDATION_ASSERT( parent_index != block_index );
#endif
		set_thread_profile_block( parent_index );

		processor = thread_hardware();
		if( parent->data.processor != processor )
		{
			const char* message = parent->data.name;
			//Thread migrated, split into new block
			profile_end_block();
			profile_begin_block( message );
		}
	}
	else
	{
		_profile_put_root_block( block_index );
		set_thread_profile_block( 0 );
	}
}
Beispiel #5
0
static void*
_profile_fail_thread(void* arg) {
	FOUNDATION_UNUSED(arg);
	thread_sleep(10);

	while (!thread_try_wait(1)) {
		profile_log(STRING_CONST("Thread message"));

		profile_begin_block(STRING_CONST("Thread block"));
		{
			profile_update_block();

			profile_begin_block(STRING_CONST("Thread subblock"));
			{
				profile_log(STRING_CONST("Sub message"));

				profile_trylock(STRING_CONST("Trylock"));

				profile_lock(STRING_CONST("Trylock"));

				profile_wait(STRING_CONST("Wait"));
				profile_signal(STRING_CONST("Signal"));

				profile_unlock(STRING_CONST("Trylock"));

				profile_log(STRING_CONST("End sub"));

				thread_yield();
			}
			profile_end_block();
		}
		profile_end_block();
	}

	return 0;
}
Beispiel #6
0
void _profile_thread_finalize( void )
{
#if BUILD_ENABLE_PROFILE
	uint32_t block_index, last_block = 0;
	while( ( block_index = get_thread_profile_block() ) )
	{
		log_warnf( 0, WARNING_SUSPICIOUS, "Profile thread cleanup, free block %u", block_index );
		if( last_block == block_index )
		{
			log_warnf( 0, WARNING_SUSPICIOUS, "Unrecoverable error, self reference in block %u", block_index );
			break;
		}
		profile_end_block();
	}
#endif
}
Beispiel #7
0
void profile_update_block( void )
{
	char* message;
	unsigned int processor;
	uint32_t block_index = get_thread_profile_block();
	profile_block_t* block;
	if( !_profile_enable || !block_index )
		return;

	block = GET_BLOCK( block_index );
	message = block->data.name;
	processor = thread_hardware();
	if( block->data.processor == processor )
		return;

	//Thread migrated to another core, split into new block
	profile_end_block();
	profile_begin_block( message );
}
Beispiel #8
0
void
lua_execute_pending(lua_t* env) {
	profile_begin_block(STRING_CONST("lua exec"));

	unsigned int head = env->queue_head;
	while (env->queue[head].cmd != LUACMD_WAIT) {
		//Execute
		switch (env->queue[head].cmd) {
		case LUACMD_LOAD:
			lua_do_eval_stream(env, env->queue[head].data.ptr);
			break;

		case LUACMD_EVAL:
			lua_do_eval_string(env, env->queue[head].data.name, env->queue[head].size);
			break;

		case LUACMD_CALL:
			lua_do_call_custom(env, env->queue[head].data.name, env->queue[head].size, &env->queue[head].arg);
			break;

		case LUACMD_BIND:
		case LUACMD_BIND_INT:
		case LUACMD_BIND_VAL:
			lua_do_bind(env, env->queue[head].data.name, env->queue[head].size, env->queue[head].cmd,
			            env->queue[head].arg.value[0]);
			break;

		default:
			break;
		}

		//Mark as executed
		env->queue[head].cmd = LUACMD_WAIT;

		if (++head == BUILD_LUA_CALL_QUEUE_SIZE)
			head = 0;
	}
	env->queue_head = head;

	profile_end_block();
}
Beispiel #9
0
void system_process_events( void )
{
#if FOUNDATION_PLATFORM_ANDROID
	profile_begin_block( "system events" );

	int ident = 0;
	int events = 0;
	int nummsg = 0;
	struct android_poll_source* source = 0;
	struct android_app* app = android_app();

	while( ( ident = ALooper_pollAll( 0, 0, &events, (void**)&source ) ) >= 0 )
	{
		// Process this event.
		if( source )
			source->process( app, source );
		++nummsg;
	}
	
	profile_end_block();
#endif
}
Beispiel #10
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;
}