diff --git a/src/projections/Tools/EntryMethodProfile/ArrayIndexComparator.java b/src/projections/Tools/EntryMethodProfile/ArrayIndexComparator.java new file mode 100644 index 00000000..88825f99 --- /dev/null +++ b/src/projections/Tools/EntryMethodProfile/ArrayIndexComparator.java @@ -0,0 +1,29 @@ +package projections.Tools.EntryMethodProfile; + +import java.util.Comparator; + +/** + * Used to sort data array by index rather than use a more expensive data structure + */ +public class ArrayIndexComparator implements Comparator { + private final double[] array; + ArrayIndexComparator(double[] array) { + this.array = array; + } + + Integer[] createIndexArray() + { + Integer[] indexes = new Integer[array.length]; + for (int i = 0; i < array.length; i++) + { + indexes[i] = i; + } + return indexes; + } + + @Override + public int compare(Integer index1, Integer index2) + { + return (int)(array[index2] - array[index1]); + } +} diff --git a/src/projections/Tools/EntryMethodProfile/MethodProfileWindow.java b/src/projections/Tools/EntryMethodProfile/MethodProfileWindow.java new file mode 100644 index 00000000..90420e03 --- /dev/null +++ b/src/projections/Tools/EntryMethodProfile/MethodProfileWindow.java @@ -0,0 +1,247 @@ +package projections.Tools.EntryMethodProfile; + +import org.jfree.chart.title.TextTitle; +import projections.analysis.TimedProgressThreadExecutor; + +import projections.gui.*; + +import org.jfree.chart.*; +import org.jfree.chart.title.LegendTitle; +import org.jfree.ui.RectangleEdge; +import org.jfree.chart.plot.PiePlot; +import org.jfree.data.general.DefaultPieDataset; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.*; + +public class MethodProfileWindow extends ProjectionsWindow implements ActionListener +{ + private static int myRun = 0; + + private MethodProfileWindow thisWindow; + private MainWindow mainWindow; + + private JMenuItem mClose; + private JMenuItem mSaveScreenshot; + + private TreeMap LoadData; + private TreeMap LastIndices; + + private long startTime; + private long endTime; + private int firstPE; + private int lastPE; + + private JFreeChart chart; + + public MethodProfileWindow(MainWindow mainWindow) { + super(mainWindow); + thisWindow = this; + this.mainWindow = mainWindow; + + LoadData = new TreeMap(); + LastIndices = new TreeMap(); + + setForeground(Color.lightGray); + setTitle("Entry Method Profile - " + MainWindow.runObject[myRun].getFilename() + ".sts"); + + createMenus(); + pack(); + showDialog(); + } + + protected void createMenus() { + JMenuBar mbar = new JMenuBar(); + + // File Menu + JMenu fileMenu = new JMenu("File"); + + mClose = new JMenuItem("Close"); + mClose.addActionListener(this); + fileMenu.add(mClose); + + mbar.add(fileMenu); + + // Screenshot Menu + JMenu saveMenu = new JMenu("Save To Image"); + + mSaveScreenshot = new JMenuItem("Save Profile Chart as JPG or PNG"); + mSaveScreenshot.addActionListener(this); + saveMenu.add(mSaveScreenshot); + + mbar.add(saveMenu); + + this.setJMenuBar(mbar); + } + + @Override + public void actionPerformed(ActionEvent ae) { +// super.actionPerformed(ae); + Object c = ae.getSource(); + + if(c == mClose) { + this.close(); + } else if(c == mSaveScreenshot) { + JPanelToImage.saveToFileChooserSelection(chart.createBufferedImage(1100, 700), "Save Profile Chart", "./EntryMethodProfile.png"); + } + } + + public void setGraphSpecificData() { + + } + + public void showDialog() { + try { + if (dialog == null) { + dialog = new RangeDialog(this, "Select Range", null, false); + } + dialog.displayDialog(); + if (!dialog.isCancelled()) { + final SortedSet pes = dialog.getSelectedProcessors(); + firstPE = pes.first(); + lastPE = pes.last(); + startTime = dialog.getStartTime(); + endTime = dialog.getEndTime(); + + final SwingWorker worker = new SwingWorker() { + public Object doInBackground() { + // Load memory usages here + thisWindow.loadData(pes); + return null; + } + + public void done() { + thisWindow.createPlot(); + } + }; + worker.execute(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void createPlot() { + setVisible(false); + + int lastIndex = -1; + Iterator pes = LastIndices.keySet().iterator(); + while(pes.hasNext()) { + Long pe = pes.next(); + int currIndex = LastIndices.get(pe); + if(currIndex > lastIndex) + lastIndex = currIndex; + } + + double[] data = new double[lastIndex]; + pes = LoadData.keySet().iterator(); + while(pes.hasNext()) { + Long pe = pes.next(); + double[] currData = LoadData.get(pe); + int lastVal = Math.min(currData.length, lastIndex); + for(int i = 0; i < lastVal; i++) { + data[i] += currData[i]; + } + } + + ArrayIndexComparator comparator = new ArrayIndexComparator(data); + Integer[] indices = comparator.createIndexArray(); + Arrays.sort(indices, comparator); + + DefaultPieDataset dataset = new DefaultPieDataset( ); + for(int i = 0; i < lastIndex; i++) { + int curr = indices[i]; + if(data[curr] == 0) + break; + dataset.setValue(MainWindow.runObject[myRun].getEntryNameByIndex(curr), data[curr]); + } + chart = ChartFactory.createPieChart( + "Entry Method Profile", // chart title + dataset, // data + false, // include legend + true, + false); + + PiePlot plot = (PiePlot)chart.getPlot(); + + LegendItemCollection legendItemsOld = plot.getLegendItems(); + final LegendItemCollection legendItemsNew = new LegendItemCollection(); + for(int i = 0; i < Math.min(legendItemsOld.getItemCount(), 5); i++) { + legendItemsNew.add(legendItemsOld.get(i)); + } + LegendItemSource source = new LegendItemSource() { + LegendItemCollection lic = new LegendItemCollection(); { + lic.addAll(legendItemsNew); + } + public LegendItemCollection getLegendItems() { + return lic; + } + }; + LegendTitle legendTitle = new LegendTitle(source); + legendTitle.setPosition(RectangleEdge.BOTTOM); + chart.addLegend(legendTitle); + + String titleText; + if(lastPE == firstPE) + titleText = "Processor: " + firstPE + "; "; + else + titleText = "Processor(s): " + firstPE + " - " + lastPE + "; "; + titleText += "Time: " + U.humanReadableString(startTime) + " - " + U.humanReadableString(endTime); + + TextTitle choiceText = new TextTitle(titleText); + choiceText.setPosition(RectangleEdge.TOP); + chart.addSubtitle(choiceText); + + plot.setLabelGenerator(null); + + ChartPanel chartpanel = new ChartPanel(chart); + chart.setBackgroundPaint(Color.white); + + chartpanel.setPreferredSize(new Dimension(1100,700)); + + Container windowPane = thisWindow.getContentPane(); + windowPane.removeAll(); + windowPane.setLayout(new BorderLayout()); + windowPane.add(chartpanel, BorderLayout.CENTER); + + thisWindow.pack(); + thisWindow.setVisible(true); + } + + private void loadData(final SortedSet processorList) { + if( MainWindow.runObject[myRun].hasLogFiles() || MainWindow.runObject[myRun].hasSumDetailFiles() ) { + // Do parallel loading because we have full logs + + // Create a list of worker threads + LinkedList readyReaders = new LinkedList(); + + for(Integer nextPe : processorList){ + readyReaders.add( new ThreadedFileReader(nextPe, myRun, startTime, endTime)); + } + + // Determine a component to show the progress bar with + Component guiRootForProgressBar = null; + if(thisWindow!=null && thisWindow.isVisible()) { + guiRootForProgressBar = thisWindow; + } else if(mainWindow!=null && mainWindow.isVisible()){ + guiRootForProgressBar = mainWindow; + } else if(MainWindow.runObject[myRun].guiRoot!=null && MainWindow.runObject[myRun].guiRoot.isVisible()){ + guiRootForProgressBar = MainWindow.runObject[myRun].guiRoot; + } + + // Pass this list of threads to a class that manages/runs the threads nicely + TimedProgressThreadExecutor threadManager = new TimedProgressThreadExecutor("Loading Entry Method Profile in Parallel", readyReaders, guiRootForProgressBar, true); + threadManager.runAll(); + + Iterator titer = readyReaders.iterator(); + while(titer.hasNext()){ + ThreadedFileReader r = (ThreadedFileReader) titer.next(); + LoadData.put(r.getPe(), r.getData()); + LastIndices.put(r.getPe(), r.getLastIndex()); + } + } + } +} \ No newline at end of file diff --git a/src/projections/Tools/EntryMethodProfile/ThreadedFileReader.java b/src/projections/Tools/EntryMethodProfile/ThreadedFileReader.java new file mode 100644 index 00000000..f0ed3232 --- /dev/null +++ b/src/projections/Tools/EntryMethodProfile/ThreadedFileReader.java @@ -0,0 +1,107 @@ +package projections.Tools.EntryMethodProfile; + +import java.io.IOException; +import java.util.Stack; + +import projections.analysis.EndOfLogSuccess; +import projections.analysis.GenericLogReader; +import projections.analysis.ProjDefs; +import projections.gui.MainWindow; +import projections.misc.LogEntryData; + +class ThreadedFileReader implements Runnable { + + private int pe; + private int myRun; + private int lastIndex; + private long startTime; + private long endTime; + + private double load[]; + + private int _SIZE = 500000; + + /** Construct a file reading thread that will determine the load for each entry function + * + * The resulting output data will be assigned into the array specified without synchronization + * + * */ + protected ThreadedFileReader(int pe, int myRun, long startTime, long endTime){ + this.pe = pe; + this.myRun = myRun; + this.startTime = startTime; + this.endTime = endTime; + } + + public void run() { + GenericLogReader reader = new GenericLogReader(pe, MainWindow.runObject[myRun].getVersion()); + + // First take data and put it into intervals. + load = new double[_SIZE]; + Stack stack = new Stack(); + lastIndex = -1; + + try { + while (true) { +// System.out.println("c before " + (count)); + LogEntryData data = reader.nextEvent(); +// System.out.println("c after " + (count)); + + switch(data.type) { + case ProjDefs.BEGIN_PROCESSING: + stack.push(data); + break; + case ProjDefs.END_PROCESSING: + if(stack.empty()) { + break; + } + LogEntryData beginData = stack.pop(); + if(beginData.entry != data.entry) { + break; + } else if((data.time - beginData.time) > 0 && data.time < endTime && beginData.time >= startTime) { + if(beginData.entry > _SIZE) { + int newSize = _SIZE + beginData.entry; + double[] tempEvents = new double[newSize]; + System.arraycopy(load, 0, tempEvents, 0, _SIZE); + load = tempEvents; + _SIZE = newSize; + } + load[beginData.entry] += (data.time - beginData.time); + } + lastIndex = Math.max(lastIndex, beginData.entry); + break; + default: + break; + } + } + } + catch (EndOfLogSuccess e) { + // Done reading file + } catch (IOException e) { + // Error reading file + } + + try { + reader.close(); + } catch (IOException e1) { + System.err.println("Error: could not close log file reader for processor " + pe ); + } + } + + public double[] getData(){ + return load; + } + + public long getPe() { + return pe; + } + + int getLastIndex() { + return lastIndex; + } +} + + + + + diff --git a/src/projections/Tools/Histogram/ThreadedFileReader.java b/src/projections/Tools/Histogram/ThreadedFileReader.java index 77176831..010107a3 100644 --- a/src/projections/Tools/Histogram/ThreadedFileReader.java +++ b/src/projections/Tools/Histogram/ThreadedFileReader.java @@ -352,7 +352,7 @@ else if (logdata.time >= endTime)//startTime <= endTime <= endIdle case ProjDefs.CREATION: //if (logEnd == true) break; - if (logdata.time > endTime) { + if (logdata.time < startTime || logdata.time > endTime) { break; } // respect the user threshold. diff --git a/src/projections/Tools/MessageSizeEvolution/BinDialogPanel.java b/src/projections/Tools/MessageSizeEvolution/BinDialogPanel.java new file mode 100644 index 00000000..eb795ab7 --- /dev/null +++ b/src/projections/Tools/MessageSizeEvolution/BinDialogPanel.java @@ -0,0 +1,263 @@ +package projections.Tools.MessageSizeEvolution; + +import projections.gui.JIntTextField; +import projections.gui.JLongTextField; +import projections.gui.RangeDialog; +import projections.gui.RangeDialogExtensionPanel; +import projections.gui.U; +import projections.gui.Util; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JCheckBox; +import javax.swing.border.LineBorder; +import javax.swing.border.TitledBorder; + +import java.awt.GridBagLayout; +import java.awt.GridBagConstraints; +import java.awt.Insets; +import java.awt.Color; +import java.awt.BorderLayout; + +import java.text.DecimalFormat; + +class BinDialogPanel + extends RangeDialogExtensionPanel { + + private JLabel timeBinRangeLabel; + private JIntTextField timeNumBinsField; + private long timeBinSize; + private long timeMinBinSize; + + private JLabel msgBinRangeLabel; + private JIntTextField msgNumBinsField; + private JLongTextField msgBinSizeField; + private JLongTextField msgMinBinSizeField; + private JCheckBox msgLogScale; + private JCheckBox msgIncludeCreation; + + private boolean prevScale; + + private RangeDialog parent; + + BinDialogPanel() { + JPanel timeBinPanel; + JPanel msgBinPanel; + + JLabel timeNumBinsLabel; + + JLabel msgNumBinsLabel; + JLabel msgBinSizeLabel; + JLabel msgMinBinSizeLabel; + + GridBagLayout gbl = new GridBagLayout(); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.BOTH; + gbc.insets = new Insets(2,2,2,2); + + // Time Panel + timeBinPanel = new JPanel(); + timeBinPanel.setLayout(gbl); + timeBinPanel.setBorder(new TitledBorder(new LineBorder(Color.black), "TIME-BASED BINS")); + + timeNumBinsLabel = new JLabel("# of Time Bins:", JLabel.LEFT); + timeNumBinsField = new JIntTextField(-1, 5); + + timeBinRangeLabel = new JLabel("", JLabel.LEFT); + + Util.gblAdd(timeBinPanel, timeNumBinsLabel, gbc, 0,0, 1,1, 1,1); + Util.gblAdd(timeBinPanel, timeNumBinsField, gbc, 1,0, 1,1, 1,1); + Util.gblAdd(timeBinPanel, timeBinRangeLabel, gbc, 0,1, 4,1, 1,1); + + // Messages Panel + msgBinPanel = new JPanel(); + msgBinPanel.setLayout(gbl); + msgBinPanel.setBorder(new TitledBorder(new LineBorder(Color.black), + "MESSAGE-BASED BINS")); + + msgNumBinsLabel = new JLabel("# of Msg Bins:", JLabel.LEFT); + msgNumBinsField = new JIntTextField(-1, 5); + + msgBinSizeLabel = new JLabel("Bin Size (bytes):", JLabel.LEFT); + msgBinSizeField = new JLongTextField(-1, 12); + + msgMinBinSizeLabel = new JLabel("Starting Bin Size:", JLabel.LEFT); + msgMinBinSizeField = new JLongTextField(-1, 12); + + msgBinRangeLabel = new JLabel("", JLabel.LEFT); + + msgLogScale = new JCheckBox("Log Scale"); + msgIncludeCreation = new JCheckBox("Creation Events"); + + Util.gblAdd(msgBinPanel, msgNumBinsLabel, gbc, 0,0, 1,1, 1,1); + Util.gblAdd(msgBinPanel, msgNumBinsField, gbc, 1,0, 1,1, 1,1); + Util.gblAdd(msgBinPanel, msgLogScale, gbc, 2,0, 1,1, 1,1); + Util.gblAdd(msgBinPanel, msgIncludeCreation, gbc, 3,0, 1,1, 1,1); + Util.gblAdd(msgBinPanel, msgMinBinSizeLabel, gbc, 0,1, 1,1, 1,1); + Util.gblAdd(msgBinPanel, msgMinBinSizeField, gbc, 1,1, 1,1, 1,1); + Util.gblAdd(msgBinPanel, msgBinSizeLabel, gbc, 2,1, 1,1, 1,1); + Util.gblAdd(msgBinPanel, msgBinSizeField, gbc, 3,1, 1,1, 1,1); + Util.gblAdd(msgBinPanel, msgBinRangeLabel, gbc, 0,2, 4,1, 1,1); + + this.setLayout(new BorderLayout()); + this.add(timeBinPanel, BorderLayout.CENTER); + this.add(msgBinPanel, BorderLayout.SOUTH); + } + + // Accessor methods + int getTimeNumBins() { + if(timeNumBinsField.getValue() - 1 >= 0) + return timeNumBinsField.getValue() - 1; + else + return 0; + } + + public void setTimeNumBins(int numBins) { + timeNumBinsField.setValue(numBins); + parent.someInputChanged(); + } + + long getTimeBinSize() { + return timeBinSize; + } + + public void setTimeBinSize(long binSize) { + timeBinSize = binSize; + parent.someInputChanged(); + } + + long getTimeMinBinSize() { + return timeMinBinSize; + } + + public void setTimeMinBinSize(long size) { + timeMinBinSize = size; + parent.someInputChanged(); + } + + // Messages + int getMsgNumBins() { + if (msgNumBinsField.getValue()-1 >= 0) + return msgNumBinsField.getValue()-1; + else + return 0; + } + + public void setMsgNumBins(int numBins) { + msgNumBinsField.setValue(numBins); + parent.someInputChanged(); + } + + long getMsgBinSize() { + return msgBinSizeField.getValue(); + } + + public void setMsgBinSize(long binSize) { + msgBinSizeField.setValue(binSize); + parent.someInputChanged(); + } + + long getMsgMinBinSize() { + return msgMinBinSizeField.getValue(); + } + + public void setMsgMinBinSize(long size) { + msgMinBinSizeField.setValue(size); + parent.someInputChanged(); + } + + boolean getMsgLogScale() { + return msgLogScale.isSelected(); + } + + public void setMsgLogScale(boolean logScale) { + msgLogScale.setSelected(logScale); + parent.someInputChanged(); + } + + boolean getMsgCreationEvent() { + return msgIncludeCreation.isSelected(); + } + + public void setMsgIncludeCreation(boolean includeCreation) { + msgIncludeCreation.setSelected(includeCreation); + parent.someInputChanged(); + } + + public boolean isInputValid() { + return true; + } + + public void setInitialFields() { + // default values for time 1ms to 100ms + timeNumBinsField.setText("100"); + timeMinBinSize = parent.getStartTime(); + timeBinSize = parent.getSelectedTotalTime() / 100; + + // default values for messages 100 bytes to 2k + msgNumBinsField.setText("10"); + msgBinSizeField.setText("1000"); + msgBinSizeField.setEnabled(false); + msgMinBinSizeField.setText("128"); + msgLogScale.setSelected(true); + msgIncludeCreation.setSelected(false); + + prevScale = true; + updateFields(); + } + + public void setParentDialogBox(RangeDialog parent) { + this.parent = parent; + timeNumBinsField.addActionListener(parent); + timeNumBinsField.addKeyListener(parent); + timeNumBinsField.addFocusListener(parent); + msgNumBinsField.addActionListener(parent); + msgNumBinsField.addKeyListener(parent); + msgNumBinsField.addFocusListener(parent); + msgBinSizeField.addActionListener(parent); + msgBinSizeField.addKeyListener(parent); + msgBinSizeField.addFocusListener(parent); + msgMinBinSizeField.addActionListener(parent); + msgMinBinSizeField.addKeyListener(parent); + msgMinBinSizeField.addFocusListener(parent); + msgLogScale.addActionListener(parent); + } + + public void updateFields() { + timeMinBinSize = parent.getStartTime(); + timeBinSize = parent.getSelectedTotalTime() / getTimeNumBins(); + + timeBinRangeLabel.setText("Bin size ranges from : " + + U.humanReadableString(timeMinBinSize) + + " to " + + U.humanReadableString(timeMinBinSize + + parent.getSelectedTotalTime())); + + boolean currScale = getMsgLogScale(); + DecimalFormat _format = new DecimalFormat(); + if(currScale) { + if(!prevScale) { + if(msgMinBinSizeField.getValue() < 128) + msgMinBinSizeField.setText("128"); + msgBinSizeField.setEnabled(false); + prevScale = true; + } + + msgBinRangeLabel.setText("Bin size ranges from : " + + _format.format(msgMinBinSizeField.getValue()) + + " bytes to " + + _format.format(msgMinBinSizeField.getValue() * + Math.pow(2, msgNumBinsField.getValue())) + " bytes."); + } else { + if(prevScale) { + msgBinSizeField.setEnabled(true); + prevScale = false; + } + msgBinRangeLabel.setText("Bin size ranges from : " + + _format.format(msgMinBinSizeField.getValue()) + + " bytes to " + + _format.format(msgMinBinSizeField.getValue() + + getMsgNumBins() * msgBinSizeField.getValue()) + " bytes."); + } + } +} diff --git a/src/projections/Tools/MessageSizeEvolution/CustomRangeAxis.java b/src/projections/Tools/MessageSizeEvolution/CustomRangeAxis.java new file mode 100644 index 00000000..e008c064 --- /dev/null +++ b/src/projections/Tools/MessageSizeEvolution/CustomRangeAxis.java @@ -0,0 +1,145 @@ +package projections.Tools.MessageSizeEvolution; + +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.axis.AxisState; +import org.jfree.chart.axis.ValueTick; +import org.jfree.chart.axis.LogTick; +import org.jfree.chart.axis.TickType; +import org.jfree.chart.util.AttrStringUtils; + +import org.jfree.text.TextUtilities; +import org.jfree.ui.RectangleEdge; + +import projections.gui.U; + +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.geom.Line2D; +import java.awt.geom.Rectangle2D; + +import java.text.NumberFormat; +import java.text.ParseException; + +import java.util.List; +import java.util.Locale; + +class CustomRangeAxis + extends NumberAxis { + + private long timeMinBinSize; + + CustomRangeAxis(long timeMinBinSize) { + this.timeMinBinSize = timeMinBinSize; + } + + @Override + protected AxisState drawTickMarksAndLabels(Graphics2D g2, double cursor, Rectangle2D plotArea, Rectangle2D dataArea, RectangleEdge edge) { + AxisState state = new AxisState(cursor); + if (isAxisLineVisible()) { + drawAxisLine(g2, cursor, dataArea, edge); + } + List ticks = refreshTicks(g2, state, dataArea, edge); + state.setTicks(ticks); + g2.setFont(getTickLabelFont()); + Object saved = g2.getRenderingHint(RenderingHints.KEY_STROKE_CONTROL); + g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, + RenderingHints.VALUE_STROKE_NORMALIZE); + for(Object o : ticks) { + ValueTick tick = (ValueTick) o; + if (isTickLabelsVisible()) { + g2.setPaint(getTickLabelPaint()); + float[] anchorPoint = calculateAnchorPoint(tick, cursor, + dataArea, edge); + if (tick instanceof LogTick) { + LogTick lt = (LogTick) tick; + if (lt.getAttributedLabel() == null) { + continue; + } + AttrStringUtils.drawRotatedString(lt.getAttributedLabel(), + g2, anchorPoint[0], anchorPoint[1], + tick.getTextAnchor(), tick.getAngle(), + tick.getRotationAnchor()); + } else { + if (tick.getText() == null) { + continue; + } + String text = tick.getText(); + String result; + if(!text.equals("") && text.matches("[0-9, /,]+")) { + Number num; + try { + num = NumberFormat.getNumberInstance(Locale.US).parse(text); + } catch(ParseException e) { + e.printStackTrace(); + return null; + } + result = U.humanReadableString(num.longValue() + timeMinBinSize); + } else + result = text; + TextUtilities.drawRotatedString(result, g2, + anchorPoint[0], anchorPoint[1], + tick.getTextAnchor(), tick.getAngle(), + tick.getRotationAnchor()); + } + } + + if ((isTickMarksVisible() && tick.getTickType().equals( + TickType.MAJOR)) || (isMinorTickMarksVisible() + && tick.getTickType().equals(TickType.MINOR))) { + + double ol = (tick.getTickType().equals(TickType.MINOR)) + ? getMinorTickMarkOutsideLength() + : getTickMarkOutsideLength(); + + double il = (tick.getTickType().equals(TickType.MINOR)) + ? getMinorTickMarkInsideLength() + : getTickMarkInsideLength(); + + float xx = (float) valueToJava2D(tick.getValue(), dataArea, + edge); + Line2D mark = null; + g2.setStroke(getTickMarkStroke()); + g2.setPaint(getTickMarkPaint()); + if (edge == RectangleEdge.LEFT) { + mark = new Line2D.Double(cursor - ol, xx, cursor + il, xx); + } + else if (edge == RectangleEdge.RIGHT) { + mark = new Line2D.Double(cursor + ol, xx, cursor - il, xx); + } + else if (edge == RectangleEdge.TOP) { + mark = new Line2D.Double(xx, cursor - ol, xx, cursor + il); + } + else if (edge == RectangleEdge.BOTTOM) { + mark = new Line2D.Double(xx, cursor + ol, xx, cursor - il); + } + g2.draw(mark); + } + } + g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, saved); + + // need to work out the space used by the tick labels... + // so we can update the cursor... + double used = 0.0; + if (isTickLabelsVisible()) { + if (edge == RectangleEdge.LEFT) { + used += findMaximumTickLabelWidth(ticks, g2, plotArea, + isVerticalTickLabels()); + state.cursorLeft(used); + } else if (edge == RectangleEdge.RIGHT) { + used = findMaximumTickLabelWidth(ticks, g2, plotArea, + isVerticalTickLabels()); + state.cursorRight(used); + } else if (edge == RectangleEdge.TOP) { + used = findMaximumTickLabelHeight(ticks, g2, plotArea, + isVerticalTickLabels()); + state.cursorUp(used); + } else if (edge == RectangleEdge.BOTTOM) { + used = findMaximumTickLabelHeight(ticks, g2, plotArea, + isVerticalTickLabels()); + state.cursorDown(used); + } + } + + return state; + } +} diff --git a/src/projections/Tools/MessageSizeEvolution/CustomToolTipGenerator.java b/src/projections/Tools/MessageSizeEvolution/CustomToolTipGenerator.java new file mode 100644 index 00000000..e7864446 --- /dev/null +++ b/src/projections/Tools/MessageSizeEvolution/CustomToolTipGenerator.java @@ -0,0 +1,72 @@ +package projections.Tools.MessageSizeEvolution; + +import org.jfree.chart.labels.StandardCategoryToolTipGenerator; +import org.jfree.data.category.CategoryDataset; +import projections.gui.U; + +import java.text.DecimalFormat; + +public class CustomToolTipGenerator + extends StandardCategoryToolTipGenerator { + private double[][] values; + private long timeNumBins; + private long timeBinSize; + private long timeMinBinSize; + private long msgNumBins; + private long msgBinSize; + private long msgMinBinSize; + private boolean msgLogScale; + + CustomToolTipGenerator(double[][] values, long timeNumBins, long timeBinSize, long timeMinBinSize, long msgNumBins, long msgBinSize, long msgMinBinSize, boolean msgLogScale) { + super(); + this.values = new double[values.length][values[0].length]; + for(int i = 0; i < values.length; i++) { + System.arraycopy(values[i], 0, this.values[i], 0, values[i].length); + } + this.timeBinSize = timeBinSize; + this.timeMinBinSize = timeMinBinSize; + this.timeNumBins = timeNumBins; + this.msgBinSize = msgBinSize; + this.msgMinBinSize = msgMinBinSize; + this.msgNumBins = msgNumBins; + this.msgLogScale = msgLogScale; + } + + @Override + public String generateToolTip(CategoryDataset dataset, int row, int column) { + DecimalFormat _format = new DecimalFormat(); + String toolTip = ""; + + if(row < timeNumBins) + toolTip += "Time Bin: " + U.humanReadableString(row * timeBinSize + timeMinBinSize) + + " to " + U.humanReadableString((row + 1) * timeBinSize + timeMinBinSize); + else + toolTip += "Time Bin: > " + U.humanReadableString(timeNumBins * timeBinSize + timeMinBinSize); + + toolTip += "
"; + + if(column > 0) { + if(msgLogScale) + toolTip += "Message Size Bin: " + _format.format(msgMinBinSize * Math.pow(2, msgNumBins - column)) + + " bytes to " + _format.format(msgMinBinSize * Math.pow(2, msgNumBins - column + 1)) + " bytes"; + else + toolTip += "Message Size Bin: " + _format.format(msgMinBinSize + (msgNumBins - column) * msgBinSize) + + " bytes to " + _format.format(msgMinBinSize + (msgNumBins - column + 1) * msgBinSize) + " bytes"; + } else { + if(msgLogScale) + toolTip += "Message Size Bin: > " + _format.format(msgMinBinSize * Math.pow(2, msgNumBins)) + + " bytes"; + else + toolTip += "Message Size Bin: " + _format.format(msgMinBinSize + msgNumBins * msgBinSize) + + " bytes"; + } + + toolTip += "
"; + + toolTip += "Count: " + values[row][column]; + + toolTip += ""; + + return toolTip; + } +} diff --git a/src/projections/Tools/MessageSizeEvolution/MessageSizeEvolutionWindow.java b/src/projections/Tools/MessageSizeEvolution/MessageSizeEvolutionWindow.java new file mode 100644 index 00000000..dc4a74c7 --- /dev/null +++ b/src/projections/Tools/MessageSizeEvolution/MessageSizeEvolutionWindow.java @@ -0,0 +1,258 @@ +package projections.Tools.MessageSizeEvolution; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.CategoryPlot; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.data.category.DefaultCategoryDataset; + +import projections.analysis.TimedProgressThreadExecutor; +import projections.gui.ProjectionsWindow; +import projections.gui.MainWindow; +import projections.gui.RangeDialog; +import projections.gui.U; +import projections.gui.JPanelToImage; + +import javax.swing.JMenuBar; +import javax.swing.SwingWorker; +import javax.swing.JOptionPane; +import javax.swing.JMenuItem; +import javax.swing.JMenu; + +import java.awt.Component; +import java.awt.Color; +import java.awt.Container; +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.text.DecimalFormat; +import java.util.LinkedList; + +public class MessageSizeEvolutionWindow + extends ProjectionsWindow + implements ActionListener{ + + private int myRun = 0; + + //menu stuff + private JMenuItem mClose; + private JMenuItem mSaveScreenshot; + + private BinDialogPanel binpanel; + + private int numEPs; + private JFreeChart chart; + + // counts is indexed by msg bin index, then time bin index followed by ep id. + // NOTE: bin indices need not be of the same size + private double[][][] counts; + + private int timeNumBins; + private long timeBinSize; + private long timeMinBinSize; + private int msgNumBins; + private long msgBinSize; + private long msgMinBinSize; + private boolean msgLogScale; + private boolean msgCreationEvent; + + private MessageSizeEvolutionWindow thisWindow; + private MainWindow mainWindow; + + private DecimalFormat _format; + + public MessageSizeEvolutionWindow(MainWindow mainWindow) { + super(mainWindow); + thisWindow = this; + this.mainWindow = mainWindow; + + setTitle("Projections Message Size Evolution - " + MainWindow.runObject[myRun].getFilename() + ".sts"); + _format = new DecimalFormat(); + + createMenus(); + pack(); + showDialog(); + } + + public void close() { + super.close(); + } + + public void showDialog() { + if(dialog == null) { + binpanel = new BinDialogPanel(); + dialog = new RangeDialog(this, "Select Message Size Evolution Time Range", binpanel, false); + } + + dialog.displayDialog(); + if(!dialog.isCancelled()) { + final SwingWorker worker = new SwingWorker() { + @Override + protected Object doInBackground() throws Exception { + timeNumBins = binpanel.getTimeNumBins(); + timeBinSize = binpanel.getTimeBinSize(); + timeMinBinSize = binpanel.getTimeMinBinSize(); + msgNumBins = binpanel.getMsgNumBins(); + msgBinSize = binpanel.getMsgBinSize(); + msgMinBinSize = binpanel.getMsgMinBinSize(); + msgLogScale = binpanel.getMsgLogScale(); + msgCreationEvent = binpanel.getMsgCreationEvent(); + if(!msgLogScale && (timeBinSize == 0 || msgBinSize == 0)) { + //prevents dividing by zero + JOptionPane.showMessageDialog(null, "You cannot enter a bin size of zero.", "Error", JOptionPane.ERROR_MESSAGE); + System.out.println("You cannot enter a bin size of zero."); + return null; + } else if(msgLogScale && msgMinBinSize < 128) { + JOptionPane.showMessageDialog(null, "You cannot enter a starting bin size less than 128.", "Error", JOptionPane.ERROR_MESSAGE); + System.out.println("You cannot enter a starting bin size less than 128."); + return null; + } + numEPs = MainWindow.runObject[myRun].getNumUserEntries() + 1; + counts = new double[timeNumBins + 1][msgNumBins + 1][numEPs]; + + // Create a list of worker threads + LinkedList readyReaders = new LinkedList(); + for(Integer nextPe : dialog.getSelectedProcessors()) { + readyReaders.add( new ThreadedFileReader(counts, nextPe, dialog.getStartTime(), dialog.getEndTime(), timeNumBins, timeBinSize, timeMinBinSize, msgNumBins, msgBinSize, msgMinBinSize, msgLogScale, msgCreationEvent)); + } + + // Determine a component to show the progress bar with + Component guiRootForProgressBar = null; + if(thisWindow != null && thisWindow.isVisible()) + guiRootForProgressBar = thisWindow; + else if(mainWindow != null && mainWindow.isVisible()) + guiRootForProgressBar = mainWindow; + else if(MainWindow.runObject[myRun].guiRoot != null && MainWindow.runObject[myRun].guiRoot.isVisible()) + guiRootForProgressBar = MainWindow.runObject[myRun].guiRoot; + + // Pass this list of threads to a class that manages/runs the threads nicely + TimedProgressThreadExecutor threadManager = new TimedProgressThreadExecutor("Loading Message Size Evolution in Parallel", readyReaders, guiRootForProgressBar, true); + threadManager.runAll(); + + return null; + } + + protected void done() { + createPlot(); + } + }; + worker.execute(); + } + } + + private void createPlot() { + thisWindow.setVisible(false); + + double[][] heatMap = new double[counts.length][]; + double maxVal = Double.MIN_VALUE, minVal = Double.MAX_VALUE; + DefaultCategoryDataset dataset = new DefaultCategoryDataset(); + for(int i = 0; i < counts.length; i++) { + heatMap[i] = new double[counts[i].length]; + for(int j = counts[i].length - 1; j >= 0; j--) { + double sum = 0; + for(int k = 0; k < counts[i][j].length; k++) { + sum += counts[i][j][k]; + } + if(sum > maxVal) + maxVal = sum; + if(sum < minVal) + minVal = sum; + String msgKey; + if(j == counts[i].length - 1) { + if(msgLogScale) + msgKey = " >= " + _format.format(msgMinBinSize * Math.pow(2, j)); + else + msgKey = " >= " + _format.format((j * msgBinSize) + msgMinBinSize); + } else { + if (msgLogScale) + msgKey = _format.format(msgMinBinSize * Math.pow(2, j)) + " - " + _format.format(msgMinBinSize * Math.pow(2, j + 1) - 1); + else + msgKey = _format.format((j * msgBinSize) + msgMinBinSize) + " - " + _format.format(((j + 1) * msgBinSize) + msgMinBinSize - 1); + } + dataset.addValue(timeBinSize, + U.humanReadableString((i * timeBinSize) + timeMinBinSize), + msgKey + ); + heatMap[i][counts[i].length - 1 - j] = sum; + } + } + + chart = ChartFactory.createStackedBarChart( + "Message Size Evolution Chart", + "Message Size", + "Time", + dataset, + PlotOrientation.HORIZONTAL, + false, + true, + false + ); + + CategoryPlot plot = chart.getCategoryPlot(); + StackedRenderer renderer = new StackedRenderer(heatMap, maxVal); + renderer.setBaseToolTipGenerator(new CustomToolTipGenerator(heatMap, timeNumBins, timeBinSize, timeMinBinSize, msgNumBins, msgBinSize, msgMinBinSize, msgLogScale)); + plot.setRenderer(renderer); + + CustomRangeAxis rangeAxis = new CustomRangeAxis(timeMinBinSize); + plot.setRangeAxis(rangeAxis); + plot.setBackgroundPaint(Color.WHITE); + + final ChartPanel chartPanel = new ChartPanel(chart); + chart.setBackgroundPaint(Color.LIGHT_GRAY); + + Container windowPane = thisWindow.getContentPane(); + windowPane.removeAll(); + windowPane.setLayout(new BorderLayout()); + windowPane.add(chartPanel, BorderLayout.CENTER); + + thisWindow.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + chartPanel.setMaximumDrawHeight(e.getComponent().getHeight()); + chartPanel.setMaximumDrawWidth(e.getComponent().getWidth()); + chartPanel.setMinimumDrawWidth(e.getComponent().getWidth()); + chartPanel.setMinimumDrawHeight(e.getComponent().getHeight()); + } + }); + + thisWindow.pack(); + thisWindow.setVisible(true); + } + + protected void createMenus() { + JMenuBar mbar = new JMenuBar(); + + //File Menu + JMenu fileMenu = new JMenu("File"); + + mClose = new JMenuItem("Close"); + mClose.addActionListener(this); + fileMenu.add(mClose); + + mbar.add(fileMenu); + + //Screenshot Menu + JMenu saveMenu = new JMenu("Save To Image"); + + mSaveScreenshot = new JMenuItem("Save Profile Chart to JPG or PNG"); + mSaveScreenshot.addActionListener(this); + saveMenu.add(mSaveScreenshot); + + mbar.add(saveMenu); + + this.setJMenuBar(mbar); + } + + @Override + public void actionPerformed(ActionEvent ae) { + Object c = ae.getSource(); + if(c == mClose) + this.close(); + else if(c == mSaveScreenshot) + JPanelToImage.saveToFileChooserSelection(chart.createBufferedImage(1100, 700), "Save Evolution Chart", "./MessageSizeEvolution.png"); + } +} diff --git a/src/projections/Tools/MessageSizeEvolution/StackedRenderer.java b/src/projections/Tools/MessageSizeEvolution/StackedRenderer.java new file mode 100644 index 00000000..e5f5abbe --- /dev/null +++ b/src/projections/Tools/MessageSizeEvolution/StackedRenderer.java @@ -0,0 +1,41 @@ +package projections.Tools.MessageSizeEvolution; + +import org.jfree.chart.renderer.GrayPaintScale; +import org.jfree.chart.renderer.category.StackedBarRenderer; +import org.jfree.chart.renderer.category.StandardBarPainter; + +import java.awt.Color; +import java.awt.Paint; + +class StackedRenderer + extends StackedBarRenderer { + + private double[][] values; + private double logMax; + private GrayPaintScale paintScale; + + StackedRenderer(double[][] values, double maxVal) { + super(); + setDrawBarOutline(true); + setBarPainter(new StandardBarPainter()); + setShadowVisible(false); + setSeriesPaint(0, Color.BLUE); + this.values = new double[values.length][values[0].length]; + logMax = Math.log(maxVal + 1) / Math.log(2); + for(int i = 0; i < values.length; i++) { + System.arraycopy(values[i], 0, this.values[i], 0, values[i].length); + } + paintScale = new GrayPaintScale(0, logMax); + } + + @Override + public Paint getItemPaint(final int row, final int col) { + // get opposite value of scale so that white = min, black = max + return paintScale.getPaint(logMax - (Math.log(values[row][col] + 1) / Math.log(2))); + } + + @Override + public Paint getItemOutlinePaint(int row, int column) { + return new Color(225, 225, 225); + } +} diff --git a/src/projections/Tools/MessageSizeEvolution/ThreadedFileReader.java b/src/projections/Tools/MessageSizeEvolution/ThreadedFileReader.java new file mode 100644 index 00000000..41b64186 --- /dev/null +++ b/src/projections/Tools/MessageSizeEvolution/ThreadedFileReader.java @@ -0,0 +1,112 @@ +package projections.Tools.MessageSizeEvolution; + +import projections.analysis.EndOfLogSuccess; +import projections.analysis.GenericLogReader; +import projections.analysis.ProjDefs; +import projections.gui.MainWindow; +import projections.misc.LogEntryData; + +import java.io.IOException; + +class ThreadedFileReader + implements Runnable { + private int pe; + private long startTime; + private long endTime; + private int myRun = 0; + + private int timeNumBins; + private long timeBinSize; + private long timeMinBinSize; + private int msgNumBins; + private long msgBinSize; + private long msgMinBinSize; + private boolean msgLogScale; + private boolean msgCreationEvent; + + private double [][][] outputCounts; + + protected ThreadedFileReader(double[][][] outputCounts, int pe, long startTime, long endTime, int timeNumBins, long timeBinSize, long timeMinBinSize, int msgNumBins, long msgBinSize, long msgMinBinSize, boolean msgLogScale, boolean msgCreationEvent) { + this.pe = pe; + this.startTime = startTime; + this.endTime = endTime; + this.timeNumBins = timeNumBins; + this.timeBinSize = timeBinSize; + this.timeMinBinSize = timeMinBinSize; + this.msgNumBins = msgNumBins; + this.msgBinSize = msgBinSize; + this.msgMinBinSize = msgMinBinSize; + this.outputCounts = outputCounts; + this.msgLogScale = msgLogScale; + this.msgCreationEvent = msgCreationEvent; + } + + public void run() { + double [][][] myCounts = getCounts(); + // in synchronized manner accumulate into global counts: + synchronized (outputCounts) { + for(int i = 0; i < outputCounts.length; i++) { + for(int j = 0; j < outputCounts[i].length; j++) { + for(int k = 0; k < outputCounts[i][j].length; k++) { + outputCounts[i][j][k] += myCounts[i][j][k]; + } + } + } + } + } + + private double[][][] getCounts() { + long adjustedTime; + long adjustedSize; + + int numEPs = MainWindow.runObject[myRun].getNumUserEntries()+1; + double[][][] countData = new double[timeNumBins + 1][msgNumBins + 1][numEPs]; + + GenericLogReader reader = new GenericLogReader(pe, MainWindow.runObject[myRun].getVersion()); + try { + while(true) { + LogEntryData logData = reader.nextEvent(); + switch (logData.type) { + case ProjDefs.CREATION: + if(!msgCreationEvent) + break; + case ProjDefs.BEGIN_PROCESSING: + if (logData.time < startTime || logData.time > endTime || (msgLogScale && logData.msglen < msgMinBinSize) || logData.pe == pe) + break; + adjustedSize = logData.msglen; + if(!msgLogScale) + adjustedSize -= msgMinBinSize; + adjustedTime = logData.time - timeMinBinSize; + if (adjustedSize >= 0 && adjustedTime >= 0) { + int msgTargetBin; + if(msgLogScale) + msgTargetBin = (int)Math.floor(Math.log(Math.floor(adjustedSize / msgMinBinSize)) / Math.log(2)); + else + msgTargetBin = (int) (adjustedSize / msgBinSize); + int timeTargetBin = (int) (adjustedTime / timeBinSize); + if (msgTargetBin >= msgNumBins) + msgTargetBin = msgNumBins; + if (timeTargetBin >= timeNumBins) + timeTargetBin = timeNumBins; + countData[timeTargetBin][msgTargetBin][logData.entry] += 1.0; + } + break; + } + } + } catch(EndOfLogSuccess e) { + // successfully reached end of log file + } catch (Exception e) { + System.err.println("Exception" + e); + e.printStackTrace(); + System.exit(-1); + } + + try { + reader.close(); + } catch (IOException e) { + System.err.println("Error: could not close log file reader for processor " + pe ); + } + + return countData; + } +} diff --git a/src/projections/Tools/UserStatsOverTime/UserStatsTimeWindow.java b/src/projections/Tools/UserStatsOverTime/UserStatsTimeWindow.java index 8f641ccd..805b1531 100644 --- a/src/projections/Tools/UserStatsOverTime/UserStatsTimeWindow.java +++ b/src/projections/Tools/UserStatsOverTime/UserStatsTimeWindow.java @@ -11,6 +11,7 @@ import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.BorderLayout; +import java.io.File; import java.text.DecimalFormat; import java.util.*; import java.io.IOException; @@ -25,6 +26,7 @@ import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.JTable; +import javax.swing.JFileChooser; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; @@ -95,6 +97,7 @@ public class UserStatsTimeWindow extends ProjectionsWindow plot. XYSeriesCollection is necessary because we can change Y Axis on the XYSeriesCollection level, but not on the XYSeries level */ private List graphedData; + private List seriesName; private List globalSum; private List maxValue; private List minValue; @@ -106,6 +109,7 @@ public class UserStatsTimeWindow extends ProjectionsWindow private List statInfo; private final String[] columnNames = { + "Series Name", "Stat Name", "PEs", "Average Value", @@ -140,6 +144,7 @@ public UserStatsTimeWindow(MainWindow mainWindow) { numColumns = columnNames.length; //Initialize global vectors to hold overall data + seriesName = new ArrayList(); globalSum = new ArrayList(); maxValue = new ArrayList(); minValue = new ArrayList(); @@ -289,6 +294,7 @@ public Vector getResultsTable(){ } Vector row = new Vector(); + row.add("" + seriesName.get(curRow)); row.add(new String("" +statNames[curStat] )); row.add(pes); row.add(new String("" + globalSum.get(curRow)/ numCalls.get(curRow) )); @@ -359,22 +365,17 @@ private boolean getData() { double max= 0; double min=0; int nCalls=0; + seriesName.add(statDialog.getSeriesName()); + String currSeriesName = statDialog.getSeriesName(); //Get User choices String xType = statDialog.getXValue(); String xAgg = statDialog.getAggregate(); curStat = statDialog.getStatIndex(); - //Get name of series for Legend based off stat name and PE's used - String seriesName = statNames[curStat] + ": "; - for(Integer pe : processorList) { - if( pe.equals(processorList.last())) - seriesName+=pe.toString(); - else seriesName+=pe.toString() + ", "; - } - XYSeries data = new XYSeries(seriesName,true); - XYSeries dumpedData = new XYSeries(seriesName, true); + XYSeries data = new XYSeries(currSeriesName,true); + XYSeries dumpedData = new XYSeries(currSeriesName, true); //Get full string to print out for dumping this line - statInfo.add(seriesName + " Aggregate: " + xAgg + " StartTime: " + startTime + " EndTime: " + endTime); + statInfo.add(currSeriesName + " Aggregate: " + xAgg + " StartTime: " + startTime + " EndTime: " + endTime); int numPes = 0; //Loop through every PE @@ -501,6 +502,23 @@ else if (logData.stat>max) //Dump all current graph data into .dat files public void dumpData() { + + String currDir; + JFileChooser fc = new JFileChooser(); + fc.setCurrentDirectory(new File(".")); + fc.setDialogTitle("Choose destination folder"); + fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + fc.setAcceptAllFileFilterUsed(false); + + if(fc.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) { + if(fc.getSelectedFile().isDirectory()) + currDir = fc.getSelectedFile().getAbsolutePath(); + else + currDir = fc.getCurrentDirectory().getAbsolutePath(); + } else { + return; + } + int lineIdx = 0; //Loop through every plot, and create a file for it. for (XYSeriesCollection curLine : graphedData) { @@ -510,7 +528,7 @@ public void dumpData() { double[][] curTimes = dumpedTimes.get(lineIdx).toArray(); FileOutputStream out; try { - out = new FileOutputStream("./line" + lineIdx + ".dat"); + out = new FileOutputStream(currDir + "/" + seriesName.get(lineIdx) + ".dat"); } catch (FileNotFoundException e) { System.err.println("Error opening file for line " + lineIdx); continue; diff --git a/src/projections/Tools/UserStatsPerPE/UserStatsProcWindow.java b/src/projections/Tools/UserStatsPerPE/UserStatsProcWindow.java index 19165b1a..befb2c79 100644 --- a/src/projections/Tools/UserStatsPerPE/UserStatsProcWindow.java +++ b/src/projections/Tools/UserStatsPerPE/UserStatsProcWindow.java @@ -2,7 +2,6 @@ import java.awt.Checkbox; import java.awt.CheckboxGroup; -import java.awt.Component; import java.awt.Cursor; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; @@ -11,98 +10,101 @@ import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; -import java.text.DecimalFormat; -import java.util.LinkedList; import java.util.SortedSet; import java.util.TreeSet; import java.io.IOException; import javax.swing.JButton; -import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.SwingWorker; import projections.gui.GenericGraphColorer; import projections.gui.GenericGraphWindow; -import projections.gui.IntervalChooserPanel; import projections.gui.MainWindow; import projections.gui.RangeDialog; -import projections.gui.U; import projections.gui.Util; import projections.gui.ColorManager; +import projections.gui.EntryMethodVisibility; +import projections.gui.ChooseUserEntriesWindow; import projections.misc.LogEntryData; import projections.analysis.ProjDefs; import projections.analysis.GenericLogReader; import projections.analysis.EndOfLogSuccess; -import projections.analysis.TimedProgressThreadExecutor; /* UserStats Per PE Tool by Joshua lew 7/6/16. This tool plots every User Stat on a bar graph. Each X tick is a different PE. The Popups provide additional info about each stat on each PE. The Use can choose whether to plot max, min, avg */ public class UserStatsProcWindow extends GenericGraphWindow -implements ItemListener, ActionListener +implements ItemListener, ActionListener, EntryMethodVisibility { - // Temporary hardcode. This variable will be assigned appropriate // meaning in future versions of Projections that support multiple // runs. private static int myRun = 0; // Sent External code commented out and may be implemented later - private UserStatsProcWindow thisWindow; - // private EntrySelectionDialog entryDialog; - - private JPanel mainPanel; - private IntervalChooserPanel intervalPanel; - - private JPanel graphPanel; - private JPanel controlPanel; - - private JButton setRanges; - // private JButton epSelection; - - private SortedSet processorList; + private String[] statNames; + private double[][] avgValue; + private double[][] maxValue; + private double[][] minValue; + private double[][] sumValue; + private double[][] counts_display; + private boolean[] display_mask; + private int currOption; + private GenericGraphColorer colorer; - private String[] statNames; - private double[][] avgValue; - private double[][] maxValue; - private double[][] minValue; - private int[][] numCalls; - - private int numStats; - private int numPEs; - - // format for output - private DecimalFormat _format; + private int numStats; + private int numPEs; - private JPanel checkBoxPanel; + private JButton setRanges; private Checkbox avgValueBox; private Checkbox maxValueBox; private Checkbox minValueBox; + private Checkbox sumValueBox; public UserStatsProcWindow(MainWindow mainWindow) { super("User Stats over Time Graph - " + MainWindow.runObject[myRun].getFilename() + ".sts", mainWindow); - + thisWindow = this; // Read in information about User Stats numStats = MainWindow.runObject[myRun].getNumUserDefinedStats(); statNames = MainWindow.runObject[myRun].getUserStatNames(); - _format = new DecimalFormat("###,###.###"); + display_mask = new boolean[numStats]; + for(int i = 0; i < numStats; i++) + display_mask[i] = true; + currOption = 0; + colorer = new GenericGraphColorer() { + private final Paint[] colorMap = ColorManager.createColorMap(numStats); + @Override + public Paint[] getColorMap() { + return colorMap; + } + }; createMenus(); + if(mChooseColors.getActionListeners()[0] != null) + mChooseColors.removeActionListener(mChooseColors.getActionListeners()[0]); + mChooseColors.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + new ChooseUserEntriesWindow(thisWindow, thisWindow, colorer, MainWindow.runObject[myRun].getSts().getUserStatNameMap(), "Stat"); + } + }); createLayout(); pack(); - thisWindow = this; - showDialog(); } //Set initial layout of window private void createLayout() { + JPanel mainPanel; + JPanel graphPanel; + JPanel controlPanel; + JPanel checkBoxPanel; mainPanel = new JPanel(); getContentPane().add(mainPanel); @@ -122,9 +124,12 @@ private void createLayout() { maxValueBox.addItemListener(this); minValueBox = new Checkbox("Min Value", cbg, false); minValueBox.addItemListener(this); + sumValueBox = new Checkbox("Sum Value", cbg, false); + sumValueBox.addItemListener(this); Util.gblAdd(checkBoxPanel, avgValueBox, gbc, 0,0, 1,1, 1,1); Util.gblAdd(checkBoxPanel, maxValueBox, gbc, 1,0, 1,1, 1,1); Util.gblAdd(checkBoxPanel, minValueBox, gbc, 2,0, 1,1, 1,1); + Util.gblAdd(checkBoxPanel, sumValueBox, gbc, 3,0, 1,1, 1,1); // control panel items setRanges = new JButton("Select New Range"); @@ -132,21 +137,48 @@ private void createLayout() { controlPanel = new JPanel(); controlPanel.setLayout(gbl); - Util.gblAdd(controlPanel, setRanges, gbc, 0,0, 1,1, 0,0); + Util.gblAdd(controlPanel, setRanges, gbc, 0,0, 1,1, 0,0); graphPanel = getMainPanel(); - Util.gblAdd(mainPanel, graphPanel, gbc, 0,1, 1,1, 1,1); - Util.gblAdd(mainPanel, controlPanel, gbc, 0,3, 1,0, 0,0); + Util.gblAdd(mainPanel, graphPanel, gbc, 0,1, 1,1, 1,1); + Util.gblAdd(mainPanel, controlPanel, gbc, 0,3, 1,0, 0,0); - Util.gblAdd(mainPanel, checkBoxPanel, gbc, 0,2, 1,1, 0,0); + Util.gblAdd(mainPanel, checkBoxPanel, gbc, 0,2, 1,1, 0,0); } //Set graph data. protected void setGraphSpecificData(){ setXAxis("Processor",processorList ); setYAxis("value", ""); - setDataSource("User Stats", avgValue,new MyColorer(), this); - refreshGraph(); + setDataSource("User Stats", counts_display, colorer, this); + } + + private void calcDisplayData() { + double[][] currVals; + switch (currOption) { + default: + case 0: + currVals = avgValue; + break; + case 1: + currVals = maxValue; + break; + case 2: + currVals = minValue; + break; + case 3: + currVals = sumValue; + break; + } + + for(int i = 0; i < numPEs; i++) { + for(int j = 0; j < numStats; j++) { + if(display_mask[j]) + counts_display[i][j] = currVals[i][j]; + else + counts_display[i][j] = 0; + } + } } //Show dialog and read in data based off user choices @@ -159,19 +191,15 @@ public void showDialog() { if (!dialog.isCancelled()) { //Read in information from dialog processorList = new TreeSet(dialog.getSelectedProcessors()); - numPEs = 0; - for(Integer pe : processorList) - numPEs+=1; - + numPEs = processorList.size(); final SwingWorker worker = new SwingWorker() { public Object doInBackground() { - getData(dialog.getStartTime(),dialog.getEndTime()); + getData(dialog.getStartTime(), dialog.getEndTime()); return null; } public void done() { - setGraphSpecificData(); + displayMustBeRedrawn(); thisWindow.setVisible(true); - thisWindow.repaint(); } }; worker.execute(); @@ -186,7 +214,9 @@ private void getData(long startTime, long endTime) { avgValue = new double[numPEs][numStats]; maxValue = new double[numPEs][numStats]; minValue = new double[numPEs][numStats]; - numCalls = new int[numPEs][numStats]; + sumValue = new double[numPEs][numStats]; + counts_display = new double[numPEs][numStats]; + int[][] numCalls = new int[numPEs][numStats]; int peIdx = 0; for(Integer pe : processorList) { @@ -207,7 +237,7 @@ private void getData(long startTime, long endTime) { //Read in index of stat in current LogEntry statIndex = MainWindow.runObject[myRun].getUserDefinedStatIndex(logData.userEventID); //Store the data accordingly - avgValue[peIdx][statIndex] += logData.stat; + sumValue[peIdx][statIndex] += logData.stat; //keeps track of how many times this specific stat was updated on this specific PE numCalls[peIdx][statIndex]+=1; //Set min and max accordingly. @@ -243,12 +273,12 @@ else if (logData.stat>maxValue[peIdx][statIndex]) } - /*To make avgValue, we must divide each element, which currently holds its sum, + /*To make avgValue, we must divide each element of sumValue, which currently holds its sum, by the number of times it was called to get an avg value*/ for(int i = 0; i tabledata; - List columnNames; - - public MyTableModel(List TD, List CN, EntryMethodVisibility data_, boolean checkboxesVisible) { - tabledata=TD; - columnNames=CN; - data = data_; - if (data!=null) - data.displayMustBeRedrawn(); - displayVisibilityCheckboxes = checkboxesVisible; - } - - public boolean isCellEditable(int row, int col) { - if (displayVisibilityCheckboxes && (col == 0 || col == 3)) { - return true; - } else if (col == 2) { - return true; - } else { - return false; - } - } - - public int getColumnCount() { - if (displayVisibilityCheckboxes) - return 4; - else - return 3; - } - - public Class getColumnClass(int c) { - return getValueAt(0, c).getClass(); - } - - public int getRowCount() { - return tabledata.size(); - } - - public Object getValueAt(int rowIndex, int columnIndex) { - return tabledata.get(rowIndex).get(columnIndex); - } - - public String getColumnName(int col) { - return columnNames.get(col); - } - - public void setValueAt(Object value, int row, int col) { - if(col==0 && displayVisibilityCheckboxes){ - Boolean newValue = (Boolean) value; - Integer id = (Integer) tabledata.get(row).get(2); - - if(newValue){ - // remove from list of disabled entry methods - data.makeEntryVisibleID(id); - } else { - // add to list of disabled entry methods - data.makeEntryInvisibleID(id); - } - data.displayMustBeRedrawn(); - } else { -// System.out.println("setValueAt col = " + col); - } - - tabledata.get(row).set(col,value); - fireTableCellUpdated(row, col); - } - - public void actionPerformed(ActionEvent e) { - System.out.println("Action for object: " + e.getSource()); - fireTableDataChanged(); - data.displayMustBeRedrawn(); - } -} diff --git a/src/projections/gui/ChooseUserEntriesWindow.java b/src/projections/gui/ChooseUserEntriesWindow.java new file mode 100644 index 00000000..a43d7332 --- /dev/null +++ b/src/projections/gui/ChooseUserEntriesWindow.java @@ -0,0 +1,161 @@ +package projections.gui; + +import javax.swing.JFrame; +import javax.swing.JTable; +import javax.swing.JScrollPane; +import javax.swing.JPanel; +import javax.swing.JButton; +import javax.swing.table.TableColumn; + +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class ChooseUserEntriesWindow extends JFrame { + + private int myRun = 0; + + private ColorUpdateNotifier gw; + private EntryMethodVisibility data; + private List tabledata; + private Map entryNames; + private GenericGraphColorer colorer; + private String[] eventNames; + private String option; + + public ChooseUserEntriesWindow(EntryMethodVisibility data, ColorUpdateNotifier gw, GenericGraphColorer colorer, Map entryNames, String option) { + this.data = data; + this.gw = gw; + this.colorer = colorer; + this.entryNames = entryNames; + this.eventNames = null; + this.option = option; + createLayout(); + } + + ChooseUserEntriesWindow(EntryMethodVisibility data, ColorUpdateNotifier gw, GenericGraphColorer colorer, Map entryNames, String option, String[] eventNames) { + this.data = data; + this.gw = gw; + this.colorer = colorer; + this.entryNames = entryNames; + this.eventNames = eventNames; + this.option = option; + createLayout(); + } + + private void createLayout() { + setTitle("Choose which User " + option + "s are displayed"); + List columnNames = new ArrayList(4); + columnNames.add("Visible"); + columnNames.add("User " + option + " Name"); + columnNames.add("ID"); + columnNames.add("Color"); + + tabledata = new ArrayList(); + + makeTableData(); + + final MyTableModel tableModel = new MyTableModel(tabledata, columnNames, data, true); + + JTable table = new JTable(tableModel); + initColumnSizes(table); + + table.setDefaultRenderer(ClickableColorBox.class, new ColorRenderer()); + table.setDefaultEditor(ClickableColorBox.class, new ColorEditor()); + + JScrollPane scroller = new JScrollPane(table); + scroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + + JPanel p = new JPanel(); + p.setLayout(new BorderLayout()); + + JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new FlowLayout()); + JButton checkAll = new JButton("Make All Visible"); + checkAll.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + changeVisibility(true, tableModel); + tableModel.fireTableDataChanged(); + data.displayMustBeRedrawn(); + } + }); + JButton uncheckAll = new JButton("Hide All"); + uncheckAll.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + changeVisibility(false, tableModel); + tableModel.fireTableDataChanged(); + data.displayMustBeRedrawn(); + } + }); + buttonPanel.add(checkAll); + buttonPanel.add(uncheckAll); + p.add(buttonPanel, BorderLayout.NORTH); + p.add(scroller, BorderLayout.CENTER); + this.setContentPane(p); + + pack(); + setSize(800, 400); + setVisible(true); + } + + private void makeTableData() { + tabledata.clear(); + for(Integer id : entryNames.keySet()) { + int currIndex = id; + if(eventNames != null) { + String currName = entryNames.get(id); + for (int i = 0; i < eventNames.length; i++) { + if (currName.equals(eventNames[i])) { + currIndex = i; + break; + } + } + } + List tableRow = new ArrayList(4); + tableRow.add(data.entryIsVisibleID(currIndex)); + if(eventNames != null) + tableRow.add(eventNames[currIndex]); + else + tableRow.add(entryNames.get(currIndex)); + tableRow.add(currIndex); + tableRow.add(new ClickableColorBox(currIndex, (Color)colorer.getColorMap()[currIndex], myRun, gw, colorer)); + tabledata.add(tableRow); + } + } + + private void initColumnSizes(JTable table) { + TableColumn column; + + column = table.getColumnModel().getColumn(0); + column.setPreferredWidth(70); + + column = table.getColumnModel().getColumn(1); + column.setPreferredWidth(680); + + column = table.getColumnModel().getColumn(2); + column.setPreferredWidth(50); + } + + private void changeVisibility(boolean visible, MyTableModel tableModel) { + for(List v : tabledata) { + Integer id = (Integer) v.get(2); + if (visible) + data.makeEntryVisibleID(id); + else + data.makeEntryInvisibleID(id); + } + for (List v : tabledata) { + v.set(0,visible); + } + tableModel.fireTableDataChanged(); + data.displayMustBeRedrawn(); + } +} diff --git a/src/projections/gui/ClickableColorBox.java b/src/projections/gui/ClickableColorBox.java new file mode 100644 index 00000000..439bbfcf --- /dev/null +++ b/src/projections/gui/ClickableColorBox.java @@ -0,0 +1,37 @@ +package projections.gui; + +import java.awt.Color; + +public class ClickableColorBox { + public int myRun; + Color c; + + private ColorUpdateNotifier gw; + private int id; + private GenericGraphColorer colorer; + + ClickableColorBox(int id_, Color c_, int myRun_, ColorUpdateNotifier gw_) { + id = id_; + c = c_; + myRun = myRun_; + gw=gw_; + colorer = null; + } + + ClickableColorBox(int id_, Color c_, int myRun_, ColorUpdateNotifier gw_, GenericGraphColorer colorer_) { + id = id_; + c = c_; + myRun = myRun_; + gw=gw_; + colorer = colorer_; + } + + public void setColor(Color c){ + this.c = c; + if(colorer != null) + colorer.getColorMap()[id] = c; + else + MainWindow.runObject[myRun].setEntryColor(id, c); + gw.colorsHaveChanged(); + } +} diff --git a/src/projections/gui/MainMenuManager.java b/src/projections/gui/MainMenuManager.java index fbae0426..980c8a67 100644 --- a/src/projections/gui/MainMenuManager.java +++ b/src/projections/gui/MainMenuManager.java @@ -12,6 +12,7 @@ import javax.swing.JMenuBar; import javax.swing.JMenuItem; +import projections.Tools.MessageSizeEvolution.MessageSizeEvolutionWindow; import projections.Tools.PerformanceCounters.PerfWindow; import projections.Tools.TopologyDisplay.TopologyDisplayWindow; import projections.Tools.CommunicationOverTime.CommTimeWindow; @@ -22,10 +23,10 @@ import projections.Tools.MemoryUsage.MemoryUsageWindow; import projections.Tools.NoiseMiner.NoiseMinerWindow; import projections.Tools.Overview.OverviewWindow; +import projections.Tools.EntryMethodProfile.MethodProfileWindow; import projections.Tools.Streaming.StreamingTool; import projections.Tools.TimeProfile.TimeProfileWindow; import projections.Tools.Timeline.TimelineWindow; -import projections.Tools.TimelineRendered.TimelineRenderedWindow; import projections.Tools.UserStatsOverTime.UserStatsTimeWindow; import projections.Tools.UserStatsPerPE.UserStatsProcWindow; import projections.analysis.ProjMain; @@ -96,6 +97,8 @@ class MainMenuManager private JMenuItem streamingMenuItem; private JMenuItem memoryUsageMenuItem; private JMenuItem topologyDisplayMenuItem; + private JMenuItem methodProfileMenuItem; + private JMenuItem messageSizeEvolutionMenuItem; private JCheckBoxMenuItem perfLogMenuItem; @@ -135,6 +138,8 @@ private void stateChanged(int state, int sumDetail) { noiseMinerMenuItem.setEnabled(false); memoryUsageMenuItem.setEnabled(false); topologyDisplayMenuItem.setEnabled(true); + methodProfileMenuItem.setEnabled(false); + messageSizeEvolutionMenuItem.setEnabled(false); break; case OPENED_SUMMARY: @@ -169,6 +174,8 @@ private void stateChanged(int state, int sumDetail) { noiseMinerMenuItem.setEnabled(true); memoryUsageMenuItem.setEnabled(true); topologyDisplayMenuItem.setEnabled(true); + methodProfileMenuItem.setEnabled(false); + messageSizeEvolutionMenuItem.setEnabled(false); break; case OPENED_FILES : @@ -211,6 +218,8 @@ private void stateChanged(int state, int sumDetail) { noiseMinerMenuItem.setEnabled(true); memoryUsageMenuItem.setEnabled(true); topologyDisplayMenuItem.setEnabled(true); + methodProfileMenuItem.setEnabled(true); + messageSizeEvolutionMenuItem.setEnabled(true); break; } @@ -270,6 +279,8 @@ private void createMenus() { streamingMenuItem = new JMenuItem("Streaming CCS"); memoryUsageMenuItem = new JMenuItem("Memory Usage"); topologyDisplayMenuItem = new JMenuItem("Topology Display"); + methodProfileMenuItem = new JMenuItem("Entry Method Profile"); + messageSizeEvolutionMenuItem = new JMenuItem("Message Size Evolution"); timelinesMenuItem.addActionListener(this); //renderedTimelinesMenuItem.addActionListener(this); @@ -294,6 +305,8 @@ private void createMenus() { streamingMenuItem.addActionListener(this); memoryUsageMenuItem.addActionListener(this); topologyDisplayMenuItem.addActionListener(this); + methodProfileMenuItem.addActionListener(this); + messageSizeEvolutionMenuItem.addActionListener(this); toolMenu.add(timelinesMenuItem); //toolMenu.add(renderedTimelinesMenuItem); @@ -318,6 +331,8 @@ private void createMenus() { toolMenu.add(streamingMenuItem); toolMenu.add(memoryUsageMenuItem); toolMenu.add(topologyDisplayMenuItem); + toolMenu.add(methodProfileMenuItem); + toolMenu.add(messageSizeEvolutionMenuItem); menubar.add(toolMenu); @@ -437,6 +452,12 @@ else if (mi == streamingMenuItem) else if (mi == topologyDisplayMenuItem) parent.openTool(new TopologyDisplayWindow(parent) ); + + else if (mi == methodProfileMenuItem) + parent.openTool(new MethodProfileWindow(parent) ); + + else if(mi == messageSizeEvolutionMenuItem) + parent.openTool(new MessageSizeEvolutionWindow(parent)); else System.out.println("ERROR: unknown menu item was selected" + mi); diff --git a/src/projections/gui/MyTableModel.java b/src/projections/gui/MyTableModel.java new file mode 100644 index 00000000..7a14004d --- /dev/null +++ b/src/projections/gui/MyTableModel.java @@ -0,0 +1,74 @@ +package projections.gui; + +import javax.swing.table.AbstractTableModel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +public class MyTableModel extends AbstractTableModel implements ActionListener { + EntryMethodVisibility data; + + private boolean displayVisibilityCheckboxes; + private List tabledata; + private List columnNames; + + MyTableModel(List TD, List CN, EntryMethodVisibility data_, boolean checkboxesVisible) { + tabledata=TD; + columnNames=CN; + data = data_; + if (data!=null) + data.displayMustBeRedrawn(); + displayVisibilityCheckboxes = checkboxesVisible; + } + + public boolean isCellEditable(int row, int col) { + return ((displayVisibilityCheckboxes && (col == 0 || col == 3)) || col == 2); + } + + public int getColumnCount() { + if (displayVisibilityCheckboxes) + return 4; + else + return 3; + } + + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + + public int getRowCount() { + return tabledata.size(); + } + + public Object getValueAt(int rowIndex, int columnIndex) { + return tabledata.get(rowIndex).get(columnIndex); + } + + public String getColumnName(int col) { + return columnNames.get(col); + } + + public void setValueAt(Object value, int row, int col) { + if(col==0 && displayVisibilityCheckboxes){ + Boolean newValue = (Boolean) value; + Integer id = (Integer) tabledata.get(row).get(2); + if(newValue){ + // remove from list of disabled entry methods + data.makeEntryVisibleID(id); + } else { + // add to list of disabled entry methods + data.makeEntryInvisibleID(id); + } + data.displayMustBeRedrawn(); + } + + tabledata.get(row).set(col,value); + fireTableCellUpdated(row, col); + } + + public void actionPerformed(ActionEvent e) { + System.out.println("Action for object: " + e.getSource()); + fireTableDataChanged(); + data.displayMustBeRedrawn(); + } +} \ No newline at end of file diff --git a/src/projections/gui/StatDialog.java b/src/projections/gui/StatDialog.java index 6470fb5a..fd2dfb38 100644 --- a/src/projections/gui/StatDialog.java +++ b/src/projections/gui/StatDialog.java @@ -33,6 +33,7 @@ import javax.swing.JProgressBar; import javax.swing.SwingWorker; import javax.swing.JOptionPane; +import javax.swing.JTextField; /* Stat Dialog created by Joshua Lew 7/5/16 @@ -45,6 +46,7 @@ Which X values to use (Wall Timer, Ordered, User Specified) Color Lines/Points/Both Which Stat to plot + Series name This Dialog is specialized for the UserStatOverTime tool and would require a little work to use with other tools @@ -74,6 +76,7 @@ public final class StatDialog extends JDialog private JSelectField processorsField; private TimeTextField startTimeField; private TimeTextField endTimeField; + private JTextField seriesNameField; private JPanel timePanel, processorsPanel,statPanel; private JButton bOK, bCancel; @@ -121,6 +124,7 @@ public void someInputChanged() { if(isInputValid()){ // System.out.println("Input is valid"); totalTimeLabel.setText(U.humanReadableString(getSelectedTotalTime())); + bOK.setEnabled(true); } else { // System.out.println("Input is NOT valid"); @@ -227,6 +231,16 @@ private JPanel createMainLayout() { gbc.fill = GridBagConstraints.BOTH; gbc.insets = new Insets(2, 2, 2, 2); + JPanel seriesPanel = new JPanel(); + seriesPanel.setLayout(gbl); + JLabel seriesNameLabel = new JLabel("Series Name :", JLabel.LEFT); + seriesNameField = new JTextField("", 12); + seriesNameField.addActionListener(this); + seriesNameField.addKeyListener(this); + seriesNameField.addFocusListener(this); + Util.gblAdd(seriesPanel, seriesNameLabel, gbc, 0, 0, 1, 1, 1, 1); + Util.gblAdd(seriesPanel, seriesNameField, gbc, 1, 0, 3, 1, 1, 1); + // Default processor range layout processorsPanel = new JPanel(); processorsPanel.setLayout(gbl); @@ -355,12 +369,14 @@ private JPanel createMainLayout() { // general layout inputPanel.setLayout(gbl); - Util.gblAdd(inputPanel, processorsPanel, + Util.gblAdd(inputPanel, seriesPanel, gbc, 0,0, 1,1, 1,1); - Util.gblAdd(inputPanel, timePanel, + Util.gblAdd(inputPanel, processorsPanel, gbc, 0,1, 1,1, 1,1); - Util.gblAdd(inputPanel, statPanel, + Util.gblAdd(inputPanel, timePanel, gbc, 0,2, 1,1, 1,1); + Util.gblAdd(inputPanel, statPanel, + gbc, 0,3, 1,1, 1,1); return inputPanel; } @@ -390,6 +406,11 @@ private JPanel createButtonLayout() { /** Check for validity of the input fields in this dialog box and any contained tool-specific Jpanel */ private boolean isInputValid(){ + if(seriesNameField.getText().trim().equals("")) { + seriesNameField.setForeground(Color.red); + return false; + } + // start time cannot be greater or equal to end time if (getStartTime() >= getEndTime()) { startTextLabel.setForeground(Color.red); @@ -425,6 +446,7 @@ private boolean isInputValid(){ endTimeField.setForeground(Color.black); processorTextLabel.setForeground(Color.black); processorsField.setForeground(Color.black); + seriesNameField.setForeground(Color.black); return true; @@ -439,6 +461,9 @@ public boolean isCancelled() { return (dialogState == DIALOG_CANCELLED); } + public String getSeriesName() { + return seriesNameField.getText(); + } public long getStartTime() { return startTimeField.getValue(); diff --git a/src/projections/gui/UserEventsWindow.java b/src/projections/gui/UserEventsWindow.java index f5e733d0..bde5a514 100644 --- a/src/projections/gui/UserEventsWindow.java +++ b/src/projections/gui/UserEventsWindow.java @@ -1,14 +1,13 @@ package projections.gui; +import java.awt.Paint; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; -import java.awt.Paint; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.util.SortedSet; -import javax.swing.JButton; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.ProgressMonitor; @@ -27,221 +26,271 @@ * Legends are in place (and probably replace the name) */ class UserEventsWindow extends GenericGraphWindow - implements ActionListener + implements ActionListener, EntryMethodVisibility { private UserEventsWindow thisWindow; - // Temporary hardcode. This variable will be assigned appropriate - // meaning in future versions of Projections that support multiple - // runs. - private static int myRun = 0; - - private JPanel mainPanel; - private JPanel controlPanel; + // Temporary hardcode. This variable will be assigned appropriate + // meaning in future versions of Projections that support multiple + // runs. + private static int myRun = 0; - private IntervalChooserPanel intervalPanel; + private IntervalChooserPanel intervalPanel; // data used for intervalgraphdialog - private int startInterval; - private int endInterval; - private long intervalSize; - private SortedSet processorList; - - // meta data variables - private int numActivities; - // Normally derived from MainWindow.runObject[myRun].java - private String activityNames[]; - - // stored raw data - private double[][] graphData; - private long[][] numCalls; + private int startInterval; + private int endInterval; + private long intervalSize; + private SortedSet processorList; + + // meta data variables + private int numActivities; + private int numPEs; + // Normally derived from MainWindow.runObject[myRun].java + private String activityNames[]; + + // stored raw data + private double[][] graphData; + private double[][] graphData_display; + private long[][] numCalls; + private boolean[] display_mask; + private GenericGraphColorer colorer; - protected UserEventsWindow(MainWindow mainWindow) { - super("Projections User Events Tool - " + - MainWindow.runObject[myRun].getFilename() + ".sts", mainWindow); - // hardcode start. Usually derived from MainWindow.runObject[myRun].java - numActivities = MainWindow.runObject[myRun].getNumUserDefinedEvents(); - activityNames = MainWindow.runObject[myRun].getUserEventNames(); - // Normally would set activity names here. - - createMenus(); - createLayout(); - pack(); - thisWindow = this; - showDialog(); - } - - private void createLayout() { - mainPanel = new JPanel(); - getContentPane().add(mainPanel); - - GridBagConstraints gbc = new GridBagConstraints(); - GridBagLayout gbl = new GridBagLayout(); + UserEventsWindow(MainWindow mainWindow) { + super("Projections User Events Tool - " + + MainWindow.runObject[myRun].getFilename() + ".sts", mainWindow); + thisWindow = this; + // hardcode start. Usually derived from MainWindow.runObject[myRun].java + numActivities = MainWindow.runObject[myRun].getNumUserDefinedEvents(); + activityNames = MainWindow.runObject[myRun].getUserEventNames(); + display_mask = new boolean[numActivities]; + for(int i = 0; i < numActivities; i++) + display_mask[i] = true; + colorer = new GenericGraphColorer() { + private final Paint[] colorMap = ColorManager.createColorMap(numActivities); + @Override + public Paint[] getColorMap() { + return colorMap; + } + }; + createMenus(); + if(mChooseColors.getActionListeners()[0] != null) + mChooseColors.removeActionListener(mChooseColors.getActionListeners()[0]); + mChooseColors.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + new ChooseUserEntriesWindow(thisWindow, thisWindow, colorer, MainWindow.runObject[myRun].getSts().getUserEventNameMap(), "Event", activityNames); + } + }); + createLayout(); + pack(); + showDialog(); + } + + private void createLayout() { + JPanel mainPanel; + JPanel controlPanel; + + mainPanel = new JPanel(); + getContentPane().add(mainPanel); + + GridBagConstraints gbc = new GridBagConstraints(); + GridBagLayout gbl = new GridBagLayout(); - gbc.fill = GridBagConstraints.BOTH; - mainPanel.setLayout(gbl); - - // Assume no special control features for now - controlPanel = new JPanel(); - controlPanel.setLayout(gbl); - - JPanel graphPanel = getMainPanel(); - Util.gblAdd(mainPanel, graphPanel, gbc, 0,0, 1,1, 1,1); - Util.gblAdd(mainPanel, controlPanel, gbc, 0,1, 1,0, 0,0); - } - -// protected void createMenus(){ -// super.createMenus(); -// } - - public void showDialog() { - if (dialog == null) { - intervalPanel = new IntervalChooserPanel(); - dialog = new RangeDialog(this, "Select Range", intervalPanel, false); - } - - dialog.displayDialog(); - if (!dialog.isCancelled()){ - intervalSize = intervalPanel.getIntervalSize(); - startInterval = (int)intervalPanel.getStartInterval(); - endInterval = (int)intervalPanel.getEndInterval(); - processorList = dialog.getSelectedProcessors(); - final SwingWorker worker = new SwingWorker() { - public Object doInBackground() { - if (true) { - // Long non-gui (except progress) code here. - constructToolData(); - } - return null; - } - public void done() { - // GUI code after Long non-gui code (above) is done. - setGraphSpecificData(); - thisWindow.setVisible(true); - } - }; - worker.execute(); - } - } - - private void constructToolData() { - int count = 0; - ProgressMonitor progressBar = - new ProgressMonitor(MainWindow.runObject[myRun].guiRoot, - "Reading log files", - "", 0, - processorList.size()); - progressBar.setNote("Reading"); - progressBar.setProgress(0); - graphData = new double[processorList.size()][]; - numCalls = new long[processorList.size()][]; - - for(Integer pe : processorList) { - progressBar.setProgress(count); - progressBar.setNote("[PE: " + pe + " ] Reading Data."); - if (progressBar.isCanceled()) { - return; + gbc.fill = GridBagConstraints.BOTH; + mainPanel.setLayout(gbl); + + // Assume no special control features for now + controlPanel = new JPanel(); + controlPanel.setLayout(gbl); + + JPanel graphPanel = getMainPanel(); + Util.gblAdd(mainPanel, graphPanel, gbc, 0,0, 1,1, 1,1); + Util.gblAdd(mainPanel, controlPanel, gbc, 0,1, 1,0, 0,0); + } + + public void showDialog() { + if (dialog == null) { + intervalPanel = new IntervalChooserPanel(); + dialog = new RangeDialog(this, "Select Range", intervalPanel, false); } - // process data here. - graphData[count] = new double[numActivities]; - numCalls[count] = new long[numActivities]; - - // READ - nothing here - GenericLogReader reader = new GenericLogReader( pe, - MainWindow.runObject[myRun].getVersion()); - LogEntryData logData; - LogEntryData logDataEnd; - - // Skip to the first begin. - try { - logData = reader.nextEventOfType(ProjDefs.USER_EVENT_PAIR); - logDataEnd = reader.nextEventOfType(ProjDefs.USER_EVENT_PAIR); - - while (logData.time < startInterval*intervalSize) { - logData = reader.nextEventOfType(ProjDefs.USER_EVENT_PAIR); - logDataEnd = reader.nextEventOfType(ProjDefs.USER_EVENT_PAIR); + + dialog.displayDialog(); + if (!dialog.isCancelled()){ + intervalSize = intervalPanel.getIntervalSize(); + startInterval = (int)intervalPanel.getStartInterval(); + endInterval = (int)intervalPanel.getEndInterval(); + processorList = dialog.getSelectedProcessors(); + numPEs = processorList.size(); + graphData = new double[numPEs][]; + graphData_display = new double[numPEs][]; + numCalls = new long[numPEs][]; + for(int i = 0; i < numPEs; i++) { + graphData[i] = new double[numActivities]; + graphData_display[i] = new double[numActivities]; + numCalls[i] = new long[numActivities]; } - int eventIndex = 0; - while (true) { - // process pair read previously - eventIndex = MainWindow.runObject[myRun].getUserDefinedEventIndex(logData.userEventID); - graphData[count][eventIndex] += - logDataEnd.time - logData.time; - numCalls[count][eventIndex]++; + final SwingWorker worker = new SwingWorker() { + public Object doInBackground() { + constructToolData(); + return null; + } + public void done() { + displayMustBeRedrawn(); + thisWindow.setVisible(true); + } + }; + worker.execute(); + } + } + + private void constructToolData() { + int count = 0; + ProgressMonitor progressBar = + new ProgressMonitor(MainWindow.runObject[myRun].guiRoot, + "Reading log files", + "", 0, + processorList.size()); + progressBar.setNote("Reading"); + progressBar.setProgress(0); + + for(Integer pe : processorList) { + progressBar.setProgress(count); + progressBar.setNote("[PE: " + pe + " ] Reading Data."); + if (progressBar.isCanceled()) { + return; + } + + // READ - nothing here + GenericLogReader reader = new GenericLogReader( pe, + MainWindow.runObject[myRun].getVersion()); + LogEntryData logData; + LogEntryData logDataEnd; + + // Skip to the first begin. + try { logData = reader.nextEventOfType(ProjDefs.USER_EVENT_PAIR); logDataEnd = reader.nextEventOfType(ProjDefs.USER_EVENT_PAIR); - if (logDataEnd.time > endInterval*intervalSize) { - break; + + while (logData.time < startInterval*intervalSize) { + logData = reader.nextEventOfType(ProjDefs.USER_EVENT_PAIR); + logDataEnd = reader.nextEventOfType(ProjDefs.USER_EVENT_PAIR); + } + int eventIndex; + while (true) { + // process pair read previously + eventIndex = MainWindow.runObject[myRun].getUserDefinedEventIndex(logData.userEventID); + graphData[count][eventIndex] += + logDataEnd.time - logData.time; + numCalls[count][eventIndex]++; + logData = reader.nextEventOfType(ProjDefs.USER_EVENT_PAIR); + logDataEnd = reader.nextEventOfType(ProjDefs.USER_EVENT_PAIR); + if (logDataEnd.time > endInterval*intervalSize) { + break; + } } + }catch (EndOfLogSuccess e) { + // do nothing + } catch (IOException e) { + System.out.println("Exception while reading log file " + pe); } - }catch (EndOfLogSuccess e) { - // do nothing - } catch (IOException e) { - System.out.println("Exception while reading log file " + pe); - } - try { - reader.close(); - } catch (IOException e1) { - System.err.println("Error: could not close log file reader for processor " + pe ); + try { + reader.close(); + } catch (IOException e1) { + System.err.println("Error: could not close log file reader for processor " + pe ); + } + + + count++; } + progressBar.close(); + } + + protected void setGraphSpecificData() { + setXAxis("Processors", processorList); + setYAxis("Time (us)", "us"); + setDataSource("User Events", graphData_display, colorer, this); + } + private void calcDisplayData() { + for(int i = 0; i < numPEs; i++) { + for(int j = 0; j < numActivities; j++) { + if(display_mask[j]) + graphData_display[i][j] = graphData[i][j]; + else + graphData_display[i][j] = 0; + } + } + } - count++; + public String[] getPopup(int xVal, int yVal) { + if ((xVal < 0) || (yVal < 0)) { + return null; + } + String[] rString = new String[3]; + + rString[0] = "Name: " + activityNames[yVal]; + rString[1] = "Time Spent: " + U.humanReadableString((long)(graphData[xVal][yVal])); + rString[2] = "Count: " + numCalls[xVal][yVal]; + return rString; } - progressBar.close(); - } - - - - - - /** A class that provides the colors for the display */ - public class UserEventColorer implements GenericGraphColorer { - public Paint[] getColorMap() { - int numUserEvents = MainWindow.runObject[myRun].getNumUserDefinedEvents(); - Paint[] outColors = ColorManager.createColorMap(numUserEvents); - return outColors; + public void actionPerformed(ActionEvent e) { + if (e.getSource() instanceof JMenuItem) { + String arg = ((JMenuItem)e.getSource()).getText(); + if (arg.equals("Close")) { + close(); + } else if(arg.equals("Set Range")) { + showDialog(); + } } } - - - - - protected void setGraphSpecificData() { - setXAxis("Processors", processorList); - setYAxis("Time (us)", "us"); - setDataSource("User Events", graphData, new UserEventColorer() , this); - refreshGraph(); - } - - - public String[] getPopup(int xVal, int yVal) { - if ((xVal < 0) || (yVal < 0)) { - return null; + public void refreshGraph() { + super.refreshGraph(); + } + + protected void createMenus() { + super.createMenus(); + } + + @Override + public void displayMustBeRedrawn() { + calcDisplayData(); + setGraphSpecificData(); + refreshGraph(); + } + + @Override + public boolean entryIsVisibleID(Integer id) { + return true; + } + + @Override + public int[] getEntriesArray() { + return null; + } + + @Override + public void makeEntryInvisibleID(Integer id) { + display_mask[id] = false; + } + + @Override + public void makeEntryVisibleID(Integer id) { + display_mask[id] = true; + } + + @Override + public boolean hasEntryList() { + return false; + } + + @Override + public boolean handleIdleOverhead() { + return false; } - String[] rString = new String[3]; - - rString[0] = "Name: " + activityNames[yVal]; - rString[1] = "Time Spent: " + U.humanReadableString((long)(graphData[xVal][yVal])); - rString[2] = "Count: " + numCalls[xVal][yVal]; - return rString; - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource() instanceof JButton) { -// JButton b = (JButton)e.getSource(); - } else if (e.getSource() instanceof JMenuItem) { - String arg = ((JMenuItem)e.getSource()).getText(); - if (arg.equals("Close")) { - close(); - } else if(arg.equals("Set Range")) { - showDialog(); - } - } - } }