您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

TracingEventQueue.java 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * Copyright (c) 2007, Kirill Grouchnikov
  3. * All rights reserved.
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. * - Redistributions of source code must retain the above copyright notice,
  7. * this list of conditions and the following disclaimer.
  8. * - Redistributions in binary form must reproduce the above copyright notice,
  9. * this list of conditions and the following disclaimer in the documentation
  10. * and/or other materials provided with the distribution.
  11. * - Neither the name of the <ORGANIZATION> nor the names of its contributors
  12. * may be used to endorse or promote products derived from this software
  13. * without specific prior written permission.
  14. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  15. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  18. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  19. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  20. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  21. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  22. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  23. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  24. * POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. package com.dmdirc.addons.swingdebug;
  27. import com.dmdirc.addons.ui_swing.DMDircEventQueue;
  28. import com.dmdirc.addons.ui_swing.SwingController;
  29. import com.dmdirc.config.IdentityManager;
  30. import com.dmdirc.interfaces.ConfigChangeListener;
  31. import com.dmdirc.plugins.Plugin;
  32. import java.awt.AWTEvent;
  33. import java.lang.management.ManagementFactory;
  34. import java.lang.management.ThreadInfo;
  35. import java.lang.management.ThreadMXBean;
  36. import java.util.Collections;
  37. import java.util.HashMap;
  38. import java.util.Map;
  39. import java.util.Set;
  40. import javax.management.MBeanServer;
  41. import javax.management.ObjectName;
  42. /**
  43. * Event queue extention to monitor long running tasks on the EDT. Original
  44. * code found at http://today.java.net/lpt/a/433 modified to work as a DMDirc
  45. * plugin.
  46. */
  47. public class TracingEventQueue extends DMDircEventQueue implements
  48. Runnable, ConfigChangeListener {
  49. /** Threshold before event is considered long running. */
  50. private long thresholdDelay;
  51. /** Map of event to time started. */
  52. private final Map<AWTEvent, Long> eventTimeMap;
  53. /** Thread bean, used to get thread info. */
  54. private ThreadMXBean threadBean;
  55. /** boolean to end thread. */
  56. private boolean running = false;
  57. /** Parent plugin. */
  58. private final Plugin parentPlugin;
  59. /** Tracing thread. */
  60. private Thread tracingThread;
  61. /**
  62. * Instantiates a new tracing thread.
  63. *
  64. * @param parentPlugin Parent plugin
  65. * @param controller Swing controller
  66. */
  67. public TracingEventQueue(final Plugin parentPlugin,
  68. final SwingController controller) {
  69. super(controller);
  70. this.parentPlugin = parentPlugin;
  71. eventTimeMap = Collections.synchronizedMap(
  72. new HashMap<AWTEvent, Long>());
  73. IdentityManager.getIdentityManager().getGlobalConfiguration().addChangeListener(
  74. parentPlugin.getDomain(), "debugEDT", this);
  75. IdentityManager.getIdentityManager().getGlobalConfiguration().addChangeListener(
  76. parentPlugin.getDomain(), "slowedttaskthreshold", this);
  77. checkTracing();
  78. try {
  79. final MBeanServer mbeanServer = ManagementFactory
  80. .getPlatformMBeanServer();
  81. final ObjectName objName = new ObjectName(
  82. ManagementFactory.THREAD_MXBEAN_NAME);
  83. final Set<ObjectName> mbeans = mbeanServer.queryNames(objName,
  84. null);
  85. for (final ObjectName name : mbeans) {
  86. threadBean = ManagementFactory.newPlatformMXBeanProxy(
  87. mbeanServer, name.toString(), ThreadMXBean.class);
  88. }
  89. } catch (final Exception e) {
  90. e.printStackTrace();
  91. }
  92. }
  93. /** {@inheritDoc} */
  94. @Override
  95. protected void preDispatchEvent(final AWTEvent event) {
  96. eventDispatched(event);
  97. }
  98. /** {@inheritDoc} */
  99. @Override
  100. protected void postDispatchEvent(final AWTEvent event) {
  101. eventProcessed(event);
  102. }
  103. /**
  104. * Marks the start time for the specified event.
  105. *
  106. * @param event Event to monitor
  107. */
  108. public void eventDispatched(final AWTEvent event) {
  109. eventTimeMap.put(event, System.currentTimeMillis());
  110. }
  111. /**
  112. * Marks the end time for the specified event.
  113. *
  114. * @param event Event to finish monitoring.
  115. */
  116. public void eventProcessed(final AWTEvent event) {
  117. checkEventTime(event, System.currentTimeMillis(),
  118. eventTimeMap.get(event));
  119. eventTimeMap.put(event, null);
  120. }
  121. /**
  122. * Check how long an event took, if over threshold notify user.
  123. *
  124. * @param event Event to check
  125. * @param currTime Current time
  126. * @param startTime Start time
  127. */
  128. private void checkEventTime(final AWTEvent event, final long currTime,
  129. final long startTime) {
  130. final long currProcessingTime = currTime - startTime;
  131. if (currProcessingTime >= thresholdDelay) {
  132. System.out.println("Event [" + event.hashCode() + "] "
  133. + event.getClass().getName()
  134. + " is taking too much time on EDT (" + currProcessingTime
  135. + ")");
  136. if (threadBean != null) {
  137. final long[] threadIds = threadBean.getAllThreadIds();
  138. for (final long threadId : threadIds) {
  139. final ThreadInfo threadInfo = threadBean.getThreadInfo(
  140. threadId, Integer.MAX_VALUE);
  141. if (threadInfo != null
  142. && threadInfo.getThreadName().startsWith(
  143. "AWT-EventQueue")) {
  144. System.out.println(threadInfo.getThreadName() + " / "
  145. + threadInfo.getThreadState());
  146. final StackTraceElement[] stack = threadInfo.getStackTrace();
  147. for (final StackTraceElement stackEntry : stack) {
  148. System.out.println("\t" + stackEntry.getClassName()
  149. + "." + stackEntry.getMethodName() + " ["
  150. + stackEntry.getLineNumber() + "]");
  151. }
  152. }
  153. }
  154. final long[] deadlockedThreads = threadBean.findDeadlockedThreads();
  155. if (deadlockedThreads != null && deadlockedThreads.length > 0) {
  156. System.out.println("Deadlocked threads:");
  157. for (final long threadId : deadlockedThreads) {
  158. final ThreadInfo threadInfo = threadBean.getThreadInfo(
  159. threadId, Integer.MAX_VALUE);
  160. System.out.println(threadInfo.getThreadName() + " / "
  161. + threadInfo.getThreadState());
  162. final StackTraceElement[] stack = threadInfo.getStackTrace();
  163. for (final StackTraceElement stackEntry : stack) {
  164. System.out.println("\t" + stackEntry.getClassName()
  165. + "." + stackEntry.getMethodName() + " ["
  166. + stackEntry.getLineNumber() + "]");
  167. }
  168. }
  169. }
  170. }
  171. }
  172. }
  173. /** {@inheritDoc} */
  174. @Override
  175. public void run() {
  176. running = true;
  177. while (running) {
  178. final long currTime = System.currentTimeMillis();
  179. synchronized (eventTimeMap) {
  180. for (final Map.Entry<AWTEvent, Long> entry : eventTimeMap
  181. .entrySet()) {
  182. final AWTEvent event = entry.getKey();
  183. if (entry.getValue() == null) {
  184. continue;
  185. }
  186. final long startTime = entry.getValue();
  187. checkEventTime(event, currTime, startTime);
  188. }
  189. }
  190. try {
  191. Thread.sleep(thresholdDelay);
  192. } catch (final InterruptedException ie) {
  193. // Ignore
  194. }
  195. }
  196. }
  197. /**
  198. * Cancels this thread.
  199. */
  200. public void cancel() {
  201. running = false;
  202. }
  203. private void checkTracing() {
  204. final boolean tracing = IdentityManager.getIdentityManager().getGlobalConfiguration()
  205. .getOptionBool(parentPlugin.getDomain(), "debugEDT");
  206. thresholdDelay = IdentityManager.getIdentityManager().getGlobalConfiguration()
  207. .getOptionInt(parentPlugin.getDomain(), "slowedttaskthreshold");
  208. if (tracing) {
  209. running = true;
  210. tracingThread = new Thread(this);
  211. tracingThread.start();
  212. } else {
  213. running = false;
  214. }
  215. }
  216. /** {@inheritDoc} */
  217. @Override
  218. public void configChanged(final String domain, final String key) {
  219. checkTracing();
  220. }
  221. }