Skip to content

Instantly share code, notes, and snippets.

@Boostibot
Created March 2, 2024 18:15
Show Gist options
  • Save Boostibot/81214ab3fc923076d3d68e448af87979 to your computer and use it in GitHub Desktop.
Save Boostibot/81214ab3fc923076d3d68e448af87979 to your computer and use it in GitHub Desktop.
A tiny c++ profiler
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <chrono>
static int64_t perf_counter_ns()
{
using namespace std::chrono;
return (int64_t) duration_cast<nanoseconds>(system_clock::now().time_since_epoch()).count();
}
static double clock_s()
{
static int64_t init_time = perf_counter_ns();
int64_t now = perf_counter_ns();
double clock = (double) (now - init_time) * 1e-9;
return clock;
}
struct Profile_Point {
int64_t counter_sum_ns;
int64_t runs;
bool is_in_progress;
Profile_Point* next;
const char* name;
const char* file;
const char* function;
int line;
};
struct Profiles {
Profile_Point* profiles;
int64_t count;
};
//Staic variables inside static inline functions in c++
// are guaranteed to be truly global (ie shared across translation units)
static inline Profiles* profiles_get()
{
static Profiles profiles = {0};
return &profiles;
}
static void profiles_print()
{
typedef long long lli;
printf("(%-3i) avg total runs location & name\n", (int) profiles_get()->count);
for(Profile_Point* point = profiles_get()->profiles; point != NULL; point = point->next) {
assert(point);
double ns_to_ms = 1e-3;
double avg_time = (double) point->counter_sum_ns / point->runs *ns_to_ms;
double total_time = point->counter_sum_ns*ns_to_ms;
printf("%13.4lf %13.2lf %10lli %s:%i ", avg_time, total_time, (lli) point->runs, point->function, point->line);
if(point->name && strlen(point->name) > 0)
printf("\"%s\"", point->name);
printf("\n");
}
}
static void profiles_print_once_every(double seconds)
{
double now = clock_s();
static double last_time = 0;
if(last_time + seconds < now)
{
printf("\n\n");
last_time = now;
profiles_print();
}
}
struct Profile_Running
{
int64_t start = 0;
Profile_Point* point = NULL;
Profile_Running(Profile_Point* point, const char* name, const char* file, const char* function, int line) {
if(point->line == 0)
{
point->name = name;
point->file = file;
point->function = function;
point->line = line;
point->runs = 0;
point->counter_sum_ns = 0;
point->next = profiles_get()->profiles;
profiles_get()->profiles = point;
profiles_get()->count += 1;
}
this->point = point;
start = perf_counter_ns();
point->is_in_progress = true;
}
~Profile_Running() {
if(point->is_in_progress)
{
point->is_in_progress = false;
int64_t end = perf_counter_ns();
point->counter_sum_ns += end - start;
point->runs += 1;
}
}
};
#define CONCAT_(a, b) a ## b
#define CONCAT(a, b) CONCAT_(a, b)
#define UNIQUE_NAME(name) CONCAT(name, __LINE__)
#ifndef _MSC_VER
#define __FUNCTION__ __func__
#endif
//use this macro: PROFILE() or PROFILE("")
#define PROFILE(...) \
static Profile_Point UNIQUE_NAME(__profile__) = {0}; \
Profile_Running UNIQUE_NAME(__running__)(&UNIQUE_NAME(__profile__), "" __VA_ARGS__, __FILE__, __FUNCTION__, __LINE__) \
void profile_example()
{
PROFILE(); //profiles this scope (entire function)
{
PROFILE("my_profile"); //profiles this scope and name it my_profile
//do some work...
}
profiles_print(); //print the profiles
// ... or print them with interval of at least 3 seconds
profiles_print_once_every(3);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment