commit fc4b14bc2856fc43c1b6393acbfd045f7f3dd5fa Author: Mika Date: Thu Dec 4 15:57:39 2025 +0000 Add main.c diff --git a/main.c b/main.c new file mode 100644 index 0000000..7f31a09 --- /dev/null +++ b/main.c @@ -0,0 +1,124 @@ +/* + * cpu_governor_monitor - Simple CLI tool to sample the current CPU governor + * and log it together with a caller-supplied C-state indicator. + */ + +#include +#include +#include +#include +#include +#include + +#define GOVERNOR_PATH "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor" + +struct cpu_log_entry { + char governor[30]; + int c_state; + time_t timestamp; +}; + +static void trim_newline(char *str) +{ + if (!str) { + return; + } + size_t len = strcspn(str, "\r\n"); + str[len] = '\0'; +} + +const char *get_current_governor(void) +{ + static char governor_buf[30] = "unknown"; + FILE *file = fopen(GOVERNOR_PATH, "r"); + + if (!file) { + perror("fopen scaling_governor"); + return governor_buf; + } + + if (!fgets(governor_buf, sizeof(governor_buf), file)) { + perror("fgets scaling_governor"); + snprintf(governor_buf, sizeof(governor_buf), "unknown"); + fclose(file); + return governor_buf; + } + + fclose(file); + trim_newline(governor_buf); + return governor_buf; +} + +void log_cpu_state(const char *governor, int c_state) +{ + struct cpu_log_entry entry; + memset(&entry, 0, sizeof(entry)); + + if (governor) { + strncpy(entry.governor, governor, sizeof(entry.governor) - 1); + } else { + strncpy(entry.governor, "unknown", sizeof(entry.governor) - 1); + } + + entry.c_state = c_state; + entry.timestamp = time(NULL); + + char ts_buf[32]; + struct tm tm_info; + + if (localtime_r(&entry.timestamp, &tm_info) != NULL) { + strftime(ts_buf, sizeof(ts_buf), "%Y-%m-%d %H:%M:%S", &tm_info); + } else { + snprintf(ts_buf, sizeof(ts_buf), "unknown_time"); + } + + printf("timestamp=%s (epoch=%ld) governor=%s c_state=%d\n", + ts_buf, + (long)entry.timestamp, + entry.governor, + entry.c_state); +} + +static void print_usage(const char *prog) +{ + fprintf(stderr, "Usage: %s [c_state]\n", prog); + fprintf(stderr, "If c_state is omitted, -1 is logged to indicate unknown.\n"); +} + +static int parse_c_state(const char *arg, int *c_state) +{ + char *endptr = NULL; + long value = strtol(arg, &endptr, 10); + + if (endptr == arg || *endptr != '\0') { + return -1; + } + + if (value < INT_MIN || value > INT_MAX) { + return -1; + } + + *c_state = (int)value; + return 0; +} + +int main(int argc, char *argv[]) +{ + int c_state = -1; + + if (argc > 2) { + print_usage(argv[0]); + return EXIT_FAILURE; + } + + if (argc == 2) { + if (parse_c_state(argv[1], &c_state) != 0) { + fprintf(stderr, "Invalid c_state value: %s\n", argv[1]); + return EXIT_FAILURE; + } + } + + const char *governor = get_current_governor(); + log_cpu_state(governor, c_state); + return EXIT_SUCCESS; +}