1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * ident	"%Z%%M%	%I%	%E% SMI"
27  *
28  */
29 
30 package com.sun.solaris.service.locality;
31 
32 import java.util.*;
33 
34 import com.sun.solaris.service.pools.*;
35 
36 /**
37  * A representation of the Locality Groups for a single Solaris
38  * instance.
39  */
40 public class LocalityDomain
41 {
42 	/**
43 	 * Obtain a Locality Group snapshot based on the view
44 	 * available to the caller.
45 	 */
46 	public static final int LGRP_VIEW_CALLER = 0;
47 
48 	/**
49 	 * Obtain a Locality Group snapshot based on the view
50 	 * of the Operating System.
51 	 */
52 	public static final int LGRP_VIEW_OS = 1;
53 
54         static
55 	{
56                 System.loadLibrary("jlgrp");
57         }
58 
59 	/**
60 	 * The view used to create this LocalityDomain.
61 	 */
62 	private int view;
63 
64 	/**
65 	 * The cookie which represents the snapshot of locality
66 	 * information held by the lgrp library.
67 	 */
68 	private long cookie;
69 
70 	/**
71 	 * The root LocalityGroup for the LocalityDomain
72 	 */
73 	private LocalityGroup root;
74 
75 	/**
76 	 * Cached value of maxLatency.
77 	 */
78 	private final int maxLatency;
79 
80 	/**
81 	 * String representation of often used property.
82 	 */
83 	private final static String CPU_SYS_ID = "cpu.sys_id";
84 
85 	/**
86 	 * Constructor.
87 	 *
88 	 * @param view to use when creating the LocalityDomain.
89          * @throws Exception if there is a problem initializing the
90          * lgrp snapshot.
91 	 */
92 	public LocalityDomain(int view) throws Exception
93 	{
94 		this.view = view;
95 		cookie = jl_init(view);
96 		root = jl_root();
97 		/*
98 		 * The maxLatency calculation is expensive and is used
99 		 * every time a locality objective is examined. Since
100 		 * it will never change over the lifetime of a
101 		 * LocalityDomain, we calculate it once in the
102 		 * constructor and cache for future use.
103 		 */
104 		maxLatency = calcMaxLatency();
105 	}
106 
107         /**
108          * Reclaim the resource allocated by the C proxy.
109          *
110          * @throws Throwable if there is a problem reclaiming the reosurces.
111          */
112         protected void finalize() throws Throwable
113         {
114                 try
115                 {
116 			close();
117                 }
118                 finally
119                 {
120                         super.finalize();
121                 }
122         }
123 
124 	/**
125 	 * Return the "root" LocalityGroup.
126 	 */
127 	public LocalityGroup getRoot()
128 	{
129 		return (root);
130 	}
131 
132 	/**
133 	 * Close this LocalityDomain. Resources are reclaimed in the C
134 	 * proxy and this LocalityDomain should never be used
135 	 * again. None of the LocalityGroups which are referenced from
136 	 * this LocalityDomain should be used after this method is
137 	 * invoked. NB: jl_fini returns a success indicator which is
138 	 * ignored as we are closing this domain.
139 	 */
140 	public void close()
141 	{
142 		if (cookie != 0) {
143 			jl_fini();
144 			cookie = 0;
145 			root = null;
146 		}
147 	}
148 
149 	/**
150 	 * Return a string representation of this instance.
151 	 */
152 	public String toString()
153 	{
154 		return (root.toString());
155 	}
156 
157 	/**
158 	 * Return the groups in this domain to which the supplied cpus
159 	 * belong, excluding the supplied set of groups.
160 	 *
161 	 * @param exclude Set of groups to be excluded.
162 	 * @param cpus List of cpus
163 	 *
164 	 * @throws PoolsException if there is an error accessing the
165 	 * cpu details.
166 	 */
167 	public Set foreignGroups(Set exclude, List cpus) throws PoolsException
168 	{
169 		Iterator cpuIt = cpus.iterator();
170 		Set result = new HashSet();
171 		while (cpuIt.hasNext()) {
172 			Component comp = (Component) cpuIt.next();
173 			int id = (int) comp.getLongProperty(CPU_SYS_ID);
174 			LocalityGroup group = getGroup(id);
175 			if (group != null && exclude.contains(group) == false)
176 				result.add(group);
177 		}
178 		return (result);
179 	}
180 
181 	/**
182 	 * Return the locality group which contains the majority of
183 	 * the cpus in the supplied list. If more than one group
184 	 * satisfies this criteria, then the choice of group is
185 	 * deterministic but unspecified.
186 	 *
187 	 * @param cpus List of cpus to be examined.
188 	 *
189 	 * @throws PoolsException if there is an error accessing the
190 	 * cpu details.
191 	 */
192 	public LocalityGroup getRepresentativeGroup(List cpus)
193 	    throws PoolsException
194 	{
195 		Iterator cpuIt = cpus.iterator();
196 		Map grps = new HashMap();
197 		while (cpuIt.hasNext()) {
198 			Component comp = (Component) cpuIt.next();
199 			int id = (int) comp.getLongProperty(CPU_SYS_ID);
200 			LocalityGroup group = getGroup(id);
201 			Integer score = (Integer) grps.get(group);
202 			if (score != null) {
203 				int iscore = score.intValue() + 1;
204 				grps.put(group, new Integer(iscore));
205 			} else {
206 				grps.put(group, new Integer(1));
207 			}
208 		}
209 		Iterator groupIt = grps.keySet().iterator();
210 		LocalityGroup centre = null;
211 		Integer highest = new Integer(0);
212 		while (groupIt.hasNext()) {
213 			LocalityGroup cand = (LocalityGroup) groupIt.next();
214 			Integer value = (Integer) grps.get(cand);
215 			if (value.intValue() > highest.intValue()) {
216 				highest = value;
217 				centre = cand;
218 			}
219 		}
220 		return (centre);
221 	}
222 
223 	/**
224 	 * Return the maximum latency between the groups in this
225 	 * domain.
226 	 *
227 	 */
228 	private int calcMaxLatency()
229 	{
230 		int max = 0;
231 
232 		Set groups = getGroups();
233 		Iterator outer = groups.iterator();
234 		while (outer.hasNext()) {
235 			Iterator inner = groups.iterator();
236 			LocalityGroup g1 = (LocalityGroup) outer.next();
237 			while (inner.hasNext()) {
238 				LocalityGroup g2 = (LocalityGroup) inner.next();
239 				int latency = g1.getLatency(g2);
240 				if (latency > max)
241 					max = latency;
242 			}
243 		}
244 		return (max);
245 	}
246 
247 	/**
248 	 * Return the maximum possible latency between all locality
249 	 * groups in this domain.
250 	 */
251 	public int getMaxLatency()
252 	{
253 		return (maxLatency);
254 	}
255 
256 	/**
257 	 * Return the set of all LocalityGroups for this LocalityDomain.
258 	 */
259 	public Set getGroups()
260 	{
261 		Set groups = new HashSet();
262 		groups.add(root);
263 		getGroups(root, groups);
264 		return (groups);
265 	}
266 
267 	/**
268 	 * Add all the descendent LocalityGroups for the supplied
269 	 * group into the supplied set.
270 	 *
271 	 * @param group is the group whose descendents are processed.
272 	 * @param descendents the set to add descendents of group.
273 	 */
274 	private void getGroups(LocalityGroup group, Set descendents)
275 	{
276 		Set children = group.getChildren();
277 
278 		if (! children.isEmpty()) {
279 			Iterator itChild = children.iterator();
280 			while (itChild.hasNext()) {
281 				LocalityGroup child = (LocalityGroup) itChild.
282 				    next();
283 				getGroups(child, descendents);
284 			}
285 			descendents.addAll(children);
286 		}
287 	}
288 
289 	/**
290 	 * Return the LocalityGroup containing the supplied CPU
291 	 * id. Search all LocalityGroups starting at the root group.
292 	 *
293 	 * @param cpuid is the sys-id of the CPU to search for.
294 	 */
295 	public LocalityGroup getGroup(int cpuid)
296 	{
297 		LocalityGroup answer = getGroup(root, cpuid);
298 		return (getGroup(root, cpuid));
299 	}
300 
301 	/**
302 	 * Return the LocalityGroup containing the supplied CPU
303 	 * id. Search LocalityGroups starting at the supplied group.
304 	 *
305 	 * @param group is the group to start searching from.
306 	 * @param cpuid is the sys-id of the CPU to search for.
307 	 */
308 	private LocalityGroup getGroup(LocalityGroup group, int cpuid)
309 	{
310 		Set children = group.getChildren();
311 
312 		if (children.isEmpty()) {
313 			int cpus[] = group.getCPUIDs();
314 
315 
316 			for (int i = 0; i < cpus.length; i++)
317 				if (cpus[i] == cpuid) {
318 					return (group);
319 				}
320 		} else {
321 			Iterator itGroup = children.iterator();
322 			while (itGroup.hasNext()) {
323 				LocalityGroup owner;
324 				LocalityGroup child = (LocalityGroup) itGroup.
325 				    next();
326 				if ((owner = getGroup(child, cpuid)) != null)
327 					return (owner);
328 			}
329 		}
330 		return (null);
331 	}
332 
333 	/**
334 	 * Initialise the LocalityDomain with an lgrp snapshot.
335 	 *
336 	 * @param view is the type of snapshot to obtain.
337 	 */
338 	private native long jl_init(int view) throws Exception;
339 
340 	/**
341 	 * Release the lgrp snapshot.
342 	 */
343 	private native int jl_fini();
344 
345 	/**
346 	 * Find the root LocalityGroup.
347 	 */
348 	private native LocalityGroup jl_root();
349 
350 }
351