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; 37 uint64_t branches, branch_misses; 38 uint32_t last_branches, last_branch_misses; 39 int 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 ret = pread(ci->cd[core].msr_fd, &counter, 58 sizeof(counter), IA32_PERFCTR1); 59 if (ret < 0) 60 RTE_LOG(ERR, POWER_MANAGER, 61 "unable to read counter for core %u\n", 62 core); 63 branch_misses = counter; 64 65 66 ci->cd[core].last_branches = branches; 67 ci->cd[core].last_branch_misses = branch_misses; 68 69 hits_diff = (int)branches - (int)last_branches; 70 if (hits_diff <= 0) { 71 /* Likely a counter overflow condition, skip this round */ 72 return -1.0; 73 } 74 75 miss_diff = (int)branch_misses - (int)last_branch_misses; 76 if (miss_diff <= 0) { 77 /* Likely a counter overflow condition, skip this round */ 78 return -1.0; 79 } 80 81 g_branches = hits_diff; 82 g_branch_misses = miss_diff; 83 84 if (hits_diff < (INTERVAL*100)) { 85 /* Likely no workload running on this core. Skip. */ 86 return -1.0; 87 } 88 89 ratio = (float)miss_diff * (float)100 / (float)hits_diff; 90 91 if (ratio < ci->branch_ratio_threshold) 92 power_manager_scale_core_min(core); 93 else 94 power_manager_scale_core_max(core); 95 96 g_active = 1; 97 return ratio; 98 } 99 100 int 101 add_core_to_monitor(int core) 102 { 103 struct core_info *ci; 104 char proc_file[UNIX_PATH_MAX]; 105 int ret; 106 107 ci = get_core_info(); 108 109 if (core < ci->core_count) { 110 long setup; 111 112 snprintf(proc_file, UNIX_PATH_MAX, "/dev/cpu/%d/msr", core); 113 ci->cd[core].msr_fd = open(proc_file, O_RDWR | O_SYNC); 114 if (ci->cd[core].msr_fd < 0) { 115 RTE_LOG(ERR, POWER_MANAGER, 116 "Error opening MSR file for core %d " 117 "(is msr kernel module loaded?)\n", 118 core); 119 return -1; 120 } 121 /* 122 * Set up branch counters 123 */ 124 setup = IA32_PERFEVT_BRANCH_HITS; 125 ret = pwrite(ci->cd[core].msr_fd, &setup, 126 sizeof(setup), IA32_PERFEVTSEL0); 127 if (ret < 0) { 128 RTE_LOG(ERR, POWER_MANAGER, 129 "unable to set counter for core %u\n", 130 core); 131 return ret; 132 } 133 setup = IA32_PERFEVT_BRANCH_MISS; 134 ret = pwrite(ci->cd[core].msr_fd, &setup, 135 sizeof(setup), IA32_PERFEVTSEL1); 136 if (ret < 0) { 137 RTE_LOG(ERR, POWER_MANAGER, 138 "unable to set counter for core %u\n", 139 core); 140 return ret; 141 } 142 /* 143 * Close the file and re-open as read only so 144 * as not to hog the resource 145 */ 146 close(ci->cd[core].msr_fd); 147 ci->cd[core].msr_fd = open(proc_file, O_RDONLY); 148 if (ci->cd[core].msr_fd < 0) { 149 RTE_LOG(ERR, POWER_MANAGER, 150 "Error opening MSR file for core %d " 151 "(is msr kernel module loaded?)\n", 152 core); 153 return -1; 154 } 155 ci->cd[core].oob_enabled = 1; 156 } 157 return 0; 158 } 159 160 int 161 remove_core_from_monitor(int core) 162 { 163 struct core_info *ci; 164 char proc_file[UNIX_PATH_MAX]; 165 int ret; 166 167 ci = get_core_info(); 168 169 if (ci->cd[core].oob_enabled) { 170 long setup; 171 172 /* 173 * close the msr file, then reopen rw so we can 174 * disable the counters 175 */ 176 if (ci->cd[core].msr_fd != 0) 177 close(ci->cd[core].msr_fd); 178 snprintf(proc_file, UNIX_PATH_MAX, "/dev/cpu/%d/msr", core); 179 ci->cd[core].msr_fd = open(proc_file, O_RDWR | O_SYNC); 180 if (ci->cd[core].msr_fd < 0) { 181 RTE_LOG(ERR, POWER_MANAGER, 182 "Error opening MSR file for core %d " 183 "(is msr kernel module loaded?)\n", 184 core); 185 return -1; 186 } 187 setup = 0x0; /* clear event */ 188 ret = pwrite(ci->cd[core].msr_fd, &setup, 189 sizeof(setup), IA32_PERFEVTSEL0); 190 if (ret < 0) { 191 RTE_LOG(ERR, POWER_MANAGER, 192 "unable to set counter for core %u\n", 193 core); 194 return ret; 195 } 196 setup = 0x0; /* clear event */ 197 ret = pwrite(ci->cd[core].msr_fd, &setup, 198 sizeof(setup), IA32_PERFEVTSEL1); 199 if (ret < 0) { 200 RTE_LOG(ERR, POWER_MANAGER, 201 "unable to set counter for core %u\n", 202 core); 203 return ret; 204 } 205 206 close(ci->cd[core].msr_fd); 207 ci->cd[core].msr_fd = 0; 208 ci->cd[core].oob_enabled = 0; 209 } 210 return 0; 211 } 212 213 int 214 branch_monitor_init(void) 215 { 216 return 0; 217 } 218 219 void 220 run_branch_monitor(void) 221 { 222 struct core_info *ci; 223 int print = 0; 224 float ratio; 225 int printed; 226 int reads = 0; 227 228 ci = get_core_info(); 229 230 while (run_loop) { 231 232 if (!run_loop) 233 break; 234 usleep(INTERVAL); 235 int j; 236 print++; 237 printed = 0; 238 for (j = 0; j < ci->core_count; j++) { 239 if (ci->cd[j].oob_enabled) { 240 ratio = apply_policy(j); 241 if ((print > PRINT_LOOP_COUNT) && (g_active)) { 242 printf(" %d: %.4f {%lu} {%d}", j, 243 ratio, g_branches, 244 reads); 245 printed = 1; 246 reads = 0; 247 } else { 248 reads++; 249 } 250 } 251 } 252 if (print > PRINT_LOOP_COUNT) { 253 if (printed) 254 printf("\n"); 255 print = 0; 256 } 257 } 258 } 259