1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <stdint.h> 4 #include "resctrl.h" 5 6 struct perf_event_read { 7 __u64 nr; /* The number of events */ 8 struct { 9 __u64 value; /* The value of the event */ 10 } values[2]; 11 }; 12 13 static struct perf_event_attr pea_llc_miss; 14 static struct perf_event_read pe_read; 15 static int pe_fd; 16 char llc_occup_path[1024]; 17 18 static void perf_event_attr_initialize(__u64 config) 19 { 20 memset(&pea_llc_miss, 0, sizeof(struct perf_event_attr)); 21 pea_llc_miss.type = PERF_TYPE_HARDWARE; 22 pea_llc_miss.size = sizeof(struct perf_event_attr); 23 pea_llc_miss.read_format = PERF_FORMAT_GROUP; 24 pea_llc_miss.exclude_kernel = 1; 25 pea_llc_miss.exclude_hv = 1; 26 pea_llc_miss.exclude_idle = 1; 27 pea_llc_miss.exclude_callchain_kernel = 1; 28 pea_llc_miss.inherit = 1; 29 pea_llc_miss.exclude_guest = 1; 30 pea_llc_miss.disabled = 1; 31 pea_llc_miss.config = config; 32 } 33 34 /* Start counters to log values */ 35 static void perf_event_reset_enable(void) 36 { 37 ioctl(pe_fd, PERF_EVENT_IOC_RESET, 0); 38 ioctl(pe_fd, PERF_EVENT_IOC_ENABLE, 0); 39 } 40 41 static void perf_event_initialize_read_format(void) 42 { 43 memset(&pe_read, 0, sizeof(struct perf_event_read)); 44 pe_read.nr = 1; 45 } 46 47 static int perf_open(pid_t pid, int cpu_no) 48 { 49 pe_fd = perf_event_open(&pea_llc_miss, pid, cpu_no, -1, PERF_FLAG_FD_CLOEXEC); 50 if (pe_fd == -1) { 51 ksft_perror("Error opening leader"); 52 return -1; 53 } 54 55 perf_event_reset_enable(); 56 57 return 0; 58 } 59 60 /* 61 * Get LLC Occupancy as reported by RESCTRL FS 62 * For CMT, 63 * 1. If con_mon grp and mon grp given, then read from mon grp in 64 * con_mon grp 65 * 2. If only con_mon grp given, then read from con_mon grp 66 * 3. If both not given, then read from root con_mon grp 67 * For CAT, 68 * 1. If con_mon grp given, then read from it 69 * 2. If con_mon grp not given, then read from root con_mon grp 70 * 71 * Return: =0 on success. <0 on failure. 72 */ 73 static int get_llc_occu_resctrl(unsigned long *llc_occupancy) 74 { 75 FILE *fp; 76 77 fp = fopen(llc_occup_path, "r"); 78 if (!fp) { 79 ksft_perror("Failed to open results file"); 80 81 return -1; 82 } 83 if (fscanf(fp, "%lu", llc_occupancy) <= 0) { 84 ksft_perror("Could not get llc occupancy"); 85 fclose(fp); 86 87 return -1; 88 } 89 fclose(fp); 90 91 return 0; 92 } 93 94 /* 95 * print_results_cache: the cache results are stored in a file 96 * @filename: file that stores the results 97 * @bm_pid: child pid that runs benchmark 98 * @llc_value: perf miss value / 99 * llc occupancy value reported by resctrl FS 100 * 101 * Return: 0 on success, < 0 on error. 102 */ 103 static int print_results_cache(const char *filename, int bm_pid, __u64 llc_value) 104 { 105 FILE *fp; 106 107 if (strcmp(filename, "stdio") == 0 || strcmp(filename, "stderr") == 0) { 108 printf("Pid: %d \t LLC_value: %llu\n", bm_pid, llc_value); 109 } else { 110 fp = fopen(filename, "a"); 111 if (!fp) { 112 ksft_perror("Cannot open results file"); 113 114 return -1; 115 } 116 fprintf(fp, "Pid: %d \t llc_value: %llu\n", bm_pid, llc_value); 117 fclose(fp); 118 } 119 120 return 0; 121 } 122 123 /* 124 * perf_event_measure - Measure perf events 125 * @filename: Filename for writing the results 126 * @bm_pid: PID that runs the benchmark 127 * 128 * Measures perf events (e.g., cache misses) and writes the results into 129 * @filename. @bm_pid is written to the results file along with the measured 130 * value. 131 * 132 * Return: =0 on success. <0 on failure. 133 */ 134 static int perf_event_measure(const char *filename, int bm_pid) 135 { 136 int ret; 137 138 /* Stop counters after one span to get miss rate */ 139 ioctl(pe_fd, PERF_EVENT_IOC_DISABLE, 0); 140 141 ret = read(pe_fd, &pe_read, sizeof(struct perf_event_read)); 142 if (ret == -1) { 143 ksft_perror("Could not get perf value"); 144 return -1; 145 } 146 147 return print_results_cache(filename, bm_pid, pe_read.values[0].value); 148 } 149 150 /* 151 * measure_llc_resctrl - Measure resctrl LLC value from resctrl 152 * @filename: Filename for writing the results 153 * @bm_pid: PID that runs the benchmark 154 * 155 * Measures LLC occupancy from resctrl and writes the results into @filename. 156 * @bm_pid is written to the results file along with the measured value. 157 * 158 * Return: =0 on success. <0 on failure. 159 */ 160 int measure_llc_resctrl(const char *filename, int bm_pid) 161 { 162 unsigned long llc_occu_resc = 0; 163 int ret; 164 165 ret = get_llc_occu_resctrl(&llc_occu_resc); 166 if (ret < 0) 167 return ret; 168 169 return print_results_cache(filename, bm_pid, llc_occu_resc); 170 } 171 172 /* 173 * cache_val: execute benchmark and measure LLC occupancy resctrl 174 * and perf cache miss for the benchmark 175 * @param: parameters passed to cache_val() 176 * @span: buffer size for the benchmark 177 * 178 * Return: 0 when the test was run, < 0 on error. 179 */ 180 int cat_val(struct resctrl_val_param *param, size_t span) 181 { 182 int memflush = 1, operation = 0, ret = 0; 183 char *resctrl_val = param->resctrl_val; 184 pid_t bm_pid; 185 186 if (strcmp(param->filename, "") == 0) 187 sprintf(param->filename, "stdio"); 188 189 bm_pid = getpid(); 190 191 /* Taskset benchmark to specified cpu */ 192 ret = taskset_benchmark(bm_pid, param->cpu_no); 193 if (ret) 194 return ret; 195 196 /* Write benchmark to specified con_mon grp, mon_grp in resctrl FS*/ 197 ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp, 198 resctrl_val); 199 if (ret) 200 return ret; 201 202 perf_event_attr_initialize(PERF_COUNT_HW_CACHE_MISSES); 203 perf_event_initialize_read_format(); 204 205 /* Test runs until the callback setup() tells the test to stop. */ 206 while (1) { 207 ret = param->setup(param); 208 if (ret == END_OF_TESTS) { 209 ret = 0; 210 break; 211 } 212 if (ret < 0) 213 break; 214 ret = perf_open(bm_pid, param->cpu_no); 215 if (ret) 216 break; 217 218 if (run_fill_buf(span, memflush, operation, true)) { 219 fprintf(stderr, "Error-running fill buffer\n"); 220 ret = -1; 221 goto pe_close; 222 } 223 224 sleep(1); 225 ret = perf_event_measure(param->filename, bm_pid); 226 if (ret) 227 goto pe_close; 228 } 229 230 return ret; 231 232 pe_close: 233 close(pe_fd); 234 return ret; 235 } 236 237 /* 238 * show_cache_info - Show generic cache test information 239 * @no_of_bits: Number of bits 240 * @avg_llc_val: Average of LLC cache result data 241 * @cache_span: Cache span 242 * @lines: @cache_span in lines or bytes 243 */ 244 void show_cache_info(int no_of_bits, __u64 avg_llc_val, size_t cache_span, bool lines) 245 { 246 ksft_print_msg("Number of bits: %d\n", no_of_bits); 247 ksft_print_msg("Average LLC val: %llu\n", avg_llc_val); 248 ksft_print_msg("Cache span (%s): %zu\n", lines ? "lines" : "bytes", 249 cache_span); 250 } 251