162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*  cpufreq-bench CPUFreq microbenchmark
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <stdio.h>
862306a36Sopenharmony_ci#include <stdlib.h>
962306a36Sopenharmony_ci#include <stdarg.h>
1062306a36Sopenharmony_ci#include <string.h>
1162306a36Sopenharmony_ci#include <time.h>
1262306a36Sopenharmony_ci#include <dirent.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <sys/utsname.h>
1562306a36Sopenharmony_ci#include <sys/types.h>
1662306a36Sopenharmony_ci#include <sys/stat.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "parse.h"
1962306a36Sopenharmony_ci#include "config.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/**
2262306a36Sopenharmony_ci * converts priority string to priority
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * @param str string that represents a scheduler priority
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * @retval priority
2762306a36Sopenharmony_ci * @retval SCHED_ERR when the priority doesn't exit
2862306a36Sopenharmony_ci **/
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cienum sched_prio string_to_prio(const char *str)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	if (strncasecmp("high", str, strlen(str)) == 0)
3362306a36Sopenharmony_ci		return  SCHED_HIGH;
3462306a36Sopenharmony_ci	else if (strncasecmp("default", str, strlen(str)) == 0)
3562306a36Sopenharmony_ci		return SCHED_DEFAULT;
3662306a36Sopenharmony_ci	else if (strncasecmp("low", str, strlen(str)) == 0)
3762306a36Sopenharmony_ci		return SCHED_LOW;
3862306a36Sopenharmony_ci	else
3962306a36Sopenharmony_ci		return SCHED_ERR;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/**
4362306a36Sopenharmony_ci * create and open logfile
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * @param dir directory in which the logfile should be created
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci * @retval logfile on success
4862306a36Sopenharmony_ci * @retval NULL when the file can't be created
4962306a36Sopenharmony_ci **/
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciFILE *prepare_output(const char *dirname)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	FILE *output = NULL;
5462306a36Sopenharmony_ci	int len;
5562306a36Sopenharmony_ci	char *filename, *filename_tmp;
5662306a36Sopenharmony_ci	struct utsname sysdata;
5762306a36Sopenharmony_ci	DIR *dir;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	dir = opendir(dirname);
6062306a36Sopenharmony_ci	if (dir == NULL) {
6162306a36Sopenharmony_ci		if (mkdir(dirname, 0755)) {
6262306a36Sopenharmony_ci			perror("mkdir");
6362306a36Sopenharmony_ci			fprintf(stderr, "error: Cannot create dir %s\n",
6462306a36Sopenharmony_ci				dirname);
6562306a36Sopenharmony_ci			return NULL;
6662306a36Sopenharmony_ci		}
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	len = strlen(dirname) + 30;
7062306a36Sopenharmony_ci	filename = malloc(sizeof(char) * len);
7162306a36Sopenharmony_ci	if (!filename) {
7262306a36Sopenharmony_ci		perror("malloc");
7362306a36Sopenharmony_ci		goto out_dir;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (uname(&sysdata) == 0) {
7762306a36Sopenharmony_ci		len += strlen(sysdata.nodename) + strlen(sysdata.release);
7862306a36Sopenharmony_ci		filename_tmp = realloc(filename, sizeof(*filename) * len);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci		if (filename_tmp == NULL) {
8162306a36Sopenharmony_ci			free(filename);
8262306a36Sopenharmony_ci			perror("realloc");
8362306a36Sopenharmony_ci			goto out_dir;
8462306a36Sopenharmony_ci		}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci		filename = filename_tmp;
8762306a36Sopenharmony_ci		snprintf(filename, len - 1, "%s/benchmark_%s_%s_%li.log",
8862306a36Sopenharmony_ci			dirname, sysdata.nodename, sysdata.release, time(NULL));
8962306a36Sopenharmony_ci	} else {
9062306a36Sopenharmony_ci		snprintf(filename, len - 1, "%s/benchmark_%li.log",
9162306a36Sopenharmony_ci			dirname, time(NULL));
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	dprintf("logfilename: %s\n", filename);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	output = fopen(filename, "w+");
9762306a36Sopenharmony_ci	if (output == NULL) {
9862306a36Sopenharmony_ci		perror("fopen");
9962306a36Sopenharmony_ci		fprintf(stderr, "error: unable to open logfile\n");
10062306a36Sopenharmony_ci		goto out;
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	fprintf(stdout, "Logfile: %s\n", filename);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	fprintf(output, "#round load sleep performance powersave percentage\n");
10662306a36Sopenharmony_ciout:
10762306a36Sopenharmony_ci	free(filename);
10862306a36Sopenharmony_ciout_dir:
10962306a36Sopenharmony_ci	closedir(dir);
11062306a36Sopenharmony_ci	return output;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/**
11462306a36Sopenharmony_ci * returns the default config
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci * @retval default config on success
11762306a36Sopenharmony_ci * @retval NULL when the output file can't be created
11862306a36Sopenharmony_ci **/
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistruct config *prepare_default_config()
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct config *config = malloc(sizeof(struct config));
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	dprintf("loading defaults\n");
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	config->sleep = 500000;
12762306a36Sopenharmony_ci	config->load = 500000;
12862306a36Sopenharmony_ci	config->sleep_step = 500000;
12962306a36Sopenharmony_ci	config->load_step = 500000;
13062306a36Sopenharmony_ci	config->cycles = 5;
13162306a36Sopenharmony_ci	config->rounds = 50;
13262306a36Sopenharmony_ci	config->cpu = 0;
13362306a36Sopenharmony_ci	config->prio = SCHED_HIGH;
13462306a36Sopenharmony_ci	config->verbose = 0;
13562306a36Sopenharmony_ci	strncpy(config->governor, "ondemand", sizeof(config->governor));
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	config->output = stdout;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci#ifdef DEFAULT_CONFIG_FILE
14062306a36Sopenharmony_ci	if (prepare_config(DEFAULT_CONFIG_FILE, config))
14162306a36Sopenharmony_ci		return NULL;
14262306a36Sopenharmony_ci#endif
14362306a36Sopenharmony_ci	return config;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/**
14762306a36Sopenharmony_ci * parses config file and returns the config to the caller
14862306a36Sopenharmony_ci *
14962306a36Sopenharmony_ci * @param path config file name
15062306a36Sopenharmony_ci *
15162306a36Sopenharmony_ci * @retval 1 on error
15262306a36Sopenharmony_ci * @retval 0 on success
15362306a36Sopenharmony_ci **/
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ciint prepare_config(const char *path, struct config *config)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	size_t len = 0;
15862306a36Sopenharmony_ci	char opt[16], val[32], *line = NULL;
15962306a36Sopenharmony_ci	FILE *configfile;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (config == NULL) {
16262306a36Sopenharmony_ci		fprintf(stderr, "error: config is NULL\n");
16362306a36Sopenharmony_ci		return 1;
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	configfile = fopen(path, "r");
16762306a36Sopenharmony_ci	if (configfile == NULL) {
16862306a36Sopenharmony_ci		perror("fopen");
16962306a36Sopenharmony_ci		fprintf(stderr, "error: unable to read configfile\n");
17062306a36Sopenharmony_ci		free(config);
17162306a36Sopenharmony_ci		return 1;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	while (getline(&line, &len, configfile) != -1) {
17562306a36Sopenharmony_ci		if (line[0] == '#' || line[0] == ' ' || line[0] == '\n')
17662306a36Sopenharmony_ci			continue;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci		if (sscanf(line, "%14s = %30s", opt, val) < 2)
17962306a36Sopenharmony_ci			continue;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci		dprintf("parsing: %s -> %s\n", opt, val);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci		if (strcmp("sleep", opt) == 0)
18462306a36Sopenharmony_ci			sscanf(val, "%li", &config->sleep);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci		else if (strcmp("load", opt) == 0)
18762306a36Sopenharmony_ci			sscanf(val, "%li", &config->load);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		else if (strcmp("load_step", opt) == 0)
19062306a36Sopenharmony_ci			sscanf(val, "%li", &config->load_step);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		else if (strcmp("sleep_step", opt) == 0)
19362306a36Sopenharmony_ci			sscanf(val, "%li", &config->sleep_step);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci		else if (strcmp("cycles", opt) == 0)
19662306a36Sopenharmony_ci			sscanf(val, "%u", &config->cycles);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		else if (strcmp("rounds", opt) == 0)
19962306a36Sopenharmony_ci			sscanf(val, "%u", &config->rounds);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		else if (strcmp("verbose", opt) == 0)
20262306a36Sopenharmony_ci			sscanf(val, "%u", &config->verbose);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		else if (strcmp("output", opt) == 0)
20562306a36Sopenharmony_ci			config->output = prepare_output(val);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci		else if (strcmp("cpu", opt) == 0)
20862306a36Sopenharmony_ci			sscanf(val, "%u", &config->cpu);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci		else if (strcmp("governor", opt) == 0) {
21162306a36Sopenharmony_ci			strncpy(config->governor, val,
21262306a36Sopenharmony_ci					sizeof(config->governor));
21362306a36Sopenharmony_ci			config->governor[sizeof(config->governor) - 1] = '\0';
21462306a36Sopenharmony_ci		}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		else if (strcmp("priority", opt) == 0) {
21762306a36Sopenharmony_ci			if (string_to_prio(val) != SCHED_ERR)
21862306a36Sopenharmony_ci				config->prio = string_to_prio(val);
21962306a36Sopenharmony_ci		}
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	free(line);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	return 0;
22562306a36Sopenharmony_ci}
226