New upstream version 18.08
[deb_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 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 }