1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * Copyright (c) 2013-2014 Oracle and/or its affiliates. All Rights Reserved.
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or
5f08c3bdfSopenharmony_ci * modify it under the terms of the GNU General Public License as
6f08c3bdfSopenharmony_ci * published by the Free Software Foundation; either version 2 of
7f08c3bdfSopenharmony_ci * the License, or (at your option) any later version.
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * This program is distributed in the hope that it would be useful,
10f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
11f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12f08c3bdfSopenharmony_ci * GNU General Public License for more details.
13f08c3bdfSopenharmony_ci *
14f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License
15f08c3bdfSopenharmony_ci * along with this program; if not, write the Free Software Foundation,
16f08c3bdfSopenharmony_ci * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17f08c3bdfSopenharmony_ci *
18f08c3bdfSopenharmony_ci * Author: Alexey Kodanev <alexey.kodanev@oracle.com>
19f08c3bdfSopenharmony_ci *
20f08c3bdfSopenharmony_ci * Check support for disabling dynamic overclocking in acpi_cpufreq driver.
21f08c3bdfSopenharmony_ci * Required Linux 3.7+.
22f08c3bdfSopenharmony_ci *
23f08c3bdfSopenharmony_ci * The test compares time spent on sum calculation with/without
24f08c3bdfSopenharmony_ci * boost-disable bit. If boost is enabled we can get a slightly shorter
25f08c3bdfSopenharmony_ci * time period. Measure elapsed time instead of sysfs cpuinfo_cur_freq value,
26f08c3bdfSopenharmony_ci * because after the upstream commit 8673b83bf2f013379453b4779047bf3c6ae387e4,
27f08c3bdfSopenharmony_ci * current cpu frequency became target cpu frequency.
28f08c3bdfSopenharmony_ci */
29f08c3bdfSopenharmony_ci
30f08c3bdfSopenharmony_ci#define _GNU_SOURCE
31f08c3bdfSopenharmony_ci#include <errno.h>
32f08c3bdfSopenharmony_ci#include <sched.h>
33f08c3bdfSopenharmony_ci#include <time.h>
34f08c3bdfSopenharmony_ci
35f08c3bdfSopenharmony_ci#include "test.h"
36f08c3bdfSopenharmony_ci#include "lapi/posix_clocks.h"
37f08c3bdfSopenharmony_ci#include "safe_macros.h"
38f08c3bdfSopenharmony_ci
39f08c3bdfSopenharmony_cichar *TCID = "cpufreq_boost";
40f08c3bdfSopenharmony_ci
41f08c3bdfSopenharmony_ci#define SYSFS_CPU_DIR "/sys/devices/system/cpu/"
42f08c3bdfSopenharmony_ci
43f08c3bdfSopenharmony_cistruct cpufreq_driver_info {
44f08c3bdfSopenharmony_ci	char *name;
45f08c3bdfSopenharmony_ci	int off;
46f08c3bdfSopenharmony_ci	char *on_str;
47f08c3bdfSopenharmony_ci	char *off_str;
48f08c3bdfSopenharmony_ci	char *file;
49f08c3bdfSopenharmony_ci};
50f08c3bdfSopenharmony_cistatic const struct cpufreq_driver_info cdrv[] = {
51f08c3bdfSopenharmony_ci	{ "acpi_cpufreq", 0, "1", "0", SYSFS_CPU_DIR "cpufreq/boost" },
52f08c3bdfSopenharmony_ci	{ "intel_pstate", 1, "0", "1", SYSFS_CPU_DIR "intel_pstate/no_turbo" },
53f08c3bdfSopenharmony_ci};
54f08c3bdfSopenharmony_cistatic int id = -1;
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_cistatic int boost_value;
57f08c3bdfSopenharmony_ci
58f08c3bdfSopenharmony_ciconst char governor[]	= SYSFS_CPU_DIR "cpu0/cpufreq/scaling_governor";
59f08c3bdfSopenharmony_cistatic char governor_name[16];
60f08c3bdfSopenharmony_ci
61f08c3bdfSopenharmony_ciconst char maxspeed[]	= SYSFS_CPU_DIR "cpu0/cpufreq/scaling_max_freq";
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_cistatic void check_set_turbo(char *file, char *off)
64f08c3bdfSopenharmony_ci{
65f08c3bdfSopenharmony_ci	int fd;
66f08c3bdfSopenharmony_ci
67f08c3bdfSopenharmony_ci	fd = SAFE_OPEN(NULL, file, O_WRONLY);
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_ci	/* We try to skip test when getting EPERM. */
70f08c3bdfSopenharmony_ci	if (write(fd, off, 1) == -1 && errno == EPERM) {
71f08c3bdfSopenharmony_ci		SAFE_CLOSE(NULL, fd);
72f08c3bdfSopenharmony_ci		tst_brkm(TCONF, NULL,
73f08c3bdfSopenharmony_ci			 "Turbo is disabled by BIOS or unavailable on processor");
74f08c3bdfSopenharmony_ci	}
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_ci	SAFE_CLOSE(NULL, fd);
77f08c3bdfSopenharmony_ci}
78f08c3bdfSopenharmony_ci
79f08c3bdfSopenharmony_cistatic void cleanup(void)
80f08c3bdfSopenharmony_ci{
81f08c3bdfSopenharmony_ci	FILE_PRINTF(cdrv[id].file, "%d", boost_value);
82f08c3bdfSopenharmony_ci
83f08c3bdfSopenharmony_ci	if (governor[0] != '\0')
84f08c3bdfSopenharmony_ci		FILE_PRINTF(governor, "%s", governor_name);
85f08c3bdfSopenharmony_ci}
86f08c3bdfSopenharmony_ci
87f08c3bdfSopenharmony_cistatic void setup(void)
88f08c3bdfSopenharmony_ci{
89f08c3bdfSopenharmony_ci	int fd;
90f08c3bdfSopenharmony_ci	unsigned int i;
91f08c3bdfSopenharmony_ci	tst_require_root();
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_ci	if (tst_is_virt(VIRT_ANY))
94f08c3bdfSopenharmony_ci		tst_brkm(TCONF, NULL, "running in a virtual machine, overclock not reliably measureable");
95f08c3bdfSopenharmony_ci
96f08c3bdfSopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cdrv); ++i) {
97f08c3bdfSopenharmony_ci		fd = open(cdrv[i].file, O_RDWR);
98f08c3bdfSopenharmony_ci		if (fd == -1)
99f08c3bdfSopenharmony_ci			continue;
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_ci		id = i;
102f08c3bdfSopenharmony_ci		close(fd);
103f08c3bdfSopenharmony_ci		break;
104f08c3bdfSopenharmony_ci	}
105f08c3bdfSopenharmony_ci
106f08c3bdfSopenharmony_ci	if (id == -1)
107f08c3bdfSopenharmony_ci		tst_brkm(TCONF, NULL, "overclock not supported");
108f08c3bdfSopenharmony_ci
109f08c3bdfSopenharmony_ci	tst_resm(TINFO, "found '%s' driver, sysfs knob '%s'",
110f08c3bdfSopenharmony_ci		cdrv[id].name, cdrv[id].file);
111f08c3bdfSopenharmony_ci
112f08c3bdfSopenharmony_ci	tst_sig(FORK, DEF_HANDLER, cleanup);
113f08c3bdfSopenharmony_ci
114f08c3bdfSopenharmony_ci	SAFE_FILE_SCANF(NULL, cdrv[i].file, "%d", &boost_value);
115f08c3bdfSopenharmony_ci
116f08c3bdfSopenharmony_ci	/* For intel_pstate, we cannot write data into intel_pstate/no_turbo
117f08c3bdfSopenharmony_ci	 * and return EPERM if turbo is disabled by BIOS or unavailable on
118f08c3bdfSopenharmony_ci	 * processor.  We should check this case by writing original data.
119f08c3bdfSopenharmony_ci	 */
120f08c3bdfSopenharmony_ci	if (!strcmp(cdrv[i].name, "intel_pstate") && boost_value == cdrv[i].off)
121f08c3bdfSopenharmony_ci		check_set_turbo(cdrv[i].file, cdrv[i].off_str);
122f08c3bdfSopenharmony_ci
123f08c3bdfSopenharmony_ci	/* change cpu0 scaling governor */
124f08c3bdfSopenharmony_ci	SAFE_FILE_SCANF(NULL, governor, "%s", governor_name);
125f08c3bdfSopenharmony_ci	SAFE_FILE_PRINTF(cleanup, governor, "%s", "performance");
126f08c3bdfSopenharmony_ci
127f08c3bdfSopenharmony_ci	/* use only cpu0 */
128f08c3bdfSopenharmony_ci	cpu_set_t set;
129f08c3bdfSopenharmony_ci	CPU_ZERO(&set);
130f08c3bdfSopenharmony_ci	CPU_SET(0, &set);
131f08c3bdfSopenharmony_ci	if (sched_setaffinity(0, sizeof(cpu_set_t), &set) < 0)
132f08c3bdfSopenharmony_ci		tst_brkm(TBROK | TERRNO, cleanup, "failed to set CPU0");
133f08c3bdfSopenharmony_ci
134f08c3bdfSopenharmony_ci	struct sched_param params;
135f08c3bdfSopenharmony_ci	params.sched_priority = sched_get_priority_max(SCHED_FIFO);
136f08c3bdfSopenharmony_ci	if (sched_setscheduler(getpid(), SCHED_FIFO, &params)) {
137f08c3bdfSopenharmony_ci		tst_resm(TWARN | TERRNO,
138f08c3bdfSopenharmony_ci			"failed to set FIFO sched with max priority");
139f08c3bdfSopenharmony_ci	}
140f08c3bdfSopenharmony_ci}
141f08c3bdfSopenharmony_ci
142f08c3bdfSopenharmony_cistatic int load_cpu(int max_freq_khz)
143f08c3bdfSopenharmony_ci{
144f08c3bdfSopenharmony_ci	int sum = 0, i = 0, total_time_ms;
145f08c3bdfSopenharmony_ci	struct timespec tv_start, tv_end;
146f08c3bdfSopenharmony_ci
147f08c3bdfSopenharmony_ci	const int max_sum = max_freq_khz / 1000;
148f08c3bdfSopenharmony_ci	const int units = 1000000; /* Mhz */
149f08c3bdfSopenharmony_ci
150f08c3bdfSopenharmony_ci	clock_gettime(CLOCK_MONOTONIC_RAW, &tv_start);
151f08c3bdfSopenharmony_ci
152f08c3bdfSopenharmony_ci	do {
153f08c3bdfSopenharmony_ci		for (i = 0; i < units; ++i)
154f08c3bdfSopenharmony_ci			asm ("" : : : "memory");
155f08c3bdfSopenharmony_ci	} while (++sum < max_sum);
156f08c3bdfSopenharmony_ci
157f08c3bdfSopenharmony_ci	clock_gettime(CLOCK_MONOTONIC_RAW, &tv_end);
158f08c3bdfSopenharmony_ci
159f08c3bdfSopenharmony_ci	total_time_ms = (tv_end.tv_sec - tv_start.tv_sec) * 1000 +
160f08c3bdfSopenharmony_ci		(tv_end.tv_nsec - tv_start.tv_nsec) / 1000000;
161f08c3bdfSopenharmony_ci
162f08c3bdfSopenharmony_ci	if (!total_time_ms)
163f08c3bdfSopenharmony_ci		tst_brkm(TBROK, cleanup, "time period is 0");
164f08c3bdfSopenharmony_ci
165f08c3bdfSopenharmony_ci	tst_resm(TINFO, "elapsed time is %d ms", total_time_ms);
166f08c3bdfSopenharmony_ci
167f08c3bdfSopenharmony_ci	return total_time_ms;
168f08c3bdfSopenharmony_ci}
169f08c3bdfSopenharmony_ci
170f08c3bdfSopenharmony_cistatic void test_run(void)
171f08c3bdfSopenharmony_ci{
172f08c3bdfSopenharmony_ci	int boost_time, boost_off_time, max_freq_khz;
173f08c3bdfSopenharmony_ci	SAFE_FILE_SCANF(cleanup, maxspeed, "%d", &max_freq_khz);
174f08c3bdfSopenharmony_ci	tst_resm(TINFO, "maximum speed is %d KHz", max_freq_khz);
175f08c3bdfSopenharmony_ci
176f08c3bdfSopenharmony_ci	/* Enable boost */
177f08c3bdfSopenharmony_ci	if (boost_value == cdrv[id].off)
178f08c3bdfSopenharmony_ci		SAFE_FILE_PRINTF(cleanup, cdrv[id].file, "%s", cdrv[id].on_str);
179f08c3bdfSopenharmony_ci	tst_resm(TINFO, "load CPU0 with boost enabled");
180f08c3bdfSopenharmony_ci	boost_time = load_cpu(max_freq_khz);
181f08c3bdfSopenharmony_ci
182f08c3bdfSopenharmony_ci	/* Disable boost */
183f08c3bdfSopenharmony_ci	SAFE_FILE_PRINTF(cleanup, cdrv[id].file, "%s", cdrv[id].off_str);
184f08c3bdfSopenharmony_ci	tst_resm(TINFO, "load CPU0 with boost disabled");
185f08c3bdfSopenharmony_ci	boost_off_time = load_cpu(max_freq_khz);
186f08c3bdfSopenharmony_ci
187f08c3bdfSopenharmony_ci	boost_off_time *= .98;
188f08c3bdfSopenharmony_ci
189f08c3bdfSopenharmony_ci	tst_resm((boost_time < boost_off_time) ? TPASS : TFAIL,
190f08c3bdfSopenharmony_ci		"compare time spent with and without boost (-2%%)");
191f08c3bdfSopenharmony_ci}
192f08c3bdfSopenharmony_ci
193f08c3bdfSopenharmony_ciint main(int argc, char *argv[])
194f08c3bdfSopenharmony_ci{
195f08c3bdfSopenharmony_ci	tst_parse_opts(argc, argv, NULL, NULL);
196f08c3bdfSopenharmony_ci
197f08c3bdfSopenharmony_ci	setup();
198f08c3bdfSopenharmony_ci
199f08c3bdfSopenharmony_ci	test_run();
200f08c3bdfSopenharmony_ci
201f08c3bdfSopenharmony_ci	cleanup();
202f08c3bdfSopenharmony_ci
203f08c3bdfSopenharmony_ci	tst_exit();
204f08c3bdfSopenharmony_ci}
205