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 if (!config) { 125 perror("malloc"); 126 return NULL; 127 } 128 129 dprintf("loading defaults\n"); 130 131 config->sleep = 500000; 132 config->load = 500000; 133 config->sleep_step = 500000; 134 config->load_step = 500000; 135 config->cycles = 5; 136 config->rounds = 50; 137 config->cpu = 0; 138 config->prio = SCHED_HIGH; 139 config->verbose = 0; 140 strncpy(config->governor, "ondemand", sizeof(config->governor)); 141 142 config->output = stdout; 143 144 #ifdef DEFAULT_CONFIG_FILE 145 if (prepare_config(DEFAULT_CONFIG_FILE, config)) 146 return NULL; 147 #endif 148 return config; 149 } 150 151 /** 152 * parses config file and returns the config to the caller 153 * 154 * @param path config file name 155 * 156 * @retval 1 on error 157 * @retval 0 on success 158 **/ 159 160 int prepare_config(const char *path, struct config *config) 161 { 162 size_t len = 0; 163 char opt[16], val[32], *line = NULL; 164 FILE *configfile; 165 166 if (config == NULL) { 167 fprintf(stderr, "error: config is NULL\n"); 168 return 1; 169 } 170 171 configfile = fopen(path, "r"); 172 if (configfile == NULL) { 173 fprintf(stderr, "error: unable to read configfile: %s, %s\n", 174 path, strerror(errno)); 175 free(config); 176 return 1; 177 } 178 179 while (getline(&line, &len, configfile) != -1) { 180 if (line[0] == '#' || line[0] == ' ' || line[0] == '\n') 181 continue; 182 183 if (sscanf(line, "%14s = %30s", opt, val) < 2) 184 continue; 185 186 dprintf("parsing: %s -> %s\n", opt, val); 187 188 if (strcmp("sleep", opt) == 0) 189 sscanf(val, "%li", &config->sleep); 190 191 else if (strcmp("load", opt) == 0) 192 sscanf(val, "%li", &config->load); 193 194 else if (strcmp("load_step", opt) == 0) 195 sscanf(val, "%li", &config->load_step); 196 197 else if (strcmp("sleep_step", opt) == 0) 198 sscanf(val, "%li", &config->sleep_step); 199 200 else if (strcmp("cycles", opt) == 0) 201 sscanf(val, "%u", &config->cycles); 202 203 else if (strcmp("rounds", opt) == 0) 204 sscanf(val, "%u", &config->rounds); 205 206 else if (strcmp("verbose", opt) == 0) 207 sscanf(val, "%u", &config->verbose); 208 209 else if (strcmp("output", opt) == 0) 210 config->output = prepare_output(val); 211 212 else if (strcmp("cpu", opt) == 0) 213 sscanf(val, "%u", &config->cpu); 214 215 else if (strcmp("governor", opt) == 0) { 216 strncpy(config->governor, val, 217 sizeof(config->governor)); 218 config->governor[sizeof(config->governor) - 1] = '\0'; 219 } 220 221 else if (strcmp("priority", opt) == 0) { 222 if (string_to_prio(val) != SCHED_ERR) 223 config->prio = string_to_prio(val); 224 } 225 } 226 227 free(line); 228 229 return 0; 230 } 231