1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Intel Corporation
9 #include "oob_monitor.h"
10 #include "power_manager.h"
11 #include "channel_manager.h"
13 static volatile unsigned run_loop = 1;
14 static uint64_t g_branches, g_branch_misses;
17 void branch_monitor_exit(void)
22 /* Number of microseconds between each poll */
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
33 apply_policy(int core)
37 uint64_t branches, branch_misses;
38 uint64_t last_branches, last_branch_misses;
39 int64_t hits_diff, miss_diff;
42 int freq_window_idx, up_count = 0, i;
47 last_branches = ci->cd[core].last_branches;
48 last_branch_misses = ci->cd[core].last_branch_misses;
50 ret = pread(ci->cd[core].msr_fd, &counter,
51 sizeof(counter), IA32_PERFCTR0);
53 RTE_LOG(ERR, POWER_MANAGER,
54 "unable to read counter for core %u\n",
59 ret = pread(ci->cd[core].msr_fd, &counter,
60 sizeof(counter), IA32_PERFCTR1);
62 RTE_LOG(ERR, POWER_MANAGER,
63 "unable to read counter for core %u\n",
65 branch_misses = counter;
68 ci->cd[core].last_branches = branches;
69 ci->cd[core].last_branch_misses = branch_misses;
72 * Intentional right shift to make MSB 0 to avoid
73 * possible signed overflow or truncation.
77 hits_diff = (int64_t)branches - (int64_t)last_branches;
79 /* Likely a counter overflow condition, skip this round */
84 * Intentional right shift to make MSB 0 to avoid
85 * possible signed overflow or truncation.
88 last_branch_misses >>= 1;
89 miss_diff = (int64_t)branch_misses - (int64_t)last_branch_misses;
91 /* Likely a counter overflow condition, skip this round */
95 g_branches = hits_diff;
96 g_branch_misses = miss_diff;
98 if (hits_diff < (INTERVAL*100)) {
99 /* Likely no workload running on this core. Skip. */
103 ratio = (float)miss_diff * (float)100 / (float)hits_diff;
106 * Store the last few directions that the ratio indicates
107 * we should take. If there's on 'up', then we scale up
108 * quickly. If all indicate 'down', only then do we scale
109 * down. Each core_details struct has it's own array.
111 freq_window_idx = ci->cd[core].freq_window_idx;
112 if (ratio > ci->branch_ratio_threshold)
113 ci->cd[core].freq_directions[freq_window_idx] = 1;
115 ci->cd[core].freq_directions[freq_window_idx] = 0;
118 freq_window_idx = freq_window_idx & (FREQ_WINDOW_SIZE-1);
119 ci->cd[core].freq_window_idx = freq_window_idx;
122 for (i = 0; i < FREQ_WINDOW_SIZE; i++)
123 up_count += ci->cd[core].freq_directions[i];
126 if (ci->cd[core].freq_state != FREQ_MIN) {
127 power_manager_scale_core_min(core);
128 ci->cd[core].freq_state = FREQ_MIN;
131 if (ci->cd[core].freq_state != FREQ_MAX) {
132 power_manager_scale_core_max(core);
133 ci->cd[core].freq_state = FREQ_MAX;
142 add_core_to_monitor(int core)
144 struct core_info *ci;
145 char proc_file[UNIX_PATH_MAX];
148 ci = get_core_info();
150 if (core < ci->core_count) {
153 snprintf(proc_file, UNIX_PATH_MAX, "/dev/cpu/%d/msr", core);
154 ci->cd[core].msr_fd = open(proc_file, O_RDWR | O_SYNC);
155 if (ci->cd[core].msr_fd < 0) {
156 RTE_LOG(ERR, POWER_MANAGER,
157 "Error opening MSR file for core %d "
158 "(is msr kernel module loaded?)\n",
163 * Set up branch counters
165 setup = IA32_PERFEVT_BRANCH_HITS;
166 ret = pwrite(ci->cd[core].msr_fd, &setup,
167 sizeof(setup), IA32_PERFEVTSEL0);
169 RTE_LOG(ERR, POWER_MANAGER,
170 "unable to set counter for core %u\n",
174 setup = IA32_PERFEVT_BRANCH_MISS;
175 ret = pwrite(ci->cd[core].msr_fd, &setup,
176 sizeof(setup), IA32_PERFEVTSEL1);
178 RTE_LOG(ERR, POWER_MANAGER,
179 "unable to set counter for core %u\n",
184 * Close the file and re-open as read only so
185 * as not to hog the resource
187 close(ci->cd[core].msr_fd);
188 ci->cd[core].msr_fd = open(proc_file, O_RDONLY);
189 if (ci->cd[core].msr_fd < 0) {
190 RTE_LOG(ERR, POWER_MANAGER,
191 "Error opening MSR file for core %d "
192 "(is msr kernel module loaded?)\n",
196 ci->cd[core].oob_enabled = 1;
202 remove_core_from_monitor(int core)
204 struct core_info *ci;
205 char proc_file[UNIX_PATH_MAX];
208 ci = get_core_info();
210 if (ci->cd[core].oob_enabled) {
214 * close the msr file, then reopen rw so we can
215 * disable the counters
217 if (ci->cd[core].msr_fd != 0)
218 close(ci->cd[core].msr_fd);
219 snprintf(proc_file, UNIX_PATH_MAX, "/dev/cpu/%d/msr", core);
220 ci->cd[core].msr_fd = open(proc_file, O_RDWR | O_SYNC);
221 if (ci->cd[core].msr_fd < 0) {
222 RTE_LOG(ERR, POWER_MANAGER,
223 "Error opening MSR file for core %d "
224 "(is msr kernel module loaded?)\n",
228 setup = 0x0; /* clear event */
229 ret = pwrite(ci->cd[core].msr_fd, &setup,
230 sizeof(setup), IA32_PERFEVTSEL0);
232 RTE_LOG(ERR, POWER_MANAGER,
233 "unable to set counter for core %u\n",
237 setup = 0x0; /* clear event */
238 ret = pwrite(ci->cd[core].msr_fd, &setup,
239 sizeof(setup), IA32_PERFEVTSEL1);
241 RTE_LOG(ERR, POWER_MANAGER,
242 "unable to set counter for core %u\n",
247 close(ci->cd[core].msr_fd);
248 ci->cd[core].msr_fd = 0;
249 ci->cd[core].oob_enabled = 0;
255 branch_monitor_init(void)
261 run_branch_monitor(void)
263 struct core_info *ci;
269 ci = get_core_info();
279 for (j = 0; j < ci->core_count; j++) {
280 if (ci->cd[j].oob_enabled) {
281 ratio = apply_policy(j);
282 if ((print > PRINT_LOOP_COUNT) && (g_active)) {
283 printf(" %d: %.4f {%lu} {%d}", j,
293 if (print > PRINT_LOOP_COUNT) {