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/include/trick/FrameLog.hh b/include/trick/FrameLog.hh index edff7600..4f8e799a 100644 --- a/include/trick/FrameLog.hh +++ b/include/trick/FrameLog.hh @@ -158,6 +158,9 @@ namespace Trick { void set_clock(Trick::Clock & in_clock) ; + + Trick::JobData target_job_array; /* -- job array to access job info in realtime */ + private: std::vector trick_jobs; // ** vector containing all trick job names std::vector user_jobs; // ** vector containing all user job names diff --git a/include/trick/JobData.hh b/include/trick/JobData.hh index 8ad72103..fbc12b1f 100644 --- a/include/trick/JobData.hh +++ b/include/trick/JobData.hh @@ -92,7 +92,7 @@ namespace Trick { long long frame_time ; /**< trick_io(**) */ /** Cumulative time in seconds used for job in frame (rt_stop_time - rt_start_time) / time_tic_value */ - double frame_time_seconds; /**< trick_io(**) trick_units(s) */ + double frame_time_seconds; /**< trick_io(*io) trick_units(s) */ /** Sim_object_id.id (for job identification in timeline logging) */ double frame_id; /**< trick_io(**) */ 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..1c362ed8 --- /dev/null +++ b/trick_source/java/src/main/java/trick/rtperf/rtPerf.java @@ -0,0 +1,1083 @@ +//======================================== +// 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() + { + System.err.println("Host is " + host + " and port is " + port); + // get host and port for selected sim +// if (runningSimList != null && runningSimList.getSelectedItem() != null) +// { +// System.err.println("Line 1\n"); +// String selectedStr = runningSimList.getSelectedItem().toString(); +// // remove the run info if it is shown +// int leftPre = selectedStr.indexOf("("); +// if (leftPre != -1) +// { +// System.err.println("Line 2\n"); +// selectedStr = selectedStr.substring(0, leftPre); +// } +// // can be separated either by : or whitespace +// String[] elements = selectedStr.split(":"); +// +// if (elements == null || elements.length < 2) +// { +// System.err.println("Line 3\n"); +// elements = selectedStr.split("\\s+"); +// } +// +// if (elements == null || elements.length < 2) +// { +// System.err.println("Line 4\n"); +// String errMsg = "Can't connect! Please provide valid host name and port number separated by : or whitespace!"; +// printErrorMessage(errMsg); +// return; +// } +// +// System.err.println("Line 5\n"); +// host = elements[0].trim(); +// +// try +// { +// port = Integer.parseInt(elements[1].trim()); +// } +// catch (NumberFormatException nfe) +// { +// System.err.println("Line 6\n"); +// String errMsg = elements[1] + " is not a valid port number!"; +// printErrorMessage(errMsg); +// return; +// } +// } + + getInitializationPacket(); + + if (commandSimcom == null) + { + System.err.println("Line 7\n"); + String errMsg = "Sorry, can't connect. Please make sure the availability of both server and port!"; + printErrorMessage(errMsg); + return; + } + else + { + System.err.println("Line 8\n"); + 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_frame_log.frame_log.target_job_array.frame_time_seconds\")\n"); + commandSimcom.put("trick.var_send()\n"); + + results = commandSimcom.get().split("\t"); + System.out.println(results[0] + " and " + results[1]); +// 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); + } + return; + } + + + /** + * 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(); + } + } +} diff --git a/trick_source/sim_services/FrameLog/FrameLog.cpp b/trick_source/sim_services/FrameLog/FrameLog.cpp index 2eb4516e..9c10db8e 100644 --- a/trick_source/sim_services/FrameLog/FrameLog.cpp +++ b/trick_source/sim_services/FrameLog/FrameLog.cpp @@ -361,6 +361,13 @@ int Trick::FrameLog::frame_clock_stop(Trick::JobData * curr_job) { Trick::JobData * target_job = (Trick::JobData *)curr_job->sup_class_data ; int thread, mode; double time_scale; + + bool isMonitor = false; + + std::string monitor_job_name = "trick_real_time.rt_sync.rt_monitor"; + + if ( monitor_job_name.compare(target_job->name) == 0 ) + isMonitor = true; /** @par Detailed Design: */ if ( target_job != NULL ) { @@ -370,6 +377,10 @@ int Trick::FrameLog::frame_clock_stop(Trick::JobData * curr_job) { time_scale = 1.0 / target_job->time_tic_value; target_job->frame_time += (target_job->rt_stop_time - target_job->rt_start_time); target_job->frame_time_seconds = target_job->frame_time * time_scale; + if (isMonitor) + { + target_job_array = *target_job; + } thread = target_job->thread; mode = exec_get_mode();