From c311abce8ae54d2c3b3c0bd0ee3ad2a1f5b8f39d Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Wed, 30 Oct 2024 11:57:37 -0500 Subject: [PATCH] Break up and document the classes that compose JobPerf. --- .../java/trick/jobperf/JobExecutionEvent.java | 50 ++ .../src/main/java/trick/jobperf/JobPerf.java | 769 +----------------- .../src/main/java/trick/jobperf/JobStats.java | 184 +++++ .../java/trick/jobperf/KeyedColorMap.java | 123 +++ .../main/java/trick/jobperf/RunRegistry.java | 73 ++ .../java/trick/jobperf/StatisticsRecord.java | 28 + .../src/main/java/trick/jobperf/TimeSpan.java | 24 + .../java/trick/jobperf/TraceViewCanvas.java | 281 +++++++ .../trick/jobperf/TraceViewInputToolBar.java | 59 ++ .../java/trick/jobperf/TraceViewMenuBar.java | 72 ++ .../trick/jobperf/TraceViewOutputToolBar.java | 56 ++ .../java/trick/jobperf/TraceViewWindow.java | 60 ++ 12 files changed, 1041 insertions(+), 738 deletions(-) create mode 100644 trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/JobStats.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/KeyedColorMap.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/RunRegistry.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/StatisticsRecord.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/TimeSpan.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/TraceViewMenuBar.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/TraceViewOutputToolBar.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/TraceViewWindow.java diff --git a/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java b/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java new file mode 100644 index 00000000..180a2677 --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java @@ -0,0 +1,50 @@ +package trick.jobperf; + +import java.awt.*; +import java.awt.event.*; +import java.awt.image.BufferedImage; +import java.io.*; +import java.lang.Math; +import java.util.*; +import java.util.List; +import javax.swing.*; +import javax.swing.event.*; +import java.net.URL; + + +/** +* Class JobExecutionEvent represents one execution/run of a Trick job. +* identifies the job. and specify the +* clock times at which the job started and finished. +* and indicate whether the job was run as +* an "end-of-frame", or a "top-of-frame" job. +*/ +class JobExecutionEvent { + public String id; + public boolean isEOF; + public boolean isTOF; + public double start; + public double stop; + + /** + * @param identifier identifies the relavant Trick job. + * @param isTopOfFrame true if the job is a "top-of-frame" job, otherwise false. + * @param isEndOfFrame true if the job is a "end-of-frame" job, otherwise false. + * @param start_time the start time (seconds) of the identified job. + * @param stop_time the stop time (seconds) of the identified job. + */ + public JobExecutionEvent(String identifier, boolean isTopOfFrame, boolean isEndOfFrame, double start_time, double stop_time) { + id = identifier; + isEOF = isEndOfFrame; + isTOF = isTopOfFrame; + start = start_time; + stop = stop_time; + } + /** + * Create a String representation of an object of this class. + */ + @Override + public String toString() { + return ( "JobExecutionEvent: " + id + "," + start + "," + stop ); + } +} diff --git a/trick_source/java/src/main/java/trick/jobperf/JobPerf.java b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java index 72426b20..b1169f9b 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobPerf.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java @@ -1,737 +1,23 @@ package trick.jobperf; import java.awt.*; -import java.awt.event.*; -import java.awt.image.BufferedImage; import java.io.*; -import java.lang.Math; import java.util.*; -import java.util.List; import javax.swing.*; -import javax.swing.event.*; - -class JobExecutionEvent { - public String id; - public boolean isEOF; - public boolean isTOF; - public double start; - public double stop; - - public JobExecutionEvent(String identifier, boolean isTopOfFrame, boolean isEndOfFrame, double start_time, double stop_time) { - id = identifier; - isEOF = isEndOfFrame; - isTOF = isTopOfFrame; - start = start_time; - stop = stop_time; - } - - public String toString() { - return ( "JobExecutionEvent: " + id + "," + start + "," + stop ); - } -} - -class KeyedColorMap { - private Map colorMap; - int minColorIntensity; - - public KeyedColorMap() { - colorMap = new HashMap(); - minColorIntensity = 100; - } - - private Color generateColor () { - Random rand = new Random(); - boolean found = false; - int R = 0; - int G = 0; - int B = 0; - - while (!found) { - R = rand.nextInt(256); - G = rand.nextInt(256); - B = rand.nextInt(256); - found = true; - if ((R < minColorIntensity) && (G < minColorIntensity) && (B < minColorIntensity)) { - found = false; - } - } - return new Color( R,G,B); - } - - public void addKey( String identifier ) { - if (!colorMap.containsKey(identifier)) { - colorMap.put(identifier, generateColor()); - } - } - - // Given the key, return the color. - public Color getColor(String identifier) { - return colorMap.get(identifier); - } - - // Given the color, return the key. - public String getKeyOfColor(Color search_color) { - for (Map.Entry entry : colorMap.entrySet()) { - String id = entry.getKey(); - Color color = entry.getValue(); - if (color.getRGB() == search_color.getRGB()) { - return id; - } - } - return null; - } - - public void readFile(String fileName) throws IOException { - try { - BufferedReader in = new BufferedReader( new FileReader(fileName) ); - String line; - String field[]; - - while( (line = in.readLine()) !=null) { - field = line.split(","); - String id = field[0]; - int R = Integer.parseInt( field[1]); - int G = Integer.parseInt( field[2]); - int B = Integer.parseInt( field[3]); - colorMap.put(id, new Color(R,G,B)); - } - in.close(); - } catch ( java.io.FileNotFoundException e ) { - System.out.println("File \"" + fileName + "\" not found.\n"); - } - } - - public void writeFile(String fileName) throws IOException { - BufferedWriter out = new BufferedWriter( new FileWriter(fileName) ); - for (Map.Entry entry : colorMap.entrySet()) { - String id = entry.getKey(); - Color color = entry.getValue(); - String line = String.format(id + "," + color.getRed() + - "," + color.getGreen() + - "," + color.getBlue() + "\n"); - out.write(line, 0, line.length()); - } - out.flush(); - out.close(); - } -} // KeyedColorMap - -class TraceViewCanvas extends JPanel { - - public static final int MIN_TRACE_WIDTH = 4; - public static final int DEFAULT_TRACE_WIDTH = 10; - public static final int MAX_TRACE_WIDTH = 30; - public static final int LEFT_MARGIN = 100; - public static final int RIGHT_MARGIN = 100; - public static final int TOP_MARGIN = 20; - public static final int BOTTOM_MARGIN = 20; - - private int traceWidth; - private double frameDuration; - private List jobExecList; - private KeyedColorMap idToColorMap; - private BufferedImage image; - private TraceViewOutputToolBar sToolBar; - private Cursor crossHairCursor; - private Cursor defaultCursor; - - public TraceViewCanvas( ArrayList jobExecEvtList, TraceViewOutputToolBar outputToolBar ) { - - traceWidth = DEFAULT_TRACE_WIDTH; - frameDuration = 1.0; - image = null; - sToolBar = outputToolBar; - jobExecList = jobExecEvtList; - crossHairCursor = new Cursor( Cursor.CROSSHAIR_CURSOR ); - defaultCursor = new Cursor( Cursor.DEFAULT_CURSOR ); - double smallestStart = Double.MAX_VALUE; - double largestStop = -Double.MAX_VALUE; - - try { - idToColorMap = new KeyedColorMap(); - idToColorMap.readFile("IdToColors.txt"); - - boolean wasTOF = false; - double startOfFrame = 0.0; - double lastStartOfFrame = 0.0; - double frameSizeSum = 0.0; - int frameNumber = 0; - int frameSizeCount = 0; - - for (JobExecutionEvent jobExec : jobExecList ) { - if (jobExec.start < smallestStart) smallestStart = jobExec.start; - if (jobExec.stop > largestStop) largestStop = jobExec.stop; - // Calculate the average frame size. - if (!wasTOF && jobExec.isTOF) { - startOfFrame = jobExec.start; - if (frameNumber > 0) { - double frameSize = (startOfFrame - lastStartOfFrame); - frameSizeSum += frameSize; - frameSizeCount ++; - } - lastStartOfFrame = startOfFrame; - frameNumber++; - } - wasTOF = jobExec.isTOF; - idToColorMap.addKey(jobExec.id); - } - - // Calculate the average frame size. - frameDuration = frameSizeSum / frameSizeCount; - idToColorMap.writeFile("IdToColors.txt"); - - System.out.println("File loaded.\n"); - } catch ( java.io.FileNotFoundException e ) { - System.out.println("File not found.\n"); - System.exit(0); - } catch ( java.io.IOException e ) { - System.out.println("IO Exception.\n"); - System.exit(0); - } - - int preferredHeight = traceWidth * (int)((largestStop - smallestStart) / frameDuration) + TOP_MARGIN; - setPreferredSize(new Dimension(500, preferredHeight)); - - ViewListener viewListener = new ViewListener(); - addMouseListener(viewListener); - addMouseMotionListener(viewListener); - } - - public double getFrameDuration() { - return frameDuration; - } - - public void setFrameDuration(double duration) { - frameDuration = duration; - repaint(); - } - - public void increaseTraceWidth() { - if (traceWidth < MAX_TRACE_WIDTH) { - traceWidth ++; - repaint(); - } - } - - public void decreaseTraceWidth() { - if (traceWidth > MIN_TRACE_WIDTH) { - traceWidth --; - repaint(); - } - } - - private boolean traceRectContains(int x, int y) { - int traceRectXMax = getWidth() - RIGHT_MARGIN; - if ( x < (LEFT_MARGIN)) return false; - if ( x > (traceRectXMax)) return false; - if ( y < TOP_MARGIN) return false; - return true; - } - - private boolean timeRectContains(int x, int y) { - int timeRectXMin = 30; - int timeRectXMax = LEFT_MARGIN; - if ( x < 30 ) return false; - if ( x > LEFT_MARGIN) return false; - if ( y < TOP_MARGIN) return false; - return true; - } - - private class ViewListener extends MouseInputAdapter { - public void mouseReleased(MouseEvent e) { - int x = e.getX(); - int y = e.getY(); - Color color = new Color ( image.getRGB(x,y) ); - - String id = idToColorMap.getKeyOfColor( color ); - sToolBar.setJobID(id); - - if ( y > TOP_MARGIN) { - int frameNumber = (y - TOP_MARGIN) / traceWidth; - sToolBar.setFrameNumber(frameNumber); - } - if ( traceRectContains(x, y)) { - double pixelsPerSecond = (double)calcTraceRectWidth() / frameDuration; - double subFrameTime = (x - LEFT_MARGIN) / pixelsPerSecond; - sToolBar.setSubFrameTime(subFrameTime); - } - } - - public void mouseMoved(MouseEvent e) { - int x = e.getX(); - int y = e.getY(); - if ( traceRectContains(x, y)) { - setCursor(crossHairCursor); - } else { - setCursor(defaultCursor); - } - } - } - - private int calcTraceRectHeight() { - return ( getHeight() - TOP_MARGIN - BOTTOM_MARGIN); - } - - private int calcTraceRectWidth() { - return ( getWidth() - LEFT_MARGIN - RIGHT_MARGIN); - } - - private void doDrawing(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - - RenderingHints rh = new RenderingHints( - RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - - rh.put(RenderingHints.KEY_RENDERING, - RenderingHints.VALUE_RENDER_QUALITY); - - int traceRectHeight = calcTraceRectHeight(); - int traceRectWidth = calcTraceRectWidth(); - double pixelsPerSecond = (double)traceRectWidth / frameDuration; - - // Panel Background Color Fill - g2d.setPaint(Color.WHITE); - g2d.fillRect(0, 0, getWidth(), getHeight()); - - // Frame Trace Rectangle Fill - g2d.setPaint(Color.BLACK); - g2d.fillRect(LEFT_MARGIN, TOP_MARGIN, traceRectWidth, traceRectHeight); - - boolean wasEOF = false; - boolean wasTOF = false; - double startOfFrame = 0.0; - int frameNumber = 0; - - for (JobExecutionEvent jobExec : jobExecList ) { - - if (!wasTOF && jobExec.isTOF) { - startOfFrame = jobExec.start; - frameNumber ++; - } - - wasTOF = jobExec.isTOF; - wasEOF = jobExec.isEOF; - - int jobY = TOP_MARGIN + frameNumber * traceWidth; - int jobStartX = LEFT_MARGIN + (int)((jobExec.start - startOfFrame) * pixelsPerSecond); - int jobWidth = (int)( (jobExec.stop - jobExec.start) * pixelsPerSecond); - - g2d.setPaint(Color.BLACK); - g2d.drawString ( String.format("%8.3f", startOfFrame), 30, jobY + traceWidth/2); - g2d.setPaint( idToColorMap.getColor( jobExec.id ) ); - g2d.fillRect(jobStartX, jobY, jobWidth, traceWidth-2); - - } // for - } // doDrawing - - @Override - public void paintComponent(Graphics g) { - super.paintComponent(g); - image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB); - Graphics2D g2 = image.createGraphics(); - doDrawing(g2); - g.drawImage(image, 0, 0, this); - g2.dispose(); - } -} // class TraceViewCanvas - -class TraceViewInputToolBar extends JToolBar implements ActionListener { - - private TraceViewCanvas traceView; - private JTextField frameDurationField; - - public TraceViewInputToolBar (TraceViewCanvas tv) { - traceView = tv; - add( new JLabel(" Frame Size: ")); - frameDurationField = new JTextField(15); - frameDurationField.setText( String.format("%8.4f", traceView.getFrameDuration()) ); - add(frameDurationField); - - JButton setButton = new JButton("Set"); - setButton.addActionListener(this); - setButton.setActionCommand("setFrameSize"); - setButton.setToolTipText("Set frame size in seconds."); - add(setButton); - } - public void actionPerformed(ActionEvent event) { - String s = event.getActionCommand(); - switch (s) { - case "setFrameSize": - double newFrameSize = 0.0; - try { - newFrameSize = Double.parseDouble( frameDurationField.getText() ); - } catch ( NumberFormatException e) { - frameDurationField.setText( String.format("%8.4f", traceView.getFrameDuration()) ); - } - if ( newFrameSize > 0.0) { - traceView.setFrameDuration( newFrameSize ); - } - break; - default: - System.out.println("Unknown Action Command:" + s); - break; - } - } -} // class TraceViewInputToolBar - -class TraceViewOutputToolBar extends JToolBar { - private JTextField IDField; - private JTextField frameNumberField; - private JTextField subFrameTimeField; - - public TraceViewOutputToolBar () { - - add( new JLabel(" Job ID: ")); - IDField = new JTextField(15); - IDField.setEditable(false); - IDField.setText( ""); - add(IDField); - - add( new JLabel(" Frame Number: ")); - frameNumberField = new JTextField(15); - frameNumberField.setEditable(false); - frameNumberField.setText( "0"); - add(frameNumberField); - - add( new JLabel(" Subframe Time: ")); - subFrameTimeField = new JTextField(15); - subFrameTimeField.setEditable(false); - subFrameTimeField.setText( "0.00"); - add(subFrameTimeField); - } - public void setJobID(String id) { - IDField.setText( id ); - } - public void setFrameNumber(int fn) { - frameNumberField.setText( String.format("%d", fn)); - } - public void setSubFrameTime(double time) { - subFrameTimeField.setText( String.format("%8.4f", time)); - } -} // class TraceViewOutputToolBar - -class TraceViewMenuBar extends JMenuBar implements ActionListener { - - private TraceViewCanvas traceView; - - public TraceViewMenuBar(TraceViewCanvas tv) { - traceView = tv; - - JMenu fileMenu = new JMenu("File"); - JMenuItem fileMenuExit = new JMenuItem("Exit"); - fileMenuExit.setActionCommand("exit"); - fileMenuExit.addActionListener(this); - fileMenu.add(fileMenuExit); - add(fileMenu); - - JMenu optionsMenu = new JMenu("Options"); - JMenu traceSizeMenu = new JMenu("TraceSize"); - JMenuItem traceSizeMenuIncrease = new JMenuItem("Increase Trace Width"); - traceSizeMenuIncrease.setActionCommand("increase-trace_width"); - KeyStroke ctrlPlus = KeyStroke.getKeyStroke('P', InputEvent.CTRL_MASK ); - traceSizeMenuIncrease.setAccelerator(ctrlPlus); - traceSizeMenuIncrease.addActionListener(this); - traceSizeMenu.add(traceSizeMenuIncrease); - JMenuItem traceSizeMenuDecrease = new JMenuItem("Decrease Trace Width"); - traceSizeMenuDecrease.setActionCommand("decrease-trace_width"); - KeyStroke ctrlMinus = KeyStroke.getKeyStroke('-', InputEvent.CTRL_MASK); - traceSizeMenuDecrease.setAccelerator(ctrlMinus); - traceSizeMenuDecrease.addActionListener(this); - traceSizeMenu.add(traceSizeMenuDecrease); - optionsMenu.add(traceSizeMenu); - add(optionsMenu); - - } - public void actionPerformed(ActionEvent e) { - String s = e.getActionCommand(); - switch (s) { - case "increase-trace_width": - traceView.increaseTraceWidth(); - break; - case "decrease-trace_width": - traceView.decreaseTraceWidth(); - break; - case "exit": - System.exit(0); - default: - System.out.println("Unknown Action Command:" + s); - break; - } - } -} // class TraceViewMenuBar - -class TraceViewWindow extends JFrame { - - public TraceViewWindow( ArrayList jobExecList ) { - TraceViewOutputToolBar outputToolBar = new TraceViewOutputToolBar(); - TraceViewCanvas traceView = new TraceViewCanvas( jobExecList, outputToolBar); - - TraceViewMenuBar menuBar = new TraceViewMenuBar(traceView); - setJMenuBar(menuBar); - - TraceViewInputToolBar nToolBar = new TraceViewInputToolBar( traceView ); - add(nToolBar, BorderLayout.NORTH); - - JScrollPane scrollPane = new JScrollPane( traceView ); - scrollPane.setPreferredSize(new Dimension(800, 400)); - - JPanel tracePanel = new JPanel(); - tracePanel.setPreferredSize(new Dimension(800, 400)); - tracePanel.add(scrollPane); - tracePanel.setLayout(new BoxLayout(tracePanel, BoxLayout.X_AXIS)); - - JPanel mainPanel = new JPanel(); - mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); - mainPanel.add(tracePanel); - - add(outputToolBar, BorderLayout.SOUTH); - - setTitle("JobPerf"); - setSize(800, 500); - add(mainPanel); - pack(); - setVisible(true); - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - setFocusable(true); - setVisible(true); - - traceView.repaint(); - } -} // class TraceViewWindow - -class Interval { - public double start; - public double stop; - public Interval( double begin, double end) { - start = begin; - stop = end; - } - public double getDuration() { - return stop - start; - } -} // Interval - -class RunRegistry { - ArrayList intervalList; - - public RunRegistry() { - intervalList = new ArrayList(); - } - void addSample(double start, double stop) { - Interval interval = new Interval(start, stop); - intervalList.add(interval); - } - double getMeanDuration() { - double mean = 0.0; - int N = intervalList.size(); - if (N > 0) { - double sum = 0.0; - for (Interval interval : intervalList ) { - sum += interval.getDuration(); - } - mean = sum / N; - } - return mean; - } - double getStdDev() { - double stddev = 0.0; - int N = intervalList.size(); - if (N > 0) { - double sum = 0.0; - double mean = getMeanDuration(); - for (Interval interval : intervalList ) { - double duration = interval.getDuration(); - double difference = duration - mean; - sum += difference * difference; - } - stddev = Math.sqrt( sum / N ); - } - return stddev; - } - double getMaxDuration() { - double maxDuration = Double.MIN_VALUE; - for (Interval interval : intervalList ) { - double duration = interval.getDuration(); - if (duration > maxDuration) { - maxDuration = duration; - } - } - return maxDuration; - } - double getMinDuration() { - double minDuration = Double.MAX_VALUE; - for (Interval interval : intervalList ) { - double duration = interval.getDuration(); - if (duration < minDuration) { - minDuration = duration; - } - } - return minDuration; - } -} // RunRegistry - -class StatisticsRecord { - public String id; - public double meanValue; - public double stddev; - public double maxValue; - public double minValue; - public StatisticsRecord( String s, double mean, double sd, double min, double max) { - id = s; - meanValue = mean; - stddev = sd; - minValue = min; - maxValue = max; - } -} // StatisticsRecord - -class CompareByID implements Comparator { - public int compare(StatisticsRecord a, StatisticsRecord b) { - return a.id.compareTo(b.id); - } -} // CompareByID - -class CompareByMeanValue implements Comparator { - public int compare(StatisticsRecord a, StatisticsRecord b) { - if ( a.meanValue < b.meanValue) return -1; - if ( a.meanValue > b.meanValue) return 1; - return 0; - } -} // CompareByMeanValue - -class CompareByStdDev implements Comparator { - public int compare(StatisticsRecord a, StatisticsRecord b) { - if ( a.stddev < b.stddev) return -1; - if ( a.stddev > b.stddev) return 1; - return 0; - } -} // CompareByStdDev - -class CompareByMaxDuration implements Comparator { - public int compare(StatisticsRecord a, StatisticsRecord b) { - if ( a.maxValue < b.maxValue) return -1; - if ( a.maxValue > b.maxValue) return 1; - return 0; - } -} // CompareByMaxDuration - -class CompareByMinDuration implements Comparator { - public int compare(StatisticsRecord a, StatisticsRecord b) { - if ( a.minValue < b.minValue) return -1; - if ( a.minValue > b.minValue) return 1; - return 0; - } -} // CompareByMinDuration - -class JobStats { - - enum SortCriterion { - ID { - @Override - public String toString() { return "Identifier"; } - }, - MEAN { - @Override - public String toString() { return "Mean Value"; } - }, - STDDEV { - @Override - public String toString() { return "Standard Deviation"; } - }, - MAX { - @Override - public String toString() { return "Maximum Value"; } - }, - MIN { - @Override - public String toString() { return "Minimum Value"; } - } - } - - SortCriterion currentSortCriterion = SortCriterion.MEAN; - ArrayList jobStatisticsList; - - public JobStats( ArrayList jobExecList ) { - - Map runRegistryMap - = new HashMap(); - - for (JobExecutionEvent jobExec : jobExecList ) { - RunRegistry runRegistry = runRegistryMap.get(jobExec.id); - if (runRegistry != null) { - runRegistry.addSample(jobExec.start, jobExec.stop); - } else { - runRegistry = new RunRegistry(); - runRegistry.addSample(jobExec.start, jobExec.stop); - runRegistryMap.put(jobExec.id, runRegistry); - } - } - - jobStatisticsList = new ArrayList(); - - for (Map.Entry entry : runRegistryMap.entrySet()) { - String id = entry.getKey(); - RunRegistry register = entry.getValue(); - double mean = register.getMeanDuration(); - double stddev = register.getStdDev(); - double min = register.getMinDuration(); - double max = register.getMaxDuration(); - - jobStatisticsList.add( new StatisticsRecord(id, mean, stddev, min, max)); - } - } - - // Sort by MeanDuration in descending order. - public void SortByID() { - Collections.sort( jobStatisticsList, new CompareByID()); - currentSortCriterion = SortCriterion.ID; - } - - // Sort by MeanDuration in descending order. - public void SortByMeanValue() { - Collections.sort( jobStatisticsList, Collections.reverseOrder( new CompareByMeanValue())); - currentSortCriterion = SortCriterion.MEAN; - } - - // Sort by Standard Deviation of duration in descending order. - public void SortByStdDev() { - Collections.sort( jobStatisticsList, Collections.reverseOrder( new CompareByStdDev())); - currentSortCriterion = SortCriterion.STDDEV; - } - - // Sort by MaxDuration in descending order. - public void SortByMaxValue() { - Collections.sort( jobStatisticsList, Collections.reverseOrder( new CompareByMaxDuration())); - currentSortCriterion = SortCriterion.MAX; - } - - // Sort by MinDuration in descending order. - public void SortByMinValue() { - Collections.sort( jobStatisticsList, Collections.reverseOrder( new CompareByMinDuration())); - currentSortCriterion = SortCriterion.MIN; - } - - public void write() { - System.out.println(" [Job Duration Statistics Sorted by " + currentSortCriterion +"]"); - System.out.println("----------------------------------------------------------------------"); - System.out.println(" Job Id Mean Duration Std Dev Min Duration Max Duration"); - System.out.println("---------- -------------- -------------- -------------- --------------"); - for (StatisticsRecord jobStatisticsRecord : jobStatisticsList ) { - System.out.println( String.format("%10s %14.6f %14.6f %14.6f %14.6f", - jobStatisticsRecord.id, - jobStatisticsRecord.meanValue, - jobStatisticsRecord.stddev, - jobStatisticsRecord.minValue, - jobStatisticsRecord.maxValue)); - } - } -} // JobStats +/** +* Class JobPerf is an application that renders time line data from a Trick based + simulation and generates run-time statistics reports for the simulation jobs. + It can be run with or without a GUI. +*/ public class JobPerf extends JFrame { ArrayList jobExecEvtList; JobStats jobStats; + /** + * Constructor + * @param args the command line arguments. + */ public JobPerf( String[] args ) { TraceViewWindow traceViewWindow; boolean interactive = true; @@ -782,7 +68,7 @@ public class JobPerf extends JFrame { ++ii; } // while - jobExecEvtList = JobExecutionEventList(fileName); + jobExecEvtList = getJobExecutionEventList(fileName); jobStats = new JobStats(jobExecEvtList); if (printReport) { if (sortOrder == JobStats.SortCriterion.ID ) jobStats.SortByID(); @@ -797,33 +83,38 @@ public class JobPerf extends JFrame { } } + /** + * Print the usage instructions to the terminal. + */ private static void printHelpText() { System.out.println( "----------------------------------------------------------------------\n" - + "usage: trick-jperf [options] \n" + + "usage: trick-jperf [options] \n\n" + "options: \n" + "-h, --help\n" - + " Print this help text and exit." + + " Print this help text and exit.\n" + "-x, --nogui\n" - + " Don't run as a GUI application. Command line only." + + " Don't run as a GUI application. Command line only.\n" + "-p, --report\n" - + " Write sorted job statics report to the terminal." + + " Write sorted job statics report to the terminal.\n" + "-s0, --sort=id\n" - + " Sort job statistics by identifier." + + " Sort job statistics by identifier.\n" + "-s1, --sort=mean [default]\n" - + " Sort job statistics by mean duration." + + " Sort job statistics by mean duration.\n" + "-s2, --sort=stddev\n" - + " Sort job statistics by standard deviation of duration." + + " Sort job statistics by standard deviation of duration.\n" + "-s3, --sort=min\n" - + " Sort job statistics by minimum duration." + + " Sort job statistics by minimum duration.\n" + "-s4, --sort=max\n" - + " Sort job statistics by maximum duration." + + " Sort job statistics by maximum duration.\n" + "----------------------------------------------------------------------\n" ); } - // Read the timeline file. - private ArrayList JobExecutionEventList( String fileName ) { + /** + * Read the timeline file, resulting in a ArrayList. + */ + private ArrayList getJobExecutionEventList( String fileName ) { String line; String field[]; @@ -858,8 +149,10 @@ public class JobPerf extends JFrame { return jobExecEvtList; } + /** + * Entry point for the Java application. + */ public static void main(String[] args) { JobPerf jobPerf = new JobPerf( args ); - } // main - -} // class JobPerf + } +} diff --git a/trick_source/java/src/main/java/trick/jobperf/JobStats.java b/trick_source/java/src/main/java/trick/jobperf/JobStats.java new file mode 100644 index 00000000..fd709c40 --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/JobStats.java @@ -0,0 +1,184 @@ +package trick.jobperf; + +import java.io.*; +import java.util.*; + +/** +* Class CompareByID compares two StatisticsRecord's by id. +*/ +class CompareByID implements Comparator { + public int compare(StatisticsRecord a, StatisticsRecord b) { + return a.id.compareTo(b.id); + } +} +/** +* Class CompareByMeanValue compares two StatisticsRecord's by meanValue. +*/ +class CompareByMeanValue implements Comparator { + public int compare(StatisticsRecord a, StatisticsRecord b) { + if ( a.meanValue < b.meanValue) return -1; + if ( a.meanValue > b.meanValue) return 1; + return 0; + } +} +/** +* Class CompareByStdDev compares two StatisticsRecord's by stddev. +*/ +class CompareByStdDev implements Comparator { + public int compare(StatisticsRecord a, StatisticsRecord b) { + if ( a.stddev < b.stddev) return -1; + if ( a.stddev > b.stddev) return 1; + return 0; + } +} +/** +* Class CompareByMaxDuration compares two StatisticsRecord's by maxValue. +*/ +class CompareByMaxDuration implements Comparator { + public int compare(StatisticsRecord a, StatisticsRecord b) { + if ( a.maxValue < b.maxValue) return -1; + if ( a.maxValue > b.maxValue) return 1; + return 0; + } +} +/** +* Class CompareByMinDuration compares two StatisticsRecord's by minValue. +*/ +class CompareByMinDuration implements Comparator { + public int compare(StatisticsRecord a, StatisticsRecord b) { + if ( a.minValue < b.minValue) return -1; + if ( a.minValue > b.minValue) return 1; + return 0; + } +} + +/** +* Class JobStats represents the statistics, i.e., mean, std deviation, max value, +* and min value of the run-duration of each of the Trick jobs in jobExecList. The +* statistic records can be sorted by any of the statistics, and by the job id, +* prior to being written as a report. +*/ +public class JobStats { + + /** + * Enum SortCriterion enumerates the valid ways that JobStats records can be + * sorted. + */ + enum SortCriterion { + ID { + @Override + public String toString() { return "Identifier"; } + }, + MEAN { + @Override + public String toString() { return "Mean Value"; } + }, + STDDEV { + @Override + public String toString() { return "Standard Deviation"; } + }, + MAX { + @Override + public String toString() { return "Maximum Value"; } + }, + MIN { + @Override + public String toString() { return "Minimum Value"; } + } + } + + SortCriterion currentSortCriterion = SortCriterion.MEAN; + ArrayList jobStatisticsList; + + /** + * Constructor + * @param jobExecList - the timeline data. + */ + public JobStats( ArrayList jobExecList ) { + + Map runRegistryMap + = new HashMap(); + + for (JobExecutionEvent jobExec : jobExecList ) { + RunRegistry runRegistry = runRegistryMap.get(jobExec.id); + if (runRegistry != null) { + runRegistry.addTimeSpan(jobExec.start, jobExec.stop); + } else { + runRegistry = new RunRegistry(); + runRegistry.addTimeSpan(jobExec.start, jobExec.stop); + runRegistryMap.put(jobExec.id, runRegistry); + } + } + + jobStatisticsList = new ArrayList(); + + for (Map.Entry entry : runRegistryMap.entrySet()) { + String id = entry.getKey(); + RunRegistry runRegistry = entry.getValue(); + double mean = runRegistry.getMeanDuration(); + double stddev = runRegistry.getStdDev(); + double min = runRegistry.getMinDuration(); + double max = runRegistry.getMaxDuration(); + + jobStatisticsList.add( new StatisticsRecord(id, mean, stddev, min, max)); + } + } + + /** + * Sort by mean duration in descending order. + */ + public void SortByID() { + Collections.sort( jobStatisticsList, new CompareByID()); + currentSortCriterion = SortCriterion.ID; + } + + /** + * Sort by mean duration in descending order. + */ + public void SortByMeanValue() { + Collections.sort( jobStatisticsList, Collections.reverseOrder( new CompareByMeanValue())); + currentSortCriterion = SortCriterion.MEAN; + } + + /** + * Sort by standard deviation of duration in descending order. + */ + public void SortByStdDev() { + Collections.sort( jobStatisticsList, Collections.reverseOrder( new CompareByStdDev())); + currentSortCriterion = SortCriterion.STDDEV; + } + + /** + * Sort by maximum duration in descending order. + */ + public void SortByMaxValue() { + Collections.sort( jobStatisticsList, Collections.reverseOrder( new CompareByMaxDuration())); + currentSortCriterion = SortCriterion.MAX; + } + + /** + * Sort by minimum duration in descending order. + */ + public void SortByMinValue() { + Collections.sort( jobStatisticsList, Collections.reverseOrder( new CompareByMinDuration())); + currentSortCriterion = SortCriterion.MIN; + } + + /** + Write a text report to System.out. + */ + public void write() { + System.out.println(" [Job Duration Statistics Sorted by " + currentSortCriterion +"]"); + System.out.println("----------------------------------------------------------------------"); + System.out.println(" Job Id Mean Duration Std Dev Min Duration Max Duration"); + System.out.println("---------- -------------- -------------- -------------- --------------"); + for (StatisticsRecord jobStatisticsRecord : jobStatisticsList ) { + System.out.println( String.format("%10s %14.6f %14.6f %14.6f %14.6f", + jobStatisticsRecord.id, + jobStatisticsRecord.meanValue, + jobStatisticsRecord.stddev, + jobStatisticsRecord.minValue, + jobStatisticsRecord.maxValue)); + } + } +} diff --git a/trick_source/java/src/main/java/trick/jobperf/KeyedColorMap.java b/trick_source/java/src/main/java/trick/jobperf/KeyedColorMap.java new file mode 100644 index 00000000..7c91e007 --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/KeyedColorMap.java @@ -0,0 +1,123 @@ +package trick.jobperf; + +import java.awt.*; +import java.io.*; +import java.util.*; + +/** +* Class KeyedColorMap associates identifiers with unique RGB colors. +*/ +public class KeyedColorMap { + private Map colorMap; + int minLuminance; + + /** + * Constructor + */ + public KeyedColorMap() { + colorMap = new HashMap(); + minLuminance = 30; + } + + /** + * Generate a random color, that's not too dark. + * @ return the generated color. + */ + private Color generateColor () { + Random rand = new Random(); + boolean found = false; + int R = 0; + int G = 0; + int B = 0; + + while (!found) { + R = rand.nextInt(256); + G = rand.nextInt(256); + B = rand.nextInt(256); + found = true; + // Reference: https://www.w3.org/TR/AERT/#color-contrast + double luminance = (0.299*R + 0.587*G + 0.114*B); + if (luminance < minLuminance ) found = false; + } + return new Color( R,G,B); + } + + /** + * Add an identifier, and a generated Color to the KeyedColorMap. + * The Color will be generated randomly. + * @ param identifier Specifies the key for which a color will be generated. + */ + public void addKey( String identifier ) { + if (!colorMap.containsKey(identifier)) { + colorMap.put(identifier, generateColor()); + } + } + + /** + * Given an identifier, return its color. + * @param identifier the key. + * @return the Color associated with the key. + */ + public Color getColor(String identifier) { + return colorMap.get(identifier); + } + + /** + * Given a color, return the associated key, otherwise return null. + * @param searchColor the Color to search for. + * @return the identifier associated with the searchColor. + */ + public String getKeyOfColor(Color searchColor) { + for (Map.Entry entry : colorMap.entrySet()) { + String id = entry.getKey(); + Color color = entry.getValue(); + if (color.getRGB() == searchColor.getRGB()) { + return id; + } + } + return null; + } + + /** + * Write the identifier, color key/value pairs of the KeyedColorMap to a file. + * @param fileName + */ + public void writeFile(String fileName) throws IOException { + BufferedWriter out = new BufferedWriter( new FileWriter(fileName) ); + for (Map.Entry entry : colorMap.entrySet()) { + String id = entry.getKey(); + Color color = entry.getValue(); + String line = String.format(id + "," + color.getRed() + + "," + color.getGreen() + + "," + color.getBlue() + "\n"); + out.write(line, 0, line.length()); + } + out.flush(); + out.close(); + } // method writeFile + + /** + * Read identifier, color key-value pairs into the KeyedColorMap from a file. + * @param fileName + */ + public void readFile(String fileName) throws IOException { + try { + BufferedReader in = new BufferedReader( new FileReader(fileName) ); + String line; + String field[]; + + while( (line = in.readLine()) !=null) { + field = line.split(","); + String id = field[0]; + int R = Integer.parseInt( field[1]); + int G = Integer.parseInt( field[2]); + int B = Integer.parseInt( field[3]); + colorMap.put(id, new Color(R,G,B)); + } + in.close(); + } catch ( java.io.FileNotFoundException e ) { + System.out.println("File \"" + fileName + "\" not found.\n"); + } + } // method readFile + +} // class KeyedColorMap diff --git a/trick_source/java/src/main/java/trick/jobperf/RunRegistry.java b/trick_source/java/src/main/java/trick/jobperf/RunRegistry.java new file mode 100644 index 00000000..94d3407b --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/RunRegistry.java @@ -0,0 +1,73 @@ +package trick.jobperf; + +import java.lang.Math; +import java.util.*; + +/** +* Class RunRegistry represents a list of timeSpan's on which we can calculate +* the average (mean), standard deviation, minimum, and maximum of the timeSpans +* in the list. +*/ +public class RunRegistry { + ArrayList timeSpanList; + /* + * Constructor + */ + public RunRegistry() { + timeSpanList = new ArrayList(); + } + void addTimeSpan(double start, double stop) { + TimeSpan timeSpan = new TimeSpan(start, stop); + timeSpanList.add(timeSpan); + } + void addTimeSpan(TimeSpan timeSpan) { + timeSpanList.add(timeSpan); + } + double getMeanDuration() { + double mean = 0.0; + int N = timeSpanList.size(); + if (N > 0) { + double sum = 0.0; + for (TimeSpan timeSpan : timeSpanList ) { + sum += timeSpan.getDuration(); + } + mean = sum / N; + } + return mean; + } + double getStdDev() { + double stddev = 0.0; + int N = timeSpanList.size(); + if (N > 0) { + double sum = 0.0; + double mean = getMeanDuration(); + for (TimeSpan timeSpan : timeSpanList ) { + double duration = timeSpan.getDuration(); + double difference = duration - mean; + sum += difference * difference; + } + stddev = Math.sqrt( sum / N ); + } + return stddev; + } + double getMaxDuration() { + double maxDuration = Double.MIN_VALUE; + for (TimeSpan timeSpan : timeSpanList ) { + double duration = timeSpan.getDuration(); + if (duration > maxDuration) { + maxDuration = duration; + } + } + return maxDuration; + } + double getMinDuration() { + double minDuration = Double.MAX_VALUE; + for (TimeSpan timeSpan : timeSpanList ) { + double duration = timeSpan.getDuration(); + if (duration < minDuration) { + minDuration = duration; + } + } + return minDuration; + } +} diff --git a/trick_source/java/src/main/java/trick/jobperf/StatisticsRecord.java b/trick_source/java/src/main/java/trick/jobperf/StatisticsRecord.java new file mode 100644 index 00000000..53159543 --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/StatisticsRecord.java @@ -0,0 +1,28 @@ +package trick.jobperf; + +/** +* Class StatisticsRecord represents the statistics, i.e., mean, std deviation, +* max value, and min value of the run-duration of an identified Trick job. +*/ +public class StatisticsRecord { + public String id; + public double meanValue; + public double stddev; + public double maxValue; + public double minValue; + /** + * Constructor + * @param s - the job identifier. + * @param mean - the mean value of job duration. + * @param sd - the standard deviation of job duration. + * @param min - the minimum value of job duration. + * @param max - the maximum value of job duration. + */ + public StatisticsRecord( String s, double mean, double sd, double min, double max) { + id = s; + meanValue = mean; + stddev = sd; + minValue = min; + maxValue = max; + } +} diff --git a/trick_source/java/src/main/java/trick/jobperf/TimeSpan.java b/trick_source/java/src/main/java/trick/jobperf/TimeSpan.java new file mode 100644 index 00000000..f441fd4c --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/TimeSpan.java @@ -0,0 +1,24 @@ +package trick.jobperf; + +/** +* Class TimeSpan represents a span of time. +*/ +public class TimeSpan { + public double start; + public double stop; + /** + * Constructor + * @param begin the start time. + * @param end the end time. + */ + public TimeSpan( double begin, double end) { + start = begin; + stop = end; + } + /** + * @return the stop time minus the start time. + */ + public double getDuration() { + return stop - start; + } +} diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java new file mode 100644 index 00000000..169e2e24 --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java @@ -0,0 +1,281 @@ +package trick.jobperf; + +import java.awt.*; +import java.awt.event.*; +import java.awt.image.BufferedImage; +import java.io.*; +import java.util.*; +import java.util.List; +import javax.swing.*; +import javax.swing.event.*; + +/** +* Class TraceViewCanvas renders the simulation timeline data stored in +* an ArrayList of JobExecutionEvent's [jobExecEvtList]. Information regarding mouse clicks +* are sent to the TraceViewOutputToolBar [outputToolBar.] +*/ +public class TraceViewCanvas extends JPanel { + + public static final int MIN_TRACE_WIDTH = 4; + public static final int DEFAULT_TRACE_WIDTH = 10; + public static final int MAX_TRACE_WIDTH = 30; + public static final int LEFT_MARGIN = 100; + public static final int RIGHT_MARGIN = 100; + public static final int TOP_MARGIN = 20; + public static final int BOTTOM_MARGIN = 20; + + private int traceWidth; + private double frameDuration; + private List jobExecList; + private KeyedColorMap idToColorMap; + private BufferedImage image; + private TraceViewOutputToolBar sToolBar; + private Cursor crossHairCursor; + private Cursor defaultCursor; + + /** + * Constructor + * @param jobExecEvtList the job time line data. + * @param outputToolBar the toolbar to which data is to be sent for display. + */ + public TraceViewCanvas( ArrayList jobExecEvtList, TraceViewOutputToolBar outputToolBar ) { + + traceWidth = DEFAULT_TRACE_WIDTH; + frameDuration = 1.0; + image = null; + sToolBar = outputToolBar; + jobExecList = jobExecEvtList; + crossHairCursor = new Cursor( Cursor.CROSSHAIR_CURSOR ); + defaultCursor = new Cursor( Cursor.DEFAULT_CURSOR ); + double smallestStart = Double.MAX_VALUE; + double largestStop = -Double.MAX_VALUE; + + try { + idToColorMap = new KeyedColorMap(); + File colorfile = new File("IdToColors.txt"); + if (colorfile.exists()) { + idToColorMap.readFile("IdToColors.txt"); + } + + boolean wasTOF = false; + double startOfFrame = 0.0; + double lastStartOfFrame = 0.0; + double frameSizeSum = 0.0; + int frameNumber = 0; + int frameSizeCount = 0; + + for (JobExecutionEvent jobExec : jobExecList ) { + if (jobExec.start < smallestStart) smallestStart = jobExec.start; + if (jobExec.stop > largestStop) largestStop = jobExec.stop; + // Calculate the average frame size. + if (!wasTOF && jobExec.isTOF) { + startOfFrame = jobExec.start; + if (frameNumber > 0) { + double frameSize = (startOfFrame - lastStartOfFrame); + frameSizeSum += frameSize; + frameSizeCount ++; + } + lastStartOfFrame = startOfFrame; + frameNumber++; + } + wasTOF = jobExec.isTOF; + idToColorMap.addKey(jobExec.id); + } + + // Calculate the average frame size. + frameDuration = frameSizeSum / frameSizeCount; + idToColorMap.writeFile("IdToColors.txt"); + + System.out.println("File loaded.\n"); + } catch ( java.io.FileNotFoundException e ) { + System.out.println("File not found.\n"); + System.exit(0); + } catch ( java.io.IOException e ) { + System.out.println("IO Exception.\n"); + System.exit(0); + } + + int preferredHeight = traceWidth * (int)((largestStop - smallestStart) / frameDuration) + TOP_MARGIN; + setPreferredSize(new Dimension(500, preferredHeight)); + + ViewListener viewListener = new ViewListener(); + addMouseListener(viewListener); + addMouseMotionListener(viewListener); + } + + /** + * @return the current working frame size used for rendering. Initially this + * is estimated from the timeline data, but it can be set to the actual + * realtime frame size of the user's sim. + */ + public double getFrameDuration() { + return frameDuration; + } + /** + * Set the frame size to be used for rendering the timeline data. + * @param duration the frame size. + */ + public void setFrameDuration(double duration) { + frameDuration = duration; + repaint(); + } + + /** + * Increment the width to be used to render the job traces if the current + * trace width is less than MAX_TRACE_WIDTH. + */ + public void increaseTraceWidth() { + if (traceWidth < MAX_TRACE_WIDTH) { + traceWidth ++; + repaint(); + } + } + + /** + * Decrement the width to be used to render the job traces if the current + * trace width is greater than MIN_TRACE_WIDTH. + */ + public void decreaseTraceWidth() { + if (traceWidth > MIN_TRACE_WIDTH) { + traceWidth --; + repaint(); + } + } + + /** + * @return true if the trace rectangle contains the point , otherwise + * false. + */ + private boolean traceRectContains(int x, int y) { + int traceRectXMax = getWidth() - RIGHT_MARGIN; + if ( x < (LEFT_MARGIN)) return false; + if ( x > (traceRectXMax)) return false; + if ( y < TOP_MARGIN) return false; + return true; + } + /** + * @return true if the time rectangle contains the point , otherwise + * false. + */ + private boolean timeRectContains(int x, int y) { + int timeRectXMin = 30; + int timeRectXMax = LEFT_MARGIN; + if ( x < 30 ) return false; + if ( x > LEFT_MARGIN) return false; + if ( y < TOP_MARGIN) return false; + return true; + } + + /** + * Class ViewListener monitors mouse activity within the TraceViewCanvas. + */ + private class ViewListener extends MouseInputAdapter { + + @Override + public void mouseReleased(MouseEvent e) { + int x = e.getX(); + int y = e.getY(); + Color color = new Color ( image.getRGB(x,y) ); + + String id = idToColorMap.getKeyOfColor( color ); + sToolBar.setJobID(id); + + if ( y > TOP_MARGIN) { + int frameNumber = (y - TOP_MARGIN) / traceWidth; + sToolBar.setFrameNumber(frameNumber); + } + if ( traceRectContains(x, y)) { + double pixelsPerSecond = (double)calcTraceRectWidth() / frameDuration; + double subFrameTime = (x - LEFT_MARGIN) / pixelsPerSecond; + sToolBar.setSubFrameTime(subFrameTime); + } + } + + @Override + public void mouseMoved(MouseEvent e) { + int x = e.getX(); + int y = e.getY(); + if ( traceRectContains(x, y)) { + setCursor(crossHairCursor); + } else { + setCursor(defaultCursor); + } + } + } + + /** + * @return the height of the trace rectangle. + */ + private int calcTraceRectHeight() { + return ( getHeight() - TOP_MARGIN - BOTTOM_MARGIN); + } + + /** + * @return the width of the trace rectangle. + */ + private int calcTraceRectWidth() { + return ( getWidth() - LEFT_MARGIN - RIGHT_MARGIN); + } + + /** + * Render the job execution traces in the jobExecEvtList. + */ + private void doDrawing(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + + RenderingHints rh = new RenderingHints( + RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + rh.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + + int traceRectHeight = calcTraceRectHeight(); + int traceRectWidth = calcTraceRectWidth(); + double pixelsPerSecond = (double)traceRectWidth / frameDuration; + + // Panel Background Color Fill + g2d.setPaint(Color.WHITE); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + // Frame Trace Rectangle Fill + g2d.setPaint(Color.BLACK); + g2d.fillRect(LEFT_MARGIN, TOP_MARGIN, traceRectWidth, traceRectHeight); + + boolean wasEOF = false; + boolean wasTOF = false; + double startOfFrame = 0.0; + int frameNumber = 0; + + for (JobExecutionEvent jobExec : jobExecList ) { + + if (!wasTOF && jobExec.isTOF) { + startOfFrame = jobExec.start; + frameNumber ++; + } + + wasTOF = jobExec.isTOF; + wasEOF = jobExec.isEOF; + + int jobY = TOP_MARGIN + frameNumber * traceWidth; + int jobStartX = LEFT_MARGIN + (int)((jobExec.start - startOfFrame) * pixelsPerSecond); + int jobWidth = (int)( (jobExec.stop - jobExec.start) * pixelsPerSecond); + + g2d.setPaint(Color.BLACK); + g2d.drawString ( String.format("%8.3f", startOfFrame), 30, jobY + traceWidth/2); + g2d.setPaint( idToColorMap.getColor( jobExec.id ) ); + g2d.fillRect(jobStartX, jobY, jobWidth, traceWidth-2); + + } + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB); + Graphics2D g2 = image.createGraphics(); + doDrawing(g2); + g.drawImage(image, 0, 0, this); + g2.dispose(); + } +} diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java new file mode 100644 index 00000000..c5a690ca --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java @@ -0,0 +1,59 @@ +package trick.jobperf; + +import java.awt.*; +import java.awt.event.*; +import java.io.*; +import javax.swing.*; +import java.net.URL; + +/** +* Class TraceViewInputToolBar initially displays an estimate of the frame size +* for the JobPerf input timeline data. A user may also enter the intended frame +* size into the JTextField, and pressing the "Set" button, which calls +* traceView.setFrameDuration( newFrameSize ); +*/ +public class TraceViewInputToolBar extends JToolBar implements ActionListener { + + private TraceViewCanvas traceView; + private JTextField frameDurationField; + /** + * Constructor + * @param tvc TraceViewCanvas to be controlled. + */ + public TraceViewInputToolBar (TraceViewCanvas tvc) { + traceView = tvc; + add( new JLabel(" Frame Size: ")); + frameDurationField = new JTextField(15); + frameDurationField.setText( String.format("%8.4f", traceView.getFrameDuration()) ); + add(frameDurationField); + + JButton setButton = new JButton("Set"); + setButton.addActionListener(this); + setButton.setActionCommand("setFrameSize"); + setButton.setToolTipText("Set frame size in seconds."); + add(setButton); + + // Add Trick LOGO here. + + } + @Override + public void actionPerformed(ActionEvent event) { + String s = event.getActionCommand(); + switch (s) { + case "setFrameSize": + double newFrameSize = 0.0; + try { + newFrameSize = Double.parseDouble( frameDurationField.getText() ); + } catch ( NumberFormatException e) { + frameDurationField.setText( String.format("%8.4f", traceView.getFrameDuration()) ); + } + if ( newFrameSize > 0.0) { + traceView.setFrameDuration( newFrameSize ); + } + break; + default: + System.out.println("Unknown Action Command:" + s); + break; + } + } +} diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewMenuBar.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewMenuBar.java new file mode 100644 index 00000000..1ee5353e --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewMenuBar.java @@ -0,0 +1,72 @@ +package trick.jobperf; + +import java.awt.*; +import java.awt.event.*; +import java.io.*; +import javax.swing.*; + +/** +* Class TraceViewMenuBar represents the menu bar of the JobPerf application. +* It aggregates the following GUI components: +* JMenuBar [this] +* JMenu [fileMenu] +* JMenuItem [fileMenuExit], Action: Call System.exit(0); +* JMenu [optionsMenu] +* JMenu [traceSizeMenu] +* JMenuItem [traceSizeMenuIncrease], Action: Call traceView.increaseTraceWidth(). +* JMenuItem [traceSizeMenuDecrease], Action: Call traceView.decreaseTraceWidth() +*/ +public class TraceViewMenuBar extends JMenuBar implements ActionListener { + + private TraceViewCanvas traceView; + + /** + * Constructor + * @param tvc the TraceViewCanvas to be controlled by this menu bar. + */ + public TraceViewMenuBar(TraceViewCanvas tvc) { + traceView = tvc; + + JMenu fileMenu = new JMenu("File"); + JMenuItem fileMenuExit = new JMenuItem("Exit"); + fileMenuExit.setActionCommand("exit"); + fileMenuExit.addActionListener(this); + fileMenu.add(fileMenuExit); + add(fileMenu); + + JMenu optionsMenu = new JMenu("Options"); + JMenu traceSizeMenu = new JMenu("TraceSize"); + JMenuItem traceSizeMenuIncrease = new JMenuItem("Increase Trace Width"); + traceSizeMenuIncrease.setActionCommand("increase-trace_width"); + KeyStroke ctrlPlus = KeyStroke.getKeyStroke('P', InputEvent.CTRL_MASK ); + traceSizeMenuIncrease.setAccelerator(ctrlPlus); + traceSizeMenuIncrease.addActionListener(this); + traceSizeMenu.add(traceSizeMenuIncrease); + JMenuItem traceSizeMenuDecrease = new JMenuItem("Decrease Trace Width"); + traceSizeMenuDecrease.setActionCommand("decrease-trace_width"); + KeyStroke ctrlMinus = KeyStroke.getKeyStroke('-', InputEvent.CTRL_MASK); + traceSizeMenuDecrease.setAccelerator(ctrlMinus); + traceSizeMenuDecrease.addActionListener(this); + traceSizeMenu.add(traceSizeMenuDecrease); + optionsMenu.add(traceSizeMenu); + add(optionsMenu); + + } + @Override + public void actionPerformed(ActionEvent e) { + String s = e.getActionCommand(); + switch (s) { + case "increase-trace_width": + traceView.increaseTraceWidth(); + break; + case "decrease-trace_width": + traceView.decreaseTraceWidth(); + break; + case "exit": + System.exit(0); + default: + System.out.println("Unknown Action Command:" + s); + break; + } + } +} diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewOutputToolBar.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewOutputToolBar.java new file mode 100644 index 00000000..c31e0e38 --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewOutputToolBar.java @@ -0,0 +1,56 @@ +package trick.jobperf; + +import javax.swing.*; + +/** +* Class TraceViewOutputToolBar displays information output from a +* TraceViewCanvas. Specifically, this displays the Job ID, frame number, and +* subFrame Time associated with a mouse click position on the TraceViewCanvas. +*/ +class TraceViewOutputToolBar extends JToolBar { + private JTextField IDField; + private JTextField frameNumberField; + private JTextField subFrameTimeField; + + /** + * Constructor + */ + public TraceViewOutputToolBar () { + + add( new JLabel(" Job ID: ")); + IDField = new JTextField(15); + IDField.setEditable(false); + IDField.setText( ""); + add(IDField); + + add( new JLabel(" Frame Number: ")); + frameNumberField = new JTextField(15); + frameNumberField.setEditable(false); + frameNumberField.setText( "0"); + add(frameNumberField); + + add( new JLabel(" Subframe Time: ")); + subFrameTimeField = new JTextField(15); + subFrameTimeField.setEditable(false); + subFrameTimeField.setText( "0.00"); + add(subFrameTimeField); + } + /** + * @param id job identifier to display. + */ + public void setJobID(String id) { + IDField.setText( id ); + } + /** + * @param fn frame number to display. + */ + public void setFrameNumber(int fn) { + frameNumberField.setText( String.format("%d", fn)); + } + /** + * @param time subframe time to display. + */ + public void setSubFrameTime(double time) { + subFrameTimeField.setText( String.format("%8.4f", time)); + } +} diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewWindow.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewWindow.java new file mode 100644 index 00000000..23741a07 --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewWindow.java @@ -0,0 +1,60 @@ +package trick.jobperf; + +import java.awt.*; +import java.util.*; +import javax.swing.*; + +/** +* Class TraceViewWindow represents the main window of the JobPerf application. +* It aggregates the following GUI components: +* +* - TraceViewMenuBar [menuBar] +* - TraceViewInputToolBar [toolbar] +* - JPanel [mainPanel] +* - JPanel [tracePanel] +* - JScrollPane [scrollPane] +* - TraceViewCanvas [traceView] +* - TraceViewOutputToolBar [outputToolBar] +*/ +public class TraceViewWindow extends JFrame { + + /** + * Constructor + * @param jobExecList an ArrayList of JobExecutionEvent, i.e., the job timeline data. + */ + public TraceViewWindow( ArrayList jobExecList ) { + TraceViewOutputToolBar outputToolBar = new TraceViewOutputToolBar(); + TraceViewCanvas traceView = new TraceViewCanvas( jobExecList, outputToolBar); + + TraceViewMenuBar menuBar = new TraceViewMenuBar(traceView); + setJMenuBar(menuBar); + + TraceViewInputToolBar nToolBar = new TraceViewInputToolBar( traceView ); + add(nToolBar, BorderLayout.NORTH); + + JScrollPane scrollPane = new JScrollPane( traceView ); + scrollPane.setPreferredSize(new Dimension(800, 400)); + + JPanel tracePanel = new JPanel(); + tracePanel.setPreferredSize(new Dimension(800, 400)); + tracePanel.add(scrollPane); + tracePanel.setLayout(new BoxLayout(tracePanel, BoxLayout.X_AXIS)); + + JPanel mainPanel = new JPanel(); + mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); + mainPanel.add(tracePanel); + + add(outputToolBar, BorderLayout.SOUTH); + + setTitle("JobPerf"); + setSize(800, 500); + add(mainPanel); + pack(); + setVisible(true); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setFocusable(true); + setVisible(true); + + traceView.repaint(); + } +}