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