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.Overflow;
028    import org.crsh.text.ui.RowElement;
029    import org.crsh.text.ui.TableElement;
030    import org.crsh.util.Utils;
031    
032    import java.lang.management.ManagementFactory;
033    import java.lang.management.ThreadMXBean;
034    import java.util.Collections;
035    import java.util.Comparator;
036    import java.util.EnumMap;
037    import java.util.HashMap;
038    import java.util.Iterator;
039    import java.util.List;
040    import java.util.Map;
041    
042    public class ThreadRenderable extends Renderable<Thread> {
043    
044      /** . */
045      private static final EnumMap<Thread.State, Color> colorMapping = new EnumMap<Thread.State, Color>(Thread.State.class);
046    
047      static {
048        colorMapping.put(Thread.State.NEW, Color.cyan);
049        colorMapping.put(Thread.State.RUNNABLE, Color.green);
050        colorMapping.put(Thread.State.BLOCKED, Color.red);
051        colorMapping.put(Thread.State.WAITING, Color.yellow);
052        colorMapping.put(Thread.State.TIMED_WAITING, Color.magenta);
053        colorMapping.put(Thread.State.TERMINATED, Color.blue);
054      }
055    
056      @Override
057      public Class<Thread> getType() {
058        return Thread.class;
059      }
060    
061      @Override
062      public Renderer renderer(Iterator<Thread> stream) {
063    
064        //
065        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
066    
067        //
068        List<Thread> threads = Utils.list(stream);
069    
070        // Sample CPU
071        Map<Long, Long> times1 = new HashMap<Long, Long>();
072        for (Thread thread : threads) {
073          long cpu = threadMXBean.getThreadCpuTime(thread.getId());
074          times1.put(thread.getId(), cpu);
075        }
076    
077        try {
078          // Sleep 100ms
079          Thread.sleep(100);
080        }
081        catch (InterruptedException e) {
082        }
083    
084        // Resample
085        Map<Long, Long> times2 = new HashMap<Long, Long>(threads.size());
086        for (Thread thread : threads) {
087          long cpu = threadMXBean.getThreadCpuTime(thread.getId());
088          times2.put(thread.getId(), cpu);
089        }
090    
091        // Compute delta map and total time
092        long total = 0;
093        Map<Long, Long> deltas = new HashMap<Long, Long>(threads.size());
094        for (Long id : times2.keySet()) {
095          long time1 = times2.get(id);
096          long time2 = times1.get(id);
097          if (time1 == -1) {
098            time1 = time2;
099          } else if (time2 == -1) {
100            time2 = time1;
101          }
102          long delta = time2 - time1;
103          deltas.put(id, delta);
104          total += delta;
105        }
106    
107        // Compute cpu
108        final HashMap<Thread, Long> cpus = new HashMap<Thread, Long>(threads.size());
109        for (Thread thread : threads) {
110          long cpu = total == 0 ? 0 : Math.round((deltas.get(thread.getId()) * 100) / total);
111          cpus.put(thread, cpu);
112        }
113    
114        // Sort by CPU time : should be a rendering hint...
115        Collections.sort(threads, new Comparator<Thread>() {
116          public int compare(Thread o1, Thread o2) {
117            long l1 = cpus.get(o1);
118            long l2 = cpus.get(o2);
119            if (l1 < l2) {
120              return 1;
121            } else if (l1 > l2) {
122              return -1;
123            } else {
124              return 0;
125            }
126          }
127        });
128    
129        //
130        TableElement table = new TableElement(1,3,2,1,1,1,1,1,1).overflow(Overflow.HIDDEN).rightCellPadding(1);
131    
132        // Header
133        RowElement header = new RowElement();
134        header.style(Decoration.bold.fg(Color.black).bg(Color.white));
135        header.add(new LabelElement("ID"));
136        header.add(new LabelElement("NAME"));
137        header.add(new LabelElement("GROUP"));
138        header.add(new LabelElement("PRIORITY"));
139        header.add(new LabelElement("STATE"));
140        header.add(new LabelElement("%CPU"));
141        header.add(new LabelElement("TIME"));
142        header.add(new LabelElement("INTERRUPTED"));
143        header.add(new LabelElement("DAEMON"));
144        table.add(header);
145    
146        //
147        for (Thread thread : threads) {
148          Color c = colorMapping.get(thread.getState());
149          long seconds = times2.get(thread.getId()) / 1000000000;
150          long min = seconds / 60;
151          String time = min + ":" + (seconds % 60);
152          long cpu = cpus.get(thread);
153    
154          //
155          ThreadGroup group = thread.getThreadGroup();
156    
157          //
158          RowElement row = new RowElement();
159          row.add(new LabelElement(thread.getId()));
160          row.add(new LabelElement(thread.getName()));
161          row.add(new LabelElement(group == null ? "" : group.getName()));
162          row.add(new LabelElement(thread.getPriority()));
163          row.add(new LabelElement(thread.getState()).style(c.fg()));
164          row.add(new LabelElement(cpu));
165          row.add(new LabelElement(time));
166          row.add(new LabelElement(thread.isInterrupted()));
167          row.add(new LabelElement(thread.isDaemon()));
168          table.add(row);
169        }
170    
171        //
172        return table.renderer();
173      }
174    }