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