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.visualize.nodeusage;
017:
018: import org.griphyn.cPlanner.common.LogManager;
019:
020: import org.griphyn.cPlanner.visualize.WorkflowMeasurements;
021: import org.griphyn.cPlanner.visualize.Measurement;
022:
023: import java.util.List;
024: import java.util.Iterator;
025:
026: import java.io.PrintWriter;
027: import java.io.FileWriter;
028: import java.io.File;
029: import java.io.IOException;
030:
031: import java.util.List;
032: import java.util.ArrayList;
033:
034: import java.text.NumberFormat;
035: import java.text.DecimalFormat;
036:
037: /**
038: * An implementation that plots in the Ploticus format.
039: *
040: * @author Karan Vahi
041: * @version $Revision: 50 $
042: */
043:
044: public class Ploticus {
045:
046: /**
047: * The default timing units.
048: */
049: public static final String DEFAULT_TIMING_UNITS = "seconds";
050:
051: /**
052: * The minutes unit for the x axis.
053: */
054: public static final String MINUTES_TIMING_UNITS = "minutes";
055:
056: /**
057: * The minutes unit for the x axis.
058: */
059: public static final String HOURS_TIMING_UNITS = "hours";
060:
061: /**
062: * The directory where the files are to be generated.
063: *
064: */
065: private String mDirectory;
066:
067: /**
068: * The basename of the files.
069: */
070: private String mBasename;
071:
072: /**
073: * A boolean indicating whether to use stat info or not.
074: */
075: private boolean mUseStatInfo;
076:
077: /**
078: * The handle to the logging object.
079: */
080: private LogManager mLogger;
081:
082: /**
083: * The number formatter to format the float entries.
084: */
085: private NumberFormat mNumFormatter;
086:
087: /**
088: * The time units.
089: */
090: private String mTimeUnits;
091:
092: /**
093: * The default constructor.
094: *
095: */
096: public Ploticus() {
097: mLogger = LogManager.getInstance();
098: mDirectory = ".";
099: mBasename = "ploticus";
100: mNumFormatter = new DecimalFormat("0.000");
101: mTimeUnits = this .DEFAULT_TIMING_UNITS;
102: }
103:
104: /**
105: * Initializer method.
106: *
107: * @param directory the directory where the plots need to be generated.
108: * @param basename the basename for the files that are generated.
109: * @param useStatInfo boolean indicating whether to use stat info or not.
110: */
111: public void initialize(String directory, String basename,
112: boolean useStatInfo) {
113: mDirectory = directory;
114: mBasename = basename;
115: mUseStatInfo = useStatInfo;
116: }
117:
118: /**
119: * Plot out the space usage. Writes out a Ploticus data file.
120: *
121: * @param wm the workflow measurements.
122: * @param unit the unit in which we need to plot the number.
123: * @param timeUnits units in which to plot time.
124: *
125: * @return List of file pathnames for the files that are written out.
126: *
127: * @exception IOException in case of unable to write to the file.
128: */
129: public List plot(WorkflowMeasurements wm, char unit,
130: String timeUnits) throws IOException {
131: //first let us sort on the timestamps
132: wm.sort();
133:
134: String site;
135:
136: List result = new ArrayList(2);
137:
138: //sanity check on time units
139: mTimeUnits = (timeUnits == null) ? this .DEFAULT_TIMING_UNITS
140: : timeUnits;
141:
142: //go thru space usage for each site.
143: for (Iterator it = wm.siteIterator(); it.hasNext();) {
144: site = (String) it.next();
145:
146: String dataFile = getFilename(site, "_nu.dat");
147: String scriptFile = getFilename(site, "_nu.pl");
148: result.add(dataFile);
149: result.add(scriptFile);
150:
151: PrintWriter dataPW = new PrintWriter(new FileWriter(
152: dataFile));
153: mLogger.log("Will write out to " + dataFile + ","
154: + scriptFile, LogManager.DEBUG_MESSAGE_LEVEL);
155:
156: long min = 0;
157: boolean first = true;
158: long absTime, time = 0; //in seconds
159: long currJobs = 0;
160: long maxJobs = 0;
161: float cTime = 0;
162:
163: //go through space usage for a particular site
164: for (Iterator sizeIT = wm.getMeasurements(site).iterator(); sizeIT
165: .hasNext();) {
166: Measurement m = (Measurement) sizeIT.next();
167: absTime = m.getTime().getTime();
168: currJobs = ((Integer) m.getValue()).intValue();
169:
170: if (first) {
171: min = absTime;
172: first = false;
173: }
174:
175: //calculate the relative time in seconds
176: time = (absTime - min) / 1000;
177:
178: //convert time from seconds to units specified
179: cTime = convertFromSecondsTo(time, timeUnits);
180:
181: //update the max space
182: if (currJobs > maxJobs) {
183: maxJobs = currJobs;
184: }
185:
186: //log the entry in the data file.
187: String entry = constructEntry(m.getJobName(), cTime,
188: currJobs);
189: mLogger.log(entry, LogManager.DEBUG_MESSAGE_LEVEL);
190: dataPW.println(entry);
191:
192: }
193:
194: //the value in time right now it the max time
195: generateScriptFile(scriptFile, dataFile,
196: new Character(unit).toString(), cTime, maxJobs);
197:
198: //close and flush to file per site
199: dataPW.close();
200: }
201:
202: return result;
203: }
204:
205: /**
206: * Generates the script file required to give as input to ploticus.
207: *
208: * @param name the path to the script file.
209: * @param dataFile the path to corresponding data file.
210: * @param yUnits the units for the space value.
211: * @param maxX the time in seconds.
212: * @param maxY the maximum space.
213: */
214: public void generateScriptFile(String name, String dataFile,
215: String yUnits, float maxX, float maxY) throws IOException {
216:
217: PrintWriter writer = new PrintWriter(new FileWriter(name));
218:
219: //write the page proc
220: writer.println("#proc page");
221: writer.println("#if @DEVICE in png,gif");
222: writer.println("\t scale: 0.6");
223: writer.println("#endif");
224: writer.println();
225:
226: //write the getdata proc
227: writer.println("#proc getdata");
228: writer.print("file: ");
229: writer.println(new File(dataFile).getName());
230: writer.println(" fieldnames: time number_of_jobs");
231: writer.println();
232:
233: //write out area defn
234: writer.println("#proc areadef");
235: writer.println("title: Number of jobs running over time");
236: writer.println("titledetails: size=14 align=C");
237: writer.println("rectangle: 1 1 8 4");
238:
239: /* we let ploticus worry about ranges */
240: // writer.print( "xrange: 0 " );
241: // //round to the latest 100
242: // long modTime = ( maxTime/100 + 1 )* 100 ;
243: // //round space to latest 100 if > 0
244: // float modSpace = maxSpace > 1 ?
245: // (new Float(maxSpace/100).intValue() + 1)* 100:
246: // maxSpace;
247: // writer.println( modTime );
248: // writer.print( "yrange: 0 " );
249: // writer.println( modSpace );
250: // writer.println();
251: writer.println("xautorange datafield=1");
252: writer.println("yautorange datafield=2 lowfix=0");//y axis always starts from 0
253: //round to the latest 100
254: float modTime = (maxX / 100 + 1) * 100;
255: //round space to latest 100 if > 0
256: float modSpace = maxY > 1 ? (new Float(maxY / 10).intValue() + 1) * 10
257: : maxY;
258:
259: //we want 15-16 points on the x axis
260: float xIncrement = ((modTime / 150) + 1) * 10;
261: writer.println("#proc xaxis");
262: writer.print("stubs: inc ");
263: writer.println(xIncrement);
264: writer.print("minorticinc: ");
265: writer.println(xIncrement / 2);
266: writer.print("label: time in ");
267: writer.println(mTimeUnits);
268: writer.println();
269:
270: //we want 10 points on the y axis
271: float yIncrement = modSpace / 10;
272: writer.println("#proc yaxis");
273: writer.print("stubs: inc ");
274: writer.println(yIncrement);
275: writer.print("minorticinc: ");
276: writer.println(yIncrement / 2);
277: writer.println("gridskip: min");
278: //writer.println( "ticincrement: 100 1000" );
279: writer.println("label: number of jobs running ");
280: writer.println();
281:
282: writer.println("#proc lineplot");
283: writer.println("xfield: time");
284: writer.println("yfield: number_of_jobs");
285: writer.println("linedetails: color=blue width=.5");
286: writer.println();
287:
288: writer.println("#proc legend");
289: writer.println("location: max-1 max");
290: writer.println("seglen: 0.2");
291:
292: writer.close();
293: }
294:
295: /**
296: * Returns the filename of the ploticus file to be generated.
297: *
298: * @param site the site handle.
299: * @param suffix the suffix to be applied to the file.
300: *
301: * @return the path to the file.
302: */
303: protected String getFilename(String site, String suffix) {
304: StringBuffer sb = new StringBuffer();
305: sb.append(mDirectory).append(File.separator).append(mBasename)
306: .append("-").append(site).append(suffix);
307:
308: return sb.toString();
309: }
310:
311: /**
312: * Returns an entry that needs to be plotted in the graph.
313: *
314: * @param jobname the name of the associated job.
315: * @param time the time
316: * @param measurement measurement
317: *
318: * @return the entry to be logged
319: */
320: protected String constructEntry(String job, float time,
321: long measurement) {
322:
323: StringBuffer sb = new StringBuffer();
324: sb.append(mNumFormatter.format(time)).append("\t").append(
325: measurement).append("\t").append(job);
326:
327: return sb.toString();
328: }
329:
330: /**
331: * Converts from seconds to one of the units specified.
332: *
333: * @param time the time.
334: * @param units the units
335: *
336: * @return converted value in long.
337: */
338: private float convertFromSecondsTo(long time, String units) {
339: if (!validTimeUnits(units)) {
340: throw new RuntimeException("Unsupported time units "
341: + units);
342: }
343:
344: if (units == this .DEFAULT_TIMING_UNITS) {
345: return time;
346: }
347:
348: float result;
349:
350: float factor = (units.equals(this .MINUTES_TIMING_UNITS)) ? 60
351: : (units.equals(HOURS_TIMING_UNITS)) ? 3600 : -1;
352:
353: result = (time / (int) factor + (time % factor) / factor);
354:
355: return result;
356: }
357:
358: /**
359: * Returns a boolean indicating if a valid time unit or not.
360: *
361: * @param unit the time unit.
362: *
363: * @return boolean
364: */
365: private boolean validTimeUnits(String units) {
366:
367: return (units.equals(this.DEFAULT_TIMING_UNITS)
368: || units.equals(this.MINUTES_TIMING_UNITS) || units
369: .equals(this.HOURS_TIMING_UNITS));
370:
371: }
372:
373: }
|