package org.ntlab.trace; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Stack; public class TraceJPDA { protected HashMap<String, ThreadInstanceJPDA> threads = new HashMap<String, ThreadInstanceJPDA>(); /** * 指定したJSONトレースファイルを解読して Trace オブジェクトを生成する * @param traceFile トレースファイルのパス */ public TraceJPDA(BufferedReader file) { try { readJPDA(file); file.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 指定したJSONトレースファイルを解読して Trace オブジェクトを生成する * @param traceFile トレースファイルのパス */ public TraceJPDA(String traceFile) { BufferedReader file; try { file = new BufferedReader(new FileReader(traceFile)); readJPDA(file); file.close(); } catch (IOException e) { e.printStackTrace(); } } private void readJPDA(BufferedReader file) throws IOException { // トレースファイル読み込み String line = null; String[] columns; String[] columns2; String[] stack; String[] signature; String threadId; int prevDepth = 0; int depth = 0; long timeStamp = 0L; ThreadInstanceJPDA thread = null; while ((line = file.readLine()) != null) { // トレースファイルの解析 columns = line.split(":"); if (columns.length < 4) continue; threadId = columns[0]; stack = columns[2].split(" "); columns2 = columns[3].split("\t"); if (columns2.length < 2) continue; timeStamp = Integer.parseInt(columns[1]) * 3600 + Integer.parseInt(stack[stack.length - 1]) * 60 + Integer.parseInt(columns2[0]); depth = stack.length - 1; signature = columns2[1].split(" -- "); thread = threads.get(threadId); if (thread == null) { thread = new ThreadInstanceJPDA(threadId); threads.put(threadId, thread); } if (signature.length < 2) continue; for (int i = 0; i < depth - prevDepth + 1; i++) { thread.returnMethod(); } thread.callMethod(signature[1] + "." + signature[0] + "()", timeStamp); prevDepth = depth; } } /** * メソッド毎に全メソッド実行を全てのスレッドから取り出す * @return メソッドシグニチャからメソッド実行のリストへのHashMap */ public HashMap<String, ArrayList<MethodExecutionJPDA>> getAllMethodExecutions() { final HashMap<String, ArrayList<MethodExecutionJPDA>> results = new HashMap<>(); for (ThreadInstanceJPDA thread: threads.values()) { thread.traverseMethodExecutionsBackward(new MethodExecutionJPDA.IMethodExecutionVisitorJPDA() { @Override public boolean preVisitThread(ThreadInstanceJPDA thread) { return false; } @Override public boolean postVisitThread(ThreadInstanceJPDA thread) { return false; } @Override public boolean preVisitMethodExecution(MethodExecutionJPDA methodExecution) { ArrayList<MethodExecutionJPDA> executions = results.get(methodExecution.getSignature()); if (executions == null) { executions = new ArrayList<MethodExecutionJPDA>(); results.put(methodExecution.getSignature(), executions); } executions.add(methodExecution); return false; } @Override public boolean postVisitMethodExecution(MethodExecutionJPDA methodExecution, ArrayList<MethodExecutionJPDA> children) { return false; } }); } return results; } /** * 全メソッドのシグニチャを取得する * @return 全メソッドシグニチャ */ public HashSet<String> getAllMethodSignatures() { final HashSet<String> results = new HashSet<String>(); for (ThreadInstanceJPDA thread: threads.values()) { thread.traverseMethodExecutionsBackward(new MethodExecutionJPDA.IMethodExecutionVisitorJPDA() { @Override public boolean preVisitThread(ThreadInstanceJPDA thread) { return false; } @Override public boolean postVisitThread(ThreadInstanceJPDA thread) { return false; } @Override public boolean preVisitMethodExecution(MethodExecutionJPDA methodExecution) { results.add(methodExecution.getSignature()); return false; } @Override public boolean postVisitMethodExecution(MethodExecutionJPDA methodExecution, ArrayList<MethodExecutionJPDA> children) { return false; } }); } return results; } public void traverseMethodExecutionsBackward(MethodExecutionJPDA.IMethodExecutionVisitorJPDA visitor) { for (ThreadInstanceJPDA thread: threads.values()) { visitor.preVisitThread(thread); thread.traverseMethodExecutionsBackward(visitor); visitor.postVisitThread(thread); } } }