• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2018 Google, Inc.
3  *
4  * SPDX-License-Identifier: GPL-2.0-or-later
5  */
6 
7 #define _GNU_SOURCE
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <sched.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <time.h>
15 #include <unistd.h>
16 
17 #include "tst_cpu.h"
18 #include "tst_safe_file_ops.h"
19 
20 #include "util.h"
21 
affine(int cpu)22 void affine(int cpu)
23 {
24 	cpu_set_t cpuset;
25 	CPU_ZERO(&cpuset);
26 	CPU_SET(cpu, &cpuset);
27 	ERROR_CHECK(sched_setaffinity(0, sizeof(cpu_set_t), &cpuset));
28 }
29 
30 /*
31  * Busywait for a certain amount of wallclock time.
32  * If sleep is nonzero, sleep for 1ms between each check.
33  */
burn(unsigned int usec,int sleep)34 void burn(unsigned int usec, int sleep)
35 {
36 	unsigned long long now_usec, end_usec;
37 	struct timespec ts;
38 
39 	if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
40 		printf("clock_gettime() reported an error\n");
41 		return;
42 	}
43 	end_usec = (ts.tv_sec) * USEC_PER_SEC + (ts.tv_nsec / 1000) + usec;
44 	while(1) {
45 		if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
46 			printf("clock_gettime() reported an error\n");
47 			return;
48 		}
49 		now_usec = ts.tv_sec * USEC_PER_SEC + ts.tv_nsec / 1000;
50 		if (now_usec > end_usec)
51 			return;
52 		if (sleep)
53 			usleep(1000);
54 	}
55 }
56 
57 #define CAP_STATE_FILE_SIZE 1024
read_capacity_sched_domains(int cpu,unsigned int * cap)58 static int read_capacity_sched_domains(int cpu, unsigned int *cap)
59 {
60 	char *filebuf, *tmp1, *tmp2;
61 	char cap_states_file[100];
62 	int cap_states_fd;
63 	int bytes, rv;
64 
65 	sprintf(cap_states_file,
66 			"/proc/sys/kernel/sched_domain/cpu%d/domain0/group0/energy/cap_states",
67 			cpu);
68 	cap_states_fd = open(cap_states_file, O_RDONLY);
69 	if (cap_states_fd == -1)
70 		return -ENOENT;
71 
72 	bytes = CAP_STATE_FILE_SIZE;
73 	filebuf = calloc(1, CAP_STATE_FILE_SIZE + 1);
74 	if (!filebuf) {
75 		printf("Failed to calloc buffer for cap_states\n");
76 		return -1;
77 	}
78 	tmp1 = filebuf;
79 	while (bytes) {
80 		rv = read(cap_states_fd, tmp1, bytes);
81 		if (rv == -1) {
82 			printf("Could not read cap_states\n");
83 			return -1;
84 		}
85 		if (rv == 0)
86 			break;
87 		tmp1 += rv;
88 		bytes -= rv;
89 	}
90 	if (tmp1 - filebuf == CAP_STATE_FILE_SIZE) {
91 		printf("CAP_STATE_FILE_SIZE exhausted, increase\n");
92 		return -1;
93 	}
94 	tmp1 = strrchr(filebuf, '\t');
95 	if (!tmp1 || tmp1 == filebuf ) {
96 		printf("Malformatted cap_states_file (1).\n%s\n", filebuf);
97 		return -1;
98 	}
99 	tmp1 = strrchr(tmp1 - 1, '\t');
100 	if (!tmp1 || tmp1 == filebuf) {
101 		printf("Malformatted cap_states_file (2).\n%s\n", filebuf);
102 		return -1;
103 	}
104 	tmp1 = strrchr(tmp1 - 1, '\t');
105 	if (!tmp1 || tmp1 == filebuf) {
106 		printf("Malformatted cap_states_file (3).\n%s\n", filebuf);
107 		return -1;
108 	}
109 	/* tmp1 now points to tab after the capacity we want. */
110 	*tmp1 = 0;
111 	tmp2 = strrchr(tmp1 - 1, '\t');
112 	if (!tmp2)
113 		tmp2 = filebuf;
114 	else
115 		tmp2++;
116 	if (sscanf(tmp2,"%d", cap) != 1) {
117 		printf("Failed to parse capacity from cap_states.\n");
118 		return -1;
119 	}
120 	free(filebuf);
121 	if (close(cap_states_fd)) {
122 		printf("Failed to close cap_states file.\n");
123 		return -1;
124 	}
125 
126 	return 0;
127 }
128 
read_capacity_sysfs(int cpu,unsigned int * cap)129 static int read_capacity_sysfs(int cpu, unsigned int *cap)
130 {
131 	char path[100];
132 
133 	sprintf(path, "/sys/devices/system/cpu/cpu%d/cpu_capacity", cpu);
134 
135 	return SAFE_FILE_LINES_SCANF(path, "%u", cap);
136 }
137 
read_cpu_capacity(int cpu,unsigned int * cap)138 static int read_cpu_capacity(int cpu, unsigned int *cap)
139 {
140 	int ret = read_capacity_sched_domains(cpu, cap);
141 
142 	/*
143 	 * Capacities are exposed in sched debug for android 4.9 and older.
144 	 * Otherwise, upstream uses a sysfs interface.
145 	 */
146 	if (ret == -ENOENT)
147 		ret = read_capacity_sysfs(cpu, cap);
148 
149 	if (ret)
150 		perror(NULL);
151 
152 	return ret;
153 }
154 
155 /*
156  * get_bigs = 0, search for smallest CPUs
157  * get_bigs = 1, search for CPUs other than the smallest CPUs
158  */
find_cpus_with_capacity(int get_bigs,cpu_set_t * cpuset)159 int find_cpus_with_capacity(int get_bigs, cpu_set_t *cpuset)
160 {
161 	unsigned int cap, smallest = -1;
162 	int i;
163 
164 	CPU_ZERO(cpuset);
165 
166 	for (i = 0; i < tst_ncpus(); i++) {
167 		if (read_cpu_capacity(i, &cap))
168 			return -1;
169 
170 		if (cap < smallest) {
171 			smallest = cap;
172 			CPU_ZERO(cpuset);
173 			CPU_SET(i, cpuset);
174 		} else if (cap == smallest) {
175 			CPU_SET(i, cpuset);
176 		}
177 	}
178 
179 	if (!get_bigs)
180 		return 0;
181 
182 	for (i = 0; i < tst_ncpus(); i++)
183 		if (CPU_ISSET(i, cpuset))
184 			CPU_CLR(i, cpuset);
185 		else
186 			CPU_SET(i, cpuset);
187 
188 	return 0;
189 }
190 
191