Skip to content

Fix bugs in User Events, User Stats Per Process and User Stats Over Time views #59

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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<Integer> {
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]);
}
}
247 changes: 247 additions & 0 deletions src/projections/Tools/EntryMethodProfile/MethodProfileWindow.java
Original file line number Diff line number Diff line change
@@ -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<Long, double[]> LoadData;
private TreeMap<Long, Integer> 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<Long, double[]>();
LastIndices = new TreeMap<Long, Integer>();

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<Integer> 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<Long> 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<Integer> 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<Runnable> readyReaders = new LinkedList<Runnable>();

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<Runnable> titer = readyReaders.iterator();
while(titer.hasNext()){
ThreadedFileReader r = (ThreadedFileReader) titer.next();
LoadData.put(r.getPe(), r.getData());
LastIndices.put(r.getPe(), r.getLastIndex());
}
}
}
}
107 changes: 107 additions & 0 deletions src/projections/Tools/EntryMethodProfile/ThreadedFileReader.java
Original file line number Diff line number Diff line change
@@ -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<LogEntryData> stack = new Stack<LogEntryData>();
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;
}
}





2 changes: 1 addition & 1 deletion src/projections/Tools/Histogram/ThreadedFileReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading