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