PageRenderTime 26ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/share/demo/management/JTop/JTop.java

https://github.com/ikeji/openjdk7-jdk
Java | 375 lines | 217 code | 39 blank | 119 comment | 15 complexity | 4c33ac017e30454b72e4318c2980c823 MD5 | raw file
  1. /*
  2. * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * - Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. *
  11. * - Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. *
  15. * - Neither the name of Oracle nor the names of its
  16. * contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  20. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  21. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  23. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  24. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  26. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  27. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. /*
  32. *
  33. * Example of using the java.lang.management API to sort threads
  34. * by CPU usage.
  35. *
  36. * JTop class can be run as a standalone application.
  37. * It first establishs a connection to a target VM specified
  38. * by the given hostname and port number where the JMX agent
  39. * to be connected. It then polls for the thread information
  40. * and the CPU consumption of each thread to display every 2
  41. * seconds.
  42. *
  43. * It is also used by JTopPlugin which is a JConsolePlugin
  44. * that can be used with JConsole (see README.txt). The JTop
  45. * GUI will be added as a JConsole tab by the JTop plugin.
  46. *
  47. * @see com.sun.tools.jconsole.JConsolePlugin
  48. *
  49. * @author Mandy Chung
  50. */
  51. import java.lang.management.*;
  52. import javax.management.*;
  53. import javax.management.remote.*;
  54. import java.io.IOException;
  55. import java.util.ArrayList;
  56. import java.util.Collections;
  57. import java.util.List;
  58. import java.util.Map;
  59. import java.util.Set;
  60. import java.util.SortedMap;
  61. import java.util.Timer;
  62. import java.util.TimerTask;
  63. import java.util.TreeMap;
  64. import java.util.concurrent.ExecutionException;
  65. import java.text.NumberFormat;
  66. import java.net.MalformedURLException;
  67. import static java.lang.management.ManagementFactory.*;
  68. import java.awt.*;
  69. import javax.swing.*;
  70. import javax.swing.border.*;
  71. import javax.swing.table.*;
  72. /**
  73. * JTop is a JPanel to display thread's name, CPU time, and its state
  74. * in a table.
  75. */
  76. public class JTop extends JPanel {
  77. private static final long serialVersionUID = -1499762160973870696L;
  78. private MBeanServerConnection server;
  79. private ThreadMXBean tmbean;
  80. private MyTableModel tmodel;
  81. public JTop() {
  82. super(new GridLayout(1,0));
  83. tmodel = new MyTableModel();
  84. JTable table = new JTable(tmodel);
  85. table.setPreferredScrollableViewportSize(new Dimension(500, 300));
  86. // Set the renderer to format Double
  87. table.setDefaultRenderer(Double.class, new DoubleRenderer());
  88. // Add some space
  89. table.setIntercellSpacing(new Dimension(6,3));
  90. table.setRowHeight(table.getRowHeight() + 4);
  91. // Create the scroll pane and add the table to it.
  92. JScrollPane scrollPane = new JScrollPane(table);
  93. // Add the scroll pane to this panel.
  94. add(scrollPane);
  95. }
  96. // Set the MBeanServerConnection object for communicating
  97. // with the target VM
  98. public void setMBeanServerConnection(MBeanServerConnection mbs) {
  99. this.server = mbs;
  100. try {
  101. this.tmbean = newPlatformMXBeanProxy(server,
  102. THREAD_MXBEAN_NAME,
  103. ThreadMXBean.class);
  104. } catch (IOException e) {
  105. e.printStackTrace();
  106. }
  107. if (!tmbean.isThreadCpuTimeSupported()) {
  108. System.err.println("This VM does not support thread CPU time monitoring");
  109. } else {
  110. tmbean.setThreadCpuTimeEnabled(true);
  111. }
  112. }
  113. class MyTableModel extends AbstractTableModel {
  114. private static final long serialVersionUID = -7877310288576779514L;
  115. private String[] columnNames = {"ThreadName",
  116. "CPU(sec)",
  117. "State"};
  118. // List of all threads. The key of each entry is the CPU time
  119. // and its value is the ThreadInfo object with no stack trace.
  120. private List<Map.Entry<Long, ThreadInfo>> threadList =
  121. Collections.emptyList();
  122. public MyTableModel() {
  123. }
  124. @Override
  125. public int getColumnCount() {
  126. return columnNames.length;
  127. }
  128. @Override
  129. public int getRowCount() {
  130. return threadList.size();
  131. }
  132. @Override
  133. public String getColumnName(int col) {
  134. return columnNames[col];
  135. }
  136. @Override
  137. public Object getValueAt(int row, int col) {
  138. Map.Entry<Long, ThreadInfo> me = threadList.get(row);
  139. switch (col) {
  140. case 0 :
  141. // Column 0 shows the thread name
  142. return me.getValue().getThreadName();
  143. case 1 :
  144. // Column 1 shows the CPU usage
  145. long ns = me.getKey().longValue();
  146. double sec = ns / 1000000000;
  147. return new Double(sec);
  148. case 2 :
  149. // Column 2 shows the thread state
  150. return me.getValue().getThreadState();
  151. default:
  152. return null;
  153. }
  154. }
  155. @Override
  156. public Class<?> getColumnClass(int c) {
  157. return getValueAt(0, c).getClass();
  158. }
  159. void setThreadList(List<Map.Entry<Long, ThreadInfo>> list) {
  160. threadList = list;
  161. }
  162. }
  163. /**
  164. * Get the thread list with CPU consumption and the ThreadInfo
  165. * for each thread sorted by the CPU time.
  166. */
  167. private List<Map.Entry<Long, ThreadInfo>> getThreadList() {
  168. // Get all threads and their ThreadInfo objects
  169. // with no stack trace
  170. long[] tids = tmbean.getAllThreadIds();
  171. ThreadInfo[] tinfos = tmbean.getThreadInfo(tids);
  172. // build a map with key = CPU time and value = ThreadInfo
  173. SortedMap<Long, ThreadInfo> map = new TreeMap<Long, ThreadInfo>();
  174. for (int i = 0; i < tids.length; i++) {
  175. long cpuTime = tmbean.getThreadCpuTime(tids[i]);
  176. // filter out threads that have been terminated
  177. if (cpuTime != -1 && tinfos[i] != null) {
  178. map.put(new Long(cpuTime), tinfos[i]);
  179. }
  180. }
  181. // build the thread list and sort it with CPU time
  182. // in decreasing order
  183. Set<Map.Entry<Long, ThreadInfo>> set = map.entrySet();
  184. List<Map.Entry<Long, ThreadInfo>> list =
  185. new ArrayList<Map.Entry<Long, ThreadInfo>>(set);
  186. Collections.reverse(list);
  187. return list;
  188. }
  189. /**
  190. * Format Double with 4 fraction digits
  191. */
  192. class DoubleRenderer extends DefaultTableCellRenderer {
  193. private static final long serialVersionUID = 1704639497162584382L;
  194. NumberFormat formatter;
  195. public DoubleRenderer() {
  196. super();
  197. setHorizontalAlignment(JLabel.RIGHT);
  198. }
  199. @Override
  200. public void setValue(Object value) {
  201. if (formatter==null) {
  202. formatter = NumberFormat.getInstance();
  203. formatter.setMinimumFractionDigits(4);
  204. }
  205. setText((value == null) ? "" : formatter.format(value));
  206. }
  207. }
  208. // SwingWorker responsible for updating the GUI
  209. //
  210. // It first gets the thread and CPU usage information as a
  211. // background task done by a worker thread so that
  212. // it will not block the event dispatcher thread.
  213. //
  214. // When the worker thread finishes, the event dispatcher
  215. // thread will invoke the done() method which will update
  216. // the UI.
  217. class Worker extends SwingWorker<List<Map.Entry<Long, ThreadInfo>>,Object> {
  218. private MyTableModel tmodel;
  219. Worker(MyTableModel tmodel) {
  220. this.tmodel = tmodel;
  221. }
  222. // Get the current thread info and CPU time
  223. @Override
  224. public List<Map.Entry<Long, ThreadInfo>> doInBackground() {
  225. return getThreadList();
  226. }
  227. // fire table data changed to trigger GUI update
  228. // when doInBackground() is finished
  229. @Override
  230. protected void done() {
  231. try {
  232. // Set table model with the new thread list
  233. tmodel.setThreadList(get());
  234. // refresh the table model
  235. tmodel.fireTableDataChanged();
  236. } catch (InterruptedException e) {
  237. } catch (ExecutionException e) {
  238. }
  239. }
  240. }
  241. // Return a new SwingWorker for UI update
  242. public SwingWorker<?,?> newSwingWorker() {
  243. return new Worker(tmodel);
  244. }
  245. public static void main(String[] args) throws Exception {
  246. // Validate the input arguments
  247. if (args.length != 1) {
  248. usage();
  249. }
  250. String[] arg2 = args[0].split(":");
  251. if (arg2.length != 2) {
  252. usage();
  253. }
  254. String hostname = arg2[0];
  255. int port = -1;
  256. try {
  257. port = Integer.parseInt(arg2[1]);
  258. } catch (NumberFormatException x) {
  259. usage();
  260. }
  261. if (port < 0) {
  262. usage();
  263. }
  264. // Create the JTop Panel
  265. final JTop jtop = new JTop();
  266. // Set up the MBeanServerConnection to the target VM
  267. MBeanServerConnection server = connect(hostname, port);
  268. jtop.setMBeanServerConnection(server);
  269. // A timer task to update GUI per each interval
  270. TimerTask timerTask = new TimerTask() {
  271. @Override
  272. public void run() {
  273. // Schedule the SwingWorker to update the GUI
  274. jtop.newSwingWorker().execute();
  275. }
  276. };
  277. // Create the standalone window with JTop panel
  278. // by the event dispatcher thread
  279. SwingUtilities.invokeAndWait(new Runnable() {
  280. @Override
  281. public void run() {
  282. createAndShowGUI(jtop);
  283. }
  284. });
  285. // refresh every 2 seconds
  286. Timer timer = new Timer("JTop Sampling thread");
  287. timer.schedule(timerTask, 0, 2000);
  288. }
  289. // Establish a connection with the remote application
  290. //
  291. // You can modify the urlPath to the address of the JMX agent
  292. // of your application if it has a different URL.
  293. //
  294. // You can also modify the following code to take
  295. // username and password for client authentication.
  296. private static MBeanServerConnection connect(String hostname, int port) {
  297. // Create an RMI connector client and connect it to
  298. // the RMI connector server
  299. String urlPath = "/jndi/rmi://" + hostname + ":" + port + "/jmxrmi";
  300. MBeanServerConnection server = null;
  301. try {
  302. JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath);
  303. JMXConnector jmxc = JMXConnectorFactory.connect(url);
  304. server = jmxc.getMBeanServerConnection();
  305. } catch (MalformedURLException e) {
  306. // should not reach here
  307. } catch (IOException e) {
  308. System.err.println("\nCommunication error: " + e.getMessage());
  309. System.exit(1);
  310. }
  311. return server;
  312. }
  313. private static void usage() {
  314. System.out.println("Usage: java JTop <hostname>:<port>");
  315. System.exit(1);
  316. }
  317. /**
  318. * Create the GUI and show it. For thread safety,
  319. * this method should be invoked from the
  320. * event-dispatching thread.
  321. */
  322. private static void createAndShowGUI(JPanel jtop) {
  323. // Create and set up the window.
  324. JFrame frame = new JFrame("JTop");
  325. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  326. // Create and set up the content pane.
  327. JComponent contentPane = (JComponent) frame.getContentPane();
  328. contentPane.add(jtop, BorderLayout.CENTER);
  329. contentPane.setOpaque(true); //content panes must be opaque
  330. contentPane.setBorder(new EmptyBorder(12, 12, 12, 12));
  331. frame.setContentPane(contentPane);
  332. // Display the window.
  333. frame.pack();
  334. frame.setVisible(true);
  335. }
  336. }