xref: /dpdk/examples/vm_power_manager/oob_monitor_x86.c (revision 25d11a86c56d50947af33d0b79ede622809bd8b9)
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