Commit | Line | Data |
---|---|---|
7fe2f639 DB |
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; | |
0b81561c | 68 | char *filename, *filename_tmp; |
7fe2f639 DB |
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); | |
983d9e06 CIK |
84 | if (!filename) { |
85 | perror("malloc"); | |
86 | goto out_dir; | |
87 | } | |
7fe2f639 DB |
88 | |
89 | if (uname(&sysdata) == 0) { | |
90 | len += strlen(sysdata.nodename) + strlen(sysdata.release); | |
0b81561c | 91 | filename_tmp = realloc(filename, sizeof(*filename) * len); |
7fe2f639 | 92 | |
0b81561c AS |
93 | if (filename_tmp == NULL) { |
94 | free(filename); | |
7fe2f639 | 95 | perror("realloc"); |
983d9e06 | 96 | goto out_dir; |
7fe2f639 DB |
97 | } |
98 | ||
0b81561c | 99 | filename = filename_tmp; |
02af3cb5 | 100 | snprintf(filename, len - 1, "%s/benchmark_%s_%s_%li.log", |
7fe2f639 DB |
101 | dirname, sysdata.nodename, sysdata.release, time(NULL)); |
102 | } else { | |
02af3cb5 DB |
103 | snprintf(filename, len - 1, "%s/benchmark_%li.log", |
104 | dirname, time(NULL)); | |
7fe2f639 DB |
105 | } |
106 | ||
107 | dprintf("logilename: %s\n", filename); | |
108 | ||
02af3cb5 DB |
109 | output = fopen(filename, "w+"); |
110 | if (output == NULL) { | |
7fe2f639 DB |
111 | perror("fopen"); |
112 | fprintf(stderr, "error: unable to open logfile\n"); | |
983d9e06 | 113 | goto out; |
7fe2f639 DB |
114 | } |
115 | ||
116 | fprintf(stdout, "Logfile: %s\n", filename); | |
117 | ||
7fe2f639 | 118 | fprintf(output, "#round load sleep performance powersave percentage\n"); |
983d9e06 CIK |
119 | out: |
120 | free(filename); | |
121 | out_dir: | |
122 | closedir(dir); | |
7fe2f639 DB |
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; | |
02af3cb5 | 145 | config->cpu = 0; |
7fe2f639 DB |
146 | config->prio = SCHED_HIGH; |
147 | config->verbose = 0; | |
148 | strncpy(config->governor, "ondemand", 8); | |
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; | |
13f6de52 RS |
171 | char opt[16], val[32], *line = NULL; |
172 | FILE *configfile; | |
7fe2f639 DB |
173 | |
174 | if (config == NULL) { | |
175 | fprintf(stderr, "error: config is NULL\n"); | |
176 | return 1; | |
177 | } | |
178 | ||
13f6de52 | 179 | configfile = fopen(path, "r"); |
7fe2f639 DB |
180 | if (configfile == NULL) { |
181 | perror("fopen"); | |
02af3cb5 | 182 | fprintf(stderr, "error: unable to read configfile\n"); |
7fe2f639 DB |
183 | free(config); |
184 | return 1; | |
185 | } | |
186 | ||
02af3cb5 | 187 | while (getline(&line, &len, configfile) != -1) { |
13f6de52 | 188 | if (line[0] == '#' || line[0] == ' ' || line[0] == '\n') |
7fe2f639 DB |
189 | continue; |
190 | ||
13f6de52 RS |
191 | if (sscanf(line, "%14s = %30s", opt, val) < 2) |
192 | continue; | |
7fe2f639 DB |
193 | |
194 | dprintf("parsing: %s -> %s\n", opt, val); | |
195 | ||
13f6de52 | 196 | if (strcmp("sleep", opt) == 0) |
7fe2f639 DB |
197 | sscanf(val, "%li", &config->sleep); |
198 | ||
13f6de52 | 199 | else if (strcmp("load", opt) == 0) |
7fe2f639 DB |
200 | sscanf(val, "%li", &config->load); |
201 | ||
13f6de52 | 202 | else if (strcmp("load_step", opt) == 0) |
7fe2f639 DB |
203 | sscanf(val, "%li", &config->load_step); |
204 | ||
13f6de52 | 205 | else if (strcmp("sleep_step", opt) == 0) |
7fe2f639 DB |
206 | sscanf(val, "%li", &config->sleep_step); |
207 | ||
13f6de52 | 208 | else if (strcmp("cycles", opt) == 0) |
7fe2f639 DB |
209 | sscanf(val, "%u", &config->cycles); |
210 | ||
13f6de52 | 211 | else if (strcmp("rounds", opt) == 0) |
7fe2f639 DB |
212 | sscanf(val, "%u", &config->rounds); |
213 | ||
13f6de52 | 214 | else if (strcmp("verbose", opt) == 0) |
7fe2f639 DB |
215 | sscanf(val, "%u", &config->verbose); |
216 | ||
13f6de52 | 217 | else if (strcmp("output", opt) == 0) |
7fe2f639 DB |
218 | config->output = prepare_output(val); |
219 | ||
13f6de52 | 220 | else if (strcmp("cpu", opt) == 0) |
7fe2f639 DB |
221 | sscanf(val, "%u", &config->cpu); |
222 | ||
13f6de52 RS |
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 | } | |
7fe2f639 | 228 | |
13f6de52 | 229 | else if (strcmp("priority", opt) == 0) { |
02af3cb5 | 230 | if (string_to_prio(val) != SCHED_ERR) |
7fe2f639 DB |
231 | config->prio = string_to_prio(val); |
232 | } | |
233 | } | |
234 | ||
235 | free(line); | |
7fe2f639 DB |
236 | |
237 | return 0; | |
238 | } |