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