Newer
Older
MagnetRON / src / org / ntlab / trace / TraceJSON.java
  1. package org.ntlab.trace;
  2.  
  3. import java.io.BufferedReader;
  4. import java.io.FileReader;
  5. import java.io.IOException;
  6. import java.util.ArrayList;
  7. import java.util.HashMap;
  8. import java.util.HashSet;
  9. import java.util.Iterator;
  10. import java.util.Stack;
  11.  
  12. public class TraceJSON extends Trace {
  13. private HashMap<String, ClassInfo> classes = new HashMap<>();
  14. private TraceJSON() {
  15. }
  16.  
  17. /**
  18. * 指定したJSONのトレースファイルを解読して Trace オブジェクトを生成する
  19. * @param file トレースファイル
  20. */
  21. public TraceJSON(BufferedReader file) {
  22. try {
  23. readJSON(file);
  24. file.close();
  25. } catch (IOException e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. /**
  30. * 指定したJSONのトレースファイルを解読して Trace オブジェクトを生成する
  31. * @param traceFile トレースファイルのパス
  32. */
  33. public TraceJSON(String traceFile) {
  34. BufferedReader file;
  35. try {
  36. file = new BufferedReader(new FileReader(traceFile));
  37. readJSON(file);
  38. file.close();
  39. } catch (IOException e) {
  40. e.printStackTrace();
  41. }
  42. }
  43.  
  44. private void readJSON(BufferedReader file) throws IOException {
  45. // トレースファイル読み込み
  46. String line = null;
  47. String[] type;
  48. String[] classNameData;
  49. String[] pathData;
  50. String[] signature;
  51. String[] receiver;
  52. String[] arguments;
  53. String[] lineData;
  54. String[] threadId;
  55. String[] thisObj;
  56. String[] containerObj;
  57. String[] valueObj;
  58. String[] returnValue;
  59. String[] arrayObj;
  60. String[] thisData;
  61. String[] containerData;
  62. String[] valueData;
  63. String[] returnData;
  64. String[] fieldData;
  65. String[] arrayData;
  66. String[] blockIdData;
  67. String[] incomingsData;
  68. String[] dimensionData;
  69. String[] indexData;
  70. String className;
  71. String classPath;
  72. String loaderPath;
  73. String time;
  74. String thisObjectId;
  75. String thisClassName;
  76. String containerObjectId;
  77. String containerClassName;
  78. String valueObjectId;
  79. String valueClassName;
  80. String returnClassName;
  81. String returnObjectId;
  82. String arrayObjectId;
  83. String arrayClassName;
  84. String shortSignature;
  85. boolean isConstractor = false;
  86. boolean isCollectionType = false;
  87. boolean isStatic = false;
  88. int dimension;
  89. int index;
  90. int blockId;
  91. int incomings;
  92. int lineNum;
  93. long timeStamp = 0L;
  94. ThreadInstance thread = null;
  95. HashMap<String, Stack<String>> stacks = new HashMap<String, Stack<String>>();
  96. while ((line = file.readLine()) != null) {
  97. // トレースファイルの解析
  98. if (line.startsWith("{\"type\":\"classDef\"")) {
  99. // クラス定義
  100. type = line.split(",\"name\":\"");
  101. classNameData = type[1].split("\",\"path\":\"");
  102. className = classNameData[0];
  103. pathData = classNameData[1].split("\",\"loaderPath\":\"");
  104. classPath = pathData[0].substring(1); // 先頭の / を取り除く
  105. loaderPath = pathData[1].substring(1, pathData[1].length() - 3); // 先頭の / と、末尾の "}, を取り除く
  106. initializeClass(className, classPath, loaderPath);
  107. } else if (line.startsWith("{\"type\":\"methodCall\"")) {
  108. // メソッド呼び出しの呼び出し側
  109. type = line.split(",\"callerSideSignature\":\"");
  110. signature = type[1].split("\",\"threadId\":");
  111. threadId = signature[1].split(",\"lineNum\":");
  112. lineNum = Integer.parseInt(threadId[1].substring(0, threadId[1].length() - 2)); // 末尾の }, を取り除く
  113. thread = threads.get(threadId[0]);
  114. thread.preCallMethod(signature[0], lineNum);
  115. } else if (line.startsWith("{\"type\":\"methodEntry\"")) {
  116. // メソッド呼び出し
  117. type = line.split("\"signature\":\"");
  118. signature = type[1].split("\",\"receiver\":");
  119. receiver = signature[1].split(",\"args\":");
  120. arguments = receiver[1].split(",\"threadId\":");
  121. threadId = arguments[1].split(",\"time\":");
  122. thisData = parseClassNameAndObjectId(receiver[0]);
  123. thisClassName = thisData[0];
  124. thisObjectId = thisData[1];
  125. isConstractor = false;
  126. isStatic = false;
  127. if (signature[0].contains("static ")) {
  128. isStatic = true;
  129. }
  130. thread = threads.get(threadId[0]);
  131. time = threadId[1].substring(0, threadId[1].length() - 2); // 末尾の }, を取り除く
  132. timeStamp = Long.parseLong(time);
  133. Stack<String> stack;
  134. if (thread == null) {
  135. thread = new ThreadInstance(threadId[0]);
  136. threads.put(threadId[0], thread);
  137. stack = new Stack<String>();
  138. stacks.put(threadId[0], stack);
  139. } else {
  140. stack = stacks.get(threadId[0]);
  141. }
  142. stack.push(signature[0]);
  143. // メソッド呼び出しの設定
  144. thread.callMethod(signature[0], null, thisClassName, thisObjectId, isConstractor, isStatic, timeStamp);
  145. // 引数の設定
  146. thread.setArgments(parseArguments(arguments));
  147. } else if (line.startsWith("{\"type\":\"constructorEntry\"")) {
  148. // コンストラクタ呼び出し
  149. type = line.split("\"signature\":\"");
  150. signature = type[1].split("\",\"class\":\"");
  151. receiver = signature[1].split("\",\"args\":");
  152. arguments = receiver[1].split(",\"threadId\":");
  153. threadId = arguments[1].split(",\"time\":");
  154. thisClassName = receiver[0];
  155. thisObjectId = "0";
  156. isConstractor = true;
  157. isStatic = false;
  158. thread = threads.get(threadId[0]);
  159. time = threadId[1].substring(0, threadId[1].length() - 2); // 末尾の }, を取り除く
  160. timeStamp = Long.parseLong(time);
  161. Stack<String> stack;
  162. if (thread == null) {
  163. thread = new ThreadInstance(threadId[0]);
  164. threads.put(threadId[0], thread);
  165. stack = new Stack<String>();
  166. stacks.put(threadId[0], stack);
  167. } else {
  168. stack = stacks.get(threadId[0]);
  169. }
  170. stack.push(signature[0]);
  171. // メソッド呼び出しの設定
  172. thread.callMethod(signature[0], null, thisClassName, thisObjectId, isConstractor, isStatic, timeStamp);
  173. // 引数の設定
  174. thread.setArgments(parseArguments(arguments));
  175. } else if (line.startsWith("{\"type\":\"methodExit\"")) {
  176. // メソッドからの復帰
  177. type = line.split(",\"shortSignature\":\"");
  178. signature = type[1].split("\",\"receiver\":");
  179. receiver = signature[1].split(",\"returnValue\":");
  180. returnValue = receiver[1].split(",\"threadId\":");
  181. threadId = returnValue[1].split(",\"time\":");
  182. thisData = parseClassNameAndObjectId(receiver[0]);
  183. thisClassName = thisData[0];
  184. thisObjectId = thisData[1];
  185. returnData = parseClassNameAndObjectId(returnValue[0]);
  186. returnClassName = returnData[0];
  187. returnObjectId = returnData[1];
  188. shortSignature = signature[0];
  189. time = threadId[1].substring(0, threadId[1].length() - 2); // 末尾の }, を取り除く
  190. timeStamp = Long.parseLong(time);
  191. Stack<String> stack = stacks.get(threadId[0]);
  192. if (!stack.isEmpty()) {
  193. String line2 = stack.peek();
  194. if (line2.endsWith(shortSignature)) {
  195. stack.pop();
  196. } else {
  197. do {
  198. stack.pop();
  199. thread.terminateMethod();
  200. line2 = stack.peek();
  201. } while (!stack.isEmpty() && !line2.endsWith(shortSignature));
  202. if (!stack.isEmpty()) stack.pop();
  203. }
  204. thread = threads.get(threadId[0]);
  205. ObjectReference returnVal = new ObjectReference(returnObjectId, returnClassName);
  206. isCollectionType = false;
  207. if(thisClassName.contains("java.util.List")
  208. || thisClassName.contains("java.util.Vector")
  209. || thisClassName.contains("java.util.Iterator")
  210. || thisClassName.contains("java.util.ListIterator")
  211. || thisClassName.contains("java.util.ArrayList")
  212. || thisClassName.contains("java.util.Stack")
  213. || thisClassName.contains("java.util.Hash")
  214. || thisClassName.contains("java.util.Map")
  215. || thisClassName.contains("java.util.Set")
  216. || thisClassName.contains("java.util.Linked")
  217. || thisClassName.contains("java.util.Collection")
  218. || thisClassName.contains("java.util.Arrays")
  219. || thisClassName.contains("java.lang.Thread")) {
  220. isCollectionType = true;
  221. }
  222. // メソッドからの復帰の設定
  223. thread.returnMethod(returnVal, thisObjectId, isCollectionType, timeStamp);
  224. }
  225. } else if (line.startsWith("{\"type\":\"constructorExit\"")) {
  226. // コンストラクタからの復帰
  227. type = line.split(",\"shortSignature\":\"");
  228. signature = type[1].split("\",\"returnValue\":");
  229. returnValue = signature[1].split(",\"threadId\":");
  230. threadId = returnValue[1].split(",\"time\":");
  231. returnData = parseClassNameAndObjectId(returnValue[0]);
  232. thisClassName = returnClassName = returnData[0];
  233. thisObjectId = returnObjectId = returnData[1];
  234. time = threadId[1].substring(0, threadId[1].length() - 2); // 末尾の }, を取り除く
  235. timeStamp = Long.parseLong(time);
  236. Stack<String> stack = stacks.get(threadId[0]);
  237. shortSignature = signature[0];
  238. if (!stack.isEmpty()) {
  239. String line2 = stack.peek();
  240. if (line2.endsWith(shortSignature)) {
  241. stack.pop();
  242. } else {
  243. do {
  244. stack.pop();
  245. thread.terminateMethod();
  246. line2 = stack.peek();
  247. } while (!stack.isEmpty() && !line2.endsWith(shortSignature));
  248. if (!stack.isEmpty()) stack.pop();
  249. }
  250. thread = threads.get(threadId[0]);
  251. ObjectReference returnVal = new ObjectReference(returnObjectId, returnClassName);
  252. isCollectionType = false;
  253. if(thisClassName.contains("java.util.List")
  254. || thisClassName.contains("java.util.Vector")
  255. || thisClassName.contains("java.util.Iterator")
  256. || thisClassName.contains("java.util.ListIterator")
  257. || thisClassName.contains("java.util.ArrayList")
  258. || thisClassName.contains("java.util.Stack")
  259. || thisClassName.contains("java.util.Hash")
  260. || thisClassName.contains("java.util.Map")
  261. || thisClassName.contains("java.util.Set")
  262. || thisClassName.contains("java.util.Linked")
  263. || thisClassName.contains("java.lang.Thread")) {
  264. isCollectionType = true;
  265. }
  266. // メソッドからの復帰の設定
  267. thread.returnMethod(returnVal, thisObjectId, isCollectionType, timeStamp);
  268. }
  269. } else if (line.startsWith("{\"type\":\"fieldGet\"")) {
  270. // フィールドアクセス
  271. type = line.split(",\"fieldName\":\"");
  272. fieldData = type[1].split("\",\"this\":");
  273. thisObj = fieldData[1].split(",\"container\":");
  274. containerObj = thisObj[1].split(",\"value\":");
  275. valueObj = containerObj[1].split(",\"threadId\":");
  276. threadId = valueObj[1].split(",\"lineNum\":");
  277. lineData = threadId[1].split(",\"time\":");
  278. thisData = parseClassNameAndObjectId(thisObj[0]);
  279. thisClassName = thisData[0];
  280. thisObjectId = thisData[1];
  281. containerData = parseClassNameAndObjectId(containerObj[0]);
  282. containerClassName = containerData[0];
  283. containerObjectId = containerData[1];
  284. valueData = parseClassNameAndObjectId(valueObj[0]);
  285. valueClassName = valueData[0];
  286. valueObjectId = valueData[1];
  287. thread = threads.get(threadId[0]);
  288. lineNum = Integer.parseInt(lineData[0]);
  289. time = lineData[1].substring(0, lineData[1].length() - 2); // 末尾の }, を取り除く
  290. timeStamp = Long.parseLong(time);
  291. // フィールドアクセスの設定
  292. if (thread != null) thread.fieldAccess(fieldData[0], valueClassName, valueObjectId, containerClassName, containerObjectId, thisClassName, thisObjectId, lineNum, timeStamp);
  293. } else if (line.startsWith("{\"type\":\"fieldSet\"")) {
  294. // フィールド更新
  295. type = line.split(",\"fieldName\":\"");
  296. fieldData = type[1].split("\",\"container\":");
  297. containerObj = fieldData[1].split(",\"value\":");
  298. valueObj = containerObj[1].split(",\"threadId\":");
  299. threadId = valueObj[1].split(",\"lineNum\":");
  300. lineData = threadId[1].split(",\"time\":");
  301. containerData = parseClassNameAndObjectId(containerObj[0]);
  302. containerClassName = containerData[0];
  303. containerObjectId = containerData[1];
  304. valueData = parseClassNameAndObjectId(valueObj[0]);
  305. valueClassName = valueData[0];
  306. valueObjectId = valueData[1];
  307. thread = threads.get(threadId[0]);
  308. lineNum = Integer.parseInt(lineData[0]);
  309. time = lineData[1].substring(0, lineData[1].length() - 2); // 末尾の }, を取り除く
  310. timeStamp = Long.parseLong(time);
  311. // フィールド更新の設定
  312. if (thread != null) thread.fieldUpdate(fieldData[0], valueClassName, valueObjectId, containerClassName, containerObjectId, lineNum, timeStamp);
  313. } else if (line.startsWith("{\"type\":\"arrayCreate\"")) {
  314. // 配列生成
  315. type = line.split(",\"array\":");
  316. arrayObj = type[1].split(",\"dimension\":");
  317. arrayData = parseClassNameAndObjectId(arrayObj[0]);
  318. arrayClassName = arrayData[0];
  319. arrayObjectId = arrayData[1];
  320. dimensionData = arrayObj[1].split(",\"threadId\":");
  321. dimension = Integer.parseInt(dimensionData[0]);
  322. threadId = dimensionData[1].split(",\"lineNum\":");
  323. thread = threads.get(threadId[0]);
  324. lineData = threadId[1].split(",\"time\":");
  325. lineNum = Integer.parseInt(lineData[0]);
  326. time = lineData[1].substring(0, lineData[1].length() - 2); // 末尾の }, を取り除く
  327. timeStamp = Long.parseLong(time);
  328. if (thread != null) thread.arrayCreate(arrayClassName, arrayObjectId, dimension, lineNum, timeStamp);
  329. } else if (line.startsWith("{\"type\":\"arraySet\"")) {
  330. // 配列要素への代入
  331. type = line.split(",\"array\":");
  332. arrayObj = type[1].split(",\"index\":");
  333. arrayData = parseClassNameAndObjectId(arrayObj[0]);
  334. arrayClassName = arrayData[0];
  335. arrayObjectId = arrayData[1];
  336. indexData = arrayObj[1].split(",\"value\":");
  337. index = Integer.parseInt(indexData[0]);
  338. valueObj = indexData[1].split(",\"threadId\":");
  339. valueData = parseClassNameAndObjectId(valueObj[0]);
  340. valueClassName = valueData[0];
  341. valueObjectId = valueData[1];
  342. threadId = valueObj[1].split(",\"time\":");
  343. thread = threads.get(threadId[0]);
  344. time = threadId[1].substring(0, threadId[1].length() - 2); // 末尾の }, を取り除く
  345. timeStamp = Long.parseLong(time);
  346. if (thread != null) thread.arraySet(arrayClassName, arrayObjectId, index, valueClassName, valueObjectId, 0, timeStamp);
  347. } else if (line.startsWith("{\"type\":\"arrayGet\"")) {
  348. // 配列要素の参照
  349. type = line.split(",\"array\":");
  350. arrayObj = type[1].split(",\"index\":");
  351. arrayData = parseClassNameAndObjectId(arrayObj[0]);
  352. arrayClassName = arrayData[0];
  353. arrayObjectId = arrayData[1];
  354. indexData = arrayObj[1].split(",\"value\":");
  355. index = Integer.parseInt(indexData[0]);
  356. valueObj = indexData[1].split(",\"threadId\":");
  357. valueData = parseClassNameAndObjectId(valueObj[0]);
  358. valueClassName = valueData[0];
  359. valueObjectId = valueData[1];
  360. threadId = valueObj[1].split(",\"time\":");
  361. thread = threads.get(threadId[0]);
  362. time = threadId[1].substring(0, threadId[1].length() - 2); // 末尾の }, を取り除く
  363. timeStamp = Long.parseLong(time);
  364. if (thread != null) thread.arrayGet(arrayClassName, arrayObjectId, index, valueClassName, valueObjectId, 0, timeStamp);
  365. } else if (line.startsWith("{\"type\":\"blockEntry\"")) {
  366. // ブロックの開始
  367. type = line.split(",\"methodSignature\":\"");
  368. signature = type[1].split("\",\"blockId\":");
  369. blockIdData = signature[1].split(",\"incomings\":");
  370. blockId = Integer.parseInt(blockIdData[0]);
  371. incomingsData = blockIdData[1].split(",\"threadId\":");
  372. incomings = Integer.parseInt(incomingsData[0]);
  373. threadId = incomingsData[1].split(",\"lineNum\":");
  374. thread = threads.get(threadId[0]);
  375. lineData = threadId[1].split(",\"time\":");
  376. lineNum = Integer.parseInt(lineData[0]);
  377. time = lineData[1].substring(0, lineData[1].length() - 2); // 末尾の }, を取り除く
  378. timeStamp = Long.parseLong(time);
  379. if (thread != null) thread.blockEnter(blockId, incomings, lineNum, timeStamp);
  380. }
  381. }
  382. }
  383.  
  384. /**
  385. * クラス名とオブジェクトIDを表すJSONオブジェクトを解読する
  386. * @param classNameAndObjectIdJSON トレースファイル内のJSONオブジェクト
  387. * @return
  388. */
  389. protected String[] parseClassNameAndObjectId(String classNameAndObjectIdJSON) {
  390. // 先頭の {"class":" の10文字と末尾の } を取り除いて分離
  391. return classNameAndObjectIdJSON.substring(10, classNameAndObjectIdJSON.length() - 1).split("\",\"id\":");
  392. }
  393. /**
  394. * 引数を表すJSON配列を解読する
  395. * @param arguments
  396. * @return
  397. */
  398. protected ArrayList<ObjectReference> parseArguments(String[] arguments) {
  399. String[] argData;
  400. argData = arguments[0].substring(1, arguments[0].length() - 1).split(","); // 先頭の [ と末尾の ] を取り除く
  401. ArrayList<ObjectReference> argumentsData = new ArrayList<ObjectReference>();
  402. for (int k = 0; k < argData.length - 1; k += 2) {
  403. argumentsData.add(new ObjectReference(argData[k+1].substring(5, argData[k+1].length() - 1), argData[k].substring(10, argData[k].length() - 1)));
  404. }
  405. return argumentsData;
  406. }
  407. /**
  408. * オンライン解析用シングルトンの取得
  409. * @return オンライン解析用トレース
  410. */
  411. public static TraceJSON getInstance() {
  412. if (theTrace == null) {
  413. theTrace = new TraceJSON();
  414. }
  415. return (TraceJSON)theTrace;
  416. }
  417. /**
  418. * スレッドIDを指定してスレッドインスタンスを取得する(オンライン解析用)
  419. * @param threadId
  420. * @return スレッドインスタンス
  421. */
  422. public static ThreadInstance getThreadInstance(String threadId) {
  423. return getInstance().threads.get(threadId);
  424. }
  425. /**
  426. * 指定したスレッド上で現在実行中のメソッド実行を取得する
  427. * @param thread 対象スレッド
  428. * @return thread 上で現在実行中のメソッド実行
  429. */
  430. public static MethodExecution getCurrentMethodExecution(Thread thread) {
  431. ThreadInstance t = getInstance().threads.get(String.valueOf(thread.getId()));
  432. return t.getCurrentMethodExecution();
  433. }
  434. /**
  435. * 指定したスレッド上で現在実行中のトレースポイントを取得する
  436. * @param thread 対象スレッド
  437. * @return thread 上で現在実行中の実行文のトレースポイント
  438. */
  439. public static TracePoint getCurrentTracePoint(Thread thread) {
  440. ThreadInstance t = getInstance().threads.get(String.valueOf(thread.getId()));
  441. return t.getCurrentTracePoint();
  442. }
  443.  
  444. public void initializeClass(String name, String path, String loaderPath) {
  445. classes.put(name, new ClassInfo(name, path, loaderPath));
  446. }
  447.  
  448. public ClassInfo getClassInfo(String className) {
  449. return classes.get(className);
  450. }
  451. public TracePoint getArraySetTracePoint(final Reference ref, TracePoint before) {
  452. final TracePoint start = before.duplicate();
  453. before = traverseStatementsInTraceBackward(new IStatementVisitor() {
  454. @Override
  455. public boolean preVisitStatement(Statement statement) {
  456. if (statement instanceof ArrayUpdate) {
  457. ArrayUpdate arraySet = (ArrayUpdate)start.getStatement();
  458. String srcObjId = ref.getSrcObjectId();
  459. String dstObjId = ref.getDstObjectId();
  460. String srcClassName = ref.getSrcClassName();
  461. String dstClassName = ref.getDstClassName();
  462. if ((srcObjId != null && srcObjId.equals(arraySet.getArrayObjectId()))
  463. || (srcObjId == null || isNull(srcObjId)) && srcClassName.equals(arraySet.getArrayClassName())) {
  464. if ((dstObjId != null && dstObjId.equals(arraySet.getValueObjectId()))
  465. || ((dstObjId == null || isNull(dstObjId)) && dstClassName.equals(arraySet.getValueClassName()))) {
  466. if (srcObjId == null) {
  467. ref.setSrcObjectId(arraySet.getArrayObjectId());
  468. } else if (srcClassName == null) {
  469. ref.setSrcClassName(arraySet.getArrayClassName());
  470. }
  471. if (dstObjId == null) {
  472. ref.setDstObjectId(arraySet.getValueObjectId());
  473. } else if (dstClassName == null) {
  474. ref.setDstClassName(arraySet.getValueClassName());
  475. }
  476. return true;
  477. }
  478. }
  479. }
  480. return false;
  481. }
  482. @Override
  483. public boolean postVisitStatement(Statement statement) { return false; }
  484. }, start);
  485. if (before != null) {
  486. return before;
  487. }
  488. return null;
  489. }
  490. /**
  491. * 実行された全ブロックを取得する
  492. * @return 全ブロック(メソッド名:ブロックID)
  493. */
  494. public HashSet<String> getAllBlocks() {
  495. final HashSet<String> blocks = new HashSet<String>();
  496. Iterator<String> threadsIterator = threads.keySet().iterator();
  497. for (; threadsIterator.hasNext();) {
  498. ThreadInstance thread = threads.get(threadsIterator.next());
  499. thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() {
  500. @Override
  501. public boolean preVisitThread(ThreadInstance thread) {
  502. return false;
  503. }
  504. @Override
  505. public boolean postVisitThread(ThreadInstance thread) {
  506. return false;
  507. }
  508. @Override
  509. public boolean preVisitMethodExecution(MethodExecution methodExecution) {
  510. for (Statement s: methodExecution.getStatements()) {
  511. if (s instanceof BlockEnter) {
  512. blocks.add(methodExecution.getSignature() + ":" + ((BlockEnter)s).getBlockId());
  513. }
  514. }
  515. return false;
  516. }
  517. @Override
  518. public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList<MethodExecution> children) {
  519. return false;
  520. }
  521. });
  522. }
  523. return blocks;
  524. }
  525. /**
  526. * マーク内で実行が開始されたブロックを取得する
  527. * @param markStart マークの開始時刻
  528. * @param markEnd マークの終了時刻
  529. * @return 該当するブロック(メソッド名:ブロックID)
  530. */
  531. public HashSet<String> getMarkedBlocks(final long markStart, final long markEnd) {
  532. final HashSet<String> blocks = new HashSet<String>();
  533. Iterator<String> threadsIterator = threads.keySet().iterator();
  534. for (; threadsIterator.hasNext();) {
  535. ThreadInstance thread = threads.get(threadsIterator.next());
  536. thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() {
  537. @Override
  538. public boolean preVisitThread(ThreadInstance thread) {
  539. return false;
  540. }
  541. @Override
  542. public boolean postVisitThread(ThreadInstance thread) {
  543. return false;
  544. }
  545. @Override
  546. public boolean preVisitMethodExecution(MethodExecution methodExecution) {
  547. if (!methodExecution.isTerminated() && methodExecution.getExitTime() < markStart) return true; // 探索終了
  548. if (methodExecution.getEntryTime() > markEnd) return false;
  549. for (Statement s: methodExecution.getStatements()) {
  550. if (s instanceof BlockEnter) {
  551. long entryTime = ((BlockEnter)s).getTimeStamp();
  552. if (entryTime >= markStart && entryTime <= markEnd) {
  553. blocks.add(methodExecution.getSignature() + ":" + ((BlockEnter)s).getBlockId());
  554. }
  555. }
  556. }
  557. return false;
  558. }
  559. @Override
  560. public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList<MethodExecution> children) {
  561. return false;
  562. }
  563. });
  564. }
  565. return blocks;
  566. }
  567. /**
  568. * 実行された全フローを取得する
  569. * @return 全フロー(メソッド名:フロー元ブロックID:フロー先ブロックID)
  570. */
  571. public HashSet<String> getAllFlows() {
  572. final HashSet<String> flows = new HashSet<String>();
  573. Iterator<String> threadsIterator = threads.keySet().iterator();
  574. for (; threadsIterator.hasNext();) {
  575. ThreadInstance thread = threads.get(threadsIterator.next());
  576. thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() {
  577. @Override
  578. public boolean preVisitThread(ThreadInstance thread) {
  579. return false;
  580. }
  581. @Override
  582. public boolean postVisitThread(ThreadInstance thread) {
  583. return false;
  584. }
  585. @Override
  586. public boolean preVisitMethodExecution(MethodExecution methodExecution) {
  587. int prevBlockId = -1;
  588. for (Statement s: methodExecution.getStatements()) {
  589. if (s instanceof BlockEnter) {
  590. int curBlockID = ((BlockEnter)s).getBlockId();
  591. if (prevBlockId != -1) {
  592. flows.add(methodExecution.getSignature() + ":" + prevBlockId + ":" + curBlockID);
  593. } else {
  594. flows.add(methodExecution.getSignature() + ":" + curBlockID);
  595. }
  596. prevBlockId = curBlockID;
  597. }
  598. }
  599. return false;
  600. }
  601. @Override
  602. public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList<MethodExecution> children) {
  603. return false;
  604. }
  605. });
  606. }
  607. return flows;
  608. }
  609. /**
  610. * マーク内で実行されたフローを取得する
  611. * @param markStart マークの開始時刻
  612. * @param markEnd マークの終了時刻
  613. * @return 該当するフロー(メソッド名:フロー元ブロックID:フロー先ブロックID)
  614. */
  615. public HashSet<String> getMarkedFlows(final long markStart, final long markEnd) {
  616. final HashSet<String> flows = new HashSet<String>();
  617. Iterator<String> threadsIterator = threads.keySet().iterator();
  618. for (; threadsIterator.hasNext();) {
  619. ThreadInstance thread = threads.get(threadsIterator.next());
  620. thread.traverseMethodExecutionsBackward(new IMethodExecutionVisitor() {
  621. @Override
  622. public boolean preVisitThread(ThreadInstance thread) {
  623. return false;
  624. }
  625. @Override
  626. public boolean postVisitThread(ThreadInstance thread) {
  627. return false;
  628. }
  629. @Override
  630. public boolean preVisitMethodExecution(MethodExecution methodExecution) {
  631. if (!methodExecution.isTerminated() && methodExecution.getExitTime() < markStart) return true; // 探索終了
  632. if (methodExecution.getEntryTime() > markEnd) return false;
  633. int prevBlockId = -1;
  634. for (Statement s: methodExecution.getStatements()) {
  635. if (s instanceof BlockEnter) {
  636. long entryTime = ((BlockEnter)s).getTimeStamp();
  637. int curBlockID = ((BlockEnter)s).getBlockId();
  638. if (entryTime >= markStart && entryTime <= markEnd) {
  639. if (prevBlockId != -1) {
  640. flows.add(methodExecution.getSignature() + ":" + prevBlockId + ":" + curBlockID);
  641. } else {
  642. flows.add(methodExecution.getSignature() + ":" + curBlockID);
  643. }
  644. }
  645. prevBlockId = curBlockID;
  646. }
  647. }
  648. return false;
  649. }
  650. @Override
  651. public boolean postVisitMethodExecution(MethodExecution methodExecution, ArrayList<MethodExecution> children) {
  652. return false;
  653. }
  654. });
  655. }
  656. return flows;
  657. }
  658. /**
  659. * トレース内の全スレッドを同期させながら全実行文を逆方向に探索する
  660. *
  661. * @param visitor 実行文のビジター
  662. * @return 中断したトレースポイント
  663. */
  664. public TracePoint traverseStatementsInTraceBackward(IStatementVisitor visitor) {
  665. HashMap<String, ArrayList<MethodExecution>> threadRoots = new HashMap<String, ArrayList<MethodExecution>>();
  666. HashMap<String, TracePoint> threadLastPoints = new HashMap<String, TracePoint>();
  667. // 各スレッドにおいて一番最後に開始したメソッド実行を探す
  668. long traceLastTime = 0;
  669. String traceLastThread = null;
  670. long traceLastTime2 = 0;
  671. String traceLastThread2 = null;
  672. for (String threadId: threads.keySet()) {
  673. ThreadInstance thread = threads.get(threadId);
  674. ArrayList<MethodExecution> roots = (ArrayList<MethodExecution>)thread.getRoot().clone();
  675. threadRoots.put(threadId, roots);
  676. TracePoint threadLastTp;
  677. do {
  678. MethodExecution threadLastExecution = roots.remove(roots.size() - 1);
  679. threadLastTp = threadLastExecution.getExitPoint();
  680. } while (!threadLastTp.isValid() && roots.size() > 0);
  681. if (threadLastTp.isValid()) {
  682. threadLastPoints.put(threadId, threadLastTp);
  683. long threadLastTime;
  684. if (threadLastTp.getStatement() instanceof MethodInvocation) {
  685. threadLastTime = ((MethodInvocation) threadLastTp.getStatement()).getCalledMethodExecution().getExitTime();
  686. } else {
  687. threadLastTime = threadLastTp.getStatement().getTimeStamp();
  688. }
  689. if (traceLastTime < threadLastTime) {
  690. traceLastTime2 = traceLastTime;
  691. traceLastThread2 = traceLastThread;
  692. traceLastTime = threadLastTime;
  693. traceLastThread = threadId;
  694. } else if (traceLastTime2 < threadLastTime) {
  695. traceLastTime2 = threadLastTime;
  696. traceLastThread2 = threadId;
  697. }
  698. } else {
  699. threadLastPoints.put(threadId, null);
  700. }
  701. }
  702. return traverseStatementsInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2);
  703. }
  704. /**
  705. * トレース内の全スレッドを同期させながら指定したトレースポイントから逆方向に探索する
  706. *
  707. * @param visitor 実行文のビジター
  708. * @param before 探索開始トレースポイント
  709. * @return 中断したトレースポイント
  710. */
  711. public TracePoint traverseStatementsInTraceBackward(IStatementVisitor visitor, TracePoint before) {
  712. if (before == null) {
  713. return traverseStatementsInTraceBackward(visitor);
  714. }
  715. // 全てのスレッドのトレースポイントを before の前まで巻き戻す
  716. HashMap<String, ArrayList<MethodExecution>> threadRoots = new HashMap<String, ArrayList<MethodExecution>>();
  717. HashMap<String, TracePoint> threadLastPoints = new HashMap<String, TracePoint>();
  718. String traceLastThread = null;
  719. long traceLastTime2 = 0;
  720. String traceLastThread2 = null;
  721. ThreadInstance thread = threads.get(before.getStatement().getThreadNo());
  722. for (String threadId: threads.keySet()) {
  723. ThreadInstance t = threads.get(threadId);
  724. ArrayList<MethodExecution> rootExecutions = (ArrayList<MethodExecution>)t.getRoot().clone();
  725. threadRoots.put(threadId, rootExecutions);
  726. if (t == thread) {
  727. traceLastThread = threadId;
  728. threadLastPoints.put(threadId, before);
  729. for (int n = rootExecutions.size() - 1; n >= 0; n--) {
  730. MethodExecution root = rootExecutions.get(n);
  731. if (root.getEntryTime() > before.getStatement().getTimeStamp()) {
  732. rootExecutions.remove(n);
  733. } else {
  734. break;
  735. }
  736. }
  737. if (rootExecutions.size() > 0) {
  738. rootExecutions.remove(rootExecutions.size() - 1);
  739. }
  740. } else {
  741. TracePoint threadBeforeTp;
  742. do {
  743. MethodExecution threadLastExecution = rootExecutions.remove(rootExecutions.size() - 1);
  744. threadBeforeTp = threadLastExecution.getExitPoint();
  745. } while (!threadBeforeTp.isValid() && rootExecutions.size() > 0);
  746. if (threadBeforeTp.isValid()) {
  747. TracePoint[] tp = new TracePoint[] {threadBeforeTp};
  748. long threadLastTime;
  749. if (before.getStatement() instanceof MethodInvocation) {
  750. threadLastTime = ((MethodInvocation) before.getStatement()).getCalledMethodExecution().getExitTime();
  751. } else {
  752. threadLastTime = before.getStatement().getTimeStamp();
  753. }
  754. getLastStatementInThread(rootExecutions, tp, threadLastTime, new IStatementVisitor() {
  755. @Override
  756. public boolean preVisitStatement(Statement statement) { return false; }
  757. @Override
  758. public boolean postVisitStatement(Statement statement) { return false; }
  759. });
  760. threadLastPoints.put(threadId, tp[0]);
  761. if (tp[0] != null) {
  762. if (tp[0].getStatement() instanceof MethodInvocation) {
  763. threadLastTime = ((MethodInvocation) tp[0].getStatement()).getCalledMethodExecution().getExitTime(); // ※Exception が発生した場合は考えなくてよい?
  764. } else {
  765. threadLastTime = tp[0].getStatement().getTimeStamp();
  766. }
  767. if (traceLastTime2 < threadLastTime) {
  768. traceLastTime2 = threadLastTime;
  769. traceLastThread2 = threadId;
  770. }
  771. }
  772. } else {
  773. threadLastPoints.put(threadId, null);
  774. }
  775. }
  776. }
  777. return traverseStatementsInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2);
  778. }
  779. /**
  780. * トレース内の全スレッドを同期させながら指定したトレースポイントから逆方向に探索する
  781. *
  782. * @param visitor 実行文のビジター
  783. * @param before 探索開始時間
  784. * @return 中断したトレースポイント
  785. */
  786. public TracePoint traverseStatementsInTraceBackward(IStatementVisitor visitor, long before) {
  787. if (before <= 0L) {
  788. return traverseStatementsInTraceBackward(visitor);
  789. }
  790. // 全てのスレッドのトレースポイントを before の前まで巻き戻す
  791. HashMap<String, ArrayList<MethodExecution>> threadRoots = new HashMap<String, ArrayList<MethodExecution>>();
  792. HashMap<String, TracePoint> threadLastPoints = new HashMap<String, TracePoint>();
  793. long traceLastTime = 0;
  794. String traceLastThread = null;
  795. long traceLastTime2 = 0;
  796. String traceLastThread2 = null;
  797. for (String threadId: threads.keySet()) {
  798. ThreadInstance t = threads.get(threadId);
  799. ArrayList<MethodExecution> rootExecutions = (ArrayList<MethodExecution>)t.getRoot().clone();
  800. threadRoots.put(threadId, rootExecutions);
  801. TracePoint threadBeforeTp;
  802. do {
  803. MethodExecution threadLastExecution = rootExecutions.remove(rootExecutions.size() - 1);
  804. threadBeforeTp = threadLastExecution.getExitPoint();
  805. } while (!threadBeforeTp.isValid() && rootExecutions.size() > 0);
  806. if (threadBeforeTp.isValid()) {
  807. TracePoint[] tp = new TracePoint[] {threadBeforeTp};
  808. getLastStatementInThread(rootExecutions, tp, before, new IStatementVisitor() {
  809. @Override
  810. public boolean preVisitStatement(Statement statement) { return false; }
  811. @Override
  812. public boolean postVisitStatement(Statement statement) { return false; }
  813. });
  814. threadLastPoints.put(threadId, tp[0]);
  815. if (tp[0] != null) {
  816. long threadLastTime;
  817. if (tp[0].getStatement() instanceof MethodInvocation) {
  818. threadLastTime = ((MethodInvocation) tp[0].getStatement()).getCalledMethodExecution().getExitTime(); // ※Exception が発生した場合は考えなくてよい?
  819. } else {
  820. threadLastTime = tp[0].getStatement().getTimeStamp();
  821. }
  822. if (traceLastTime < threadLastTime) {
  823. traceLastTime2 = traceLastTime;
  824. traceLastThread2 = traceLastThread;
  825. traceLastTime = threadLastTime;
  826. traceLastThread = threadId;
  827. } else if (traceLastTime2 < threadLastTime) {
  828. traceLastTime2 = threadLastTime;
  829. traceLastThread2 = threadId;
  830. }
  831. }
  832. } else {
  833. threadLastPoints.put(threadId, null);
  834. }
  835. }
  836. return traverseStatementsInTraceBackwardSub(visitor, threadRoots, threadLastPoints, traceLastThread, traceLastThread2, traceLastTime2);
  837. }
  838.  
  839. private TracePoint traverseStatementsInTraceBackwardSub(IStatementVisitor visitor,
  840. HashMap<String, ArrayList<MethodExecution>> threadRoots,
  841. HashMap<String, TracePoint> threadLastPoints,
  842. String traceLastThread, String traceLastThread2, long traceLastTime2) {
  843. // 全スレッドの同期をとりながら逆向きに実行文を探索する
  844. for (;;) {
  845. // 探索対象のスレッド内の逆向き探索
  846. TracePoint lastTp = threadLastPoints.get(traceLastThread);
  847. while (lastTp != null) {
  848. Statement statement = lastTp.getStatement();
  849. if (visitor.preVisitStatement(statement)) return lastTp;
  850. if (statement instanceof MethodInvocation) {
  851. // 呼び出し先がある場合、呼び出し先に潜る
  852. lastTp.stepBackNoReturn();
  853. if (lastTp.isValid()) {
  854. // 普通に呼び出し先に移った場合
  855. MethodExecution methodExecution = ((MethodInvocation) statement).getCalledMethodExecution();
  856. if (!methodExecution.isTerminated() && methodExecution.getExitTime() < traceLastTime2) {
  857. break;
  858. }
  859. continue;
  860. }
  861. // 空のメソッド実行の場合
  862. } else {
  863. if (visitor.postVisitStatement(statement)) return lastTp;
  864. }
  865. if (lastTp.isValid() && lastTp.getStatement().getTimeStamp() < traceLastTime2) break;
  866. // 1ステップ巻き戻す
  867. while (!lastTp.stepBackOver() && lastTp.isValid()) {
  868. // 呼び出し元に戻った場合(メソッド呼び出し文に復帰)
  869. statement = lastTp.getStatement();
  870. if (visitor.postVisitStatement(statement)) return lastTp;
  871. }
  872. if (!lastTp.isValid()) {
  873. // 呼び出し木の開始時点まで探索し終えた場合
  874. ArrayList<MethodExecution> roots = threadRoots.get(traceLastThread);
  875. while (!lastTp.isValid() && roots.size() > 0) {
  876. // 次の呼び出し木を探す
  877. MethodExecution lastExecution = roots.remove(roots.size() - 1);
  878. lastTp = lastExecution.getExitPoint();
  879. }
  880. if (lastTp.isValid()) {
  881. // 次の呼び出し木があればそれを最後から探索
  882. threadLastPoints.put(traceLastThread, lastTp);
  883. if (lastTp.getStatement().getTimeStamp() < traceLastTime2) break;
  884. } else {
  885. // そのスレッドの探索がすべて終了した場合
  886. threadLastPoints.put(traceLastThread, null);
  887. break;
  888. }
  889. }
  890. }
  891. traceLastThread = traceLastThread2;
  892. // 次の次に探索すべきスレッド(未探索の領域が一番最後まで残っているスレッド)を決定する
  893. traceLastTime2 = 0;
  894. traceLastThread2 = null;
  895. boolean continueTraverse = false;
  896. for (String threadId: threadLastPoints.keySet()) {
  897. if (!threadId.equals(traceLastThread)) {
  898. TracePoint threadLastTp = threadLastPoints.get(threadId);
  899. if (threadLastTp != null) {
  900. continueTraverse = true;
  901. long threadLastTime;
  902. if (threadLastTp.getStatement() instanceof MethodInvocation) {
  903. threadLastTime = ((MethodInvocation) threadLastTp.getStatement()).getCalledMethodExecution().getExitTime();
  904. } else {
  905. threadLastTime = threadLastTp.getStatement().getTimeStamp();
  906. }
  907. if (traceLastTime2 < threadLastTime) {
  908. traceLastTime2 = threadLastTime;
  909. traceLastThread2 = threadId;
  910. }
  911. }
  912. }
  913. }
  914. if (traceLastThread == null && traceLastThread2 == null) break;
  915. if (!continueTraverse && threadLastPoints.get(traceLastThread) == null) break;
  916. }
  917. return null;
  918. }
  919. }