You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2019/01/14 02:41:06 UTC

[servicecomb-java-chassis] 01/04: [SCB-1096]change the method calculate process cpu rate to same with top: fix as reviewed

This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 6d278c11b9e924fb96f64ab7f07ae67c90773326
Author: heyile <25...@qq.com>
AuthorDate: Wed Jan 9 22:07:01 2019 +0800

    [SCB-1096]change the method calculate process cpu rate to same with top: fix as reviewed
---
 .../metrics/core/meter/os/CpuMeter.java            |   3 +-
 .../core/meter/os/cpu/AbstractCpuUsage.java        |  74 ++------
 .../metrics/core/meter/os/cpu/CpuUtils.java        | 193 +++++++++++++++++++++
 .../metrics/core/meter/os/cpu/OsCpuUsage.java      |  51 +++---
 .../metrics/core/meter/os/cpu/ProcessCpuUsage.java |  42 ++---
 .../metrics/core/TestOsMeterInitializer.java       |  25 ++-
 .../metrics/core/meter/os/TestCpuMeter.java        | 127 +++++++-------
 .../metrics/core/meter/os/TestOsMeter.java         |  36 +++-
 8 files changed, 369 insertions(+), 182 deletions(-)

diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/CpuMeter.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/CpuMeter.java
index 6edcf1b..b271fdb 100644
--- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/CpuMeter.java
+++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/CpuMeter.java
@@ -29,7 +29,7 @@ public class CpuMeter {
   // read from /proc/stat
   private OsCpuUsage allCpuUsage;
 
-  // read from /proc/{pid}/stat
+  // read from /proc/self/stat /proc/uptime
   private ProcessCpuUsage processCpuUsage;
 
   public CpuMeter(Id id) {
@@ -50,7 +50,6 @@ public class CpuMeter {
 
   public void update() {
     allCpuUsage.update();
-    processCpuUsage.setPeriodTotalTime(allCpuUsage.getPeriodTotalTime());
     processCpuUsage.update();
   }
 
diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/AbstractCpuUsage.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/AbstractCpuUsage.java
index af4f514..e2b28fc 100644
--- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/AbstractCpuUsage.java
+++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/AbstractCpuUsage.java
@@ -16,48 +16,33 @@
  */
 package org.apache.servicecomb.metrics.core.meter.os.cpu;
 
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-
-import org.apache.commons.io.FileUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import com.netflix.spectator.api.Id;
 
 public abstract class AbstractCpuUsage {
-  private static final Logger LOGGER = LoggerFactory.getLogger(AbstractCpuUsage.class);
-
-  protected String filePath;
 
   protected Id id;
 
-  protected long lastBusyTime;
-
-  protected long periodTotalTime;
-
   protected double usage;
 
-  public AbstractCpuUsage(Id id, String filePath) {
-    this.id = id;
-    this.filePath = filePath;
-  }
+  protected int cpuCount = Runtime.getRuntime().availableProcessors();
 
-  public Id getId() {
-    return id;
-  }
+  static class Period {
+    double last;
+
+    double period;
 
-  public long getPeriodTotalTime() {
-    return periodTotalTime;
+    void update(double current) {
+      period = current - last;
+      last = current;
+    }
   }
 
-  public long getLastBusyTime() {
-    return lastBusyTime;
+  public AbstractCpuUsage(Id id) {
+    this.id = id;
   }
 
-  public String getFilePath() {
-    return filePath;
+  public Id getId() {
+    return id;
   }
 
   public double getUsage() {
@@ -68,36 +53,5 @@ public abstract class AbstractCpuUsage {
     this.usage = usage;
   }
 
-  public void setPeriodTotalTime(long periodTotalTime) {
-    this.periodTotalTime = periodTotalTime;
-  }
-
-  protected String[] readAndSplitStat() throws IOException {
-    File file = new File(filePath);
-    String stat = FileUtils.readLines(file, StandardCharsets.UTF_8).get(0);
-    return stat.trim().split("\\s+");
-  }
-
-  public void update() {
-    String[] stats;
-    try {
-      stats = readAndSplitStat();
-    } catch (IOException e) {
-      LOGGER.error(String.format("Failed to read cpu info/%s.", filePath), e);
-      return;
-    }
-
-    update(stats);
-  }
-
-  protected void update(String[] stats) {
-    long currentBusyTime = readCurrentBusyTime(stats);
-
-    usage = periodTotalTime == 0 ? 0 : (double) (currentBusyTime - lastBusyTime) / periodTotalTime;
-    usage *= Runtime.getRuntime().availableProcessors();
-
-    lastBusyTime = currentBusyTime;
-  }
-
-  protected abstract long readCurrentBusyTime(String[] stats);
+  protected abstract void updateUsage(double periodBusy, double periodTotal);
 }
diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/CpuUtils.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/CpuUtils.java
new file mode 100644
index 0000000..2519bb8
--- /dev/null
+++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/CpuUtils.java
@@ -0,0 +1,193 @@
+/*
+ * 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.servicecomb.metrics.core.meter.os.cpu;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.io.Files;
+
+public final class CpuUtils {
+  private static final Logger LOGGER = LoggerFactory.getLogger(CpuUtils.class);
+
+  public static final File PROC_STAT = new File("/proc/stat");
+
+  public static final File UPTIME = new File("/proc/uptime");
+
+  public static final File SELF_PROCESS = new File("/proc/self/stat");
+
+  private CpuUtils() {
+  }
+
+  public static String[] readAndSplitFirstLine(String filePath) {
+    return readAndSplitFirstLine(new File(filePath));
+  }
+
+  public static String[] readAndSplitFirstLine(File file) {
+    try {
+      return Files.asCharSource(file, StandardCharsets.UTF_8).readFirstLine().trim().split("\\s+");
+    } catch (IOException | NullPointerException e) {
+      LOGGER.error(String.format("Failed to read file %s", file.getName()), e);
+    }
+    return null;
+  }
+
+  public static double summary(String[] stats, int start, int len) {
+    double total = 0;
+    for (int idx = start; idx < start + len; idx++) {
+      total += Double.parseDouble(stats[idx]);
+    }
+    return total;
+  }
+
+  private static double readProcStatTotal() {
+    String[] stats = readAndSplitFirstLine(PROC_STAT);
+    return summary(stats, 1, 8);
+  }
+
+  public static double readProcStatTotal(String[] stats) {
+    return summary(stats, 1, 8);
+  }
+
+  private static double readUptimeTotal() {
+    String[] uptime = readAndSplitFirstLine(UPTIME);
+    return Double.parseDouble(uptime[0]);
+  }
+
+  private static boolean isBetween(long x, long lower, long upper) {
+    return lower <= x && x <= upper;
+  }
+
+  /**
+   *  unit of /proc/uptime is seconds
+   *  unit of /proc/self/stat is jiffies
+   *  hence, we should calculate userHZ to get process cpu rate
+   *
+   * @return userHZ
+   */
+  public static int calcHertz() {
+    double up1, up2, seconds;
+    double jiffies;
+
+    for (; ; ) {
+      try {
+        up1 = readUptimeTotal();
+        jiffies = readProcStatTotal();
+        up2 = readUptimeTotal();
+      } catch (Throwable e) {
+        LOGGER.error("Failed to calc hertz, should never happened, try again.", e);
+        continue;
+      }
+
+      /* want under 0.1% error */
+      if (0 == (long) ((up2 - up1) * 1000.0 / up1)) {
+        break;
+      }
+    }
+
+    seconds = (up1 + up2) / 2;
+    long hz = Math.round(jiffies / seconds / Runtime.getRuntime().availableProcessors());
+    /* actual values used by 2.4 kernels: 32 64 100 128 1000 1024 1200 */
+    /* S/390 (sometimes) */
+    if (isBetween(hz, 9, 11)) {
+      return 10;
+    }
+
+    /* user-mode Linux */
+    if (isBetween(hz, 18, 22)) {
+      return 20;
+    }
+
+    /* ia64 emulator */
+    if (isBetween(hz, 30, 34)) {
+      return 32;
+    }
+
+    if (isBetween(hz, 48, 52)) {
+      return 50;
+    }
+
+    if (isBetween(hz, 58, 61)) {
+      return 60;
+    }
+
+    /* StrongARM /Shark */
+    if (isBetween(hz, 62, 65)) {
+      return 64;
+    }
+
+    /* normal Linux */
+    if (isBetween(hz, 95, 105)) {
+      return 100;
+    }
+
+    /* MIPS, ARM */
+    if (isBetween(hz, 124, 132)) {
+      return 128;
+    }
+
+    /* normal << 1 */
+    if (isBetween(hz, 195, 204)) {
+      return 200;
+    }
+
+    if (isBetween(hz, 247, 252)) {
+      return 250;
+    }
+
+    if (isBetween(hz, 253, 260)) {
+      return 256;
+    }
+
+    /* normal << 2 */
+    if (isBetween(hz, 393, 408)) {
+      return 400;
+    }
+
+    /* SMP WinNT */
+    if (isBetween(hz, 410, 600)) {
+      return 500;
+    }
+
+    /* normal << 3 */
+    if (isBetween(hz, 790, 808)) {
+      return 800;
+    }
+
+    /* ARM */
+    if (isBetween(hz, 990, 1010)) {
+      return 1000;
+    }
+
+    /* Alpha, ia64 */
+    if (isBetween(hz, 1015, 1035)) {
+      return 1024;
+    }
+
+    /* Alpha */
+    if (isBetween(hz, 1180, 1220)) {
+      return 1200;
+    }
+
+    LOGGER.warn("Unknown HZ value! ({}) Assume {}.\n", hz, 100);
+    return 100;
+  }
+}
diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/OsCpuUsage.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/OsCpuUsage.java
index 48b9a8c..2ec1670 100644
--- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/OsCpuUsage.java
+++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/OsCpuUsage.java
@@ -19,48 +19,53 @@ package org.apache.servicecomb.metrics.core.meter.os.cpu;
 import com.netflix.spectator.api.Id;
 
 /*
- * unit : 1 jiffies = 10ms = 0.01 s
+ * unit : 1 jiffies
  * more details :
  * http://man7.org/linux/man-pages/man5/proc.5.html
  * CMD :  /proc/stat
  * cpu  2445171 599297 353967 24490633 11242   0    10780    2993             0      0
  * cpu  user    nice   system idle     iowait  irq  softirq  stealstolen      guest  guest_nice
- * 0    1       2      3      4        5        6   7        8
+ * 0    1       2      3      4        5        6   7        8                9      10
  * total = user + nice + system + idle + iowait + irq + softirq + stealstolen
  * busy = total - idle
  */
 public class OsCpuUsage extends AbstractCpuUsage {
-  private long lastTotalTime;
 
-  private long currentTotalTime;
+  private Period total = new Period();
+
+  private Period idle = new Period();
 
   public OsCpuUsage(Id id) {
-    super(id, "/proc/stat");
+    super(id);
   }
 
-  @Override
-  protected void update(String[] stats) {
-    currentTotalTime = readCurrentTotalTime(stats);
-    periodTotalTime = currentTotalTime - lastTotalTime;
-    lastTotalTime = currentTotalTime;
-
-    super.update(stats);
+  public void update() {
+    String[] stats = CpuUtils.readAndSplitFirstLine(CpuUtils.PROC_STAT);
+    if (stats == null) {
+      return;
+    }
+    update(stats);
   }
 
-  private long readCurrentTotalTime(String[] stats) {
-    long total = 0L;
-    for (int i = 1; i <= 8; i++) {
-      total += Long.parseLong(stats[i]);
+  private void update(String[] stats) {
+
+    long currentIdle = Long.parseLong(stats[4]);
+    idle.update(currentIdle);
+
+    long totalCpu = 0L;
+    for (int i = 1; i < 9; i++) {
+      totalCpu += Long.parseLong(stats[i]);
     }
-    return total;
+    total.update(totalCpu);
+    updateUsage(total.period - idle.period, total.period);
   }
 
   @Override
-  protected long readCurrentBusyTime(String[] stats) {
-    return currentTotalTime - Long.parseLong(stats[4]);
-  }
-
-  public long getLastTotalTime() {
-    return lastTotalTime;
+  protected void updateUsage(double periodBusy, double periodTotal) {
+    usage = periodTotal == 0 ? 0 : periodBusy / periodTotal;
+    if (usage > 1) {
+      usage = 1;
+    }
+    usage *= cpuCount;
   }
 }
diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/ProcessCpuUsage.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/ProcessCpuUsage.java
index 57efd85..b0116bb 100644
--- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/ProcessCpuUsage.java
+++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/meter/os/cpu/ProcessCpuUsage.java
@@ -16,48 +16,48 @@
  */
 package org.apache.servicecomb.metrics.core.meter.os.cpu;
 
-import java.lang.management.ManagementFactory;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import com.netflix.spectator.api.Id;
 
 /*
- * unit : 1 jiffies = 10ms = 0.01 s
+ * unit : 1 jiffies
  * more details :
  * http://man7.org/linux/man-pages/man5/proc.5.html
  * CMD :  /proc/[pid]/stat
  * 6754 (kubelet) S      1     995   995      0       -1     4202752   193281  592501546 0       12       1152076 907044 87991  113319  ..
  * pid  comm      state  ppid  pgrp  session  tty_nr  tpgid  flags     minflt  cminflt   majflt  cmajflt  utime   stime  cutime cstime
  * 0    1         2      3     4     5        6       7      8         9       10        11      12       13      14     15     16
- * busy = utime + stime + cutime + cstime
+ * busy = utime + stime
  *
  */
 public class ProcessCpuUsage extends AbstractCpuUsage {
-  private static final Logger LOGGER = LoggerFactory.getLogger(ProcessCpuUsage.class);
+  private Period busy = new Period();
+
+  private Period total = new Period();
+
+  private int userHZ = CpuUtils.calcHertz();
 
   public ProcessCpuUsage(Id id) {
-    super(id, String.format("/proc/%s/stat", getCurrentPid()));
+    super(id);
   }
 
-  private static String getCurrentPid() {
-    String name = ManagementFactory.getRuntimeMXBean().getName();
-    int idx = name.indexOf('@');
-    if (idx > 0) {
-      return name.substring(0, idx);
+  public void update() {
+    String[] stats = CpuUtils.readAndSplitFirstLine(CpuUtils.SELF_PROCESS);
+    String[] uptime = CpuUtils.readAndSplitFirstLine(CpuUtils.UPTIME);
+
+    if (stats == null || stats.length < 15 || uptime == null) {
+      return;
     }
+    busy.update(Double.parseDouble(stats[13]) + Double.parseDouble(stats[14]));
+    total.update(Double.parseDouble(uptime[0]) * userHZ * cpuCount);
 
-    LOGGER.error("Failed to get current process id. {}", name);
-    throw new IllegalStateException("Failed to get current process Id");
+    updateUsage(busy.period, total.period);
   }
 
   @Override
-  protected long readCurrentBusyTime(String[] stats) {
-    long busy = 0L;
-    for (int i = 13; i <= 16; i++) {
-      busy += Long.parseLong(stats[i]);
+  protected void updateUsage(double periodBusy, double periodTotal) {
+    usage = periodTotal == 0 ? 0 : periodBusy / periodTotal;
+    if (usage > 1) {
+      usage = 1;
     }
-    return busy;
   }
 }
diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestOsMeterInitializer.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestOsMeterInitializer.java
index 8f2f60f..2514934 100644
--- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestOsMeterInitializer.java
+++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestOsMeterInitializer.java
@@ -31,6 +31,7 @@ import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry;
 import org.apache.servicecomb.metrics.core.meter.os.CpuMeter;
 import org.apache.servicecomb.metrics.core.meter.os.NetMeter;
 import org.apache.servicecomb.metrics.core.meter.os.OsMeter;
+import org.apache.servicecomb.metrics.core.meter.os.cpu.CpuUtils;
 import org.apache.servicecomb.metrics.core.meter.os.net.InterfaceUsage;
 import org.junit.After;
 import org.junit.Assert;
@@ -38,6 +39,7 @@ import org.junit.Before;
 import org.junit.Test;
 
 import com.google.common.eventbus.EventBus;
+import com.google.common.io.Files;
 import com.netflix.spectator.api.DefaultRegistry;
 import com.netflix.spectator.api.ManualClock;
 import com.netflix.spectator.api.Registry;
@@ -66,15 +68,28 @@ public class TestOsMeterInitializer {
   public void init(@Mocked Runtime runtime, @Mocked RuntimeMXBean mxBean) {
     ReflectUtils.setField(SystemUtils.class, null, "IS_OS_LINUX", true);
     List<String> list = new ArrayList<>();
-    list.add("cpu  1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1");
+    list.add("13  1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1");
     list.add("useless");
     list.add("eth0: 0 0    0    0    0     0          0          0         0 0    0      0     0     0    0    0");
+    new MockUp<Files>() {
+      //Files.readFirstLine
+      @Mock
+      public String readFirstLine(File file, Charset encoding) {
+        return list.get(0);
+      }
+    };
     new MockUp<FileUtils>() {
       @Mock
       public List<String> readLines(File file, Charset encoding) {
         return list;
       }
     };
+    new MockUp<CpuUtils>() {
+      @Mock
+      public int calcHertz() {
+        return 100;
+      }
+    };
     new MockUp<ManagementFactory>() {
       @Mock
       RuntimeMXBean getRuntimeMXBean() {
@@ -92,8 +107,6 @@ public class TestOsMeterInitializer {
       {
         runtime.availableProcessors();
         result = 2;
-        mxBean.getName();
-        result = "6666@desktop111";
       }
     };
     globalRegistry.add(registry);
@@ -106,14 +119,8 @@ public class TestOsMeterInitializer {
     CpuMeter cpuMeter = osMeter.getCpuMeter();
     NetMeter netMeter = osMeter.getNetMeter();
     Assert.assertEquals(0.0, cpuMeter.getProcessCpuUsage().getUsage(), 0.0);
-    Assert.assertEquals("/proc/6666/stat", cpuMeter.getProcessCpuUsage().getFilePath());
-    Assert.assertEquals(4L, cpuMeter.getProcessCpuUsage().getLastBusyTime());
-    Assert.assertEquals(8L, cpuMeter.getProcessCpuUsage().getPeriodTotalTime());
 
     Assert.assertEquals(0.0, cpuMeter.getAllCpuUsage().getUsage(), 0.0);
-    Assert.assertEquals(8L, cpuMeter.getAllCpuUsage().getPeriodTotalTime());
-    Assert.assertEquals(7L, cpuMeter.getAllCpuUsage().getLastBusyTime());
-    Assert.assertEquals("/proc/stat", cpuMeter.getAllCpuUsage().getFilePath());
 
     Map<String, InterfaceUsage> interfaceInfoMap = netMeter.getInterfaceUsageMap();
     Assert.assertEquals(1, interfaceInfoMap.size());
diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestCpuMeter.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestCpuMeter.java
index 5b28191..30cc412 100644
--- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestCpuMeter.java
+++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestCpuMeter.java
@@ -17,16 +17,19 @@
 package org.apache.servicecomb.metrics.core.meter.os;
 
 import java.io.File;
+import java.io.IOException;
 import java.lang.management.ManagementFactory;
 import java.lang.management.RuntimeMXBean;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.commons.io.FileUtils;
+import org.apache.servicecomb.metrics.core.meter.os.cpu.CpuUtils;
 import org.junit.Assert;
 import org.junit.Test;
 
+import com.google.common.io.CharSource;
+import com.google.common.io.Files;
 import com.netflix.spectator.api.Id;
 import com.netflix.spectator.api.Measurement;
 
@@ -38,13 +41,12 @@ import mockit.Mocked;
 public class TestCpuMeter {
 
   @Test
-  public void testRefreshCpuSuccess(@Mocked Id id, @Mocked Runtime runtime, @Mocked RuntimeMXBean mxBean) {
-    List<String> list = new ArrayList<>();
-    list.add("cpu  1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1");
-    new MockUp<FileUtils>() {
+  public void testRefreshCpuSuccess(@Mocked Id id, @Mocked Runtime runtime, @Mocked RuntimeMXBean mxBean,
+      @Mocked CharSource charSource) throws IOException {
+    new MockUp<Files>() {
       @Mock
-      public List<String> readLines(File file, Charset encoding) {
-        return list;
+      public CharSource asCharSource(File file, Charset encoding) {
+        return charSource;
       }
     };
     new MockUp<ManagementFactory>() {
@@ -53,7 +55,12 @@ public class TestCpuMeter {
         return mxBean;
       }
     };
-
+    new MockUp<CpuUtils>() {
+      @Mock
+      public int calcHertz() {
+        return 4;
+      }
+    };
     new MockUp<Runtime>() {
       @Mock
       public Runtime getRuntime() {
@@ -64,44 +71,42 @@ public class TestCpuMeter {
       {
         runtime.availableProcessors();
         result = 2;
-        mxBean.getName();
-        result = "6666@desktop111";
+        charSource.readFirstLine();
+        result = "1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1";
       }
     };
     CpuMeter cpuMeter = new CpuMeter(id);
     Assert.assertEquals(0.0, cpuMeter.getAllCpuUsage().getUsage(), 0.0);
     Assert.assertEquals(0.0, cpuMeter.getProcessCpuUsage().getUsage(), 0.0);
 
-    Assert.assertEquals(4L, cpuMeter.getProcessCpuUsage().getLastBusyTime());
-    Assert.assertEquals(8L, cpuMeter.getAllCpuUsage().getPeriodTotalTime());
-    Assert.assertEquals(8L, cpuMeter.getAllCpuUsage().getLastTotalTime());
-    Assert.assertEquals(7L, cpuMeter.getAllCpuUsage().getLastBusyTime());
-
-    Assert.assertEquals("/proc/stat", cpuMeter.getAllCpuUsage().getFilePath());
-    Assert.assertEquals("/proc/6666/stat", cpuMeter.getProcessCpuUsage().getFilePath());
-
-    list.add(0, "cpu  2 2 2 2 2 2 2 2 0 0 2 2 2 2 2 2 2 2 2 2");
+    new Expectations() {
+      {
+        charSource.readFirstLine();
+        result = "2 2 2 2 2 2 2 2 2 0 0 2 2 2 2 2 2 2 2 2 2";
+      }
+    };
     cpuMeter.update();
-    Assert.assertEquals(1.0, cpuMeter.getProcessCpuUsage().getUsage(), 0.0);
-    Assert.assertEquals(1.75, cpuMeter.getAllCpuUsage().getUsage(), 0.0);
 
-    Assert.assertEquals(8L, cpuMeter.getProcessCpuUsage().getLastBusyTime());
-    Assert.assertEquals(16L, cpuMeter.getAllCpuUsage().getLastTotalTime());
-    Assert.assertEquals(8L, cpuMeter.getAllCpuUsage().getPeriodTotalTime());
-    Assert.assertEquals(14L, cpuMeter.getAllCpuUsage().getLastBusyTime());
+    Assert.assertEquals(1.75, cpuMeter.getAllCpuUsage().getUsage(), 0.0);
+    Assert.assertEquals(0.5, cpuMeter.getProcessCpuUsage().getUsage(), 0.0);
   }
 
   @Test
-  public void testRefreshError(@Mocked Id id, @Mocked Runtime runtime, @Mocked RuntimeMXBean mxBean) {
-    List<String> list = new ArrayList<>();
-    list.add("cpu  1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1");
-    new MockUp<FileUtils>() {
+  public void testRefreshError(@Mocked Id id, @Mocked Runtime runtime, @Mocked RuntimeMXBean mxBean,
+      @Mocked CharSource charSource) throws IOException {
+
+    new MockUp<Files>() {
       @Mock
-      public List<String> readLines(File file, Charset encoding) {
-        return list;
+      public CharSource asCharSource(File file, Charset encoding) {
+        return charSource;
+      }
+    };
+    new MockUp<CpuUtils>() {
+      @Mock
+      public int calcHertz() {
+        return 4;
       }
     };
-
     new MockUp<ManagementFactory>() {
       @Mock
       RuntimeMXBean getRuntimeMXBean() {
@@ -118,46 +123,42 @@ public class TestCpuMeter {
       {
         runtime.availableProcessors();
         result = 2;
-        mxBean.getName();
-        result = "6666@desktop111";
+        charSource.readFirstLine();
+        result = "1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1";
       }
     };
     CpuMeter cpuMeter = new CpuMeter(id);
     Assert.assertEquals(0.0, cpuMeter.getAllCpuUsage().getUsage(), 0.0);
     Assert.assertEquals(0.0, cpuMeter.getProcessCpuUsage().getUsage(), 0.0);
-
-    Assert.assertEquals(4L, cpuMeter.getProcessCpuUsage().getLastBusyTime());
-    Assert.assertEquals(8L, cpuMeter.getAllCpuUsage().getPeriodTotalTime());
-    Assert.assertEquals(8L, cpuMeter.getAllCpuUsage().getLastTotalTime());
-    Assert.assertEquals(7L, cpuMeter.getAllCpuUsage().getLastBusyTime());
-
-    Assert.assertEquals("/proc/stat", cpuMeter.getAllCpuUsage().getFilePath());
-    Assert.assertEquals("/proc/6666/stat", cpuMeter.getProcessCpuUsage().getFilePath());
-
-    list.add(0, "cpu  1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1");
+    new Expectations() {
+      {
+        charSource.readFirstLine();
+        result = "1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1";
+      }
+    };
     cpuMeter.update();
 
     Assert.assertEquals(0.0, cpuMeter.getAllCpuUsage().getUsage(), 0.0);
     Assert.assertEquals(0.0, cpuMeter.getProcessCpuUsage().getUsage(), 0.0);
-
-    Assert.assertEquals(4L, cpuMeter.getProcessCpuUsage().getLastBusyTime());
-    Assert.assertEquals(0L, cpuMeter.getAllCpuUsage().getPeriodTotalTime());
-    Assert.assertEquals(8L, cpuMeter.getAllCpuUsage().getLastTotalTime());
-    Assert.assertEquals(7L, cpuMeter.getAllCpuUsage().getLastBusyTime());
   }
 
   @Test
-  public void testCalcMeasurements(@Mocked Id id, @Mocked Runtime runtime, @Mocked RuntimeMXBean mxBean) {
+  public void testCalcMeasurements(@Mocked Id id, @Mocked Runtime runtime, @Mocked RuntimeMXBean mxBean,
+      @Mocked CharSource charSource) throws IOException {
     List<Measurement> measurements = new ArrayList<>();
-    List<String> list = new ArrayList<>();
-    list.add("cpu  1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1");
-    new MockUp<FileUtils>() {
+
+    new MockUp<Files>() {
       @Mock
-      public List<String> readLines(File file, Charset encoding) {
-        return list;
+      public CharSource asCharSource(File file, Charset encoding) {
+        return charSource;
+      }
+    };
+    new MockUp<CpuUtils>() {
+      @Mock
+      public int calcHertz() {
+        return 4;
       }
     };
-
     new MockUp<ManagementFactory>() {
       @Mock
       RuntimeMXBean getRuntimeMXBean() {
@@ -174,12 +175,18 @@ public class TestCpuMeter {
       {
         runtime.availableProcessors();
         result = 2;
-        mxBean.getName();
-        result = "6666@desktop111";
+        charSource.readFirstLine();
+        result = "1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1";
       }
     };
     CpuMeter cpuMeter = new CpuMeter(id);
-    list.add(0, "cpu  2 2 2 2 2 2 2 2 0 0 2 2 2 2 2 2 2 2 2 2");
+
+    new Expectations() {
+      {
+        charSource.readFirstLine();
+        result = "2 2 2 2 2 2 2 2 2 0 0 2 2 2 2 2 2 2 2 2 2";
+      }
+    };
     cpuMeter.calcMeasurements(measurements, 0);
     Assert.assertEquals(2, measurements.size());
     Measurement measurement = measurements.get(0);
@@ -187,6 +194,6 @@ public class TestCpuMeter {
     Assert.assertEquals(1.75, measurement.value(), 0.0);
     measurement = measurements.get(1);
     Assert.assertEquals(0, measurement.timestamp());
-    Assert.assertEquals(1.0, measurement.value(), 0.0);
+    Assert.assertEquals(0.5, measurement.value(), 0.0);
   }
 }
diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestOsMeter.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestOsMeter.java
index 79b20a7..e93518a 100644
--- a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestOsMeter.java
+++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/meter/os/TestOsMeter.java
@@ -18,6 +18,7 @@ package org.apache.servicecomb.metrics.core.meter.os;
 
 
 import java.io.File;
+import java.io.IOException;
 import java.lang.management.ManagementFactory;
 import java.lang.management.RuntimeMXBean;
 import java.nio.charset.Charset;
@@ -25,10 +26,13 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.commons.io.FileUtils;
+import org.apache.servicecomb.metrics.core.meter.os.cpu.CpuUtils;
 import org.junit.Assert;
 import org.junit.Test;
 
 import com.google.common.collect.Lists;
+import com.google.common.io.CharSource;
+import com.google.common.io.Files;
 import com.netflix.spectator.api.DefaultRegistry;
 import com.netflix.spectator.api.ManualClock;
 import com.netflix.spectator.api.Measurement;
@@ -43,9 +47,10 @@ public class TestOsMeter {
   Registry registry = new DefaultRegistry(new ManualClock());
 
   @Test
-  public void testCalcMeasurement(@Mocked Runtime runtime, @Mocked RuntimeMXBean mxBean) {
+  public void testCalcMeasurement(@Mocked Runtime runtime, @Mocked RuntimeMXBean mxBean,
+      @Mocked CharSource charSource) throws IOException {
     List<String> list = new ArrayList<>();
-    list.add("cpu  1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1");
+    list.add("useless");
     list.add("useless");
     list.add("eth0: 0 0    0    0    0     0          0          0         0 0    0      0     0     0    0    0");
     new MockUp<FileUtils>() {
@@ -54,6 +59,18 @@ public class TestOsMeter {
         return list;
       }
     };
+    new MockUp<CpuUtils>() {
+      @Mock
+      public int calcHertz() {
+        return 4;
+      }
+    };
+    new MockUp<Files>() {
+      @Mock
+      public CharSource asCharSource(File file, Charset encoding) {
+        return charSource;
+      }
+    };
     new MockUp<ManagementFactory>() {
       @Mock
       RuntimeMXBean getRuntimeMXBean() {
@@ -70,21 +87,26 @@ public class TestOsMeter {
       {
         runtime.availableProcessors();
         result = 2;
-        mxBean.getName();
-        result = "6666@desktop111";
+        charSource.readFirstLine();
+        result = "1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1";
       }
     };
     OsMeter osMeter = new OsMeter(registry);
     list.clear();
-    list.add("cpu  2 2 2 2 2 2 2 2 0 0 2 2 2 2 2 2 2 2 2 2");
+    list.add("useless");
     list.add("useless");
     list.add("eth0: 1 1    0    0    0     0          0          1         1 1    1      0     0     0    0    0");
-
+    new Expectations() {
+      {
+        charSource.readFirstLine();
+        result = "2 2 2 2 2 2 2 2 2 0 0 2 2 2 2 2 2 2 2 2 2";
+      }
+    };
     osMeter.calcMeasurements(1, 1);
     ArrayList<Measurement> measurements = Lists.newArrayList(osMeter.measure());
     Assert.assertEquals(6, measurements.size());
     Assert.assertEquals(1.75, measurements.get(0).value(), 0.0);
-    Assert.assertEquals(1.0, measurements.get(1).value(), 0.0);
+    Assert.assertEquals(0.5, measurements.get(1).value(), 0.0);
     Assert.assertEquals(1.0, measurements.get(2).value(), 0.0);
     Assert.assertEquals(1.0, measurements.get(3).value(), 0.0);
     Assert.assertEquals(1.0, measurements.get(4).value(), 0.0);