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.Plot;
028: import org.griphyn.cPlanner.visualize.spaceusage.Ploticus;
029: import org.griphyn.cPlanner.visualize.spaceusage.KickstartOutputFilenameFilter;
030: import org.griphyn.cPlanner.visualize.spaceusage.SpaceUsage;
031: import org.griphyn.cPlanner.visualize.spaceusage.SpaceUsageCallback;
032: import org.griphyn.cPlanner.visualize.spaceusage.TailStatd;
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 PlotSpaceUsage 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 size units.
098: */
099: private String mSizeUnits;
100:
101: /**
102: * The time units.
103: */
104: private String mTimeUnits;
105:
106: /**
107: * The timing source used to order the events.
108: */
109: private String mTimingSource;
110:
111: /**
112: * A boolean indicating to use stat information for estimating
113: * directory sizes.
114: */
115: private boolean mUseStatInfo;
116:
117: /**
118: * Default constructor.
119: */
120: public PlotSpaceUsage() {
121: super ();
122: mLogMsg = new String();
123: mVersion = Version.instance().toString();
124: mOutputDir = this .DEFAULT_OUTPUT_DIR;
125: mLoggingLevel = 0;
126: mSizeUnits = "K";
127: mTimeUnits = null;
128: mBasename = "ploticus";
129: mTimingSource = this .DEFAULT_TIMING_SOURCE;
130: mUseStatInfo = false;
131: }
132:
133: /**
134: * The main program.
135: *
136: *
137: * @param args the main arguments passed to the plotter.
138: */
139: public static void main(String[] args) {
140:
141: PlotSpaceUsage me = new PlotSpaceUsage();
142: int result = 0;
143: double starttime = new Date().getTime();
144: double execTime = -1;
145:
146: try {
147: me.executeCommand(args);
148: } catch (FactoryException fe) {
149: me.log(fe.convertException(),
150: LogManager.FATAL_MESSAGE_LEVEL);
151: result = 2;
152: } catch (RuntimeException rte) {
153: //catch all runtime exceptions including our own that
154: //are thrown that may have chained causes
155: me.log(convertException(rte),
156: LogManager.FATAL_MESSAGE_LEVEL);
157: result = 1;
158: } catch (Exception e) {
159: //unaccounted for exceptions
160: me.log(e.getMessage(), LogManager.FATAL_MESSAGE_LEVEL);
161: e.printStackTrace();
162: result = 3;
163: } finally {
164: double endtime = new Date().getTime();
165: execTime = (endtime - starttime) / 1000;
166: }
167:
168: // warn about non zero exit code
169: if (result != 0) {
170: me.log("Non-zero exit-code " + result,
171: LogManager.WARNING_MESSAGE_LEVEL);
172: } else {
173: //log the time taken to execute
174: me.log("Time taken to execute is " + execTime + " seconds",
175: LogManager.INFO_MESSAGE_LEVEL);
176: }
177:
178: System.exit(result);
179: }
180:
181: /**
182: * Executes the command on the basis of the options specified.
183: *
184: * @param args the command line options.
185: */
186: public void executeCommand(String[] args) {
187: parseCommandLineArguments(args);
188:
189: //set logging level only if explicitly set by user
190: if (mLoggingLevel > 0) {
191: mLogger.setLevel(mLoggingLevel);
192: }
193:
194: //do sanity check on units
195: mSizeUnits = mSizeUnits.trim();
196: if (mSizeUnits.length() != 1) {
197: throw new RuntimeException(
198: "The valid size units can be K or M or G");
199: }
200:
201: //do sanity check on input directory
202: if (mInputDir == null) {
203: throw new RuntimeException(
204: "You need to specify the directory containing kickstart records");
205:
206: }
207: File dir = new File(mInputDir);
208: if (dir.isDirectory()) {
209: //see if it is readable
210: if (!dir.canRead()) {
211: throw new RuntimeException("Cannot read directory "
212: + mInputDir);
213: }
214: } else {
215: throw new RuntimeException(mInputDir
216: + " is not a directory ");
217: }
218:
219: //sanity check on output directory
220: dir = new File(mOutputDir);
221: if (dir.exists()) {
222: //directory already exists.
223: if (dir.isDirectory()) {
224: if (!dir.canWrite()) {
225: throw new RuntimeException(
226: "Cannot write out to output directory "
227: + mOutputDir);
228: }
229: } else {
230: //directory is a file
231: throw new RuntimeException(mOutputDir
232: + " is not a directory ");
233: }
234:
235: } else {
236: dir.mkdirs();
237: }
238:
239: KickstartParser su = new KickstartParser();
240:
241: //determing the callback on the basis of timing source
242: Callback c;
243: if (mTimingSource.equalsIgnoreCase(this .DEFAULT_TIMING_SOURCE)) {
244: c = new SpaceUsageCallback();
245: } else if (mTimingSource
246: .equalsIgnoreCase(this .TAILSTATD_TIMING_SOURCE)) {
247: c = new TailStatd();
248: } else {
249: throw new RuntimeException(
250: "No callback available for timing source"
251: + mTimingSource);
252: }
253: mLogger.log("Timing Source being used is " + mTimingSource,
254: LogManager.DEBUG_MESSAGE_LEVEL);
255: c.initialize(mInputDir, mUseStatInfo);
256: su.setCallback(c);
257:
258: //String dir = "/usr/sukhna/work/test/dags/ivdgl1/blackdiamond/run0004";
259: File directory = new File(mInputDir);
260: String[] files = directory
261: .list(new KickstartOutputFilenameFilter());
262: for (int i = 0; i < files.length; i++) {
263: String file = mInputDir + File.separator + files[i];
264:
265: try {
266: log("Parsing file " + file,
267: LogManager.DEBUG_MESSAGE_LEVEL);
268: su.parseKickstartFile(file);
269: } catch (IOException ioe) {
270: log("Unable to parse kickstart file " + file
271: + convertException(ioe),
272: LogManager.DEBUG_MESSAGE_LEVEL);
273: } catch (FriendlyNudge fn) {
274: log("Problem parsing file " + file
275: + convertException(fn),
276: LogManager.WARNING_MESSAGE_LEVEL);
277: }
278: }
279:
280: //we are done with parsing
281: c.done();
282:
283: SpaceUsage s = (SpaceUsage) c.getConstructedObject();
284: s.sort();
285: log(" Space Store is \n" + c.getConstructedObject(),
286: LogManager.DEBUG_MESSAGE_LEVEL);
287:
288: //generate the ploticus format
289: Plot plotter = new Ploticus();
290: plotter.initialize(mOutputDir, mBasename, mUseStatInfo);
291: try {
292: List result = plotter.plot(s, mSizeUnits.charAt(0),
293: mTimeUnits);
294:
295: for (Iterator it = result.iterator(); it.hasNext();) {
296: mLogger.log("Written out file " + it.next(),
297: LogManager.INFO_MESSAGE_LEVEL);
298: }
299: } catch (IOException ioe) {
300: log("Unable to plot the files " + convertException(ioe),
301: LogManager.DEBUG_MESSAGE_LEVEL);
302: }
303:
304: }
305:
306: /**
307: * Parses the command line arguments using GetOpt and returns a
308: * <code>PlannerOptions</code> contains all the options passed by the
309: * user at the command line.
310: *
311: * @param args the arguments passed by the user at command line.
312: */
313: public void parseCommandLineArguments(String[] args) {
314: LongOpt[] longOptions = generateValidOptions();
315:
316: Getopt g = new Getopt("plot-space-usage", args,
317: "b:i:o:s:t:T:uhvV", longOptions, false);
318: g.setOpterr(false);
319:
320: int option = 0;
321:
322: while ((option = g.getopt()) != -1) {
323: //System.out.println("Option tag " + (char)option);
324: switch (option) {
325:
326: case 'b'://the basename
327: this .mBasename = g.getOptarg();
328: break;
329:
330: case 'i'://dir
331: this .mInputDir = g.getOptarg();
332: break;
333:
334: case 'h'://help
335: printLongVersion();
336: System.exit(0);
337: return;
338:
339: case 'o'://output directory
340: this .mOutputDir = g.getOptarg();
341: break;
342:
343: case 's'://size-units
344: this .mSizeUnits = g.getOptarg();
345: break;
346:
347: case 't'://timing source
348: this .mTimingSource = g.getOptarg();
349: break;
350:
351: case 'T'://time units
352: this .mTimeUnits = g.getOptarg();
353: break;
354:
355: case 'u'://use-stat
356: this .mUseStatInfo = true;
357: break;
358:
359: case 'v'://verbose
360: mLoggingLevel++;
361: break;
362:
363: case 'V'://version
364: mLogger.log(getGVDSVersion(),
365: LogManager.INFO_MESSAGE_LEVEL);
366: System.exit(0);
367:
368: default: //same as help
369: printShortVersion();
370: throw new RuntimeException(
371: "Incorrect option or option usage "
372: + (char) option);
373:
374: }
375: }
376:
377: }
378:
379: /**
380: * Tt generates the LongOpt which contain the valid options that the command
381: * will accept.
382: *
383: * @return array of <code>LongOpt</code> objects , corresponding to the valid
384: * options
385: */
386: public LongOpt[] generateValidOptions() {
387: LongOpt[] longopts = new LongOpt[10];
388:
389: longopts[0] = new LongOpt("input", LongOpt.REQUIRED_ARGUMENT,
390: null, 'i');
391: longopts[1] = new LongOpt("output", LongOpt.REQUIRED_ARGUMENT,
392: null, 'o');
393: longopts[2] = new LongOpt("size-units",
394: LongOpt.REQUIRED_ARGUMENT, null, 's');
395: longopts[3] = new LongOpt("verbose", LongOpt.NO_ARGUMENT, null,
396: 'v');
397: longopts[4] = new LongOpt("help", LongOpt.NO_ARGUMENT, null,
398: 'h');
399: longopts[5] = new LongOpt("Version", LongOpt.NO_ARGUMENT, null,
400: 'V');
401: longopts[6] = new LongOpt("basename",
402: LongOpt.REQUIRED_ARGUMENT, null, 'b');
403: longopts[7] = new LongOpt("timing-source",
404: LongOpt.REQUIRED_ARGUMENT, null, 't');
405: longopts[8] = new LongOpt("use-stat", LongOpt.NO_ARGUMENT,
406: null, 'u');
407: longopts[9] = new LongOpt("time-units",
408: LongOpt.REQUIRED_ARGUMENT, null, 'T');
409: return longopts;
410: }
411:
412: /**
413: * Prints out a short description of what the command does.
414: */
415: public void printShortVersion() {
416: String text = "\n $Id: PlotSpaceUsage.java 50 2007-05-19 00:48:32Z gmehta $ "
417: + "\n "
418: + getGVDSVersion()
419: + "\n Usage : plot-space-usage [-Dprop [..]] -i <input directory> "
420: + " [-o output directory] [-b basename] [-s size units] [-t timing source] "
421: + " [-T time units] [-u] [-v] [-V] [-h]";
422:
423: System.out.println(text);
424: }
425:
426: /**
427: * Prints the long description, displaying in detail what the various options
428: * to the command stand for.
429: */
430: public void printLongVersion() {
431:
432: String text = "\n $Id: PlotSpaceUsage.java 50 2007-05-19 00:48:32Z gmehta $ "
433: + "\n "
434: + getGVDSVersion()
435: + "\n plot-space-usage - A plotting tool that plots out the space usage on remote clusters over time"
436: + "\n Usage: plot_space_usage [-Dprop [..]] --dir <input directory> [--base basename] "
437: + "\n [--output output directory] [--timing-source source] [--use-stat] [--verbose] [--Version] [--help] "
438: + "\n"
439: + "\n Mandatory Options "
440: + "\n --input the directory where the kickstart records reside."
441: + "\n Other Options "
442: + "\n -b |--basename the basename prefix for constructing the ploticus files."
443: + "\n -o |--output the output directory where to generate the ploticus files."
444: + "\n -s |--size-units the units in which you want the filesizes to be plotted (can be K or M or G)."
445: + "\n -t |--timing-source the source from which the ordering of events is determined. "
446: + "\n Can be kickstart or tailstatd. Defaults to kickstart."
447: + "\n -T |--time-units the units in which you want the x axis to be plotted (seconds|minutes|hours) Defaults to seconds."
448: + "\n -u |--use-stat use the file stat information in kickstart records to estimate directory usage"
449: + "\n -v |--verbose increases the verbosity of messages about what is going on"
450: + "\n -V |--version displays the version of the Pegasus Workflow Planner"
451: + "\n -h |--help generates this help."
452: + "\n The following exitcodes are produced"
453: + "\n 0 plotter was able to generate plots"
454: + "\n 1 an error occured. In most cases, the error message logged should give a"
455: + "\n clear indication as to where things went wrong."
456: + "\n 2 an error occured while loading a specific module implementation at runtime"
457: + "\n ";
458:
459: System.out.println(text);
460: //mLogger.log(text,LogManager.INFO_MESSAGE_LEVEL);
461: }
462:
463: /**
464: * Loads all the properties that would be needed by the Toolkit classes.
465: */
466: public void loadProperties() {
467: //empty for time being
468: }
469:
470: }
|