xref: /dpdk/examples/vm_power_manager/power_manager.c (revision f30a1bbd63f494f5ba623582d7e9166c817794a4)
13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
23998e2a0SBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation
3d26c18c9SAlan Carew  */
4d26c18c9SAlan Carew 
5d26c18c9SAlan Carew #include <stdio.h>
6d26c18c9SAlan Carew #include <stdlib.h>
7d26c18c9SAlan Carew #include <stdint.h>
8d26c18c9SAlan Carew #include <inttypes.h>
9d26c18c9SAlan Carew #include <fcntl.h>
10d26c18c9SAlan Carew #include <unistd.h>
11d26c18c9SAlan Carew #include <dirent.h>
12d26c18c9SAlan Carew #include <errno.h>
13d26c18c9SAlan Carew 
1499a968faSDavid Hunt #include <sys/sysinfo.h>
15d26c18c9SAlan Carew #include <sys/types.h>
16d26c18c9SAlan Carew 
17d26c18c9SAlan Carew #include <rte_log.h>
18*f30a1bbdSSivaprasad Tummala #include <rte_power_cpufreq.h>
19d26c18c9SAlan Carew #include <rte_spinlock.h>
20d26c18c9SAlan Carew 
216453b928SDavid Hunt #include "channel_manager.h"
22d26c18c9SAlan Carew #include "power_manager.h"
236453b928SDavid Hunt #include "oob_monitor.h"
24d26c18c9SAlan Carew 
25d26c18c9SAlan Carew #define POWER_SCALE_CORE(DIRECTION, core_num , ret) do { \
266453b928SDavid Hunt 	if (core_num >= ci.core_count) \
27d26c18c9SAlan Carew 		return -1; \
286453b928SDavid Hunt 	if (!(ci.cd[core_num].global_enabled_cpus)) \
29d26c18c9SAlan Carew 		return -1; \
30d26c18c9SAlan Carew 	rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); \
31d26c18c9SAlan Carew 	ret = rte_power_freq_##DIRECTION(core_num); \
32d26c18c9SAlan Carew 	rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); \
33d26c18c9SAlan Carew } while (0)
34d26c18c9SAlan Carew 
357e06c0deSTyler Retzlaff struct __rte_cache_aligned freq_info {
36d26c18c9SAlan Carew 	rte_spinlock_t power_sl;
37d26c18c9SAlan Carew 	uint32_t freqs[RTE_MAX_LCORE_FREQS];
38d26c18c9SAlan Carew 	unsigned num_freqs;
397e06c0deSTyler Retzlaff };
40d26c18c9SAlan Carew 
41751227a0SDavid Hunt static struct freq_info global_core_freq_info[RTE_MAX_LCORE];
42d26c18c9SAlan Carew 
4399a968faSDavid Hunt struct core_info ci;
44d26c18c9SAlan Carew 
45d26c18c9SAlan Carew #define SYSFS_CPU_PATH "/sys/devices/system/cpu/cpu%u/topology/core_id"
46d26c18c9SAlan Carew 
4799a968faSDavid Hunt struct core_info *
4899a968faSDavid Hunt get_core_info(void)
4999a968faSDavid Hunt {
5099a968faSDavid Hunt 	return &ci;
5199a968faSDavid Hunt }
5299a968faSDavid Hunt 
5399a968faSDavid Hunt int
5499a968faSDavid Hunt core_info_init(void)
5599a968faSDavid Hunt {
5699a968faSDavid Hunt 	struct core_info *ci;
5799a968faSDavid Hunt 	int i;
5899a968faSDavid Hunt 
5999a968faSDavid Hunt 	ci = get_core_info();
6099a968faSDavid Hunt 
6199a968faSDavid Hunt 	ci->core_count = get_nprocs_conf();
6299a968faSDavid Hunt 	ci->cd = malloc(ci->core_count * sizeof(struct core_details));
6331c9a664SDavid Hunt 	memset(ci->cd, 0, ci->core_count * sizeof(struct core_details));
6499a968faSDavid Hunt 	if (!ci->cd) {
6599a968faSDavid Hunt 		RTE_LOG(ERR, POWER_MANAGER, "Failed to allocate memory for core info.");
6699a968faSDavid Hunt 		return -1;
6799a968faSDavid Hunt 	}
6899a968faSDavid Hunt 	for (i = 0; i < ci->core_count; i++) {
6999a968faSDavid Hunt 		ci->cd[i].global_enabled_cpus = 1;
7095f648ffSRory Sexton 		ci->cd[i].branch_ratio_threshold = BRANCH_RATIO_THRESHOLD;
7199a968faSDavid Hunt 	}
7299a968faSDavid Hunt 	printf("%d cores in system\n", ci->core_count);
7399a968faSDavid Hunt 	return 0;
7499a968faSDavid Hunt }
7599a968faSDavid Hunt 
76d26c18c9SAlan Carew int
77d26c18c9SAlan Carew power_manager_init(void)
78d26c18c9SAlan Carew {
796453b928SDavid Hunt 	unsigned int i, num_cpus = 0, num_freqs = 0;
80d26c18c9SAlan Carew 	int ret = 0;
816453b928SDavid Hunt 	struct core_info *ci;
82c12ade20SDavid Hunt 	unsigned int max_core_num;
83d26c18c9SAlan Carew 
846ff7b996SDavid Hunt 	rte_power_set_env(PM_ENV_NOT_SET);
856453b928SDavid Hunt 
866453b928SDavid Hunt 	ci = get_core_info();
876453b928SDavid Hunt 	if (!ci) {
886453b928SDavid Hunt 		RTE_LOG(ERR, POWER_MANAGER,
896453b928SDavid Hunt 				"Failed to get core info!\n");
90d26c18c9SAlan Carew 		return -1;
91d26c18c9SAlan Carew 	}
926453b928SDavid Hunt 
93751227a0SDavid Hunt 	if (ci->core_count > RTE_MAX_LCORE)
94751227a0SDavid Hunt 		max_core_num = RTE_MAX_LCORE;
95c12ade20SDavid Hunt 	else
96c12ade20SDavid Hunt 		max_core_num = ci->core_count;
97c12ade20SDavid Hunt 
98c12ade20SDavid Hunt 	for (i = 0; i < max_core_num; i++) {
99b49c677aSDavid Hunt 		if (rte_lcore_index(i) == -1)
100b49c677aSDavid Hunt 			continue;
101b49c677aSDavid Hunt 
1026453b928SDavid Hunt 		if (ci->cd[i].global_enabled_cpus) {
1037f472f74SDavid Hunt 			if (rte_power_init(i) < 0)
1047f472f74SDavid Hunt 				RTE_LOG(ERR, POWER_MANAGER,
1057f472f74SDavid Hunt 						"Unable to initialize power manager "
106d26c18c9SAlan Carew 						"for core %u\n", i);
1076453b928SDavid Hunt 			num_cpus++;
1086453b928SDavid Hunt 			num_freqs = rte_power_freqs(i,
1096453b928SDavid Hunt 					global_core_freq_info[i].freqs,
1107f472f74SDavid Hunt 					RTE_MAX_LCORE_FREQS);
1117f472f74SDavid Hunt 			if (num_freqs == 0) {
1127f472f74SDavid Hunt 				RTE_LOG(ERR, POWER_MANAGER,
1137f472f74SDavid Hunt 					"Unable to get frequency list for core %u\n",
1147f472f74SDavid Hunt 					i);
1156453b928SDavid Hunt 				ci->cd[i].oob_enabled = 0;
116d26c18c9SAlan Carew 				ret = -1;
117d26c18c9SAlan Carew 			}
1187f472f74SDavid Hunt 			global_core_freq_info[i].num_freqs = num_freqs;
1196453b928SDavid Hunt 
120d26c18c9SAlan Carew 			rte_spinlock_init(&global_core_freq_info[i].power_sl);
121d26c18c9SAlan Carew 		}
1226453b928SDavid Hunt 		if (ci->cd[i].oob_enabled)
1236453b928SDavid Hunt 			add_core_to_monitor(i);
1246453b928SDavid Hunt 	}
1256453b928SDavid Hunt 	RTE_LOG(INFO, POWER_MANAGER, "Managing %u cores out of %u available host cores\n",
1266453b928SDavid Hunt 			num_cpus, ci->core_count);
127d26c18c9SAlan Carew 	return ret;
128d26c18c9SAlan Carew 
129d26c18c9SAlan Carew }
130d26c18c9SAlan Carew 
131d26c18c9SAlan Carew uint32_t
132d26c18c9SAlan Carew power_manager_get_current_frequency(unsigned core_num)
133d26c18c9SAlan Carew {
134d26c18c9SAlan Carew 	uint32_t freq, index;
135d26c18c9SAlan Carew 
136751227a0SDavid Hunt 	if (core_num >= RTE_MAX_LCORE) {
137d26c18c9SAlan Carew 		RTE_LOG(ERR, POWER_MANAGER, "Core(%u) is out of range 0...%d\n",
138751227a0SDavid Hunt 				core_num, RTE_MAX_LCORE-1);
139d26c18c9SAlan Carew 		return -1;
140d26c18c9SAlan Carew 	}
1416453b928SDavid Hunt 	if (!(ci.cd[core_num].global_enabled_cpus))
142d26c18c9SAlan Carew 		return 0;
143d26c18c9SAlan Carew 
144d26c18c9SAlan Carew 	rte_spinlock_lock(&global_core_freq_info[core_num].power_sl);
145d26c18c9SAlan Carew 	index = rte_power_get_freq(core_num);
146d26c18c9SAlan Carew 	rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl);
1473f1fc5f2SDavid Hunt 	if (index >= RTE_MAX_LCORE_FREQS)
148d26c18c9SAlan Carew 		freq = 0;
149d26c18c9SAlan Carew 	else
150d26c18c9SAlan Carew 		freq = global_core_freq_info[core_num].freqs[index];
151d26c18c9SAlan Carew 
152d26c18c9SAlan Carew 	return freq;
153d26c18c9SAlan Carew }
154d26c18c9SAlan Carew 
155d26c18c9SAlan Carew int
156d26c18c9SAlan Carew power_manager_exit(void)
157d26c18c9SAlan Carew {
158d26c18c9SAlan Carew 	unsigned int i;
159d26c18c9SAlan Carew 	int ret = 0;
1606453b928SDavid Hunt 	struct core_info *ci;
161c12ade20SDavid Hunt 	unsigned int max_core_num;
162d26c18c9SAlan Carew 
1636453b928SDavid Hunt 	ci = get_core_info();
1646453b928SDavid Hunt 	if (!ci) {
1656453b928SDavid Hunt 		RTE_LOG(ERR, POWER_MANAGER,
1666453b928SDavid Hunt 				"Failed to get core info!\n");
1676453b928SDavid Hunt 		return -1;
1686453b928SDavid Hunt 	}
1696453b928SDavid Hunt 
170751227a0SDavid Hunt 	if (ci->core_count > RTE_MAX_LCORE)
171751227a0SDavid Hunt 		max_core_num = RTE_MAX_LCORE;
172c12ade20SDavid Hunt 	else
173c12ade20SDavid Hunt 		max_core_num = ci->core_count;
174c12ade20SDavid Hunt 
175c12ade20SDavid Hunt 	for (i = 0; i < max_core_num; i++) {
176b49c677aSDavid Hunt 		if (rte_lcore_index(i) == -1)
177b49c677aSDavid Hunt 			continue;
178b49c677aSDavid Hunt 
1796453b928SDavid Hunt 		if (ci->cd[i].global_enabled_cpus) {
180d26c18c9SAlan Carew 			if (rte_power_exit(i) < 0) {
181d26c18c9SAlan Carew 				RTE_LOG(ERR, POWER_MANAGER, "Unable to shutdown power manager "
182d26c18c9SAlan Carew 						"for core %u\n", i);
183d26c18c9SAlan Carew 				ret = -1;
184d26c18c9SAlan Carew 			}
1856453b928SDavid Hunt 			ci->cd[i].global_enabled_cpus = 0;
186d26c18c9SAlan Carew 		}
1876453b928SDavid Hunt 		remove_core_from_monitor(i);
1886453b928SDavid Hunt 	}
189d26c18c9SAlan Carew 	return ret;
190d26c18c9SAlan Carew }
191d26c18c9SAlan Carew 
192d26c18c9SAlan Carew int
193d26c18c9SAlan Carew power_manager_scale_core_up(unsigned core_num)
194d26c18c9SAlan Carew {
195d26c18c9SAlan Carew 	int ret = 0;
196d26c18c9SAlan Carew 
197d26c18c9SAlan Carew 	POWER_SCALE_CORE(up, core_num, ret);
198d26c18c9SAlan Carew 	return ret;
199d26c18c9SAlan Carew }
200d26c18c9SAlan Carew 
201d26c18c9SAlan Carew int
202d26c18c9SAlan Carew power_manager_scale_core_down(unsigned core_num)
203d26c18c9SAlan Carew {
204d26c18c9SAlan Carew 	int ret = 0;
205d26c18c9SAlan Carew 
206d26c18c9SAlan Carew 	POWER_SCALE_CORE(down, core_num, ret);
207d26c18c9SAlan Carew 	return ret;
208d26c18c9SAlan Carew }
209d26c18c9SAlan Carew 
210d26c18c9SAlan Carew int
211d26c18c9SAlan Carew power_manager_scale_core_min(unsigned core_num)
212d26c18c9SAlan Carew {
213d26c18c9SAlan Carew 	int ret = 0;
214d26c18c9SAlan Carew 
215d26c18c9SAlan Carew 	POWER_SCALE_CORE(min, core_num, ret);
216d26c18c9SAlan Carew 	return ret;
217d26c18c9SAlan Carew }
218d26c18c9SAlan Carew 
219d26c18c9SAlan Carew int
220d26c18c9SAlan Carew power_manager_scale_core_max(unsigned core_num)
221d26c18c9SAlan Carew {
222d26c18c9SAlan Carew 	int ret = 0;
223d26c18c9SAlan Carew 
224d26c18c9SAlan Carew 	POWER_SCALE_CORE(max, core_num, ret);
225d26c18c9SAlan Carew 	return ret;
226d26c18c9SAlan Carew }
227567997b9SDavid Hunt 
228567997b9SDavid Hunt int
229567997b9SDavid Hunt power_manager_enable_turbo_core(unsigned int core_num)
230567997b9SDavid Hunt {
231567997b9SDavid Hunt 	int ret = 0;
232567997b9SDavid Hunt 
233567997b9SDavid Hunt 	POWER_SCALE_CORE(enable_turbo, core_num, ret);
234567997b9SDavid Hunt 	return ret;
235567997b9SDavid Hunt }
236567997b9SDavid Hunt 
237567997b9SDavid Hunt int
238567997b9SDavid Hunt power_manager_disable_turbo_core(unsigned int core_num)
239567997b9SDavid Hunt {
240567997b9SDavid Hunt 	int ret = 0;
241567997b9SDavid Hunt 
242567997b9SDavid Hunt 	POWER_SCALE_CORE(disable_turbo, core_num, ret);
243567997b9SDavid Hunt 	return ret;
244567997b9SDavid Hunt }
2457f472f74SDavid Hunt 
2467f472f74SDavid Hunt int
2477f472f74SDavid Hunt power_manager_scale_core_med(unsigned int core_num)
2487f472f74SDavid Hunt {
2497f472f74SDavid Hunt 	int ret = 0;
2506453b928SDavid Hunt 	struct core_info *ci;
2517f472f74SDavid Hunt 
2526453b928SDavid Hunt 	ci = get_core_info();
253751227a0SDavid Hunt 	if (core_num >= RTE_MAX_LCORE)
2547f472f74SDavid Hunt 		return -1;
2556453b928SDavid Hunt 	if (!(ci->cd[core_num].global_enabled_cpus))
2567f472f74SDavid Hunt 		return -1;
2577f472f74SDavid Hunt 	rte_spinlock_lock(&global_core_freq_info[core_num].power_sl);
2587f472f74SDavid Hunt 	ret = rte_power_set_freq(core_num,
2597f472f74SDavid Hunt 				global_core_freq_info[core_num].num_freqs / 2);
2607f472f74SDavid Hunt 	rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl);
2617f472f74SDavid Hunt 	return ret;
2627f472f74SDavid Hunt }
263