^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* cpufreq-bench CPUFreq microbenchmark
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <stdarg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <dirent.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <sys/utsname.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <sys/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <sys/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "parse.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "config.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * converts priority string to priority
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * @param str string that represents a scheduler priority
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * @retval priority
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * @retval SCHED_ERR when the priority doesn't exit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) **/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) enum sched_prio string_to_prio(const char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) if (strncasecmp("high", str, strlen(str)) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return SCHED_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) else if (strncasecmp("default", str, strlen(str)) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return SCHED_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) else if (strncasecmp("low", str, strlen(str)) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return SCHED_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return SCHED_ERR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * create and open logfile
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * @param dir directory in which the logfile should be created
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * @retval logfile on success
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * @retval NULL when the file can't be created
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) **/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) FILE *prepare_output(const char *dirname)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) FILE *output = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) char *filename, *filename_tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct utsname sysdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) DIR *dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) dir = opendir(dirname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (dir == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (mkdir(dirname, 0755)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) perror("mkdir");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) fprintf(stderr, "error: Cannot create dir %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) dirname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) len = strlen(dirname) + 30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) filename = malloc(sizeof(char) * len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (!filename) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) perror("malloc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) goto out_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (uname(&sysdata) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) len += strlen(sysdata.nodename) + strlen(sysdata.release);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) filename_tmp = realloc(filename, sizeof(*filename) * len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (filename_tmp == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) free(filename);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) perror("realloc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) goto out_dir;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) filename = filename_tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) snprintf(filename, len - 1, "%s/benchmark_%s_%s_%li.log",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) dirname, sysdata.nodename, sysdata.release, time(NULL));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) snprintf(filename, len - 1, "%s/benchmark_%li.log",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) dirname, time(NULL));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) dprintf("logfilename: %s\n", filename);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) output = fopen(filename, "w+");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (output == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) perror("fopen");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) fprintf(stderr, "error: unable to open logfile\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) fprintf(stdout, "Logfile: %s\n", filename);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) fprintf(output, "#round load sleep performance powersave percentage\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) free(filename);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) out_dir:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) closedir(dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return output;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) * returns the default config
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * @retval default config on success
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * @retval NULL when the output file can't be created
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) **/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) struct config *prepare_default_config()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) struct config *config = malloc(sizeof(struct config));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) dprintf("loading defaults\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) config->sleep = 500000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) config->load = 500000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) config->sleep_step = 500000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) config->load_step = 500000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) config->cycles = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) config->rounds = 50;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) config->cpu = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) config->prio = SCHED_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) config->verbose = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) strncpy(config->governor, "ondemand", sizeof(config->governor));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) config->output = stdout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) #ifdef DEFAULT_CONFIG_FILE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (prepare_config(DEFAULT_CONFIG_FILE, config))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) return config;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * parses config file and returns the config to the caller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * @param path config file name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * @retval 1 on error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * @retval 0 on success
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) **/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) int prepare_config(const char *path, struct config *config)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) size_t len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) char opt[16], val[32], *line = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) FILE *configfile;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (config == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) fprintf(stderr, "error: config is NULL\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) configfile = fopen(path, "r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) if (configfile == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) perror("fopen");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) fprintf(stderr, "error: unable to read configfile\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) free(config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) while (getline(&line, &len, configfile) != -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (line[0] == '#' || line[0] == ' ' || line[0] == '\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (sscanf(line, "%14s = %30s", opt, val) < 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) dprintf("parsing: %s -> %s\n", opt, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) if (strcmp("sleep", opt) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) sscanf(val, "%li", &config->sleep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) else if (strcmp("load", opt) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) sscanf(val, "%li", &config->load);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) else if (strcmp("load_step", opt) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) sscanf(val, "%li", &config->load_step);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) else if (strcmp("sleep_step", opt) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) sscanf(val, "%li", &config->sleep_step);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) else if (strcmp("cycles", opt) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) sscanf(val, "%u", &config->cycles);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) else if (strcmp("rounds", opt) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) sscanf(val, "%u", &config->rounds);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) else if (strcmp("verbose", opt) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) sscanf(val, "%u", &config->verbose);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) else if (strcmp("output", opt) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) config->output = prepare_output(val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) else if (strcmp("cpu", opt) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) sscanf(val, "%u", &config->cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) else if (strcmp("governor", opt) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) strncpy(config->governor, val,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) sizeof(config->governor));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) config->governor[sizeof(config->governor) - 1] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) else if (strcmp("priority", opt) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (string_to_prio(val) != SCHED_ERR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) config->prio = string_to_prio(val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) free(line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }