From d3c9722485327eb5b96de2f2108e9a84bd46096d Mon Sep 17 00:00:00 2001 From: Alexander Kolbasov Date: Mon, 16 Aug 2010 15:39:49 -0700 Subject: 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 --- usr/src/uts/common/disp/cmt.c | 10 ++- usr/src/uts/common/os/cap_util.c | 68 +++++++++++++----- usr/src/uts/common/os/pghw.c | 145 +++++++++++++++++++++++++-------------- usr/src/uts/common/sys/pg.h | 6 +- usr/src/uts/common/sys/pghw.h | 5 +- 5 files changed, 156 insertions(+), 78 deletions(-) (limited to 'usr/src/uts/common') 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 @@ -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 #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -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 @@ -30,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -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; + } } /* @@ -466,34 +486,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 * @@ -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 #include -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, -- cgit v1.2.3