package com.aptana.rdt.internal.profiling;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
public class CallGraphParser extends AbstractProfileOutputParser {
private ProfileThread thread;
public List<ProfileThread> parse(Reader reader) {
thread = null;
List<String> lines = getLines(reader);
String id = getId(lines.remove(0));
float totalTime = getTotalTime(lines.remove(0));
thread = new ProfileThread(id, totalTime);
lines.remove(0); // blank
lines.remove(0); // column names
List<MethodCall> calls = parseMethodCalls(lines);
thread.addMethodCalls(calls);
List<ProfileThread> threads = new ArrayList<ProfileThread>();
threads.add(thread);
return threads;
}
// FIXME Wow all of this code is very, very ugly
private List<MethodCall> parseMethodCalls(List<String> lines) {
List<List<String>> groups = createGroups(lines);
List<MethodCall> calls = new ArrayList<MethodCall>(groups.size());
for (List<String> group : groups) {
calls.add(createMethodCall(group));
}
return calls;
}
private MethodCall createMethodCall(List<String> group) {
String caller = null;
MethodCall call = null;
for (String line : group) {
if (line == null || line.trim().length() == 0) continue;
String[] parts = split(line);
if (!parts[0].endsWith("%")) {
if (call == null) { // caller
caller = parts[parts.length - 1];
} else { // callee
call.addCallee(parts[parts.length - 1]);
}
} else {
call = getMethodCall(line);
}
}
if (caller != null) call.addCaller(caller);
return call;
}
private String[] split(String line) {
List<String> tokens = new ArrayList<String>();
StringTokenizer tokenizer = new StringTokenizer(line);
while(tokenizer.hasMoreTokens()) {
tokens.add(tokenizer.nextToken());
}
return tokens.toArray(new String[tokens.size()]);
}
private MethodCall getMethodCall(String line) {
StringTokenizer tokenizer = new StringTokenizer(line);
// FIXME The method we're focusing on is the one that has values for percentage..
// methods above it are the ones that call it
// methods below are the methods it calls
String rawTotalPercent = tokenizer.nextToken();
if (!rawTotalPercent.endsWith("%")) {
// FIXME Pull out the method name and add it as a caller or callee to the generated Statistic!
return null;
} else {
rawTotalPercent = rawTotalPercent.substring(0, rawTotalPercent.length() - 1);
}
float totalPercent = Float.parseFloat(rawTotalPercent);
float selfPercent = Float.parseFloat(stripLastChar(tokenizer.nextToken()));
float total = Float.parseFloat(tokenizer.nextToken());
float self = Float.parseFloat(tokenizer.nextToken());
float wait = Float.parseFloat(tokenizer.nextToken());
float child = Float.parseFloat(tokenizer.nextToken());
String rawCalls = tokenizer.nextToken();
if (rawCalls.indexOf('/') != -1) {
rawCalls = rawCalls.substring(0, rawCalls.indexOf('/'));
}
int calls = Integer.parseInt(rawCalls); // FIXME not always just a number, but also XXXX/XXXX
String methodName = tokenizer.nextToken();
return new MethodCall(thread, methodName, calls, totalPercent, selfPercent, self, wait, child);
}
private List<List<String>> createGroups(List<String> lines) {
List<List<String>> groups = new ArrayList<List<String>>();
List<String> group = null;
for (String line : lines) {
if (line.startsWith("------")) {
if (group != null) groups.add(group);
// We have a new group
group = new ArrayList<String>();
} else {
group.add(line);
}
}
groups.add(group);
return groups;
}
private float getTotalTime(String line) {
String raw = line.substring(line.indexOf(": ") + 2);
return Float.parseFloat(raw);
}
private String getId(String line) {
return line.substring(line.indexOf(": ") + 2);
}
}