Line | Hits | Source |
---|---|---|
1 | package umich.cac.data; | |
2 | ||
3 | import java.util.logging.Level; | |
4 | import java.util.logging.Logger; | |
5 | ||
6 | /** | |
7 | * This class encapsulates Nodes fields, which is pretty complex, the most | |
8 | * complex of all fields. A node consists of just the number of nodes, like | |
9 | * Resource_List.nodes=2. The nodes resource_list item (i.e. the node | |
10 | * configuration) declares the node requirements for a job. It is a string of | |
11 | * individual node specifications separated by plus signs, +. For example, | |
12 | * | |
13 | * <pre> | |
14 | * 3+2:fast | |
15 | * </pre> | |
16 | * | |
17 | * requests 3 plain nodes and 2 ``fast'' nodes. A node specification is | |
18 | * generally one of the following types the name of a particular node in the | |
19 | * cluster, | |
20 | * <OL> | |
21 | * <LI>a node with a particular set of properties (e.g. fast and compute), | |
22 | * <LI>a number of nodes, | |
23 | * <LI>a number of nodes with a particular set of properties. | |
24 | * </OL> | |
25 | * In the last case, the number of nodes is specified first, and the properties | |
26 | * of the nodes are listed afterwards, colon-separated. For instance, | |
27 | * | |
28 | * <pre> | |
29 | * 4:fast:compute:db | |
30 | * </pre> | |
31 | * | |
32 | * <P> | |
33 | * | |
34 | * Two important properties that may be specified are: <b>shared</b> | |
35 | * indicates that the nodes are not to be allocated exclusively for the job. If | |
36 | * this property is not specified, the PBS scheduler will allocate each | |
37 | * processor exclusively to the job. * Note: The shared property may only be | |
38 | * used as a global modifier. <b>ppn=<number of processors per node></b> | |
39 | * requests a certain number of processors per node be allocated. The node | |
40 | * configuration may also have one or more global modifiers of the form #<i> | |
41 | * property</i> | |
42 | * | |
43 | * appended to the end of it which is equivalent to appending <i>property</i> | |
44 | * | |
45 | * to each node specification individually. That is, | |
46 | * | |
47 | * <pre> | |
48 | * 4+5:fast+2:compute#large | |
49 | * </pre> | |
50 | * | |
51 | * is completely equivalent to | |
52 | * | |
53 | * <pre> | |
54 | * 4:large+5:fast:large+2:compute:large | |
55 | * </pre>: The following are some possible configurations. | |
56 | * <p> | |
57 | * specified number of nodes: | |
58 | * | |
59 | * <pre> | |
60 | * nodes=<num nodes> nodes=<num nodes>#shared | |
61 | * </pre> | |
62 | * | |
63 | * specified number of nodes with a certain number of processors per node: | |
64 | * | |
65 | * <pre> | |
66 | * nodes=<num nodes>:ppn=<num procs per node> nodes=<num nodes>:ppn=<num procs per node>#shared | |
67 | * *</pre> | |
68 | * | |
69 | * specific nodes: | |
70 | * | |
71 | * <pre> | |
72 | * nodes=hosta+hostb+hostc nodes=hosta+hostb+hostc#shared | |
73 | * *</pre> | |
74 | * | |
75 | * specified number of nodes with particular properties | |
76 | * | |
77 | * <pre> | |
78 | * nodes=num nodes:property1:property2#shared | |
79 | * </pre> | |
80 | * | |
81 | * or I have found | |
82 | * | |
83 | * <pre> | |
84 | * nodes=hostname:ppn=2 | |
85 | * </pre> | |
86 | * | |
87 | * | |
88 | * Example encoding is as follows | |
89 | * | |
90 | * <pre> | |
91 | * <neednodes> <globalproperty> shared</globalproperty> <nodegroup numnodes="10" ppn="8"></nodegroup> <nodegroup numnodes="1"> <nodename>hostname</nodename> </nodegroup> <nodegroup numnodes="12" ppn="2"> <property>bigdisk</property> <property>fatmemory</property> </nodegroup> | |
92 | * </pre> | |
93 | * | |
94 | * @author rmach@umich.edu | |
95 | * @version $Header: /cvsroot/pbsaccounting/pbsaccounting/src/umich/cac/data/NodesField.java,v 1.3 2003/10/21 19:08:00 rodmach Exp $ | |
96 | */ | |
97 | ||
98 | public class NodesField extends Field { | |
99 | ||
100 | /** | |
101 | * Logger | |
102 | */ | |
103 | ||
104 | 45 | private Logger logger = Logger.getLogger(NodesField.class.getName()); |
105 | ||
106 | /** | |
107 | * Constructor for Nodes field | |
108 | * | |
109 | * @param fieldName | |
110 | * Name of this field | |
111 | * @param rawValue | |
112 | * the raw value of this field from PBS accounting data | |
113 | * @param fieldType | |
114 | * Description of the Parameter | |
115 | */ | |
116 | ||
117 | public NodesField( | |
118 | FieldName fieldName, | |
119 | String rawValue, | |
120 | FieldType fieldType) { | |
121 | 0 | super(fieldName, rawValue, fieldType); |
122 | 0 | setup(fieldName, rawValue, fieldType); |
123 | ||
124 | 0 | } |
125 | ||
126 | /** | |
127 | * Constructor for Nodes field, for a RESOURCE_LIST field type | |
128 | * | |
129 | * @param fieldName | |
130 | * Name of this field | |
131 | * @param rawValue | |
132 | * the raw value of this field from PBS accounting data | |
133 | */ | |
134 | ||
135 | public NodesField(FieldName fieldName, String rawValue) { | |
136 | 42 | super(fieldName, rawValue, FieldType.RESOURCE_LIST); |
137 | 42 | setup(fieldName, rawValue, FieldType.RESOURCE_LIST); |
138 | ||
139 | 42 | } |
140 | ||
141 | /** | |
142 | * Sets up the Nodes field | |
143 | * | |
144 | * @param fieldName | |
145 | * Name of this field | |
146 | * @param rawValue | |
147 | * the raw value of this field from PBS accounting data | |
148 | * @param fieldType | |
149 | * The field type this should be under Resource_List | |
150 | */ | |
151 | ||
152 | private void setup( | |
153 | FieldName fieldName, | |
154 | String rawValue, | |
155 | FieldType fieldType) { | |
156 | ||
157 | /* | |
158 | * 4+5:fast+2:compute#large foo+bar+taz | |
159 | * 4+2:ppn=2:fatdisk:bigscratch#shared | |
160 | */ | |
161 | ||
162 | //Step one, remove any global properties, and handle those | |
163 | 42 | int globalIndex = rawValue.indexOf("#"); |
164 | ||
165 | 42 | if (globalIndex == -1) { |
166 | //There are no global properties | |
167 | 36 | logger.fine("No global properties found"); |
168 | } else { | |
169 | 6 | String globalProperties = rawValue.substring(globalIndex); |
170 | 6 | addGlobalProperties(globalProperties); |
171 | //Strip off the globalProperties | |
172 | 6 | rawValue = rawValue.substring(0, globalIndex); |
173 | } | |
174 | ||
175 | /* | |
176 | * Nope, then the format happens to be the + separated version, with | |
177 | * properties delimited with : Resource_List.nodes=2:ppn=2 | |
178 | * 4+2:ppn=2:fatdisk:bigscratch | |
179 | */ | |
180 | ||
181 | // + separates node requirements | |
182 | 42 | String needNodes[] = rawValue.split("\\+"); |
183 | ||
184 | 99 | for (int i = 0; i < needNodes.length; i++) { |
185 | ||
186 | 57 | int propertySeparator = needNodes[i].indexOf(":"); |
187 | ||
188 | //Check if this node requirement has any properties | |
189 | 57 | if (propertySeparator != -1) { |
190 | ||
191 | 27 | String numNodes = needNodes[i].substring(0, propertySeparator); |
192 | 27 | String propertiesArray = |
193 | needNodes[i].substring(propertySeparator); | |
194 | ||
195 | // : separates properties | |
196 | 27 | String properties[] = propertiesArray.split(":"); |
197 | ||
198 | 27 | FieldName needNodesFieldName = |
199 | new FieldName("nodegroup", "none", FieldType.RESOURCE_LIST); | |
200 | 27 | Field nodeGroupField = |
201 | new Field(needNodesFieldName, "", FieldType.RESOURCE_LIST); | |
202 | ||
203 | 27 | if (isNumeric(numNodes)) { |
204 | 18 | Attribute nodesAttribute = |
205 | new Attribute("numnodes", numNodes); | |
206 | 18 | nodeGroupField.addAttribute(nodesAttribute); |
207 | } else { | |
208 | /* | |
209 | * This is like nodes=hostname:ppn=2:fatdisk, e.g. the part | |
210 | * before the colon is the "hostname" instead of the number | |
211 | * of hosts with the feature. I just set it to "1" since | |
212 | * this would be same as nodes=1:ppn=2:fatdisk | |
213 | */ | |
214 | ||
215 | 9 | FieldName nodeNameFieldName = |
216 | new FieldName( | |
217 | "nodename", | |
218 | "none", | |
219 | FieldType.RESOURCE_LIST); | |
220 | //Here numNodes is just the hostname | |
221 | 9 | Field nodeNameField = |
222 | new Field( | |
223 | nodeNameFieldName, | |
224 | numNodes, | |
225 | FieldType.RESOURCE_LIST); | |
226 | 9 | nodeGroupField.addChild(nodeNameField); |
227 | ||
228 | 9 | Attribute nodesAttribute = new Attribute("numnodes", "1"); |
229 | 9 | nodeGroupField.addAttribute(nodesAttribute); |
230 | ||
231 | } | |
232 | ||
233 | 93 | for (int j = 0; j < properties.length; j++) { |
234 | ||
235 | 66 | if (properties[j].equals("")) { |
236 | 27 | continue; |
237 | } | |
238 | 39 | if (properties[j].startsWith("ppn=")) { |
239 | 18 | int ppnAttributeIndex = properties[j].indexOf("="); |
240 | 18 | String ppnAttributeValue = |
241 | properties[j].substring(ppnAttributeIndex + 1); | |
242 | 18 | Attribute attribute = |
243 | new Attribute("ppn", ppnAttributeValue); | |
244 | 18 | nodeGroupField.addAttribute(attribute); |
245 | ||
246 | } else { | |
247 | 21 | FieldName propertyFieldName = |
248 | new FieldName( | |
249 | "property", | |
250 | "none", | |
251 | FieldType.RESOURCE_LIST); | |
252 | 21 | Field propertiesField = |
253 | new Field( | |
254 | propertyFieldName, | |
255 | properties[j], | |
256 | FieldType.RESOURCE_LIST); | |
257 | 21 | nodeGroupField.addChild(propertiesField); |
258 | } | |
259 | } | |
260 | ||
261 | 27 | addChild(nodeGroupField); |
262 | ||
263 | } else { | |
264 | //Else, we have a node with no additional properties. | |
265 | ||
266 | 30 | if (isNumeric(needNodes[i])) { |
267 | ||
268 | 21 | FieldName needNodesFieldName = |
269 | new FieldName( | |
270 | "nodegroup", | |
271 | "none", | |
272 | FieldType.RESOURCE_LIST); | |
273 | 21 | Field nodeGroupField = |
274 | new Field( | |
275 | needNodesFieldName, | |
276 | "", | |
277 | FieldType.RESOURCE_LIST); | |
278 | 21 | Attribute nodesAttribute = |
279 | new Attribute("numnodes", needNodes[i]); | |
280 | 21 | nodeGroupField.addAttribute(nodesAttribute); |
281 | 21 | addChild(nodeGroupField); |
282 | } else { | |
283 | 9 | addHost(needNodes[i]); |
284 | } | |
285 | ||
286 | } | |
287 | } | |
288 | ||
289 | 42 | } |
290 | ||
291 | private void addHost(String hostString) { | |
292 | ||
293 | 9 | FieldName needNodesFieldName = |
294 | new FieldName("nodegroup", "none", FieldType.RESOURCE_LIST); | |
295 | 9 | Field nodeGroupField = |
296 | new Field(needNodesFieldName, "", FieldType.RESOURCE_LIST); | |
297 | 9 | Attribute nodesAttribute = new Attribute("numnodes", "1"); |
298 | 9 | nodeGroupField.addAttribute(nodesAttribute); |
299 | ||
300 | 9 | FieldName nodeNameFieldName = |
301 | new FieldName("nodename", "none", FieldType.RESOURCE_LIST); | |
302 | 9 | Field nodeNameField = |
303 | new Field(nodeNameFieldName, hostString, FieldType.RESOURCE_LIST); | |
304 | ||
305 | 9 | nodeGroupField.addChild(nodeNameField); |
306 | 9 | addChild(nodeGroupField); |
307 | 9 | } |
308 | ||
309 | /** | |
310 | * Add global properties, the global properties are list of global | |
311 | * properties delimited by a # sign | |
312 | * | |
313 | * @param globalPropertiesString | |
314 | * the global properties to add | |
315 | */ | |
316 | ||
317 | private void addGlobalProperties(String globalPropertiesString) { | |
318 | ||
319 | 6 | String[] globalProperties = globalPropertiesString.split("#"); |
320 | ||
321 | 18 | for (int i = 0; i < globalProperties.length; i++) { |
322 | 12 | String propertyValue = globalProperties[i]; |
323 | ||
324 | //To prevent the empty property value resulting from the split | |
325 | 12 | if (propertyValue.length() == 0) { |
326 | 6 | continue; |
327 | } | |
328 | ||
329 | 6 | if (logger.isLoggable(Level.INFO)) { |
330 | 6 | logger.info( |
331 | "Adding global property with value " + propertyValue); | |
332 | } | |
333 | ||
334 | 6 | FieldName propertyFieldName = |
335 | new FieldName( | |
336 | "globalproperty", | |
337 | "none", | |
338 | FieldType.RESOURCE_LIST); | |
339 | ||
340 | 6 | Field propertyField = |
341 | new Field( | |
342 | propertyFieldName, | |
343 | propertyValue, | |
344 | FieldType.RESOURCE_LIST); | |
345 | 6 | addChild(propertyField); |
346 | } | |
347 | ||
348 | 6 | } |
349 | ||
350 | /** | |
351 | * Decide whether data is numeric. It is numeric if each of its characters | |
352 | * is a digit. | |
353 | * | |
354 | * @param s | |
355 | * String to test if it is numeric, contains all digits | |
356 | */ | |
357 | private boolean isNumeric(String s) { | |
358 | 57 | boolean isNumeric = false; |
359 | ||
360 | 96 | for (int i = 0; i < s.length(); i++) { |
361 | 57 | if (!Character.isDigit(s.charAt(i))) { |
362 | 18 | isNumeric = false; |
363 | 18 | break; |
364 | } else { | |
365 | 39 | isNumeric = true; |
366 | } | |
367 | ||
368 | } | |
369 | ||
370 | 57 | return isNumeric; |
371 | } | |
372 | ||
373 | } |
this report was generated by version 1.0.5 of jcoverage. |
copyright © 2003, jcoverage ltd. all rights reserved. |