From c477b8a808d39da9e908738ad5d40e3e93096f82 Mon Sep 17 00:00:00 2001 From: Mika Date: Wed, 3 Dec 2025 13:45:00 +0000 Subject: [PATCH] Add main.c --- main.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 main.c diff --git a/main.c b/main.c new file mode 100644 index 0000000..6d30355 --- /dev/null +++ b/main.c @@ -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 +#include +#include +#include + +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 \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; +}