tools/power/turbostat: Handle cgroup v2 cpu limitation
authorZhang Rui <rui.zhang@intel.com>
Fri, 20 Oct 2023 01:39:22 +0000 (09:39 +0800)
committerZhang Rui <rui.zhang@intel.com>
Tue, 24 Oct 2023 05:38:09 +0000 (13:38 +0800)
CPUs can be isolated via cgroup settings and turbostat should avoid
migrating to these CPUs, just like it does for the '-c' cpus.

Introduce cpu_effective_set to save the cgroup cpu limitation info from
/sys/fs/cgroup/cpuset.cpus.effective. And use cpu_allowed_set as the
intersection of cpu_present_set, cpu_effective_set and cpu_subset.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
tools/power/x86/turbostat/turbostat.c

index 3a759b49f25e13237a5ece30b7f1363f24f0c74e..0ef6fba118b1bc2e70f07bc746964b35fe8df616 100644 (file)
@@ -904,8 +904,8 @@ int backwards_count;
 char *progname;
 
 #define CPU_SUBSET_MAXCPUS     1024    /* need to use before probe... */
-cpu_set_t *cpu_present_set, *cpu_allowed_set, *cpu_affinity_set, *cpu_subset;
-size_t cpu_present_setsize, cpu_allowed_setsize, cpu_affinity_setsize, cpu_subset_size;
+cpu_set_t *cpu_present_set, *cpu_effective_set, *cpu_allowed_set, *cpu_affinity_set, *cpu_subset;
+size_t cpu_present_setsize, cpu_effective_setsize, cpu_allowed_setsize, cpu_affinity_setsize, cpu_subset_size;
 #define MAX_ADDED_COUNTERS 8
 #define MAX_ADDED_THREAD_COUNTERS 24
 #define BITMASK_SIZE 32
@@ -3419,6 +3419,10 @@ void free_all_buffers(void)
        cpu_present_set = NULL;
        cpu_present_setsize = 0;
 
+       CPU_FREE(cpu_effective_set);
+       cpu_effective_set = NULL;
+       cpu_effective_setsize = 0;
+
        CPU_FREE(cpu_allowed_set);
        cpu_allowed_set = NULL;
        cpu_allowed_setsize = 0;
@@ -3741,6 +3745,46 @@ int for_all_proc_cpus(int (func) (int))
        return 0;
 }
 
+#define PATH_EFFECTIVE_CPUS    "/sys/fs/cgroup/cpuset.cpus.effective"
+
+static char cpu_effective_str[1024];
+
+static int update_effective_str(bool startup)
+{
+       FILE *fp;
+       char *pos;
+       char buf[1024];
+       int ret;
+
+       if (cpu_effective_str[0] == '\0' && !startup)
+               return 0;
+
+       fp = fopen(PATH_EFFECTIVE_CPUS, "r");
+       if (!fp)
+               return 0;
+
+       pos = fgets(buf, 1024, fp);
+       if (!pos)
+               err(1, "%s: file read failed\n", PATH_EFFECTIVE_CPUS);
+
+       fclose(fp);
+
+       ret = strncmp(cpu_effective_str, buf, 1024);
+       if (!ret)
+               return 0;
+
+       strncpy(cpu_effective_str, buf, 1024);
+       return 1;
+}
+
+static void update_effective_set(bool startup)
+{
+       update_effective_str(startup);
+
+       if (parse_cpu_str(cpu_effective_str, cpu_effective_set, cpu_effective_setsize))
+               err(1, "%s: cpu str malformat %s\n", PATH_EFFECTIVE_CPUS, cpu_effective_str);
+}
+
 void re_initialize(void)
 {
        free_all_buffers();
@@ -4257,6 +4301,10 @@ restart:
                        re_initialize();
                        goto restart;
                }
+               if (update_effective_str(false)) {
+                       re_initialize();
+                       goto restart;
+               }
                do_sleep();
                if (snapshot_proc_sysfs_files())
                        goto restart;
@@ -5777,6 +5825,16 @@ void topology_probe(bool startup)
        CPU_ZERO_S(cpu_present_setsize, cpu_present_set);
        for_all_proc_cpus(mark_cpu_present);
 
+       /*
+        * Allocate and initialize cpu_effective_set
+        */
+       cpu_effective_set = CPU_ALLOC((topo.max_cpu_num + 1));
+       if (cpu_effective_set == NULL)
+               err(3, "CPU_ALLOC");
+       cpu_effective_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1));
+       CPU_ZERO_S(cpu_effective_setsize, cpu_effective_set);
+       update_effective_set(startup);
+
        /*
         * Allocate and initialize cpu_allowed_set
         */
@@ -5787,30 +5845,37 @@ void topology_probe(bool startup)
        CPU_ZERO_S(cpu_allowed_setsize, cpu_allowed_set);
 
        /*
-        * Validate cpu_subset and update cpu_allowed_set.
+        * Validate and update cpu_allowed_set.
         *
-        * Make sure all cpus in cpu_subset are also in cpu_present_set during startup,
-        * and give a warning when cpus in cpu_subset become unavailable at runtime.
+        * Make sure all cpus in cpu_subset are also in cpu_present_set during startup.
+        * Give a warning when cpus in cpu_subset become unavailable at runtime.
+        * Give a warning when cpus are not effective because of cgroup setting.
         *
-        * cpu_allowed_set is the intersection of cpu_present_set and cpu_subset.
+        * cpu_allowed_set is the intersection of cpu_present_set/cpu_effective_set/cpu_subset.
         */
        for (i = 0; i < CPU_SUBSET_MAXCPUS; ++i) {
-               if (!cpu_subset) {
-                       if (CPU_ISSET_S(i, cpu_present_setsize, cpu_present_set))
-                               CPU_SET_S(i, cpu_allowed_setsize, cpu_allowed_set);
+               if (cpu_subset && !CPU_ISSET_S(i, cpu_subset_size, cpu_subset))
                        continue;
-               }
-               if (CPU_ISSET_S(i, cpu_subset_size, cpu_subset)) {
-                       if (!CPU_ISSET_S(i, cpu_present_setsize, cpu_present_set)) {
-                               /* all cpus in cpu_subset must be in cpu_present_set during startup */
+
+               if (!CPU_ISSET_S(i, cpu_present_setsize, cpu_present_set)) {
+                       if (cpu_subset) {
+                               /* cpus in cpu_subset must be in cpu_present_set during startup */
                                if (startup)
                                        err(1, "cpu%d not present", i);
                                else
                                        fprintf(stderr, "cpu%d not present\n", i);
-                       } else {
-                               CPU_SET_S(i, cpu_allowed_setsize, cpu_allowed_set);
                        }
+                       continue;
                }
+
+               if (CPU_COUNT_S(cpu_effective_setsize, cpu_effective_set)) {
+                       if (!CPU_ISSET_S(i, cpu_effective_setsize, cpu_effective_set)) {
+                               fprintf(stderr, "cpu%d not effective\n", i);
+                               continue;
+                       }
+               }
+
+               CPU_SET_S(i, cpu_allowed_setsize, cpu_allowed_set);
        }
 
        if (!CPU_COUNT_S(cpu_allowed_setsize, cpu_allowed_set))