summaryrefslogtreecommitdiffstats
path: root/tools/power/x86
diff options
context:
space:
mode:
authorSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>2023-02-22 03:42:19 -0800
committerSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>2023-03-22 13:36:55 -0700
commit997074df658e444e79a5294b685b77b08a3c414c (patch)
treee70dc21c3831abb7b6fb43576002d3a6cd54c25c /tools/power/x86
parent57797f19d5a78b5a84b7452790f7da22865f6420 (diff)
downloadlinux-997074df658e444e79a5294b685b77b08a3c414c.tar.gz
linux-997074df658e444e79a5294b685b77b08a3c414c.tar.bz2
linux-997074df658e444e79a5294b685b77b08a3c414c.zip
tools/power/x86/intel-speed-select: Use cgroup v2 isolation
On supported systems, it is possiible to isolate CPUs instead of CPU online/offline. This is optional and can be specified using -g option when running as daemon or in combination with -o option for SST-PP level change. CPU isolation doesn't isolate IRQs. So IRQs needs to be moved away from isoolated CPUs. This can be done via IRQ sysfs or irqbalance daemon. The IRQ balance daemon is also capable to parse thermal HFI messages to move IRQs away from CPUS, which are supposed be isolated. But this requires version released after July 2022. Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Diffstat (limited to 'tools/power/x86')
-rw-r--r--tools/power/x86/intel-speed-select/isst-config.c155
-rw-r--r--tools/power/x86/intel-speed-select/isst-daemon.c15
-rw-r--r--tools/power/x86/intel-speed-select/isst.h5
3 files changed, 173 insertions, 2 deletions
diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c
index a9bd87b4d4ee..c4d00426cb6a 100644
--- a/tools/power/x86/intel-speed-select/isst-config.c
+++ b/tools/power/x86/intel-speed-select/isst-config.c
@@ -44,6 +44,7 @@ static int cmd_help;
static int force_online_offline;
static int auto_mode;
static int fact_enable_fail;
+static int cgroupv2;
/* clos related */
static int current_clos = -1;
@@ -834,7 +835,137 @@ int find_phy_core_num(int logical_cpu)
return -EINVAL;
}
+int use_cgroupv2(void)
+{
+ return cgroupv2;
+}
+
+int enable_cpuset_controller(void)
+{
+ int fd, ret;
+
+ fd = open("/sys/fs/cgroup/cgroup.subtree_control", O_RDWR, 0);
+ if (fd < 0) {
+ debug_printf("Can't activate cpuset controller\n");
+ debug_printf("Either you are not root user or CGroup v2 is not supported\n");
+ return fd;
+ }
+
+ ret = write(fd, " +cpuset", strlen(" +cpuset"));
+ close(fd);
+
+ if (ret == -1) {
+ debug_printf("Can't activate cpuset controller: Write failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int level)
+{
+ int i, first, curr_index, index, ret, fd;
+ static char str[512], dir_name[64];
+ static char cpuset_cpus[128];
+ int str_len = sizeof(str);
+ DIR *dir;
+
+ snprintf(dir_name, sizeof(dir_name), "/sys/fs/cgroup/%d-%d-%d", id->pkg, id->die, id->punit);
+ dir = opendir(dir_name);
+ if (!dir) {
+ ret = mkdir(dir_name, 0744);
+ if (ret) {
+ debug_printf("Can't create dir:%s errno:%d\n", dir_name, errno);
+ return ret;
+ }
+ }
+ closedir(dir);
+
+ if (!level) {
+ sprintf(cpuset_cpus, "%s/cpuset.cpus.partition", dir_name);
+
+ fd = open(cpuset_cpus, O_RDWR, 0);
+ if (fd < 0) {
+ return fd;
+ }
+
+ ret = write(fd, "member", strlen("member"));
+ if (ret == -1) {
+ printf("Can't update to member\n");
+ return ret;
+ }
+
+ return 0;
+ }
+
+ if (!CPU_COUNT_S(mask_size, cpu_mask)) {
+ return -1;
+ }
+ curr_index = 0;
+ first = 1;
+ str[0] = '\0';
+ for (i = 0; i < get_topo_max_cpus(); ++i) {
+ if (!is_cpu_in_power_domain(i, id))
+ continue;
+
+ if (CPU_ISSET_S(i, mask_size, cpu_mask))
+ continue;
+
+ if (!first) {
+ index = snprintf(&str[curr_index],
+ str_len - curr_index, ",");
+ curr_index += index;
+ if (curr_index >= str_len)
+ break;
+ }
+ index = snprintf(&str[curr_index], str_len - curr_index, "%d",
+ i);
+ curr_index += index;
+ if (curr_index >= str_len)
+ break;
+ first = 0;
+ }
+
+ debug_printf("isolated CPUs list: package:%d curr_index:%d [%s]\n", id->pkg, curr_index ,str);
+
+ snprintf(cpuset_cpus, sizeof(cpuset_cpus), "%s/cpuset.cpus", dir_name);
+
+ fd = open(cpuset_cpus, O_RDWR, 0);
+ if (fd < 0) {
+ return fd;
+ }
+
+ ret = write(fd, str, strlen(str));
+ close(fd);
+
+ if (ret == -1) {
+ debug_printf("Can't activate cpuset controller: Write failed\n");
+ return ret;
+ }
+
+ snprintf(cpuset_cpus, sizeof(cpuset_cpus), "%s/cpuset.cpus.partition", dir_name);
+
+ fd = open(cpuset_cpus, O_RDWR, 0);
+ if (fd < 0) {
+ return fd;
+ }
+
+ ret = write(fd, "isolated", strlen("isolated"));
+ if (ret == -1) {
+ debug_printf("Can't update to isolated\n");
+ ret = write(fd, "root", strlen("root"));
+ if (ret == -1)
+ debug_printf("Can't update to root\n");
+ }
+
+ close(fd);
+
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
static int isst_fill_platform_info(void)
{
@@ -1273,6 +1404,23 @@ display_result:
isst_display_error_info_message(1, "Can't get coremask, online/offline option is ignored", 0, 0);
goto free_mask;
}
+
+ if (use_cgroupv2()) {
+ int ret;
+
+ fprintf(stderr, "Using cgroup v2 in lieu of online/offline\n");
+ ret = enable_cpuset_controller();
+ if (ret)
+ goto use_offline;
+
+ ret = isolate_cpus(id, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask, tdp_level);
+ if (ret)
+ goto use_offline;
+
+ goto free_mask;
+ }
+
+use_offline:
if (ctdp_level.cpu_count) {
int i, max_cpus = get_topo_max_cpus();
for (i = 0; i < max_cpus; ++i) {
@@ -2787,6 +2935,7 @@ static void usage(void)
printf("\t[-b|--oob : Start a daemon to process HFI events for perf profile change from Out of Band agent.\n");
printf("\t[-n|--no-daemon : Don't run as daemon. By default --oob will turn on daemon mode\n");
printf("\t[-w|--delay : Delay for reading config level state change in OOB poll mode.\n");
+ printf("\t[-g|--cgroupv2 : Try to use cgroup v2 CPU isolation instead of CPU online/offline.\n");
printf("\nResult format\n");
printf("\tResult display uses a common format for each command:\n");
printf("\tResults are formatted in text/JSON with\n");
@@ -2839,6 +2988,7 @@ static void cmdline(int argc, char **argv)
{ "oob", no_argument, 0, 'b' },
{ "no-daemon", no_argument, 0, 'n' },
{ "poll-interval", required_argument, 0, 'w' },
+ { "cgroupv2", required_argument, 0, 'g' },
{ 0, 0, 0, 0 }
};
@@ -2869,7 +3019,7 @@ static void cmdline(int argc, char **argv)
goto out;
progname = argv[0];
- while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:n", long_options,
+ while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:ng", long_options,
&option_index)) != -1) {
switch (opt) {
case 'a':
@@ -2928,6 +3078,9 @@ static void cmdline(int argc, char **argv)
}
poll_interval = ret;
break;
+ case 'g':
+ cgroupv2 = 1;
+ break;
default:
usage();
}
diff --git a/tools/power/x86/intel-speed-select/isst-daemon.c b/tools/power/x86/intel-speed-select/isst-daemon.c
index 6fa2942b5e12..12053fa43542 100644
--- a/tools/power/x86/intel-speed-select/isst-daemon.c
+++ b/tools/power/x86/intel-speed-select/isst-daemon.c
@@ -83,6 +83,19 @@ void process_level_change(struct isst_id *id)
return;
}
+ if (use_cgroupv2()) {
+ int ret;
+
+ ret = enable_cpuset_controller();
+ if (ret)
+ goto use_offline;
+
+ isolate_cpus(id, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask, pkg_dev.current_level);
+
+ goto free_mask;
+ }
+
+use_offline:
if (ctdp_level.cpu_count) {
int i, max_cpus = get_topo_max_cpus();
for (i = 0; i < max_cpus; ++i) {
@@ -97,7 +110,7 @@ void process_level_change(struct isst_id *id)
}
}
}
-
+free_mask:
free_cpu_set(ctdp_level.core_cpumask);
}
diff --git a/tools/power/x86/intel-speed-select/isst.h b/tools/power/x86/intel-speed-select/isst.h
index 1984cc564fa9..6a37c26b1ef7 100644
--- a/tools/power/x86/intel-speed-select/isst.h
+++ b/tools/power/x86/intel-speed-select/isst.h
@@ -315,4 +315,9 @@ extern void hfi_exit(void);
extern struct isst_platform_ops *mbox_get_platform_ops(void);
extern struct isst_platform_ops *tpmi_get_platform_ops(void);
+/* Cgroup related interface */
+extern int enable_cpuset_controller(void);
+extern int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int level);
+extern int use_cgroupv2(void);
+
#endif