static void _log_outputf( uint64_t context, int severity, const char* prefix, const char* format, va_list list, void* std ) { log_timestamp_t timestamp = _log_make_timestamp(); uint64_t tid = thread_id(); unsigned int pid = thread_hardware(); int need, more, remain, size = 383; char local_buffer[385]; char* buffer = local_buffer; while(1) { //This is guaranteed to always fit in minimum size of 383 bytes defined above, so need is always > 0 if( _log_prefix ) need = snprintf( buffer, size, "[%u:%02u:%02u.%03u] <%" PRIx64 ":%d> %s", timestamp.hours, timestamp.minutes, timestamp.seconds, timestamp.milliseconds, tid, pid, prefix ); else need = snprintf( buffer, size, "%s", prefix ); remain = size - need; { va_list clist; va_copy( clist, list ); more = vsnprintf( buffer + need, remain, format, clist ); va_end( clist ); } if( ( more > -1 ) && ( more < remain ) ) { buffer[need+more] = '\n'; buffer[need+more+1] = 0; #if FOUNDATION_PLATFORM_WINDOWS OutputDebugStringA( buffer ); #endif #if FOUNDATION_PLATFORM_ANDROID if( _log_stdout ) __android_log_write( ANDROID_LOG_DEBUG + severity - 1, environment_application()->short_name, buffer ); #else if( _log_stdout && std ) fprintf( std, "%s", buffer ); #endif if( _log_callback ) _log_callback( context, severity, buffer ); break; } if( ( more > -1 ) && ( need > -1 ) ) size = more + need + 1; else size *= 2; if( buffer != local_buffer ) memory_deallocate( buffer ); buffer = memory_allocate( size + 2, 0, MEMORY_TEMPORARY ); } if( buffer != local_buffer ) memory_deallocate( buffer ); }
void profile_begin_block( const char* message ) { uint32_t parent; if( !_profile_enable ) return; parent = get_thread_profile_block(); if( !parent ) { //Allocate new master block profile_block_t* block = _profile_allocate_block(); uint32_t blockindex; if( !block ) return; blockindex = BLOCK_INDEX( block ); block->data.id = atomic_add32( &_profile_counter, 1 ); string_copy( block->data.name, message, MAX_MESSAGE_LENGTH ); block->data.processor = thread_hardware(); block->data.thread = (uint32_t)thread_id(); block->data.start = time_current() - _profile_ground_time; set_thread_profile_block( blockindex ); } else { //Allocate new child block profile_block_t* parentblock; profile_block_t* subblock = _profile_allocate_block(); uint32_t subindex; if( !subblock ) return; subindex = BLOCK_INDEX( subblock ); parentblock = GET_BLOCK( parent ); subblock->data.id = atomic_add32( &_profile_counter, 1 ); subblock->data.parentid = parentblock->data.id; string_copy( subblock->data.name, message, MAX_MESSAGE_LENGTH ); subblock->data.processor = thread_hardware(); subblock->data.thread = (uint32_t)thread_id(); subblock->data.start = time_current() - _profile_ground_time; subblock->previous = parent; subblock->sibling = parentblock->child; if( parentblock->child ) GET_BLOCK( parentblock->child )->previous = subindex; parentblock->child = subindex; set_thread_profile_block( subindex ); } }
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 ); } }
static void _profile_put_message_block( uint32_t id, const char* message ) { profile_block_t* subblock = 0; int len = (int)string_length( message ); //Allocate new master block profile_block_t* block = _profile_allocate_block(); if( !block ) return; block->data.id = id; block->data.processor = thread_hardware(); block->data.thread = (uint32_t)thread_id(); block->data.start = time_current() - _profile_ground_time; block->data.end = atomic_add32( &_profile_counter, 1 ); memcpy( block->data.name, message, ( len >= MAX_MESSAGE_LENGTH ) ? MAX_MESSAGE_LENGTH : len ); len -= MAX_MESSAGE_LENGTH; message += MAX_MESSAGE_LENGTH; subblock = block; while( len > 0 ) { //add subblock profile_block_t* cblock = _profile_allocate_block(); uint16_t cblock_index; if( !cblock ) return; cblock_index = BLOCK_INDEX( cblock ); cblock->data.id = id + 1; cblock->data.parentid = (uint32_t)subblock->data.end; cblock->data.processor = block->data.processor; cblock->data.thread = block->data.thread; cblock->data.start = block->data.start; cblock->data.end = atomic_add32( &_profile_counter, 1 ); memcpy( cblock->data.name, message, ( len >= MAX_MESSAGE_LENGTH ) ? MAX_MESSAGE_LENGTH : len ); cblock->sibling = subblock->child; if( cblock->sibling ) GET_BLOCK( cblock->sibling )->previous = cblock_index; subblock->child = cblock_index; cblock->previous = BLOCK_INDEX( subblock ); subblock = cblock; len -= MAX_MESSAGE_LENGTH; message += MAX_MESSAGE_LENGTH; } _profile_put_simple_block( BLOCK_INDEX( block ) ); }
void profile_end_frame( uint64_t counter ) { profile_block_t* block; if( !_profile_enable ) return; //Allocate new master block block = _profile_allocate_block(); if( !block ) return; block->data.id = PROFILE_ID_ENDFRAME; block->data.processor = thread_hardware(); block->data.thread = (uint32_t)thread_id(); block->data.start = time_current() - _profile_ground_time; block->data.end = counter; _profile_put_simple_block( BLOCK_INDEX( block ) ); }
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 ); }