# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1210927039 -3600
# Node ID d0817f08599afe3f2d7ffa2e3fd88e6a65f5e85d
# Parent f65906f262f9928abfd2ba642ba2051919cdfbbe
Provide Px statistic data to user through libxc
Sampling and collecting dynamic Px statistic data, including
Px state value, Px count, Px residency time, Px transition
matrix, etc. Provide Px statistic data to user through libxc.
Signed-off-by: Liu Jinsong <jinsong.liu@xxxxxxxxx>
---
tools/libxc/Makefile | 1
tools/libxc/xc_pm.c | 101 +++++++++++++++++++++++++++
tools/libxc/xenctrl.h | 19 +++++
xen/arch/x86/acpi/Makefile | 1
xen/arch/x86/acpi/cpufreq/cpufreq.c | 16 +++-
xen/arch/x86/acpi/cpufreq/utility.c | 77 +++++++++++++++++++++
xen/arch/x86/acpi/pmstat.c | 110 ++++++++++++++++++++++++++++++
xen/arch/x86/platform_hypercall.c | 3
xen/common/sysctl.c | 16 ++++
xen/include/acpi/cpufreq/processor_perf.h | 23 ++++++
xen/include/public/sysctl.h | 37 +++++++++-
11 files changed, 397 insertions(+), 7 deletions(-)
diff -r f65906f262f9 -r d0817f08599a tools/libxc/Makefile
--- a/tools/libxc/Makefile Fri May 16 09:31:03 2008 +0100
+++ b/tools/libxc/Makefile Fri May 16 09:37:19 2008 +0100
@@ -20,6 +20,7 @@ CTRL_SRCS-y += xc_sedf.c
CTRL_SRCS-y += xc_sedf.c
CTRL_SRCS-y += xc_csched.c
CTRL_SRCS-y += xc_tbuf.c
+CTRL_SRCS-y += xc_pm.c
ifneq ($(stubdom),y)
CTRL_SRCS-y += xc_resume.c
endif
diff -r f65906f262f9 -r d0817f08599a tools/libxc/xc_pm.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxc/xc_pm.c Fri May 16 09:37:19 2008 +0100
@@ -0,0 +1,101 @@
+/******************************************************************************
+ * xc_pm.c - Libxc API for Xen Power Management (Px/Cx/Tx, etc.) statistic
+ *
+ * Copyright (c) 2008, Liu Jinsong <jinsong.liu@xxxxxxxxx>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "xc_private.h"
+
+int xc_pm_get_max_px(int xc_handle, int cpuid, int *max_px)
+{
+ DECLARE_SYSCTL;
+ int ret;
+
+ sysctl.cmd = XEN_SYSCTL_get_pmstat;
+ sysctl.u.get_pmstat.type = PMSTAT_get_max_px;
+ sysctl.u.get_pmstat.cpuid = cpuid;
+ ret = xc_sysctl(xc_handle, &sysctl);
+ if ( ret )
+ return ret;
+
+ *max_px = sysctl.u.get_pmstat.u.getpx.total;
+ return ret;
+}
+
+int xc_pm_get_pxstat(int xc_handle, int cpuid, struct xc_px_stat *pxpt)
+{
+ DECLARE_SYSCTL;
+ int max_px, ret;
+
+ if ( !pxpt || !(pxpt->trans_pt) || !(pxpt->pt) )
+ return -EINVAL;
+
+ if ( (ret = xc_pm_get_max_px(xc_handle, cpuid, &max_px)) != 0)
+ return ret;
+
+ if ( (ret = lock_pages(pxpt->trans_pt,
+ max_px * max_px * sizeof(uint64_t))) != 0 )
+ return ret;
+
+ if ( (ret = lock_pages(pxpt->pt,
+ max_px * sizeof(struct xc_px_val))) != 0 )
+ {
+ unlock_pages(pxpt->trans_pt, max_px * max_px * sizeof(uint64_t));
+ return ret;
+ }
+
+ sysctl.cmd = XEN_SYSCTL_get_pmstat;
+ sysctl.u.get_pmstat.type = PMSTAT_get_pxstat;
+ sysctl.u.get_pmstat.cpuid = cpuid;
+ set_xen_guest_handle(sysctl.u.get_pmstat.u.getpx.trans_pt, pxpt->trans_pt);
+ set_xen_guest_handle(sysctl.u.get_pmstat.u.getpx.pt,
+ (pm_px_val_t *)pxpt->pt);
+
+ ret = xc_sysctl(xc_handle, &sysctl);
+ if ( ret )
+ {
+ unlock_pages(pxpt->trans_pt, max_px * max_px * sizeof(uint64_t));
+ unlock_pages(pxpt->pt, max_px * sizeof(struct xc_px_val));
+ return ret;
+ }
+
+ pxpt->total = sysctl.u.get_pmstat.u.getpx.total;
+ pxpt->usable = sysctl.u.get_pmstat.u.getpx.usable;
+ pxpt->last = sysctl.u.get_pmstat.u.getpx.last;
+ pxpt->cur = sysctl.u.get_pmstat.u.getpx.cur;
+
+ unlock_pages(pxpt->trans_pt, max_px * max_px * sizeof(uint64_t));
+ unlock_pages(pxpt->pt, max_px * sizeof(struct xc_px_val));
+
+ return ret;
+}
+
+int xc_pm_reset_pxstat(int xc_handle, int cpuid)
+{
+ DECLARE_SYSCTL;
+
+ sysctl.cmd = XEN_SYSCTL_get_pmstat;
+ sysctl.u.get_pmstat.type = PMSTAT_reset_pxstat;
+ sysctl.u.get_pmstat.cpuid = cpuid;
+
+ return xc_sysctl(xc_handle, &sysctl);
+}
diff -r f65906f262f9 -r d0817f08599a tools/libxc/xenctrl.h
--- a/tools/libxc/xenctrl.h Fri May 16 09:31:03 2008 +0100
+++ b/tools/libxc/xenctrl.h Fri May 16 09:37:19 2008 +0100
@@ -1034,4 +1034,23 @@ void xc_cpuid_to_str(const unsigned int
char **strs);
#endif
+struct xc_px_val {
+ uint64_t freq; /* Px core frequency */
+ uint64_t residency; /* Px residency time */
+ uint64_t count; /* Px transition count */
+};
+
+struct xc_px_stat {
+ uint8_t total; /* total Px states */
+ uint8_t usable; /* usable Px states */
+ uint8_t last; /* last Px state */
+ uint8_t cur; /* current Px state */
+ uint64_t *trans_pt; /* Px transition table */
+ struct xc_px_val *pt;
+};
+
+int xc_pm_get_max_px(int xc_handle, int cpuid, int *max_px);
+int xc_pm_get_pxstat(int xc_handle, int cpuid, struct xc_px_stat *pxpt);
+int xc_pm_reset_pxstat(int xc_handle, int cpuid);
+
#endif /* XENCTRL_H */
diff -r f65906f262f9 -r d0817f08599a xen/arch/x86/acpi/Makefile
--- a/xen/arch/x86/acpi/Makefile Fri May 16 09:31:03 2008 +0100
+++ b/xen/arch/x86/acpi/Makefile Fri May 16 09:37:19 2008 +0100
@@ -2,3 +2,4 @@ subdir-y += cpufreq
obj-y += boot.o
obj-y += power.o suspend.o wakeup_prot.o cpu_idle.o
+obj-y += pmstat.o
diff -r f65906f262f9 -r d0817f08599a xen/arch/x86/acpi/cpufreq/cpufreq.c
--- a/xen/arch/x86/acpi/cpufreq/cpufreq.c Fri May 16 09:31:03 2008 +0100
+++ b/xen/arch/x86/acpi/cpufreq/cpufreq.c Fri May 16 09:37:19 2008 +0100
@@ -369,6 +369,8 @@ static int acpi_cpufreq_target(struct cp
if (!check_freqs(cmd.mask, freqs.new, data))
return -EAGAIN;
+ px_statistic_update(cmd.mask, perf->state, next_perf_state);
+
perf->state = next_perf_state;
policy->cur = freqs.new;
@@ -581,9 +583,13 @@ int acpi_cpufreq_init(void)
for_each_online_cpu(i) {
xen_px_policy[i].cpu = i;
+ ret = px_statistic_init(i);
+ if (ret)
+ goto out;
+
ret = acpi_cpufreq_cpu_init(&xen_px_policy[i]);
if (ret)
- goto cpufreq_init_out;
+ goto out;
}
/* setup ondemand cpufreq */
@@ -593,10 +599,10 @@ int acpi_cpufreq_init(void)
i = first_cpu(pt[dom]);
ret = cpufreq_governor_dbs(&xen_px_policy[i], CPUFREQ_GOV_START);
if (ret)
- goto cpufreq_init_out;
- }
-
-cpufreq_init_out:
+ goto out;
+ }
+
+out:
xfree(pt);
return ret;
diff -r f65906f262f9 -r d0817f08599a xen/arch/x86/acpi/cpufreq/utility.c
--- a/xen/arch/x86/acpi/cpufreq/utility.c Fri May 16 09:31:03 2008 +0100
+++ b/xen/arch/x86/acpi/cpufreq/utility.c Fri May 16 09:37:19 2008 +0100
@@ -34,6 +34,83 @@ struct cpufreq_driver *cpufreq_driver;
struct cpufreq_driver *cpufreq_driver;
/*********************************************************************
+ * Px STATISTIC INFO *
+ *********************************************************************/
+
+void px_statistic_update(cpumask_t cpumask, uint8_t from, uint8_t to)
+{
+ uint32_t i;
+ uint64_t now;
+
+ now = NOW();
+
+ for_each_cpu_mask(i, cpumask) {
+ struct pm_px *pxpt = &px_statistic_data[i];
+ uint32_t statnum = processor_pminfo[i].perf.state_count;
+
+ pxpt->u.last = from;
+ pxpt->u.cur = to;
+ pxpt->u.pt[to].count++;
+ pxpt->u.pt[from].residency += now - pxpt->prev_state_wall;
+
+ (*(pxpt->u.trans_pt + from*statnum + to))++;
+
+ pxpt->prev_state_wall = now;
+ }
+}
+
+int px_statistic_init(int cpuid)
+{
+ uint32_t i, count;
+ struct pm_px *pxpt = &px_statistic_data[cpuid];
+ struct processor_pminfo *pmpt = &processor_pminfo[cpuid];
+
+ count = pmpt->perf.state_count;
+
+ pxpt->u.trans_pt = xmalloc_array(uint64_t, count * count);
+ if (!pxpt->u.trans_pt)
+ return -ENOMEM;
+
+ pxpt->u.pt = xmalloc_array(struct pm_px_val, count);
+ if (!pxpt->u.pt) {
+ xfree(pxpt->u.trans_pt);
+ return -ENOMEM;
+ }
+
+ memset(pxpt->u.trans_pt, 0, count * count * (sizeof(uint64_t)));
+ memset(pxpt->u.pt, 0, count * (sizeof(struct pm_px_val)));
+
+ pxpt->u.total = pmpt->perf.state_count;
+ pxpt->u.usable = pmpt->perf.state_count - pmpt->perf.ppc;
+
+ for (i=0; i < pmpt->perf.state_count; i++)
+ pxpt->u.pt[i].freq = pmpt->perf.states[i].core_frequency;
+
+ pxpt->prev_state_wall = NOW();
+
+ return 0;
+}
+
+void px_statistic_reset(int cpuid)
+{
+ uint32_t i, j, count;
+ struct pm_px *pxpt = &px_statistic_data[cpuid];
+
+ count = processor_pminfo[cpuid].perf.state_count;
+
+ for (i=0; i < count; i++) {
+ pxpt->u.pt[i].residency = 0;
+ pxpt->u.pt[i].count = 0;
+
+ for (j=0; j < count; j++)
+ *(pxpt->u.trans_pt + i*count + j) = 0;
+ }
+
+ pxpt->prev_state_wall = NOW();
+}
+
+
+/*********************************************************************
* FREQUENCY TABLE HELPERS *
*********************************************************************/
diff -r f65906f262f9 -r d0817f08599a xen/arch/x86/acpi/pmstat.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/acpi/pmstat.c Fri May 16 09:37:19 2008 +0100
@@ -0,0 +1,110 @@
+/*****************************************************************************
+# pmstat.c - Power Management statistic information (Px/Cx/Tx, etc.)
+#
+# Copyright (c) 2008, Liu Jinsong <jinsong.liu@xxxxxxxxx>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The full GNU General Public License is included in this distribution in the
+# file called LICENSE.
+#
+*****************************************************************************/
+
+#include <xen/config.h>
+#include <xen/lib.h>
+#include <xen/errno.h>
+#include <xen/sched.h>
+#include <xen/event.h>
+#include <xen/irq.h>
+#include <xen/iocap.h>
+#include <xen/compat.h>
+#include <xen/guest_access.h>
+#include <asm/current.h>
+#include <public/xen.h>
+#include <xen/cpumask.h>
+#include <asm/processor.h>
+#include <xen/percpu.h>
+
+#include <public/sysctl.h>
+#include <acpi/cpufreq/cpufreq.h>
+
+struct pm_px px_statistic_data[NR_CPUS];
+
+int do_get_pm_info(struct xen_sysctl_get_pmstat *op)
+{
+ int ret = 0;
+ struct pm_px *pxpt = &px_statistic_data[op->cpuid];
+ struct processor_pminfo *pmpt = &processor_pminfo[op->cpuid];
+
+ /* to protect the case when Px was controlled by dom0-kernel */
+ /* or when CPU_FREQ not set in which case ACPI Px objects not parsed */
+ if ( !pmpt->perf.init )
+ return -EINVAL;
+
+ if ( !cpu_online(op->cpuid) )
+ return -EINVAL;
+
+ switch( op->type )
+ {
+ case PMSTAT_get_max_px:
+ {
+ op->u.getpx.total = pmpt->perf.state_count;
+ break;
+ }
+
+ case PMSTAT_get_pxstat:
+ {
+ uint64_t now, ct;
+
+ now = NOW();
+ pxpt->u.usable = pmpt->perf.state_count - pmpt->perf.ppc;
+ pxpt->u.pt[pxpt->u.cur].residency += now - pxpt->prev_state_wall;
+ pxpt->prev_state_wall = now;
+
+ ct = pmpt->perf.state_count;
+ if ( copy_to_guest(op->u.getpx.trans_pt, pxpt->u.trans_pt, ct*ct) )
+ {
+ ret = -EFAULT;
+ break;
+ }
+
+ if ( copy_to_guest(op->u.getpx.pt, pxpt->u.pt, ct) )
+ {
+ ret = -EFAULT;
+ break;
+ }
+
+ op->u.getpx.total = pxpt->u.total;
+ op->u.getpx.usable = pxpt->u.usable;
+ op->u.getpx.last = pxpt->u.last;
+ op->u.getpx.cur = pxpt->u.cur;
+
+ break;
+ }
+
+ case PMSTAT_reset_pxstat:
+ {
+ px_statistic_reset(op->cpuid);
+ break;
+ }
+
+ default:
+ printk("not defined sub-hypercall @ do_get_pm_info\n");
+ ret = -ENOSYS;
+ break;
+ }
+
+ return ret;
+}
diff -r f65906f262f9 -r d0817f08599a xen/arch/x86/platform_hypercall.c
--- a/xen/arch/x86/platform_hypercall.c Fri May 16 09:31:03 2008 +0100
+++ b/xen/arch/x86/platform_hypercall.c Fri May 16 09:37:19 2008 +0100
@@ -403,7 +403,10 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe
if ( xenpxpt->flags == ( XEN_PX_PCT | XEN_PX_PSS |
XEN_PX_PSD | XEN_PX_PPC ) )
+ {
+ pxpt->init =1;
cpu_count++;
+ }
if ( cpu_count == num_online_cpus() )
ret = acpi_cpufreq_init();
break;
diff -r f65906f262f9 -r d0817f08599a xen/common/sysctl.c
--- a/xen/common/sysctl.c Fri May 16 09:31:03 2008 +0100
+++ b/xen/common/sysctl.c Fri May 16 09:37:19 2008 +0100
@@ -25,6 +25,8 @@
#include <xen/nodemask.h>
#include <xsm/xsm.h>
+extern int do_get_pm_info(struct xen_sysctl_get_pmstat *op);
+
extern long arch_do_sysctl(
struct xen_sysctl *op, XEN_GUEST_HANDLE(xen_sysctl_t) u_sysctl);
@@ -193,6 +195,20 @@ long do_sysctl(XEN_GUEST_HANDLE(xen_sysc
op->u.availheap.avail_bytes <<= PAGE_SHIFT;
ret = copy_to_guest(u_sysctl, op, 1) ? -EFAULT : 0;
+ }
+ break;
+
+ case XEN_SYSCTL_get_pmstat:
+ {
+ ret = do_get_pm_info(&op->u.get_pmstat);
+ if ( ret )
+ break;
+
+ if ( copy_to_guest(u_sysctl, op, 1) )
+ {
+ ret = -EFAULT;
+ break;
+ }
}
break;
diff -r f65906f262f9 -r d0817f08599a xen/include/acpi/cpufreq/processor_perf.h
--- a/xen/include/acpi/cpufreq/processor_perf.h Fri May 16 09:31:03 2008 +0100
+++ b/xen/include/acpi/cpufreq/processor_perf.h Fri May 16 09:37:19 2008 +0100
@@ -2,9 +2,13 @@
#define __XEN_PROCESSOR_PM_H__
#include <public/platform.h>
+#include <public/sysctl.h>
int get_cpu_id(u8);
int acpi_cpufreq_init(void);
+void px_statistic_update(cpumask_t, uint8_t, uint8_t);
+int px_statistic_init(int);
+void px_statistic_reset(int);
struct processor_performance {
uint32_t state;
@@ -16,15 +20,32 @@ struct processor_performance {
struct xen_psd_package domain_info;
cpumask_t shared_cpu_map;
uint32_t shared_type;
+
+ uint32_t init;
};
struct processor_pminfo {
uint32_t acpi_id;
uint32_t id;
- uint32_t flag;
struct processor_performance perf;
};
extern struct processor_pminfo processor_pminfo[NR_CPUS];
+struct px_stat {
+ uint8_t total; /* total Px states */
+ uint8_t usable; /* usable Px states */
+ uint8_t last; /* last Px state */
+ uint8_t cur; /* current Px state */
+ uint64_t *trans_pt; /* Px transition table */
+ pm_px_val_t *pt;
+};
+
+struct pm_px {
+ struct px_stat u;
+ uint64_t prev_state_wall;
+};
+
+extern struct pm_px px_statistic_data[NR_CPUS];
+
#endif /* __XEN_PROCESSOR_PM_H__ */
diff -r f65906f262f9 -r d0817f08599a xen/include/public/sysctl.h
--- a/xen/include/public/sysctl.h Fri May 16 09:31:03 2008 +0100
+++ b/xen/include/public/sysctl.h Fri May 16 09:37:19 2008 +0100
@@ -212,7 +212,41 @@ struct xen_sysctl_availheap {
};
typedef struct xen_sysctl_availheap xen_sysctl_availheap_t;
DEFINE_XEN_GUEST_HANDLE(xen_sysctl_availheap_t);
-
+
+#define XEN_SYSCTL_get_pmstat 10
+struct pm_px_val {
+ uint64_aligned_t freq; /* Px core frequency */
+ uint64_aligned_t residency; /* Px residency time */
+ uint64_aligned_t count; /* Px transition count */
+};
+typedef struct pm_px_val pm_px_val_t;
+DEFINE_XEN_GUEST_HANDLE(pm_px_val_t);
+
+struct pm_px_stat {
+ uint8_t total; /* total Px states */
+ uint8_t usable; /* usable Px states */
+ uint8_t last; /* last Px state */
+ uint8_t cur; /* current Px state */
+ XEN_GUEST_HANDLE_64(uint64) trans_pt; /* Px transition table */
+ XEN_GUEST_HANDLE_64(pm_px_val_t) pt;
+};
+typedef struct pm_px_stat pm_px_stat_t;
+DEFINE_XEN_GUEST_HANDLE(pm_px_stat_t);
+
+struct xen_sysctl_get_pmstat {
+#define PMSTAT_get_max_px 0x11
+#define PMSTAT_get_pxstat 0x12
+#define PMSTAT_reset_pxstat 0x13
+ uint32_t type;
+ uint32_t cpuid;
+ union {
+ struct pm_px_stat getpx;
+ /* other struct for cx, tx, etc */
+ } u;
+};
+typedef struct xen_sysctl_get_pmstat xen_sysctl_get_pmstat_t;
+DEFINE_XEN_GUEST_HANDLE(xen_sysctl_get_pmstat_t);
+
struct xen_sysctl {
uint32_t cmd;
uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */
@@ -226,6 +260,7 @@ struct xen_sysctl {
struct xen_sysctl_debug_keys debug_keys;
struct xen_sysctl_getcpuinfo getcpuinfo;
struct xen_sysctl_availheap availheap;
+ struct xen_sysctl_get_pmstat get_pmstat;
uint8_t pad[128];
} u;
};
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|