From f45a43eda06948cf00b2c71f407801e6b41342e6 Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Thu, 26 Sep 2024 11:18:06 -0500 Subject: [PATCH 01/13] Initial Commit of Frame Performance - jperf --- bin/trick-jperf | 8 + include/trick/FrameLog.hh | 2 + include/trick/JobData.hh | 6 + trick_source/java/pom.xml | 16 + .../src/main/java/trick/jobperf/JobPerf.java | 553 ++++++++++++++++++ .../sim_services/FrameLog/FrameLog.cpp | 53 +- 6 files changed, 633 insertions(+), 5 deletions(-) create mode 100755 bin/trick-jperf create mode 100644 trick_source/java/src/main/java/trick/jobperf/JobPerf.java diff --git a/bin/trick-jperf b/bin/trick-jperf new file mode 100755 index 000000000..7fb8d3468 --- /dev/null +++ b/bin/trick-jperf @@ -0,0 +1,8 @@ +#!/usr/bin/perl + +use FindBin qw($RealBin); +use lib ("$RealBin/../libexec/trick/pm", "$RealBin/../lib/trick/pm") ; +use launch_java ; + +launch_java("JPERF", "JPerf") ; + diff --git a/include/trick/FrameLog.hh b/include/trick/FrameLog.hh index edff7600b..35f519543 100644 --- a/include/trick/FrameLog.hh +++ b/include/trick/FrameLog.hh @@ -20,6 +20,8 @@ namespace Trick { /** Data to save for each timeline sample.\n */ struct timeline_t { bool trick_job; + bool isEndOfFrame; + bool isTopOfFrame; double id; long long start; long long stop; diff --git a/include/trick/JobData.hh b/include/trick/JobData.hh index 8ad72103e..3c5fde622 100644 --- a/include/trick/JobData.hh +++ b/include/trick/JobData.hh @@ -47,6 +47,12 @@ namespace Trick { /** Indicates if a scheduler is handling this job */ bool handled; /**< trick_units(--) */ + /** Indicates whether this is an "top_of_frame" job. */ + bool isTopOfFrame; /**< trick_units(--) */ + + /** Indicates whether this is an "end_of_frame" job. */ + bool isEndOfFrame; /**< trick_units(--) */ + /** The cycle time */ double cycle; /**< trick_units(s) */ diff --git a/trick_source/java/pom.xml b/trick_source/java/pom.xml index ee69706ca..c9cecb6a7 100644 --- a/trick_source/java/pom.xml +++ b/trick_source/java/pom.xml @@ -282,6 +282,22 @@ MM + + + jobperf + package + + shade + + + + + trick.jobperf.JobPerf + + + JPerf + + diff --git a/trick_source/java/src/main/java/trick/jobperf/JobPerf.java b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java new file mode 100644 index 000000000..c410178d8 --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java @@ -0,0 +1,553 @@ +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 TraceViewPanel extends JPanel { + + public static final int MIN_TRACE_WIDTH = 4; + 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 SouthToolBar sToolBar; + private Cursor crossHairCursor; + private Cursor defaultCursor; + + public TraceViewPanel( String fileName, SouthToolBar southToolBar ) { + + traceWidth = 10; + frameDuration = 1.0; + image = null; + sToolBar = southToolBar; + crossHairCursor = new Cursor( Cursor.CROSSHAIR_CURSOR ); + defaultCursor = new Cursor( Cursor.DEFAULT_CURSOR ); + double smallestJobTime = Double.MAX_VALUE; + double largestJobTime = -Double.MAX_VALUE; + + // Read the Job execution file to build the jobExecList. + try { + BufferedReader in = new BufferedReader( new FileReader(fileName) ); + jobExecList = new ArrayList(); + idToColorMap = new KeyedColorMap(); + idToColorMap.readFile("IdToColors.txt"); + Random rand = new Random(); + String line; + String field[]; + + // Strip the header off the CSV file. + line = in.readLine(); + System.out.println("LINE = \"" + line + "\".\n"); + + boolean wasTOF = false; + double startOfFrame = 0.0; + double lastStartOfFrame = 0.0; + double frameSizeSum = 0.0; + int frameNumber = 0; + int frameSizeCount = 0; + + while( (line = in.readLine()) !=null) { + field = line.split(","); + String id = field[0]; + boolean isTOF = false; + boolean isEOF = false; + if (Integer.parseInt(field[1]) == 1) isTOF = true; + if (Integer.parseInt(field[2]) == 1) isEOF = true; + double start = Double.parseDouble( field[3]); + double stop = Double.parseDouble( field[4]); + + if (start < stop) { + JobExecutionEvent evt = new JobExecutionEvent(id, isTOF, isEOF, start, stop); + jobExecList.add( evt); + if (start < smallestJobTime) smallestJobTime = start; + if (stop > largestJobTime) largestJobTime = stop; + // Calculate the average frame size. + if (!wasTOF && isTOF) { + startOfFrame = start; + if (frameNumber > 0) { + double frameSize = (startOfFrame - lastStartOfFrame); + frameSizeSum += frameSize; + frameSizeCount ++; + } + lastStartOfFrame = startOfFrame; + frameNumber++; + } + wasTOF = isTOF; + } + idToColorMap.addKey(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)((largestJobTime - smallestJobTime) / 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 TraceViewPanel + +class NorthToolBar extends JToolBar implements ActionListener { + + private TraceViewPanel traceView; + private JTextField frameDurationField; + + public NorthToolBar (TraceViewPanel 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 NorthToolBar + +class SouthToolBar extends JToolBar { + private JTextField IDField; + private JTextField frameNumberField; + private JTextField subFrameTimeField; + + public SouthToolBar () { + + 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 SouthToolBar + +class PerfMenuBar extends JMenuBar implements ActionListener { + + private TraceViewPanel traceView; + + public PerfMenuBar(TraceViewPanel 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(KeyEvent.VK_P, Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()); + 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(KeyEvent.VK_MINUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()); + 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 PerfMenuBar + +public class JobPerf extends JFrame { + + private List JobExecutionEventlist; + + public JobPerf( TraceViewPanel traceView, SouthToolBar southToolBar) { + + PerfMenuBar menuBar = new PerfMenuBar(traceView); + setJMenuBar(menuBar); + + NorthToolBar nToolBar = new NorthToolBar( 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(southToolBar, BorderLayout.SOUTH); + + setTitle("JobPerf"); + setSize(800, 500); + add(mainPanel); + pack(); + setVisible(true); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setFocusable(true); + setVisible(true); + + traceView.repaint(); + } + + private static void printHelpText() { + System.out.println( + "----------------------------------------------------------------------\n" + + "usage: java jar JobPerf.jar \n" + + "----------------------------------------------------------------------\n" + ); + } + + public static void main(String[] args) { + int ii = 0; + String fileName = "in.csv"; + while (ii < args.length) { + switch (args[ii]) { + case "-help" : + case "--help" : { + printHelpText(); + System.exit(0); + } break; + default : { + fileName = args[ii]; + } break; + } + ++ii; + } // while + + SouthToolBar sToolBar = new SouthToolBar(); + TraceViewPanel traceView = new TraceViewPanel( fileName, sToolBar); + JobPerf jobPerf = new JobPerf(traceView, sToolBar); + + } // main +} // class JobPerf diff --git a/trick_source/sim_services/FrameLog/FrameLog.cpp b/trick_source/sim_services/FrameLog/FrameLog.cpp index 2eb4516e3..f69807293 100644 --- a/trick_source/sim_services/FrameLog/FrameLog.cpp +++ b/trick_source/sim_services/FrameLog/FrameLog.cpp @@ -384,6 +384,7 @@ int Trick::FrameLog::frame_clock_stop(Trick::JobData * curr_job) { mode = Run; } } + /** @li Save all cyclic job start & stop times for this frame into timeline structure. */ if ((mode==Run) || (mode==Step)) { // cyclic job if (tl_count[thread] < tl_max_samples) { @@ -391,6 +392,8 @@ int Trick::FrameLog::frame_clock_stop(Trick::JobData * curr_job) { timeline[thread][tl_count[thread]].start = target_job->rt_start_time; timeline[thread][tl_count[thread]].stop = target_job->rt_stop_time; timeline[thread][tl_count[thread]].trick_job = target_job->tags.count("TRK"); + timeline[thread][tl_count[thread]].isEndOfFrame = target_job->isEndOfFrame; + timeline[thread][tl_count[thread]].isTopOfFrame = target_job->isTopOfFrame; tl_count[thread]++; } /** @li Save all non-cyclic job start & stop times for this frame into timeline_other structure. */ @@ -582,8 +585,44 @@ int Trick::FrameLog::shutdown() { return(0) ; } + +// ================================================================ +// NEW Time-line for Jperf +// ================================================================ + for (int thread_num = 0; thread_num < num_threads; thread_num ++) { + + if (thread_num == 0) { + snprintf(log_buff, sizeof(log_buff), "%s/log_newtimeline.csv", command_line_args_get_output_dir()); + } else { + snprintf(log_buff, sizeof(log_buff), "%s/log_newtimelineC%d.csv", command_line_args_get_output_dir(), thread_num); + } + + FILE *fp_log; + if ((fp_log = fopen(log_buff, "w")) == NULL) { + message_publish(MSG_ERROR, "Could not open log_timeline.csv file for Job Timeline Logging\n") ; + exit(0); + } + + fprintf(fp_log,"jobID,isTopOfFrame,isEndOfFrame,startTime,stopTime\n"); + + time_scale = 1.0 / exec_get_time_tic_value(); + tl = timeline[thread_num]; + for ( ii = 0 ; ii < tl_count[thread_num] ; ii++ ) { + start = tl[ii].start * time_scale; + stop = tl[ii].stop * time_scale; + int isTrickJob = (tl[ii].trick_job) ? 1 : 0; + int isEndOfFrame = (tl[ii].isEndOfFrame) ? 1 : 0; + int isTopOfFrame = (tl[ii].isTopOfFrame) ? 1 : 0; + fprintf(fp_log,"%f,%d,%d,%f,%f\n", tl[ii].id, isTopOfFrame, isEndOfFrame, start, stop); + } + fflush(fp_log); + fclose(fp_log); + } + /** @li Manually create the log_timeline and log_timeline_init files from saved timeline data. */ if (fp_time_main == NULL) { + + snprintf(log_buff, sizeof(log_buff), "%s/log_timeline.csv", command_line_args_get_output_dir()); if ((fp_time_main = fopen(log_buff, "w")) == NULL) { message_publish(MSG_ERROR, "Could not open log_timeline.csv file for Job Timeline Logging\n") ; @@ -591,11 +630,14 @@ int Trick::FrameLog::shutdown() { } fprintf(fp_time_main, "trick_frame_log.frame_log.job_time {s},"); fprintf(fp_time_main, "trick_frame_log.frame_log.job_trick_id {--},frame_log.frame_log.job_user_id {--}"); + for (jj=1; jj Date: Thu, 26 Sep 2024 12:08:35 -0500 Subject: [PATCH 02/13] Fix KeyStroke.getKeyStroke call. --- trick_source/java/src/main/java/trick/jobperf/JobPerf.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 c410178d8..b22b507fc 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobPerf.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java @@ -450,13 +450,13 @@ public PerfMenuBar(TraceViewPanel tv) { JMenu traceSizeMenu = new JMenu("TraceSize"); JMenuItem traceSizeMenuIncrease = new JMenuItem("Increase Trace Width"); traceSizeMenuIncrease.setActionCommand("increase-trace_width"); - KeyStroke ctrlPlus = KeyStroke.getKeyStroke(KeyEvent.VK_P, Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()); + 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(KeyEvent.VK_MINUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()); + KeyStroke ctrlMinus = KeyStroke.getKeyStroke('-', InputEvent.CTRL_MASK); traceSizeMenuDecrease.setAccelerator(ctrlMinus); traceSizeMenuDecrease.addActionListener(this); traceSizeMenu.add(traceSizeMenuDecrease); From f287155f8c08eefc8e539bb01ede802e4998a6be Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Thu, 26 Sep 2024 14:57:33 -0500 Subject: [PATCH 03/13] Separate reading of file from processing it. --- .../src/main/java/trick/jobperf/JobPerf.java | 109 ++++++++++-------- 1 file changed, 61 insertions(+), 48 deletions(-) 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 b22b507fc..7596759d2 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobPerf.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java @@ -119,6 +119,7 @@ public void writeFile(String fileName) throws IOException { class TraceViewPanel 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; @@ -134,30 +135,21 @@ class TraceViewPanel extends JPanel { private Cursor crossHairCursor; private Cursor defaultCursor; - public TraceViewPanel( String fileName, SouthToolBar southToolBar ) { + public TraceViewPanel( ArrayList jobExecEvtList, SouthToolBar southToolBar ) { - traceWidth = 10; + traceWidth = DEFAULT_TRACE_WIDTH; frameDuration = 1.0; image = null; sToolBar = southToolBar; + jobExecList = jobExecEvtList; crossHairCursor = new Cursor( Cursor.CROSSHAIR_CURSOR ); defaultCursor = new Cursor( Cursor.DEFAULT_CURSOR ); - double smallestJobTime = Double.MAX_VALUE; - double largestJobTime = -Double.MAX_VALUE; + double smallestStart = Double.MAX_VALUE; + double largestStop = -Double.MAX_VALUE; - // Read the Job execution file to build the jobExecList. try { - BufferedReader in = new BufferedReader( new FileReader(fileName) ); - jobExecList = new ArrayList(); idToColorMap = new KeyedColorMap(); idToColorMap.readFile("IdToColors.txt"); - Random rand = new Random(); - String line; - String field[]; - - // Strip the header off the CSV file. - line = in.readLine(); - System.out.println("LINE = \"" + line + "\".\n"); boolean wasTOF = false; double startOfFrame = 0.0; @@ -166,35 +158,22 @@ public TraceViewPanel( String fileName, SouthToolBar southToolBar ) { int frameNumber = 0; int frameSizeCount = 0; - while( (line = in.readLine()) !=null) { - field = line.split(","); - String id = field[0]; - boolean isTOF = false; - boolean isEOF = false; - if (Integer.parseInt(field[1]) == 1) isTOF = true; - if (Integer.parseInt(field[2]) == 1) isEOF = true; - double start = Double.parseDouble( field[3]); - double stop = Double.parseDouble( field[4]); - - if (start < stop) { - JobExecutionEvent evt = new JobExecutionEvent(id, isTOF, isEOF, start, stop); - jobExecList.add( evt); - if (start < smallestJobTime) smallestJobTime = start; - if (stop > largestJobTime) largestJobTime = stop; - // Calculate the average frame size. - if (!wasTOF && isTOF) { - startOfFrame = start; - if (frameNumber > 0) { - double frameSize = (startOfFrame - lastStartOfFrame); - frameSizeSum += frameSize; - frameSizeCount ++; - } - lastStartOfFrame = startOfFrame; - frameNumber++; + 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 ++; } - wasTOF = isTOF; + lastStartOfFrame = startOfFrame; + frameNumber++; } - idToColorMap.addKey(id); + wasTOF = jobExec.isTOF; + idToColorMap.addKey(jobExec.id); } // Calculate the average frame size. @@ -210,7 +189,7 @@ public TraceViewPanel( String fileName, SouthToolBar southToolBar ) { System.exit(0); } - int preferredHeight = traceWidth * (int)((largestJobTime - smallestJobTime) / frameDuration) + TOP_MARGIN; + int preferredHeight = traceWidth * (int)((largestStop - smallestStart) / frameDuration) + TOP_MARGIN; setPreferredSize(new Dimension(500, preferredHeight)); ViewListener viewListener = new ViewListener(); @@ -484,9 +463,10 @@ public void actionPerformed(ActionEvent e) { public class JobPerf extends JFrame { - private List JobExecutionEventlist; + public JobPerf( String fileName ) { - public JobPerf( TraceViewPanel traceView, SouthToolBar southToolBar) { + SouthToolBar southToolBar = new SouthToolBar(); + TraceViewPanel traceView = new TraceViewPanel( JobExecutionEventList(fileName), southToolBar); PerfMenuBar menuBar = new PerfMenuBar(traceView); setJMenuBar(menuBar); @@ -528,6 +508,42 @@ private static void printHelpText() { ); } + // Read the timeline file. + private ArrayList JobExecutionEventList( String fileName ) { + String line; + String field[]; + + ArrayList jobExecEvtList = new ArrayList(); + try { + BufferedReader in = new BufferedReader( new FileReader(fileName) ); + + // Strip the header off the CSV file. + line = in.readLine(); + while( (line = in.readLine()) !=null) { + field = line.split(","); + String id = field[0]; + boolean isTOF = false; + if (Integer.parseInt(field[1]) == 1) isTOF = true; + boolean isEOF = false; + if (Integer.parseInt(field[2]) == 1) isEOF = true; + double start = Double.parseDouble( field[3]); + double stop = Double.parseDouble( field[4]); + + if (start < stop) { + JobExecutionEvent evt = new JobExecutionEvent(id, isTOF, isEOF, start, stop); + jobExecEvtList.add( evt); + } + } + } catch ( java.io.FileNotFoundException e ) { + System.out.println("File \"" + fileName + "\" not found.\n"); + System.exit(0); + } catch ( java.io.IOException e ) { + System.out.println("IO Exception.\n"); + System.exit(0); + } + return jobExecEvtList; + } + public static void main(String[] args) { int ii = 0; String fileName = "in.csv"; @@ -545,9 +561,6 @@ public static void main(String[] args) { ++ii; } // while - SouthToolBar sToolBar = new SouthToolBar(); - TraceViewPanel traceView = new TraceViewPanel( fileName, sToolBar); - JobPerf jobPerf = new JobPerf(traceView, sToolBar); - + JobPerf jobPerf = new JobPerf(fileName); } // main } // class JobPerf From 7e60ca864ed913bd89c748aa2a6b09fd50e132f1 Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Tue, 1 Oct 2024 12:19:48 -0500 Subject: [PATCH 04/13] Refactor JobPerf.java to clean up names and organization. --- .../src/main/java/trick/jobperf/JobPerf.java | 63 +++++++++++-------- 1 file changed, 36 insertions(+), 27 deletions(-) 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 7596759d2..2fcc3a9e4 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobPerf.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java @@ -116,7 +116,7 @@ public void writeFile(String fileName) throws IOException { } } // KeyedColorMap -class TraceViewPanel extends JPanel { +class TraceViewCanvas extends JPanel { public static final int MIN_TRACE_WIDTH = 4; public static final int DEFAULT_TRACE_WIDTH = 10; @@ -131,21 +131,21 @@ class TraceViewPanel extends JPanel { private List jobExecList; private KeyedColorMap idToColorMap; private BufferedImage image; - private SouthToolBar sToolBar; + private TraceViewOutputToolBar sToolBar; private Cursor crossHairCursor; private Cursor defaultCursor; - public TraceViewPanel( ArrayList jobExecEvtList, SouthToolBar southToolBar ) { + public TraceViewCanvas( ArrayList jobExecEvtList, TraceViewOutputToolBar outputToolBar ) { traceWidth = DEFAULT_TRACE_WIDTH; frameDuration = 1.0; image = null; - sToolBar = southToolBar; + 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; + double smallestStart = Double.MAX_VALUE; + double largestStop = -Double.MAX_VALUE; try { idToColorMap = new KeyedColorMap(); @@ -334,14 +334,14 @@ public void paintComponent(Graphics g) { g.drawImage(image, 0, 0, this); g2.dispose(); } -} // class TraceViewPanel +} // class TraceViewCanvas -class NorthToolBar extends JToolBar implements ActionListener { +class TraceViewInputToolBar extends JToolBar implements ActionListener { - private TraceViewPanel traceView; + private TraceViewCanvas traceView; private JTextField frameDurationField; - public NorthToolBar (TraceViewPanel tv) { + public TraceViewInputToolBar (TraceViewCanvas tv) { traceView = tv; add( new JLabel(" Frame Size: ")); frameDurationField = new JTextField(15); @@ -373,14 +373,14 @@ public void actionPerformed(ActionEvent event) { break; } } -} // class NorthToolBar +} // class TraceViewInputToolBar -class SouthToolBar extends JToolBar { +class TraceViewOutputToolBar extends JToolBar { private JTextField IDField; private JTextField frameNumberField; private JTextField subFrameTimeField; - public SouthToolBar () { + public TraceViewOutputToolBar () { add( new JLabel(" Job ID: ")); IDField = new JTextField(15); @@ -409,13 +409,13 @@ public void setFrameNumber(int fn) { public void setSubFrameTime(double time) { subFrameTimeField.setText( String.format("%8.4f", time)); } -} // class SouthToolBar +} // class TraceViewOutputToolBar -class PerfMenuBar extends JMenuBar implements ActionListener { +class TraceViewMenuBar extends JMenuBar implements ActionListener { - private TraceViewPanel traceView; + private TraceViewCanvas traceView; - public PerfMenuBar(TraceViewPanel tv) { + public TraceViewMenuBar(TraceViewCanvas tv) { traceView = tv; JMenu fileMenu = new JMenu("File"); @@ -459,19 +459,18 @@ public void actionPerformed(ActionEvent e) { break; } } -} // class PerfMenuBar +} // class TraceViewMenuBar -public class JobPerf extends JFrame { - - public JobPerf( String fileName ) { +class TraceViewWindow extends JFrame { - SouthToolBar southToolBar = new SouthToolBar(); - TraceViewPanel traceView = new TraceViewPanel( JobExecutionEventList(fileName), southToolBar); + public TraceViewWindow( ArrayList jobExecList ) { + TraceViewOutputToolBar outputToolBar = new TraceViewOutputToolBar(); + TraceViewCanvas traceView = new TraceViewCanvas( jobExecList, outputToolBar); - PerfMenuBar menuBar = new PerfMenuBar(traceView); + TraceViewMenuBar menuBar = new TraceViewMenuBar(traceView); setJMenuBar(menuBar); - NorthToolBar nToolBar = new NorthToolBar( traceView ); + TraceViewInputToolBar nToolBar = new TraceViewInputToolBar( traceView ); add(nToolBar, BorderLayout.NORTH); JScrollPane scrollPane = new JScrollPane( traceView ); @@ -486,7 +485,7 @@ public JobPerf( String fileName ) { mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); mainPanel.add(tracePanel); - add(southToolBar, BorderLayout.SOUTH); + add(outputToolBar, BorderLayout.SOUTH); setTitle("JobPerf"); setSize(800, 500); @@ -499,6 +498,15 @@ public JobPerf( String fileName ) { traceView.repaint(); } +} // class TraceViewWindow + +public class JobPerf extends JFrame { + ArrayList jobExecEvtList; + + public JobPerf( String fileName ) { + jobExecEvtList = JobExecutionEventList(fileName); + TraceViewWindow traceViewWindow = new TraceViewWindow( jobExecEvtList ); + } private static void printHelpText() { System.out.println( @@ -561,6 +569,7 @@ public static void main(String[] args) { ++ii; } // while - JobPerf jobPerf = new JobPerf(fileName); + JobPerf jobPerf = new JobPerf( fileName ); } // main + } // class JobPerf From c8bf080de8845df515d54b43508b8de390c04f85 Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Tue, 15 Oct 2024 10:12:19 -0500 Subject: [PATCH 05/13] Add statistics reporting to jperf. --- .../src/main/java/trick/jobperf/JobPerf.java | 289 ++++++++++++++++-- 1 file changed, 268 insertions(+), 21 deletions(-) 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 2fcc3a9e4..2f530354d 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobPerf.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java @@ -500,19 +500,282 @@ public TraceViewWindow( ArrayList jobExecList ) { } } // 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 ExecutionRegister { + ArrayList intervalList; + + public ExecutionRegister() { + intervalList = new ArrayList(); + } + void addSample(double start, double stop) { + Interval interval = new Interval(start, stop); + intervalList.add(interval); + } + double getMean() { + 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 = getMean(); + 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; + } +} // ExecutionRegister + +class JobStatisticsRecord { + public String id; + public double mean; + public double stddev; + public double max; + public double min; + public JobStatisticsRecord( String s, double a, double b, double c, double d) { + id = s; + mean = a; + stddev = b; + max = c; + min = d; + } +} // JobStatisticsRecord + +// Compare method returns -1,0,1 to say whether it's less than, equal to, or greater than the other. + +class CompareByID implements Comparator { + public int compare(JobStatisticsRecord a, JobStatisticsRecord b) { + return a.id.compareTo(b.id); + } +} // CompareByID + +class CompareByMeanDuration implements Comparator { + public int compare(JobStatisticsRecord a, JobStatisticsRecord b) { + if ( a.mean < b.mean) return -1; + if ( a.mean > b.mean) return 1; + return 0; + } +} // CompareByMeanDuration + +class CompareByStdDev implements Comparator { + public int compare(JobStatisticsRecord a, JobStatisticsRecord 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(JobStatisticsRecord a, JobStatisticsRecord b) { + if ( a.max < b.max) return -1; + if ( a.max > b.max) return 1; + return 0; + } +} // CompareByMaxDuration + +class CompareByMinDuration implements Comparator { + public int compare(JobStatisticsRecord a, JobStatisticsRecord b) { + if ( a.min < b.min) return -1; + if ( a.min > b.min) return 1; + return 0; + } +} // CompareByMinDuration + +class JobStatistics { + ArrayList jobStatisticsList; + + public JobStatistics( ArrayList jobExecList ) { + + Map executionRegisterMap + = new HashMap(); + + for (JobExecutionEvent jobExec : jobExecList ) { + ExecutionRegister executionRegister = executionRegisterMap.get(jobExec.id); + if (executionRegister != null) { + executionRegister.addSample(jobExec.start, jobExec.stop); + } else { + executionRegister = new ExecutionRegister(); + executionRegister.addSample(jobExec.start, jobExec.stop); + executionRegisterMap.put(jobExec.id, executionRegister); + } + } + + jobStatisticsList = new ArrayList(); + + for (Map.Entry entry : executionRegisterMap.entrySet()) { + String id = entry.getKey(); + ExecutionRegister register = entry.getValue(); + double mean = register.getMean(); + double stddev = register.getStdDev(); + double min = register.getMinDuration(); + double max = register.getMaxDuration(); + + jobStatisticsList.add( new JobStatisticsRecord(id, mean, stddev, min, max)); + } + } + + + // Sort by MeanDuration in descending order. + public void SortByID() { + Collections.sort( jobStatisticsList, new CompareByID()); + } + + // Sort by MeanDuration in descending order. + public void SortByMeanDuration() { + Collections.sort( jobStatisticsList, Collections.reverseOrder( new CompareByMeanDuration())); + } + + // Sort by Standard Deviation of duration in descending order. + public void SortByStdDev() { + Collections.sort( jobStatisticsList, Collections.reverseOrder( new CompareByStdDev())); + } + + // Sort by MaxDuration in descending order. + public void SortByMaxDuration() { + Collections.sort( jobStatisticsList, Collections.reverseOrder( new CompareByMaxDuration())); + } + + // Sort by MinDuration in descending order. + public void SortByMinDuration() { + Collections.sort( jobStatisticsList, Collections.reverseOrder( new CompareByMinDuration())); + } + + public void write() { + System.out.println(" Job Id Mean Duration Std Dev Min Duration Max Duration"); + System.out.println("---------- -------------- -------------- -------------- --------------"); + for (JobStatisticsRecord jobStatisticsRecord : jobStatisticsList ) { + System.out.println( String.format("%10s %14.6f %14.6f %14.6f %14.6f", + jobStatisticsRecord.id, + jobStatisticsRecord.mean, + jobStatisticsRecord.stddev, + jobStatisticsRecord.min, + jobStatisticsRecord.max)); + } + } +} // JobStatistics + public class JobPerf extends JFrame { ArrayList jobExecEvtList; + JobStatistics jobStats; + + enum SortBy { ID, MEAN, STDDEV, MAX, MIN } + + public JobPerf( String[] args ) { + TraceViewWindow traceViewWindow; + boolean interactive = true; + boolean printReport = false; + SortBy sortMethod = SortBy.MEAN; + String fileName = "in.csv"; + + int ii = 0; + while (ii < args.length) { + switch (args[ii]) { + case "--help" : { + printHelpText(); + System.exit(0); + } break; + case "--nogui" : { + interactive = false; + } break; + case "--report" : { + printReport = true; + } break; + case "--sort=id" : { + sortMethod = SortBy.ID; + } break; + case "--sort=mean" : { + sortMethod = SortBy.MEAN; + } break; + case "--sort=stddev" : { + sortMethod = SortBy.STDDEV; + } break; + case "--sort=max" : { + sortMethod = SortBy.MAX; + } break; + case "--sort=min" : { + sortMethod = SortBy.MIN; + } break; + default : { + fileName = args[ii]; + } break; + } //switch + ++ii; + } // while - public JobPerf( String fileName ) { jobExecEvtList = JobExecutionEventList(fileName); - TraceViewWindow traceViewWindow = new TraceViewWindow( jobExecEvtList ); + jobStats = new JobStatistics(jobExecEvtList); + if (printReport) { + if (sortMethod == SortBy.ID ) jobStats.SortByID(); + if (sortMethod == SortBy.MEAN ) jobStats.SortByMeanDuration(); + if (sortMethod == SortBy.STDDEV ) jobStats.SortByStdDev(); + if (sortMethod == SortBy.MAX ) jobStats.SortByMaxDuration(); + if (sortMethod == SortBy.MIN ) jobStats.SortByMinDuration(); + jobStats.write(); + } + if (interactive) { + traceViewWindow = new TraceViewWindow(jobExecEvtList); + } } private static void printHelpText() { System.out.println( "----------------------------------------------------------------------\n" - + "usage: java jar JobPerf.jar \n" - + "----------------------------------------------------------------------\n" + + "usage: trick-jperf [options] \n" + + "options: \n" + + "--help\n" + + "--nogui\n" + + "--report\n" + + "--sort=id\n" + + "--sort=mean\n" + + "--sort=stddev\n" + + "--sort=min\n" + + "--sort=max\n" + + "----------------------------------------------------------------------\n" ); } @@ -553,23 +816,7 @@ private ArrayList JobExecutionEventList( String fileName ) { } public static void main(String[] args) { - int ii = 0; - String fileName = "in.csv"; - while (ii < args.length) { - switch (args[ii]) { - case "-help" : - case "--help" : { - printHelpText(); - System.exit(0); - } break; - default : { - fileName = args[ii]; - } break; - } - ++ii; - } // while - - JobPerf jobPerf = new JobPerf( fileName ); + JobPerf jobPerf = new JobPerf( args ); } // main } // class JobPerf From 1c6c73bdc66df3f2a97fbe6891eb712e4fa354db Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Thu, 17 Oct 2024 15:43:45 -0500 Subject: [PATCH 06/13] Fix min/max issue, and rename types and variables for clarity. --- .../src/main/java/trick/jobperf/JobPerf.java | 209 +++++++++++------- 1 file changed, 126 insertions(+), 83 deletions(-) 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 2f530354d..72426b207 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobPerf.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java @@ -512,17 +512,17 @@ public double getDuration() { } } // Interval -class ExecutionRegister { +class RunRegistry { ArrayList intervalList; - public ExecutionRegister() { + public RunRegistry() { intervalList = new ArrayList(); } void addSample(double start, double stop) { Interval interval = new Interval(start, stop); intervalList.add(interval); } - double getMean() { + double getMeanDuration() { double mean = 0.0; int N = intervalList.size(); if (N > 0) { @@ -539,7 +539,7 @@ void addSample(double start, double stop) { int N = intervalList.size(); if (N > 0) { double sum = 0.0; - double mean = getMean(); + double mean = getMeanDuration(); for (Interval interval : intervalList ) { double duration = interval.getDuration(); double difference = duration - mean; @@ -569,176 +569,211 @@ void addSample(double start, double stop) { } return minDuration; } -} // ExecutionRegister +} // RunRegistry -class JobStatisticsRecord { +class StatisticsRecord { public String id; - public double mean; + public double meanValue; public double stddev; - public double max; - public double min; - public JobStatisticsRecord( String s, double a, double b, double c, double d) { + public double maxValue; + public double minValue; + public StatisticsRecord( String s, double mean, double sd, double min, double max) { id = s; - mean = a; - stddev = b; - max = c; - min = d; + meanValue = mean; + stddev = sd; + minValue = min; + maxValue = max; } -} // JobStatisticsRecord +} // StatisticsRecord -// Compare method returns -1,0,1 to say whether it's less than, equal to, or greater than the other. - -class CompareByID implements Comparator { - public int compare(JobStatisticsRecord a, JobStatisticsRecord b) { +class CompareByID implements Comparator { + public int compare(StatisticsRecord a, StatisticsRecord b) { return a.id.compareTo(b.id); } } // CompareByID -class CompareByMeanDuration implements Comparator { - public int compare(JobStatisticsRecord a, JobStatisticsRecord b) { - if ( a.mean < b.mean) return -1; - if ( a.mean > b.mean) return 1; +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; } -} // CompareByMeanDuration +} // CompareByMeanValue -class CompareByStdDev implements Comparator { - public int compare(JobStatisticsRecord a, JobStatisticsRecord b) { +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(JobStatisticsRecord a, JobStatisticsRecord b) { - if ( a.max < b.max) return -1; - if ( a.max > b.max) return 1; +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(JobStatisticsRecord a, JobStatisticsRecord b) { - if ( a.min < b.min) return -1; - if ( a.min > b.min) return 1; +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 JobStatistics { - ArrayList jobStatisticsList; +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 JobStatistics( ArrayList jobExecList ) { + public JobStats( ArrayList jobExecList ) { - Map executionRegisterMap - = new HashMap(); + Map runRegistryMap + = new HashMap(); for (JobExecutionEvent jobExec : jobExecList ) { - ExecutionRegister executionRegister = executionRegisterMap.get(jobExec.id); - if (executionRegister != null) { - executionRegister.addSample(jobExec.start, jobExec.stop); + RunRegistry runRegistry = runRegistryMap.get(jobExec.id); + if (runRegistry != null) { + runRegistry.addSample(jobExec.start, jobExec.stop); } else { - executionRegister = new ExecutionRegister(); - executionRegister.addSample(jobExec.start, jobExec.stop); - executionRegisterMap.put(jobExec.id, executionRegister); + runRegistry = new RunRegistry(); + runRegistry.addSample(jobExec.start, jobExec.stop); + runRegistryMap.put(jobExec.id, runRegistry); } } - jobStatisticsList = new ArrayList(); + jobStatisticsList = new ArrayList(); - for (Map.Entry entry : executionRegisterMap.entrySet()) { + for (Map.Entry entry : runRegistryMap.entrySet()) { String id = entry.getKey(); - ExecutionRegister register = entry.getValue(); - double mean = register.getMean(); + RunRegistry register = entry.getValue(); + double mean = register.getMeanDuration(); double stddev = register.getStdDev(); double min = register.getMinDuration(); double max = register.getMaxDuration(); - jobStatisticsList.add( new JobStatisticsRecord(id, mean, stddev, min, max)); + 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 SortByMeanDuration() { - Collections.sort( jobStatisticsList, Collections.reverseOrder( new CompareByMeanDuration())); + 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 SortByMaxDuration() { + public void SortByMaxValue() { Collections.sort( jobStatisticsList, Collections.reverseOrder( new CompareByMaxDuration())); + currentSortCriterion = SortCriterion.MAX; } // Sort by MinDuration in descending order. - public void SortByMinDuration() { + 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 (JobStatisticsRecord jobStatisticsRecord : jobStatisticsList ) { + for (StatisticsRecord jobStatisticsRecord : jobStatisticsList ) { System.out.println( String.format("%10s %14.6f %14.6f %14.6f %14.6f", jobStatisticsRecord.id, - jobStatisticsRecord.mean, + jobStatisticsRecord.meanValue, jobStatisticsRecord.stddev, - jobStatisticsRecord.min, - jobStatisticsRecord.max)); + jobStatisticsRecord.minValue, + jobStatisticsRecord.maxValue)); } } -} // JobStatistics +} // JobStats public class JobPerf extends JFrame { ArrayList jobExecEvtList; - JobStatistics jobStats; - - enum SortBy { ID, MEAN, STDDEV, MAX, MIN } + JobStats jobStats; public JobPerf( String[] args ) { TraceViewWindow traceViewWindow; boolean interactive = true; boolean printReport = false; - SortBy sortMethod = SortBy.MEAN; + JobStats.SortCriterion sortOrder = JobStats.SortCriterion.MEAN; String fileName = "in.csv"; int ii = 0; while (ii < args.length) { switch (args[ii]) { + case "-h" : case "--help" : { printHelpText(); System.exit(0); } break; + case "-x" : case "--nogui" : { interactive = false; } break; + case "-p" : case "--report" : { printReport = true; } break; + case "-s0" : case "--sort=id" : { - sortMethod = SortBy.ID; + sortOrder = JobStats.SortCriterion.ID; } break; + case "-s1" : case "--sort=mean" : { - sortMethod = SortBy.MEAN; + sortOrder = JobStats.SortCriterion.MEAN; } break; + case "-s2" : case "--sort=stddev" : { - sortMethod = SortBy.STDDEV; + sortOrder = JobStats.SortCriterion.STDDEV; } break; + case "-s3" : case "--sort=max" : { - sortMethod = SortBy.MAX; + sortOrder = JobStats.SortCriterion.MAX; } break; + case "-s4" : case "--sort=min" : { - sortMethod = SortBy.MIN; + sortOrder = JobStats.SortCriterion.MIN; } break; default : { fileName = args[ii]; @@ -748,13 +783,13 @@ public JobPerf( String[] args ) { } // while jobExecEvtList = JobExecutionEventList(fileName); - jobStats = new JobStatistics(jobExecEvtList); + jobStats = new JobStats(jobExecEvtList); if (printReport) { - if (sortMethod == SortBy.ID ) jobStats.SortByID(); - if (sortMethod == SortBy.MEAN ) jobStats.SortByMeanDuration(); - if (sortMethod == SortBy.STDDEV ) jobStats.SortByStdDev(); - if (sortMethod == SortBy.MAX ) jobStats.SortByMaxDuration(); - if (sortMethod == SortBy.MIN ) jobStats.SortByMinDuration(); + if (sortOrder == JobStats.SortCriterion.ID ) jobStats.SortByID(); + if (sortOrder == JobStats.SortCriterion.MEAN ) jobStats.SortByMeanValue(); + if (sortOrder == JobStats.SortCriterion.STDDEV ) jobStats.SortByStdDev(); + if (sortOrder == JobStats.SortCriterion.MAX ) jobStats.SortByMaxValue(); + if (sortOrder == JobStats.SortCriterion.MIN ) jobStats.SortByMinValue(); jobStats.write(); } if (interactive) { @@ -767,14 +802,22 @@ private static void printHelpText() { "----------------------------------------------------------------------\n" + "usage: trick-jperf [options] \n" + "options: \n" - + "--help\n" - + "--nogui\n" - + "--report\n" - + "--sort=id\n" - + "--sort=mean\n" - + "--sort=stddev\n" - + "--sort=min\n" - + "--sort=max\n" + + "-h, --help\n" + + " Print this help text and exit." + + "-x, --nogui\n" + + " Don't run as a GUI application. Command line only." + + "-p, --report\n" + + " Write sorted job statics report to the terminal." + + "-s0, --sort=id\n" + + " Sort job statistics by identifier." + + "-s1, --sort=mean [default]\n" + + " Sort job statistics by mean duration." + + "-s2, --sort=stddev\n" + + " Sort job statistics by standard deviation of duration." + + "-s3, --sort=min\n" + + " Sort job statistics by minimum duration." + + "-s4, --sort=max\n" + + " Sort job statistics by maximum duration." + "----------------------------------------------------------------------\n" ); } From c311abce8ae54d2c3b3c0bd0ee3ad2a1f5b8f39d Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Wed, 30 Oct 2024 11:57:37 -0500 Subject: [PATCH 07/13] 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 000000000..180a26772 --- /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 72426b207..b1169f9b8 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 JobPerf( String[] args ) { ++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 JobPerf( String[] args ) { } } + /** + * 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 @@ private ArrayList JobExecutionEventList( String fileName ) { 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 000000000..fd709c406 --- /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 000000000..7c91e0079 --- /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 000000000..94d3407b7 --- /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 000000000..53159543e --- /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 000000000..f441fd4c6 --- /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 000000000..169e2e248 --- /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 000000000..c5a690caf --- /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 000000000..1ee5353ee --- /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 000000000..c31e0e380 --- /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 000000000..23741a079 --- /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(); + } +} From efe90ae2304ef68913687043161b47f9bddb515b Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Mon, 2 Dec 2024 12:17:46 -0600 Subject: [PATCH 08/13] Frame range selection and speed improvements. --- .../main/java/trick/jobperf/FrameRecord.java | 27 ++ .../jobperf/InvalidFrameBoundsExpection.java | 12 + .../src/main/java/trick/jobperf/JobPerf.java | 12 +- .../java/trick/jobperf/TraceViewCanvas.java | 259 ++++++++++++------ .../trick/jobperf/TraceViewInputToolBar.java | 117 ++++++-- .../java/trick/jobperf/TraceViewMenuBar.java | 10 +- .../trick/jobperf/TraceViewOutputToolBar.java | 34 +++ .../java/trick/jobperf/TraceViewWindow.java | 13 +- 8 files changed, 351 insertions(+), 133 deletions(-) create mode 100644 trick_source/java/src/main/java/trick/jobperf/FrameRecord.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/InvalidFrameBoundsExpection.java diff --git a/trick_source/java/src/main/java/trick/jobperf/FrameRecord.java b/trick_source/java/src/main/java/trick/jobperf/FrameRecord.java new file mode 100644 index 000000000..2f4ce8f7e --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/FrameRecord.java @@ -0,0 +1,27 @@ +package trick.jobperf; +import java.util.*; +/** +* Class FrameRecord represents the set of jobs that have been executed during a +* frame. +*/ +public class FrameRecord { + public ArrayList jobEvents; + public double start; + public double stop; + /** + * Constructor + */ + public FrameRecord() { + start = 0.0; + stop = 0.0; + jobEvents = new ArrayList() + + ; + } + /** + * @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/InvalidFrameBoundsExpection.java b/trick_source/java/src/main/java/trick/jobperf/InvalidFrameBoundsExpection.java new file mode 100644 index 000000000..faded8ec7 --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/InvalidFrameBoundsExpection.java @@ -0,0 +1,12 @@ +package trick.jobperf; + +/** +* Class InvalidFrameBoundsExpection is an exception indicating +* that the user has specified an illegal range for the frames +* to be rendered. +*/ +class InvalidFrameBoundsExpection extends Exception { + public InvalidFrameBoundsExpection(String message) { + super(message); + } +} 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 b1169f9b8..3992c3b86 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobPerf.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java @@ -6,9 +6,15 @@ import javax.swing.*; /** -* 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. + * Capabilites That Need To Be Added + * - a way to filter the data to be within a user specified sub time period + * within the data set. + */ + +/** +* Class JobPerf is an application that renders time-line data from a Trick based + simulation. It also 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; diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java index 169e2e248..c6f28128a 100644 --- a/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java @@ -11,44 +11,61 @@ /** * 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.] +* an ArrayList of JobExecutionEvent's [jobExecEvtList]. Information regarding +* mouse clicks are sent to the TraceViewOutputToolBar [outputToolBar.] +* @author John M. Penn */ 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 DEFAULT_TRACE_WIDTH = 15; 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; + public static final int DEFAULT_FRAMES_TO_RENDER = 100; private int traceWidth; - private double frameDuration; - private List jobExecList; + private double frameSize; + private double totalDuration; + private FrameRecord[] frameArray; + private FrameRange frameRenderRange; private KeyedColorMap idToColorMap; private BufferedImage image; private TraceViewOutputToolBar sToolBar; private Cursor crossHairCursor; private Cursor defaultCursor; + public class FrameRange { + public int first; + public int last; + FrameRange (int first, int last) { + this.first = first; + this.last = last; + } + public boolean contains(int n) { + return ((first <= n) && (n <= last)); + } + public int size() { + return last - first + 1; + } + } + /** * 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 ) { + public TraceViewCanvas( ArrayList jobExecEvtList, + TraceViewOutputToolBar outputToolBar ) { traceWidth = DEFAULT_TRACE_WIDTH; - frameDuration = 1.0; + frameSize = 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(); @@ -56,34 +73,44 @@ public TraceViewCanvas( ArrayList jobExecEvtList, TraceViewOu 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); + + List frameList = new ArrayList(); + FrameRecord frameRecord = new FrameRecord(); + for (JobExecutionEvent jobExec : jobExecEvtList ) { + + if (!wasTOF && jobExec.isTOF) { + // Wrap up the previous frame record. + frameRecord.stop = jobExec.start; + frameList.add(frameRecord); + + // Start a new frame record. + frameRecord = new FrameRecord(); + frameRecord.start = jobExec.start; + } + frameRecord.jobEvents.add(jobExec); + + wasTOF = jobExec.isTOF; + idToColorMap.addKey(jobExec.id); + } + frameArray = frameList.toArray( new FrameRecord[ frameList.size() ]); + + // Estimate the total duration and the average frame size. Notice + // that we skip the first frame. + totalDuration = 0.0; + for (int n=1; n < frameArray.length; n++) { + totalDuration += frameArray[n].getDuration(); } + frameSize = totalDuration/(frameArray.length-1); - // Calculate the average frame size. - frameDuration = frameSizeSum / frameSizeCount; + // Set the range of frames to be rendered. + int last_frame_to_render = frameArray.length-1; + if ( frameArray.length > DEFAULT_FRAMES_TO_RENDER) { + last_frame_to_render = DEFAULT_FRAMES_TO_RENDER-1; + } + frameRenderRange = new FrameRange(0, last_frame_to_render); + + // Write the color file. idToColorMap.writeFile("IdToColors.txt"); System.out.println("File loaded.\n"); @@ -95,28 +122,60 @@ public TraceViewCanvas( ArrayList jobExecEvtList, TraceViewOu System.exit(0); } - int preferredHeight = traceWidth * (int)((largestStop - smallestStart) / frameDuration) + TOP_MARGIN; - setPreferredSize(new Dimension(500, preferredHeight)); + setPreferredSize(new Dimension(500, neededPanelHeight())); ViewListener viewListener = new ViewListener(); addMouseListener(viewListener); addMouseMotionListener(viewListener); } + public int getFrameTotal() { + return frameArray.length; + } + + public int getFirstRenderFrame() { + return frameRenderRange.first; + } + + public void setFirstRenderFrame(int first) throws InvalidFrameBoundsExpection { + if ((first >= 0) && (first <= frameRenderRange.last)) { + frameRenderRange = new FrameRange(first, frameRenderRange.last); + setPreferredSize(new Dimension(500, neededPanelHeight())); + repaint(); + } else { + throw new InvalidFrameBoundsExpection(""); + } + } + + public int getLastRenderFrame() { + return frameRenderRange.last; + } + + public void setLastRenderFrame(int last) throws InvalidFrameBoundsExpection { + if ((last >= frameRenderRange.first) && (last < frameArray.length)) { + frameRenderRange = new FrameRange(frameRenderRange.first, last); + // Re-render this TraceViewCanvas. + setPreferredSize(new Dimension(500, neededPanelHeight())); + repaint(); + } else { + throw new InvalidFrameBoundsExpection(""); + } + } + /** - * @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. + * @return the current working frame size (seconds) 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; + public double getFrameSize() { + return frameSize; } /** - * Set the frame size to be used for rendering the timeline data. + * Set the frame size (seconds) to be used for rendering the timeline data. * @param duration the frame size. */ - public void setFrameDuration(double duration) { - frameDuration = duration; + public void setFrameSize(double time) { + frameSize = time; repaint(); } @@ -124,7 +183,7 @@ public void setFrameDuration(double duration) { * 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() { + public void incrementTraceWidth() { if (traceWidth < MAX_TRACE_WIDTH) { traceWidth ++; repaint(); @@ -135,7 +194,7 @@ public void increaseTraceWidth() { * 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() { + public void decrementTraceWidth() { if (traceWidth > MIN_TRACE_WIDTH) { traceWidth --; repaint(); @@ -150,19 +209,7 @@ 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; + if (( y < TOP_MARGIN) || (y > (TOP_MARGIN + traceRectHeight()))) return false; return true; } @@ -177,20 +224,47 @@ public void mouseReleased(MouseEvent e) { int y = e.getY(); Color color = new Color ( image.getRGB(x,y) ); + // Get and display the ID of the job associated with the color. String id = idToColorMap.getKeyOfColor( color ); sToolBar.setJobID(id); + // Determine the frame number that we clicked on from the y- + // coordinate of the click position. + int frameNumber = 0; if ( y > TOP_MARGIN) { - int frameNumber = (y - TOP_MARGIN) / traceWidth; + frameNumber = (y - TOP_MARGIN) / traceWidth + frameRenderRange.first; sToolBar.setFrameNumber(frameNumber); } + + // Determine the subframe-time where we clicked from the x-coordinate + // of the click position. if ( traceRectContains(x, y)) { - double pixelsPerSecond = (double)calcTraceRectWidth() / frameDuration; + double pixelsPerSecond = (double)traceRectWidth() / frameSize; double subFrameTime = (x - LEFT_MARGIN) / pixelsPerSecond; sToolBar.setSubFrameTime(subFrameTime); } + + /** + * If we clicked on a job trace (above), show the start and stop + * times of the job, otherwise clear the start and stop fields. + */ + if (id != null) { + FrameRecord frame = frameArray[frameNumber]; + for (JobExecutionEvent jobExec : frame.jobEvents) { + if (id.equals( jobExec.id)) { + sToolBar.setJobStartTime(jobExec.start); + sToolBar.setJobStopTime(jobExec.stop); + } + } + } else { + sToolBar.clearJobStartStopTime(); + } } + /** + * Set the cursor to a crossHairCursor if it's over the frame traces, + * otherwise, set it to the defaultCursor. + */ @Override public void mouseMoved(MouseEvent e) { int x = e.getX(); @@ -206,17 +280,25 @@ public void mouseMoved(MouseEvent e) { /** * @return the height of the trace rectangle. */ - private int calcTraceRectHeight() { - return ( getHeight() - TOP_MARGIN - BOTTOM_MARGIN); + private int traceRectHeight() { + return traceWidth * frameRenderRange.size(); } /** * @return the width of the trace rectangle. */ - private int calcTraceRectWidth() { + private int traceRectWidth() { return ( getWidth() - LEFT_MARGIN - RIGHT_MARGIN); } + /** + * Calculate the height of the TraceViewCanvas (JPanel) needed to render the + * selected range of frames. + */ + private int neededPanelHeight() { + return traceWidth * frameRenderRange.size() + TOP_MARGIN + BOTTOM_MARGIN; + } + /** * Render the job execution traces in the jobExecEvtList. */ @@ -230,9 +312,9 @@ private void doDrawing(Graphics g) { rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - int traceRectHeight = calcTraceRectHeight(); - int traceRectWidth = calcTraceRectWidth(); - double pixelsPerSecond = (double)traceRectWidth / frameDuration; + int traceRectHeight = traceRectHeight(); + int traceRectWidth = traceRectWidth(); + double pixelsPerSecond = (double)traceRectWidth / frameSize; // Panel Background Color Fill g2d.setPaint(Color.WHITE); @@ -240,35 +322,32 @@ private void doDrawing(Graphics g) { // 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; + g2d.fillRect(LEFT_MARGIN, TOP_MARGIN, traceRectWidth, traceRectHeight()); - for (JobExecutionEvent jobExec : jobExecList ) { + // Draw each frame in the selected range of frames to be rendered. + for (int n = frameRenderRange.first; + n <= frameRenderRange.last; + n++) { - if (!wasTOF && jobExec.isTOF) { - startOfFrame = jobExec.start; - frameNumber ++; - } + FrameRecord frame = frameArray[n]; - 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); + // Draw the frame + for (JobExecutionEvent jobExec : frame.jobEvents) { + int jobY = TOP_MARGIN + (n - frameRenderRange.first) * traceWidth; + int jobStartX = LEFT_MARGIN + (int)((jobExec.start - frame.start) * pixelsPerSecond); + int jobWidth = (int)( (jobExec.stop - jobExec.start) * pixelsPerSecond); + g2d.setPaint(Color.BLACK); + g2d.drawString ( String.format("%d", n), 50, jobY + traceWidth/2); + g2d.setPaint( idToColorMap.getColor( jobExec.id ) ); + g2d.fillRect(jobStartX, jobY, jobWidth, traceWidth-2); + } } } + /** + * This function paints the TraceViewCanvas (i.e, JPanel) when required. + */ @Override public void paintComponent(Graphics g) { super.paintComponent(g); diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java index c5a690caf..c441b1f74 100644 --- a/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java @@ -10,50 +10,109 @@ * 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 ); +* traceView.setFrameSize( newFrameSize ); +* +* Class TraceViewInputToolBar aggregates the following GUI components: +* TraceViewInputToolBar (isa JToolBar) +* JLabel () +* JTextField [frameSizeField] +* JLabel +* JLabel +* JTextField [firstRenderFrameField] +* JLabel +* JTextField [lastRenderFrameField] */ -public class TraceViewInputToolBar extends JToolBar implements ActionListener { +public class TraceViewInputToolBar extends JToolBar { private TraceViewCanvas traceView; - private JTextField frameDurationField; + private JTextField frameSizeField; + private JTextField firstRenderFrameField; + private JTextField lastRenderFrameField; /** * 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); + frameSizeField = new JTextField(15); + frameSizeField.setText( String.format("%8.4f", traceView.getFrameSize()) ); + add(frameSizeField); + frameSizeField.addKeyListener( new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + setFrameSize(); + } + } + }); - JButton setButton = new JButton("Set"); - setButton.addActionListener(this); - setButton.setActionCommand("setFrameSize"); - setButton.setToolTipText("Set frame size in seconds."); - add(setButton); + add( new JLabel( String.format(" Total Frame Range: %d ... %d", 0, traceView.getFrameTotal()-1 ))); - // Add Trick LOGO here. + add( new JLabel(" Selected Frame Range: ")); - } - @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()) ); + firstRenderFrameField = new JTextField(15); + firstRenderFrameField.setText( String.format("%d", traceView.getFirstRenderFrame()) ); + add(firstRenderFrameField); + firstRenderFrameField.addKeyListener( new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + setFirstRenderFrame(); } - if ( newFrameSize > 0.0) { - traceView.setFrameDuration( newFrameSize ); + } + }); + + add( new JLabel("...")); + lastRenderFrameField = new JTextField(15); + lastRenderFrameField.setText( String.format("%d", traceView.getLastRenderFrame()) ); + add(lastRenderFrameField); + lastRenderFrameField.addKeyListener( new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ENTER) { + setLastRenderFrame(); } - break; - default: - System.out.println("Unknown Action Command:" + s); - break; + } + }); + + // Add Trick LOGO here. + } + + private void setFirstRenderFrame() { + int newStartFrame = 0; + try { + newStartFrame = Integer.parseInt( firstRenderFrameField.getText() ); + traceView.setFirstRenderFrame( newStartFrame ); + } catch ( NumberFormatException e) { + firstRenderFrameField.setText( String.format("%d", traceView.getFirstRenderFrame())); + } catch ( InvalidFrameBoundsExpection e) { + firstRenderFrameField.setText( String.format("%d", traceView.getFirstRenderFrame())); + } + } + + private void setLastRenderFrame() { + int newFinalFrame = 0; + try { + newFinalFrame = Integer.parseInt( lastRenderFrameField.getText() ); + traceView.setLastRenderFrame( newFinalFrame ); + } catch ( NumberFormatException e) { + lastRenderFrameField.setText( String.format("%d", traceView.getLastRenderFrame())); + } catch (InvalidFrameBoundsExpection e) { + lastRenderFrameField.setText( String.format("%d", traceView.getLastRenderFrame())); + } + } + + private void setFrameSize() { + double newFrameSize = 0.0; + try { + newFrameSize = Double.parseDouble( frameSizeField.getText() ); + } catch ( NumberFormatException e) { + frameSizeField.setText( String.format("%8.4f", traceView.getFrameSize()) ); + } + if ( newFrameSize > 0.0) { + traceView.setFrameSize( newFrameSize ); } } } diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewMenuBar.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewMenuBar.java index 1ee5353ee..cae9d40be 100644 --- a/trick_source/java/src/main/java/trick/jobperf/TraceViewMenuBar.java +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewMenuBar.java @@ -13,8 +13,8 @@ * JMenuItem [fileMenuExit], Action: Call System.exit(0); * JMenu [optionsMenu] * JMenu [traceSizeMenu] -* JMenuItem [traceSizeMenuIncrease], Action: Call traceView.increaseTraceWidth(). -* JMenuItem [traceSizeMenuDecrease], Action: Call traceView.decreaseTraceWidth() +* JMenuItem [traceSizeMenuIncrease], Action: Call traceView.incrementTraceWidth(). +* JMenuItem [traceSizeMenuDecrease], Action: Call traceView.decrementTraceWidth() */ public class TraceViewMenuBar extends JMenuBar implements ActionListener { @@ -38,7 +38,7 @@ public TraceViewMenuBar(TraceViewCanvas tvc) { 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 ); + KeyStroke ctrlPlus = KeyStroke.getKeyStroke('=', InputEvent.CTRL_MASK ); traceSizeMenuIncrease.setAccelerator(ctrlPlus); traceSizeMenuIncrease.addActionListener(this); traceSizeMenu.add(traceSizeMenuIncrease); @@ -57,10 +57,10 @@ public void actionPerformed(ActionEvent e) { String s = e.getActionCommand(); switch (s) { case "increase-trace_width": - traceView.increaseTraceWidth(); + traceView.incrementTraceWidth(); break; case "decrease-trace_width": - traceView.decreaseTraceWidth(); + traceView.decrementTraceWidth(); break; case "exit": System.exit(0); diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewOutputToolBar.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewOutputToolBar.java index c31e0e380..d0ea6a380 100644 --- a/trick_source/java/src/main/java/trick/jobperf/TraceViewOutputToolBar.java +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewOutputToolBar.java @@ -9,6 +9,8 @@ */ class TraceViewOutputToolBar extends JToolBar { private JTextField IDField; + private JTextField startField; + private JTextField stopField; private JTextField frameNumberField; private JTextField subFrameTimeField; @@ -23,6 +25,18 @@ public TraceViewOutputToolBar () { IDField.setText( ""); add(IDField); + add( new JLabel(" Job Start: ")); + startField = new JTextField(15); + startField.setEditable(false); + startField.setText( ""); + add(startField); + + add( new JLabel(" Job Stop: ")); + stopField = new JTextField(15); + stopField.setEditable(false); + stopField.setText( ""); + add(stopField); + add( new JLabel(" Frame Number: ")); frameNumberField = new JTextField(15); frameNumberField.setEditable(false); @@ -41,6 +55,26 @@ public TraceViewOutputToolBar () { public void setJobID(String id) { IDField.setText( id ); } + /** + * @param time to be displayed in the job start field. + */ + public void setJobStartTime(Double time) { + startField.setText( String.format("%8.4f", time) ); + } + /** + * @param time to be displayed in the job stop field. + */ + public void setJobStopTime(Double time) { + stopField.setText( String.format("%8.4f", time) ); + } + /** + * Clear the startField and stopField. + */ + public void clearJobStartStopTime() { + startField.setText(""); + stopField.setText(""); + IDField.setText(""); + } /** * @param fn frame number to display. */ diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewWindow.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewWindow.java index 23741a079..b9ba346ee 100644 --- a/trick_source/java/src/main/java/trick/jobperf/TraceViewWindow.java +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewWindow.java @@ -13,7 +13,7 @@ * - JPanel [mainPanel] * - JPanel [tracePanel] * - JScrollPane [scrollPane] -* - TraceViewCanvas [traceView] +* - TraceViewCanvas [traceViewCanvas] * - TraceViewOutputToolBar [outputToolBar] */ public class TraceViewWindow extends JFrame { @@ -24,16 +24,17 @@ public class TraceViewWindow extends JFrame { */ public TraceViewWindow( ArrayList jobExecList ) { TraceViewOutputToolBar outputToolBar = new TraceViewOutputToolBar(); - TraceViewCanvas traceView = new TraceViewCanvas( jobExecList, outputToolBar); + TraceViewCanvas traceViewCanvas = new TraceViewCanvas( jobExecList, outputToolBar); - TraceViewMenuBar menuBar = new TraceViewMenuBar(traceView); + TraceViewMenuBar menuBar = new TraceViewMenuBar( traceViewCanvas); setJMenuBar(menuBar); - TraceViewInputToolBar nToolBar = new TraceViewInputToolBar( traceView ); + TraceViewInputToolBar nToolBar = new TraceViewInputToolBar( traceViewCanvas ); add(nToolBar, BorderLayout.NORTH); - JScrollPane scrollPane = new JScrollPane( traceView ); + JScrollPane scrollPane = new JScrollPane( traceViewCanvas ); scrollPane.setPreferredSize(new Dimension(800, 400)); + scrollPane.getVerticalScrollBar().setUnitIncrement( 20 ); JPanel tracePanel = new JPanel(); tracePanel.setPreferredSize(new Dimension(800, 400)); @@ -55,6 +56,6 @@ public TraceViewWindow( ArrayList jobExecList ) { setFocusable(true); setVisible(true); - traceView.repaint(); + traceViewCanvas.repaint(); } } From 590c3dda9b39b14801aa85827c9c85a7d4b921f4 Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Wed, 4 Dec 2024 14:16:04 -0600 Subject: [PATCH 09/13] Indicate selected frame --- .../java/src/main/java/trick/jobperf/JobPerf.java | 2 +- .../main/java/trick/jobperf/TraceViewCanvas.java | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) 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 3992c3b86..205de5d1c 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobPerf.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java @@ -16,7 +16,7 @@ simulation. It also generates run-time statistics reports for the simulation jobs. It can be run with or without a GUI. */ -public class JobPerf extends JFrame { +public class JobPerf { ArrayList jobExecEvtList; JobStats jobStats; diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java index c6f28128a..485b0f25d 100644 --- a/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java @@ -30,6 +30,7 @@ public class TraceViewCanvas extends JPanel { private double frameSize; private double totalDuration; private FrameRecord[] frameArray; + private int selectedFrameNumber; private FrameRange frameRenderRange; private KeyedColorMap idToColorMap; private BufferedImage image; @@ -63,6 +64,7 @@ public TraceViewCanvas( ArrayList jobExecEvtList, traceWidth = DEFAULT_TRACE_WIDTH; frameSize = 1.0; image = null; + selectedFrameNumber = 0; sToolBar = outputToolBar; crossHairCursor = new Cursor( Cursor.CROSSHAIR_CURSOR ); defaultCursor = new Cursor( Cursor.DEFAULT_CURSOR ); @@ -230,10 +232,10 @@ public void mouseReleased(MouseEvent e) { // Determine the frame number that we clicked on from the y- // coordinate of the click position. - int frameNumber = 0; + if ( y > TOP_MARGIN) { - frameNumber = (y - TOP_MARGIN) / traceWidth + frameRenderRange.first; - sToolBar.setFrameNumber(frameNumber); + selectedFrameNumber = (y - TOP_MARGIN) / traceWidth + frameRenderRange.first; + sToolBar.setFrameNumber(selectedFrameNumber); } // Determine the subframe-time where we clicked from the x-coordinate @@ -249,13 +251,14 @@ public void mouseReleased(MouseEvent e) { * times of the job, otherwise clear the start and stop fields. */ if (id != null) { - FrameRecord frame = frameArray[frameNumber]; + FrameRecord frame = frameArray[selectedFrameNumber]; for (JobExecutionEvent jobExec : frame.jobEvents) { if (id.equals( jobExec.id)) { sToolBar.setJobStartTime(jobExec.start); sToolBar.setJobStopTime(jobExec.stop); } } + repaint(); } else { sToolBar.clearJobStartStopTime(); } @@ -338,6 +341,9 @@ private void doDrawing(Graphics g) { int jobWidth = (int)( (jobExec.stop - jobExec.start) * pixelsPerSecond); g2d.setPaint(Color.BLACK); + if (n == selectedFrameNumber) { + g2d.setPaint(Color.GREEN); + } g2d.drawString ( String.format("%d", n), 50, jobY + traceWidth/2); g2d.setPaint( idToColorMap.getColor( jobExec.id ) ); g2d.fillRect(jobStartX, jobY, jobWidth, traceWidth-2); From 8533029a620d3331a4181afc15992fc6f0721da9 Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Thu, 23 Jan 2025 14:50:38 -0600 Subject: [PATCH 10/13] Added Jobs-stats and, Frame-details windows, job names,classes, contained jobs and so forth. --- .../main/java/trick/jobperf/FrameRecord.java | 55 ++++++- .../java/trick/jobperf/FrameViewCanvas.java | 92 +++++++++++ .../java/trick/jobperf/FrameViewWindow.java | 31 ++++ .../java/trick/jobperf/JobExecutionEvent.java | 28 +++- .../src/main/java/trick/jobperf/JobPerf.java | 58 +++++-- .../java/trick/jobperf/JobSpecification.java | 33 ++++ .../trick/jobperf/JobSpecificationMap.java | 59 +++++++ .../src/main/java/trick/jobperf/JobStats.java | 39 +++-- .../trick/jobperf/JobStatsViewCanvas.java | 91 +++++++++++ .../trick/jobperf/JobStatsViewWindow.java | 113 ++++++++++++++ .../java/trick/jobperf/KeyedColorMap.java | 8 +- .../java/trick/jobperf/StatisticsRecord.java | 16 +- .../java/trick/jobperf/TraceViewCanvas.java | 144 +++++++++++++----- .../trick/jobperf/TraceViewInputToolBar.java | 36 ++++- .../java/trick/jobperf/TraceViewMenuBar.java | 60 +++++--- .../trick/jobperf/TraceViewOutputToolBar.java | 92 ++++++----- .../java/trick/jobperf/TraceViewWindow.java | 8 +- 17 files changed, 810 insertions(+), 153 deletions(-) create mode 100644 trick_source/java/src/main/java/trick/jobperf/FrameViewCanvas.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/FrameViewWindow.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/JobSpecification.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/JobSpecificationMap.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/JobStatsViewCanvas.java create mode 100644 trick_source/java/src/main/java/trick/jobperf/JobStatsViewWindow.java diff --git a/trick_source/java/src/main/java/trick/jobperf/FrameRecord.java b/trick_source/java/src/main/java/trick/jobperf/FrameRecord.java index 2f4ce8f7e..fd92e4f4a 100644 --- a/trick_source/java/src/main/java/trick/jobperf/FrameRecord.java +++ b/trick_source/java/src/main/java/trick/jobperf/FrameRecord.java @@ -1,5 +1,30 @@ package trick.jobperf; import java.util.*; + +/** +* Class CompareByDuration compares two JobExecutionEvent's by their duration. +*/ +class CompareByDuration implements Comparator { + public int compare(JobExecutionEvent a, JobExecutionEvent b) { + Double dur_a = a.stop - a.start; + Double dur_b = b.stop - b.start; + if ( dur_a > dur_b) return -1; + if ( dur_a < dur_b) return 1; + return 0; + } +} + +/** +* Class CompareByDuration compares two JobExecutionEvent's by their start time. +*/ +class CompareByStartTime implements Comparator { + public int compare(JobExecutionEvent a, JobExecutionEvent b) { + if ( a.start < b.start) return -1; + if ( a.start > a.start) return 1; + return 0; + } +} + /** * Class FrameRecord represents the set of jobs that have been executed during a * frame. @@ -14,14 +39,38 @@ public class FrameRecord { public FrameRecord() { start = 0.0; stop = 0.0; - jobEvents = new ArrayList() - - ; + jobEvents = new ArrayList(); } + /** * @return the stop time minus the start time. */ public double getDuration() { return stop - start; } + + public void SortByJobEventDuration() { + Collections.sort( jobEvents, new CompareByDuration()); + } + + public void SortByStartTime() { + Collections.sort( jobEvents, new CompareByStartTime()); + } + + /** + * For each jobEvent in the frame, record the number of times + * its start time is contained within + * another jobs stop/stop range. + */ + public void CalculateJobContainment() { + SortByJobEventDuration(); + int N = jobEvents.size(); + for (int i = 0 ; i < (N-1); i++) { + for (int j = i+1 ; j < N; j++) { + if ( jobEvents.get(i).contains( jobEvents.get(j) )) { + jobEvents.get(j).contained ++ ; + } + } + } + } } diff --git a/trick_source/java/src/main/java/trick/jobperf/FrameViewCanvas.java b/trick_source/java/src/main/java/trick/jobperf/FrameViewCanvas.java new file mode 100644 index 000000000..8ebdcebb5 --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/FrameViewCanvas.java @@ -0,0 +1,92 @@ +package trick.jobperf; + +import java.awt.*; +import java.io.*; +import java.util.*; +import javax.swing.*; + +public class FrameViewCanvas extends JPanel { + private FrameRecord frame; + private TraceViewCanvas tvc; + private Font headingsFont; + private Font dataFont; + + public FrameViewCanvas( TraceViewCanvas tvc, FrameRecord frame ) { + this.tvc = tvc; + this.frame = frame; + dataFont = new Font("Arial", Font.PLAIN, 18); + headingsFont = new Font("Arial", Font.BOLD, 18); + + setPreferredSize(new Dimension(800, neededPanelHeight())); + } + + 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); + + // Panel Background Color Fill + g2d.setPaint(Color.WHITE); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + // TITLE + g2d.setFont(headingsFont); + g2d.setPaint( Color.RED ); + g2d.drawString("Frame Details", 100, 50); + + // Column Headings + g2d.setFont(headingsFont); + g2d.setPaint( Color.BLUE ); + g2d.drawString("Job-ID", 100, 80); + g2d.drawString("Job-Class", 180, 80); + g2d.drawString("Start-Time", 420, 80); + g2d.drawString("Stop-Time", 520, 80); + g2d.drawString("Duration", 620, 80); + g2d.drawString("Job-Name", 740, 80); + + frame.SortByStartTime(); + + // For each job in the frame. + int jobY = 100; + for (JobExecutionEvent jobExec : frame.jobEvents) { + g2d.setPaint( tvc.idToColorMap.getColor( jobExec.id ) ); + g2d.fillRect(50, jobY, 20, 20); + g2d.setPaint( Color.BLACK ); + jobY += 20; + JobSpecification jobSpec = tvc.jobSpecificationMap.getJobSpecification(jobExec.id); + double duration = jobExec.stop - jobExec.start; + + g2d.setFont(dataFont); + g2d.drawString(jobExec.id, 100, jobY); + g2d.drawString(jobSpec.jobClass, 180, jobY); + g2d.drawString( String.format("%12.6f", jobExec.start), 420, jobY); + g2d.drawString( String.format("%12.6f", jobExec.stop), 520, jobY); + g2d.drawString( String.format("%12.6f", duration), 620, jobY); + g2d.drawString(jobSpec.name, 740, jobY); + } + frame.SortByJobEventDuration(); + } + + /** + * Calculate the height of the FrameViewCanvas (JPanel) needed to render the + * jobs in the frame. + */ + private int neededPanelHeight() { + return 20 * frame.jobEvents.size() + 100; + } + + /** + * This function paints the FrameViewCanvas (i.e, JPanel) when required. + */ + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + doDrawing(g); + } + +} diff --git a/trick_source/java/src/main/java/trick/jobperf/FrameViewWindow.java b/trick_source/java/src/main/java/trick/jobperf/FrameViewWindow.java new file mode 100644 index 000000000..2e0f8b971 --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/FrameViewWindow.java @@ -0,0 +1,31 @@ +package trick.jobperf; + +import java.awt.*; +import java.io.*; +import java.util.*; +import javax.swing.*; + +public class FrameViewWindow extends JFrame { + public FrameViewWindow( TraceViewCanvas tvc, FrameRecord frame, int frameNumber ) { + + FrameViewCanvas frameViewCanvas = new FrameViewCanvas(tvc, frame); + + JScrollPane scrollPane = new JScrollPane( frameViewCanvas ); + scrollPane.getVerticalScrollBar().setUnitIncrement( 20 ); + + JPanel scrollingFrameViewCanvas = new JPanel(); + scrollingFrameViewCanvas.add(scrollPane); + scrollingFrameViewCanvas.setLayout(new BoxLayout(scrollingFrameViewCanvas, BoxLayout.X_AXIS)); + + setTitle("Frame " + frameNumber); + setPreferredSize(new Dimension(1200, 400)); + add(scrollingFrameViewCanvas); + pack(); + setVisible(true); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + setFocusable(true); + setVisible(true); + + frameViewCanvas.repaint(); + } +} diff --git a/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java b/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java index 180a26772..af93f2baa 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java @@ -11,7 +11,6 @@ import javax.swing.event.*; import java.net.URL; - /** * Class JobExecutionEvent represents one execution/run of a Trick job. * identifies the job. and specify the @@ -25,6 +24,7 @@ class JobExecutionEvent { public boolean isTOF; public double start; public double stop; + public int contained; /** * @param identifier identifies the relavant Trick job. @@ -33,13 +33,27 @@ class JobExecutionEvent { * @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; + public JobExecutionEvent(String id, boolean isTOF, boolean isEOF, double start, double stop) { + this.id = id; + this.isEOF = isEOF; + this.isTOF = isTOF; + this.start = start; + this.stop = stop; + contained = 1; } + + /** + * Determine whether a job's start time is contained + * within another jobs stop/stop range. + */ + public boolean contains( JobExecutionEvent other ) { + if ((other.start >= this.start) && + (other.start <= this.stop)) { + return true; + } + return false; + } + /** * Create a String representation of an object of this class. */ 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 205de5d1c..b9365a435 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobPerf.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java @@ -5,12 +5,8 @@ import java.util.*; import javax.swing.*; -/** - * Capabilites That Need To Be Added - * - a way to filter the data to be within a user specified sub time period - * within the data set. - */ - +import java.nio.file.Path; +import java.nio.file.Paths; /** * Class JobPerf is an application that renders time-line data from a Trick based simulation. It also generates run-time statistics reports for the simulation @@ -29,7 +25,7 @@ public JobPerf( String[] args ) { boolean interactive = true; boolean printReport = false; JobStats.SortCriterion sortOrder = JobStats.SortCriterion.MEAN; - String fileName = "in.csv"; + String timeLineFileName = "in.csv"; int ii = 0; while (ii < args.length) { @@ -68,24 +64,58 @@ public JobPerf( String[] args ) { sortOrder = JobStats.SortCriterion.MIN; } break; default : { - fileName = args[ii]; + timeLineFileName = args[ii]; } break; } //switch ++ii; } // while - jobExecEvtList = getJobExecutionEventList(fileName); - jobStats = new JobStats(jobExecEvtList); + // All files shall be in the same directory as the timeline file. + String filesDir = Paths.get(timeLineFileName).toAbsolutePath().getParent().toString(); + System.out.println( "\n\nFilesDir = " + filesDir + "\n\n"); + + + // Generate the JobSpecificationMap from information extracted from the S_job_execution + // file, that should be in the same directory as the time-line file. + File s_job_execution_file = new File( filesDir + "/S_job_execution" ); + JobSpecificationMap jobSpecificationMap = null; + try { + jobSpecificationMap = new JobSpecificationMap( s_job_execution_file ); + } catch ( java.io.FileNotFoundException e ) { + System.out.println("File \"" + s_job_execution_file.toString() + "\" not found.\n"); + System.exit(0); + } catch ( java.io.IOException e ) { + System.out.println("IO Exception while attempting to read " + s_job_execution_file.toString() + ".\n"); + System.exit(0); + } + + // Read Color Map + KeyedColorMap idToColorMap = null; + File colorMapFile = null; + try { + colorMapFile = new File(filesDir + "/IdToColors.txt"); + idToColorMap = new KeyedColorMap( colorMapFile.toString()); + if ( colorMapFile.exists()) { + idToColorMap.readFile(); + } + } catch ( java.io.IOException e ) { + System.out.println("IO Exception while attempting to read " + colorMapFile.toString() + ".\n"); + System.exit(0); + } + + jobExecEvtList = getJobExecutionEventList(timeLineFileName); + if (printReport) { + jobStats = new JobStats(jobExecEvtList); if (sortOrder == JobStats.SortCriterion.ID ) jobStats.SortByID(); if (sortOrder == JobStats.SortCriterion.MEAN ) jobStats.SortByMeanValue(); if (sortOrder == JobStats.SortCriterion.STDDEV ) jobStats.SortByStdDev(); if (sortOrder == JobStats.SortCriterion.MAX ) jobStats.SortByMaxValue(); if (sortOrder == JobStats.SortCriterion.MIN ) jobStats.SortByMinValue(); - jobStats.write(); + jobStats.write( jobSpecificationMap); } if (interactive) { - traceViewWindow = new TraceViewWindow(jobExecEvtList); + traceViewWindow = new TraceViewWindow(jobExecEvtList, idToColorMap, jobSpecificationMap); } } @@ -132,7 +162,9 @@ private ArrayList getJobExecutionEventList( String fileName ) line = in.readLine(); while( (line = in.readLine()) !=null) { field = line.split(","); - String id = field[0]; + // Need to strip trailing 0's from the id to make the ID's in + // 1) timeline file and 2) the S_job_execution file consistent. + String id = field[0].replaceAll("0*$",""); boolean isTOF = false; if (Integer.parseInt(field[1]) == 1) isTOF = true; boolean isEOF = false; diff --git a/trick_source/java/src/main/java/trick/jobperf/JobSpecification.java b/trick_source/java/src/main/java/trick/jobperf/JobSpecification.java new file mode 100644 index 000000000..0b8e465f1 --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/JobSpecification.java @@ -0,0 +1,33 @@ +package trick.jobperf; + +import java.awt.*; +import java.io.*; +import java.util.*; + + +/** +* Class JobSpecification represents ... +*/ +class JobSpecification { + public String name; + public String jobClass; + public int phase; + + /** + * @param name identifies the relevant Trick job. + * @param jobClass the Trick job class. + * @param phase the Trick phase number of the Trick job. + */ + public JobSpecification(String name, String jobClass, int phase) { + this.name = name; + this.jobClass = jobClass; + this.phase = phase; + } + /** + * Create a String representation of an object of this jobClass. + */ + @Override + public String toString() { + return ( "JobSpecification: " + name + "," + jobClass + "," + phase ); + } +} diff --git a/trick_source/java/src/main/java/trick/jobperf/JobSpecificationMap.java b/trick_source/java/src/main/java/trick/jobperf/JobSpecificationMap.java new file mode 100644 index 000000000..d5f7b6d1b --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/JobSpecificationMap.java @@ -0,0 +1,59 @@ +package trick.jobperf; + +import java.awt.*; +import java.io.*; +import java.util.*; +import java.nio.file.*; + +/** +* Class JobSpecificationMap associates identifiers with unique RGB colors. +*/ +public class JobSpecificationMap { + private Map jobSpecMap; + + /** + * Constructor + */ + public JobSpecificationMap( File file ) throws IOException, FileNotFoundException { + jobSpecMap = new HashMap(); + System.out.println( "INSTANCIATING JobSpecificationMap("+ file.toString() +")."); + BufferedReader in = new BufferedReader( new FileReader( file.toString()) ); + String line; + String field[]; + + while( (line = in.readLine()) != null) { + if ( line.matches("\\s+1 [|].*$") ) { + field = line.split("[|]"); + if (field.length == 9) { + String jobclass = field[2].trim(); + int phase = Integer.parseInt( field[3].trim()); + String id = field[7].trim(); + String name = field[8].trim(); + // System.out.println( "JobSpec = <" + id + "," + name + "," + jobclass + ">\n\n"); + jobSpecMap.put(id, new JobSpecification(name, jobclass, phase)); + } + } + } + in.close(); + } + + /** + * Add an identifier, and a JobSpecification to the JobSpecificationMap. + * @ param identifier Specifies the key. + */ + public void addKey( String identifier, JobSpecification jobSpec) { + if (!jobSpecMap.containsKey(identifier)) { + jobSpecMap.put(identifier, jobSpec); + } + } + + /** + * Given an identifier, return the corresponding JobSpecification. + * @param identifier the key. + * @return the JobSpecification associated with the key. + */ + public JobSpecification getJobSpecification(String identifier) { + return jobSpecMap.get(identifier); + } + +} // class JobSpecificationMap diff --git a/trick_source/java/src/main/java/trick/jobperf/JobStats.java b/trick_source/java/src/main/java/trick/jobperf/JobStats.java index fd709c406..0bc4e5a03 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobStats.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobStats.java @@ -46,8 +46,8 @@ public int compare(StatisticsRecord a, StatisticsRecord b) { */ 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; + if ( a.minValue > b.minValue) return -1; + if ( a.minValue < b.minValue) return 1; return 0; } } @@ -87,8 +87,8 @@ enum SortCriterion { } } - SortCriterion currentSortCriterion = SortCriterion.MEAN; - ArrayList jobStatisticsList; + public SortCriterion currentSortCriterion = SortCriterion.MEAN; + public ArrayList jobStatisticsList; /** * Constructor @@ -122,6 +122,7 @@ public JobStats( ArrayList jobExecList ) { jobStatisticsList.add( new StatisticsRecord(id, mean, stddev, min, max)); } + SortByMeanValue(); } /** @@ -167,18 +168,26 @@ public void SortByMinValue() { /** Write a text report to System.out. */ - public void write() { + public void write( JobSpecificationMap jobSpecificationMap ) { + 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)); + System.out.println("--------------------------------------------------------------------------------------------------"); + System.out.println(" Job Id Mean Duration Std Dev Min Duration Max Duration Name"); + System.out.println("---------- -------------- -------------- -------------- -------------- ---------------------------"); + + for (StatisticsRecord jobStatisticsRecord : jobStatisticsList ) { + + JobSpecification jobSpec = jobSpecificationMap.getJobSpecification( jobStatisticsRecord.id); + + System.out.println( String.format("%10s %14.6f %14.6f %14.6f %14.6f %s", + jobStatisticsRecord.id, + jobStatisticsRecord.meanValue, + jobStatisticsRecord.stddev, + jobStatisticsRecord.minValue, + jobStatisticsRecord.maxValue, + jobSpec.name + ) + ); } } } diff --git a/trick_source/java/src/main/java/trick/jobperf/JobStatsViewCanvas.java b/trick_source/java/src/main/java/trick/jobperf/JobStatsViewCanvas.java new file mode 100644 index 000000000..5de148bce --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/JobStatsViewCanvas.java @@ -0,0 +1,91 @@ +package trick.jobperf; + +import java.awt.*; +import java.io.*; +import java.util.*; +import javax.swing.*; + +public class JobStatsViewCanvas extends JPanel { + + private Font headingsFont; + private Font dataFont; + JobStats jobStats; + JobSpecificationMap jobSpecificationMap; + + public JobStatsViewCanvas( JobStats jobStats, + JobSpecificationMap jobSpecificationMap ) { + this.jobStats = jobStats; + this.jobSpecificationMap = jobSpecificationMap; + + dataFont = new Font("Arial", Font.PLAIN, 18); + headingsFont = new Font("Arial", Font.BOLD, 18); + + setPreferredSize(new Dimension(800, neededPanelHeight())); + } + + 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); + + // Panel Background Color Fill + g2d.setPaint(Color.WHITE); + g2d.fillRect(0, 0, getWidth(), getHeight()); + + // Title + g2d.setFont(headingsFont); + g2d.setPaint( Color.RED ); + g2d.drawString("Jobs Duration Statistics Sorted by " + jobStats.currentSortCriterion, 100, 50); + + // Column Headings + g2d.setFont(headingsFont); + + g2d.setPaint( Color.BLUE ); + g2d.drawString("Job-ID", 100, 80); + g2d.drawString("Mean Dur", 200, 80); + g2d.drawString("Std Dev", 300, 80); + g2d.drawString("Min Dur", 400, 80); + g2d.drawString("Max Dur", 500, 80); + g2d.drawString("Job-Name", 600, 80); + + // For each record + int jobY = 100; + for (StatisticsRecord jobStatisticsRecord : jobStats.jobStatisticsList ) { + + JobSpecification jobSpec = jobSpecificationMap.getJobSpecification( jobStatisticsRecord.id); + + g2d.setFont(dataFont); + g2d.setPaint( Color.BLACK ); + g2d.drawString(jobStatisticsRecord.id, 100, jobY); + g2d.drawString( String.format("%14.6f", jobStatisticsRecord.meanValue), 180, jobY); + g2d.drawString( String.format("%14.6f", jobStatisticsRecord.stddev), 280, jobY); + g2d.drawString( String.format("%14.6f", jobStatisticsRecord.minValue), 380, jobY); + g2d.drawString( String.format("%14.6f", jobStatisticsRecord.maxValue), 480, jobY); + g2d.drawString(jobSpec.name, 600, jobY); + jobY += 20; + } + } + + /** + * Calculate the height of the JobStatsCanvas (JPanel) needed to render the + * jobs in the frame. + */ + private int neededPanelHeight() { + return 20 * jobStats.jobStatisticsList.size() + 100; + } + + /** + * This function paints the JobStatsCanvas (i.e, JPanel) when required. + */ + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + doDrawing(g); + } + +} diff --git a/trick_source/java/src/main/java/trick/jobperf/JobStatsViewWindow.java b/trick_source/java/src/main/java/trick/jobperf/JobStatsViewWindow.java new file mode 100644 index 000000000..f8f9af15e --- /dev/null +++ b/trick_source/java/src/main/java/trick/jobperf/JobStatsViewWindow.java @@ -0,0 +1,113 @@ +package trick.jobperf; + +import java.awt.*; +import java.awt.event.*; +import java.io.*; +import java.util.*; +import javax.swing.*; + +class SortButtonsToolBar extends JToolBar implements ActionListener { + JobStatsViewCanvas statsViewCanvas; + private JButton sortByIDButton; + private JButton sortByMean; + private JButton sortByStdDev; + private JButton sortByMin; + private JButton sortByMax; + + public SortButtonsToolBar( JobStatsViewCanvas statsViewCanvas ) { + this.statsViewCanvas = statsViewCanvas; + + add( new JLabel("Sort by : ")); + sortByIDButton = new JButton("ID"); + sortByIDButton.addActionListener(this); + sortByIDButton.setActionCommand("sort-by-ID"); + sortByIDButton.setToolTipText("Sort by Job ID"); + add(sortByIDButton); + + sortByMean = new JButton("Mean"); + sortByMean.addActionListener(this); + sortByMean.setActionCommand("sort-by-mean"); + sortByMean.setToolTipText("Sort by Mean Job Run Duration"); + add(sortByMean); + + sortByStdDev = new JButton("Std Dev"); + sortByStdDev.addActionListener(this); + sortByStdDev.setActionCommand("sort-by-std-dev"); + sortByStdDev.setToolTipText("Sort by Std Deviation of Job Run Duration"); + add(sortByStdDev); + + sortByMin = new JButton("Min"); + sortByMin.addActionListener(this); + sortByMin.setActionCommand("sort-by-min"); + sortByMin.setToolTipText("Sort by Minimum Job Run Duration"); + add(sortByMin); + + sortByMax = new JButton("Max"); + sortByMax.addActionListener(this); + sortByMax.setActionCommand("sort-by-max"); + sortByMax.setToolTipText("Sort by Maximum Job Run Duration"); + add(sortByMax); + } + + public void actionPerformed(ActionEvent e) { + String s = e.getActionCommand(); + switch (s) { + case "sort-by-ID": + statsViewCanvas.jobStats.SortByID(); + statsViewCanvas.repaint(); + break; + case "sort-by-mean": + statsViewCanvas.jobStats.SortByMeanValue(); + statsViewCanvas.repaint(); + break; + case "sort-by-std-dev": + statsViewCanvas.jobStats.SortByStdDev(); + statsViewCanvas.repaint(); + break; + case "sort-by-min": + statsViewCanvas.jobStats.SortByMinValue(); + statsViewCanvas.repaint(); + break; + case "sort-by-max": + statsViewCanvas.jobStats.SortByMaxValue(); + statsViewCanvas.repaint(); + break; + default: + System.out.println("Unknown Action Command:" + s); + break; + } + } +} + +public class JobStatsViewWindow extends JFrame { + + public JobStatsViewWindow( JobStats jobStats, JobSpecificationMap jobSpecificationMap ) { + + JobStatsViewCanvas statsViewCanvas = new JobStatsViewCanvas( jobStats, jobSpecificationMap); + + JScrollPane scrollPane = new JScrollPane( statsViewCanvas ); + scrollPane.setPreferredSize(new Dimension(800, 400)); + scrollPane.getVerticalScrollBar().setUnitIncrement( 20 ); + + SortButtonsToolBar toolbar = new SortButtonsToolBar( statsViewCanvas); + + JPanel scrollingJobStatsCanvas = new JPanel(); + scrollingJobStatsCanvas.setPreferredSize(new Dimension(800, 400)); + scrollingJobStatsCanvas.add(toolbar); + scrollingJobStatsCanvas.add(scrollPane); + + scrollingJobStatsCanvas.setLayout( new BoxLayout(scrollingJobStatsCanvas, BoxLayout.Y_AXIS)); + + setTitle("Job Statistics"); + // setSize(800, 500); + setPreferredSize(new Dimension(1200, 500)); + add(scrollingJobStatsCanvas); + pack(); + setVisible(true); + setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + setFocusable(true); + setVisible(true); + + statsViewCanvas.repaint(); + } +} diff --git a/trick_source/java/src/main/java/trick/jobperf/KeyedColorMap.java b/trick_source/java/src/main/java/trick/jobperf/KeyedColorMap.java index 7c91e0079..5e727453c 100644 --- a/trick_source/java/src/main/java/trick/jobperf/KeyedColorMap.java +++ b/trick_source/java/src/main/java/trick/jobperf/KeyedColorMap.java @@ -10,11 +10,13 @@ public class KeyedColorMap { private Map colorMap; int minLuminance; + String fileName; /** * Constructor */ - public KeyedColorMap() { + public KeyedColorMap(String fileName) { + this.fileName = fileName; colorMap = new HashMap(); minLuminance = 30; } @@ -82,7 +84,7 @@ public String getKeyOfColor(Color searchColor) { * Write the identifier, color key/value pairs of the KeyedColorMap to a file. * @param fileName */ - public void writeFile(String fileName) throws IOException { + public void writeFile() throws IOException { BufferedWriter out = new BufferedWriter( new FileWriter(fileName) ); for (Map.Entry entry : colorMap.entrySet()) { String id = entry.getKey(); @@ -100,7 +102,7 @@ public void writeFile(String fileName) throws IOException { * Read identifier, color key-value pairs into the KeyedColorMap from a file. * @param fileName */ - public void readFile(String fileName) throws IOException { + public void readFile() throws IOException { try { BufferedReader in = new BufferedReader( new FileReader(fileName) ); String line; diff --git a/trick_source/java/src/main/java/trick/jobperf/StatisticsRecord.java b/trick_source/java/src/main/java/trick/jobperf/StatisticsRecord.java index 53159543e..a1e851b84 100644 --- a/trick_source/java/src/main/java/trick/jobperf/StatisticsRecord.java +++ b/trick_source/java/src/main/java/trick/jobperf/StatisticsRecord.java @@ -12,17 +12,17 @@ public class StatisticsRecord { public double minValue; /** * Constructor - * @param s - the job identifier. + * @param id - the job identifier. * @param mean - the mean value of job duration. - * @param sd - the standard deviation of job duration. + * @param stddev - 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; + public StatisticsRecord( String id, double mean, double stddev, double min, double max) { + this.id = id; + this.meanValue = mean; + this.stddev = stddev; + this.minValue = min; + this.maxValue = max; } } diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java index 485b0f25d..9552ad826 100644 --- a/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java @@ -17,26 +17,31 @@ */ public class TraceViewCanvas extends JPanel { - public static final int MIN_TRACE_WIDTH = 4; - public static final int DEFAULT_TRACE_WIDTH = 15; - public static final int MAX_TRACE_WIDTH = 30; + public static final int MIN_TRACE_WIDTH = 12; + public static final int DEFAULT_TRACE_WIDTH = 18; + public static final int MAX_TRACE_WIDTH = 24; 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 TOP_MARGIN = 50; public static final int BOTTOM_MARGIN = 20; public static final int DEFAULT_FRAMES_TO_RENDER = 100; + public KeyedColorMap idToColorMap; + public JobSpecificationMap jobSpecificationMap; + public JobStats jobStats; + private int traceWidth; private double frameSize; private double totalDuration; private FrameRecord[] frameArray; private int selectedFrameNumber; private FrameRange frameRenderRange; - private KeyedColorMap idToColorMap; private BufferedImage image; - private TraceViewOutputToolBar sToolBar; + private TraceViewOutputToolBar outputToolBar; private Cursor crossHairCursor; private Cursor defaultCursor; + private Font frameFont12; + private Font frameFont18; public class FrameRange { public int first; @@ -59,22 +64,28 @@ public int size() { * @param outputToolBar the toolbar to which data is to be sent for display. */ public TraceViewCanvas( ArrayList jobExecEvtList, - TraceViewOutputToolBar outputToolBar ) { + TraceViewOutputToolBar outputToolBar, + KeyedColorMap idToColorMap, + JobSpecificationMap jobSpecificationMap ) { traceWidth = DEFAULT_TRACE_WIDTH; frameSize = 1.0; image = null; selectedFrameNumber = 0; - sToolBar = outputToolBar; + + this.outputToolBar = outputToolBar; + this.idToColorMap = idToColorMap; + this.jobSpecificationMap = jobSpecificationMap; + + jobStats = new JobStats(jobExecEvtList); + crossHairCursor = new Cursor( Cursor.CROSSHAIR_CURSOR ); defaultCursor = new Cursor( Cursor.DEFAULT_CURSOR ); + frameFont12 = new Font("Arial", Font.PLAIN, 12); + frameFont18 = new Font("Arial", Font.PLAIN, 18); + try { - idToColorMap = new KeyedColorMap(); - File colorfile = new File("IdToColors.txt"); - if (colorfile.exists()) { - idToColorMap.readFile("IdToColors.txt"); - } boolean wasTOF = false; List frameList = new ArrayList(); @@ -84,6 +95,7 @@ public TraceViewCanvas( ArrayList jobExecEvtList, if (!wasTOF && jobExec.isTOF) { // Wrap up the previous frame record. frameRecord.stop = jobExec.start; + frameRecord.CalculateJobContainment(); frameList.add(frameRecord); // Start a new frame record. @@ -95,9 +107,10 @@ public TraceViewCanvas( ArrayList jobExecEvtList, wasTOF = jobExec.isTOF; idToColorMap.addKey(jobExec.id); } + frameArray = frameList.toArray( new FrameRecord[ frameList.size() ]); - // Estimate the total duration and the average frame size. Notice + // Determine the total duration and the average frame size. Notice // that we skip the first frame. totalDuration = 0.0; for (int n=1; n < frameArray.length; n++) { @@ -112,13 +125,10 @@ public TraceViewCanvas( ArrayList jobExecEvtList, } frameRenderRange = new FrameRange(0, last_frame_to_render); - // Write the color file. - idToColorMap.writeFile("IdToColors.txt"); + // Write the color map to a file. + idToColorMap.writeFile(); - System.out.println("File loaded.\n"); - } catch ( java.io.FileNotFoundException e ) { - System.out.println("File not found.\n"); - System.exit(0); + // System.out.println("File loaded.\n"); } catch ( java.io.IOException e ) { System.out.println("IO Exception.\n"); System.exit(0); @@ -203,6 +213,20 @@ public void decrementTraceWidth() { } } + /** + * + */ + public void displaySelectedFrame() { + FrameViewWindow window = new FrameViewWindow( this, frameArray[selectedFrameNumber], selectedFrameNumber); + } + + /** + * + */ + public void displayJobStatsWindow() { + JobStatsViewWindow window = new JobStatsViewWindow( jobStats, jobSpecificationMap); + } + /** * @return true if the trace rectangle contains the point , otherwise * false. @@ -228,22 +252,27 @@ public void mouseReleased(MouseEvent e) { // Get and display the ID of the job associated with the color. String id = idToColorMap.getKeyOfColor( color ); - sToolBar.setJobID(id); + outputToolBar.setJobID(id); + + // Get and display the job name associated with the ID. + JobSpecification jobSpec = jobSpecificationMap.getJobSpecification(id); + if (jobSpec != null) { + outputToolBar.setJobName(jobSpec.name); + outputToolBar.setJobClass(jobSpec.jobClass); + } // Determine the frame number that we clicked on from the y- // coordinate of the click position. - if ( y > TOP_MARGIN) { selectedFrameNumber = (y - TOP_MARGIN) / traceWidth + frameRenderRange.first; - sToolBar.setFrameNumber(selectedFrameNumber); } // Determine the subframe-time where we clicked from the x-coordinate // of the click position. + double subFrameClickTime = 0.0; if ( traceRectContains(x, y)) { double pixelsPerSecond = (double)traceRectWidth() / frameSize; - double subFrameTime = (x - LEFT_MARGIN) / pixelsPerSecond; - sToolBar.setSubFrameTime(subFrameTime); + subFrameClickTime = (x - LEFT_MARGIN) / pixelsPerSecond; } /** @@ -252,15 +281,17 @@ public void mouseReleased(MouseEvent e) { */ if (id != null) { FrameRecord frame = frameArray[selectedFrameNumber]; + Double clickTime = frame.start + subFrameClickTime; for (JobExecutionEvent jobExec : frame.jobEvents) { - if (id.equals( jobExec.id)) { - sToolBar.setJobStartTime(jobExec.start); - sToolBar.setJobStopTime(jobExec.stop); + if (id.equals( jobExec.id) && + clickTime >= jobExec.start && + clickTime <= jobExec.stop ) { + outputToolBar.setJobTimes(jobExec.start, jobExec.stop); } } repaint(); } else { - sToolBar.clearJobStartStopTime(); + outputToolBar.clearJobFields(); } } @@ -327,26 +358,61 @@ private void doDrawing(Graphics g) { g2d.setPaint(Color.BLACK); g2d.fillRect(LEFT_MARGIN, TOP_MARGIN, traceRectWidth, traceRectHeight()); + if (traceWidth >= DEFAULT_TRACE_WIDTH) { + g2d.setFont(frameFont18); + } else { + g2d.setFont(frameFont12); + } + + FontMetrics fm = g2d.getFontMetrics(); + int TX = 0; + + String FN_text = "Frame #"; + TX = (LEFT_MARGIN - fm.stringWidth(FN_text))/2; + g2d.drawString (FN_text, TX, 40); + + g2d.drawString ("Top of Frame", LEFT_MARGIN, 40); + + String EOF_text = "End of Frame"; + TX = LEFT_MARGIN + traceRectWidth - fm.stringWidth(EOF_text); + g2d.drawString (EOF_text, TX, 40); + // Draw each frame in the selected range of frames to be rendered. for (int n = frameRenderRange.first; n <= frameRenderRange.last; n++) { FrameRecord frame = frameArray[n]; + int jobY = TOP_MARGIN + (n - frameRenderRange.first) * traceWidth; + + // Draw frame number. + if (n == selectedFrameNumber) { + g2d.setPaint(Color.RED); + // g2d.drawString ( "\u25b6", 20, jobY + traceWidth - 2); + g2d.drawString ( "\u25c0", 80, jobY + traceWidth - 2); + // g2d.fillRect(LEFT_MARGIN-traceWidth, jobY, traceWidth, traceWidth); + } else { + g2d.setPaint(Color.BLACK); + } + + g2d.drawString ( String.format("%d", n), 40, jobY + traceWidth - 2); // Draw the frame - for (JobExecutionEvent jobExec : frame.jobEvents) { - int jobY = TOP_MARGIN + (n - frameRenderRange.first) * traceWidth; - int jobStartX = LEFT_MARGIN + (int)((jobExec.start - frame.start) * pixelsPerSecond); - int jobWidth = (int)( (jobExec.stop - jobExec.start) * pixelsPerSecond); + // NOTE that the jobEvents within the frame are expected to be sorted in duration-order, + // so that smaller sub-jobs are not obscurred. - g2d.setPaint(Color.BLACK); - if (n == selectedFrameNumber) { - g2d.setPaint(Color.GREEN); - } - g2d.drawString ( String.format("%d", n), 50, jobY + traceWidth/2); + for (JobExecutionEvent jobExec : frame.jobEvents) { + int jobStartX = (int)((jobExec.start - frame.start) * pixelsPerSecond) + LEFT_MARGIN; + int jobWidth = (int)((jobExec.stop - jobExec.start) * pixelsPerSecond); g2d.setPaint( idToColorMap.getColor( jobExec.id ) ); - g2d.fillRect(jobStartX, jobY, jobWidth, traceWidth-2); + int jobHeight = traceWidth - 2; + if (jobExec.contained > 1) { + jobHeight = traceWidth / jobExec.contained; + } + + // int jobStartY = jobY + (traceWidth - 2) - jobHeight; + g2d.fillRect(jobStartX, jobY, jobWidth, jobHeight); + } } } diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java index c441b1f74..b09c6c23d 100644 --- a/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java @@ -22,10 +22,11 @@ * JLabel * JTextField [lastRenderFrameField] */ -public class TraceViewInputToolBar extends JToolBar { +public class TraceViewInputToolBar extends JToolBar implements ActionListener { private TraceViewCanvas traceView; private JTextField frameSizeField; + private JButton frameDetailsButton; private JTextField firstRenderFrameField; private JTextField lastRenderFrameField; /** @@ -35,8 +36,8 @@ public class TraceViewInputToolBar extends JToolBar { public TraceViewInputToolBar (TraceViewCanvas tvc) { traceView = tvc; - add( new JLabel(" Frame Size: ")); - frameSizeField = new JTextField(15); + add( new JLabel(" Frame Size (Avg): ")); + frameSizeField = new JTextField(10); frameSizeField.setText( String.format("%8.4f", traceView.getFrameSize()) ); add(frameSizeField); frameSizeField.addKeyListener( new KeyAdapter() { @@ -48,11 +49,17 @@ public void keyPressed(KeyEvent e) { } }); - add( new JLabel( String.format(" Total Frame Range: %d ... %d", 0, traceView.getFrameTotal()-1 ))); + frameDetailsButton = new JButton("Frame Details"); + frameDetailsButton.addActionListener(this); + frameDetailsButton.setActionCommand("display-frame-details"); + frameDetailsButton.setToolTipText("Display the job details of the selected frame."); + add(frameDetailsButton); - add( new JLabel(" Selected Frame Range: ")); + add( new JLabel( String.format(" Frames : [%d ... %d]", 0, traceView.getFrameTotal()-1 ))); - firstRenderFrameField = new JTextField(15); + add( new JLabel(" Selected Range: ")); + + firstRenderFrameField = new JTextField(10); firstRenderFrameField.setText( String.format("%d", traceView.getFirstRenderFrame()) ); add(firstRenderFrameField); firstRenderFrameField.addKeyListener( new KeyAdapter() { @@ -65,7 +72,7 @@ public void keyPressed(KeyEvent e) { }); add( new JLabel("...")); - lastRenderFrameField = new JTextField(15); + lastRenderFrameField = new JTextField(10); lastRenderFrameField.setText( String.format("%d", traceView.getLastRenderFrame()) ); add(lastRenderFrameField); lastRenderFrameField.addKeyListener( new KeyAdapter() { @@ -77,9 +84,24 @@ public void keyPressed(KeyEvent e) { } }); + add( new JLabel(" ")); + // Add Trick LOGO here. } + @Override + public void actionPerformed(ActionEvent e) { + String s = e.getActionCommand(); + switch (s) { + case "display-frame-details": + traceView.displaySelectedFrame(); + break; + default: + System.out.println("Unknown Action Command:" + s); + break; + } + } + private void setFirstRenderFrame() { int newStartFrame = 0; try { diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewMenuBar.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewMenuBar.java index cae9d40be..602c849e9 100644 --- a/trick_source/java/src/main/java/trick/jobperf/TraceViewMenuBar.java +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewMenuBar.java @@ -11,10 +11,10 @@ * JMenuBar [this] * JMenu [fileMenu] * JMenuItem [fileMenuExit], Action: Call System.exit(0); -* JMenu [optionsMenu] +* JMenu [viewMenu] * JMenu [traceSizeMenu] -* JMenuItem [traceSizeMenuIncrease], Action: Call traceView.incrementTraceWidth(). -* JMenuItem [traceSizeMenuDecrease], Action: Call traceView.decrementTraceWidth() +* JMenuItem [traceSizeIncrease], Action: Call traceView.incrementTraceWidth(). +* JMenuItem [traceSizeDecrease], Action: Call traceView.decrementTraceWidth() */ public class TraceViewMenuBar extends JMenuBar implements ActionListener { @@ -30,26 +30,45 @@ public TraceViewMenuBar(TraceViewCanvas tvc) { JMenu fileMenu = new JMenu("File"); JMenuItem fileMenuExit = new JMenuItem("Exit"); fileMenuExit.setActionCommand("exit"); + KeyStroke ctrlQ = KeyStroke.getKeyStroke('Q', InputEvent.CTRL_MASK ); + fileMenuExit.setAccelerator(ctrlQ); 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"); + JMenu viewMenu = new JMenu("View"); + + JMenuItem traceSizeIncrease = new JMenuItem("Increase Trace Width"); + traceSizeIncrease.setActionCommand("increase-trace_width"); KeyStroke ctrlPlus = KeyStroke.getKeyStroke('=', InputEvent.CTRL_MASK ); - traceSizeMenuIncrease.setAccelerator(ctrlPlus); - traceSizeMenuIncrease.addActionListener(this); - traceSizeMenu.add(traceSizeMenuIncrease); - JMenuItem traceSizeMenuDecrease = new JMenuItem("Decrease Trace Width"); - traceSizeMenuDecrease.setActionCommand("decrease-trace_width"); + traceSizeIncrease.setAccelerator(ctrlPlus); + traceSizeIncrease.addActionListener(this); + viewMenu.add(traceSizeIncrease); + + JMenuItem traceSizeDecrease = new JMenuItem("Decrease Trace Width"); + traceSizeDecrease.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); + traceSizeDecrease.setAccelerator(ctrlMinus); + traceSizeDecrease.addActionListener(this); + viewMenu.add(traceSizeDecrease); + + viewMenu.addSeparator(); + + JMenuItem showFrame = new JMenuItem("Frame Details ..."); + showFrame.setActionCommand("expand-selected-frame"); + KeyStroke ctrlF = KeyStroke.getKeyStroke('F', InputEvent.CTRL_MASK); + showFrame.setAccelerator(ctrlF); + showFrame.addActionListener(this); + viewMenu.add(showFrame); + + JMenuItem showStats = new JMenuItem("Job Statistics ..."); + showStats.setActionCommand("show-job-stats"); + KeyStroke ctrlV = KeyStroke.getKeyStroke('V', InputEvent.CTRL_MASK); + showStats.setAccelerator(ctrlV); + showStats.addActionListener(this); + viewMenu.add(showStats); + + add(viewMenu); } @Override @@ -62,6 +81,13 @@ public void actionPerformed(ActionEvent e) { case "decrease-trace_width": traceView.decrementTraceWidth(); break; + case "expand-selected-frame": + traceView.displaySelectedFrame(); + break; + case "show-job-stats": + traceView.jobStats.SortByID(); + traceView.displayJobStatsWindow(); + break; case "exit": System.exit(0); default: diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewOutputToolBar.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewOutputToolBar.java index d0ea6a380..5ea038ed5 100644 --- a/trick_source/java/src/main/java/trick/jobperf/TraceViewOutputToolBar.java +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewOutputToolBar.java @@ -1,18 +1,20 @@ package trick.jobperf; +import java.awt.*; 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. +* TraceViewCanvas. */ class TraceViewOutputToolBar extends JToolBar { private JTextField IDField; + private JTextField nameField; + private JTextField classField; private JTextField startField; private JTextField stopField; - private JTextField frameNumberField; - private JTextField subFrameTimeField; + // private JTextField frameNumberField; + private JTextField durationField; /** * Constructor @@ -20,71 +22,83 @@ class TraceViewOutputToolBar extends JToolBar { public TraceViewOutputToolBar () { add( new JLabel(" Job ID: ")); - IDField = new JTextField(15); + IDField = new JTextField(5); IDField.setEditable(false); IDField.setText( ""); add(IDField); - add( new JLabel(" Job Start: ")); - startField = new JTextField(15); + add( new JLabel(" Name: ")); + nameField = new JTextField(25); + nameField.setEditable(false); + nameField.setText( ""); + add(nameField); + + add( new JLabel(" Class: ")); + classField = new JTextField(12); + classField.setEditable(false); + classField.setText( ""); + add(classField); + + add( new JLabel(" Start: ")); + startField = new JTextField(6); startField.setEditable(false); startField.setText( ""); add(startField); - add( new JLabel(" Job Stop: ")); - stopField = new JTextField(15); + add( new JLabel(" Stop: ")); + stopField = new JTextField(6); stopField.setEditable(false); stopField.setText( ""); add(stopField); - 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); + add( new JLabel(" Duration: ")); + durationField = new JTextField(6); + durationField.setEditable(false); + durationField.setText( ""); + add(durationField); } + /** * @param id job identifier to display. */ public void setJobID(String id) { IDField.setText( id ); } + /** - * @param time to be displayed in the job start field. + * @param id job identifier to display. */ - public void setJobStartTime(Double time) { - startField.setText( String.format("%8.4f", time) ); + public void setJobName(String name) { + nameField.setText(name); } + /** - * @param time to be displayed in the job stop field. + * @param id job class to display. */ - public void setJobStopTime(Double time) { - stopField.setText( String.format("%8.4f", time) ); + public void setJobClass(String name) { + classField.setText(name); } + + /** + * @param time to be displayed in the job start field. + */ + public void setJobTimes(Double start_time, Double stop_time) { + startField.setText( String.format("%8.4f", start_time) ); + stopField.setText( String.format("%8.4f", stop_time) ); + Double duration = stop_time - start_time; + durationField.setText( String.format("%8.4f", duration) ); + } + /** * Clear the startField and stopField. */ - public void clearJobStartStopTime() { + public void clearJobFields() { + nameField.setText(""); + classField.setText(""); startField.setText(""); stopField.setText(""); + durationField.setText(""); IDField.setText(""); } - /** - * @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 index b9ba346ee..c87f1b2d3 100644 --- a/trick_source/java/src/main/java/trick/jobperf/TraceViewWindow.java +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewWindow.java @@ -22,9 +22,13 @@ public class TraceViewWindow extends JFrame { * Constructor * @param jobExecList an ArrayList of JobExecutionEvent, i.e., the job timeline data. */ - public TraceViewWindow( ArrayList jobExecList ) { + public TraceViewWindow( ArrayList jobExecList, + KeyedColorMap idToColorMap, + JobSpecificationMap jobSpecificationMap ) { + TraceViewOutputToolBar outputToolBar = new TraceViewOutputToolBar(); - TraceViewCanvas traceViewCanvas = new TraceViewCanvas( jobExecList, outputToolBar); + + TraceViewCanvas traceViewCanvas = new TraceViewCanvas( jobExecList, outputToolBar, idToColorMap, jobSpecificationMap); TraceViewMenuBar menuBar = new TraceViewMenuBar( traceViewCanvas); setJMenuBar(menuBar); From 75957282167538343ed3adad7685cbe1b2b28a33 Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Tue, 28 Jan 2025 15:28:04 -0600 Subject: [PATCH 11/13] Refactor timeline log and improve frame boundary determination. --- .../java/trick/jobperf/FrameViewCanvas.java | 12 +++++++--- .../java/trick/jobperf/JobExecutionEvent.java | 8 +++---- .../src/main/java/trick/jobperf/JobPerf.java | 24 ++++++++++--------- .../trick/jobperf/JobSpecificationMap.java | 4 ++-- .../java/trick/jobperf/TraceViewCanvas.java | 5 +++- .../sim_services/FrameLog/FrameLog.cpp | 7 ++---- 6 files changed, 34 insertions(+), 26 deletions(-) diff --git a/trick_source/java/src/main/java/trick/jobperf/FrameViewCanvas.java b/trick_source/java/src/main/java/trick/jobperf/FrameViewCanvas.java index 8ebdcebb5..7dd3162e8 100644 --- a/trick_source/java/src/main/java/trick/jobperf/FrameViewCanvas.java +++ b/trick_source/java/src/main/java/trick/jobperf/FrameViewCanvas.java @@ -58,16 +58,22 @@ private void doDrawing(Graphics g) { g2d.fillRect(50, jobY, 20, 20); g2d.setPaint( Color.BLACK ); jobY += 20; - JobSpecification jobSpec = tvc.jobSpecificationMap.getJobSpecification(jobExec.id); double duration = jobExec.stop - jobExec.start; g2d.setFont(dataFont); g2d.drawString(jobExec.id, 100, jobY); - g2d.drawString(jobSpec.jobClass, 180, jobY); g2d.drawString( String.format("%12.6f", jobExec.start), 420, jobY); g2d.drawString( String.format("%12.6f", jobExec.stop), 520, jobY); g2d.drawString( String.format("%12.6f", duration), 620, jobY); - g2d.drawString(jobSpec.name, 740, jobY); + + JobSpecification jobSpec = tvc.jobSpecificationMap.getJobSpecification(jobExec.id); + if ( jobSpec == null) { + g2d.drawString("???", 180, jobY); + g2d.drawString("???", 740, jobY); + } else { + g2d.drawString(jobSpec.jobClass, 180, jobY); + g2d.drawString(jobSpec.name, 740, jobY); + } } frame.SortByJobEventDuration(); } diff --git a/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java b/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java index af93f2baa..ea7648165 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java @@ -15,13 +15,13 @@ * 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. +* indicates whether the job was run as +* an "top-of-frame" job. */ class JobExecutionEvent { public String id; - public boolean isEOF; public boolean isTOF; + public boolean isEOF; public double start; public double stop; public int contained; @@ -35,8 +35,8 @@ class JobExecutionEvent { */ public JobExecutionEvent(String id, boolean isTOF, boolean isEOF, double start, double stop) { this.id = id; - this.isEOF = isEOF; this.isTOF = isTOF; + this.isEOF = isEOF; this.start = start; this.stop = stop; contained = 1; 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 b9365a435..9fed20847 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobPerf.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java @@ -74,7 +74,6 @@ public JobPerf( String[] args ) { String filesDir = Paths.get(timeLineFileName).toAbsolutePath().getParent().toString(); System.out.println( "\n\nFilesDir = " + filesDir + "\n\n"); - // Generate the JobSpecificationMap from information extracted from the S_job_execution // file, that should be in the same directory as the time-line file. File s_job_execution_file = new File( filesDir + "/S_job_execution" ); @@ -103,7 +102,7 @@ public JobPerf( String[] args ) { System.exit(0); } - jobExecEvtList = getJobExecutionEventList(timeLineFileName); + jobExecEvtList = getJobExecutionEventList(timeLineFileName, jobSpecificationMap); if (printReport) { jobStats = new JobStats(jobExecEvtList); @@ -150,7 +149,8 @@ private static void printHelpText() { /** * Read the timeline file, resulting in a ArrayList. */ - private ArrayList getJobExecutionEventList( String fileName ) { + private ArrayList getJobExecutionEventList( String fileName, + JobSpecificationMap jobSpecificationMap ) { String line; String field[]; @@ -162,16 +162,18 @@ private ArrayList getJobExecutionEventList( String fileName ) line = in.readLine(); while( (line = in.readLine()) !=null) { field = line.split(","); - // Need to strip trailing 0's from the id to make the ID's in - // 1) timeline file and 2) the S_job_execution file consistent. - String id = field[0].replaceAll("0*$",""); + + String id = field[0].trim(); + JobSpecification jobSpec = jobSpecificationMap.getJobSpecification(id); boolean isTOF = false; - if (Integer.parseInt(field[1]) == 1) isTOF = true; boolean isEOF = false; - if (Integer.parseInt(field[2]) == 1) isEOF = true; - double start = Double.parseDouble( field[3]); - double stop = Double.parseDouble( field[4]); - + if (jobSpec.jobClass.equals("top_of_frame")) { + isTOF = true; + } else if (jobSpec.jobClass.equals("end_of_frame")) { + isEOF = true; + } + double start = Double.parseDouble( field[1]); + double stop = Double.parseDouble( field[2]); if (start < stop) { JobExecutionEvent evt = new JobExecutionEvent(id, isTOF, isEOF, start, stop); jobExecEvtList.add( evt); diff --git a/trick_source/java/src/main/java/trick/jobperf/JobSpecificationMap.java b/trick_source/java/src/main/java/trick/jobperf/JobSpecificationMap.java index d5f7b6d1b..af6996bd8 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobSpecificationMap.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobSpecificationMap.java @@ -27,10 +27,10 @@ public JobSpecificationMap( File file ) throws IOException, FileNotFoundExceptio if (field.length == 9) { String jobclass = field[2].trim(); int phase = Integer.parseInt( field[3].trim()); - String id = field[7].trim(); + String id = String.format("%.2f", Double.parseDouble( field[7].trim())); String name = field[8].trim(); - // System.out.println( "JobSpec = <" + id + "," + name + "," + jobclass + ">\n\n"); jobSpecMap.put(id, new JobSpecification(name, jobclass, phase)); + //System.out.println("JobSpec = " + id + "," + jobclass + "," + name); } } } diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java index 9552ad826..df24b5596 100644 --- a/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java @@ -87,12 +87,13 @@ public TraceViewCanvas( ArrayList jobExecEvtList, try { boolean wasTOF = false; + boolean wasEOF = false; List frameList = new ArrayList(); FrameRecord frameRecord = new FrameRecord(); for (JobExecutionEvent jobExec : jobExecEvtList ) { - if (!wasTOF && jobExec.isTOF) { + if ((!wasTOF && jobExec.isTOF) || ( wasEOF && !jobExec.isEOF )) { // Wrap up the previous frame record. frameRecord.stop = jobExec.start; frameRecord.CalculateJobContainment(); @@ -105,6 +106,8 @@ public TraceViewCanvas( ArrayList jobExecEvtList, frameRecord.jobEvents.add(jobExec); wasTOF = jobExec.isTOF; + wasEOF = jobExec.isEOF; + idToColorMap.addKey(jobExec.id); } diff --git a/trick_source/sim_services/FrameLog/FrameLog.cpp b/trick_source/sim_services/FrameLog/FrameLog.cpp index f69807293..131fc9ba1 100644 --- a/trick_source/sim_services/FrameLog/FrameLog.cpp +++ b/trick_source/sim_services/FrameLog/FrameLog.cpp @@ -603,17 +603,14 @@ int Trick::FrameLog::shutdown() { exit(0); } - fprintf(fp_log,"jobID,isTopOfFrame,isEndOfFrame,startTime,stopTime\n"); + fprintf(fp_log,"jobID,startTime,stopTime\n"); time_scale = 1.0 / exec_get_time_tic_value(); tl = timeline[thread_num]; for ( ii = 0 ; ii < tl_count[thread_num] ; ii++ ) { start = tl[ii].start * time_scale; stop = tl[ii].stop * time_scale; - int isTrickJob = (tl[ii].trick_job) ? 1 : 0; - int isEndOfFrame = (tl[ii].isEndOfFrame) ? 1 : 0; - int isTopOfFrame = (tl[ii].isTopOfFrame) ? 1 : 0; - fprintf(fp_log,"%f,%d,%d,%f,%f\n", tl[ii].id, isTopOfFrame, isEndOfFrame, start, stop); + fprintf(fp_log,"%5.2f, %f, %f\n", tl[ii].id, start, stop); } fflush(fp_log); fclose(fp_log); From 65d1355c263c8f53946b7eddbcbd57efafbc9c34 Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Wed, 29 Jan 2025 14:45:17 -0600 Subject: [PATCH 12/13] Fix check of whether one job executes within the bounds of another. --- .../java/src/main/java/trick/jobperf/JobExecutionEvent.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java b/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java index ea7648165..0f7ad614d 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobExecutionEvent.java @@ -47,8 +47,8 @@ public JobExecutionEvent(String id, boolean isTOF, boolean isEOF, double start, * within another jobs stop/stop range. */ public boolean contains( JobExecutionEvent other ) { - if ((other.start >= this.start) && - (other.start <= this.stop)) { + if ((other.start > this.start) && + (other.start < this.stop)) { return true; } return false; From 87dc1925ee9dd1738eb295e72fe64964dd2a1428 Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Thu, 30 Jan 2025 15:25:08 -0600 Subject: [PATCH 13/13] Handle case where and id in the timeline is not found in the S-job_execution file. --- .../java/trick/jobperf/FrameViewCanvas.java | 5 +++-- .../src/main/java/trick/jobperf/JobPerf.java | 20 +++++++++++-------- .../src/main/java/trick/jobperf/JobStats.java | 9 +++++++-- .../trick/jobperf/JobStatsViewCanvas.java | 14 ++++++++++--- .../java/trick/jobperf/TraceViewCanvas.java | 19 ++++++++++++++---- .../trick/jobperf/TraceViewInputToolBar.java | 20 +++++++++++++++++++ 6 files changed, 68 insertions(+), 19 deletions(-) diff --git a/trick_source/java/src/main/java/trick/jobperf/FrameViewCanvas.java b/trick_source/java/src/main/java/trick/jobperf/FrameViewCanvas.java index 7dd3162e8..c8a7be9c1 100644 --- a/trick_source/java/src/main/java/trick/jobperf/FrameViewCanvas.java +++ b/trick_source/java/src/main/java/trick/jobperf/FrameViewCanvas.java @@ -68,8 +68,9 @@ private void doDrawing(Graphics g) { JobSpecification jobSpec = tvc.jobSpecificationMap.getJobSpecification(jobExec.id); if ( jobSpec == null) { - g2d.drawString("???", 180, jobY); - g2d.drawString("???", 740, jobY); + g2d.setPaint( Color.RED ); + g2d.drawString("UNKNOWN", 180, jobY); + g2d.drawString("UNKNOWN", 740, jobY); } else { g2d.drawString(jobSpec.jobClass, 180, jobY); g2d.drawString(jobSpec.name, 740, jobY); 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 9fed20847..c933cf09d 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobPerf.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java @@ -158,20 +158,24 @@ private ArrayList getJobExecutionEventList( String fileName, try { BufferedReader in = new BufferedReader( new FileReader(fileName) ); - // Strip the header off the CSV file. + // Strip the header line off the CSV file. line = in.readLine(); + + // Iterate through and process each of the data lines. while( (line = in.readLine()) !=null) { + boolean isTOF = false; + boolean isEOF = false; field = line.split(","); String id = field[0].trim(); JobSpecification jobSpec = jobSpecificationMap.getJobSpecification(id); - boolean isTOF = false; - boolean isEOF = false; - if (jobSpec.jobClass.equals("top_of_frame")) { - isTOF = true; - } else if (jobSpec.jobClass.equals("end_of_frame")) { - isEOF = true; - } + if (jobSpec != null) { + if (jobSpec.jobClass.equals("top_of_frame")) { + isTOF = true; + } else if (jobSpec.jobClass.equals("end_of_frame")) { + isEOF = true; + } + } double start = Double.parseDouble( field[1]); double stop = Double.parseDouble( field[2]); if (start < stop) { diff --git a/trick_source/java/src/main/java/trick/jobperf/JobStats.java b/trick_source/java/src/main/java/trick/jobperf/JobStats.java index 0bc4e5a03..4df1e3521 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobStats.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobStats.java @@ -178,14 +178,19 @@ public void write( JobSpecificationMap jobSpecificationMap ) { for (StatisticsRecord jobStatisticsRecord : jobStatisticsList ) { JobSpecification jobSpec = jobSpecificationMap.getJobSpecification( jobStatisticsRecord.id); - + String jobName = null; + if (jobSpec != null) { + jobName = jobSpec.name; + } else { + jobName = "UNKNOWN"; + } System.out.println( String.format("%10s %14.6f %14.6f %14.6f %14.6f %s", jobStatisticsRecord.id, jobStatisticsRecord.meanValue, jobStatisticsRecord.stddev, jobStatisticsRecord.minValue, jobStatisticsRecord.maxValue, - jobSpec.name + jobName ) ); } diff --git a/trick_source/java/src/main/java/trick/jobperf/JobStatsViewCanvas.java b/trick_source/java/src/main/java/trick/jobperf/JobStatsViewCanvas.java index 5de148bce..51cb675b1 100644 --- a/trick_source/java/src/main/java/trick/jobperf/JobStatsViewCanvas.java +++ b/trick_source/java/src/main/java/trick/jobperf/JobStatsViewCanvas.java @@ -24,6 +24,7 @@ public JobStatsViewCanvas( JobStats jobStats, } private void doDrawing(Graphics g) { + Graphics2D g2d = (Graphics2D) g; RenderingHints rh = new RenderingHints( @@ -57,16 +58,23 @@ private void doDrawing(Graphics g) { int jobY = 100; for (StatisticsRecord jobStatisticsRecord : jobStats.jobStatisticsList ) { - JobSpecification jobSpec = jobSpecificationMap.getJobSpecification( jobStatisticsRecord.id); - g2d.setFont(dataFont); g2d.setPaint( Color.BLACK ); + g2d.drawString(jobStatisticsRecord.id, 100, jobY); g2d.drawString( String.format("%14.6f", jobStatisticsRecord.meanValue), 180, jobY); g2d.drawString( String.format("%14.6f", jobStatisticsRecord.stddev), 280, jobY); g2d.drawString( String.format("%14.6f", jobStatisticsRecord.minValue), 380, jobY); g2d.drawString( String.format("%14.6f", jobStatisticsRecord.maxValue), 480, jobY); - g2d.drawString(jobSpec.name, 600, jobY); + + JobSpecification jobSpec = jobSpecificationMap.getJobSpecification( jobStatisticsRecord.id); + if (jobSpec != null) { + g2d.drawString(jobSpec.name, 600, jobY); + } else { + g2d.setPaint( Color.RED ); + g2d.drawString("UNKNOWN", 600, jobY); + } + jobY += 20; } } diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java index df24b5596..1e5d72063 100644 --- a/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewCanvas.java @@ -94,6 +94,7 @@ public TraceViewCanvas( ArrayList jobExecEvtList, for (JobExecutionEvent jobExec : jobExecEvtList ) { if ((!wasTOF && jobExec.isTOF) || ( wasEOF && !jobExec.isEOF )) { + // Wrap up the previous frame record. frameRecord.stop = jobExec.start; frameRecord.CalculateJobContainment(); @@ -152,6 +153,20 @@ public int getFirstRenderFrame() { return frameRenderRange.first; } + public int getLastRenderFrame() { + return frameRenderRange.last; + } + + // public void moveRenderFrameRangeBy(int advance) { + // + // if ( ((frameRenderRange.first + advance) > 0) && + // ((frameRenderRange.first + advance) < frameArray.length )) + // + // + // + // } + // } + public void setFirstRenderFrame(int first) throws InvalidFrameBoundsExpection { if ((first >= 0) && (first <= frameRenderRange.last)) { frameRenderRange = new FrameRange(first, frameRenderRange.last); @@ -162,10 +177,6 @@ public void setFirstRenderFrame(int first) throws InvalidFrameBoundsExpection { } } - public int getLastRenderFrame() { - return frameRenderRange.last; - } - public void setLastRenderFrame(int last) throws InvalidFrameBoundsExpection { if ((last >= frameRenderRange.first) && (last < frameArray.length)) { frameRenderRange = new FrameRange(frameRenderRange.first, last); diff --git a/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java b/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java index b09c6c23d..6caf34709 100644 --- a/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java +++ b/trick_source/java/src/main/java/trick/jobperf/TraceViewInputToolBar.java @@ -27,6 +27,8 @@ public class TraceViewInputToolBar extends JToolBar implements ActionListener { private TraceViewCanvas traceView; private JTextField frameSizeField; private JButton frameDetailsButton; + private JButton advanceRangeButton; + private JButton retreatRangeButton; private JTextField firstRenderFrameField; private JTextField lastRenderFrameField; /** @@ -84,6 +86,18 @@ public void keyPressed(KeyEvent e) { } }); + advanceRangeButton = new JButton("Advance"); + advanceRangeButton.addActionListener(this); + advanceRangeButton.setActionCommand("advance-frame-range"); + advanceRangeButton.setToolTipText("Advance the selected range of frames to be displayed."); + add(advanceRangeButton); + + advanceRangeButton = new JButton("Retreat"); + advanceRangeButton.addActionListener(this); + advanceRangeButton.setActionCommand("retreat-frame-range"); + advanceRangeButton.setToolTipText("Retreat the selected range of frames to be displayed."); + add(advanceRangeButton); + add( new JLabel(" ")); // Add Trick LOGO here. @@ -96,6 +110,12 @@ public void actionPerformed(ActionEvent e) { case "display-frame-details": traceView.displaySelectedFrame(); break; + case "advance-frame-range": + // DO ACTION + break; + case "retreat-frame-range": + // DO ACTION + break; default: System.out.println("Unknown Action Command:" + s); break;