//////////////////////////////// // NOTE(allen): Profiling by Spall // includes #if ENABLE_MANUAL_PROFILE || ENABLE_AUTO_PROFILE # error cannot build profiling-by-spall with profiling enabled #endif #define PROFILER_SPALL 1 #define ENABLE_MANUAL_PROFILE 1 #include "base/base_context.h" #include "base/base_macros.h" #include "base/base_basic_types.h" #include "base/base_intrinsic.h" #include "base_profiling.h" #include "base_profiling_auto.c" #define SPALL_BUFFER_CAP MB(1) // linkable global/thread variables SpallProfile spall_ctx = {0}; threadvar SpallBuffer spall_buffer = {0}; // windows implementation #if OS_WINDOWS #undef function #include #define function static function U64 spallprof_tick_per_usecond(void){ typedef int QueryInfoType(S32, void*, U32, U32*); U64 result = Billion(3); B32 accurate = 0; HMODULE ntdll = LoadLibrary("ntdll.dll"); if (ntdll != 0){ QueryInfoType *NtQuerySystemInformation = (QueryInfoType*)GetProcAddress(ntdll, "NtQuerySystemInformation"); if (NtQuerySystemInformation != 0){ // TODO(allen): audit volatile U64 *hsuv = 0; U32 size = 0; S32 query_result = NtQuerySystemInformation(0xc5, (void**)&hsuv, sizeof(hsuv), &size); if (size == sizeof(hsuv) && query_result >= 0){ result = (Million(10) << 32)/(hsuv[1] >> 32); accurate = 1; } } FreeLibrary(ntdll); } if (!accurate){ // TODO(allen): This is forcing any program that is built with profiling // by spall to also link as a 'graphical' program. How else could I deal // with this bit? MessageBoxA(0, "Could not acquire accurate rdtsc/sec value", "Profiling by Spall: Error", MB_OK); } return(result); } function void* spallprof_alloc(U64 size){ void *result = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); Assert(result != 0); return(result); } function void spallprof_free(void *ptr, U64 size){ VirtualFree(ptr, 0, MEM_RELEASE); } #else # error need no implementation for profiling by spall on this os #endif // profiling interface implementation link_function void prof_open(char *name){ U64 tick_per_usecond = spallprof_tick_per_usecond(); spall_ctx = spall_init_file(name, 1000000./tick_per_usecond); } link_function void prof_close(void){ spall_quit(&spall_ctx); } link_function void prof_thread_begin(void){ void *buffer = spallprof_alloc(SPALL_BUFFER_CAP); spall_buffer.length = SPALL_BUFFER_CAP; spall_buffer.data = buffer; spall_buffer_init(&spall_ctx, &spall_buffer); } link_function void prof_thread_end(void){ spall_buffer_quit(&spall_ctx, &spall_buffer); spallprof_free(spall_buffer.data, spall_buffer.length); MemoryZeroStruct(&spall_buffer); } link_function void prof_thread_flush(void){ spall_buffer_flush(&spall_ctx, &spall_buffer); } link_function void prof_begin(char *name, U32 len){ spall_buffer_begin(&spall_ctx, &spall_buffer, name, len, intrinsic_rdtsc()); } link_function void prof_end(void){ spall_buffer_end(&spall_ctx, &spall_buffer, intrinsic_rdtsc()); }