001 /*
002 * Copyright (C) 2012 eXo Platform SAS.
003 *
004 * This is free software; you can redistribute it and/or modify it
005 * under the terms of the GNU Lesser General Public License as
006 * published by the Free Software Foundation; either version 2.1 of
007 * the License, or (at your option) any later version.
008 *
009 * This software is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public
015 * License along with this software; if not, write to the Free
016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018 */
019
020 package org.crsh.text.formatter;
021
022 import org.crsh.text.Color;
023 import org.crsh.text.Decoration;
024 import org.crsh.text.Renderable;
025 import org.crsh.text.Renderer;
026 import org.crsh.text.ui.LabelElement;
027 import org.crsh.text.ui.RowElement;
028 import org.crsh.text.ui.TableElement;
029 import org.crsh.util.Utils;
030
031 import java.lang.management.ManagementFactory;
032 import java.lang.management.ThreadMXBean;
033 import java.util.EnumMap;
034 import java.util.HashMap;
035 import java.util.Iterator;
036 import java.util.List;
037 import java.util.Map;
038
039 public class ThreadRenderable extends Renderable<Thread> {
040
041 /** . */
042 private static final EnumMap<Thread.State, Color> colorMapping = new EnumMap<Thread.State, Color>(Thread.State.class);
043
044 static {
045 colorMapping.put(Thread.State.NEW, Color.cyan);
046 colorMapping.put(Thread.State.RUNNABLE, Color.green);
047 colorMapping.put(Thread.State.BLOCKED, Color.red);
048 colorMapping.put(Thread.State.WAITING, Color.yellow);
049 colorMapping.put(Thread.State.TIMED_WAITING, Color.magenta);
050 colorMapping.put(Thread.State.TERMINATED, Color.blue);
051 }
052
053 @Override
054 public Class<Thread> getType() {
055 return Thread.class;
056 }
057
058 @Override
059 public Renderer renderer(Iterator<Thread> stream) {
060
061 //
062 ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
063
064 //
065 List<Thread> threads = Utils.list(stream);
066
067 // Sample CPU
068 Map<Long, Long> times1 = new HashMap<Long, Long>();
069 for (Thread thread : threads) {
070 long cpu = threadMXBean.getThreadCpuTime(thread.getId());
071 times1.put(thread.getId(), cpu);
072 }
073
074 try {
075 // Sleep 100ms
076 Thread.sleep(100);
077 }
078 catch (InterruptedException e) {
079 }
080
081 // Resample
082 Map<Long, Long> times2 = new HashMap<Long, Long>(threads.size());
083 for (Thread thread : threads) {
084 long cpu = threadMXBean.getThreadCpuTime(thread.getId());
085 times2.put(thread.getId(), cpu);
086 }
087
088 // Compute delta map and total time
089 long total = 0;
090 Map<Long, Long> deltas = new HashMap<Long, Long>(threads.size());
091 for (Long id : times2.keySet()) {
092 long time1 = times2.get(id);
093 long time2 = times1.get(id);
094 if (time1 == -1) {
095 time1 = time2;
096 } else if (time2 == -1) {
097 time2 = time1;
098 }
099 long delta = time2 - time1;
100 deltas.put(id, delta);
101 total += delta;
102 }
103
104 //
105 TableElement table = new TableElement(1,1,1,1,1,1,1,2,5);
106
107 // Header
108 RowElement header = new RowElement();
109 header.style(Decoration.bold.fg(Color.black).bg(Color.white));
110 header.add(new LabelElement("ID"));
111 header.add(new LabelElement("PRIORITY"));
112 header.add(new LabelElement("STATE"));
113 header.add(new LabelElement("%CPU"));
114 header.add(new LabelElement("TIME"));
115 header.add(new LabelElement("INTERRUPTED"));
116 header.add(new LabelElement("DAEMON"));
117 header.add(new LabelElement("GROUP"));
118 header.add(new LabelElement("NAME"));
119 table.add(header);
120
121 //
122 for (Thread thread : threads) {
123 Color c = colorMapping.get(thread.getState());
124 long seconds = times2.get(thread.getId()) / 1000000000;
125 long min = seconds / 60;
126 String time = min + ":" + (seconds % 60);
127 long cpu = Math.round((deltas.get(thread.getId()) * 100) / total);
128
129 //
130 ThreadGroup group = thread.getThreadGroup();
131
132 //
133 RowElement row = new RowElement();
134 row.style(c.bg().fg(Color.black));
135 row.add(new LabelElement(thread.getId()));
136 row.add(new LabelElement(thread.getPriority()));
137 row.add(new LabelElement(thread.getState()));
138 row.add(new LabelElement(cpu));
139 row.add(new LabelElement(time));
140 row.add(new LabelElement(thread.isInterrupted()));
141 row.add(new LabelElement(thread.isDaemon()));
142 row.add(new LabelElement(group == null ? "" : group.getName()));
143 row.add(new LabelElement(thread.getName()));
144 table.add(row);
145 }
146
147 //
148 return table.renderer();
149 }
150 }