Coverage Report - sk.baka.webvm.analyzer.hostos.Cpu
 
Classes in this File Line Coverage Branch Coverage Complexity
Cpu
61%
8/13
N/A
1.812
Cpu$1
N/A
N/A
1.812
Cpu$CpuUsageLinuxStrategy
86%
20/23
50%
3/6
1.812
Cpu$IOCpuUsageLinuxStrategy
95%
23/24
83%
5/6
1.812
Cpu$JavaCpuUsageStrategy
86%
20/23
50%
2/4
1.812
 
 1  
 /**
 2  
  * Copyright 2009 Martin Vysny.
 3  
  *
 4  
  * This file is part of WebVM.
 5  
  *
 6  
  * WebVM is free software: you can redistribute it and/or modify
 7  
  * it under the terms of the GNU General Public License as published by
 8  
  * the Free Software Foundation, either version 3 of the License, or
 9  
  * (at your option) any later version.
 10  
  *
 11  
  * WebVM is distributed in the hope that it will be useful,
 12  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  
  * GNU General Public License for more details.
 15  
  *
 16  
  * You should have received a copy of the GNU General Public License
 17  
  * along with WebVM.  If not, see <http://www.gnu.org/licenses/>.
 18  
  */
 19  
 package sk.baka.webvm.analyzer.hostos;
 20  
 
 21  
 import java.lang.management.OperatingSystemMXBean;
 22  
 import java.io.BufferedReader;
 23  
 import java.io.File;
 24  
 import java.io.FileReader;
 25  
 import java.lang.management.ManagementFactory;
 26  
 import java.util.Collections;
 27  
 import java.util.List;
 28  
 import java.util.StringTokenizer;
 29  
 import java.util.logging.Level;
 30  
 import java.util.logging.Logger;
 31  
 import sk.baka.tools.IOUtils;
 32  
 import sk.baka.webvm.analyzer.CpuUsage;
 33  
 import sk.baka.webvm.analyzer.ICpuUsageMeasure;
 34  
 import static sk.baka.webvm.misc.Constants.*;
 35  
 
 36  
 /**
 37  
  * Provides a CPU measurement support.
 38  
  * @author Martin Vysny
 39  
  */
 40  3
 public final class Cpu {
 41  
 
 42  
     /**
 43  
      * Creates a new measurer for Host OS CPU usage.
 44  
      * @return the CPU measurer, never null.
 45  
      */
 46  
     public static CpuUsage newHostCpu() {
 47  3
         return new CpuUsage(new CpuUsageLinuxStrategy());
 48  
     }
 49  1
     private static final CpuUsage HOST_CPU = newHostCpu();
 50  
 
 51  
     /**
 52  
      * Checks if Host OS CPU usage measurement is supported.
 53  
      * @return true if supported.
 54  
      */
 55  
     public static boolean isHostCpuSupported() {
 56  0
         return HOST_CPU.supported();
 57  
     }
 58  
 
 59  
     /**
 60  
      * Creates a new measurer for Host OS CPU IO usage (% of time spent waiting for IO).
 61  
      * @return the CPU measurer, never null.
 62  
      */
 63  
     public static CpuUsage newHostIOCpu() {
 64  3
         return new CpuUsage(new IOCpuUsageLinuxStrategy());
 65  
     }
 66  1
     private static final CpuUsage HOST_IO_CPU = newHostIOCpu();
 67  
 
 68  
     /**
 69  
      * Checks if measurer for Host OS CPU IO usage (% of time spent waiting for IO) is supported.
 70  
      * @return true if supported.
 71  
      */
 72  
     public static boolean isHostIOCpuSupported() {
 73  0
         return HOST_IO_CPU.supported();
 74  
     }
 75  
 
 76  
     /**
 77  
      * Creates a new measurer for CPU used by the owner java process.
 78  
      * @return the CPU measurer, never null.
 79  
      */
 80  
     public static CpuUsage newJavaCpu() {
 81  3
         return new CpuUsage(new JavaCpuUsageStrategy());
 82  
     }
 83  1
     private static final CpuUsage JAVA_CPU = newJavaCpu();
 84  
 
 85  
     /**
 86  
      * Checks if measurer for CPU used by the owner java process is supported.
 87  
      * @return true if supported.
 88  
      */
 89  
     public static boolean isJavaCpuSupported() {
 90  0
         return JAVA_CPU.supported();
 91  
     }
 92  
 
 93  
     /**
 94  
      * Returns a Host OS CPU usage information.
 95  
      */
 96  6
     private static class CpuUsageLinuxStrategy implements ICpuUsageMeasure {
 97  
 
 98  1
         private static final File PROC_STAT = new File("/proc/stat");
 99  
 
 100  
         public boolean supported() {
 101  3
             return PROC_STAT.exists();
 102  
         }
 103  
 
 104  
         public Object measure() throws Exception {
 105  
             // the object is really an array of longs: [user, nice, system, idle].
 106  
             // To compute the CPU usage, we have to perform:
 107  
             // (idle2-idle1)*HUNDRED_PERCENT/(user2+nice2+system2+idle2-user1-nice1-system1-idle1)
 108  2
             final BufferedReader in = new BufferedReader(new FileReader(PROC_STAT));
 109  
             try {
 110  2
                 for (String line = in.readLine(); line != null; line = in.readLine()) {
 111  2
                     if (line.startsWith("cpu ")) {
 112  2
                         final StringTokenizer t = new StringTokenizer(line);
 113  2
                         t.nextToken();
 114  2
                         final long user = Long.parseLong(t.nextToken());
 115  2
                         final long nice = Long.parseLong(t.nextToken());
 116  2
                         final long system = Long.parseLong(t.nextToken());
 117  2
                         final long idle = Long.parseLong(t.nextToken());
 118  2
                         return new long[]{user, nice, system, idle};
 119  
                     }
 120  
                 }
 121  
             } finally {
 122  2
                 IOUtils.closeQuietly(in);
 123  0
             }
 124  0
             throw new IllegalStateException("No cpu line");
 125  
         }
 126  
         private static final int MEASURE_USER = 0;
 127  
         private static final int MEASURE_NICE = 1;
 128  
         private static final int MEASURE_SYSTEM = 2;
 129  
         private static final int MEASURE_IDLE = 3;
 130  
 
 131  
         public int getAvgCpuUsage(Object m1, Object m2) {
 132  1
             final long[] me1 = (long[]) m1;
 133  1
             final long[] me2 = (long[]) m2;
 134  1
             final long sampleTimeDelta = me2[MEASURE_USER] + me2[MEASURE_NICE] + me2[MEASURE_SYSTEM] + me2[MEASURE_IDLE] -
 135  
                     me1[MEASURE_USER] - me1[MEASURE_NICE] - me1[MEASURE_SYSTEM] - me1[MEASURE_IDLE];
 136  1
             if (sampleTimeDelta <= 0) {
 137  0
                 return 0;
 138  
             }
 139  1
             final long cpuIdle = (me2[MEASURE_IDLE] - me1[MEASURE_IDLE]) * HUNDRED_PERCENT / sampleTimeDelta;
 140  1
             return HUNDRED_PERCENT - ((int) cpuIdle);
 141  
         }
 142  
     }
 143  
 
 144  
     /**
 145  
      * Returns a Host OS CPU time waiting for IO.
 146  
      */
 147  6
     private static class IOCpuUsageLinuxStrategy implements ICpuUsageMeasure {
 148  
 
 149  1
         private final static File DISKSTATS = new File("/proc/diskstats");
 150  
 
 151  
         public boolean supported() {
 152  3
             return DISKSTATS.exists();
 153  
         }
 154  
 
 155  
         public Object measure() throws Exception {
 156  
             // the object is really an array of longs: [weightedMillisSpentIO, currentTimeMillis].
 157  
             // To compute the CPU usage, we have to perform:
 158  
             // (weightedMillisSpentIO2-weightedMillisSpentIO1)*100/(currentTimeMillis2-currentTimeMillis1)
 159  2
             long weightedMillisSpentIOTotal = 0;
 160  2
             final BufferedReader in = new BufferedReader(new FileReader(DISKSTATS));
 161  2
             final long currentTimeMillis = System.currentTimeMillis();
 162  
             try {
 163  62
                 for (String line = in.readLine(); line != null; line = in.readLine()) {
 164  60
                     final StringTokenizer t = new StringTokenizer(line);
 165  60
                     final List<Object> tokens = Collections.list(t);
 166  60
                     final String devname = (String) tokens.get(DISKSTATS_DEVNAME);
 167  60
                     if (Character.isDigit(devname.charAt(devname.length() - 1))) {
 168  
                         // ignore sda2 etc - we are interested in sda only
 169  56
                         continue;
 170  
                     }
 171  4
                     final long weightedMillisSpentIO = Long.parseLong((String) tokens.get(DISKSTATS_MILLIS_SPENT_IO));
 172  4
                     weightedMillisSpentIOTotal += weightedMillisSpentIO;
 173  
                 }
 174  
             } finally {
 175  2
                 IOUtils.closeQuietly(in);
 176  2
             }
 177  2
             return new long[]{weightedMillisSpentIOTotal, currentTimeMillis};
 178  
         }
 179  
         private static final int MEASURE_MILLIS_SPENT_IO = 0;
 180  
         private static final int MEASURE_CURRENT_TIME_MILLIS = 1;
 181  
         private static final int DISKSTATS_DEVNAME = 2;
 182  
         private static final int DISKSTATS_MILLIS_SPENT_IO = 12;
 183  
 
 184  
         public int getAvgCpuUsage(Object m1, Object m2) {
 185  1
             final long[] me1 = (long[]) m1;
 186  1
             final long[] me2 = (long[]) m2;
 187  1
             final long sampleTimeDelta = me2[MEASURE_CURRENT_TIME_MILLIS] - me1[MEASURE_CURRENT_TIME_MILLIS];
 188  1
             if (sampleTimeDelta <= 0) {
 189  0
                 return 0;
 190  
             }
 191  1
             long cpuSpentIO = (me2[MEASURE_MILLIS_SPENT_IO] - me1[MEASURE_MILLIS_SPENT_IO]) * HUNDRED_PERCENT / sampleTimeDelta / NUMBER_OF_PROCESSORS;
 192  1
             return (int) cpuSpentIO;
 193  
         }
 194  
     }
 195  1
     private final static int NUMBER_OF_PROCESSORS = Runtime.getRuntime().availableProcessors();
 196  
 
 197  
     /**
 198  
      * Returns the Java process CPU usage information.
 199  
      */
 200  6
     private static class JavaCpuUsageStrategy implements ICpuUsageMeasure {
 201  
 
 202  
         private static final OperatingSystemMXBean BEAN;
 203  
         private static final Class<?> BEAN_CLASS;
 204  1
         private static final Logger log = Logger.getLogger(JavaCpuUsageStrategy.class.getName());
 205  
 
 206  
 
 207  
         static {
 208  1
             OperatingSystemMXBean b = null;
 209  1
             Class<?> clazz = null;
 210  
             try {
 211  1
                 clazz = Class.forName("com.sun.management.OperatingSystemMXBean");
 212  1
                 b = OperatingSystemMXBean.class.cast(clazz.cast(ManagementFactory.getOperatingSystemMXBean()));
 213  0
             } catch (Throwable ex) {
 214  0
                 log.log(Level.INFO, "MemoryJMXStrategy disabled: com.sun.management.OperatingSystemMXBean unavailable", ex);
 215  1
             }
 216  1
             BEAN = b;
 217  1
             BEAN_CLASS = clazz;
 218  1
         }
 219  
 
 220  
         public boolean supported() {
 221  3
             return BEAN != null;
 222  
         }
 223  
 
 224  
         public Object measure() throws Exception {
 225  2
             long processCpuTime = (Long) BEAN_CLASS.getMethod("getProcessCpuTime").invoke(BEAN);
 226  2
             processCpuTime = processCpuTime / NUMBER_OF_PROCESSORS;
 227  2
             long totalCpuTime = System.nanoTime();
 228  2
             return new long[]{processCpuTime, totalCpuTime};
 229  
         }
 230  
         private static final int TOTAL_CPU_TIME = 1;
 231  
         private static final int PROCESS_CPU_TIME = 0;
 232  
 
 233  
         public int getAvgCpuUsage(Object m1, Object m2) {
 234  1
             final long[] me1 = (long[]) m1;
 235  1
             final long[] me2 = (long[]) m2;
 236  1
             final long sampleTimeDelta = me2[TOTAL_CPU_TIME] - me1[TOTAL_CPU_TIME];
 237  1
             if (sampleTimeDelta <= 0) {
 238  0
                 return 0;
 239  
             }
 240  1
             return (int) ((me2[PROCESS_CPU_TIME] - me1[PROCESS_CPU_TIME]) * HUNDRED_PERCENT / sampleTimeDelta);
 241  
         }
 242  
     }
 243  
 
 244  0
     private Cpu() {
 245  0
         throw new AssertionError();
 246  
     }
 247  
 }