examples/vm_power: add oob monitoring functions
[dpdk.git] / examples / vm_power_manager / oob_monitor_x86.c
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 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
32
33 static float
34 apply_policy(int core)
35 {
36         struct core_info *ci;
37         uint64_t counter;
38         uint64_t branches, branch_misses;
39         uint32_t last_branches, last_branch_misses;
40         int hits_diff, miss_diff;
41         float ratio;
42         int ret;
43
44         g_active = 0;
45         ci = get_core_info();
46
47         last_branches = ci->cd[core].last_branches;
48         last_branch_misses = ci->cd[core].last_branch_misses;
49
50         ret = pread(ci->cd[core].msr_fd, &counter,
51                         sizeof(counter), IA32_PERFCTR0);
52         if (ret < 0)
53                 RTE_LOG(ERR, POWER_MANAGER,
54                                 "unable to read counter for core %u\n",
55                                 core);
56         branches = counter;
57
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         hits_diff = (int)branches - (int)last_branches;
71         if (hits_diff <= 0) {
72                 /* Likely a counter overflow condition, skip this round */
73                 return -1.0;
74         }
75
76         miss_diff = (int)branch_misses - (int)last_branch_misses;
77         if (miss_diff <= 0) {
78                 /* Likely a counter overflow condition, skip this round */
79                 return -1.0;
80         }
81
82         g_branches = hits_diff;
83         g_branch_misses = miss_diff;
84
85         if (hits_diff < (INTERVAL*100)) {
86                 /* Likely no workload running on this core. Skip. */
87                 return -1.0;
88         }
89
90         ratio = (float)miss_diff * (float)100 / (float)hits_diff;
91
92         if (ratio < RATIO_THRESHOLD)
93                 power_manager_scale_core_min(core);
94         else
95                 power_manager_scale_core_max(core);
96
97         g_active = 1;
98         return ratio;
99 }
100
101 int
102 add_core_to_monitor(int core)
103 {
104         struct core_info *ci;
105         char proc_file[UNIX_PATH_MAX];
106         int ret;
107
108         ci = get_core_info();
109
110         if (core < ci->core_count) {
111                 long setup;
112
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",
119                                         core);
120                         return -1;
121                 }
122                 /*
123                  * Set up branch counters
124                  */
125                 setup = IA32_PERFEVT_BRANCH_HITS;
126                 ret = pwrite(ci->cd[core].msr_fd, &setup,
127                                 sizeof(setup), IA32_PERFEVTSEL0);
128                 if (ret < 0) {
129                         RTE_LOG(ERR, POWER_MANAGER,
130                                         "unable to set counter for core %u\n",
131                                         core);
132                         return ret;
133                 }
134                 setup = IA32_PERFEVT_BRANCH_MISS;
135                 ret = pwrite(ci->cd[core].msr_fd, &setup,
136                                 sizeof(setup), IA32_PERFEVTSEL1);
137                 if (ret < 0) {
138                         RTE_LOG(ERR, POWER_MANAGER,
139                                         "unable to set counter for core %u\n",
140                                         core);
141                         return ret;
142                 }
143                 /*
144                  * Close the file and re-open as read only so
145                  * as not to hog the resource
146                  */
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",
153                                         core);
154                         return -1;
155                 }
156                 ci->cd[core].oob_enabled = 1;
157         }
158         return 0;
159 }
160
161 int
162 remove_core_from_monitor(int core)
163 {
164         struct core_info *ci;
165         char proc_file[UNIX_PATH_MAX];
166         int ret;
167
168         ci = get_core_info();
169
170         if (ci->cd[core].oob_enabled) {
171                 long setup;
172
173                 /*
174                  * close the msr file, then reopen rw so we can
175                  * disable the counters
176                  */
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",
185                                         core);
186                         return -1;
187                 }
188                 setup = 0x0; /* clear event */
189                 ret = pwrite(ci->cd[core].msr_fd, &setup,
190                                 sizeof(setup), IA32_PERFEVTSEL0);
191                 if (ret < 0) {
192                         RTE_LOG(ERR, POWER_MANAGER,
193                                         "unable to set counter for core %u\n",
194                                         core);
195                         return ret;
196                 }
197                 setup = 0x0; /* clear event */
198                 ret = pwrite(ci->cd[core].msr_fd, &setup,
199                                 sizeof(setup), IA32_PERFEVTSEL1);
200                 if (ret < 0) {
201                         RTE_LOG(ERR, POWER_MANAGER,
202                                         "unable to set counter for core %u\n",
203                                         core);
204                         return ret;
205                 }
206
207                 close(ci->cd[core].msr_fd);
208                 ci->cd[core].msr_fd = 0;
209                 ci->cd[core].oob_enabled = 0;
210         }
211         return 0;
212 }
213
214 int
215 branch_monitor_init(void)
216 {
217         return 0;
218 }
219
220 void
221 run_branch_monitor(void)
222 {
223         struct core_info *ci;
224         int print = 0;
225         float ratio;
226         int printed;
227         int reads = 0;
228
229         ci = get_core_info();
230
231         while (run_loop) {
232
233                 if (!run_loop)
234                         break;
235                 usleep(INTERVAL);
236                 int j;
237                 print++;
238                 printed = 0;
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,
244                                                         ratio, g_branches,
245                                                         reads);
246                                         printed = 1;
247                                         reads = 0;
248                                 } else {
249                                         reads++;
250                                 }
251                         }
252                 }
253                 if (print > PRINT_LOOP_COUNT) {
254                         if (printed)
255                                 printf("\n");
256                         print = 0;
257                 }
258         }
259 }