pghw.c revision d3c9722485327eb5b96de2f2108e9a84bd46096d
1N/A * The contents of this file are subject to the terms of the 1N/A * Common Development and Distribution License (the "License"). 1N/A * You may not use this file except in compliance with the License. 1N/A * See the License for the specific language governing permissions 1N/A * and limitations under the License. 1N/A * When distributing Covered Code, include this CDDL HEADER in each 1N/A * If applicable, add the following below this CDDL HEADER, with the 1N/A * fields enclosed by brackets "[]" replaced with your own identifying 1N/A * information: Portions Copyright [yyyy] [name of copyright owner] 1N/A * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 1N/A * Processor Groups: Hardware sharing relationship layer 1N/A * This file implements an extension to Processor Groups to capture 1N/A * hardware sharing relationships existing between logical CPUs. Examples of 1N/A * hardware sharing relationships include shared caches on some CMT 1N/A * procesoor architectures, or shared local memory controllers on NUMA 1N/A * based system architectures. 1N/A * The pghw_t structure represents the extended PG. The first member 1N/A * of the structure is the generic pg_t with the pghw specific members 1N/A * following. The generic pg_t *must* remain the first member of the 1N/A * structure as the code uses casting of structure references to access 1N/A * the generic pg_t structure elements. 1N/A * In addition to the generic CPU grouping, physical PGs have a hardware 1N/A * sharing relationship enumerated "type", and an instance id. The enumerated 1N/A * type is defined by the pghw_type_t enumeration, while the instance id 1N/A * uniquely identifies the sharing instance from among others of the same 1N/A * hardware sharing type. 1N/A * The physical PGs are organized into an overall hierarchy, and are tracked 1N/A * in a number of different per CPU, and per pghw_type_t type groups. 1N/A * || ============================ 1N/A * ||\\-----------------------// \\ \\ 1N/A * || | hwset (PGC_HW_CHIP) | ------------- ------------- 1N/A * || | (group_t) | | pghw_t | | pghw_t | 1N/A * || ----------------------- | chip 0 | | chip 1 | * || ------------- ------------- * || \\ \\ \\ \\ \\ \\ \\ \\ * || cpu cpu cpu cpu cpu cpu cpu cpu * || ============================ * ||\\-----------------------// \\ \\ * || | hwset (PGC_HW_IPIPE)| ------------- ------------- * || | (group_t) | | pghw_t | | pghw_t | * || ----------------------- | ipipe 0 | | ipipe 1 | * || ------------- ------------- * The top level pg_hw is a group of "hwset" groups. Each hwset holds of group * of physical PGs of the same hardware sharing type. Within each hwset, the * PG's instance id uniquely identifies the grouping relationshsip among other * groupings of the same sharing type. The instance id for a grouping is * platform defined, and in some cases may be used by platform code as a handle * to search for a particular relationship instance. * Each physical PG (by virtue of the embedded pg_t) contains a group of CPUs * that participate in the sharing relationship. Each CPU also has associated * with it a grouping tracking the PGs in which the CPU belongs. This can be * used to iterate over the various relationships in which the CPU participates * (the CPU's chip, cache, lgroup, etc.). * The hwsets are created dynamically as new hardware sharing relationship types * are instantiated. They are never destroyed, as once a given relationship * type appears in the system, it is quite likely that at least one instance of * that relationship will always persist as long as the system is running. * Capacity and Utilization PG kstats * These kstats are updated one at a time, so we can have a single scratch space * 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_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 * CPU may only be compared if they have the same * pg_hw_util Running value of PG utilization for the sharing * pg_hw_util_time_running * Total time spent collecting CU data. The time may be * less than wall time if CU counters were stopped for * pg_hw_util_time_stopped Total time the CU counters were stopped. * pg_hw_util_rate Utilization rate, expressed in operations per second. * pg_hw_util_rate_max Maximum observed value of utilization rate. * Calculate the string size to represent NCPUS. Allow 5 digits for each CPU ID * plus one space per CPU plus NUL byte in the end. This is only an estimate, * since we try to compress CPU ranges as x-y. In the worst case the string * representation of CPUs may be truncated. * Maximum length of the string that represents list of CPUs * Initialize the physical portion of a hardware PG * Haven't seen this hardware type yet * Hardware sharing relationship specific initialization * Teardown the physical portion of a physical PG * PG is removed from CMT hierarchy * Destroy string representation of CPUs * Find an existing physical PG in which to place * the given CPU for the specified hardware sharing * Find the pg representing the hw sharing relationship in which * Find the PG of the given hardware sharing relationship * type with the given instance id * CPUs physical ID cache creation / destruction * The cache's elements are initialized to the CPU's id * Create a new, empty hwset. * This routine may block, and must not be called from any * Create the top level PG hw group if it doesn't already exist * This is a "set" of hardware sets, that is ordered (and indexed) * by the pghw_type_t enum. * Add it to the top level pg_hw group. * Find the hwset associated with the given hardware sharing type * Remove a PG from a hwset * Return a string name given a pg_hw sharing type return (
"Integer Pipeline");
return (
"Floating Point Unit");
return (
"Data Pipe to memory");
return (
"CPU PM Active Power Domain");
return (
"CPU PM Idle Power Domain");
* Create / Update routines for PG hw kstats * It is the intention of these kstats to provide some level * of informational / debugging observability into the types * and nature of the system's detected hardware sharing relationships * Canonify PG name to conform to kstat name rules * Create a hardware performance kstat /* Class string, hw string, and policy string */ * Create a physical pg kstat /* Allow space for CPU strings */ * Check whether the caller has priv_cpc_cpu privilege. If he doesn't, * he will not get hardware utilization data. * Allocate memory for the string representing the list of CPUs in PG. * This memory should persist past the call to pghw_cu_kstat_update() * since the kstat snapshot routine will reference this memory. * PG kstat generation number is out of sync with PG's * generation mumber. It means that some CPUs could have joined * or left PG and it is not possible to compare the numbers * obtained before and after the generation change. * Reset the maximum utilization rate and start computing it * We can't block on CPU lock because when PG is destroyed (under * cpu_lock) it tries to delete this kstat and it will wait for us to * complete which will never happen since we are waiting for cpu_lock to * drop. Deadlocks are fun! * Update the string representation of CPUs in PG (pg->pghw_cpulist). * The string representation is used for kstats. * The string is allocated if it has not already been or if it is already * allocated and PG has more CPUs now. If PG has smaller or equal number of * CPUs, but the actual CPUs may have changed, the string is reset to the empty * string causes the string representation to be recreated. The pghw_generation * field is used to detect whether CPUs within the pg may have changed. * If the pghw_cpulist string is already allocated we need to make sure * that it has sufficient length. Also if the set of CPUs may have * changed, we need to re-generate the string. * There is sufficient space in the pghw_cpulist for * the new set of CPUs. Just clear the string to trigger * re-generation of list of CPUs * There is, potentially, insufficient space in * pghw_cpulist, so reallocate the string. * Allocate space to hold cpulist. * Length can not be bigger that the maximum space we have * allowed for the kstat buffer * 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.