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