All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gemstone.gemfire.internal.LinuxProcFsStatistics Maven / Gradle / Ivy

There is a newer version: 2.0-BETA
Show newest version
/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License. You
 * may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License. See accompanying
 * LICENSE file.
 */
/*
 * Changes for SnappyData data platform.
 *
 * Portions Copyright (c) 2018 SnappyData, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License. You
 * may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License. See accompanying
 * LICENSE file.
 */

package com.gemstone.gemfire.internal;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.gemstone.gemfire.GemFireIOException;
import com.gemstone.gemfire.LogWriter;
import com.gemstone.gemfire.internal.shared.NativeCalls;

public class LinuxProcFsStatistics {
  private enum CPU { 
    USER, NICE, SYSTEM, IDLE, IOWAIT, IRQ, SOFTIRQ,
    /** stands for aggregation of all columns not present in the enum list*/
    OTHER
  }  
  
  private static final int DEFAULT_PAGESIZE = 4 * 1024; 
  private static final int OneMeg = 1024 * 1024; 
  private static final String pageSizeProperty = "gemfire.statistics.linux.pageSize"; 
  private static CpuStat cpuStatSingleton;
  private static int pageSize;
  private static int sys_cpus;
  private static boolean hasProcVmStat;
  private static boolean hasDiskStats;
  static SpaceTokenizer st;
 
  /** The number of non-process files in /proc */
  private static int nonPidFilesInProc;

  /** /proc/stat tokens */
  private static final String CPU_TOKEN = "cpu ";
  private static final String PAGE = "page ";
  private static final String SWAP = "swap ";
  private static final String CTXT = "ctxt ";
  private static final String PROCESSES = "processes ";
  
  /** /proc/vmstat tokens */
  private static final String PGPGIN = "pgpgin ";
  private static final String PGPGOUT = "pgpgout ";
  private static final String PSWPIN = "pswpin ";
  private static final String PSWPOUT = "pswpout ";

  private static File procFile;
  private static FileChannel fchannel;

  //Do not create instances of this class
  private LinuxProcFsStatistics() {
  }
  
  static int init() {
    nonPidFilesInProc = getNumberOfNonProcessProcFiles();
    sys_cpus = Runtime.getRuntime().availableProcessors();
    pageSize = Integer.getInteger(pageSizeProperty, DEFAULT_PAGESIZE);
    cpuStatSingleton = new CpuStat();
    hasProcVmStat = new File("/proc/vmstat").exists();
    hasDiskStats = new File("/proc/diskstats").exists();
    st = new SpaceTokenizer();
    procFile = new File( "/proc/" + NativeCalls.getInstance().getProcessId() + "/stat" );
    try {
      fchannel = new FileInputStream(procFile).getChannel();
    } catch (FileNotFoundException e) {
      throw new GemFireIOException(e.getMessage(), e);
    }
    return 0;
  }

  static void close() {
    cpuStatSingleton = null;
    st = null;
    try {
      fchannel.close();
    } catch (IOException e) {
      // ignore
    }
  }
  
  static void readyRefresh() {
  }
  
  /* get the statistics for the specified process. 
   * ( pid_rssSize, pid_imageSize )
   * vsize is assumed to be in units of kbytes
   * System property gemfire.statistics.pagesSize can be used to configure 
   * pageSize. This is the mem_unit member of the struct returned by sysinfo()
   * 
   */ 
  static void refreshProcess(int pid, int[] ints, long[] longs, double[] doubles) {
    //Just incase a pid is not available
    if (pid == 0) return;

    try {
      fchannel.position(0);
      Reader procFileReader = Channels.newReader(fchannel,
          Charset.defaultCharset().newDecoder(), -1);
      BufferedReader br = new BufferedReader(procFileReader, 2048);
      String line = br.readLine();
      if (line == null) {
        return;
      }
      st.setString(line);
      st.skipTokens(22);
      ints[LinuxProcessStats.imageSizeINT] = (int) (st.nextTokenAsLong() / OneMeg);
      ints[LinuxProcessStats.rssSizeINT] = (int) ((st.nextTokenAsLong()*pageSize)/OneMeg);
    } catch (NoSuchElementException | IOException ignored) {
      // It might just be a case of the process going away while we
      // where trying to get its stats. 
      // So for now lets just ignore the failure and leave the stats
      // as they are.
    } finally {
      st.releaseResources();
    }
  }

  static void refreshSystem(int[] ints, long[] longs, double[] doubles) {
    ints[LinuxSystemStats.processesINT] = getProcessCount();
    ints[LinuxSystemStats.cpusINT] = sys_cpus;
    getSystemFileDescriptorStats(longs);
    longs[LinuxSystemStats.threadsSessionMaxLONG] =
        NativeCalls.getInstance().getSessionThreadLimit();
    longs[LinuxSystemStats.threadsSystemMaxLONG] = getSystemThreadLimit();

    try (BufferedReader br = Files.newBufferedReader(Paths.get("/proc/stat"),
        StandardCharsets.UTF_8)) {
      String line = null;
      while ( ( line = br.readLine() ) != null ) {
        try {
          if (line.startsWith(CPU_TOKEN)) {
            int[] cpuData = cpuStatSingleton.calculateStats(line);
            ints[LinuxSystemStats.cpuIdleINT]   = cpuData[CPU.IDLE.ordinal()]; 
            ints[LinuxSystemStats.cpuNiceINT]   = cpuData[CPU.NICE.ordinal()];
            ints[LinuxSystemStats.cpuSystemINT] = cpuData[CPU.SYSTEM.ordinal()]; 
            ints[LinuxSystemStats.cpuUserINT]   = cpuData[CPU.USER.ordinal()];
            ints[LinuxSystemStats.iowaitINT]    = cpuData[CPU.IOWAIT.ordinal()];
            ints[LinuxSystemStats.irqINT]       = cpuData[CPU.IRQ.ordinal()];
            ints[LinuxSystemStats.softirqINT]   = cpuData[CPU.SOFTIRQ.ordinal()];          
            ints[LinuxSystemStats.cpuActiveINT] = 100 - cpuData[CPU.IDLE.ordinal()];
            ints[LinuxSystemStats.cpuNonUserINT] = cpuData[CPU.OTHER.ordinal()]
                                                   + cpuData[CPU.SYSTEM.ordinal()]
                                                   + cpuData[CPU.IOWAIT.ordinal()]
                                                   + cpuData[CPU.IRQ.ordinal()]
                                                   + cpuData[CPU.SOFTIRQ.ordinal()];
          } else if ( !hasProcVmStat && line.startsWith(PAGE)) {
            int secondIndex = line.indexOf(" ", PAGE.length());
            longs[LinuxSystemStats.pagesPagedInLONG] = SpaceTokenizer.parseAsLong(line.substring(PAGE.length(), secondIndex));
            longs[LinuxSystemStats.pagesPagedOutLONG] = SpaceTokenizer.parseAsLong(line.substring(secondIndex+1));
          } else if ( !hasProcVmStat && line.startsWith(SWAP)) {
            int secondIndex = line.indexOf(" ", SWAP.length());
            longs[LinuxSystemStats.pagesSwappedInLONG] = SpaceTokenizer.parseAsLong(line.substring(SWAP.length(), secondIndex));
            longs[LinuxSystemStats.pagesSwappedOutLONG] = SpaceTokenizer.parseAsLong(line.substring(secondIndex+1));
          } else if ( line.startsWith(CTXT)) {
            longs[LinuxSystemStats.contextSwitchesLONG] = SpaceTokenizer.parseAsLong(line.substring(CTXT.length()));    
          } else if ( line.startsWith(PROCESSES)) {
            longs[LinuxSystemStats.processCreatesLONG] = SpaceTokenizer.parseAsInt(line.substring(PROCESSES.length()));        
          }
        } catch ( NoSuchElementException nsee ) {
          //this is the result of reading a partially formed file
          //just do not update what ever entry had the problem
        }
      }
    } catch ( IOException ioe ) {
    }
    getLoadAvg(doubles, longs);
    getMemInfo(ints);
    getDiskStats(longs);
    getNetStats(longs);
    if(hasProcVmStat) {
      getVmStats(longs);
    }
    st.releaseResources();
  }

  // Example of /proc/loadavg
  // 0.00 0.00 0.07 1/218 7907
  private static void getLoadAvg(double[] doubles, long[] longs) {
    try {
      String line = getLineFromFile("/proc/loadavg");
      if ( line == null ) {
        return;
      }
      st.setString(line);
      doubles[LinuxSystemStats.loadAverage1DOUBLE] = st.nextTokenAsDouble();
      doubles[LinuxSystemStats.loadAverage5DOUBLE]  = st.nextTokenAsDouble();
      doubles[LinuxSystemStats.loadAverage15DOUBLE] = st.nextTokenAsDouble();
      // also read the total number of threads in the system
      String threadLoad = st.nextToken();
      if (threadLoad != null) {
        int slashIndex = threadLoad.indexOf('/');
        if (slashIndex >= 0) {
          threadLoad = threadLoad.substring(slashIndex + 1);
        }
        try {
          longs[LinuxSystemStats.totalThreadsLONG] = Long.parseLong(threadLoad);
        } catch (NumberFormatException ignored) {
        }
      }
    } catch (NoSuchElementException ignored) {
    } finally {
      st.releaseResources();
    }
  }

  /**
   * Returns the available system memory (free + cached).
   * @param logger the logger
   * @return the available memory in bytes
   */
  public static long getAvailableMemory(LogWriter logger) {
    try (BufferedReader br = Files.newBufferedReader(Paths.get("/proc/meminfo"),
        StandardCharsets.UTF_8)) {
      long free = 0;
      Pattern p = Pattern.compile("(.*)?:\\s+(\\d+)( kB)?");

      String line;
      while ((line = br.readLine()) != null) {
        Matcher m = p.matcher(line);
        if (m.matches() && ("MemFree".equals(m.group(1)) ||
            "Cached".equals(m.group(1)))) {
          free += Long.parseLong(m.group(2));
        }
      }

      // convert to bytes
      return 1024 * free;
    } catch (IOException e) {
      logger.warning("Error determining free memory", e);
      return Long.MAX_VALUE;
    }
  }
  
  // Example of /proc/meminfo
  //          total:    used:    free:  shared: buffers:  cached:
  //Mem:  4118380544 3816050688 302329856        0 109404160 3060326400
  //Swap: 4194881536 127942656 4066938880
  private static void getMemInfo(int[] ints) {
    try (BufferedReader br = Files.newBufferedReader(Paths.get("/proc/meminfo"),
        StandardCharsets.UTF_8)) {
      //Assume all values read in are in kB, convert to MB
      String line = null;
      while ( (line = br.readLine()) != null) {
        try {
          if ( line.startsWith("MemTotal: ")) {
            st.setString(line);
            st.skipToken(); //Burn initial token
            ints[LinuxSystemStats.physicalMemoryINT] = (int) (st.nextTokenAsLong() / 1024);
          } else if ( line.startsWith("MemFree: ")) {
            st.setString(line);
            st.skipToken(); //Burn initial token
            ints[LinuxSystemStats.freeMemoryINT] = (int) (st.nextTokenAsLong() / 1024);
          } else if ( line.startsWith("SharedMem: ")) {
           st.setString(line);
           st.skipToken(); //Burn initial token
           ints[LinuxSystemStats.sharedMemoryINT] = (int) (st.nextTokenAsLong() / 1024);
          } else if ( line.startsWith("Buffers: ")) {
            st.setString(line);
            st.nextToken(); //Burn initial token
            ints[LinuxSystemStats.bufferMemoryINT] = (int) (st.nextTokenAsLong() / 1024);
          } else if ( line.startsWith("SwapTotal: ")) {
            st.setString(line);
            st.skipToken(); //Burn initial token
            ints[LinuxSystemStats.allocatedSwapINT] = (int) (st.nextTokenAsLong() / 1024);
          } else if ( line.startsWith("SwapFree: ")) {
            st.setString(line);
            st.skipToken(); //Burn initial token
            ints[LinuxSystemStats.unallocatedSwapINT] = (int) (st.nextTokenAsLong() / 1024);
          } else if ( line.startsWith("Cached: ")) {
            st.setString(line);
            st.skipToken(); //Burn initial token
            ints[LinuxSystemStats.cachedMemoryINT] = (int) (st.nextTokenAsLong() / 1024);
          } else if ( line.startsWith("Dirty: ")) {
            st.setString(line);
            st.skipToken(); //Burn initial token
            ints[LinuxSystemStats.dirtyMemoryINT] = (int) (st.nextTokenAsLong() / 1024);
          } else if ( line.startsWith("Inact_dirty: ")) { // 2.4 kernels
            st.setString(line);
            st.skipToken(); //Burn initial token
            ints[LinuxSystemStats.dirtyMemoryINT] = (int) (st.nextTokenAsLong() / 1024);
          }
        } catch(NoSuchElementException nsee) {
          //ignore and let that stat not to be updated this time
        }
      }
    } catch (IOException ignored) {
    } finally {
      st.releaseResources();
    }
  }

  /*
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo:1908275823 326949246    0    0    0     0          0         0 1908275823 326949246    0    0    0     0       0          0
*/

  private static void getNetStats(long[] longs) {
    try (BufferedReader br = Files.newBufferedReader(Paths.get("/proc/net/dev"),
        StandardCharsets.UTF_8)) {
      br.readLine(); // Discard header info
      br.readLine(); // Discard header info
      long lo_recv_packets = 0, lo_recv_bytes = 0; 
      long other_recv_packets = 0, other_recv_bytes = 0; 
      long other_recv_errs    = 0, other_recv_drop  = 0; 
      long other_xmit_packets = 0, other_xmit_bytes = 0; 
      long other_xmit_errs    = 0, other_xmit_drop  = 0, other_xmit_colls = 0; 
      String line = null;
      while ( (line = br.readLine()) != null) {
        int index = line.indexOf(":");
        boolean isloopback = (line.indexOf("lo:") != -1);
        // skip leading spaces
        final int len = line.length();
        while (++index < len) {
          if (line.charAt(index) != ' ' && line.charAt(index) != '\t') break;
        }
        st.setString(line.substring(index));
        long recv_bytes   = st.nextTokenAsLong(); 
        long recv_packets = st.nextTokenAsLong(); 
        long recv_errs    = st.nextTokenAsLong(); 
        long recv_drop    = st.nextTokenAsLong(); 
        st.skipTokens(4); //fifo, frame, compressed, multicast
        long xmit_bytes   = st.nextTokenAsLong(); 
        long xmit_packets = st.nextTokenAsLong(); 
        long xmit_errs    = st.nextTokenAsLong(); 
        long xmit_drop    = st.nextTokenAsLong(); 
        st.skipToken(); //fifo
        long xmit_colls   = st.nextTokenAsLong(); 

        if (isloopback) {
          lo_recv_packets = recv_packets;
          lo_recv_bytes = recv_bytes;
        }
        else {
          other_recv_packets += recv_packets; 
          other_recv_bytes += recv_bytes;
        }
        other_recv_errs += recv_errs;
        other_recv_drop += recv_drop;

        if (isloopback) {
          /* loopback_xmit_packets = xmit_packets; */
        } else {
          other_xmit_packets += xmit_packets;
          other_xmit_bytes += xmit_bytes;
        }
        other_xmit_errs += xmit_errs;
        other_xmit_drop += xmit_drop;
        other_xmit_colls += xmit_colls;
      }
      // fix for bug 43860
      longs[LinuxSystemStats.loopbackPacketsLONG] = lo_recv_packets;
      longs[LinuxSystemStats.loopbackBytesLONG] = lo_recv_bytes;
      longs[LinuxSystemStats.recvPacketsLONG] = other_recv_packets;
      longs[LinuxSystemStats.recvBytesLONG] = other_recv_bytes;
      longs[LinuxSystemStats.recvErrorsLONG] = other_recv_errs;
      longs[LinuxSystemStats.recvDropsLONG] = other_recv_drop;
      longs[LinuxSystemStats.xmitPacketsLONG] = other_xmit_packets;
      longs[LinuxSystemStats.xmitBytesLONG] = other_xmit_bytes;
      longs[LinuxSystemStats.xmitErrorsLONG] = other_xmit_errs;
      longs[LinuxSystemStats.xmitDropsLONG] = other_xmit_drop;
      longs[LinuxSystemStats.xmitCollisionsLONG] = other_xmit_colls;
    } catch (NoSuchElementException | IOException ignored) {
    } finally {
      st.releaseResources();
    }
  }

  // example of /proc/diskstats
//    1    0 ram0 0 0 0 0 0 0 0 0 0 0 0
//    1    1 ram1 0 0 0 0 0 0 0 0 0 0 0
//    1    2 ram2 0 0 0 0 0 0 0 0 0 0 0
//    1    3 ram3 0 0 0 0 0 0 0 0 0 0 0
//    1    4 ram4 0 0 0 0 0 0 0 0 0 0 0
//    1    5 ram5 0 0 0 0 0 0 0 0 0 0 0
//    1    6 ram6 0 0 0 0 0 0 0 0 0 0 0
//    1    7 ram7 0 0 0 0 0 0 0 0 0 0 0
//    1    8 ram8 0 0 0 0 0 0 0 0 0 0 0
//    1    9 ram9 0 0 0 0 0 0 0 0 0 0 0
//    1   10 ram10 0 0 0 0 0 0 0 0 0 0 0
//    1   11 ram11 0 0 0 0 0 0 0 0 0 0 0
//    1   12 ram12 0 0 0 0 0 0 0 0 0 0 0
//    1   13 ram13 0 0 0 0 0 0 0 0 0 0 0
//    1   14 ram14 0 0 0 0 0 0 0 0 0 0 0
//    1   15 ram15 0 0 0 0 0 0 0 0 0 0 0
//    8    0 sda 1628761 56603 37715982 5690640 6073889 34091137 330349716 279787924 0 25235208 285650572
//    8    1 sda1 151 638 45 360
//    8    2 sda2 674840 11202608 8591346 68716852
//    8    3 sda3 1010409 26512312 31733575 253868616
//    8   16 sdb 12550386 47814 213085738 60429448 5529812 210792345 1731459040 1962038752 0 33797176 2024138028
//    8   17 sdb1 12601113 213085114 216407197 1731257800
//    3    0 hda 0 0 0 0 0 0 0 0 0 0 0
  private static void getDiskStats(long[] longs) {
    String fileName;
    String line = null;

    if (hasDiskStats) {
      // 2.6 kernel
      fileName = "/proc/diskstats";
    } else {
      // 2.4 kernel
      fileName = "/proc/partitions";
    }
    try (BufferedReader br = Files.newBufferedReader(Paths.get(fileName),
        StandardCharsets.UTF_8)) {
      long readsCompleted = 0, readsMerged = 0;
      long sectorsRead    = 0, timeReading  = 0; 
      long writesCompleted = 0, writesMerged = 0; 
      long sectorsWritten  = 0, timeWriting = 0;
      long iosInProgress = 0;
      long timeIosInProgress = 0;
      long ioTime = 0;
      if (!hasDiskStats) {
        br.readLine(); // Discard header info
        br.readLine(); // Discard header info
      }
      while ( (line = br.readLine()) != null) {
        st.setString(line);
        {
          // " 8 1 sdb" on 2.6
          // " 8 1 452145145 sdb" on 2.4
          String tok = st.nextToken();
          if (tok.length() == 0 || Character.isWhitespace(tok.charAt(0))) {
            // skip over first token since it is whitespace
            tok = st.nextToken();
          }
          // skip first token it is some number
          tok = st.nextToken();
          // skip second token it is some number
          tok = st.nextToken();
          if (!hasDiskStats) {
            // skip third token it is some number
            tok = st.nextToken();
          }
          // Now tok should be the device name.
          if (Character.isDigit(tok.charAt(tok.length()-1))) {
            // If the last char is a digit
            // skip this line since it is a partition of a device; not a device.
            continue;
          }
        }
        long tmp_readsCompleted = st.nextTokenAsLong(); 
        long tmp_readsMerged = st.nextTokenAsLong(); 
        long tmp_sectorsRead = st.nextTokenAsLong(); 
        long tmp_timeReading = st.nextTokenAsLong();
        if (st.hasMoreTokens()) {
          // If we are on 2.6 then we might only have 4 longs; if so ignore this line
          // Otherwise we should have 11 long tokens.
          long tmp_writesCompleted = st.nextTokenAsLong();
          long tmp_writesMerged = st.nextTokenAsLong();
          long tmp_sectorsWritten = st.nextTokenAsLong();
          long tmp_timeWriting = st.nextTokenAsLong();
          long tmp_iosInProgress = st.nextTokenAsLong();
          long tmp_timeIosInProgress = st.nextTokenAsLong();
          long tmp_ioTime = st.nextTokenAsLong();
          readsCompleted += tmp_readsCompleted;
          readsMerged += tmp_readsMerged;
          sectorsRead += tmp_sectorsRead;
          timeReading += tmp_timeReading;
          writesCompleted += tmp_writesCompleted;
          writesMerged += tmp_writesMerged;
          sectorsWritten += tmp_sectorsWritten;
          timeWriting += tmp_timeWriting;
          iosInProgress += tmp_iosInProgress;
          timeIosInProgress += tmp_timeIosInProgress;
          ioTime += tmp_ioTime;
        }
      } // while
      final int SECTOR_SIZE = 512;
      longs[LinuxSystemStats.readsCompletedLONG] = readsCompleted;
      longs[LinuxSystemStats.readsMergedLONG] = readsMerged;
      longs[LinuxSystemStats.bytesReadLONG] = sectorsRead * SECTOR_SIZE;
      longs[LinuxSystemStats.timeReadingLONG] = timeReading;
      longs[LinuxSystemStats.writesCompletedLONG] = writesCompleted;
      longs[LinuxSystemStats.writesMergedLONG] = writesMerged;
      longs[LinuxSystemStats.bytesWrittenLONG] = sectorsWritten * SECTOR_SIZE;
      longs[LinuxSystemStats.timeWritingLONG] = timeWriting;
      longs[LinuxSystemStats.iosInProgressLONG] = iosInProgress;
      longs[LinuxSystemStats.timeIosInProgressLONG] = timeIosInProgress;
      longs[LinuxSystemStats.ioTimeLONG] = ioTime;
    } catch (NoSuchElementException nsee) {
//       com.gemstone.gemfire.distributed.internal.InternalDistributedSystem.getAnyInstance().getLoggerI18n().fine("unexpected NoSuchElementException line=" + line, nsee);
    } catch (IOException ioe) {
    } finally {
      st.releaseResources();
    }
  }

  //Example of /proc/vmstat
  //...
  //pgpgin 294333738
  //pgpgout 1057420300
  //pswpin 19422
  //pswpout 14495
  private static void getVmStats(long[] longs) {
    assert hasProcVmStat != false : "getVmStats called when hasVmStat was false";
    try (BufferedReader br = Files.newBufferedReader(Paths.get("/proc/vmstat"),
        StandardCharsets.UTF_8)) {
      String line = null;
      while((line = br.readLine()) != null) {
        if(line.startsWith(PGPGIN)) {
          longs[LinuxSystemStats.pagesPagedInLONG] 
                = SpaceTokenizer.parseAsLong(line.substring(PGPGIN.length()));  
        } else if(line.startsWith(PGPGOUT)) {
          longs[LinuxSystemStats.pagesPagedOutLONG] 
                = SpaceTokenizer.parseAsLong(line.substring(PGPGOUT.length())); 
        } else if(line.startsWith(PSWPIN)) {
          longs[LinuxSystemStats.pagesSwappedInLONG] 
                = SpaceTokenizer.parseAsLong(line.substring(PSWPIN.length()));
        } else if(line.startsWith(PSWPOUT)) {
          longs[LinuxSystemStats.pagesSwappedOutLONG] 
                = SpaceTokenizer.parseAsLong(line.substring(PSWPOUT.length()));
        }
      }
    } catch (NoSuchElementException | IOException ignored) {
    }
  }

  /**
   * Count the number of files in /proc that do not represent processes.
   * This value is cached to make counting the number of running process a 
   * cheap operation. The assumption is that the contents of /proc will not 
   * change on a running system.
   * @return the files in /proc that do NOT match /proc/[0-9]*
   */
  private static int getNumberOfNonProcessProcFiles() {
    File proc = new File("/proc");
    String[] procFiles = proc.list();
    int count = 0;
    if(procFiles != null) {
      for(String filename : procFiles) {
        char c = filename.charAt(0);
        if(! Character.isDigit(c)) {
          if (c == '.') {
            // see if the next char is a digit
            if (filename.length() > 1) {
              char c2 = filename.charAt(1);
              if (Character.isDigit(c2)) {
                // for bug 42091 do not count files that begin with a '.' followed by digits
                continue;
              }
            }
          }
          count++;
        }
      }
    }
    return count;
  }

  /**
   * @return the number of running processes on the system
   */
  private static int getProcessCount() {
    File proc = new File("/proc");
    String[] procFiles = proc.list();
    if (procFiles == null) {
      //unknown error, continue without this stat
      return 0;
    }
    return procFiles.length - nonPidFilesInProc;
  }

  /**
   * Read the first line from a given file.
   */
  private static String getLineFromFile(String fileName) {
    try (BufferedReader br = Files.newBufferedReader(Paths.get(fileName),
        StandardCharsets.UTF_8)) {
      return br.readLine();
    } catch (IOException ignored) {
    }
    return null;
  }

  /**
   * Get the current total number of threads across system and maximum number
   * of file descriptors threads allowed by OS for the machine.
   */
  private static void getSystemFileDescriptorStats(long[] longs) {
    String line = getLineFromFile("/proc/sys/fs/file-nr");
    if (line != null) {
      String[] parts = line.split("[ \t]");
      if (parts.length > 0) {
        try {
          longs[LinuxSystemStats.totalFileDescriptorsLONG] =
              Long.parseLong(parts[0]);
        } catch (NumberFormatException ignored) {
        }
        if (parts.length > 2) {
          try {
            longs[LinuxSystemStats.fileDescriptorsSystemMaxLONG] =
                Long.parseLong(parts[2]);
          } catch (NumberFormatException ignored) {
          }
        }
      }
    }
  }

  /**
   * Get the maximum number of threads allowed by OS for the machine.
   * This returns smaller of threads-max and pid_max from /proc/sys/kernel.
   */
  private static long getSystemThreadLimit() {
    String line = getLineFromFile("/proc/sys/kernel/threads-max");
    long threadsMax = 0;
    if (line != null) {
      try {
        threadsMax = Long.parseLong(line);
      } catch (NumberFormatException ignored) {
      }
    }
    line = getLineFromFile("/proc/sys/kernel/pid_max");
    if (line != null) {
      try {
        long pidMax = Long.parseLong(line);
        threadsMax = threadsMax > 0 ? Math.min(threadsMax, pidMax) : pidMax;
      } catch (NumberFormatException ignored) {
      }
    }
    return threadsMax;
  }

  //The array indices must be ordered as they appear in /proc/stats
  //      (user)   (nice) (system) (idle)    (iowait) (irq)  (softirq)
  // cpu  42813766 10844  8889075 1450764512 49963779 808244 3084872
  //
  private static class CpuStat {
    private static boolean lastCpuStatsInvalid;
    private static List lastCpuStats;

    public CpuStat() {
      lastCpuStatsInvalid = true;
    }

    public int[] calculateStats( String newStatLine ) {
      st.setString(newStatLine);
      st.skipToken(); //cpu name
      final int MAX_CPU_STATS = CPU.values().length;
      /* newer kernels now have 8 columns for cpu in
       * /proc/stat (up from 7). This number may increase
       * even further, hence we now use List in place of long[].
       * We add up entries from all columns after 7 into CPU.OTHER
       */
      List newStats = new ArrayList(8);
      List diffs = new ArrayList(8);
      long total_change = 0;
      int actualCpuStats = 0;
      long unaccountedCpuUtilization = 0;
      
      while (st.hasMoreTokens()) {
        newStats.add(st.nextTokenAsLong());
        actualCpuStats++;
      }
      
      if ( lastCpuStatsInvalid ) {
        lastCpuStats = newStats;
        lastCpuStatsInvalid = false;
        for (int i=0; i 0 && skipToken());
    }

    protected static long parseAsLong(String number) {
      long l = 0L;
      try {
        l = Long.parseLong(number);
      } catch(NumberFormatException nfe) {}
      return l;
    }

    protected static int parseAsInt(String number) {
      int i = 0;
      try {
        i = Integer.parseInt(number);
      } catch(NumberFormatException nfe) {}
      return i;
    }

    protected int nextTokenAsInt() {
      int i = 0;
      try {
        i = Integer.parseInt(nextToken());
      } catch(NumberFormatException nfe) {}
      return i;
    }

    protected long nextTokenAsLong() {
      long l = 0L;
      try {
        l = Long.parseLong(nextToken());
      } catch(NumberFormatException nfe) {}
      return l;
    }

    protected double nextTokenAsDouble() {
      double d = 0;
      try {
        d = Double.parseDouble(nextToken());
      } catch(NumberFormatException nfe) {}
      return d;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy