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;
};
};
cpu-topology.patch
Description: cpu-topology.patch
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|