/* * Licensed to the Apache Software Foundation (ASF) under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional information regarding * copyright ownership. The ASF licenses this file to You 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. */ package org.apache.geode.internal.statistics.platform; import org.apache.geode.distributed.internal.DistributionConfig; import org.apache.logging.log4j.Logger; import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; import java.util.regex.Matcher; import java.util.regex.Pattern; 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 = DistributionConfig.GEMFIRE_PREFIX + "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 "; // Do not create instances of this class private LinuxProcFsStatistics() {} public static int init() { // TODO: was package-protected 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(); return 0; } public static void close() { // TODO: was package-protected cpuStatSingleton = null; st = null; } public static void readyRefresh() { // TODO: was package-protected } /* * 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() * */ public static void refreshProcess(int pid, int[] ints, long[] longs, double[] doubles) { // TODO: // was // package-protected // Just incase a pid is not available if (pid == 0) return; InputStreamReader isr = null; BufferedReader br = null; try { File file = new File("/proc/" + pid + "/stat"); isr = new InputStreamReader(new FileInputStream(file)); br = new BufferedReader(isr, 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 nsee) { // 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. } catch (IOException ioe) { // 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(); if (br != null) try { br.close(); } catch (IOException ignore) { } } } public static void refreshSystem(int[] ints, long[] longs, double[] doubles) { // TODO: was // package-protected ints[LinuxSystemStats.processesINT] = getProcessCount(); ints[LinuxSystemStats.cpusINT] = sys_cpus; InputStreamReader isr = null; BufferedReader br = null; try { isr = new InputStreamReader(new FileInputStream("/proc/stat")); br = new BufferedReader(isr); 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) { } finally { if (br != null) try { br.close(); } catch (IOException ignore) { } } getLoadAvg(doubles); 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) { InputStreamReader isr = null; BufferedReader br = null; try { isr = new InputStreamReader(new FileInputStream("/proc/loadavg")); br = new BufferedReader(isr, 512); String line = br.readLine(); if (line == null) { return; } st.setString(line); doubles[LinuxSystemStats.loadAverage1DOUBLE] = st.nextTokenAsDouble(); doubles[LinuxSystemStats.loadAverage5DOUBLE] = st.nextTokenAsDouble(); doubles[LinuxSystemStats.loadAverage15DOUBLE] = st.nextTokenAsDouble(); } catch (NoSuchElementException nsee) { } catch (IOException ioe) { } finally { st.releaseResources(); if (br != null) try { br.close(); } catch (IOException ignore) { } } } /** * Returns the available system memory (free + cached). * * @param logger the logger * @return the available memory in bytes */ public static long getAvailableMemory(Logger logger) { try { BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/meminfo"))); try { 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; } finally { br.close(); } } catch (IOException e) { logger.warn("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) { InputStreamReader isr = null; BufferedReader br = null; try { isr = new InputStreamReader(new FileInputStream("/proc/meminfo")); br = new BufferedReader(isr); // 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 ioe) { } finally { st.releaseResources(); if (br != null) try { br.close(); } catch (IOException ignore) { } } } /* * 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) { InputStreamReader isr = null; BufferedReader br = null; try { isr = new InputStreamReader(new FileInputStream("/proc/net/dev")); br = new BufferedReader(isr); 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); st.setString(line.substring(index + 1).trim()); 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 nsee) { } catch (IOException ioe) { } finally { st.releaseResources(); if (br != null) try { br.close(); } catch (IOException ignore) { } } } // 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) { InputStreamReader isr = null; BufferedReader br = null; String line = null; try { if (hasDiskStats) { // 2.6 kernel isr = new InputStreamReader(new FileInputStream("/proc/diskstats")); } else { // 2.4 kernel isr = new InputStreamReader(new FileInputStream("/proc/partitions")); } br = new BufferedReader(isr); 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) { // org.apache.geode.distributed.internal.InternalDistributedSystem.getAnyInstance().getLoggerI18n().fine("unexpected // NoSuchElementException line=" + line, nsee); } catch (IOException ioe) { } finally { st.releaseResources(); if (br != null) try { br.close(); } catch (IOException ignore) { } } } // 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"; InputStreamReader isr = null; BufferedReader br = null; try { isr = new InputStreamReader(new FileInputStream("/proc/vmstat")); br = new BufferedReader(isr); 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 nsee) { } catch (IOException ioe) { } finally { if (br != null) try { br.close(); } catch (IOException ignore) { } } } /** * 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; } // 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<Long> 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<Long> newStats = new ArrayList<Long>(8); List<Long> diffs = new ArrayList<Long>(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 < MAX_CPU_STATS; i++) { diffs.add(0L); } diffs.set(CPU.IDLE.ordinal(), 100L); } else { for (int i = 0; i < actualCpuStats; i++) { diffs.add(newStats.get(i) - lastCpuStats.get(i)); total_change += diffs.get(i); lastCpuStats.set(i, newStats.get(i)); } if (total_change == 0) { // avoid divide by zero total_change = 1; } for (int i = 0; i < MAX_CPU_STATS; i++) { if (i < actualCpuStats) { diffs.set(i, (diffs.get(i) * 100) / total_change); } } for (int i = MAX_CPU_STATS; i < actualCpuStats; i++) { unaccountedCpuUtilization += (diffs.get(i) * 100) / total_change; } } int[] ret = new int[MAX_CPU_STATS]; for (int i = 0; i < MAX_CPU_STATS; i++) { if (i < actualCpuStats) { ret[i] = diffs.get(i).intValue(); } } ret[CPU.OTHER.ordinal()] += (int) unaccountedCpuUtilization; return ret; } } private static class SpaceTokenizer { private String str; private char[] rawChars; private int beginIdx; private int endIdx; private int nextIdx; protected SpaceTokenizer() { endIdx = -1; nextIdx = -1; } protected void releaseResources() { str = null; rawChars = null; endIdx = -1; nextIdx = -1; } private void nextIdx() { int origin = nextIdx; if (endIdx == rawChars.length || beginIdx == -1) { endIdx = -1; nextIdx = -1; return; } endIdx = -1; nextIdx = -1; for (int i = origin + 1; i < rawChars.length; i++) { char c = rawChars[i]; // Add all delimiters here if (c == ' ' || c == '\t' || c == '\n' || c == '\r') { if (endIdx == -1) { endIdx = i; } } else { // this handles multiple consecutive delimiters if (endIdx != -1) { nextIdx = i; return; } } } if (endIdx == -1) { // indicates we were still reading white space at the end of the string endIdx = rawChars.length; } } protected boolean hasMoreTokens() { return endIdx != -1; } protected void setString(String data) { str = data; rawChars = new char[str.length()]; str.getChars(0, str.length(), rawChars, 0); beginIdx = 0; endIdx = -1; nextIdx = -1; nextIdx(); } protected boolean skipToken() { if (hasMoreTokens()) { beginIdx = nextIdx; nextIdx(); return true; } return false; } protected String nextToken() { if (hasMoreTokens()) { final String ret = str.substring(beginIdx, endIdx); beginIdx = nextIdx; nextIdx(); return ret; } throw new NoSuchElementException(); } protected String peekToken() { if (hasMoreTokens()) { return str.substring(beginIdx, endIdx); } throw new NoSuchElementException(); } protected void skipTokens(int numberToSkip) { int remaining = numberToSkip + 1; while (--remaining > 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; } } }