int xc_pm_get_cxstat(xc_interface *xch, int cpuid, struct xc_cx_stat *cxpt)
{
DECLARE_SYSCTL;
- DECLARE_NAMED_HYPERCALL_BOUNCE(triggers, cxpt->triggers, 0, XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
- DECLARE_NAMED_HYPERCALL_BOUNCE(residencies, cxpt->residencies, 0, XC_HYPERCALL_BUFFER_BOUNCE_BOTH);
- int max_cx, ret;
+ DECLARE_NAMED_HYPERCALL_BOUNCE(triggers, cxpt->triggers,
+ cxpt->nr * sizeof(*cxpt->triggers),
+ XC_HYPERCALL_BUFFER_BOUNCE_OUT);
+ DECLARE_NAMED_HYPERCALL_BOUNCE(residencies, cxpt->residencies,
+ cxpt->nr * sizeof(*cxpt->residencies),
+ XC_HYPERCALL_BUFFER_BOUNCE_OUT);
+ DECLARE_NAMED_HYPERCALL_BOUNCE(pc, cxpt->pc,
+ cxpt->nr_pc * sizeof(*cxpt->pc),
+ XC_HYPERCALL_BUFFER_BOUNCE_OUT);
+ DECLARE_NAMED_HYPERCALL_BOUNCE(cc, cxpt->cc,
+ cxpt->nr_cc * sizeof(*cxpt->cc),
+ XC_HYPERCALL_BUFFER_BOUNCE_OUT);
+ int ret = -1;
- if( !cxpt->triggers || !cxpt->residencies )
- return -EINVAL;
-
- if ( (ret = xc_pm_get_max_cx(xch, cpuid, &max_cx)) )
- goto unlock_0;
-
- HYPERCALL_BOUNCE_SET_SIZE(triggers, max_cx * sizeof(uint64_t));
- HYPERCALL_BOUNCE_SET_SIZE(residencies, max_cx * sizeof(uint64_t));
-
- ret = -1;
if ( xc_hypercall_bounce_pre(xch, triggers) )
goto unlock_0;
if ( xc_hypercall_bounce_pre(xch, residencies) )
goto unlock_1;
+ if ( xc_hypercall_bounce_pre(xch, pc) )
+ goto unlock_2;
+ if ( xc_hypercall_bounce_pre(xch, cc) )
+ goto unlock_3;
sysctl.cmd = XEN_SYSCTL_get_pmstat;
sysctl.u.get_pmstat.type = PMSTAT_get_cxstat;
sysctl.u.get_pmstat.cpuid = cpuid;
+ sysctl.u.get_pmstat.u.getcx.nr = cxpt->nr;
+ sysctl.u.get_pmstat.u.getcx.nr_pc = cxpt->nr_pc;
+ sysctl.u.get_pmstat.u.getcx.nr_cc = cxpt->nr_cc;
set_xen_guest_handle(sysctl.u.get_pmstat.u.getcx.triggers, triggers);
set_xen_guest_handle(sysctl.u.get_pmstat.u.getcx.residencies, residencies);
+ set_xen_guest_handle(sysctl.u.get_pmstat.u.getcx.pc, pc);
+ set_xen_guest_handle(sysctl.u.get_pmstat.u.getcx.cc, cc);
if ( (ret = xc_sysctl(xch, &sysctl)) )
- goto unlock_2;
+ goto unlock_4;
cxpt->nr = sysctl.u.get_pmstat.u.getcx.nr;
cxpt->last = sysctl.u.get_pmstat.u.getcx.last;
cxpt->idle_time = sysctl.u.get_pmstat.u.getcx.idle_time;
- cxpt->pc2 = sysctl.u.get_pmstat.u.getcx.pc2;
- cxpt->pc3 = sysctl.u.get_pmstat.u.getcx.pc3;
- cxpt->pc6 = sysctl.u.get_pmstat.u.getcx.pc6;
- cxpt->pc7 = sysctl.u.get_pmstat.u.getcx.pc7;
- cxpt->cc3 = sysctl.u.get_pmstat.u.getcx.cc3;
- cxpt->cc6 = sysctl.u.get_pmstat.u.getcx.cc6;
- cxpt->cc7 = sysctl.u.get_pmstat.u.getcx.cc7;
+ cxpt->nr_pc = sysctl.u.get_pmstat.u.getcx.nr_pc;
+ cxpt->nr_cc = sysctl.u.get_pmstat.u.getcx.nr_cc;
+unlock_4:
+ xc_hypercall_bounce_post(xch, cc);
+unlock_3:
+ xc_hypercall_bounce_post(xch, pc);
unlock_2:
xc_hypercall_bounce_post(xch, residencies);
unlock_1:
int xc_pm_reset_pxstat(xc_interface *xch, int cpuid);
struct xc_cx_stat {
- uint32_t nr; /* entry nr in triggers & residencies, including C0 */
+ uint32_t nr; /* entry nr in triggers[]/residencies[], incl C0 */
uint32_t last; /* last Cx state */
uint64_t idle_time; /* idle time from boot */
uint64_t *triggers; /* Cx trigger counts */
uint64_t *residencies; /* Cx residencies */
- uint64_t pc2;
- uint64_t pc3;
- uint64_t pc6;
- uint64_t pc7;
- uint64_t cc3;
- uint64_t cc6;
- uint64_t cc7;
+ uint32_t nr_pc; /* entry nr in pc[] */
+ uint32_t nr_cc; /* entry nr in cc[] */
+ uint64_t *pc; /* 1-biased indexing (i.e. excl C0) */
+ uint64_t *cc; /* 1-biased indexing (i.e. excl C0) */
};
typedef struct xc_cx_stat xc_cx_stat_t;
#include <inttypes.h>
#include <sys/time.h>
+#define MAX_PKG_RESIDENCIES 12
+#define MAX_CORE_RESIDENCIES 8
+
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
static xc_interface *xc_handle;
static void print_cxstat(int cpuid, struct xc_cx_stat *cxstat)
{
- int i;
+ unsigned int i;
printf("cpu id : %d\n", cpuid);
printf("total C-states : %d\n", cxstat->nr);
printf(" residency [%20"PRIu64" ms]\n",
cxstat->residencies[i]/1000000UL);
}
- printf("pc2 : [%20"PRIu64" ms]\n"
- "pc3 : [%20"PRIu64" ms]\n"
- "pc6 : [%20"PRIu64" ms]\n"
- "pc7 : [%20"PRIu64" ms]\n",
- cxstat->pc2/1000000UL, cxstat->pc3/1000000UL,
- cxstat->pc6/1000000UL, cxstat->pc7/1000000UL);
- printf("cc3 : [%20"PRIu64" ms]\n"
- "cc6 : [%20"PRIu64" ms]\n"
- "cc7 : [%20"PRIu64" ms]\n",
- cxstat->cc3/1000000UL, cxstat->cc6/1000000UL,
- cxstat->cc7/1000000UL);
+ for ( i = 0; i < MAX_PKG_RESIDENCIES && i < cxstat->nr_pc; ++i )
+ if ( cxstat->pc[i] )
+ printf("pc%d : [%20"PRIu64" ms]\n", i + 1,
+ cxstat->pc[i] / 1000000UL);
+ for ( i = 0; i < MAX_CORE_RESIDENCIES && i < cxstat->nr_cc; ++i )
+ if ( cxstat->cc[i] )
+ printf("cc%d : [%20"PRIu64" ms]\n", i + 1,
+ cxstat->cc[i] / 1000000UL);
printf("\n");
}
if ( !max_cx_num )
return -ENODEV;
- cxstat->triggers = malloc(max_cx_num * sizeof(uint64_t));
- if ( !cxstat->triggers )
- return -ENOMEM;
- cxstat->residencies = malloc(max_cx_num * sizeof(uint64_t));
- if ( !cxstat->residencies )
+ cxstat->triggers = calloc(max_cx_num, sizeof(*cxstat->triggers));
+ cxstat->residencies = calloc(max_cx_num, sizeof(*cxstat->residencies));
+ cxstat->pc = calloc(MAX_PKG_RESIDENCIES, sizeof(*cxstat->pc));
+ cxstat->cc = calloc(MAX_CORE_RESIDENCIES, sizeof(*cxstat->cc));
+ if ( !cxstat->triggers || !cxstat->residencies ||
+ !cxstat->pc || !cxstat->cc )
{
+ free(cxstat->cc);
+ free(cxstat->pc);
+ free(cxstat->residencies);
free(cxstat->triggers);
return -ENOMEM;
}
+ cxstat->nr = max_cx_num;
+ cxstat->nr_pc = MAX_PKG_RESIDENCIES;
+ cxstat->nr_cc = MAX_CORE_RESIDENCIES;
+
ret = xc_pm_get_cxstat(xc_handle, cpuid, cxstat);
if( ret )
{
ret = -errno;
free(cxstat->triggers);
free(cxstat->residencies);
+ free(cxstat->pc);
+ free(cxstat->cc);
cxstat->triggers = NULL;
cxstat->residencies = NULL;
+ cxstat->pc = NULL;
+ cxstat->cc = NULL;
}
return ret;
free(cxstatinfo.triggers);
free(cxstatinfo.residencies);
+ free(cxstatinfo.pc);
+ free(cxstatinfo.cc);
return 0;
}
/* print out CC? and PC? */
for ( i = 0; i < socket_nr; i++ )
{
+ unsigned int n;
uint64_t res;
+
for ( j = 0; j <= info.max_cpu_index; j++ )
{
if ( cpu_to_socket[j] == socket_ids[i] )
break;
}
printf("\nSocket %d\n", socket_ids[i]);
- res = cxstat_end[j].pc2 - cxstat_start[j].pc2;
- printf("\tPC2\t%"PRIu64" ms\t%.2f%%\n", res / 1000000UL,
- 100UL * res / (double)sum_cx[j]);
- res = cxstat_end[j].pc3 - cxstat_start[j].pc3;
- printf("\tPC3\t%"PRIu64" ms\t%.2f%%\n", res / 1000000UL,
- 100UL * res / (double)sum_cx[j]);
- res = cxstat_end[j].pc6 - cxstat_start[j].pc6;
- printf("\tPC6\t%"PRIu64" ms\t%.2f%%\n", res / 1000000UL,
- 100UL * res / (double)sum_cx[j]);
- res = cxstat_end[j].pc7 - cxstat_start[j].pc7;
- printf("\tPC7\t%"PRIu64" ms\t%.2f%%\n", res / 1000000UL,
- 100UL * res / (double)sum_cx[j]);
+ for ( n = 0; n < MAX_PKG_RESIDENCIES; ++n )
+ {
+ if ( n >= cxstat_end[j].nr_pc )
+ continue;
+ res = cxstat_end[j].pc[n];
+ if ( n < cxstat_start[j].nr_pc )
+ res -= cxstat_start[j].pc[n];
+ printf("\tPC%u\t%"PRIu64" ms\t%.2f%%\n",
+ n + 1, res / 1000000UL,
+ 100UL * res / (double)sum_cx[j]);
+ }
for ( k = 0; k < core_nr; k++ )
{
for ( j = 0; j <= info.max_cpu_index; j++ )
break;
}
printf("\t Core %d CPU %d\n", core_ids[k], j);
- res = cxstat_end[j].cc3 - cxstat_start[j].cc3;
- printf("\t\tCC3\t%"PRIu64" ms\t%.2f%%\n", res / 1000000UL,
- 100UL * res / (double)sum_cx[j]);
- res = cxstat_end[j].cc6 - cxstat_start[j].cc6;
- printf("\t\tCC6\t%"PRIu64" ms\t%.2f%%\n", res / 1000000UL,
- 100UL * res / (double)sum_cx[j]);
- res = cxstat_end[j].cc7 - cxstat_start[j].cc7;
- printf("\t\tCC7\t%"PRIu64" ms\t%.2f%%\n", res / 1000000UL,
- 100UL * res / (double)sum_cx[j]);
+ for ( n = 0; n < MAX_CORE_RESIDENCIES; ++n )
+ {
+ if ( n >= cxstat_end[j].nr_cc )
+ continue;
+ res = cxstat_end[j].cc[n];
+ if ( n < cxstat_start[j].nr_cc )
+ res -= cxstat_start[j].cc[n];
+ printf("\t\tCC%u\t%"PRIu64" ms\t%.2f%%\n",
+ n + 1, res / 1000000UL,
+ 100UL * res / (double)sum_cx[j]);
+ }
}
}
}
{
free(cxstat[i].triggers);
free(cxstat[i].residencies);
+ free(cxstat[i].pc);
+ free(cxstat[i].cc);
free(pxstat[i].trans_pt);
free(pxstat[i].pt);
}
#define GET_HW_RES_IN_NS(msr, val) \
do { rdmsrl(msr, val); val = tsc_ticks2ns(val); } while( 0 )
-#define GET_PC2_RES(val) GET_HW_RES_IN_NS(0x60D, val) /* SNB only */
+#define GET_PC2_RES(val) GET_HW_RES_IN_NS(0x60D, val) /* SNB onwards */
#define GET_PC3_RES(val) GET_HW_RES_IN_NS(0x3F8, val)
#define GET_PC6_RES(val) GET_HW_RES_IN_NS(0x3F9, val)
#define GET_PC7_RES(val) GET_HW_RES_IN_NS(0x3FA, val)
+#define GET_PC8_RES(val) GET_HW_RES_IN_NS(0x630, val) /* some Haswells only */
+#define GET_PC9_RES(val) GET_HW_RES_IN_NS(0x631, val) /* some Haswells only */
+#define GET_PC10_RES(val) GET_HW_RES_IN_NS(0x632, val) /* some Haswells only */
+#define GET_CC1_RES(val) GET_HW_RES_IN_NS(0x660, val) /* Silvermont only */
#define GET_CC3_RES(val) GET_HW_RES_IN_NS(0x3FC, val)
#define GET_CC6_RES(val) GET_HW_RES_IN_NS(0x3FD, val)
-#define GET_CC7_RES(val) GET_HW_RES_IN_NS(0x3FE, val) /* SNB only */
+#define GET_CC7_RES(val) GET_HW_RES_IN_NS(0x3FE, val) /* SNB onwards */
static void lapic_timer_nop(void) { }
void (*__read_mostly lapic_timer_off)(void);
{
uint64_t pc2;
uint64_t pc3;
+ uint64_t pc4;
uint64_t pc6;
uint64_t pc7;
+ uint64_t pc8;
+ uint64_t pc9;
+ uint64_t pc10;
+ uint64_t cc1;
uint64_t cc3;
uint64_t cc6;
uint64_t cc7;
switch ( c->x86_model )
{
+ /* 4th generation Intel Core (Haswell) */
+ case 0x45:
+ GET_PC8_RES(hw_res->pc8);
+ GET_PC9_RES(hw_res->pc9);
+ GET_PC10_RES(hw_res->pc10);
+ /* fall through */
/* Sandy bridge */
case 0x2A:
case 0x2D:
/* Haswell */
case 0x3C:
case 0x3F:
- case 0x45:
case 0x46:
/* future */
case 0x3D:
GET_CC3_RES(hw_res->cc3);
GET_CC6_RES(hw_res->cc6);
break;
+ /* various Atoms */
+ case 0x27:
+ GET_PC3_RES(hw_res->pc2); /* abusing GET_PC3_RES */
+ GET_PC6_RES(hw_res->pc4); /* abusing GET_PC6_RES */
+ GET_PC7_RES(hw_res->pc6); /* abusing GET_PC7_RES */
+ break;
+ /* Silvermont */
+ case 0x37:
+ case 0x4A:
+ case 0x4D:
+ case 0x5A:
+ case 0x5D:
+ GET_PC7_RES(hw_res->pc6); /* abusing GET_PC7_RES */
+ GET_CC1_RES(hw_res->cc1);
+ GET_CC6_RES(hw_res->cc6);
+ break;
}
}
get_hw_residencies(cpu, &hw_res);
- printk("PC2[%"PRId64"] PC3[%"PRId64"] PC6[%"PRId64"] PC7[%"PRId64"]\n",
- hw_res.pc2, hw_res.pc3, hw_res.pc6, hw_res.pc7);
- printk("CC3[%"PRId64"] CC6[%"PRId64"] CC7[%"PRId64"]\n",
- hw_res.cc3, hw_res.cc6,hw_res.cc7);
+ printk("PC2[%"PRIu64"] PC%d[%"PRIu64"] PC6[%"PRIu64"] PC7[%"PRIu64"]\n",
+ hw_res.pc2,
+ hw_res.pc4 ? 4 : 3, hw_res.pc4 ?: hw_res.pc3,
+ hw_res.pc6, hw_res.pc7);
+ if ( hw_res.pc8 | hw_res.pc9 | hw_res.pc10 )
+ printk("PC8[%"PRIu64"] PC9[%"PRIu64"] PC10[%"PRIu64"]\n",
+ hw_res.pc8, hw_res.pc9, hw_res.pc10);
+ printk("CC%d[%"PRIu64"] CC6[%"PRIu64"] CC7[%"PRIu64"]\n",
+ hw_res.cc1 ? 1 : 3, hw_res.cc1 ?: hw_res.cc3,
+ hw_res.cc6, hw_res.cc7);
}
static char* acpi_cstate_method_name[] =
struct acpi_processor_power *power = processor_powers[cpuid];
uint64_t idle_usage = 0, idle_res = 0;
uint64_t usage[ACPI_PROCESSOR_MAX_POWER], res[ACPI_PROCESSOR_MAX_POWER];
- int i;
- struct hw_residencies hw_res;
+ unsigned int i, nr, nr_pc = 0, nr_cc = 0;
if ( power == NULL )
{
stat->last = 0;
stat->nr = 0;
stat->idle_time = 0;
+ stat->nr_pc = 0;
+ stat->nr_cc = 0;
return 0;
}
stat->last = power->last_state ? power->last_state->idx : 0;
stat->idle_time = get_cpu_idle_time(cpuid);
+ nr = min(stat->nr, power->count);
/* mimic the stat when detail info hasn't been registered by dom0 */
if ( pm_idle_save == NULL )
usage[1] = idle_usage = 1;
res[1] = idle_res = stat->idle_time;
-
- memset(&hw_res, 0, sizeof(hw_res));
}
else
{
+ struct hw_residencies hw_res;
+
stat->nr = power->count;
- for ( i = 1; i < power->count; i++ )
+ for ( i = 1; i < nr; i++ )
{
spin_lock_irq(&power->stat_lock);
usage[i] = power->states[i].usage;
}
get_hw_residencies(cpuid, &hw_res);
+
+#define PUT_xC(what, n) do { \
+ if ( stat->nr_##what >= n && \
+ copy_to_guest_offset(stat->what, n - 1, &hw_res.what##n, 1) ) \
+ return -EFAULT; \
+ if ( hw_res.what##n ) \
+ nr_##what = n; \
+ } while ( 0 )
+#define PUT_PC(n) PUT_xC(pc, n)
+ PUT_PC(2);
+ PUT_PC(3);
+ PUT_PC(4);
+ PUT_PC(6);
+ PUT_PC(7);
+ PUT_PC(8);
+ PUT_PC(9);
+ PUT_PC(10);
+#undef PUT_PC
+#define PUT_CC(n) PUT_xC(cc, n)
+ PUT_CC(1);
+ PUT_CC(3);
+ PUT_CC(6);
+ PUT_CC(7);
+#undef PUT_CC
+#undef PUT_xC
}
usage[0] = idle_usage;
res[0] = NOW() - idle_res;
- if ( copy_to_guest(stat->triggers, usage, stat->nr) ||
- copy_to_guest(stat->residencies, res, stat->nr) )
+ if ( copy_to_guest(stat->triggers, usage, nr) ||
+ copy_to_guest(stat->residencies, res, nr) )
return -EFAULT;
- stat->pc2 = hw_res.pc2;
- stat->pc3 = hw_res.pc3;
- stat->pc6 = hw_res.pc6;
- stat->pc7 = hw_res.pc7;
- stat->cc3 = hw_res.cc3;
- stat->cc6 = hw_res.cc6;
- stat->cc7 = hw_res.cc7;
+ stat->nr_pc = nr_pc;
+ stat->nr_cc = nr_cc;
return 0;
}
#include "xen.h"
#include "domctl.h"
-#define XEN_SYSCTL_INTERFACE_VERSION 0x0000000A
+#define XEN_SYSCTL_INTERFACE_VERSION 0x0000000B
/*
* Read console content from Xen buffer ring.
uint64_aligned_t idle_time; /* idle time from boot */
XEN_GUEST_HANDLE_64(uint64) triggers; /* Cx trigger counts */
XEN_GUEST_HANDLE_64(uint64) residencies; /* Cx residencies */
- uint64_aligned_t pc2;
- uint64_aligned_t pc3;
- uint64_aligned_t pc6;
- uint64_aligned_t pc7;
- uint64_aligned_t cc3;
- uint64_aligned_t cc6;
- uint64_aligned_t cc7;
+ uint32_t nr_pc; /* entry nr in pc[] */
+ uint32_t nr_cc; /* entry nr in cc[] */
+ XEN_GUEST_HANDLE_64(uint64) pc; /* 1-biased indexing */
+ XEN_GUEST_HANDLE_64(uint64) cc; /* 1-biased indexing */
};
struct xen_sysctl_get_pmstat {