summaryrefslogtreecommitdiff
path: root/usr/src/uts/common
diff options
context:
space:
mode:
authorAlexander Kolbasov <Alexander.Kolbasov@Sun.COM>2010-08-16 15:39:49 -0700
committerAlexander Kolbasov <Alexander.Kolbasov@Sun.COM>2010-08-16 15:39:49 -0700
commitd3c9722485327eb5b96de2f2108e9a84bd46096d (patch)
tree7d7fa19f106497a72f0335ecd0fdfd22904a67f1 /usr/src/uts/common
parent1eee170a5f6cf875d905524fea524c7c5c870aa0 (diff)
downloadillumos-gate-d3c9722485327eb5b96de2f2108e9a84bd46096d.tar.gz
PSARC 2010/309 Processor Group (PG) Kstats and Tools
6923529 Provide command for printing PG utilization 6764835 Provide command for printing processor group information 6973973 Lonely Cache PG is created on M3000
Diffstat (limited to 'usr/src/uts/common')
-rw-r--r--usr/src/uts/common/disp/cmt.c10
-rw-r--r--usr/src/uts/common/os/cap_util.c68
-rw-r--r--usr/src/uts/common/os/pghw.c145
-rw-r--r--usr/src/uts/common/sys/pg.h6
-rw-r--r--usr/src/uts/common/sys/pghw.h5
5 files changed, 156 insertions, 78 deletions
diff --git a/usr/src/uts/common/disp/cmt.c b/usr/src/uts/common/disp/cmt.c
index a5f1a52e34..3aa3b67e29 100644
--- a/usr/src/uts/common/disp/cmt.c
+++ b/usr/src/uts/common/disp/cmt.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <sys/systm.h>
@@ -256,7 +255,7 @@ pg_cmt_policy(pghw_type_t hw)
case PGHW_CHIP:
return (CMT_BALANCE);
case PGHW_CACHE:
- return (CMT_AFFINITY);
+ return (CMT_AFFINITY | CMT_BALANCE);
case PGHW_POW_ACTIVE:
case PGHW_POW_IDLE:
return (CMT_BALANCE);
@@ -1470,6 +1469,11 @@ pg_cmt_prune(pg_cmt_t *pg_bad, pg_cmt_t **lineage, int *sz, cpu_pg_t *pgdata)
ASSERT(MUTEX_HELD(&cpu_lock));
+ /*
+ * Inform pghw layer that this PG is pruned.
+ */
+ pghw_cmt_fini((pghw_t *)pg_bad);
+
hw = ((pghw_t *)pg_bad)->pghw_hw;
if (hw == PGHW_POW_ACTIVE) {
diff --git a/usr/src/uts/common/os/cap_util.c b/usr/src/uts/common/os/cap_util.c
index 16ff7f45fd..8eca9bf0a6 100644
--- a/usr/src/uts/common/os/cap_util.c
+++ b/usr/src/uts/common/os/cap_util.c
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -111,12 +110,14 @@
#include <sys/cmn_err.h>
#include <sys/cpuvar.h>
#include <sys/ddi.h>
+#include <sys/systm.h>
#include <sys/disp.h>
#include <sys/sdt.h>
#include <sys/sunddi.h>
#include <sys/thread.h>
#include <sys/pghw.h>
#include <sys/cmt.h>
+#include <sys/policy.h>
#include <sys/x_call.h>
#include <sys/cap_util.h>
@@ -226,6 +227,8 @@ static kcpc_request_list_t *cu_cpc_reqs = NULL;
*
* cu_cpu_id CPU ID for this kstat
*
+ * cu_pg_id PG ID for this kstat
+ *
* cu_generation Generation value that increases whenever any CPU goes
* offline or online. Two kstat snapshots for the same
* CPU may only be compared if they have the same
@@ -245,25 +248,29 @@ static kcpc_request_list_t *cu_cpc_reqs = NULL;
* cu_cpu_rate Utilization rate, expressed in operations per second.
*
* cu_cpu_rate_max Maximum observed value of utilization rate.
+ *
+ * cu_cpu_relationship Name of sharing relationship for the PG in this kstat
*/
struct cu_cpu_kstat {
kstat_named_t cu_cpu_id;
- kstat_named_t cu_generation;
kstat_named_t cu_pg_id;
+ kstat_named_t cu_generation;
kstat_named_t cu_cpu_util;
kstat_named_t cu_cpu_time_running;
kstat_named_t cu_cpu_time_stopped;
kstat_named_t cu_cpu_rate;
kstat_named_t cu_cpu_rate_max;
+ kstat_named_t cu_cpu_relationship;
} cu_cpu_kstat = {
- { "id", KSTAT_DATA_UINT32 },
+ { "cpu_id", KSTAT_DATA_UINT32 },
+ { "pg_id", KSTAT_DATA_INT32 },
{ "generation", KSTAT_DATA_UINT32 },
- { "pg_id", KSTAT_DATA_LONG },
{ "hw_util", KSTAT_DATA_UINT64 },
{ "hw_util_time_running", KSTAT_DATA_UINT64 },
{ "hw_util_time_stopped", KSTAT_DATA_UINT64 },
{ "hw_util_rate", KSTAT_DATA_UINT64 },
{ "hw_util_rate_max", KSTAT_DATA_UINT64 },
+ { "relationship", KSTAT_DATA_STRING },
};
/*
@@ -1289,8 +1296,9 @@ cu_cpu_fini(cpu_t *cp)
static void
cu_cpu_kstat_create(pghw_t *pg, cu_cntr_info_t *cntr_info)
{
- char *class, *sh_name;
kstat_t *ks;
+ char *sharing = pghw_type_string(pg->pghw_hw);
+ char name[KSTAT_STRLEN + 1];
/*
* Just return when no counter info or CPU
@@ -1299,14 +1307,14 @@ cu_cpu_kstat_create(pghw_t *pg, cu_cntr_info_t *cntr_info)
return;
/*
- * Get the class name from the leaf PG that this CPU belongs to.
- * If there are no PGs, just use the default class "cpu".
+ * Canonify PG name to conform to kstat name rules
*/
- class = pg ? pghw_type_string(pg->pghw_hw) : "cpu";
- sh_name = pg ? pghw_type_shortstring(pg->pghw_hw) : "cpu";
+ (void) strncpy(name, pghw_type_string(pg->pghw_hw), KSTAT_STRLEN + 1);
+ strident_canon(name, TASKQ_NAMELEN + 1);
- if ((ks = kstat_create_zone("pg_cpu", cntr_info->ci_cpu->cpu_id,
- sh_name, class, KSTAT_TYPE_NAMED,
+ if ((ks = kstat_create_zone("pg_hw_perf_cpu",
+ cntr_info->ci_cpu->cpu_id,
+ name, "processor_group", KSTAT_TYPE_NAMED,
sizeof (cu_cpu_kstat) / sizeof (kstat_named_t),
KSTAT_FLAG_VIRTUAL, GLOBAL_ZONEID)) == NULL)
return;
@@ -1314,6 +1322,7 @@ cu_cpu_kstat_create(pghw_t *pg, cu_cntr_info_t *cntr_info)
ks->ks_lock = &pg_cpu_kstat_lock;
ks->ks_data = &cu_cpu_kstat;
ks->ks_update = cu_cpu_kstat_update;
+ ks->ks_data_size += strlen(sharing) + 1;
ks->ks_private = cntr_info;
cntr_info->ci_kstat = ks;
@@ -1336,29 +1345,50 @@ cu_cpu_kstat_update(kstat_t *ksp, int rw)
if (rw == KSTAT_WRITE)
return (EACCES);
+ cp = cntr_info->ci_cpu;
+ pg = cntr_info->ci_pg;
+ kstat->cu_cpu_id.value.ui32 = cp->cpu_id;
+ kstat->cu_pg_id.value.i32 = ((pg_t *)pg)->pg_id;
+
+ /*
+ * The caller should have priv_cpc_cpu privilege to get utilization
+ * data. Callers who do not have the privilege will see zeroes as the
+ * values.
+ */
+ if (secpolicy_cpc_cpu(crgetcred()) != 0) {
+ kstat->cu_generation.value.ui32 = cp->cpu_generation;
+ kstat_named_setstr(&kstat->cu_cpu_relationship,
+ pghw_type_string(pg->pghw_hw));
+
+ kstat->cu_cpu_util.value.ui64 = 0;
+ kstat->cu_cpu_rate.value.ui64 = 0;
+ kstat->cu_cpu_rate_max.value.ui64 = 0;
+ kstat->cu_cpu_time_running.value.ui64 = 0;
+ kstat->cu_cpu_time_stopped.value.ui64 = 0;
+
+ return (0);
+ }
+
kpreempt_disable();
/*
* Update capacity and utilization statistics needed for CPU's PG (CPU)
* kstats
*/
- cp = cntr_info->ci_cpu;
+
(void) cu_cpu_update(cp, B_TRUE);
- pg = cntr_info->ci_pg;
stats = cntr_info->ci_stats;
- kstat->cu_cpu_id.value.ui32 = cp->cpu_id;
kstat->cu_generation.value.ui32 = cp->cpu_generation;
- if (pg == NULL)
- kstat->cu_pg_id.value.l = -1;
- else
- kstat->cu_pg_id.value.l = pg->pghw_pg.pg_id;
+ kstat_named_setstr(&kstat->cu_cpu_relationship,
+ pghw_type_string(pg->pghw_hw));
kstat->cu_cpu_util.value.ui64 = stats->cs_value_total;
kstat->cu_cpu_rate.value.ui64 = stats->cs_rate;
kstat->cu_cpu_rate_max.value.ui64 = stats->cs_rate_max;
kstat->cu_cpu_time_running.value.ui64 = stats->cs_time_running;
kstat->cu_cpu_time_stopped.value.ui64 = stats->cs_time_stopped;
+
/*
* Counters are stopped now, so the cs_time_stopped was last
* updated at cs_time_start time. Add the time passed since then
diff --git a/usr/src/uts/common/os/pghw.c b/usr/src/uts/common/os/pghw.c
index 534cb2c540..7b4b46f6ab 100644
--- a/usr/src/uts/common/os/pghw.c
+++ b/usr/src/uts/common/os/pghw.c
@@ -19,8 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <sys/systm.h>
@@ -30,6 +29,7 @@
#include <sys/cpuvar.h>
#include <sys/kmem.h>
#include <sys/cmn_err.h>
+#include <sys/policy.h>
#include <sys/group.h>
#include <sys/pg.h>
#include <sys/pghw.h>
@@ -117,7 +117,7 @@ struct pghw_kstat {
kstat_named_t pg_hw;
kstat_named_t pg_policy;
} pghw_kstat = {
- { "id", KSTAT_DATA_UINT32 },
+ { "id", KSTAT_DATA_INT32 },
{ "pg_class", KSTAT_DATA_STRING },
{ "ncpus", KSTAT_DATA_UINT32 },
{ "instance_id", KSTAT_DATA_UINT32 },
@@ -135,13 +135,15 @@ kmutex_t pghw_kstat_lock;
*
* kstat fields:
*
- * pgid PG ID for PG described by this kstat
+ * pg_id PG ID for PG described by this kstat
+ *
+ * pg_parent Parent PG ID. The value -1 means "no parent".
*
* pg_ncpus Number of CPUs within this PG
*
* pg_cpus String describing CPUs within this PG
*
- * pg_sharing Name of sharing relationship for this PG
+ * pg_relationship Name of sharing relationship for this PG
*
* pg_generation Generation value that increases whenever any CPU leaves
* or joins PG. Two kstat snapshots for the same
@@ -164,6 +166,7 @@ kmutex_t pghw_kstat_lock;
*/
struct pghw_cu_kstat {
kstat_named_t pg_id;
+ kstat_named_t pg_parent_id;
kstat_named_t pg_ncpus;
kstat_named_t pg_generation;
kstat_named_t pg_hw_util;
@@ -172,9 +175,10 @@ struct pghw_cu_kstat {
kstat_named_t pg_hw_util_rate;
kstat_named_t pg_hw_util_rate_max;
kstat_named_t pg_cpus;
- kstat_named_t pg_sharing;
+ kstat_named_t pg_relationship;
} pghw_cu_kstat = {
- { "id", KSTAT_DATA_UINT32 },
+ { "pg_id", KSTAT_DATA_INT32 },
+ { "parent_pg_id", KSTAT_DATA_INT32 },
{ "ncpus", KSTAT_DATA_UINT32 },
{ "generation", KSTAT_DATA_UINT32 },
{ "hw_util", KSTAT_DATA_UINT64 },
@@ -183,7 +187,7 @@ struct pghw_cu_kstat {
{ "hw_util_rate", KSTAT_DATA_UINT64 },
{ "hw_util_rate_max", KSTAT_DATA_UINT64 },
{ "cpus", KSTAT_DATA_STRING },
- { "sharing_relation", KSTAT_DATA_STRING },
+ { "relationship", KSTAT_DATA_STRING },
};
/*
@@ -213,6 +217,7 @@ static void pghw_set_remove(group_t *, pghw_t *);
static void pghw_cpulist_alloc(pghw_t *);
static int cpu2id(void *);
+static pgid_t pghw_parent_id(pghw_t *);
/*
* Initialize the physical portion of a hardware PG
@@ -261,6 +266,8 @@ pghw_fini(pghw_t *pg)
{
group_t *hwset;
+ pghw_cmt_fini(pg);
+
hwset = pghw_set_lookup(pg->pghw_hw);
ASSERT(hwset != NULL);
@@ -271,6 +278,14 @@ pghw_fini(pghw_t *pg)
if (pg->pghw_kstat != NULL)
kstat_delete(pg->pghw_kstat);
+}
+
+/*
+ * PG is removed from CMT hierarchy
+ */
+void
+pghw_cmt_fini(pghw_t *pg)
+{
/*
* Destroy string representation of CPUs
*/
@@ -280,8 +295,13 @@ pghw_fini(pghw_t *pg)
pg->pghw_cpulist = NULL;
}
- if (pg->pghw_cu_kstat != NULL)
+ /*
+ * Destroy CU kstats
+ */
+ if (pg->pghw_cu_kstat != NULL) {
kstat_delete(pg->pghw_cu_kstat);
+ pg->pghw_cu_kstat = NULL;
+ }
}
/*
@@ -467,34 +487,6 @@ pghw_type_string(pghw_type_t hw)
}
/*
- * Return a short string name given a pg_hw sharing type
- */
-char *
-pghw_type_shortstring(pghw_type_t hw)
-{
- switch (hw) {
- case PGHW_IPIPE:
- return ("instr_pipeline");
- case PGHW_CACHE:
- return ("Cache");
- case PGHW_FPU:
- return ("FPU");
- case PGHW_MPIPE:
- return ("memory_pipeline");
- case PGHW_CHIP:
- return ("Socket");
- case PGHW_MEMORY:
- return ("Memory");
- case PGHW_POW_ACTIVE:
- return ("CPU_PM_Active");
- case PGHW_POW_IDLE:
- return ("CPU_PM_Idle");
- default:
- return ("unknown");
- }
-}
-
-/*
* Create / Update routines for PG hw kstats
*
* It is the intention of these kstats to provide some level
@@ -504,10 +496,17 @@ pghw_type_shortstring(pghw_type_t hw)
void
pghw_kstat_create(pghw_t *pg)
{
- char *class = pghw_type_string(pg->pghw_hw);
+ char *sharing = pghw_type_string(pg->pghw_hw);
+ char name[KSTAT_STRLEN + 1];
/*
- * Create a physical pg kstat
+ * Canonify PG name to conform to kstat name rules
+ */
+ (void) strncpy(name, pghw_type_string(pg->pghw_hw), KSTAT_STRLEN + 1);
+ strident_canon(name, KSTAT_STRLEN + 1);
+
+ /*
+ * Create a hardware performance kstat
*/
if ((pg->pghw_kstat = kstat_create("pg", ((pg_t *)pg)->pg_id,
"pg", "pg",
@@ -531,8 +530,8 @@ pghw_kstat_create(pghw_t *pg)
/*
* Create a physical pg kstat
*/
- if ((pg->pghw_cu_kstat = kstat_create("pg", ((pg_t *)pg)->pg_id,
- "hardware", class,
+ if ((pg->pghw_cu_kstat = kstat_create("pg_hw_perf", ((pg_t *)pg)->pg_id,
+ name, "processor_group",
KSTAT_TYPE_NAMED,
sizeof (pghw_cu_kstat) / sizeof (kstat_named_t),
KSTAT_FLAG_VIRTUAL)) != NULL) {
@@ -540,7 +539,7 @@ pghw_kstat_create(pghw_t *pg)
pg->pghw_cu_kstat->ks_data = &pghw_cu_kstat;
pg->pghw_cu_kstat->ks_update = pghw_cu_kstat_update;
pg->pghw_cu_kstat->ks_private = pg;
- pg->pghw_cu_kstat->ks_data_size += strlen(class) + 1;
+ pg->pghw_cu_kstat->ks_data_size += strlen(sharing) + 1;
/* Allow space for CPU strings */
pg->pghw_cu_kstat->ks_data_size += PGHW_KSTAT_STR_LEN_MAX;
pg->pghw_cu_kstat->ks_data_size += pg_cpulist_maxlen;
@@ -572,11 +571,21 @@ pghw_cu_kstat_update(kstat_t *ksp, int rw)
struct pghw_cu_kstat *pgsp = &pghw_cu_kstat;
pghw_t *pg = ksp->ks_private;
pghw_util_t *hw_util = &pg->pghw_stats;
+ boolean_t has_cpc_privilege;
if (rw == KSTAT_WRITE)
return (EACCES);
- pgsp->pg_id.value.ui32 = ((pg_t *)pg)->pg_id;
+ /*
+ * Check whether the caller has priv_cpc_cpu privilege. If he doesn't,
+ * he will not get hardware utilization data.
+ */
+
+ has_cpc_privilege = (secpolicy_cpc_cpu(crgetcred()) == 0);
+
+ pgsp->pg_id.value.i32 = ((pg_t *)pg)->pg_id;
+ pgsp->pg_parent_id.value.i32 = (int)pghw_parent_id(pg);
+
pgsp->pg_ncpus.value.ui32 = GROUP_SIZE(&((pg_t *)pg)->pg_cpus);
/*
@@ -613,22 +622,37 @@ pghw_cu_kstat_update(kstat_t *ksp, int rw)
(void) group2intlist(&(((pg_t *)pg)->pg_cpus),
pg->pghw_cpulist, pg->pghw_cpulist_len, cpu2id);
}
- cu_pg_update(pg);
+
+ if (has_cpc_privilege)
+ cu_pg_update(pg);
+
mutex_exit(&cpu_lock);
}
pgsp->pg_generation.value.ui32 = pg->pghw_kstat_gen;
- pgsp->pg_hw_util.value.ui64 = hw_util->pghw_util;
- pgsp->pg_hw_util_time_running.value.ui64 = hw_util->pghw_time_running;
- pgsp->pg_hw_util_time_stopped.value.ui64 = hw_util->pghw_time_stopped;
- pgsp->pg_hw_util_rate.value.ui64 = hw_util->pghw_rate;
- pgsp->pg_hw_util_rate_max.value.ui64 = hw_util->pghw_rate_max;
if (pg->pghw_cpulist != NULL)
kstat_named_setstr(&pgsp->pg_cpus, pg->pghw_cpulist);
else
kstat_named_setstr(&pgsp->pg_cpus, "");
- kstat_named_setstr(&pgsp->pg_sharing, pghw_type_string(pg->pghw_hw));
+ kstat_named_setstr(&pgsp->pg_relationship,
+ pghw_type_string(pg->pghw_hw));
+
+ if (has_cpc_privilege) {
+ pgsp->pg_hw_util.value.ui64 = hw_util->pghw_util;
+ pgsp->pg_hw_util_time_running.value.ui64 =
+ hw_util->pghw_time_running;
+ pgsp->pg_hw_util_time_stopped.value.ui64 =
+ hw_util->pghw_time_stopped;
+ pgsp->pg_hw_util_rate.value.ui64 = hw_util->pghw_rate;
+ pgsp->pg_hw_util_rate_max.value.ui64 = hw_util->pghw_rate_max;
+ } else {
+ pgsp->pg_hw_util.value.ui64 = 0;
+ pgsp->pg_hw_util_time_running.value.ui64 = 0;
+ pgsp->pg_hw_util_time_stopped.value.ui64 = 0;
+ pgsp->pg_hw_util_rate.value.ui64 = 0;
+ pgsp->pg_hw_util_rate_max.value.ui64 = 0;
+ }
return (0);
}
@@ -701,3 +725,24 @@ cpu2id(void *v)
return (cp->cpu_id);
}
+
+/*
+ * Return parent ID or -1 if there is no parent.
+ * All hardware PGs are currently also CMT PGs, but for safety we check the
+ * class matches cmt before we upcast the pghw pointer to pg_cmt_t.
+ */
+static pgid_t
+pghw_parent_id(pghw_t *pghw)
+{
+ pg_t *pg = (pg_t *)pghw;
+ pgid_t parent_id = -1;
+
+ if (pg != NULL && strcmp(pg->pg_class->pgc_name, "cmt") == 0) {
+ pg_cmt_t *cmt = (pg_cmt_t *)pg;
+ pg_t *parent = (pg_t *)cmt->cmt_parent;
+ if (parent != NULL)
+ parent_id = parent->pg_id;
+ }
+
+ return (parent_id);
+}
diff --git a/usr/src/uts/common/sys/pg.h b/usr/src/uts/common/sys/pg.h
index 0a61530982..f2bd3df514 100644
--- a/usr/src/uts/common/sys/pg.h
+++ b/usr/src/uts/common/sys/pg.h
@@ -18,9 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _PG_H
@@ -43,7 +43,7 @@ extern "C" {
#include <sys/types.h>
#include <sys/kstat.h>
-typedef uint_t pgid_t; /* processor group id */
+typedef int pgid_t; /* processor group id */
typedef uint_t pg_cid_t; /* processor group class id */
struct pg;
diff --git a/usr/src/uts/common/sys/pghw.h b/usr/src/uts/common/sys/pghw.h
index f0550dba7e..f8567c6f09 100644
--- a/usr/src/uts/common/sys/pghw.h
+++ b/usr/src/uts/common/sys/pghw.h
@@ -20,8 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
*/
#ifndef _PGHW_H
@@ -153,6 +152,7 @@ extern void pghw_init(pghw_t *, cpu_t *, pghw_type_t);
extern void pghw_fini(pghw_t *);
extern void pghw_cpu_add(pghw_t *, cpu_t *);
extern pghw_t *pghw_place_cpu(cpu_t *, pghw_type_t);
+extern void pghw_cmt_fini(pghw_t *);
/*
* Physical ID cache creation / destruction
@@ -177,7 +177,6 @@ extern pghw_type_t pg_plat_hw_rank(pghw_type_t, pghw_type_t);
* String representation of the hardware type
*/
extern char *pghw_type_string(pghw_type_t);
-extern char *pghw_type_shortstring(pghw_type_t);
/*
* What comprises a "core" may vary across processor implementations,