PageRenderTime 36ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/Trunk/src/net/sf/odinms/tools/performance/CPUSampler.java

https://github.com/system32/NinjaMS
Java | 333 lines | 273 code | 40 blank | 20 comment | 47 complexity | f8e1d370e4aee3a7e525621149fbf724 MD5 | raw file
Possible License(s): AGPL-3.0
  1. /*
  2. This file is part of the OdinMS Maple Story Server
  3. Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. package net.sf.odinms.tools.performance;
  19. import java.io.IOException;
  20. import java.io.Writer;
  21. import java.lang.Thread.State;
  22. import java.util.ArrayList;
  23. import java.util.Collections;
  24. import java.util.HashMap;
  25. import java.util.LinkedList;
  26. import java.util.List;
  27. import java.util.Map;
  28. import java.util.Set;
  29. import java.util.Map.Entry;
  30. public class CPUSampler {
  31. private List<String> included = new LinkedList<String>();
  32. private static CPUSampler instance = new CPUSampler();
  33. private long interval = 5;
  34. private SamplerThread sampler = null;
  35. private Map<StackTrace, Integer> recorded = new HashMap<StackTrace, Integer>();
  36. private int totalSamples = 0;
  37. private CPUSampler() {
  38. }
  39. public static CPUSampler getInstance() {
  40. return instance;
  41. }
  42. public void setInterval(long millis) {
  43. interval = millis;
  44. }
  45. public void addIncluded(String include) {
  46. for (String alreadyIncluded : included) {
  47. if (include.startsWith(alreadyIncluded)) {
  48. return;
  49. }
  50. }
  51. included.add(include);
  52. }
  53. public void reset() {
  54. recorded.clear();
  55. totalSamples = 0;
  56. }
  57. public void start() {
  58. if (sampler == null) {
  59. sampler = new SamplerThread();
  60. sampler.start();
  61. }
  62. }
  63. public void stop() {
  64. if (sampler != null) {
  65. sampler.stop();
  66. sampler = null;
  67. }
  68. }
  69. public SampledStacktraces getTopConsumers() {
  70. List<StacktraceWithCount> ret = new ArrayList<StacktraceWithCount>();
  71. Set<Entry<StackTrace, Integer>> entrySet = recorded.entrySet();
  72. for (Entry<StackTrace, Integer> entry : entrySet) {
  73. ret.add(new StacktraceWithCount(entry.getValue(), entry.getKey()));
  74. }
  75. Collections.sort(ret);
  76. return new SampledStacktraces(ret, totalSamples);
  77. }
  78. public void save(Writer writer, int minInvocations, int topMethods) throws IOException {
  79. SampledStacktraces topConsumers = getTopConsumers();
  80. StringBuilder builder = new StringBuilder(); // build our summary :o
  81. builder.append("Top Methods:\n");
  82. for (int i = 0; i < topMethods && i < topConsumers.getTopConsumers().size(); i++) {
  83. builder.append(topConsumers.getTopConsumers().get(i).toString(topConsumers.getTotalInvocations(), 1));
  84. }
  85. builder.append("\nStack Traces:\n");
  86. writer.write(builder.toString());
  87. writer.write(topConsumers.toString(minInvocations));
  88. writer.flush();
  89. }
  90. private void consumeStackTraces(Map<Thread, StackTraceElement[]> traces) {
  91. for (Entry<Thread, StackTraceElement[]> trace : traces.entrySet()) {
  92. int relevant = findRelevantElement(trace.getValue());
  93. if (relevant != -1) {
  94. StackTrace st = new StackTrace(trace.getValue(), relevant, trace.getKey().getState());
  95. Integer i = recorded.get(st);
  96. totalSamples++;
  97. if (i == null) {
  98. recorded.put(st, Integer.valueOf(1));
  99. } else {
  100. recorded.put(st, Integer.valueOf(i.intValue() + 1));
  101. }
  102. }
  103. }
  104. }
  105. private int findRelevantElement(StackTraceElement[] trace) {
  106. if (trace.length == 0) {
  107. return -1;
  108. } else if (included.size() == 0) {
  109. return 0;
  110. }
  111. int firstIncluded = -1;
  112. for (String myIncluded : included) {
  113. for (int i = 0; i < trace.length; i++) {
  114. StackTraceElement ste = trace[i];
  115. if (ste.getClassName().startsWith(myIncluded)) {
  116. if (i < firstIncluded || firstIncluded == -1) {
  117. firstIncluded = i;
  118. break;
  119. }
  120. }
  121. }
  122. }
  123. if (firstIncluded >= 0 && trace[firstIncluded].getClassName().equals("net.sf.odinms.tools.performance.CPUSampler$SamplerThread")) { // don't sample us
  124. return -1;
  125. }
  126. return firstIncluded;
  127. }
  128. private static class StackTrace {
  129. private StackTraceElement[] trace;
  130. private State state;
  131. public StackTrace(StackTraceElement[] trace, int startAt, State state) {
  132. this.state = state;
  133. if (startAt == 0) {
  134. this.trace = trace;
  135. } else {
  136. this.trace = new StackTraceElement[trace.length - startAt];
  137. System.arraycopy(trace, startAt, this.trace, 0, this.trace.length);
  138. }
  139. }
  140. @Override
  141. public boolean equals(Object obj) {
  142. if (!(obj instanceof StackTrace)) {
  143. return false;
  144. }
  145. StackTrace other = (StackTrace) obj;
  146. if (other.trace.length != trace.length) {
  147. return false;
  148. }
  149. if (!(other.state == this.state)) {
  150. return false;
  151. }
  152. for (int i = 0; i < trace.length; i++) {
  153. if (!trace[i].equals(other.trace[i])) {
  154. return false;
  155. }
  156. }
  157. return true;
  158. }
  159. @Override
  160. public int hashCode() {
  161. int ret = 13 * trace.length + state.hashCode();
  162. for (StackTraceElement ste : trace) {
  163. ret ^= ste.hashCode();
  164. }
  165. return ret;
  166. }
  167. public StackTraceElement[] getTrace() {
  168. return trace;
  169. }
  170. @Override
  171. public String toString() {
  172. return toString(-1);
  173. }
  174. public String toString(int traceLength) {
  175. StringBuilder ret = new StringBuilder("State: ");
  176. ret.append(state.name());
  177. if (traceLength > 1) {
  178. ret.append("\n");
  179. } else {
  180. ret.append(" ");
  181. }
  182. int i = 0;
  183. for (StackTraceElement ste : trace) {
  184. i++;
  185. if (i > traceLength) {
  186. break;
  187. }
  188. ret.append(ste.getClassName());
  189. ret.append("#");
  190. ret.append(ste.getMethodName());
  191. ret.append(" (Line: ");
  192. ret.append(ste.getLineNumber());
  193. ret.append(")\n");
  194. }
  195. return ret.toString();
  196. }
  197. }
  198. private class SamplerThread implements Runnable {
  199. private boolean running = false;
  200. private boolean shouldRun = false;
  201. private Thread rthread;
  202. public void start() {
  203. if (!running) {
  204. shouldRun = true;
  205. rthread = new Thread(this, "CPU Sampling Thread");
  206. rthread.start();
  207. running = true;
  208. }
  209. }
  210. public void stop() {
  211. this.shouldRun = false;
  212. rthread.interrupt();
  213. try {
  214. rthread.join();
  215. } catch (InterruptedException e) {
  216. e.printStackTrace();
  217. }
  218. }
  219. @Override
  220. public void run() {
  221. while (shouldRun) {
  222. consumeStackTraces(Thread.getAllStackTraces());
  223. try {
  224. Thread.sleep(interval);
  225. } catch (InterruptedException e) {
  226. return;
  227. }
  228. }
  229. }
  230. }
  231. public static class StacktraceWithCount implements Comparable<StacktraceWithCount> {
  232. private int count;
  233. private StackTrace trace;
  234. public StacktraceWithCount(int count, StackTrace trace) {
  235. super();
  236. this.count = count;
  237. this.trace = trace;
  238. }
  239. public int getCount() {
  240. return count;
  241. }
  242. public StackTraceElement[] getTrace() {
  243. return trace.getTrace();
  244. }
  245. @Override
  246. public int compareTo(StacktraceWithCount o) {
  247. return -Integer.valueOf(count).compareTo(Integer.valueOf(o.count));
  248. }
  249. @Override
  250. public String toString() {
  251. return count + " Sampled Invocations\n" + trace.toString();
  252. }
  253. private double getPercentage(int total) {
  254. return Math.round((((double) count) / total) * 10000.0) / 100.0;
  255. }
  256. public String toString(int totalInvoations, int traceLength) {
  257. return count + "/" + totalInvoations + " Sampled Invocations (" + getPercentage(totalInvoations) + "%) " +
  258. trace.toString(traceLength);
  259. }
  260. }
  261. public static class SampledStacktraces {
  262. List<StacktraceWithCount> topConsumers;
  263. int totalInvocations;
  264. public SampledStacktraces(List<StacktraceWithCount> topConsumers, int totalInvocations) {
  265. super();
  266. this.topConsumers = topConsumers;
  267. this.totalInvocations = totalInvocations;
  268. }
  269. public List<StacktraceWithCount> getTopConsumers() {
  270. return topConsumers;
  271. }
  272. public int getTotalInvocations() {
  273. return totalInvocations;
  274. }
  275. @Override
  276. public String toString() {
  277. return toString(0);
  278. }
  279. public String toString(int minInvocation) {
  280. StringBuilder ret = new StringBuilder();
  281. for (StacktraceWithCount swc : topConsumers) {
  282. if (swc.getCount() >= minInvocation) {
  283. ret.append(swc.toString(totalInvocations, Integer.MAX_VALUE));
  284. ret.append("\n");
  285. }
  286. }
  287. return ret.toString();
  288. }
  289. }
  290. }