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 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 */ 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 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 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 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 */ 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