0001
0002
0003 #define _GNU_SOURCE
0004 #include <errno.h>
0005 #include <stdio.h>
0006 #include <stdlib.h>
0007 #include <signal.h>
0008 #include <sched.h>
0009 #include <string.h>
0010 #include <unistd.h>
0011 #include <fcntl.h>
0012 #include <locale.h>
0013 #include <sys/types.h>
0014 #include <sys/stat.h>
0015 #include <sys/time.h>
0016 #include <sys/wait.h>
0017
0018 #include <bpf/bpf.h>
0019 #include <bpf/libbpf.h>
0020
0021 static int cstate_map_fd, pstate_map_fd;
0022
0023 #define MAX_CPU 8
0024 #define MAX_PSTATE_ENTRIES 5
0025 #define MAX_CSTATE_ENTRIES 3
0026 #define MAX_STARS 40
0027
0028 #define CPUFREQ_MAX_SYSFS_PATH "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
0029 #define CPUFREQ_LOWEST_FREQ "208000"
0030 #define CPUFREQ_HIGHEST_FREQ "12000000"
0031
0032 struct cpu_stat_data {
0033 unsigned long cstate[MAX_CSTATE_ENTRIES];
0034 unsigned long pstate[MAX_PSTATE_ENTRIES];
0035 };
0036
0037 static struct cpu_stat_data stat_data[MAX_CPU];
0038
0039 static void cpu_stat_print(void)
0040 {
0041 int i, j;
0042 char state_str[sizeof("cstate-9")];
0043 struct cpu_stat_data *data;
0044
0045
0046 printf("\033[2J");
0047
0048
0049 printf("\nCPU states statistics:\n");
0050 printf("%-10s ", "state(ms)");
0051
0052 for (i = 0; i < MAX_CSTATE_ENTRIES; i++) {
0053 sprintf(state_str, "cstate-%d", i);
0054 printf("%-11s ", state_str);
0055 }
0056
0057 for (i = 0; i < MAX_PSTATE_ENTRIES; i++) {
0058 sprintf(state_str, "pstate-%d", i);
0059 printf("%-11s ", state_str);
0060 }
0061
0062 printf("\n");
0063
0064 for (j = 0; j < MAX_CPU; j++) {
0065 data = &stat_data[j];
0066
0067 printf("CPU-%-6d ", j);
0068 for (i = 0; i < MAX_CSTATE_ENTRIES; i++)
0069 printf("%-11ld ", data->cstate[i] / 1000000);
0070
0071 for (i = 0; i < MAX_PSTATE_ENTRIES; i++)
0072 printf("%-11ld ", data->pstate[i] / 1000000);
0073
0074 printf("\n");
0075 }
0076 }
0077
0078 static void cpu_stat_update(int cstate_fd, int pstate_fd)
0079 {
0080 unsigned long key, value;
0081 int c, i;
0082
0083 for (c = 0; c < MAX_CPU; c++) {
0084 for (i = 0; i < MAX_CSTATE_ENTRIES; i++) {
0085 key = c * MAX_CSTATE_ENTRIES + i;
0086 bpf_map_lookup_elem(cstate_fd, &key, &value);
0087 stat_data[c].cstate[i] = value;
0088 }
0089
0090 for (i = 0; i < MAX_PSTATE_ENTRIES; i++) {
0091 key = c * MAX_PSTATE_ENTRIES + i;
0092 bpf_map_lookup_elem(pstate_fd, &key, &value);
0093 stat_data[c].pstate[i] = value;
0094 }
0095 }
0096 }
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106 static int cpu_stat_inject_cpu_idle_event(void)
0107 {
0108 int rcpu, i, ret;
0109 cpu_set_t cpumask;
0110 cpu_set_t original_cpumask;
0111
0112 ret = sysconf(_SC_NPROCESSORS_CONF);
0113 if (ret < 0)
0114 return -1;
0115
0116 rcpu = sched_getcpu();
0117 if (rcpu < 0)
0118 return -1;
0119
0120
0121 sched_getaffinity(0, sizeof(original_cpumask), &original_cpumask);
0122
0123 for (i = 0; i < ret; i++) {
0124
0125
0126 if (i == rcpu)
0127 continue;
0128
0129
0130 if (!CPU_ISSET(i, &original_cpumask))
0131 continue;
0132
0133 CPU_ZERO(&cpumask);
0134 CPU_SET(i, &cpumask);
0135
0136 sched_setaffinity(0, sizeof(cpumask), &cpumask);
0137 }
0138
0139
0140 sched_setaffinity(0, sizeof(original_cpumask), &original_cpumask);
0141 return 0;
0142 }
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153 static int cpu_stat_inject_cpu_frequency_event(void)
0154 {
0155 int len, fd;
0156
0157 fd = open(CPUFREQ_MAX_SYSFS_PATH, O_WRONLY);
0158 if (fd < 0) {
0159 printf("failed to open scaling_max_freq, errno=%d\n", errno);
0160 return fd;
0161 }
0162
0163 len = write(fd, CPUFREQ_LOWEST_FREQ, strlen(CPUFREQ_LOWEST_FREQ));
0164 if (len < 0) {
0165 printf("failed to open scaling_max_freq, errno=%d\n", errno);
0166 goto err;
0167 }
0168
0169 len = write(fd, CPUFREQ_HIGHEST_FREQ, strlen(CPUFREQ_HIGHEST_FREQ));
0170 if (len < 0) {
0171 printf("failed to open scaling_max_freq, errno=%d\n", errno);
0172 goto err;
0173 }
0174
0175 err:
0176 close(fd);
0177 return len;
0178 }
0179
0180 static void int_exit(int sig)
0181 {
0182 cpu_stat_inject_cpu_idle_event();
0183 cpu_stat_inject_cpu_frequency_event();
0184 cpu_stat_update(cstate_map_fd, pstate_map_fd);
0185 cpu_stat_print();
0186 exit(0);
0187 }
0188
0189 int main(int argc, char **argv)
0190 {
0191 struct bpf_link *link = NULL;
0192 struct bpf_program *prog;
0193 struct bpf_object *obj;
0194 char filename[256];
0195 int ret;
0196
0197 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
0198 obj = bpf_object__open_file(filename, NULL);
0199 if (libbpf_get_error(obj)) {
0200 fprintf(stderr, "ERROR: opening BPF object file failed\n");
0201 return 0;
0202 }
0203
0204 prog = bpf_object__find_program_by_name(obj, "bpf_prog1");
0205 if (!prog) {
0206 printf("finding a prog in obj file failed\n");
0207 goto cleanup;
0208 }
0209
0210
0211 if (bpf_object__load(obj)) {
0212 fprintf(stderr, "ERROR: loading BPF object file failed\n");
0213 goto cleanup;
0214 }
0215
0216 cstate_map_fd = bpf_object__find_map_fd_by_name(obj, "cstate_duration");
0217 pstate_map_fd = bpf_object__find_map_fd_by_name(obj, "pstate_duration");
0218 if (cstate_map_fd < 0 || pstate_map_fd < 0) {
0219 fprintf(stderr, "ERROR: finding a map in obj file failed\n");
0220 goto cleanup;
0221 }
0222
0223 link = bpf_program__attach(prog);
0224 if (libbpf_get_error(link)) {
0225 fprintf(stderr, "ERROR: bpf_program__attach failed\n");
0226 link = NULL;
0227 goto cleanup;
0228 }
0229
0230 ret = cpu_stat_inject_cpu_idle_event();
0231 if (ret < 0)
0232 return 1;
0233
0234 ret = cpu_stat_inject_cpu_frequency_event();
0235 if (ret < 0)
0236 return 1;
0237
0238 signal(SIGINT, int_exit);
0239 signal(SIGTERM, int_exit);
0240
0241 while (1) {
0242 cpu_stat_update(cstate_map_fd, pstate_map_fd);
0243 cpu_stat_print();
0244 sleep(5);
0245 }
0246
0247 cleanup:
0248 bpf_link__destroy(link);
0249 bpf_object__close(obj);
0250 return 0;
0251 }