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    }