xref: /dpdk/examples/vm_power_manager/power_manager.c (revision 31c9a66465ad623258c4449fea54c0b42a2deae1)
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 <sys/un.h>
10d26c18c9SAlan Carew #include <fcntl.h>
11d26c18c9SAlan Carew #include <unistd.h>
12d26c18c9SAlan Carew #include <dirent.h>
13d26c18c9SAlan Carew #include <errno.h>
14d26c18c9SAlan Carew 
1599a968faSDavid Hunt #include <sys/sysinfo.h>
16d26c18c9SAlan Carew #include <sys/types.h>
17d26c18c9SAlan Carew 
18d26c18c9SAlan Carew #include <rte_log.h>
19d26c18c9SAlan Carew #include <rte_power.h>
20d26c18c9SAlan Carew #include <rte_spinlock.h>
21d26c18c9SAlan Carew 
226453b928SDavid Hunt #include "channel_manager.h"
23d26c18c9SAlan Carew #include "power_manager.h"
246453b928SDavid Hunt #include "oob_monitor.h"
25d26c18c9SAlan Carew 
26d26c18c9SAlan Carew #define POWER_SCALE_CORE(DIRECTION, core_num , ret) do { \
276453b928SDavid Hunt 	if (core_num >= ci.core_count) \
28d26c18c9SAlan Carew 		return -1; \
296453b928SDavid Hunt 	if (!(ci.cd[core_num].global_enabled_cpus)) \
30d26c18c9SAlan Carew 		return -1; \
31d26c18c9SAlan Carew 	rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); \
32d26c18c9SAlan Carew 	ret = rte_power_freq_##DIRECTION(core_num); \
33d26c18c9SAlan Carew 	rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); \
34d26c18c9SAlan Carew } while (0)
35d26c18c9SAlan Carew 
36d26c18c9SAlan Carew struct freq_info {
37d26c18c9SAlan Carew 	rte_spinlock_t power_sl;
38d26c18c9SAlan Carew 	uint32_t freqs[RTE_MAX_LCORE_FREQS];
39d26c18c9SAlan Carew 	unsigned num_freqs;
40d26c18c9SAlan Carew } __rte_cache_aligned;
41d26c18c9SAlan Carew 
42751227a0SDavid Hunt static struct freq_info global_core_freq_info[RTE_MAX_LCORE];
43d26c18c9SAlan Carew 
4499a968faSDavid Hunt struct core_info ci;
45d26c18c9SAlan Carew 
46d26c18c9SAlan Carew #define SYSFS_CPU_PATH "/sys/devices/system/cpu/cpu%u/topology/core_id"
47d26c18c9SAlan Carew 
4899a968faSDavid Hunt struct core_info *
4999a968faSDavid Hunt get_core_info(void)
5099a968faSDavid Hunt {
5199a968faSDavid Hunt 	return &ci;
5299a968faSDavid Hunt }
5399a968faSDavid Hunt 
5499a968faSDavid Hunt int
5599a968faSDavid Hunt core_info_init(void)
5699a968faSDavid Hunt {
5799a968faSDavid Hunt 	struct core_info *ci;
5899a968faSDavid Hunt 	int i;
5999a968faSDavid Hunt 
6099a968faSDavid Hunt 	ci = get_core_info();
6199a968faSDavid Hunt 
6299a968faSDavid Hunt 	ci->core_count = get_nprocs_conf();
63711f43baSDavid Hunt 	ci->branch_ratio_threshold = BRANCH_RATIO_THRESHOLD;
6499a968faSDavid Hunt 	ci->cd = malloc(ci->core_count * sizeof(struct core_details));
65*31c9a664SDavid Hunt 	memset(ci->cd, 0, ci->core_count * sizeof(struct core_details));
6699a968faSDavid Hunt 	if (!ci->cd) {
6799a968faSDavid Hunt 		RTE_LOG(ERR, POWER_MANAGER, "Failed to allocate memory for core info.");
6899a968faSDavid Hunt 		return -1;
6999a968faSDavid Hunt 	}
7099a968faSDavid Hunt 	for (i = 0; i < ci->core_count; i++) {
7199a968faSDavid Hunt 		ci->cd[i].global_enabled_cpus = 1;
7299a968faSDavid Hunt 	}
7399a968faSDavid Hunt 	printf("%d cores in system\n", ci->core_count);
7499a968faSDavid Hunt 	return 0;
7599a968faSDavid Hunt }
7699a968faSDavid Hunt 
77d26c18c9SAlan Carew int
78d26c18c9SAlan Carew power_manager_init(void)
79d26c18c9SAlan Carew {
806453b928SDavid Hunt 	unsigned int i, num_cpus = 0, num_freqs = 0;
81d26c18c9SAlan Carew 	int ret = 0;
826453b928SDavid Hunt 	struct core_info *ci;
83c12ade20SDavid Hunt 	unsigned int max_core_num;
84d26c18c9SAlan Carew 
856ff7b996SDavid Hunt 	rte_power_set_env(PM_ENV_NOT_SET);
866453b928SDavid Hunt 
876453b928SDavid Hunt 	ci = get_core_info();
886453b928SDavid Hunt 	if (!ci) {
896453b928SDavid Hunt 		RTE_LOG(ERR, POWER_MANAGER,
906453b928SDavid Hunt 				"Failed to get core info!\n");
91d26c18c9SAlan Carew 		return -1;
92d26c18c9SAlan Carew 	}
936453b928SDavid Hunt 
94751227a0SDavid Hunt 	if (ci->core_count > RTE_MAX_LCORE)
95751227a0SDavid Hunt 		max_core_num = RTE_MAX_LCORE;
96c12ade20SDavid Hunt 	else
97c12ade20SDavid Hunt 		max_core_num = ci->core_count;
98c12ade20SDavid Hunt 
99c12ade20SDavid Hunt 	for (i = 0; i < max_core_num; i++) {
1006453b928SDavid Hunt 		if (ci->cd[i].global_enabled_cpus) {
1017f472f74SDavid Hunt 			if (rte_power_init(i) < 0)
1027f472f74SDavid Hunt 				RTE_LOG(ERR, POWER_MANAGER,
1037f472f74SDavid Hunt 						"Unable to initialize power manager "
104d26c18c9SAlan Carew 						"for core %u\n", i);
1056453b928SDavid Hunt 			num_cpus++;
1066453b928SDavid Hunt 			num_freqs = rte_power_freqs(i,
1076453b928SDavid Hunt 					global_core_freq_info[i].freqs,
1087f472f74SDavid Hunt 					RTE_MAX_LCORE_FREQS);
1097f472f74SDavid Hunt 			if (num_freqs == 0) {
1107f472f74SDavid Hunt 				RTE_LOG(ERR, POWER_MANAGER,
1117f472f74SDavid Hunt 					"Unable to get frequency list for core %u\n",
1127f472f74SDavid Hunt 					i);
1136453b928SDavid Hunt 				ci->cd[i].oob_enabled = 0;
114d26c18c9SAlan Carew 				ret = -1;
115d26c18c9SAlan Carew 			}
1167f472f74SDavid Hunt 			global_core_freq_info[i].num_freqs = num_freqs;
1176453b928SDavid Hunt 
118d26c18c9SAlan Carew 			rte_spinlock_init(&global_core_freq_info[i].power_sl);
119d26c18c9SAlan Carew 		}
1206453b928SDavid Hunt 		if (ci->cd[i].oob_enabled)
1216453b928SDavid Hunt 			add_core_to_monitor(i);
1226453b928SDavid Hunt 	}
1236453b928SDavid Hunt 	RTE_LOG(INFO, POWER_MANAGER, "Managing %u cores out of %u available host cores\n",
1246453b928SDavid Hunt 			num_cpus, ci->core_count);
125d26c18c9SAlan Carew 	return ret;
126d26c18c9SAlan Carew 
127d26c18c9SAlan Carew }
128d26c18c9SAlan Carew 
129d26c18c9SAlan Carew uint32_t
130d26c18c9SAlan Carew power_manager_get_current_frequency(unsigned core_num)
131d26c18c9SAlan Carew {
132d26c18c9SAlan Carew 	uint32_t freq, index;
133d26c18c9SAlan Carew 
134751227a0SDavid Hunt 	if (core_num >= RTE_MAX_LCORE) {
135d26c18c9SAlan Carew 		RTE_LOG(ERR, POWER_MANAGER, "Core(%u) is out of range 0...%d\n",
136751227a0SDavid Hunt 				core_num, RTE_MAX_LCORE-1);
137d26c18c9SAlan Carew 		return -1;
138d26c18c9SAlan Carew 	}
1396453b928SDavid Hunt 	if (!(ci.cd[core_num].global_enabled_cpus))
140d26c18c9SAlan Carew 		return 0;
141d26c18c9SAlan Carew 
142d26c18c9SAlan Carew 	rte_spinlock_lock(&global_core_freq_info[core_num].power_sl);
143d26c18c9SAlan Carew 	index = rte_power_get_freq(core_num);
144d26c18c9SAlan Carew 	rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl);
1453f1fc5f2SDavid Hunt 	if (index >= RTE_MAX_LCORE_FREQS)
146d26c18c9SAlan Carew 		freq = 0;
147d26c18c9SAlan Carew 	else
148d26c18c9SAlan Carew 		freq = global_core_freq_info[core_num].freqs[index];
149d26c18c9SAlan Carew 
150d26c18c9SAlan Carew 	return freq;
151d26c18c9SAlan Carew }
152d26c18c9SAlan Carew 
153d26c18c9SAlan Carew int
154d26c18c9SAlan Carew power_manager_exit(void)
155d26c18c9SAlan Carew {
156d26c18c9SAlan Carew 	unsigned int i;
157d26c18c9SAlan Carew 	int ret = 0;
1586453b928SDavid Hunt 	struct core_info *ci;
159c12ade20SDavid Hunt 	unsigned int max_core_num;
160d26c18c9SAlan Carew 
1616453b928SDavid Hunt 	ci = get_core_info();
1626453b928SDavid Hunt 	if (!ci) {
1636453b928SDavid Hunt 		RTE_LOG(ERR, POWER_MANAGER,
1646453b928SDavid Hunt 				"Failed to get core info!\n");
1656453b928SDavid Hunt 		return -1;
1666453b928SDavid Hunt 	}
1676453b928SDavid Hunt 
168751227a0SDavid Hunt 	if (ci->core_count > RTE_MAX_LCORE)
169751227a0SDavid Hunt 		max_core_num = RTE_MAX_LCORE;
170c12ade20SDavid Hunt 	else
171c12ade20SDavid Hunt 		max_core_num = ci->core_count;
172c12ade20SDavid Hunt 
173c12ade20SDavid Hunt 	for (i = 0; i < max_core_num; i++) {
1746453b928SDavid Hunt 		if (ci->cd[i].global_enabled_cpus) {
175d26c18c9SAlan Carew 			if (rte_power_exit(i) < 0) {
176d26c18c9SAlan Carew 				RTE_LOG(ERR, POWER_MANAGER, "Unable to shutdown power manager "
177d26c18c9SAlan Carew 						"for core %u\n", i);
178d26c18c9SAlan Carew 				ret = -1;
179d26c18c9SAlan Carew 			}
1806453b928SDavid Hunt 			ci->cd[i].global_enabled_cpus = 0;
181d26c18c9SAlan Carew 		}
1826453b928SDavid Hunt 		remove_core_from_monitor(i);
1836453b928SDavid Hunt 	}
184d26c18c9SAlan Carew 	return ret;
185d26c18c9SAlan Carew }
186d26c18c9SAlan Carew 
187d26c18c9SAlan Carew int
188d26c18c9SAlan Carew power_manager_scale_core_up(unsigned core_num)
189d26c18c9SAlan Carew {
190d26c18c9SAlan Carew 	int ret = 0;
191d26c18c9SAlan Carew 
192d26c18c9SAlan Carew 	POWER_SCALE_CORE(up, core_num, ret);
193d26c18c9SAlan Carew 	return ret;
194d26c18c9SAlan Carew }
195d26c18c9SAlan Carew 
196d26c18c9SAlan Carew int
197d26c18c9SAlan Carew power_manager_scale_core_down(unsigned core_num)
198d26c18c9SAlan Carew {
199d26c18c9SAlan Carew 	int ret = 0;
200d26c18c9SAlan Carew 
201d26c18c9SAlan Carew 	POWER_SCALE_CORE(down, core_num, ret);
202d26c18c9SAlan Carew 	return ret;
203d26c18c9SAlan Carew }
204d26c18c9SAlan Carew 
205d26c18c9SAlan Carew int
206d26c18c9SAlan Carew power_manager_scale_core_min(unsigned core_num)
207d26c18c9SAlan Carew {
208d26c18c9SAlan Carew 	int ret = 0;
209d26c18c9SAlan Carew 
210d26c18c9SAlan Carew 	POWER_SCALE_CORE(min, core_num, ret);
211d26c18c9SAlan Carew 	return ret;
212d26c18c9SAlan Carew }
213d26c18c9SAlan Carew 
214d26c18c9SAlan Carew int
215d26c18c9SAlan Carew power_manager_scale_core_max(unsigned core_num)
216d26c18c9SAlan Carew {
217d26c18c9SAlan Carew 	int ret = 0;
218d26c18c9SAlan Carew 
219d26c18c9SAlan Carew 	POWER_SCALE_CORE(max, core_num, ret);
220d26c18c9SAlan Carew 	return ret;
221d26c18c9SAlan Carew }
222567997b9SDavid Hunt 
223567997b9SDavid Hunt int
224567997b9SDavid Hunt power_manager_enable_turbo_core(unsigned int core_num)
225567997b9SDavid Hunt {
226567997b9SDavid Hunt 	int ret = 0;
227567997b9SDavid Hunt 
228567997b9SDavid Hunt 	POWER_SCALE_CORE(enable_turbo, core_num, ret);
229567997b9SDavid Hunt 	return ret;
230567997b9SDavid Hunt }
231567997b9SDavid Hunt 
232567997b9SDavid Hunt int
233567997b9SDavid Hunt power_manager_disable_turbo_core(unsigned int core_num)
234567997b9SDavid Hunt {
235567997b9SDavid Hunt 	int ret = 0;
236567997b9SDavid Hunt 
237567997b9SDavid Hunt 	POWER_SCALE_CORE(disable_turbo, core_num, ret);
238567997b9SDavid Hunt 	return ret;
239567997b9SDavid Hunt }
2407f472f74SDavid Hunt 
2417f472f74SDavid Hunt int
2427f472f74SDavid Hunt power_manager_scale_core_med(unsigned int core_num)
2437f472f74SDavid Hunt {
2447f472f74SDavid Hunt 	int ret = 0;
2456453b928SDavid Hunt 	struct core_info *ci;
2467f472f74SDavid Hunt 
2476453b928SDavid Hunt 	ci = get_core_info();
248751227a0SDavid Hunt 	if (core_num >= RTE_MAX_LCORE)
2497f472f74SDavid Hunt 		return -1;
2506453b928SDavid Hunt 	if (!(ci->cd[core_num].global_enabled_cpus))
2517f472f74SDavid Hunt 		return -1;
2527f472f74SDavid Hunt 	rte_spinlock_lock(&global_core_freq_info[core_num].power_sl);
2537f472f74SDavid Hunt 	ret = rte_power_set_freq(core_num,
2547f472f74SDavid Hunt 				global_core_freq_info[core_num].num_freqs / 2);
2557f472f74SDavid Hunt 	rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl);
2567f472f74SDavid Hunt 	return ret;
2577f472f74SDavid Hunt }
258