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