lgrp_topo.c revision 950a2bab76698f667b8ce4ce7c4e229af5243405
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* lgroup topology
*/
/*
* Only collapse lgroups which have same latency (and resources)
*/
int lgrp_collapse_equidist = 1;
/*
* Height to limit lgroup topology
*/
unsigned int lgrp_topo_levels = LGRP_TOPO_LEVELS;
#ifdef DEBUG
/*
* Debugging output
* - 0: off
* - >0: on and bigger means more
*/
int lgrp_topo_debug = 0;
void
{
int i;
for (i = 0; i <= lgrp_alloc_max; i++)
if (klgrpset_ismember(lgrpset, i))
prom_printf("%d ", i);
prom_printf(")\n");
}
void
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++)
klgrpset_print(rsets[i]);
}
#endif /* DEBUG */
/*
* Add "from" lgroup resources to "to" lgroup resources
*/
void
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++)
}
/*
* Copy "from" lgroup resources to "to" lgroup resources
*/
void
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++)
}
/*
* Delete given lgroup ID from lgroup resource set of specified lgroup
* and its ancestors if "follow_parent" is set
*/
void
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++)
if (!follow_parent)
break;
}
}
/*
* Return whether given lgroup resource set empty
*/
int
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++)
if (!klgrpset_isempty(rset[i]))
return (0);
return (1);
}
/*
* Return whether given lgroup resource sets are same
*/
int
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++)
return (0);
return (1);
}
/*
* Return whether specified lgroup ID is in given lgroup resource set
*/
int
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++)
return (1);
return (0);
}
/*
* Return whether specified lgroup ID is in all lgroup resources
*/
int
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++)
return (0);
return (1);
}
/*
* Replace resources for given lgroup with specified resources at given
* latency and shift its old resources to its parent and its parent's resources
* to its parent, etc. until root lgroup reached
*/
void
{
int lat_new;
int lat_saved;
/*
* Save current resources and latency to insert in parent and
* then replace with new resources and latency
*/
if (!shift)
break;
}
}
/*
* Set "to" lgroup resource set with given lgroup ID
*/
void
{
int i;
for (i = 0; i < LGRP_RSRC_COUNT; i++) {
klgrpset_clear(to[i]);
}
}
/*
* Delete any ancestors of given child lgroup which don't have any other
* children
*/
int
{
int count;
#ifdef DEBUG
if (lgrp_topo_debug > 1) {
prom_printf("lgrp_ancestor_delete(0x%p[%d],0x%p)\n",
}
#endif /* DEBUG */
count = 0;
if (changed)
/*
* Visit ancestors, decrement child count for each, and remove any
* that don't have any children left until we reach an ancestor that
* has multiple children
*/
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_ancestor_delete: parent %d,"
" current %d\n",
#endif /* DEBUG */
parent->lgrp_childcnt--;
if (changed)
count++;
if (parent->lgrp_childcnt != 0)
break;
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_ancestor_delete: destroy"
" lgrp %d at 0x%p\n",
#endif /* DEBUG */
}
#ifdef DEBUG
prom_printf("lgrp_ancestor_delete: changed %d lgrps: 0x%llx\n",
#endif /* DEBUG */
return (count);
}
/*
* Consolidate lgrp1 into lgrp2
*/
int
{
int count;
int i;
/*
* Leaf lgroups should never need to be consolidated
*/
return (0);
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_consolidate(0x%p[%d],0x%p[%d],0x%p)\n",
#endif /* DEBUG */
count = 0;
if (changed)
/*
* Lgroup represents resources within certain latency, so need to keep
* biggest latency value of lgroups being consolidated
*/
/*
* Delete ancestors of lgrp1 that don't have any other children
*/
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_consolidate: delete ancestors\n");
#endif /* DEBUG */
if (changed) {
count++;
}
/*
* Reparent children lgroups of lgrp1 to lgrp2
*/
for (i = 0; i <= lgrp_alloc_max; i++) {
continue;
child = lgrp_table[i];
if (!LGRP_EXISTS(child))
continue;
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_consolidate: reparent "
"lgrp %d to lgrp %d\n",
#endif /* DEBUG */
lgrp2->lgrp_childcnt++;
if (changed) {
}
count += 2;
}
/*
* Proprogate leaves from lgrp2 to root
*/
if (changed)
count++;
}
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_consolidate: destroy lgrp %d at 0x%p\n",
prom_printf("lgrp_consolidate: changed %d lgrps: 0x%llx\n",
#endif /* DEBUG */
return (count);
}
/*
* Collapse duplicates of target lgroups given
*/
int
{
int count;
int i;
count = 0;
if (changed)
if (lgrp_collapse_off)
return (0);
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_collapse_dups(0x%llx)\n",
#endif /* DEBUG */
/*
* Look for duplicates of each target lgroup
*/
for (i = 0; i <= lgrp_alloc_max; i++) {
int j;
target = lgrp_table[i];
/*
* Skip to next lgroup if there isn't one here, this is root
* or leaf lgroup, or this isn't a target lgroup
*/
if (!LGRP_EXISTS(target) ||
continue;
/*
* Find all lgroups with same resources and latency
*/
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_collapse_dups: find "
"dups of lgrp %d at 0x%p\n",
#endif /* DEBUG */
for (j = 0; j <= lgrp_alloc_max; j++) {
lgrp = lgrp_table[j];
/*
* Skip lgroup if there isn't one here, this is root
* lgroup or leaf (which shouldn't have dups), or this
* lgroup doesn't have same resources
*/
if (!LGRP_EXISTS(lgrp) ||
lgrp->lgrp_childcnt == 0 ||
continue;
/*
* Keep first matching lgroup (but always keep root)
* and consolidate other duplicates into it
*/
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_collapse_dups: "
"keep lgrp %d at 0x%p\n",
#endif /* DEBUG */
} else {
}
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_collapse_dups:"
" consolidate lgrp %d at 0x%p"
" into lgrp %d at 0x%p\n",
#endif /* DEBUG */
&changes);
if (changed)
}
}
}
#ifdef DEBUG
prom_printf("lgrp_collapse_dups: changed %d lgrps: 0x%llx\n",
#endif /* DEBUG */
return (count);
}
/*
* Create new parent lgroup with given latency and resources for
* specified child lgroup, and insert it into hierarchy
*/
int
{
int count;
count = 0;
if (changed)
/*
* Create lgroup and set its latency and resources
*/
new = lgrp_create();
/*
* Insert new lgroup into hierarchy
*/
new->lgrp_childcnt++;
if (old) {
if (changed)
count++;
}
if (changed) {
}
count += 2;
#ifdef DEBUG
prom_printf("lgrp_new_parent: changed %d lgrps: 0x%llx\n",
#endif /* DEBUG */
return (count);
}
/*
* Proprogate resources of new leaf into parent lgroup of given child
*/
int
{
int count;
count = 0;
if (changed)
return (0);
if (changed)
count++;
/*
* Don't proprogate new leaf resources to parent if it already
* contains these resources
*/
#ifdef DEBUG
prom_printf("lgrp_proprogate: changed %d lgrps:"
" 0x%llx\n",
#endif /* DEBUG */
return (count);
}
/*
* Add leaf resources to parent lgroup
*/
#ifdef DEBUG
if (lgrp_topo_debug > 1) {
prom_printf("lgrp_proprogate: newleaf %d(0x%p), "
"latency %d, child %d(0x%p), parent %d(0x%p)\n",
prom_printf("lgrp_proprogate: parent's leaves becomes 0x%llx\n",
}
if (lgrp_topo_debug > 0) {
prom_printf("lgrp_proprogate: adding to parent %d (0x%p)\n",
}
prom_printf("lgrp_proprogate: changed %d lgrps: 0x%llx\n",
#endif /* DEBUG */
return (count);
}
/*
* Split parent lgroup of given child if child's leaf decendant (oldleaf) has
* different latency to new leaf lgroup (newleaf) than leaf lgroups of given
* child's siblings
*/
int
{
int count;
int i;
int latency;
count = 0;
if (changed)
return (0);
/*
* Parent must have more than one child to have a child split from it
* and root lgroup contains all resources and never needs to be split
*/
return (0);
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_split(0x%p[%d],0x%p[%d],0x%p[%d],0x%p)\n",
#endif /* DEBUG */
/*
* Get latency between new leaf and old leaf whose lineage it is
* being added
*/
/*
* Check whether all sibling leaves of given child lgroup have same
* latency to new leaf
*/
for (i = 0; i <= lgrp_alloc_max; i++) {
int sibling_latency;
lgrp = lgrp_table[i];
/*
* Skip non-existent lgroups, old leaf, and any lgroups that
* don't have parent as common ancestor
*/
continue;
/*
* Same latency, so skip
*/
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_split: latency(%d,%d) %d,"
" latency(%d,%d) %d\n",
#endif /* DEBUG */
if (sibling_latency == latency)
continue;
/*
* Different latencies, so remove child from its parent and
* make new parent for old leaf with same latency and same
* resources
*/
parent->lgrp_childcnt--;
if (grandparent) {
count++;
if (changed)
}
if (changed) {
count += 2;
}
#ifdef DEBUG
if (lgrp_topo_debug > 0) {
prom_printf("lgrp_split: new parent %d (0x%p) for"
" lgrp %d (0x%p)\n",
lgrp_rsets_print("new parent resources:",
}
prom_printf("lgrp_split: changed %d lgrps: 0x%llx\n",
#endif /* DEBUG */
return (count);
}
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_split: no changes\n");
#endif /* DEBUG */
return (count);
}
/*
* Return height of lgroup topology from given lgroup to root
*/
int
{
int nlevels;
if (!LGRP_EXISTS(lgrp))
return (0);
nlevels = 0;
nlevels++;
}
return (nlevels);
}
/*
* Add resources of new leaf to old leaf's lineage
*
* Assumes the following:
* - Lgroup hierarchy consists of at least a root lgroup and its leaves
* including old and new ones given below
* - New leaf lgroup has been created and does not need to have its resources
* added to it
* - Latencies have been set for root and leaf lgroups
*/
int
{
int count;
int latency;
int nlevels;
int proprogate;
int total;
if (changed)
return (0);
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("\nlgrp_lineage_add(0x%p[%d],0x%p[%d],0x%p)\n",
changed);
#endif /* DEBUG */
/*
* Get latency between old and new leaves, so we can determine
* where the new leaf fits in the old leaf's lineage
*/
/*
* Determine height of lgroup topology from old leaf to root lgroup,
* so height of topology may be limited if necessary
*/
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_lineage_add: latency(%d,%d) 0x%x, ht %d\n",
#endif /* DEBUG */
/*
* Can't add new leaf to old leaf's lineage if we haven't
* determined latency between them yet
*/
if (latency == 0)
return (0);
proprogate = 0;
/*
* Lineage of old leaf is basically a sorted list of the other leaves
* from closest to farthest, so find where to add new leaf to the
* lineage and proprogate its resources from that point up to the root
* lgroup since parent lgroups contain all the resources of their
* children
*/
do {
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_lineage_add: child %d (0x%p), parent"
" %d (0x%p)\n",
#endif /* DEBUG */
/*
* See whether parent lgroup needs to be split
*
* May need to split parent lgroup when it is ancestor to more
* than one leaf, but all its leaves don't have latency to new
* leaf within the parent lgroup's latency
* NOTE: Don't want to collapse this lgroup since we just split
* it from parent
*/
if (count) {
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_lineage_add: setting parent"
" for child %d from %d to %d\n",
#endif /* DEBUG */
if (changed)
}
/*
* Already found where resources of new leaf belong in old
* leaf's lineage, so proprogate resources of new leaf up
* through rest of ancestors
*/
if (proprogate) {
&changes);
if (changed)
continue;
}
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_lineage_add: latency 0x%x,"
" parent latency 0x%x\n",
#endif /* DEBUG */
/*
* As we work our way from the old leaf to the root lgroup,
* new leaf resources should go in between two lgroups or into
* one of the parent lgroups somewhere along the line
*/
/*
* New leaf resources should go in between current
* child and parent
*/
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_lineage_add: "
"latency < parent latency\n");
#endif /* DEBUG */
/*
* Create lgroup with desired resources and insert it
* between child and parent
*/
if (nlevels >= lgrp_topo_levels) {
break;
#ifdef DEBUG
if (lgrp_topo_debug > 0) {
prom_printf("lgrp_lineage_add: "
"replaced parent lgrp %d at 0x%p"
" for lgrp %d\n",
lgrp_rsets_print("old parent"
lgrp_rsets_print("new parent "
"resources:", rset);
}
#endif /* DEBUG */
/*
* Replace contents of parent with new
* leaf + child resources since new leaf is
* closer and shift its parent's resources to
* its parent, etc. until root lgroup reached
*/
if (*changed)
total++;
proprogate++;
} else {
&changes);
if (changed)
proprogate++;
#ifdef DEBUG
if (lgrp_topo_debug > 0) {
prom_printf("lgrp_lineage_add: new "
"parent lgrp %d at 0x%p for "
lgrp_rsets_print("new parent "
"resources:", rset);
}
#endif /* DEBUG */
continue;
}
/*
* New leaf resources should go into parent
*/
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_lineage_add: latency == "
"parent latency\n");
#endif /* DEBUG */
/*
* It's already there, so don't need to do anything.
*/
break;
&changes);
if (changed)
proprogate++;
}
/*
* Consolidate any duplicate lgroups of ones just changed
* Assume that there were no duplicates before last round of changes
*/
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_lineage_add: collapsing dups....\n");
#endif /* DEBUG */
&changes);
if (changed)
#ifdef DEBUG
prom_printf("lgrp_lineage_add: changed %d lgrps: 0x%llx\n",
#endif /* DEBUG */
return (total);
}
/*
* Add leaf lgroup to lgroup topology
*/
int
{
int count;
int i;
int latency;
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("\nlgrp_leaf_add(0x%p[%d],0x%p,%d,0x%p)\n",
#endif /* DEBUG */
count = 0;
if (changed)
/*
* Initialize parent of leaf lgroup to root
*/
#ifdef DEBUG
if (lgrp_topo_debug > 1)
lgrp_rsets_print("lgrp_leaf_add: root lgrp resources",
#endif /* DEBUG */
if (changed) {
}
count += 2;
}
/*
* Can't add leaf lgroup to rest of topology (and vice versa) unless
* latency for it is available
*/
if (latency == 0) {
#ifdef DEBUG
prom_printf("lgrp_leaf_add: changed %d lgrps: 0x%llx\n",
#endif /* DEBUG */
return (count);
}
/*
* Make sure that root and leaf lgroup latencies are set
*/
/*
* Add leaf to lineage of other leaves and vice versa
* since leaves come into existence at different times
*/
for (i = 0; i < lgrp_count; i++) {
/*
* Skip non-existent lgroups, new leaf lgroup, and
* non-leaf lgroups
*/
lgrp->lgrp_childcnt != 0) {
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_leaf_add: skip "
"lgrp %d at 0x%p\n",
#endif /* DEBUG */
continue;
}
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_leaf_add: lgrp %d (0x%p) =>"
" lgrp %d (0x%p)\n",
#endif /* DEBUG */
if (changed)
if (changed)
}
#ifdef DEBUG
prom_printf("lgrp_leaf_add: changed %d lgrps: 0x%llx\n",
#endif /* DEBUG */
return (count);
}
/*
* Remove resources of leaf from lgroup hierarchy
*/
int
{
int count;
int i;
count = 0;
if (changed)
/*
* Nothing to do if no leaf given
*/
return (0);
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_leaf_delete(0x%p[%d],0x%p,%d,0x%p)\n",
#endif /* DEBUG */
/*
* Remove leaf from any lgroups containing its resources
*/
for (i = 0; i < lgrp_count; i++) {
continue;
#ifdef DEBUG
if (lgrp_topo_debug > 0)
prom_printf("lgrp_leaf_delete: remove leaf from"
#endif /* DEBUG */
count++;
}
/*
* Remove leaf and its ancestors that don't have any other children
*/
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_leaf_delete: remove leaf and ancestors\n");
#endif /* DEBUG */
count++;
/*
* Consolidate any duplicate lgroups of ones just changed
* Assume that there were no duplicates before last round of changes
*/
#ifdef DEBUG
if (lgrp_topo_debug > 1)
prom_printf("lgrp_leaf_delete: collapsing dups\n");
#endif /* DEBUG */
&changes);
if (changed)
#ifdef DEBUG
prom_printf("lgrp_leaf_delete: changed %d lgrps: 0x%llx\n",
#endif /* DEBUG */
return (count);
}
/*
* Flatten lgroup topology down to height specified
*/
int
{
int count;
int i;
/*
* Only flatten down to 2 level for now
*/
if (levels != 2)
return (0);
/*
* Look for non-leaf lgroups to remove and leaf lgroups to reparent
*/
count = 0;
for (i = 0; i <= lgrp_count; i++) {
/*
* Skip non-existent lgroups and root
*/
if (!LGRP_EXISTS(lgrp))
continue;
continue;
}
if (lgrp->lgrp_childcnt > 0) {
/*
* Remove non-leaf lgroup from lgroup topology
*/
if (changed) {
count += 2;
}
if (parent) {
parent->lgrp_childcnt--;
}
/*
* Reparent leaf lgroup to root
*/
if (changed) {
count += 2;
}
}
}
return (count);
}
/*
* Return current height limit for lgroup topology
*/
int
lgrp_topo_ht_limit(void)
{
return (lgrp_topo_levels);
}
/*
* Return default height limit for lgroup topology
*/
int
{
return (LGRP_TOPO_LEVELS);
}
/*
* Set height limit for lgroup topology
*/
int
lgrp_topo_ht_limit_set(int ht)
{
if (ht > LGRP_TOPO_LEVELS_MAX)
else
return (ht);
}
/*
* Update lgroup topology for any leaves that don't have their latency set
*
* This may happen on some machines when the lgroup platform support doesn't
* know the latencies between nodes soon enough to provide it when the
* resources are being added. If the lgroup platform code needs to probe
* memory to determine the latencies between nodes, it must wait until the
* CPUs become active so at least one CPU in each node can probe memory in
* each node.
*/
int
{
int count;
int i;
count = 0;
if (changed)
/*
* For UMA machines, make sure that root lgroup contains all
* resources. The root lgrp should also name itself as its own leaf
*/
if (nlgrps == 1) {
for (i = 0; i < LGRP_RSRC_COUNT; i++)
return (0);
}
/*
* Look for any leaf lgroup without its latency set, finish adding it
* to the lgroup topology assuming that it exists and has the root
* lgroup as its parent, and update the memory nodes of all lgroups
* that have it as a memory resource.
*/
for (i = 0; i < lgrp_count; i++) {
/*
* Skip non-existent and non-leaf lgroups and any lgroup
* with its latency set already
*/
continue;
#ifdef DEBUG
if (lgrp_topo_debug > 1) {
prom_printf("\nlgrp_topo_update: updating lineage "
}
#endif /* DEBUG */
if (changed)
if (!klgrpset_isempty(changes))
#ifdef DEBUG
prom_printf("lgrp_topo_update: changed %d lgrps: "
"0x%llx\n",
#endif /* DEBUG */
}
(void) lpl_topo_flatten(2);
}
start_cpus();
return (count);
}
#ifdef DEBUG
void
{
if (lgrp->lgrp_childcnt == 0)
prom_printf(" (plathand %p)\n",
(void *)lgrp->lgrp_plathand);
else
prom_printf("\n");
if (parent)
else
prom_printf("\n");
prom_printf("\tleaves ");
}
void
{
while (!klgrpset_isempty(siblings)) {
int i;
for (i = 0; i <= lgrp_max; i++) {
continue;
}
}
}
#endif /* DEBUG */