[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] Add CPU topology info (thread/core/socket) in xenpm



Add CPU topology info (thread/core/socket) in xenpm

CPU topology info is necessary for power management analysis. For example, to 
analysis the effect of Px state coordination, Cx package/core coordination,  
the thread/core/socket topology information is needed.

This patch add new command "get-cpu-topology" in xenpm to print the CPU 
topology info:

e.g. in a 2 sockets, 4 cores per socket machine, the output is as follow:
# xenpm get-cpu-topology
CPU     core    socket
CPU0     0       0
CPU1     0       1
CPU2     1       0
CPU3     1       1
CPU4     2       0
CPU5     2       1
CPU6     3       0
CPU7     3       1

indicating socket 0 has CPU 0,2,4,6, and socket 1 has CPU 1,3,5,7

Signed-off-by: Yu Ke <ke.yu@xxxxxxxxx>

diff -r 4fd39881f9f1 tools/libxc/xc_pm.c
--- a/tools/libxc/xc_pm.c
+++ b/tools/libxc/xc_pm.c
@@ -306,3 +306,24 @@ int xc_set_cpufreq_para(int xc_handle, i
 
     return xc_sysctl(xc_handle, &sysctl);
 }
+
+int xc_get_cputopo(int xc_handle, struct xc_get_cputopo *info)
+{
+    int rc;
+    DECLARE_SYSCTL;
+
+    sysctl.cmd = XEN_SYSCTL_pm_op;
+    sysctl.u.pm_op.cmd = XEN_SYSCTL_pm_op_get_cputopo;
+    sysctl.u.pm_op.cpuid = 0;
+    set_xen_guest_handle( sysctl.u.pm_op.get_topo.cpu_to_core,
+                         info->cpu_to_core );
+    set_xen_guest_handle( sysctl.u.pm_op.get_topo.cpu_to_socket,
+                         info->cpu_to_socket );
+    sysctl.u.pm_op.get_topo.max_cpus = info->max_cpus;
+
+    rc = do_sysctl(xc_handle, &sysctl);
+    info->nr_cpus = sysctl.u.pm_op.get_topo.nr_cpus;
+
+    return rc;
+}
+
diff -r 4fd39881f9f1 tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -1242,4 +1242,21 @@ int xc_set_cpufreq_gov(int xc_handle, in
 int xc_set_cpufreq_gov(int xc_handle, int cpuid, char *govname);
 int xc_set_cpufreq_para(int xc_handle, int cpuid,
                         int ctrl_type, int ctrl_value);
+
+struct xc_get_cputopo {
+     /* IN: maximum addressable entry in
+      * the caller-provided cpu_to_core/socket.
+      */
+    uint32_t max_cpus;
+    uint32_t *cpu_to_core;
+    uint32_t *cpu_to_socket;
+
+    /* OUT: number of cpus returned
+     * If OUT is greater than IN then the cpu_to_core/socket is truncated!
+     */
+    uint32_t nr_cpus;
+};
+
+int xc_get_cputopo(int xc_handle, struct xc_get_cputopo *info);
+
 #endif /* XENCTRL_H */
diff -r 4fd39881f9f1 tools/misc/xenpm.c
--- a/tools/misc/xenpm.c
+++ b/tools/misc/xenpm.c
@@ -58,6 +58,7 @@ void show_help(void)
             "                                     it is used in ondemand 
governor.\n"
             " set-up-threshold      [cpuid] <num> set up threshold on CPU 
<cpuid> or all\n"
             "                                     it is used in ondemand 
governor.\n"
+            " get-cpu-topology                    get thread/core/socket 
topology info\n"
             " start                               start collect Cx/Px 
statistics,\n"
             "                                     output after CTRL-C or 
SIGINT.\n"
             );
@@ -750,6 +751,40 @@ out:
     fprintf(stderr, "failed to set governor name\n");
 }
 
+#define MAX_NR_CPU 512
+
+void cpu_topology_func(int argc, char *argv[])
+{
+    uint32_t cpu_to_core[MAX_NR_CPU];
+    uint32_t cpu_to_socket[MAX_NR_CPU];
+    struct xc_get_cputopo info;
+    int i, ret;
+
+    info.cpu_to_core = cpu_to_core;
+    info.cpu_to_socket = cpu_to_socket;
+    info.max_cpus = MAX_NR_CPU;
+    ret = xc_get_cputopo(xc_fd, &info);
+    if (!ret)
+    {
+        printf("CPU\tcore\tsocket\n");
+        for (i=0; i<info.nr_cpus; i++)
+        {
+            if ( info.cpu_to_core[i] != INVALID_TOPOLOGY_ID &&
+                    info.cpu_to_socket[i] != INVALID_TOPOLOGY_ID )
+            {
+            printf("CPU%d\t %d\t %d\n", i, info.cpu_to_core[i],
+                    info.cpu_to_socket[i]);
+            }
+        }
+    }
+    else
+    {
+        printf("Can not get Xen CPU topology!\n");
+    }
+
+    return ;
+}
+
 struct {
     const char *name;
     void (*function)(int argc, char *argv[]);
@@ -765,6 +800,7 @@ struct {
     { "set-scaling-speed", scaling_speed_func },
     { "set-sampling-rate", scaling_sampling_rate_func },
     { "set-up-threshold", scaling_up_threshold_func },
+    { "get-cpu-topology", cpu_topology_func},
 };
 
 int main(int argc, char *argv[])
diff -r 4fd39881f9f1 xen/common/sysctl.c
--- a/xen/common/sysctl.c
+++ b/xen/common/sysctl.c
@@ -224,12 +224,11 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysc
         if ( ret && (ret != -EAGAIN) )
             break;
 
-        if ( op->u.pm_op.cmd == GET_CPUFREQ_PARA )
-            if ( copy_to_guest(u_sysctl, op, 1) )
-            {
-                ret = -EFAULT;
-                break;
-            }
+        if ( copy_to_guest(u_sysctl, op, 1) )
+        {
+            ret = -EFAULT;
+            break;
+        }
     }
     break;
 
diff -r 4fd39881f9f1 xen/drivers/acpi/pmstat.c
--- a/xen/drivers/acpi/pmstat.c
+++ b/xen/drivers/acpi/pmstat.c
@@ -416,6 +416,52 @@ static int set_cpufreq_para(struct xen_s
     return ret;
 }
 
+static int get_cputopo (struct xen_sysctl_pm_op *op)
+{
+    uint32_t i, nr_cpus;
+    XEN_GUEST_HANDLE_64(uint32) cpu_to_core_arr;
+    XEN_GUEST_HANDLE_64(uint32) cpu_to_socket_arr;
+    int arr_size, ret=0;
+
+    cpu_to_core_arr = op->get_topo.cpu_to_core;
+    cpu_to_socket_arr = op->get_topo.cpu_to_socket;
+    arr_size= min_t(uint32_t, op->get_topo.max_cpus, NR_CPUS);
+
+    if ( guest_handle_is_null( cpu_to_core_arr ) ||
+            guest_handle_is_null(  cpu_to_socket_arr) )
+    {
+        ret = -EINVAL;
+        goto out;
+    }
+
+    nr_cpus = 0;
+    for ( i = 0; i < arr_size; i++ )
+    {
+        uint32_t core, socket;
+        if ( cpu_online(i) )
+        {
+            core = cpu_to_core(i);
+            socket = cpu_to_socket(i);
+            nr_cpus = i;
+        }
+        else
+        {
+            core = socket = INVALID_TOPOLOGY_ID;
+        }
+
+        if ( copy_to_guest_offset(cpu_to_core_arr, i, &core, 1) ||
+                copy_to_guest_offset(cpu_to_socket_arr, i, &socket, 1))
+        {
+            ret = -EFAULT;
+            goto out;
+        }
+    }
+
+    op->get_topo.nr_cpus = nr_cpus + 1;
+out:
+    return ret;
+}
+
 int do_pm_op(struct xen_sysctl_pm_op *op)
 {
     int ret = 0;
@@ -433,8 +479,6 @@ int do_pm_op(struct xen_sysctl_pm_op *op
         if ( !pmpt || !(pmpt->perf.init & XEN_PX_INIT) )
             return -EINVAL;
         break;
-    default:
-        return -ENODEV;
     }
 
     switch ( op->cmd )
@@ -457,6 +501,12 @@ int do_pm_op(struct xen_sysctl_pm_op *op
         break;
     }
 
+    case XEN_SYSCTL_pm_op_get_cputopo:
+    {
+        ret = get_cputopo(op);
+        break;
+    }
+
     default:
         printk("not defined sub-hypercall @ do_pm_op\n");
         ret = -ENOSYS;
diff -r 4fd39881f9f1 xen/include/asm-ia64/linux-xen/asm/processor.h
--- a/xen/include/asm-ia64/linux-xen/asm/processor.h
+++ b/xen/include/asm-ia64/linux-xen/asm/processor.h
@@ -197,6 +197,14 @@ DECLARE_PER_CPU(struct cpuinfo_ia64, cpu
  */
 #define local_cpu_data         (&__ia64_per_cpu_var(cpu_info))
 #define cpu_data(cpu)          (&per_cpu(cpu_info, cpu))
+
+#ifdef CONFIG_SMP
+#define cpu_to_core(cpu)    (cpu_data(cpu)->core_id)
+#define cpu_to_socket(cpu)  (cpu_data(cpu)->socket_id)
+#else
+#define cpu_to_core(cpu)    0
+#define cpu_to_socket(cpu)  0
+#endif
 
 extern void identify_cpu (struct cpuinfo_ia64 *);
 extern void print_cpu_info (struct cpuinfo_ia64 *);
diff -r 4fd39881f9f1 xen/include/asm-x86/processor.h
--- a/xen/include/asm-x86/processor.h
+++ b/xen/include/asm-x86/processor.h
@@ -203,6 +203,9 @@ extern void detect_ht(struct cpuinfo_x86
 #else
 static always_inline void detect_ht(struct cpuinfo_x86 *c) {}
 #endif
+
+#define cpu_to_core(_cpu)   (cpu_core_id[_cpu])
+#define cpu_to_socket(_cpu) (phys_proc_id[_cpu])
 
 /*
  * Generic CPUID function
diff -r 4fd39881f9f1 xen/include/public/sysctl.h
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -339,6 +339,24 @@ struct xen_set_cpufreq_para {
 
     uint32_t ctrl_type;
     uint32_t ctrl_value;
+}
+;
+/* Get physical CPU topology information. */
+
+
+#define INVALID_TOPOLOGY_ID  (~0U)
+struct xen_get_cputopo {
+     /* IN: maximum addressable entry in
+      * the caller-provided cpu_to_core/socket.
+      */
+    uint32_t max_cpus;
+    XEN_GUEST_HANDLE_64(uint32) cpu_to_core;
+    XEN_GUEST_HANDLE_64(uint32) cpu_to_socket;
+
+    /* OUT: number of cpus returned
+     * If OUT is greater than IN then the cpu_to_core/socket is truncated!
+     */
+    uint32_t nr_cpus;
 };
 
 struct xen_sysctl_pm_op {
@@ -350,12 +368,16 @@ struct xen_sysctl_pm_op {
     #define SET_CPUFREQ_GOV            (CPUFREQ_PARA | 0x02)
     #define SET_CPUFREQ_PARA           (CPUFREQ_PARA | 0x03)
 
+    /* get CPU topology */
+    #define XEN_SYSCTL_pm_op_get_cputopo  0x20
+
     uint32_t cmd;
     uint32_t cpuid;
     union {
         struct xen_get_cpufreq_para get_para;
         struct xen_set_cpufreq_gov  set_gov;
         struct xen_set_cpufreq_para set_para;
+        struct xen_get_cputopo      get_topo;
     };
 };

Attachment: cpu-topology.patch
Description: cpu-topology.patch

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.