Add main.c
This commit is contained in:
parent
710f32db22
commit
c477b8a808
1 changed files with 149 additions and 0 deletions
149
main.c
Normal file
149
main.c
Normal 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;
|
||||
}
|
||||
Loading…
Reference in a new issue