Add main.c

This commit is contained in:
Mika 2025-12-03 13:45:00 +00:00
parent 710f32db22
commit c477b8a808

149
main.c Normal file
View file

@ -0,0 +1,149 @@
/*
* micro_benchmark - simple CLI tool to emulate clocksource switch latency patterns.
* It runs configurable loops, estimates timing statistics, and logs results to a file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
struct benchmark_result {
int run_count;
double average_offset;
double std_deviation;
};
static struct benchmark_result g_result = {0};
static int g_last_c_state = 0;
static int g_last_governor = 0;
static double timespec_diff(const struct timespec *start, const struct timespec *end)
{
time_t sec = end->tv_sec - start->tv_sec;
long nsec = end->tv_nsec - start->tv_nsec;
return (double)sec + (double)nsec / 1e9;
}
static void simulate_switch_latency(int c_state, int governor)
{
volatile double sink = 0.0;
unsigned int base_loops = 25000;
unsigned int c_factor = (unsigned int)((c_state >= 0 ? c_state : 0) + 1) * 12000U;
unsigned int g_factor = (unsigned int)((governor >= 0 ? governor : 0) + 1) * 9000U;
unsigned int loops = base_loops + c_factor + g_factor;
for (unsigned int i = 0; i < loops; ++i) {
sink += (i & 0x7U) * 0.0001;
}
}
double run_benchmark(int runs, int c_state, int governor)
{
if (runs <= 0) {
g_result.run_count = 0;
g_result.average_offset = 0.0;
g_result.std_deviation = 0.0;
return 0.0;
}
double *samples = malloc(sizeof(double) * (size_t)runs);
if (!samples) {
fprintf(stderr, "Allocation failed\n");
exit(EXIT_FAILURE);
}
struct timespec seed_ts;
clock_gettime(CLOCK_REALTIME, &seed_ts);
srand((unsigned int)seed_ts.tv_nsec);
for (int i = 0; i < runs; ++i) {
struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
simulate_switch_latency(c_state, governor);
clock_gettime(CLOCK_MONOTONIC, &end);
double delta = timespec_diff(&start, &end);
double jitter = ((double)rand() / (double)RAND_MAX - 0.5) * 5e-6 * (c_state + 1);
delta += jitter;
if (delta < 0.0) {
delta = 0.0;
}
samples[i] = delta;
}
double sum = 0.0;
for (int i = 0; i < runs; ++i) {
sum += samples[i];
}
double avg = sum / (double)runs;
double variance = 0.0;
for (int i = 0; i < runs; ++i) {
double diff = samples[i] - avg;
variance += diff * diff;
}
variance /= (double)runs;
g_result.run_count = runs;
g_result.average_offset = avg;
g_result.std_deviation = sqrt(variance);
free(samples);
return g_result.average_offset;
}
void log_results(const char *filename)
{
if (!filename) {
return;
}
FILE *fp = fopen(filename, "w");
if (!fp) {
fprintf(stderr, "Could not open log file %s\n", filename);
return;
}
time_t now = time(NULL);
fprintf(fp, "# micro_benchmark log\n");
fprintf(fp, "timestamp=%ld\n", (long)now);
fprintf(fp, "runs=%d\n", g_result.run_count);
fprintf(fp, "c_state=%d\n", g_last_c_state);
fprintf(fp, "governor=%d\n", g_last_governor);
fprintf(fp, "average_offset=%.9f\n", g_result.average_offset);
fprintf(fp, "std_deviation=%.9f\n", g_result.std_deviation);
fclose(fp);
}
int main(int argc, char **argv)
{
if (argc < 5) {
fprintf(stderr, "Usage: %s <runs> <c_state> <governor> <logfile>\n", argv[0]);
return EXIT_FAILURE;
}
int runs = atoi(argv[1]);
int c_state = atoi(argv[2]);
int governor = atoi(argv[3]);
const char *logfile = argv[4];
if (runs <= 0) {
fprintf(stderr, "Runs must be positive\n");
return EXIT_FAILURE;
}
g_last_c_state = c_state;
g_last_governor = governor;
run_benchmark(runs, c_state, governor);
printf("Runs: %d\n", g_result.run_count);
printf("C-State: %d\n", g_last_c_state);
printf("Governor: %d\n", g_last_governor);
printf("Average offset: %.9f s\n", g_result.average_offset);
printf("Std dev: %.9f s\n", g_result.std_deviation);
log_results(logfile);
return EXIT_SUCCESS;
}