Skip to content

Instantly share code, notes, and snippets.

@Zelmoghazy
Created June 23, 2025 18:14
Show Gist options
  • Save Zelmoghazy/023b427692587afb68b05691fb95d71c to your computer and use it in GitHub Desktop.
Save Zelmoghazy/023b427692587afb68b05691fb95d71c to your computer and use it in GitHub Desktop.
Very simple profiler in C
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#include <unistd.h>
#endif
#define SIZE 10000000
#define DEFER(begin, end) \
for(int _defer_ = ((begin), 0); !_defer_; _defer_ = 1, (end))
#define CONCAT(a, b) a##b
#define CONCAT_AUX(a,b) CONCAT(a,b)
/*
Get the number of OS ticks-per-second
*/
static uint64_t get_timer_freq(void)
{
#ifdef _WIN32
LARGE_INTEGER Freq;
QueryPerformanceFrequency(&Freq);
return Freq.QuadPart;
#else
return 1000000000ULL; // nanosecond resolution (clock_gettime)
#endif
}
/*
Get the time elapsed since the last reset in nanoseconds
*/
static uint64_t get_time(void)
{
#ifdef _WIN32
LARGE_INTEGER Value;
QueryPerformanceCounter(&Value);
// We know the time of a single tick in seconds we just convert it to nanoseconds
// and multiply by the number of elapsed ticks
uint64_t elapsed_ns = Value.QuadPart * 1000000000ULL;
elapsed_ns /= get_timer_freq();
return elapsed_ns;
#else
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
uint64_t result = get_timer_freq() * (uint64_t)ts.tv_sec + (uint64_t)ts.tv_nsec;
return result;
#endif
}
typedef struct
{
uint64_t start_time;
const char* label;
} prof_zone;
prof_zone prof_start(const char* name)
{
prof_zone p;
p.start_time = get_time();
p.label = name;
printf("[PROFILE] Starting: %s\n", name);
return p;
}
void prof_end(prof_zone* p)
{
uint64_t end_time = get_time();
double elapsed_ns = (double)(end_time - p->start_time);
double elapsed_ms = elapsed_ns / 1000000.0;
printf("[PROFILE] Finished: %s (%.6f ms)\n", p->label, elapsed_ms);
}
#define PROFILE(name) \
prof_zone CONCAT_AUX(_prof_, __LINE__) = prof_start(name); \
DEFER(0, prof_end(&CONCAT_AUX(_prof_, __LINE__)))
void expensive_operation(void)
{
volatile long sum = 0;
for(int i = 0; i < SIZE; i++) {
sum += i;
}
}
void sleep_test(uint32_t ms)
{
#ifdef _WIN32
Sleep(ms);
#else
usleep(ms * 1000);
#endif
}
void string_processing(void)
{
char *buffer = NULL;
PROFILE("Allocating memory")
{
buffer = malloc(SIZE);
if(!buffer) return;
}
PROFILE("Actual Work")
{
for(int i = 0; i < SIZE; i++) {
sprintf(buffer, "Processing item %d", i);
size_t len = strlen(buffer);
(void)len;
}
}
PROFILE("Freeing memory"){
free(buffer);
}
}
int main(void)
{
PROFILE("main")
{
PROFILE("expensive_operation")
{
expensive_operation();
}
PROFILE("string_processing")
{
string_processing();
}
PROFILE("sleep test")
{
sleep_test(1000);
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment