1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | #include <stdint.h> |
4 | #include "resctrl.h" |
5 | |
6 | char llc_occup_path[1024]; |
7 | |
8 | void perf_event_attr_initialize(struct perf_event_attr *pea, __u64 config) |
9 | { |
10 | memset(pea, 0, sizeof(*pea)); |
11 | pea->type = PERF_TYPE_HARDWARE; |
12 | pea->size = sizeof(*pea); |
13 | pea->read_format = PERF_FORMAT_GROUP; |
14 | pea->exclude_kernel = 1; |
15 | pea->exclude_hv = 1; |
16 | pea->exclude_idle = 1; |
17 | pea->exclude_callchain_kernel = 1; |
18 | pea->inherit = 1; |
19 | pea->exclude_guest = 1; |
20 | pea->disabled = 1; |
21 | pea->config = config; |
22 | } |
23 | |
24 | /* Start counters to log values */ |
25 | int perf_event_reset_enable(int pe_fd) |
26 | { |
27 | int ret; |
28 | |
29 | ret = ioctl(pe_fd, PERF_EVENT_IOC_RESET, 0); |
30 | if (ret < 0) |
31 | return ret; |
32 | |
33 | ret = ioctl(pe_fd, PERF_EVENT_IOC_ENABLE, 0); |
34 | if (ret < 0) |
35 | return ret; |
36 | |
37 | return 0; |
38 | } |
39 | |
40 | void perf_event_initialize_read_format(struct perf_event_read *pe_read) |
41 | { |
42 | memset(pe_read, 0, sizeof(*pe_read)); |
43 | pe_read->nr = 1; |
44 | } |
45 | |
46 | int perf_open(struct perf_event_attr *pea, pid_t pid, int cpu_no) |
47 | { |
48 | int pe_fd; |
49 | |
50 | pe_fd = perf_event_open(hw_event: pea, pid, cpu: cpu_no, group_fd: -1, PERF_FLAG_FD_CLOEXEC); |
51 | if (pe_fd == -1) { |
52 | ksft_perror(msg: "Error opening leader" ); |
53 | return -1; |
54 | } |
55 | |
56 | perf_event_reset_enable(pe_fd); |
57 | |
58 | return pe_fd; |
59 | } |
60 | |
61 | /* |
62 | * Get LLC Occupancy as reported by RESCTRL FS |
63 | * For CMT, |
64 | * 1. If con_mon grp and mon grp given, then read from mon grp in |
65 | * con_mon grp |
66 | * 2. If only con_mon grp given, then read from con_mon grp |
67 | * 3. If both not given, then read from root con_mon grp |
68 | * For CAT, |
69 | * 1. If con_mon grp given, then read from it |
70 | * 2. If con_mon grp not given, then read from root con_mon grp |
71 | * |
72 | * Return: =0 on success. <0 on failure. |
73 | */ |
74 | static int get_llc_occu_resctrl(unsigned long *llc_occupancy) |
75 | { |
76 | FILE *fp; |
77 | |
78 | fp = fopen(llc_occup_path, "r" ); |
79 | if (!fp) { |
80 | ksft_perror(msg: "Failed to open results file" ); |
81 | |
82 | return -1; |
83 | } |
84 | if (fscanf(fp, "%lu" , llc_occupancy) <= 0) { |
85 | ksft_perror(msg: "Could not get llc occupancy" ); |
86 | fclose(fp); |
87 | |
88 | return -1; |
89 | } |
90 | fclose(fp); |
91 | |
92 | return 0; |
93 | } |
94 | |
95 | /* |
96 | * print_results_cache: the cache results are stored in a file |
97 | * @filename: file that stores the results |
98 | * @bm_pid: child pid that runs benchmark |
99 | * @llc_value: perf miss value / |
100 | * llc occupancy value reported by resctrl FS |
101 | * |
102 | * Return: 0 on success, < 0 on error. |
103 | */ |
104 | static int print_results_cache(const char *filename, int bm_pid, __u64 llc_value) |
105 | { |
106 | FILE *fp; |
107 | |
108 | if (strcmp(filename, "stdio" ) == 0 || strcmp(filename, "stderr" ) == 0) { |
109 | printf("Pid: %d \t LLC_value: %llu\n" , bm_pid, llc_value); |
110 | } else { |
111 | fp = fopen(filename, "a" ); |
112 | if (!fp) { |
113 | ksft_perror(msg: "Cannot open results file" ); |
114 | |
115 | return -1; |
116 | } |
117 | fprintf(fp, "Pid: %d \t llc_value: %llu\n" , bm_pid, llc_value); |
118 | fclose(fp); |
119 | } |
120 | |
121 | return 0; |
122 | } |
123 | |
124 | /* |
125 | * perf_event_measure - Measure perf events |
126 | * @filename: Filename for writing the results |
127 | * @bm_pid: PID that runs the benchmark |
128 | * |
129 | * Measures perf events (e.g., cache misses) and writes the results into |
130 | * @filename. @bm_pid is written to the results file along with the measured |
131 | * value. |
132 | * |
133 | * Return: =0 on success. <0 on failure. |
134 | */ |
135 | int perf_event_measure(int pe_fd, struct perf_event_read *pe_read, |
136 | const char *filename, int bm_pid) |
137 | { |
138 | int ret; |
139 | |
140 | /* Stop counters after one span to get miss rate */ |
141 | ret = ioctl(pe_fd, PERF_EVENT_IOC_DISABLE, 0); |
142 | if (ret < 0) |
143 | return ret; |
144 | |
145 | ret = read(pe_fd, pe_read, sizeof(*pe_read)); |
146 | if (ret == -1) { |
147 | ksft_perror(msg: "Could not get perf value" ); |
148 | return -1; |
149 | } |
150 | |
151 | return print_results_cache(filename, bm_pid, llc_value: pe_read->values[0].value); |
152 | } |
153 | |
154 | /* |
155 | * measure_llc_resctrl - Measure resctrl LLC value from resctrl |
156 | * @filename: Filename for writing the results |
157 | * @bm_pid: PID that runs the benchmark |
158 | * |
159 | * Measures LLC occupancy from resctrl and writes the results into @filename. |
160 | * @bm_pid is written to the results file along with the measured value. |
161 | * |
162 | * Return: =0 on success. <0 on failure. |
163 | */ |
164 | int measure_llc_resctrl(const char *filename, int bm_pid) |
165 | { |
166 | unsigned long llc_occu_resc = 0; |
167 | int ret; |
168 | |
169 | ret = get_llc_occu_resctrl(llc_occupancy: &llc_occu_resc); |
170 | if (ret < 0) |
171 | return ret; |
172 | |
173 | return print_results_cache(filename, bm_pid, llc_value: llc_occu_resc); |
174 | } |
175 | |
176 | /* |
177 | * show_cache_info - Show generic cache test information |
178 | * @no_of_bits: Number of bits |
179 | * @avg_llc_val: Average of LLC cache result data |
180 | * @cache_span: Cache span |
181 | * @lines: @cache_span in lines or bytes |
182 | */ |
183 | void show_cache_info(int no_of_bits, __u64 avg_llc_val, size_t cache_span, bool lines) |
184 | { |
185 | ksft_print_msg(msg: "Number of bits: %d\n" , no_of_bits); |
186 | ksft_print_msg(msg: "Average LLC val: %llu\n" , avg_llc_val); |
187 | ksft_print_msg(msg: "Cache span (%s): %zu\n" , lines ? "lines" : "bytes" , |
188 | cache_span); |
189 | } |
190 | |