mr4th/src/base/base_profiling_by_spall.c

129 lines
3.0 KiB
C

////////////////////////////////
// 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 <Windows.h>
#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());
}