diff --git a/bin/trick-jperf b/bin/trick-jperf
new file mode 100755
index 00000000..7fb8d346
--- /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/bin/trick-rtperf b/bin/trick-rtperf
new file mode 100755
index 00000000..f2f5e344
--- /dev/null
+++ b/bin/trick-rtperf
@@ -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("Real-time Performance Plot", "rtPerf") ;
+
diff --git a/trick_sims/SIM_robot/RUN_2DPlanar/input.py b/trick_sims/SIM_robot/RUN_2DPlanar/input.py
index dc43326a..58c24376 100644
--- a/trick_sims/SIM_robot/RUN_2DPlanar/input.py
+++ b/trick_sims/SIM_robot/RUN_2DPlanar/input.py
@@ -15,19 +15,24 @@ Manip2D.robot.kinemat.checkSingularities = False
armIntegLoop.getIntegrator(trick.Euler, Manip2D.robot.ndof)
-#==========================================
-# Start the Graphics Client
-#==========================================
-varServerPort = trick.var_server_get_port();
-RobotDisplay_path = "models/graphics/build/RobotDisplay.jar"
+graphics = False
-if (os.path.isfile(RobotDisplay_path)) :
- RobotDisplay_cmd = "java -jar " \
- + RobotDisplay_path \
- + " " + str(varServerPort) + " &" ;
- print(RobotDisplay_cmd)
- os.system( RobotDisplay_cmd);
-else :
- print('==================================================================================')
- print('RobotDisplay needs to be built. Please \"cd\" into ../models/graphics and type \"make\".')
- print('==================================================================================')
+trick.frame_log_on()
+
+if graphics:
+ #==========================================
+ # Start the Graphics Client
+ #==========================================
+ varServerPort = trick.var_server_get_port();
+ RobotDisplay_path = "models/graphics/build/RobotDisplay.jar"
+
+ if (os.path.isfile(RobotDisplay_path)) :
+ RobotDisplay_cmd = "java -jar " \
+ + RobotDisplay_path \
+ + " " + str(varServerPort) + " &" ;
+ print(RobotDisplay_cmd)
+ os.system( RobotDisplay_cmd);
+ else :
+ print('==================================================================================')
+ print('RobotDisplay needs to be built. Please \"cd\" into ../models/graphics and type \"make\".')
+ print('==================================================================================')
diff --git a/trick_source/java/pom.xml b/trick_source/java/pom.xml
index ee69706c..6500c6c0 100644
--- a/trick_source/java/pom.xml
+++ b/trick_source/java/pom.xml
@@ -282,6 +282,38 @@
MM
+
+
+ jobperf
+ package
+
+ shade
+
+
+
+
+ trick.jobperf.JobPerf
+
+
+ JPerf
+
+
+
+
+ rtperf
+ package
+
+ shade
+
+
+
+
+ trick.rtperf.rtPerf
+
+
+ rtPerf
+
+
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 00000000..72426b20
--- /dev/null
+++ b/trick_source/java/src/main/java/trick/jobperf/JobPerf.java
@@ -0,0 +1,865 @@
+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
+
+public class JobPerf extends JFrame {
+ ArrayList jobExecEvtList;
+ JobStats jobStats;
+
+ public JobPerf( String[] args ) {
+ TraceViewWindow traceViewWindow;
+ boolean interactive = true;
+ boolean printReport = false;
+ 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" : {
+ sortOrder = JobStats.SortCriterion.ID;
+ } break;
+ case "-s1" :
+ case "--sort=mean" : {
+ sortOrder = JobStats.SortCriterion.MEAN;
+ } break;
+ case "-s2" :
+ case "--sort=stddev" : {
+ sortOrder = JobStats.SortCriterion.STDDEV;
+ } break;
+ case "-s3" :
+ case "--sort=max" : {
+ sortOrder = JobStats.SortCriterion.MAX;
+ } break;
+ case "-s4" :
+ case "--sort=min" : {
+ sortOrder = JobStats.SortCriterion.MIN;
+ } break;
+ default : {
+ fileName = args[ii];
+ } break;
+ } //switch
+ ++ii;
+ } // while
+
+ jobExecEvtList = JobExecutionEventList(fileName);
+ jobStats = new JobStats(jobExecEvtList);
+ if (printReport) {
+ 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) {
+ traceViewWindow = new TraceViewWindow(jobExecEvtList);
+ }
+ }
+
+ private static void printHelpText() {
+ System.out.println(
+ "----------------------------------------------------------------------\n"
+ + "usage: trick-jperf [options] \n"
+ + "options: \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"
+ );
+ }
+
+ // 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) {
+ JobPerf jobPerf = new JobPerf( args );
+ } // main
+
+} // class JobPerf
diff --git a/trick_source/java/src/main/java/trick/rtperf/rtPerf.java b/trick_source/java/src/main/java/trick/rtperf/rtPerf.java
new file mode 100644
index 00000000..73a85b2a
--- /dev/null
+++ b/trick_source/java/src/main/java/trick/rtperf/rtPerf.java
@@ -0,0 +1,929 @@
+//========================================
+// Package
+//========================================
+package trick.rtperf;
+
+//========================================
+// Imports
+//========================================
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.Desktop;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.MulticastSocket;
+import java.net.UnknownHostException;
+import java.net.SocketTimeoutException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.channels.NotYetConnectedException;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.UnresolvedAddressException;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JMenuBar;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JSplitPane;
+import javax.swing.JTextField;
+import javax.swing.JTextPane;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+import javax.swing.SwingConstants;
+import javax.swing.SwingWorker;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultStyledDocument;
+import javax.swing.text.Document;
+import javax.swing.text.Style;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyleContext;
+import javax.swing.text.StyledEditorKit;
+
+import org.jdesktop.application.Action;
+import org.jdesktop.application.Application;
+import org.jdesktop.application.Task;
+import org.jdesktop.application.View;
+import org.jdesktop.swingx.JXEditorPane;
+import org.jdesktop.swingx.JXLabel;
+import org.jdesktop.swingx.JXPanel;
+import org.jdesktop.swingx.JXStatusBar;
+import org.jdesktop.swingx.JXTitledPanel;
+import org.jdesktop.swingx.JXTitledSeparator;
+
+import trick.common.TrickApplication;
+import trick.common.ui.UIUtils;
+import trick.common.ui.components.FontChooser;
+import trick.common.ui.panels.AnimationPlayer;
+import trick.common.ui.panels.FindBar;
+import trick.common.utils.VariableServerConnection;
+//import trick.rtperf.rtPerf.JobExecutionEvent;
+import trick.simcontrol.utils.SimControlActionController;
+import trick.simcontrol.utils.SimState;
+
+import org.jfree.chart.*;
+import org.jfree.data.general.DefaultPieDataset;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+public class rtPerf extends TrickApplication implements PropertyChangeListener {
+
+ //========================================
+ // Public data
+ //========================================
+
+
+ //========================================
+ // Protected data
+ //========================================
+
+
+ //========================================
+ // Private Data
+ //========================================
+ private int modeIndex = -1;
+ private int debug_flag ;
+ private int debug_present ;
+ private int overrun_present ;
+ private int message_present ;
+ private int message_port ;
+
+ /** whether automatically exit when sim is done/killed. */
+ private static boolean isAutoExitOn;
+
+ // The panel that displays the current sim state description as well as progress.
+ private JXTitledPanel runtimeStatePanel;
+ private String currentSimStatusDesc = "None";
+ private JProgressBar progressBar;
+ // Always enable progress bar unless the sim termination time is not defined
+ private boolean enableProgressBar = true;
+
+ private JTextField recTime;
+ //private JTextField realtimeTime;
+ //private JTextField metTime;
+ //private JTextField gmtTime;
+ private JTextField simRealtimeRatio;
+
+ private JXTitledPanel simOverrunPanel;
+ private JTextField[] simRunDirField;
+ private JTextField[] overrunField;
+ private int slaveCount;
+ private double simStartTime;
+ private double simStopTime;
+ private double execTimeTicValue;
+
+ private JToggleButton dataRecButton;
+ private JToggleButton realtimeButton;
+ private JToggleButton dumpChkpntASCIIButton;
+ private JToggleButton loadChkpntButton;
+ private JToggleButton liteButton;
+
+ private JXEditorPane statusMsgPane;
+
+ private JXLabel statusLabel;
+
+ /*
+ * The action controller that performs actions for such as clicking button, selection a menu item and etc.
+ */
+ private SimControlActionController actionController;
+
+ // The animation image player panel
+ private AnimationPlayer logoImagePanel;
+
+ // VariableServerConnection for sending/receiving Variable Server commands.
+ private VariableServerConnection commandSimcom;
+ // VariableServerConnection for receiving Sim state from Variable Server.
+ private VariableServerConnection statusSimcom;
+
+ // Socket for receiving health and status messages
+ private SocketChannel healthStatusSocketChannel ;
+
+ private JComboBox runningSimList;
+ private static String host;
+ private static int port = -1;
+ private static boolean isRestartOptionOn;
+ //True if an error was encountered during the attempt to connect to Variable Server during intialize()
+ private boolean errOnInitConnect = false;
+ //Time out when attempting to establish connection with Variable Server in milliseconds
+ private int varServerTimeout = 5000;
+
+ // The object of SimState that has Sim state data.
+ private SimState simState;
+ private String customizedCheckpointObjects;
+
+ private static Charset charset;
+
+
+ final private static String LOCALHOST = "localhost";
+
+ final private Dimension FULL_SIZE = new Dimension(680, 640);
+ final private Dimension LITE_SIZE = new Dimension(340, 360);
+
+ private DefaultPieDataset dataset;
+ private JFreeChart chart;
+ private ChartPanel chartPanel;
+ private JPanel mainPanel;
+
+ /**
+ * Connects to the variable server if {@link VariableServerConnection} is able to be created successfully and
+ * starts the communication server for sim health status messages.
+ */
+ @Action
+ public void connect() {
+ // get host and port for selected sim
+ if (runningSimList != null && runningSimList.getSelectedItem() != null) {
+ String selectedStr = runningSimList.getSelectedItem().toString();
+ // remove the run info if it is shown
+ int leftPre = selectedStr.indexOf("(");
+ if (leftPre != -1) {
+ selectedStr = selectedStr.substring(0, leftPre);
+ }
+ // can be separated either by : or whitespace
+ String[] elements = selectedStr.split(":");
+
+ if (elements == null || elements.length < 2) {
+ elements = selectedStr.split("\\s+");
+ }
+
+ if (elements == null || elements.length < 2) {
+ String errMsg = "Can't connect! Please provide valid host name and port number separated by : or whitespace!";
+ printErrorMessage(errMsg);
+ return;
+ }
+ host = elements[0].trim();
+ try {
+ port = Integer.parseInt(elements[1].trim());
+ } catch (NumberFormatException nfe) {
+ String errMsg = elements[1] + " is not a valid port number!";
+ printErrorMessage(errMsg);
+ return;
+ }
+ }
+
+ getInitializationPacket();
+
+ if (commandSimcom == null) {
+ String errMsg = "Sorry, can't connect. Please make sure the availability of both server and port!";
+ printErrorMessage(errMsg);
+ return;
+ } else {
+ Object[] keys = actionMap.allKeys();
+ // If there is a server connection established, enable all actions.
+ for (int i = 0; i < keys.length; i++) {
+ String theKey = (String)keys[i];
+ getAction(theKey).setEnabled(true);
+ }
+ }
+
+ scheduleGetSimState();
+
+ }
+
+ //========================================
+ // Set/Get methods
+ //========================================
+ /**
+ * Gets the initialization packet from Variable Server if it is up.
+ */
+ public void getInitializationPacket() {
+ String simRunDir = null;
+ String[] results = null;
+ try {
+ String errMsg = "Error: RealTimePerformanceApplication:getInitializationPacket()";
+ try {
+ if (host != null && port != -1) {
+ commandSimcom = new VariableServerConnection(host, port, varServerTimeout);
+ } else {
+ commandSimcom = null;
+ }
+ } catch (UnknownHostException host_exception) {
+ /** The IP address of the host could not be determined. */
+ errMsg += "\n Unknown host \""+host+"\"";
+ errMsg += "\n Please use a valid host name (e.g. localhost)";
+ errOnInitConnect = true;
+ printErrorMessage(errMsg);
+ } catch (SocketTimeoutException ste) {
+ /** Connection attempt timed out. */
+ errMsg += "\n Connection Timeout \""+host+"\"";
+ errMsg += "\n Please try a different host name (e.g. localhost)";
+ errOnInitConnect = true;
+ printErrorMessage(errMsg);
+ } catch (IOException ioe) {
+ /** Port number is unavailable, or there is no connection, etc. */
+ errMsg += "\n Invalid TCP/IP port number \""+port+"\"";
+ errMsg += "\n Please check the server and enter a proper port number!";
+ errMsg += "\n IOException ..." + ioe;
+ errMsg += "\n If there is no connection, please make sure SIM is up running properly!";
+ errOnInitConnect = true;
+ printErrorMessage(errMsg);
+ }
+
+ if (commandSimcom == null) {
+ (new RetrieveHostPortTask()).execute();
+ return;
+ }
+
+ actionController.setVariableServerConnection(commandSimcom);
+
+ simState = new SimState();
+
+ // Sends commands to the variable server to add several variables for retrieving simulation details.
+ commandSimcom.put("trick.var_set_client_tag(\"rtPerf\")\n");
+ commandSimcom.put("trick.var_add(\"trick_real_time.rt_sync.rt_monitor\")\n"); // Need to change these simCom commands to somethign
+
+
+ commandSimcom.put("trick.var_send() \n" +
+ "trick.var_clear() \n");
+
+ results = commandSimcom.get().split("\t");
+ if (results != null && results.length > 0) {
+ execTimeTicValue = Double.parseDouble(results[3]);
+ simStartTime = Double.parseDouble(results[1]);
+ long terminateTime = Long.parseLong(results[2]);
+ if (terminateTime >= Long.MAX_VALUE - 1) {
+ enableProgressBar = false;
+ }
+
+ // need to minus the sim start time as it could be a number other than 0.0
+ simStopTime = terminateTime/execTimeTicValue - simStartTime;
+ }
+
+
+ simRunDirField = new JTextField[slaveCount+1];
+ overrunField = new JTextField[slaveCount+1];
+
+ for (int i = 0; i < simRunDirField.length; i++) {
+ if (i==0) {
+ simRunDirField[i] = new JTextField(results[4] + java.io.File.separator + results[5] + " " + results[6]);
+ } else {
+ simRunDirField[i] = new JTextField();
+ }
+ overrunField[i] = new JTextField(" ");
+ overrunField[i].setPreferredSize( new Dimension(60, overrunField[i].getHeight()) );
+ }
+ simRunDir = results[7];
+ simRunDir = results[4] + java.io.File.separator + simRunDir;
+
+ simState.setRunPath(simRunDir);
+
+
+ for (int i = 1; i < simRunDirField.length; i++) {
+ simRunDirField[i].setText("Slave " + i);
+ }
+
+
+ if ( message_present == 1 ) {
+ commandSimcom.put("trick.var_add(\"trick_message.mdevice.port\") \n" +
+ "trick.var_send() \n" +
+ "trick.var_clear() \n");
+ results = commandSimcom.get().split("\t");
+ message_port = Integer.parseInt(results[1]) ;
+
+ }
+ }
+ catch (NumberFormatException nfe) {
+
+ }
+ catch (IOException e) {
+
+ }
+ catch (NullPointerException npe) {
+ npe.printStackTrace();
+ }
+ }
+
+ //========================================
+ // Methods
+ //========================================
+ /**
+ * Invoked when SimStatusMonitor task's progress property changes.
+ * This is required by {@link PropertyChangeListener}.
+ */
+ public void propertyChange(PropertyChangeEvent evt) {
+ if ("progress" == evt.getPropertyName()) {
+ int progress = (Integer) evt.getNewValue();
+ progressBar.setValue(progress);
+ }
+
+ }
+
+ /**
+ * Cleans up the socket communication before exiting the application.
+ */
+ @Override
+ protected void shutdown() {
+ super.shutdown();
+ try {
+ if (commandSimcom != null) {
+ commandSimcom.close();
+ }
+ if (statusSimcom != null) {
+ statusSimcom.close();
+ }
+ if (healthStatusSocketChannel != null) {
+ healthStatusSocketChannel.close() ;
+ }
+ }
+ catch (java.io.IOException ioe) {
+ }
+ }
+
+ /**
+ * Makes initialization as needed. This is called before startup().
+ *
+ * @see #startup
+ */
+ @Override
+ protected void initialize(String[] args) {
+ super.initialize(args);
+ actionController = new SimControlActionController();
+
+ getInitializationPacket();
+ }
+
+ /**
+ * Starts things such as establishing socket communication, and starting monitor tasks.
+ * This is called after startup.
+ *
+ * @see #initialize
+ * @see #startup
+ */
+ @Override
+ protected void ready() {
+ super.ready();
+
+ //logoImagePanel.start();
+
+ // The following code was commented out and moved to the end of startup()
+ // due to framework having issues with certain Java versions. In certain Java
+ // version such as JDK1.6.0_20, ready() never gets called???
+ // 05-24-2011, found out that if there was any SwingTask or Thread started
+ // before ready() in application framework, JDK1.6.0_20 would fail to realize
+ // the startup() is done. That's why ready() never gets called even though startup()
+ // is done. So modified the code to start the logo animation player after startup()
+ // and moved the following code back to where it should be.
+ if (commandSimcom == null) {
+ //logoImagePanel.pause();
+ Object[] keys = actionMap.allKeys();
+ // If there is no server connection, disable all actions except connect and quit.
+ for (int i = 0; i < keys.length; i++) {
+ String theKey = (String)keys[i];
+ if (!(theKey.equals("connect") || theKey.equals("quit"))) {
+ getAction(theKey).setEnabled(false);
+ }
+ }
+ String errMsg = "No server connection. Please connect!";
+ printErrorMessage(errMsg);
+ return;
+ }
+
+ if (isRestartOptionOn) {
+ printSendHS();
+ }
+
+ scheduleGetSimState();
+
+ }
+
+ /**
+ * Starts building GUI. This is called after initialize.
+ * Once startup() is done, ready() is called.
+ *
+ * @see #initialize
+ * @see #ready
+ */
+ @Override
+ protected void startup() {
+ super.startup();
+
+ // dont't want to the confirmation dialog for sim control panel
+ removeExitListener(exitListener);
+
+ View view = getMainView();
+ view.setComponent(createMainPanel());
+ view.setMenuBar(createMenuBar());
+ view.setToolBar(createToolBar());
+ view.setStatusBar(createStatusBar());
+
+ if(errOnInitConnect && (runningSimList != null) ) {
+ runningSimList.addItem("localhost : " + port);
+ }
+
+ show(view);
+ }
+
+
+
+
+ /**
+ * Prints an error message to the status message pane. In the event there is an error with it, a JOptionPane will pop up.
+ * @param err
+ */
+ protected void printErrorMessage(String err) {
+ try {
+ // Get the document attached to the Status Message Pane
+ Document doc = statusMsgPane.getDocument();
+
+ // Set the font color to red and the background to black
+ StyleContext sc = new StyleContext();
+ Style redStyle = sc.addStyle("Red", null);
+
+ // Add the error message to the bottom of the message pane
+ doc.insertString(doc.getLength(), err + "\n", redStyle);
+
+ // If Lite mode is engaged, or the window is small enough
+ // to obscure the message pane, create a popup for the error as well.
+ if (liteButton.isSelected() || getMainFrame().getSize().height <= LITE_SIZE.height + 50) {
+ JOptionPane.showMessageDialog(getMainFrame(), err, "Sim Control Panel Error", JOptionPane.ERROR_MESSAGE);
+ }
+ } catch (BadLocationException ble) {
+ JOptionPane.showMessageDialog(getMainFrame(),
+ "Status Message Pane had an issue when printing: " + err,
+ "Status Message Pane Error",
+ JOptionPane.ERROR_MESSAGE);
+ } catch (NullPointerException npe) {
+ System.err.println( "Sim Control Error at Initialization: \n" + err);
+ }
+ }
+
+
+ /**
+ * Helper method to print the send_hs file to the statusMsgPane.
+ */
+ private void printSendHS() {
+ if (simState != null) {
+ File sendHS = new File(simState.getRunPath() + java.io.File.separator + "send_hs");
+ if (!sendHS.exists()) {
+ return;
+ }
+
+ String lineText = null;
+
+ Document doc = statusMsgPane.getDocument();
+ StyleContext sc = new StyleContext();
+
+ // normal style is white on black
+ Style defaultStyle = sc.addStyle("Default", null);
+
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(sendHS));
+ while ((lineText = reader.readLine()) != null) {
+ doc.insertString(doc.getLength(), lineText+System.getProperty("line.separator"), defaultStyle);
+ }
+ } catch (FileNotFoundException fnfe) {
+ // do nothing
+ } catch (IOException ioe) {
+ // do nothing
+ } catch (BadLocationException ble) {
+ // do nothing
+ }
+
+ finally {
+ try {
+ if (reader != null) {
+ reader.close();
+ }
+ } catch (IOException ioe) {
+
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds all the variables to variable server for getting SIM states.
+ */
+ private void scheduleGetSimState() {
+ try {
+ statusSimcom = new VariableServerConnection(host, port);
+ statusSimcom.put("trick.var_set_client_tag(\"SimControl2\")\n");
+
+ // whenever there is data in statusSimcom socket, do something
+ String status_vars ;
+
+ status_vars = "trick.var_add(\"trick_sys.sched.time_tics\") \n" +
+ "trick.var_add(\"trick_sys.sched.mode\") \n" +
+ "trick.var_add(\"trick_real_time.rt_sync.actual_run_ratio\") \n" +
+ "trick.var_add(\"trick_real_time.rt_sync.active\") \n";
+
+ if ( debug_present != 0 ) {
+ status_vars += "trick.var_add(\"trick_instruments.debug_pause.debug_pause_flag\")\n" ;
+ }
+ if ( overrun_present != 0 ) {
+ status_vars += "trick.var_add(\"trick_real_time.rt_sync.total_overrun\")\n" ;
+ }
+ statusSimcom.put(status_vars) ;
+
+ statusSimcom.put("trick.var_cycle(0.25)\n");
+
+ getAction("connect").setEnabled(false);
+ //runningSimList.setEnabled(false);
+ }
+ catch (NumberFormatException nfe) {
+
+ }
+ catch (IOException e) {
+ statusLabel.setText("Not Ready");
+ statusLabel.setEnabled(false);
+ statusSimcom = null;
+ getAction("connect").setEnabled(true);
+ //runningSimList.setEnabled(true);
+ getAction("startSim").setEnabled(false);
+ }
+ }
+
+ //========================================
+ // Inner Classes
+ //========================================
+ private class RetrieveHostPortTask extends SwingWorker {
+
+ private MulticastSocket multicastSocket = null;
+
+ @Override
+ public Void doInBackground() {
+ while (getAction("connect").isEnabled()) {
+ retrieveHostPort();
+ }
+ return null;
+ }
+
+ @Override
+ public void done() {
+ if (multicastSocket != null) {
+ multicastSocket.close();
+ }
+ }
+
+ /**
+ * Helper method for retrieving the host and its listening ports.
+ *
+ */
+ //for Java 7, the type of elements of JComboBox needs to be specified to avoid the warning and it's not supported in Java 6
+ @SuppressWarnings("unchecked")
+ private void retrieveHostPort() {
+ try {
+ multicastSocket = new MulticastSocket(9265);
+ InetAddress group = InetAddress.getByName("239.3.14.15");
+ multicastSocket.joinGroup(group);
+
+ byte[] buffer = new byte[1024];
+ DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
+ multicastSocket.receive(packet);
+
+ // Remove the trailing newline, and split the tab-delimitted message.
+ String[] info = new String(packet.getData(), packet.getOffset(), packet.getLength()).replace("\n", "").split("\t");
+ // Reset the packet length or future messages will be clipped.
+ packet.setLength(buffer.length);
+ // version Trick 10 or later
+ if (info[7] != null) {
+ if (runningSimList != null) {
+ String hostPort = info[0] + " : " + info[1] + " (" + info[5] + " " + info[6] + ")";
+ if (!UIUtils.comboBoxContains((DefaultComboBoxModel)runningSimList.getModel(), hostPort)) {
+ // only show localhost's resource
+ // TODO: may want to have whole network resource
+ if (InetAddress.getLocalHost().equals(InetAddress.getByName(info[0]))) {
+ runningSimList.addItem(hostPort);
+ runningSimList.setSelectedItem(hostPort);
+ }
+ }
+ }
+ }
+ } catch (IOException ioe) {
+ // do nothing
+ }
+ }
+ }
+
+
+ /**
+ * Convenient method for setting the state of specified actions.
+ *
+ * @param actsStr All actions that need setting state. Each action is separated by ",".
+ * @param flag The state is set to for the actions.
+ */
+ private void setActionsEnabled(String actsStr, boolean flag) {
+ if (actsStr != null) {
+ String[] acts = actsStr.split(",");
+ setActionsEnabled(acts, flag);
+ }
+ }
+
+ // Ask why we need both of these functions since if I only have the one above I get this error "incompatible types: java.lang.String[] cannot be converted to java.lang.String"
+
+ /**
+ * Convenient method for setting the state of specified actions.
+ *
+ * @param acts The array of all the actions.
+ * @param flag The state is set to for the actions.
+ */
+ private void setActionsEnabled(String[] acts, boolean flag) {
+ if (acts != null) {
+ for (int i = 0; i < acts.length; i++) {
+ if (getAction(acts[i].trim()) != null) {
+ getAction(acts[i].trim()).setEnabled(flag);
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates the main panel for this application.
+ */
+ @Override
+ protected JComponent createMainPanel() {
+ DefaultPieDataset dataset = new DefaultPieDataset();
+ dataset.setValue("Completed", 60);
+ dataset.setValue("In Progress", 30);
+ dataset.setValue("Failed", 10);
+
+ JFreeChart chart = ChartFactory.createPieChart("Job Execution Status", dataset, true, true, false); // Chart title, dataset, include legend, tooltips, urls
+
+ // Create the chart panel to display the chart
+ ChartPanel chartPanel = new ChartPanel(chart);
+
+ // Create the main panel to hold the chart panel
+ JPanel mainPanel = new JPanel();
+ mainPanel.add(chartPanel);
+
+ return mainPanel;
+ }
+
+
+ /**
+ * Inner class for the task of monitoring health status.
+ */
+ private class MonitorHealthStatusTask extends Task {
+ public MonitorHealthStatusTask(Application app) {
+ super(app);
+ }
+
+ /*
+ * Main task. Executed in background thread.
+ */
+ @Override
+ public Void doInBackground() {
+ return null;
+ }
+
+ @Override
+ protected void finished() {
+ try {
+ if (healthStatusSocketChannel != null) {
+ healthStatusSocketChannel.close() ;
+ }
+ } catch (java.io.IOException ioe) {
+
+ }
+ }
+ }
+
+ /**
+ * Inner class for the task of monitoring the status of the currently running simulation.
+ *
+ */
+ private class MonitorSimStatusTask extends Task {
+ /**
+ * Constructor with specified {@link Application}.
+ *
+ * @param app The specified {@link Application} that needs Sim status monitoring.
+ */
+ public MonitorSimStatusTask(Application app) {
+ super(app);
+ }
+
+ @Override
+ protected Void doInBackground() {
+ String results[] = null;
+ int ii ;
+
+ while (true) {
+
+ try {
+
+ if (statusSimcom != null) {
+
+ String resultsStr = statusSimcom.get();
+ if (resultsStr == null)
+ break;
+
+ results = resultsStr.split("\t");
+ ii = 1 ;
+
+ // whenever there is data in statusSimcom socket, do something
+ if (results != null && results[0].equals("0")) {
+ // "trick_sys.sched.time_tics"
+ if (results[ii] != null && results[ii] != "") {
+ double time_tics = Double.parseDouble(results[ii]);
+ double execOutTime = time_tics/execTimeTicValue;
+ simState.setExecOutTime(execOutTime);
+ ii++ ;
+ }
+
+ // "trick_sys.sched.mode"
+ if (results.length > ii && results[ii] != null && results[ii] != "") {
+ modeIndex = Integer.parseInt(results[ii]);
+ simState.setMode(modeIndex);
+ switch (modeIndex) {
+ case SimState.INITIALIZATION_MODE:
+ //currentSimStatusDesc = "Ready to Run";
+ //setSimStateDesc(currentSimStatusDesc);
+ //break;
+ case SimState.DEBUG_STEPPING_MODE:
+ case SimState.EXIT_MODE:
+ break;
+ // need to setProgress for FREEZE_MODE because a checkpoint could be loaded
+ // during this mode and that could have a new elapsed time.
+ case SimState.FREEZE_MODE:
+ case SimState.RUN_MODE:
+ // need to minus the sim start time as it could be a negative number
+ setProgress(Math.abs((float)((simState.getExecOutTime()-simStartTime)/simStopTime)));
+ break;
+ }
+ ii++ ;
+ }
+
+ // "real_time.rt_sync.actual_run_ratio"
+ if (results.length > ii && results[ii] != null && results[ii] != "") {
+ simState.setSimRealtimeRatio(Float.parseFloat(results[ii]));
+ ii++ ;
+ }
+
+ // "real_time.rt_sync.active"
+ if (results.length > ii && results[ii] != null && results[ii] != "") {
+ simState.setRealtimeActive(Integer.parseInt(results[ii]));
+ ii++;
+ }
+
+ // "instruments.debug_pause.debug_pause_flag"
+ if (debug_present == 1 && results.length > ii && results[ii] != null && results[ii] != "") {
+ debug_flag = Integer.parseInt(results[ii]);
+ if ( debug_flag == 1 ) {
+ simState.setMode(SimState.DEBUG_STEPPING_MODE);
+ }
+ ii++ ;
+ }
+
+ // "real_time.rt_sync.total_overrun"
+ if (overrun_present == 1 && results.length > ii && results[ii] != null && results[ii] != "") {
+ simState.setOverruns(Integer.parseInt(results[ii]));
+ ii++ ;
+ }
+ } else {
+ // break the while (true) loop
+ break;
+ }
+ }
+ } catch (Exception e) {
+ break;
+ }
+ } // end while (true)
+ return null;
+ }
+
+ @Override
+ protected void succeeded(Void ignored) {
+ simState.setMode(SimState.COMPLETE_MODE);
+ }
+
+ @Override
+ protected void finished() {
+ try {
+ if (commandSimcom != null) {
+ commandSimcom.close();
+ }
+ if (statusSimcom != null) {
+ statusSimcom.close();
+ }
+ if (isAutoExitOn) {
+ exit();
+ }
+ }
+ catch (IOException e) {
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ Application.launch(rtPerf.class, args);
+
+ // Arrays.toString(args) converts such as localhost 7000 -r to [localhost, 7000, -r],
+ // so need to remove [, ] and all white spaces.
+ String commandLine = (Arrays.toString(args)).replace("[","").replace("]", "").replaceAll("\\s+", "");
+
+ // check to see if -r or -restart is used
+ Pattern restartOptionPattern = Pattern.compile("(\\-r|\\-restart)(,|$)");
+ Matcher matcher = restartOptionPattern.matcher(commandLine);
+
+ // if -r | -restart is used, set the flag and then remove it from the command line
+ if (matcher.find()) {
+ isRestartOptionOn = true;
+ commandLine = matcher.replaceAll("");
+ }
+
+ // check to see if -auto_exit is used
+ Pattern autoExitOptionPattern = Pattern.compile("(\\-auto\\_exit)(,|$)");
+ Matcher autoExitMatcher = autoExitOptionPattern.matcher(commandLine);
+
+ if (autoExitMatcher.find()) {
+ isAutoExitOn = true;
+ commandLine = autoExitMatcher.replaceAll("");
+ }
+
+ Scanner commandScanner = new Scanner(commandLine).useDelimiter(",");
+ // now need to figure out host and port, if not specified, available host&port will be listed
+ if (commandScanner.hasNextInt()) {
+ port = commandScanner.nextInt();
+ if (commandScanner.hasNext()) {
+ host = commandScanner.next();
+ }
+ } else {
+ if (commandScanner.hasNext()) {
+ host = commandScanner.next();
+ if (commandScanner.hasNextInt()) {
+ port = commandScanner.nextInt();
+ }
+ }
+ }
+
+ if (commandScanner != null) {
+ commandScanner.close();
+ }
+ }
+}
\ No newline at end of file