/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
* or http://www.opensolaris.org/os/licensing.
* 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 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* ident "%Z%%M% %I% %E% SMI"
*
*/
package com.sun.solaris.service.locality;
import java.util.*;
import com.sun.solaris.service.pools.*;
/**
* A representation of the Locality Groups for a single Solaris
* instance.
*/
public class LocalityDomain
{
/**
* Obtain a Locality Group snapshot based on the view
* available to the caller.
*/
public static final int LGRP_VIEW_CALLER = 0;
/**
* Obtain a Locality Group snapshot based on the view
* of the Operating System.
*/
public static final int LGRP_VIEW_OS = 1;
static
{
System.loadLibrary("jlgrp");
}
/**
* The view used to create this LocalityDomain.
*/
private int view;
/**
* The cookie which represents the snapshot of locality
* information held by the lgrp library.
*/
private long cookie;
/**
* The root LocalityGroup for the LocalityDomain
*/
private LocalityGroup root;
/**
* Cached value of maxLatency.
*/
private final int maxLatency;
/**
* String representation of often used property.
*/
private final static String CPU_SYS_ID = "cpu.sys_id";
/**
* Constructor.
*
* @param view to use when creating the LocalityDomain.
* @throws Exception if there is a problem initializing the
* lgrp snapshot.
*/
public LocalityDomain(int view) throws Exception
{
this.view = view;
cookie = jl_init(view);
root = jl_root();
/*
* The maxLatency calculation is expensive and is used
* every time a locality objective is examined. Since
* it will never change over the lifetime of a
* LocalityDomain, we calculate it once in the
* constructor and cache for future use.
*/
maxLatency = calcMaxLatency();
}
/**
* Reclaim the resource allocated by the C proxy.
*
* @throws Throwable if there is a problem reclaiming the reosurces.
*/
protected void finalize() throws Throwable
{
try
{
close();
}
finally
{
super.finalize();
}
}
/**
* Return the "root" LocalityGroup.
*/
public LocalityGroup getRoot()
{
return (root);
}
/**
* Close this LocalityDomain. Resources are reclaimed in the C
* proxy and this LocalityDomain should never be used
* again. None of the LocalityGroups which are referenced from
* this LocalityDomain should be used after this method is
* invoked. NB: jl_fini returns a success indicator which is
* ignored as we are closing this domain.
*/
public void close()
{
if (cookie != 0) {
jl_fini();
cookie = 0;
root = null;
}
}
/**
* Return a string representation of this instance.
*/
public String toString()
{
return (root.toString());
}
/**
* Return the groups in this domain to which the supplied cpus
* belong, excluding the supplied set of groups.
*
* @param exclude Set of groups to be excluded.
* @param cpus List of cpus
*
* @throws PoolsException if there is an error accessing the
* cpu details.
*/
public Set foreignGroups(Set exclude, List cpus) throws PoolsException
{
Iterator cpuIt = cpus.iterator();
Set result = new HashSet();
while (cpuIt.hasNext()) {
Component comp = (Component) cpuIt.next();
int id = (int) comp.getLongProperty(CPU_SYS_ID);
LocalityGroup group = getGroup(id);
if (group != null && exclude.contains(group) == false)
result.add(group);
}
return (result);
}
/**
* Return the locality group which contains the majority of
* the cpus in the supplied list. If more than one group
* satisfies this criteria, then the choice of group is
* deterministic but unspecified.
*
* @param cpus List of cpus to be examined.
*
* @throws PoolsException if there is an error accessing the
* cpu details.
*/
public LocalityGroup getRepresentativeGroup(List cpus)
throws PoolsException
{
Iterator cpuIt = cpus.iterator();
Map grps = new HashMap();
while (cpuIt.hasNext()) {
Component comp = (Component) cpuIt.next();
int id = (int) comp.getLongProperty(CPU_SYS_ID);
LocalityGroup group = getGroup(id);
Integer score = (Integer) grps.get(group);
if (score != null) {
int iscore = score.intValue() + 1;
grps.put(group, new Integer(iscore));
} else {
grps.put(group, new Integer(1));
}
}
Iterator groupIt = grps.keySet().iterator();
LocalityGroup centre = null;
Integer highest = new Integer(0);
while (groupIt.hasNext()) {
LocalityGroup cand = (LocalityGroup) groupIt.next();
Integer value = (Integer) grps.get(cand);
if (value.intValue() > highest.intValue()) {
highest = value;
centre = cand;
}
}
return (centre);
}
/**
* Return the maximum latency between the groups in this
* domain.
*
*/
private int calcMaxLatency()
{
int max = 0;
Set groups = getGroups();
Iterator outer = groups.iterator();
while (outer.hasNext()) {
Iterator inner = groups.iterator();
LocalityGroup g1 = (LocalityGroup) outer.next();
while (inner.hasNext()) {
LocalityGroup g2 = (LocalityGroup) inner.next();
int latency = g1.getLatency(g2);
if (latency > max)
max = latency;
}
}
return (max);
}
/**
* Return the maximum possible latency between all locality
* groups in this domain.
*/
public int getMaxLatency()
{
return (maxLatency);
}
/**
* Return the set of all LocalityGroups for this LocalityDomain.
*/
public Set getGroups()
{
Set groups = new HashSet();
groups.add(root);
getGroups(root, groups);
return (groups);
}
/**
* Add all the descendent LocalityGroups for the supplied
* group into the supplied set.
*
* @param group is the group whose descendents are processed.
* @param descendents the set to add descendents of group.
*/
private void getGroups(LocalityGroup group, Set descendents)
{
Set children = group.getChildren();
if (! children.isEmpty()) {
Iterator itChild = children.iterator();
while (itChild.hasNext()) {
LocalityGroup child = (LocalityGroup) itChild.
next();
getGroups(child, descendents);
}
descendents.addAll(children);
}
}
/**
* Return the LocalityGroup containing the supplied CPU
* id. Search all LocalityGroups starting at the root group.
*
* @param cpuid is the sys-id of the CPU to search for.
*/
public LocalityGroup getGroup(int cpuid)
{
LocalityGroup answer = getGroup(root, cpuid);
return (getGroup(root, cpuid));
}
/**
* Return the LocalityGroup containing the supplied CPU
* id. Search LocalityGroups starting at the supplied group.
*
* @param group is the group to start searching from.
* @param cpuid is the sys-id of the CPU to search for.
*/
private LocalityGroup getGroup(LocalityGroup group, int cpuid)
{
Set children = group.getChildren();
if (children.isEmpty()) {
int cpus[] = group.getCPUIDs();
for (int i = 0; i < cpus.length; i++)
if (cpus[i] == cpuid) {
return (group);
}
} else {
Iterator itGroup = children.iterator();
while (itGroup.hasNext()) {
LocalityGroup owner;
LocalityGroup child = (LocalityGroup) itGroup.
next();
if ((owner = getGroup(child, cpuid)) != null)
return (owner);
}
}
return (null);
}
/**
* Initialise the LocalityDomain with an lgrp snapshot.
*
* @param view is the type of snapshot to obtain.
*/
private native long jl_init(int view) throws Exception;
/**
* Release the lgrp snapshot.
*/
private native int jl_fini();
/**
* Find the root LocalityGroup.
*/
private native LocalityGroup jl_root();
}