 
| 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. |