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