[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 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |