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