001: /*
002: * This file or a portion of this file is licensed under the terms of
003: * the Globus Toolkit Public License, found in file GTPL, or at
004: * http://www.globus.org/toolkit/download/license.html. This notice must
005: * appear in redistributions of this file, with or without modification.
006: *
007: * Redistributions of this Software, with or without modification, must
008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
009: * some other similar material which is provided with the Software (if
010: * any).
011: *
012: * Copyright 1999-2004 University of Chicago and The University of
013: * Southern California. All rights reserved.
014: */
015:
016: package org.griphyn.cPlanner.toolkit;
017:
018: import org.griphyn.cPlanner.common.PegasusProperties;
019: import org.griphyn.cPlanner.common.LogManager;
020:
021: import org.griphyn.common.util.Version;
022: import org.griphyn.common.util.FactoryException;
023:
024: import org.griphyn.cPlanner.visualize.Callback;
025: import org.griphyn.cPlanner.visualize.KickstartParser;
026:
027: import org.griphyn.cPlanner.visualize.spaceusage.KickstartOutputFilenameFilter;
028:
029: import org.griphyn.cPlanner.visualize.WorkflowMeasurements;
030:
031: import org.griphyn.cPlanner.visualize.nodeusage.NodeUsageCallback;
032: import org.griphyn.cPlanner.visualize.nodeusage.Ploticus;
033:
034: import org.griphyn.vdl.toolkit.FriendlyNudge;
035:
036: import gnu.getopt.Getopt;
037: import gnu.getopt.LongOpt;
038:
039: import java.io.BufferedReader;
040: import java.io.File;
041: import java.io.IOException;
042: import java.io.InputStream;
043: import java.io.InputStreamReader;
044:
045: import java.util.Date;
046: import java.util.Iterator;
047: import java.util.List;
048:
049: /**
050: * This parses the kickstart records and generates input files for ploticus,
051: * to visualize.
052: *
053: *
054: * @author Karan Vahi
055: *
056: * @version $Revision: 50 $
057: */
058:
059: public class PlotNodeUsage extends Executable {
060:
061: /**
062: * The default output directory.
063: */
064: public static final String DEFAULT_OUTPUT_DIR = ".";
065:
066: /**
067: * The default timing source.
068: */
069: public static final String DEFAULT_TIMING_SOURCE = "Kickstart";
070:
071: /**
072: * The tailstatd timing source.
073: */
074: public static final String TAILSTATD_TIMING_SOURCE = "Tailstatd";
075:
076: /**
077: * The input directory containing the kickstart records.
078: */
079: private String mInputDir;
080:
081: /**
082: * The output directory where to generate the ploticus output.
083: */
084: private String mOutputDir;
085:
086: /**
087: * The default basename given to the files.
088: */
089: private String mBasename;
090:
091: /**
092: * The logging level to be used.
093: */
094: private int mLoggingLevel;
095:
096: /**
097: * The time units.
098: */
099: private String mTimeUnits;
100:
101: /**
102: * Default constructor.
103: */
104: public PlotNodeUsage() {
105: super ();
106: mLogMsg = new String();
107: mVersion = Version.instance().toString();
108: mOutputDir = this .DEFAULT_OUTPUT_DIR;
109: mLoggingLevel = 0;
110: mBasename = "ploticus";
111: }
112:
113: /**
114: * The main program.
115: *
116: *
117: * @param args the main arguments passed to the plotter.
118: */
119: public static void main(String[] args) {
120:
121: PlotNodeUsage me = new PlotNodeUsage();
122: int result = 0;
123: double starttime = new Date().getTime();
124: double execTime = -1;
125:
126: try {
127: me.executeCommand(args);
128: } catch (FactoryException fe) {
129: me.log(fe.convertException(),
130: LogManager.FATAL_MESSAGE_LEVEL);
131: result = 2;
132: } catch (RuntimeException rte) {
133: //catch all runtime exceptions including our own that
134: //are thrown that may have chained causes
135: me.log(convertException(rte),
136: LogManager.FATAL_MESSAGE_LEVEL);
137: result = 1;
138: } catch (Exception e) {
139: //unaccounted for exceptions
140: me.log(e.getMessage(), LogManager.FATAL_MESSAGE_LEVEL);
141: e.printStackTrace();
142: result = 3;
143: } finally {
144: double endtime = new Date().getTime();
145: execTime = (endtime - starttime) / 1000;
146: }
147:
148: // warn about non zero exit code
149: if (result != 0) {
150: me.log("Non-zero exit-code " + result,
151: LogManager.WARNING_MESSAGE_LEVEL);
152: } else {
153: //log the time taken to execute
154: me.log("Time taken to execute is " + execTime + " seconds",
155: LogManager.INFO_MESSAGE_LEVEL);
156: }
157:
158: System.exit(result);
159: }
160:
161: /**
162: * Executes the command on the basis of the options specified.
163: *
164: * @param args the command line options.
165: */
166: public void executeCommand(String[] args) {
167: parseCommandLineArguments(args);
168:
169: //set logging level only if explicitly set by user
170: if (mLoggingLevel > 0) {
171: mLogger.setLevel(mLoggingLevel);
172: }
173:
174: //do sanity check on input directory
175: if (mInputDir == null) {
176: throw new RuntimeException(
177: "You need to specify the directory containing kickstart records");
178:
179: }
180: File dir = new File(mInputDir);
181: if (dir.isDirectory()) {
182: //see if it is readable
183: if (!dir.canRead()) {
184: throw new RuntimeException("Cannot read directory "
185: + mInputDir);
186: }
187: } else {
188: throw new RuntimeException(mInputDir
189: + " is not a directory ");
190: }
191:
192: //sanity check on output directory
193: dir = new File(mOutputDir);
194: if (dir.exists()) {
195: //directory already exists.
196: if (dir.isDirectory()) {
197: if (!dir.canWrite()) {
198: throw new RuntimeException(
199: "Cannot write out to output directory "
200: + mOutputDir);
201: }
202: } else {
203: //directory is a file
204: throw new RuntimeException(mOutputDir
205: + " is not a directory ");
206: }
207:
208: } else {
209: dir.mkdirs();
210: }
211:
212: KickstartParser su = new KickstartParser();
213:
214: Callback c = new NodeUsageCallback();
215:
216: c.initialize(mInputDir, true);
217: su.setCallback(c);
218:
219: //String dir = "/usr/sukhna/work/test/dags/ivdgl1/blackdiamond/run0004";
220: File directory = new File(mInputDir);
221: String[] files = directory
222: .list(new KickstartOutputFilenameFilter());
223: for (int i = 0; i < files.length; i++) {
224: String file = mInputDir + File.separator + files[i];
225:
226: try {
227: log("Parsing file " + file,
228: LogManager.DEBUG_MESSAGE_LEVEL);
229: su.parseKickstartFile(file);
230: } catch (IOException ioe) {
231: log("Unable to parse kickstart file " + file
232: + convertException(ioe),
233: LogManager.DEBUG_MESSAGE_LEVEL);
234: } catch (FriendlyNudge fn) {
235: log("Problem parsing file " + file
236: + convertException(fn),
237: LogManager.WARNING_MESSAGE_LEVEL);
238: }
239: }
240:
241: //we are done with parsing
242: c.done();
243:
244: WorkflowMeasurements wm = (WorkflowMeasurements) c
245: .getConstructedObject();
246: wm.sort();
247: log(" Workflow Measurements is \n" + wm,
248: LogManager.DEBUG_MESSAGE_LEVEL);
249:
250: //generate the ploticus format
251: Ploticus plotter = new Ploticus();
252: plotter.initialize(mOutputDir, mBasename, true);
253: try {
254: List result = plotter.plot(wm, '0', mTimeUnits);
255:
256: for (Iterator it = result.iterator(); it.hasNext();) {
257: mLogger.log("Written out file " + it.next(),
258: LogManager.INFO_MESSAGE_LEVEL);
259: }
260: } catch (IOException ioe) {
261: log("Unable to plot the files " + convertException(ioe),
262: LogManager.DEBUG_MESSAGE_LEVEL);
263: }
264:
265: }
266:
267: /**
268: * Parses the command line arguments using GetOpt and returns a
269: * <code>PlannerOptions</code> contains all the options passed by the
270: * user at the command line.
271: *
272: * @param args the arguments passed by the user at command line.
273: */
274: public void parseCommandLineArguments(String[] args) {
275: LongOpt[] longOptions = generateValidOptions();
276:
277: Getopt g = new Getopt("plot-node-usage", args, "b:i:o:T:hvV",
278: longOptions, false);
279: g.setOpterr(false);
280:
281: int option = 0;
282:
283: while ((option = g.getopt()) != -1) {
284: //System.out.println("Option tag " + (char)option);
285: switch (option) {
286:
287: case 'b'://the basename
288: this .mBasename = g.getOptarg();
289: break;
290:
291: case 'i'://dir
292: this .mInputDir = g.getOptarg();
293: break;
294:
295: case 'h'://help
296: printLongVersion();
297: System.exit(0);
298: return;
299:
300: case 'o'://output directory
301: this .mOutputDir = g.getOptarg();
302: break;
303:
304: case 'T'://time units
305: this .mTimeUnits = g.getOptarg();
306: break;
307:
308: case 'v'://verbose
309: mLoggingLevel++;
310: break;
311:
312: case 'V'://version
313: mLogger.log(getGVDSVersion(),
314: LogManager.INFO_MESSAGE_LEVEL);
315: System.exit(0);
316:
317: default: //same as help
318: printShortVersion();
319: throw new RuntimeException(
320: "Incorrect option or option usage "
321: + (char) option);
322:
323: }
324: }
325:
326: }
327:
328: /**
329: * Tt generates the LongOpt which contain the valid options that the command
330: * will accept.
331: *
332: * @return array of <code>LongOpt</code> objects , corresponding to the valid
333: * options
334: */
335: public LongOpt[] generateValidOptions() {
336: LongOpt[] longopts = new LongOpt[7];
337:
338: longopts[0] = new LongOpt("input", LongOpt.REQUIRED_ARGUMENT,
339: null, 'i');
340: longopts[1] = new LongOpt("output", LongOpt.REQUIRED_ARGUMENT,
341: null, 'o');
342: longopts[2] = new LongOpt("verbose", LongOpt.NO_ARGUMENT, null,
343: 'v');
344: longopts[3] = new LongOpt("help", LongOpt.NO_ARGUMENT, null,
345: 'h');
346: longopts[4] = new LongOpt("Version", LongOpt.NO_ARGUMENT, null,
347: 'V');
348: longopts[5] = new LongOpt("basename",
349: LongOpt.REQUIRED_ARGUMENT, null, 'b');
350: longopts[6] = new LongOpt("time-units",
351: LongOpt.REQUIRED_ARGUMENT, null, 'T');
352: return longopts;
353: }
354:
355: /**
356: * Prints out a short description of what the command does.
357: */
358: public void printShortVersion() {
359: String text = "\n $Id: PlotNodeUsage.java 50 2007-05-19 00:48:32Z gmehta $ "
360: + "\n "
361: + getGVDSVersion()
362: + "\n Usage : plot_node_usage [-Dprop [..]] -i <input directory> "
363: + " [-o output directory] [-b basename] [-T time units] [-v] [-V] [-h]";
364:
365: System.out.println(text);
366: }
367:
368: /**
369: * Prints the long description, displaying in detail what the various options
370: * to the command stand for.
371: */
372: public void printLongVersion() {
373:
374: String text = "\n $Id: PlotNodeUsage.java 50 2007-05-19 00:48:32Z gmehta $ "
375: + "\n "
376: + getGVDSVersion()
377: + "\n plot-node-usage - A plotting tool that plots out the number of jobs running on remote clusters over time"
378: + "\n Usage: plot_node_usage [-Dprop [..]] --input <input directory> [--base basename] "
379: + "\n [--output output directory] [-T time units] [--verbose] [--Version] [--help] "
380: + "\n"
381: + "\n Mandatory Options "
382: + "\n --input the directory where the kickstart records reside."
383: + "\n Other Options "
384: + "\n -b |--basename the basename prefix for constructing the ploticus files."
385: + "\n -o |--output the output directory where to generate the ploticus files."
386: + "\n -T |--time-units the units in which you want the x axis to be plotted (seconds|minutes|hours) "
387: + "\n Defaults to seconds."
388: + "\n -v |--verbose increases the verbosity of messages about what is going on"
389: + "\n -V |--version displays the version of the Pegasus Workflow Planner"
390: + "\n -h |--help generates this help."
391: + "\n The following exitcodes are produced"
392: + "\n 0 plotter was able to generate plots"
393: + "\n 1 an error occured. In most cases, the error message logged should give a"
394: + "\n clear indication as to where things went wrong."
395: + "\n 2 an error occured while loading a specific module implementation at runtime"
396: + "\n ";
397:
398: System.out.println(text);
399: //mLogger.log(text,LogManager.INFO_MESSAGE_LEVEL);
400: }
401:
402: /**
403: * Loads all the properties that would be needed by the Toolkit classes.
404: */
405: public void loadProperties() {
406: //empty for time being
407: }
408:
409: }
|