Problem Description
A profiler is a tool which provides information about run-time performance of an application. Lets say. you are given output file format of a profiler called Jensor. Jensor captures response times of methods executed by capturing method entry and exit events. The entry and exit events are written to a log file. The log file is then processed to form a Call Trace. A Call Trace is a who called whom and when relationship. For simplicity, let us assume that the application which is profiled using Jensor is single threaded.
Your task is to create a Call Trace given a Jensor log file.
Sample
Pseudo Code
main() { call A(); call B(); call C(); loop(0 to 3, iterate by 1){ call D(); } sleep(20); } A(){ call B(); sleep(10); } B(){ sleep(20); } C(){ call A(); } D(){ call B(); }
JensorProfile.txt
Enter,main(),1345482572920,0,2 MB Enter,A(),1345482572920,0,2 MB Enter,B(),1345482572920,0,2 MB Exit,B(),1345482572951,0,2 MB Exit,A(),1345482572967,0,2 MB Enter,B(),1345482572967,0,2 MB Exit,B(),1345482572998,0,2 MB Enter,C(),1345482572998,0,2 MB Enter,A(),1345482572998,0,2 MB Enter,B(),1345482572998,0,2 MB Exit,B(),1345482573029,0,2 MB Exit,A(),1345482573045,0,2 MB Exit,C(),1345482573045,0,2 MB Enter,D(),1345482573045,0,2 MB Enter,B(),1345482573045,0,2 MB Exit,B(),1345482573076,0,2 MB Exit,D(),1345482573076,0,2 MB Enter,D(),1345482573076,0,2 MB Enter,B(),1345482573076,0,2 MB Exit,B(),1345482573096,0,2 MB Exit,D(),1345482573096,0,2 MB Enter,D(),1345482573096,0,2 MB Enter,B(),1345482573096,0,2 MB Exit,B(),1345482573116,0,2 MB Exit,D(),1345482573116,0,2 MB Enter,D(),1345482573116,0,2 MB Enter,B(),1345482573116,0,2 MB Exit,B(),1345482573136,0,2 MB Exit,D(),1345482573136,0,2 MB Exit,main(),1345482573156,1,2 MB
where,
Column 1 is name of the event. Possible events {Enter, Exit}
Column 2 is name of the method which is entered into or exited out of
Column 3 is time in milliseconds since epoch (1st Jan 1970)
Column 4 is the response time in milliseconds
Column 5 is memory consumption during that event
Columns are delimited by “,” (comma character). Row is delimited by a newline character. Each row contains a single event.
Jensor log file JensorProfile.txt is a representation of the sample program (pseudocode).
Your task is to read similar JensorProfile.txt files as input and find the nth invocation of the function in that JensorProfile.txt file.
The output should include the name of the function corresponding to that invocation, the response time of that function and total number of invocations of that function in the entire run of that program.
Code
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Scanner;
/**
*
* @author tintinmj
*/
public class JensorLogProcessor {
public static class JensorLogProcessorException extends Exception {
public JensorLogProcessorException(String s) {
super(s);
}
}
public static class InvalidInputException extends JensorLogProcessorException {
public InvalidInputException() {
super("Invalid Input");
}
}
private class JensorObject {
private final String functionName;
private final long startTime;
private long executionTime;
public JensorObject(String functionName, long startTime, long executionTime) {
this.functionName = functionName;
this.startTime = startTime;
this.executionTime = executionTime;
}
public void calculateExecutionTime(long endTime) {
this.executionTime = endTime - startTime;
}
public long getExecutionTime() {
return executionTime;
}
public String getFunctionName() {
return functionName;
}
}
@SuppressWarnings("FieldMayBeFinal")
private static Deque<JensorObject> stack = new ArrayDeque<>();
private static List<JensorObject> listOfProcesses = new ArrayList<>();
private static Map<String, Integer> numberOfFunctionCalled = new HashMap<>();
public JensorLogProcessor() {
}
public static void main(String[] args) {
try (Scanner sc = new Scanner(System.in)) {
String logFileName = sc.nextLine();
int functionNumber = sc.nextInt();
System.out.println(new JensorLogProcessor().getDetailsOfFunctionFromFile(logFileName, functionNumber));
} catch (NoSuchElementException | InvalidInputException e){
System.out.println("Invalid Input");
}
}
public String getDetailsOfFunctionFromFile(String fileName, int functionNumber) throws InvalidInputException {
parseLogFile(fileName);
if (functionNumber > listOfProcesses.size()) {
throw new InvalidInputException();
}
else {
JensorObject jensorObject = listOfProcesses.get(functionNumber - 1); // 0 based indexing
String functionName = jensorObject.getFunctionName();
long responseTime = jensorObject.getExecutionTime();
int numberOfInvocation = numberOfFunctionCalled.get(functionName);
return String.format("%s\n%s\n%s", functionName,responseTime,numberOfInvocation);
}
}
private void parseLogFile(String fileName) throws InvalidInputException {
try {
BufferedReader reader = new BufferedReader(new FileReader(fileName));
String line = reader.readLine();
while (line != null) {
parseFunctionAndProcess(line);
line = reader.readLine();
}
} catch (IOException e) {
throw new InvalidInputException();
}
}
private void parseFunctionAndProcess(String line) throws InvalidInputException {
try {
String[] functionDesc = line.split(",");
String enterOrExit = functionDesc[0];
String functionName = functionDesc[1];
long ticks = Long.parseLong(functionDesc[2]);
if(null != functionDesc[0]) switch (enterOrExit) {
case "Enter":
JensorObject jensorObject = new JensorObject(functionName,
ticks, // start ticks
0L // at starting execution ticks is 0
);
stack.push(jensorObject);
listOfProcesses.add(jensorObject);
if(numberOfFunctionCalled.containsKey(jensorObject.getFunctionName())) {
numberOfFunctionCalled.put(jensorObject.getFunctionName(),
numberOfFunctionCalled
.get(jensorObject.getFunctionName())+1);
}
else {
numberOfFunctionCalled.put(jensorObject.getFunctionName(), 1);
} break;
case "Exit":
JensorObject currentJensorObject = stack.pop();
currentJensorObject.calculateExecutionTime(ticks);
break;
}
} catch (NumberFormatException e) {
throw new InvalidInputException();
}
}
}
My code got accepted. But I want suggestion from all of you to improvement in any aspects.