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 RATIO_THRESHOLD 0.03
26 #define IA32_PERFEVTSEL0 0x186
27 #define IA32_PERFEVTSEL1 0x187
28 #define IA32_PERFCTR0 0xc1
29 #define IA32_PERFCTR1 0xc2
30 #define IA32_PERFEVT_BRANCH_HITS 0x05300c4
31 #define IA32_PERFEVT_BRANCH_MISS 0x05300c5
34 apply_policy(int core)
38 uint64_t branches, branch_misses;
39 uint32_t last_branches, last_branch_misses;
40 int hits_diff, miss_diff;
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",
58 ret = pread(ci->cd[core].msr_fd, &counter,
59 sizeof(counter), IA32_PERFCTR1);
61 RTE_LOG(ERR, POWER_MANAGER,
62 "unable to read counter for core %u\n",
64 branch_misses = counter;
67 ci->cd[core].last_branches = branches;
68 ci->cd[core].last_branch_misses = branch_misses;
70 hits_diff = (int)branches - (int)last_branches;
72 /* Likely a counter overflow condition, skip this round */
76 miss_diff = (int)branch_misses - (int)last_branch_misses;
78 /* Likely a counter overflow condition, skip this round */
82 g_branches = hits_diff;
83 g_branch_misses = miss_diff;
85 if (hits_diff < (INTERVAL*100)) {
86 /* Likely no workload running on this core. Skip. */
90 ratio = (float)miss_diff * (float)100 / (float)hits_diff;
92 if (ratio < RATIO_THRESHOLD)
93 power_manager_scale_core_min(core);
95 power_manager_scale_core_max(core);
102 add_core_to_monitor(int core)
104 struct core_info *ci;
105 char proc_file[UNIX_PATH_MAX];
108 ci = get_core_info();
110 if (core < ci->core_count) {
113 snprintf(proc_file, UNIX_PATH_MAX, "/dev/cpu/%d/msr", core);
114 ci->cd[core].msr_fd = open(proc_file, O_RDWR | O_SYNC);
115 if (ci->cd[core].msr_fd < 0) {
116 RTE_LOG(ERR, POWER_MANAGER,
117 "Error opening MSR file for core %d "
118 "(is msr kernel module loaded?)\n",
123 * Set up branch counters
125 setup = IA32_PERFEVT_BRANCH_HITS;
126 ret = pwrite(ci->cd[core].msr_fd, &setup,
127 sizeof(setup), IA32_PERFEVTSEL0);
129 RTE_LOG(ERR, POWER_MANAGER,
130 "unable to set counter for core %u\n",
134 setup = IA32_PERFEVT_BRANCH_MISS;
135 ret = pwrite(ci->cd[core].msr_fd, &setup,
136 sizeof(setup), IA32_PERFEVTSEL1);
138 RTE_LOG(ERR, POWER_MANAGER,
139 "unable to set counter for core %u\n",
144 * Close the file and re-open as read only so
145 * as not to hog the resource
147 close(ci->cd[core].msr_fd);
148 ci->cd[core].msr_fd = open(proc_file, O_RDONLY);
149 if (ci->cd[core].msr_fd < 0) {
150 RTE_LOG(ERR, POWER_MANAGER,
151 "Error opening MSR file for core %d "
152 "(is msr kernel module loaded?)\n",
156 ci->cd[core].oob_enabled = 1;
162 remove_core_from_monitor(int core)
164 struct core_info *ci;
165 char proc_file[UNIX_PATH_MAX];
168 ci = get_core_info();
170 if (ci->cd[core].oob_enabled) {
174 * close the msr file, then reopen rw so we can
175 * disable the counters
177 if (ci->cd[core].msr_fd != 0)
178 close(ci->cd[core].msr_fd);
179 snprintf(proc_file, UNIX_PATH_MAX, "/dev/cpu/%d/msr", core);
180 ci->cd[core].msr_fd = open(proc_file, O_RDWR | O_SYNC);
181 if (ci->cd[core].msr_fd < 0) {
182 RTE_LOG(ERR, POWER_MANAGER,
183 "Error opening MSR file for core %d "
184 "(is msr kernel module loaded?)\n",
188 setup = 0x0; /* clear event */
189 ret = pwrite(ci->cd[core].msr_fd, &setup,
190 sizeof(setup), IA32_PERFEVTSEL0);
192 RTE_LOG(ERR, POWER_MANAGER,
193 "unable to set counter for core %u\n",
197 setup = 0x0; /* clear event */
198 ret = pwrite(ci->cd[core].msr_fd, &setup,
199 sizeof(setup), IA32_PERFEVTSEL1);
201 RTE_LOG(ERR, POWER_MANAGER,
202 "unable to set counter for core %u\n",
207 close(ci->cd[core].msr_fd);
208 ci->cd[core].msr_fd = 0;
209 ci->cd[core].oob_enabled = 0;
215 branch_monitor_init(void)
221 run_branch_monitor(void)
223 struct core_info *ci;
229 ci = get_core_info();
239 for (j = 0; j < ci->core_count; j++) {
240 if (ci->cd[j].oob_enabled) {
241 ratio = apply_policy(j);
242 if ((print > PRINT_LOOP_COUNT) && (g_active)) {
243 printf(" %d: %.4f {%lu} {%d}", j,
253 if (print > PRINT_LOOP_COUNT) {