1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2018 Intel Corporation 3 */ 4 5 #include <unistd.h> 6 #include <fcntl.h> 7 #include <rte_log.h> 8 9 #include "oob_monitor.h" 10 #include "power_manager.h" 11 #include "channel_manager.h" 12 13 static volatile unsigned run_loop = 1; 14 static uint64_t g_branches, g_branch_misses; 15 static int g_active; 16 17 void branch_monitor_exit(void) 18 { 19 run_loop = 0; 20 } 21 22 /* Number of microseconds between each poll */ 23 #define INTERVAL 100 24 #define PRINT_LOOP_COUNT (1000000/INTERVAL) 25 #define IA32_PERFEVTSEL0 0x186 26 #define IA32_PERFEVTSEL1 0x187 27 #define IA32_PERFCTR0 0xc1 28 #define IA32_PERFCTR1 0xc2 29 #define IA32_PERFEVT_BRANCH_HITS 0x05300c4 30 #define IA32_PERFEVT_BRANCH_MISS 0x05300c5 31 32 static float 33 apply_policy(int core) 34 { 35 struct core_info *ci; 36 uint64_t counter = 0; 37 uint64_t branches, branch_misses; 38 uint64_t last_branches, last_branch_misses; 39 int64_t hits_diff, miss_diff; 40 float ratio; 41 int ret; 42 43 g_active = 0; 44 ci = get_core_info(); 45 46 last_branches = ci->cd[core].last_branches; 47 last_branch_misses = ci->cd[core].last_branch_misses; 48 49 ret = pread(ci->cd[core].msr_fd, &counter, 50 sizeof(counter), IA32_PERFCTR0); 51 if (ret < 0) 52 RTE_LOG(ERR, POWER_MANAGER, 53 "unable to read counter for core %u\n", 54 core); 55 branches = counter; 56 57 counter = 0; 58 ret = pread(ci->cd[core].msr_fd, &counter, 59 sizeof(counter), IA32_PERFCTR1); 60 if (ret < 0) 61 RTE_LOG(ERR, POWER_MANAGER, 62 "unable to read counter for core %u\n", 63 core); 64 branch_misses = counter; 65 66 67 ci->cd[core].last_branches = branches; 68 ci->cd[core].last_branch_misses = branch_misses; 69 70 /* 71 * Intentional right shift to make MSB 0 to avoid 72 * possible signed overflow or truncation. 73 */ 74 branches >>= 1; 75 last_branches >>= 1; 76 hits_diff = (int64_t)branches - (int64_t)last_branches; 77 if (hits_diff <= 0) { 78 /* Likely a counter overflow condition, skip this round */ 79 return -1.0; 80 } 81 82 /* 83 * Intentional right shift to make MSB 0 to avoid 84 * possible signed overflow or truncation. 85 */ 86 branch_misses >>= 1; 87 last_branch_misses >>= 1; 88 miss_diff = (int64_t)branch_misses - (int64_t)last_branch_misses; 89 if (miss_diff <= 0) { 90 /* Likely a counter overflow condition, skip this round */ 91 return -1.0; 92 } 93 94 g_branches = hits_diff; 95 g_branch_misses = miss_diff; 96 97 if (hits_diff < (INTERVAL*100)) { 98 /* Likely no workload running on this core. Skip. */ 99 return -1.0; 100 } 101 102 ratio = (float)miss_diff * (float)100 / (float)hits_diff; 103 104 if (ratio < ci->branch_ratio_threshold) 105 power_manager_scale_core_min(core); 106 else 107 power_manager_scale_core_max(core); 108 109 g_active = 1; 110 return ratio; 111 } 112 113 int 114 add_core_to_monitor(int core) 115 { 116 struct core_info *ci; 117 char proc_file[UNIX_PATH_MAX]; 118 int ret; 119 120 ci = get_core_info(); 121 122 if (core < ci->core_count) { 123 long setup; 124 125 snprintf(proc_file, UNIX_PATH_MAX, "/dev/cpu/%d/msr", core); 126 ci->cd[core].msr_fd = open(proc_file, O_RDWR | O_SYNC); 127 if (ci->cd[core].msr_fd < 0) { 128 RTE_LOG(ERR, POWER_MANAGER, 129 "Error opening MSR file for core %d " 130 "(is msr kernel module loaded?)\n", 131 core); 132 return -1; 133 } 134 /* 135 * Set up branch counters 136 */ 137 setup = IA32_PERFEVT_BRANCH_HITS; 138 ret = pwrite(ci->cd[core].msr_fd, &setup, 139 sizeof(setup), IA32_PERFEVTSEL0); 140 if (ret < 0) { 141 RTE_LOG(ERR, POWER_MANAGER, 142 "unable to set counter for core %u\n", 143 core); 144 return ret; 145 } 146 setup = IA32_PERFEVT_BRANCH_MISS; 147 ret = pwrite(ci->cd[core].msr_fd, &setup, 148 sizeof(setup), IA32_PERFEVTSEL1); 149 if (ret < 0) { 150 RTE_LOG(ERR, POWER_MANAGER, 151 "unable to set counter for core %u\n", 152 core); 153 return ret; 154 } 155 /* 156 * Close the file and re-open as read only so 157 * as not to hog the resource 158 */ 159 close(ci->cd[core].msr_fd); 160 ci->cd[core].msr_fd = open(proc_file, O_RDONLY); 161 if (ci->cd[core].msr_fd < 0) { 162 RTE_LOG(ERR, POWER_MANAGER, 163 "Error opening MSR file for core %d " 164 "(is msr kernel module loaded?)\n", 165 core); 166 return -1; 167 } 168 ci->cd[core].oob_enabled = 1; 169 } 170 return 0; 171 } 172 173 int 174 remove_core_from_monitor(int core) 175 { 176 struct core_info *ci; 177 char proc_file[UNIX_PATH_MAX]; 178 int ret; 179 180 ci = get_core_info(); 181 182 if (ci->cd[core].oob_enabled) { 183 long setup; 184 185 /* 186 * close the msr file, then reopen rw so we can 187 * disable the counters 188 */ 189 if (ci->cd[core].msr_fd != 0) 190 close(ci->cd[core].msr_fd); 191 snprintf(proc_file, UNIX_PATH_MAX, "/dev/cpu/%d/msr", core); 192 ci->cd[core].msr_fd = open(proc_file, O_RDWR | O_SYNC); 193 if (ci->cd[core].msr_fd < 0) { 194 RTE_LOG(ERR, POWER_MANAGER, 195 "Error opening MSR file for core %d " 196 "(is msr kernel module loaded?)\n", 197 core); 198 return -1; 199 } 200 setup = 0x0; /* clear event */ 201 ret = pwrite(ci->cd[core].msr_fd, &setup, 202 sizeof(setup), IA32_PERFEVTSEL0); 203 if (ret < 0) { 204 RTE_LOG(ERR, POWER_MANAGER, 205 "unable to set counter for core %u\n", 206 core); 207 return ret; 208 } 209 setup = 0x0; /* clear event */ 210 ret = pwrite(ci->cd[core].msr_fd, &setup, 211 sizeof(setup), IA32_PERFEVTSEL1); 212 if (ret < 0) { 213 RTE_LOG(ERR, POWER_MANAGER, 214 "unable to set counter for core %u\n", 215 core); 216 return ret; 217 } 218 219 close(ci->cd[core].msr_fd); 220 ci->cd[core].msr_fd = 0; 221 ci->cd[core].oob_enabled = 0; 222 } 223 return 0; 224 } 225 226 int 227 branch_monitor_init(void) 228 { 229 return 0; 230 } 231 232 void 233 run_branch_monitor(void) 234 { 235 struct core_info *ci; 236 int print = 0; 237 float ratio; 238 int printed; 239 int reads = 0; 240 241 ci = get_core_info(); 242 243 while (run_loop) { 244 245 if (!run_loop) 246 break; 247 usleep(INTERVAL); 248 int j; 249 print++; 250 printed = 0; 251 for (j = 0; j < ci->core_count; j++) { 252 if (ci->cd[j].oob_enabled) { 253 ratio = apply_policy(j); 254 if ((print > PRINT_LOOP_COUNT) && (g_active)) { 255 printf(" %d: %.4f {%lu} {%d}", j, 256 ratio, g_branches, 257 reads); 258 printed = 1; 259 reads = 0; 260 } else { 261 reads++; 262 } 263 } 264 } 265 if (print > PRINT_LOOP_COUNT) { 266 if (printed) 267 printf("\n"); 268 print = 0; 269 } 270 } 271 } 272