package cl.niclabs.skandium.monitor;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Hashtable;
import java.util.StringTokenizer;
import javax.swing.JScrollPane;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.view.mxGraph;
/**
* The Muscle Scheduling Monitor, it will make a 2D representation of the
* muscles execution.
*/
class MuscleMonitor extends AbstractMonitor {
private static final long serialVersionUID = 1L;
// Configuration parameters
long L_SPACE = 60; // Left space reserved
long M_HEIGHT = 16; // Muscle height
final String
EXECUTE_STYLE = "fillColor=orange;",
SPLIT_STYLE = "fillColor=blue;fontColor=white;",
MERGE_STYLE = "fillColor=red;fontColor=white;",
CONDITION_STYLE = "fillColor=green;";
// Internal resources
private MonitorController monitorc;
private Hashtable<Long, Long> map;
private mxGraph graph;
private Object parent;
// General variables
private long initTime, currentTime, lastTime;
private long initThreadId, currentThreadId, lastThreadId;
private double timeFactor;
private boolean showCond;
/**
* MuscleMonitor
*
* @param monitorc MonitorController
*/
MuscleMonitor(MonitorController monitorc) {
this.setTitle("Muscle Scheduling Monitor");
this.monitorc = monitorc;
map = new Hashtable<Long, Long>();
graph = new mxGraph();
parent = graph.getDefaultParent();
JScrollPane scroller = new JScrollPane(new mxGraphComponent(graph));
getContentPane().add(scroller);
setSize(400, 300);
}
/**
* Builds the view. Reads the log file and draws the executed threads
* based on the thread id and the running time
*
* @param logFile the log file
* @throws IOException Signals that an I/O exception has occurred.
*/
@Override
public void build() throws IOException {
initLecture(monitorc.getLogFile());
timeFactor = monitorc.getTimeFactor();
showCond = monitorc.getShowCond();
fillGraph(monitorc.getLogFile());
decorateGraph();
super.setVisible(true);
}
/**
* Initial lecture to fill some global important variables
*
* @param file
* @throws IOException
*/
private void initLecture(File file) throws IOException {
BufferedReader log = new BufferedReader(new FileReader(file));
StringTokenizer token = new StringTokenizer(log.readLine());
initTime = Long.parseLong(token.nextToken());
lastTime = 0;
initThreadId = Long.parseLong(token.nextToken());
lastThreadId = 0;
log.close();
}
/**
* Reads the registry file and draw muscles on the graph with that
* information.
*
* @param file
* @throws IOException
*/
private void fillGraph(File file) throws IOException {
graph.removeCells(graph.getChildVertices(graph.getDefaultParent()));
graph.getModel().beginUpdate();
BufferedReader log = new BufferedReader(new FileReader(file));
StringTokenizer token;
String line;
while((line = log.readLine()) != null) {
token = new StringTokenizer(line);
currentTime = Long.parseLong(token.nextToken());
currentThreadId = Long.parseLong(token.nextToken());
if(lastTime < currentTime)
lastTime = currentTime;
if(lastThreadId < currentThreadId)
lastThreadId = currentThreadId;
String when = token.nextToken(), where = token.nextToken();
if(token.nextToken().compareTo("Seq") == 0)
where = "EXECUTE";
else if(where.compareTo("SKELETON") == 0)
continue;
if(when.compareTo("BEFORE") == 0)
reportMuscleStart(where);
else
drawMuscle(where);
}
graph.getModel().endUpdate();
log.close();
}
/**
* Save the initial time of a muscle.
*
* @param where
*/
private void reportMuscleStart(String where) {
if(showCond || where.compareTo("CONDITION") != 0)
map.put(currentThreadId, currentTime);
}
/**
* Draw into the graph a rectangle in representation of the muscle
* execution.
*
* @param where
*/
private void drawMuscle(String where) {
String style;
if(where.compareTo("SPLIT") == 0)
style = SPLIT_STYLE;
else if(where.compareTo("EXECUTE") == 0)
style = EXECUTE_STYLE;
else if(where.compareTo("MERGE") == 0)
style = MERGE_STYLE;
else if(where.compareTo("CONDITION") == 0 && showCond)
style = CONDITION_STYLE;
else
return;
long startTime = map.remove(currentThreadId);
double muscleWidth = timeFactor * (currentTime - startTime);
graph.insertVertex(
parent,
null,
"" + (long) muscleWidth,
timeFactor * (startTime - initTime) + L_SPACE,
M_HEIGHT * (currentThreadId - initThreadId),
muscleWidth,
M_HEIGHT,
style
);
}
/**
* Prints symbology and decorations
*
*/
private void decorateGraph() {
graph.getModel().beginUpdate();
// Print the thread id column
for(int i = (int) initThreadId; i <= lastThreadId; i++)
graph.insertVertex(
parent,
null,
"Thread " + i,
0,
(i - initThreadId)*M_HEIGHT,
L_SPACE,
M_HEIGHT,
"fillColor=white;"
);
// Print the total time bar
graph.insertVertex(
parent,
null,
"TOTAL TIME = " + timeFactor * (lastTime - initTime),
L_SPACE,
(lastThreadId - initThreadId + 1) * M_HEIGHT,
timeFactor * (lastTime - initTime), M_HEIGHT,
"fillColor=white;"
);
graph.getModel().endUpdate();
graph.refresh();
}
}