You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by jb...@apache.org on 2021/11/19 19:44:22 UTC

[geode] 02/16: Basic OSHI based stats.

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

jbarrett pushed a commit to branch wip/oshi-multios-stats-module
in repository https://gitbox.apache.org/repos/asf/geode.git

commit 2a8bdb42d7a7713b22fd4550ff2915eee16139ab
Author: Jacob Barrett <jb...@pivotal.io>
AuthorDate: Fri Jun 11 07:28:08 2021 -0700

    Basic OSHI based stats.
---
 geode-core/build.gradle                            |   4 +-
 .../platform/OshiStatisticsBenchmark.java          | 321 +++++++++++++++++++++
 .../platform/OshiStatisticsBenchmarkTest.java      |  25 ++
 .../internal/statistics/OsStatisticsProvider.java  |  62 +++-
 .../statistics/platform/OshiProcessStats.java      |  82 ++++++
 .../statistics/platform/OshiStatistics.java        | 109 +++++++
 .../statistics/platform/OshiSystemStats.java       | 136 +++++++++
 .../internal/beans/MemberMBeanBridge.java          |   2 +-
 .../statistics/platform/OshiStatisticsTest.java    | 103 +++++++
 9 files changed, 832 insertions(+), 12 deletions(-)

diff --git a/geode-core/build.gradle b/geode-core/build.gradle
index c9c9b7b..eaa2f54 100755
--- a/geode-core/build.gradle
+++ b/geode-core/build.gradle
@@ -312,6 +312,9 @@ dependencies {
   //RMIIO is used for uploading jar files and copying them between locator an servers
   implementation('com.healthmarketscience.rmiio:rmiio')
 
+  // OSHI OS system stats
+  implementation('com.github.oshi:oshi-core:5.7.4')
+
   //Geode-common has annotations and other pieces used geode-core
   api(project(':geode-common'))
   implementation(project(':geode-logging'))
@@ -324,7 +327,6 @@ dependencies {
   //copied into it, so it is an API dependency
   api(project(':geode-management'))
 
-
   jcaImplementation(sourceSets.main.output)
 
   testImplementation(project(':geode-junit')) {
diff --git a/geode-core/src/jmh/java/org/apache/geode/internal/statistics/platform/OshiStatisticsBenchmark.java b/geode-core/src/jmh/java/org/apache/geode/internal/statistics/platform/OshiStatisticsBenchmark.java
new file mode 100644
index 0000000..d6fbb07
--- /dev/null
+++ b/geode-core/src/jmh/java/org/apache/geode/internal/statistics/platform/OshiStatisticsBenchmark.java
@@ -0,0 +1,321 @@
+/*
+ * 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 java.util.concurrent.TimeUnit;
+import java.util.function.DoubleSupplier;
+import java.util.function.IntSupplier;
+import java.util.function.LongSupplier;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+import oshi.SystemInfo;
+
+import org.apache.geode.StatisticDescriptor;
+import org.apache.geode.StatisticsType;
+import org.apache.geode.internal.statistics.SuppliableStatistics;
+
+@State(Scope.Benchmark)
+@BenchmarkMode(Mode.SampleTime)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+public class OshiStatisticsBenchmark {
+
+  private final int pid = new SystemInfo().getOperatingSystem().getProcessId();
+  private final SuppliableStatistics noopStatistics = new NoopStatistics();
+
+  @Setup
+  public void setup() {
+    OshiStatistics.init();
+  }
+
+  @Benchmark
+  public void noop() {
+
+  }
+
+  @Benchmark
+  public void refreshProcess() {
+    OshiStatistics.refreshProcess(pid, noopStatistics);
+  }
+
+  @Benchmark
+  public void refreshSystem() {
+    OshiStatistics.refreshSystem(noopStatistics);
+  }
+
+  private static class NoopStatistics implements SuppliableStatistics {
+    @Override
+    public int updateSuppliedValues() {
+      return 0;
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public int nameToId(final String name) {
+      return 0;
+    }
+
+    @Override
+    public StatisticDescriptor nameToDescriptor(final String name) {
+      return null;
+    }
+
+    @Override
+    public long getUniqueId() {
+      return 0;
+    }
+
+    @Override
+    public StatisticsType getType() {
+      return null;
+    }
+
+    @Override
+    public String getTextId() {
+      return null;
+    }
+
+    @Override
+    public long getNumericId() {
+      return 0;
+    }
+
+    @Override
+    public boolean isAtomic() {
+      return false;
+    }
+
+    @Override
+    public boolean isClosed() {
+      return false;
+    }
+
+    @Override
+    public void setInt(final int id, final int value) {
+
+    }
+
+    @Override
+    public void setInt(final String name, final int value) {
+
+    }
+
+    @Override
+    public void setInt(final StatisticDescriptor descriptor, final int value) {
+
+    }
+
+    @Override
+    public void setLong(final int id, final long value) {
+
+    }
+
+    @Override
+    public void setLong(final StatisticDescriptor descriptor, final long value) {
+
+    }
+
+    @Override
+    public void setLong(final String name, final long value) {
+
+    }
+
+    @Override
+    public void setDouble(final int id, final double value) {
+
+    }
+
+    @Override
+    public void setDouble(final StatisticDescriptor descriptor, final double value) {
+
+    }
+
+    @Override
+    public void setDouble(final String name, final double value) {
+
+    }
+
+    @Override
+    public int getInt(final int id) {
+      return 0;
+    }
+
+    @Override
+    public int getInt(final StatisticDescriptor descriptor) {
+      return 0;
+    }
+
+    @Override
+    public int getInt(final String name) {
+      return 0;
+    }
+
+    @Override
+    public long getLong(final int id) {
+      return 0;
+    }
+
+    @Override
+    public long getLong(final StatisticDescriptor descriptor) {
+      return 0;
+    }
+
+    @Override
+    public long getLong(final String name) {
+      return 0;
+    }
+
+    @Override
+    public double getDouble(final int id) {
+      return 0;
+    }
+
+    @Override
+    public double getDouble(final StatisticDescriptor descriptor) {
+      return 0;
+    }
+
+    @Override
+    public double getDouble(final String name) {
+      return 0;
+    }
+
+    @Override
+    public Number get(final StatisticDescriptor descriptor) {
+      return null;
+    }
+
+    @Override
+    public Number get(final String name) {
+      return null;
+    }
+
+    @Override
+    public long getRawBits(final StatisticDescriptor descriptor) {
+      return 0;
+    }
+
+    @Override
+    public long getRawBits(final String name) {
+      return 0;
+    }
+
+    @Override
+    public void incInt(final int id, final int delta) {
+
+    }
+
+    @Override
+    public void incInt(final StatisticDescriptor descriptor, final int delta) {
+
+    }
+
+    @Override
+    public void incInt(final String name, final int delta) {
+
+    }
+
+    @Override
+    public void incLong(final int id, final long delta) {
+
+    }
+
+    @Override
+    public void incLong(final StatisticDescriptor descriptor, final long delta) {
+
+    }
+
+    @Override
+    public void incLong(final String name, final long delta) {
+
+    }
+
+    @Override
+    public void incDouble(final int id, final double delta) {
+
+    }
+
+    @Override
+    public void incDouble(final StatisticDescriptor descriptor, final double delta) {
+
+    }
+
+    @Override
+    public void incDouble(final String name, final double delta) {
+
+    }
+
+    @Override
+    public IntSupplier setIntSupplier(final int id, final IntSupplier supplier) {
+      return null;
+    }
+
+    @Override
+    public IntSupplier setIntSupplier(final String name, final IntSupplier supplier) {
+      return null;
+    }
+
+    @Override
+    public IntSupplier setIntSupplier(final StatisticDescriptor descriptor,
+                                      final IntSupplier supplier) {
+      return null;
+    }
+
+    @Override
+    public LongSupplier setLongSupplier(final int id, final LongSupplier supplier) {
+      return null;
+    }
+
+    @Override
+    public LongSupplier setLongSupplier(final String name, final LongSupplier supplier) {
+      return null;
+    }
+
+    @Override
+    public LongSupplier setLongSupplier(final StatisticDescriptor descriptor,
+                                        final LongSupplier supplier) {
+      return null;
+    }
+
+    @Override
+    public DoubleSupplier setDoubleSupplier(final int id, final DoubleSupplier supplier) {
+      return null;
+    }
+
+    @Override
+    public DoubleSupplier setDoubleSupplier(final String name, final DoubleSupplier supplier) {
+      return null;
+    }
+
+    @Override
+    public DoubleSupplier setDoubleSupplier(final StatisticDescriptor descriptor,
+                                            final DoubleSupplier supplier) {
+      return null;
+    }
+  }
+}
diff --git a/geode-core/src/jmhTest/java/org/apache/geode/internal/statistics/platform/OshiStatisticsBenchmarkTest.java b/geode-core/src/jmhTest/java/org/apache/geode/internal/statistics/platform/OshiStatisticsBenchmarkTest.java
new file mode 100644
index 0000000..db0d965
--- /dev/null
+++ b/geode-core/src/jmhTest/java/org/apache/geode/internal/statistics/platform/OshiStatisticsBenchmarkTest.java
@@ -0,0 +1,25 @@
+/*
+ * 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.junit.Test;
+
+public class OshiStatisticsBenchmarkTest {
+  @Test
+  public void getsValidValues() {
+
+  }
+}
diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/OsStatisticsProvider.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/OsStatisticsProvider.java
index d274bf1..f2c0011 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/statistics/OsStatisticsProvider.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/OsStatisticsProvider.java
@@ -14,15 +14,24 @@
  */
 package org.apache.geode.internal.statistics;
 
+import static org.apache.geode.internal.lang.SystemUtils.isLinux;
+import static org.apache.geode.internal.lang.SystemUtils.isMacOS;
+
 import java.net.UnknownHostException;
 
+import org.jetbrains.annotations.NotNull;
+
 import org.apache.geode.Statistics;
+import org.apache.geode.StatisticsType;
 import org.apache.geode.internal.inet.LocalHostUtil;
 import org.apache.geode.internal.lang.SystemUtils;
 import org.apache.geode.internal.statistics.platform.LinuxProcFsStatistics;
 import org.apache.geode.internal.statistics.platform.LinuxProcessStats;
 import org.apache.geode.internal.statistics.platform.LinuxSystemStats;
 import org.apache.geode.internal.statistics.platform.OsStatisticsFactory;
+import org.apache.geode.internal.statistics.platform.OshiProcessStats;
+import org.apache.geode.internal.statistics.platform.OshiStatistics;
+import org.apache.geode.internal.statistics.platform.OshiSystemStats;
 import org.apache.geode.internal.statistics.platform.ProcessStats;
 
 /**
@@ -39,7 +48,7 @@ public class OsStatisticsProvider {
   }
 
   private OsStatisticsProvider() {
-    osStatsSupported = SystemUtils.isLinux();
+    osStatsSupported = isLinux() || SystemUtils.isMacOS();
   }
 
   public static OsStatisticsProvider build() {
@@ -47,7 +56,12 @@ public class OsStatisticsProvider {
   }
 
   int initOSStats() {
-    return LinuxProcFsStatistics.init();
+    if (isLinux()) {
+      return LinuxProcFsStatistics.init();
+    } else if (isMacOS()) {
+      return OshiStatistics.init();
+    }
+    return 1;
   }
 
   void closeOSStats() {
@@ -55,7 +69,11 @@ public class OsStatisticsProvider {
   }
 
   void readyRefreshOSStats() {
-    LinuxProcFsStatistics.readyRefresh();
+    if (isLinux()) {
+      LinuxProcFsStatistics.readyRefresh();
+    } else if (isMacOS()) {
+      OshiStatistics.readyRefresh();
+    }
   }
 
   /**
@@ -64,7 +82,11 @@ public class OsStatisticsProvider {
    */
   private void refreshProcess(LocalStatisticsImpl statistics) {
     int pid = (int) statistics.getNumericId();
-    LinuxProcFsStatistics.refreshProcess(pid, statistics);
+    if (isLinux()) {
+      LinuxProcFsStatistics.refreshProcess(pid, statistics);
+    } else if (isMacOS()) {
+      OshiStatistics.refreshProcess(pid, statistics);
+    }
   }
 
   /**
@@ -72,7 +94,11 @@ public class OsStatisticsProvider {
    * machine and storing them in the instance.
    */
   private void refreshSystem(LocalStatisticsImpl statistics) {
-    LinuxProcFsStatistics.refreshSystem(statistics);
+    if (isLinux()) {
+      LinuxProcFsStatistics.refreshSystem(statistics);
+    } else if (isMacOS()) {
+      OshiStatistics.refreshSystem(statistics);
+    }
   }
 
   /**
@@ -95,12 +121,19 @@ public class OsStatisticsProvider {
    */
   Statistics newProcess(OsStatisticsFactory osStatisticsFactory, long pid, String name) {
     Statistics statistics;
-    statistics = osStatisticsFactory.createOsStatistics(LinuxProcessStats.getType(), name, pid,
+    statistics = osStatisticsFactory.createOsStatistics(getProcessStatType(), name, pid,
         PROCESS_STAT_FLAG);
     // Note we don't call refreshProcess since we only want the manager to do that
     return statistics;
   }
 
+  private static StatisticsType getProcessStatType() {
+    if (isLinux()) {
+      return LinuxProcessStats.getType();
+    }
+    return OshiProcessStats.getType();
+  }
+
   /**
    * Creates a new <code>ProcessStats</code> instance that wraps the given <code>Statistics</code>.
    *
@@ -111,22 +144,31 @@ public class OsStatisticsProvider {
     if (statistics instanceof LocalStatisticsImpl) {
       refresh((LocalStatisticsImpl) statistics);
     } // otherwise its a Dummy implementation so do nothing
-    return LinuxProcessStats.createProcessStats(statistics);
+    if (isLinux()) {
+      return LinuxProcessStats.createProcessStats(statistics);
+    }
+    return OshiProcessStats.createProcessStats(statistics);
   }
 
   /**
    * Creates a {@link Statistics} with the current machine's stats. The resource's stats
    * will contain a snapshot of the current statistic values for the local machine.
    */
-  void newSystem(OsStatisticsFactory osStatisticsFactory, long id) {
-    Statistics statistics;
-    statistics = osStatisticsFactory.createOsStatistics(LinuxSystemStats.getType(),
+  void newSystem(final @NotNull OsStatisticsFactory osStatisticsFactory, long id) {
+    final Statistics statistics = osStatisticsFactory.createOsStatistics(getSystemStatType(),
         getHostSystemName(), id, SYSTEM_STAT_FLAG);
     if (statistics instanceof LocalStatisticsImpl) {
       refreshSystem((LocalStatisticsImpl) statistics);
     } // otherwise its a Dummy implementation so do nothing
   }
 
+  public static StatisticsType getSystemStatType() {
+    if (isLinux()) {
+      return LinuxSystemStats.getType();
+    }
+    return OshiSystemStats.getType();
+  }
+
   /**
    * @return this machine's fully qualified hostname or "unknownHostName" if one cannot be found.
    */
diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/platform/OshiProcessStats.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/platform/OshiProcessStats.java
new file mode 100644
index 0000000..23e6541
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/platform/OshiProcessStats.java
@@ -0,0 +1,82 @@
+/*
+ * 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.jetbrains.annotations.NotNull;
+
+import org.apache.geode.StatisticDescriptor;
+import org.apache.geode.Statistics;
+import org.apache.geode.StatisticsType;
+import org.apache.geode.StatisticsTypeFactory;
+import org.apache.geode.annotations.Immutable;
+import org.apache.geode.internal.statistics.StatisticsTypeFactoryImpl;
+
+public class OshiProcessStats {
+  static final int virtualSize;
+  static final int residentSetSize;
+  static final int threadCount;
+  static final int kernelTime;
+  static final int userTime;
+
+  @Immutable
+  private static final StatisticsType statisticsType;
+
+  static {
+    final StatisticsTypeFactory f = StatisticsTypeFactoryImpl.singleton();
+
+    statisticsType = f.createType("OSProcessStats", "Statistics on a OS process.",
+        new StatisticDescriptor[]{
+            f.createLongGauge("virtualSize",
+                "Gets the Virtual Memory Size (VSZ). Includes all memory that the process can access, including memory that is swapped out and memory that is from shared libraries.",
+                "bytes"),
+            f.createLongGauge("residentSetSize",
+                "Gets the Resident Set Size (RSS). Used to show how much memory is allocated to that process and is in RAM. It does not include memory that is swapped out. It does include memory from shared libraries as long as the pages from those libraries are actually in memory. It does include all stack and heap memory.",
+                "bytes"),
+            f.createLongGauge("threadCount",
+                "Gets the number of threads being executed by this process.",
+                "threads"),
+            f.createLongCounter("kernelTime",
+                "Gets kernel time used by the process.",
+                "milliseconds"),
+            f.createLongCounter("userTime",
+                "Gets user time used by the process.",
+                "milliseconds")
+        });
+
+    virtualSize = statisticsType.nameToId("virtualSize");
+    residentSetSize = statisticsType.nameToId("residentSetSize");
+    threadCount = statisticsType.nameToId("threadCount");
+    kernelTime = statisticsType.nameToId("kernelTime");
+    userTime = statisticsType.nameToId("userTime");
+  }
+
+  private OshiProcessStats() {
+    // no instances allowed
+  }
+
+  public static @NotNull StatisticsType getType() {
+    return statisticsType;
+  }
+
+  public static ProcessStats createProcessStats(final @NotNull Statistics stats) {
+    return new ProcessStats(stats) {
+      @Override
+      public long getProcessSize() {
+        return stats.getLong(residentSetSize);
+      }
+    };
+  }
+}
diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/platform/OshiStatistics.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/platform/OshiStatistics.java
new file mode 100644
index 0000000..2da3f55
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/platform/OshiStatistics.java
@@ -0,0 +1,109 @@
+/*
+ * 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.jetbrains.annotations.NotNull;
+import oshi.SystemInfo;
+import oshi.hardware.CentralProcessor;
+import oshi.hardware.CentralProcessor.TickType;
+import oshi.hardware.HardwareAbstractionLayer;
+import oshi.software.os.OSProcess;
+import oshi.software.os.OperatingSystem;
+
+import org.apache.geode.internal.statistics.LocalStatisticsImpl;
+import org.apache.geode.internal.statistics.SuppliableStatistics;
+
+public class OshiStatistics {
+
+  private static final OshiStatistics instance;
+
+  static {
+    final SystemInfo systemInfo = new SystemInfo();
+    instance = new OshiStatistics(systemInfo.getOperatingSystem(), systemInfo.getHardware());
+  }
+
+  private final OperatingSystem operatingSystem;
+  private final HardwareAbstractionLayer hardware;
+
+  OshiStatistics(final @NotNull OperatingSystem operatingSystem,
+                 final @NotNull HardwareAbstractionLayer hardware) {
+    this.operatingSystem = operatingSystem;
+    this.hardware = hardware;
+  }
+
+  public static int init() {
+    return 0;
+  }
+
+  public static void readyRefresh() {
+
+  }
+
+  public static void refreshProcess(final int pid, final SuppliableStatistics stats) {
+    instance.updateProcessStats(pid, stats);
+  }
+
+  public static void refreshSystem(final SuppliableStatistics stats) {
+    instance.updateSystemStats(stats);
+  }
+
+  public void updateProcessStats(final int pid, final SuppliableStatistics stats) {
+    final OSProcess process = operatingSystem.getProcess(pid);
+    stats.setLong(OshiProcessStats.virtualSize, process.getVirtualSize());
+    stats.setLong(OshiProcessStats.residentSetSize, process.getResidentSetSize());
+    stats.setLong(OshiProcessStats.threadCount, process.getThreadCount());
+    stats.setLong(OshiProcessStats.kernelTime, process.getKernelTime());
+    stats.setLong(OshiProcessStats.userTime, process.getUserTime());
+  }
+
+  public void updateSystemStats(final SuppliableStatistics stats) {
+    stats.setLong(OshiSystemStats.processCount, operatingSystem.getProcessCount());
+    stats.setLong(OshiSystemStats.threadCount, operatingSystem.getThreadCount());
+
+    final CentralProcessor processor = hardware.getProcessor();
+    stats.setLong(OshiSystemStats.contextSwitches, processor.getContextSwitches());
+    stats.setLong(OshiSystemStats.interrupts, processor.getInterrupts());
+    stats.setLong(OshiSystemStats.physicalProcessorCount, processor.getPhysicalProcessorCount());
+    stats.setLong(OshiSystemStats.logicalProcessorCount, processor.getLogicalProcessorCount());
+    stats.setLong(OshiSystemStats.maxFreq, processor.getMaxFreq());
+
+    final double[] systemLoadAverage = processor.getSystemLoadAverage(3);
+    stats.setDouble(OshiSystemStats.systemLoadAverage1, systemLoadAverage[0]);
+    stats.setDouble(OshiSystemStats.systemLoadAverage5, systemLoadAverage[1]);
+    stats.setDouble(OshiSystemStats.systemLoadAverage15, systemLoadAverage[2]);
+
+    long[] systemCpuLoadTicks = processor.getSystemCpuLoadTicks();
+    stats.setLong(OshiSystemStats.systemCpuLoadTicksUSER,
+        systemCpuLoadTicks[TickType.USER.getIndex()]);
+    stats.setLong(OshiSystemStats.systemCpuLoadTicksNICE,
+        systemCpuLoadTicks[TickType.NICE.getIndex()]);
+    stats.setLong(OshiSystemStats.systemCpuLoadTicksSYSTEM,
+        systemCpuLoadTicks[TickType.SYSTEM.getIndex()]);
+    stats.setLong(OshiSystemStats.systemCpuLoadTicksIDLE,
+        systemCpuLoadTicks[TickType.IDLE.getIndex()]);
+    stats.setLong(OshiSystemStats.systemCpuLoadTicksIOWAIT,
+        systemCpuLoadTicks[TickType.IOWAIT.getIndex()]);
+    stats.setLong(OshiSystemStats.systemCpuLoadTicksIRQ,
+        systemCpuLoadTicks[TickType.IRQ.getIndex()]);
+    stats.setLong(OshiSystemStats.systemCpuLoadTicksSOFTIRQ,
+        systemCpuLoadTicks[TickType.SOFTIRQ.getIndex()]);
+    stats.setLong(OshiSystemStats.systemCpuLoadTicksSTEAL,
+        systemCpuLoadTicks[TickType.STEAL.getIndex()]);
+
+    final long[] currentFreq = processor.getCurrentFreq();
+  }
+
+}
diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/platform/OshiSystemStats.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/platform/OshiSystemStats.java
new file mode 100644
index 0000000..7693cd0
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/platform/OshiSystemStats.java
@@ -0,0 +1,136 @@
+/*
+ * 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.jetbrains.annotations.NotNull;
+
+import org.apache.geode.StatisticDescriptor;
+import org.apache.geode.StatisticsType;
+import org.apache.geode.StatisticsTypeFactory;
+import org.apache.geode.annotations.Immutable;
+import org.apache.geode.internal.statistics.StatisticsTypeFactoryImpl;
+
+public class OshiSystemStats {
+  static final int processCount;
+  static final int threadCount;
+  static final int contextSwitches;
+  static final int interrupts;
+  static final int physicalProcessorCount;
+  static final int logicalProcessorCount;
+  static final int maxFreq;
+  static final int systemLoadAverage1;
+  static final int systemLoadAverage5;
+  static final int systemLoadAverage15;
+  static final int systemCpuLoadTicksUSER;
+  static final int systemCpuLoadTicksNICE;
+  static final int systemCpuLoadTicksSYSTEM;
+  static final int systemCpuLoadTicksIDLE;
+  static final int systemCpuLoadTicksIOWAIT;
+  static final int systemCpuLoadTicksIRQ;
+  static final int systemCpuLoadTicksSOFTIRQ;
+  static final int systemCpuLoadTicksSTEAL;
+
+  @Immutable
+  private static final StatisticsType statisticsType;
+
+  static {
+    final StatisticsTypeFactory f = StatisticsTypeFactoryImpl.singleton();
+
+    statisticsType = f.createType("OperatingSystemStats", "Statistics for an Operating System.",
+        new StatisticDescriptor[] {
+            f.createLongGauge("processCount", "Get the number of processes currently running.",
+                "processes"),
+            f.createLongGauge("threadCount",
+                "Get the number of threads currently running",
+                "threads"),
+            f.createLongCounter("contextSwitches",
+                "Get the number of system-wide context switches which have occurred.",
+                "operations", false),
+            f.createLongCounter("interrupts",
+                "Get the number of system-wide interrupts which have occurred.",
+                "interrupts"),
+            f.createLongGauge("physicalProcessorCount",
+                "Get the number of physical CPUs/cores available for processing.",
+                "processors"),
+            f.createLongGauge("logicalProcessorCount",
+                "Get the number of logical CPUs available for processing. This value may be higher than physical CPUs if hyperthreading is enabled.",
+                "processors"),
+            f.createLongGauge("maxFreq",
+                "Maximum frequency (in Hz), of the logical processors on this CPU.",
+                "Hz"),
+            f.createLongCounter("systemCpuLoadTicksUSER",
+                "Time spent in User",
+                "milliseconds"),
+            f.createLongCounter("systemCpuLoadTicksNICE",
+                "Time spent in Nice",
+                "milliseconds"),
+            f.createLongCounter("systemCpuLoadTicksSYSTEM",
+                "Time spent in System",
+                "milliseconds"),
+            f.createLongCounter("systemCpuLoadTicksIDLE",
+                "Time spent in Idle",
+                "milliseconds"),
+            f.createLongCounter("systemCpuLoadTicksIOWAIT",
+                "Time spent in IOWait",
+                "milliseconds"),
+            f.createLongCounter("systemCpuLoadTicksIRQ",
+                "Time spent in IRQ",
+                "milliseconds"),
+            f.createLongCounter("systemCpuLoadTicksSOFTIRQ",
+                "Time spent in SoftIRQ",
+                "milliseconds"),
+            f.createLongCounter("systemCpuLoadTicksSTEAL",
+                "Time spent in Steal",
+                "milliseconds"),
+            f.createDoubleGauge("systemLoadAverage1",
+                "The system load average is the sum of the number of runnable entities queued to the available processors and the number of runnable entities running on the available processors averaged over 1 minute.",
+                "processors"),
+            f.createDoubleGauge("systemLoadAverage5",
+                "The system load average is the sum of the number of runnable entities queued to the available processors and the number of runnable entities running on the available processors averaged over 5 minutes.",
+                "processors"),
+            f.createDoubleGauge("systemLoadAverage15",
+                "The system load average is the sum of the number of runnable entities queued to the available processors and the number of runnable entities running on the available processors averaged over 15 minutes.",
+                "processors"),
+    });
+
+    processCount = statisticsType.nameToId("processCount");
+    threadCount = statisticsType.nameToId("threadCount");
+    contextSwitches = statisticsType.nameToId("contextSwitches");
+    interrupts = statisticsType.nameToId("interrupts");
+    physicalProcessorCount = statisticsType.nameToId("physicalProcessorCount");
+    logicalProcessorCount = statisticsType.nameToId("logicalProcessorCount");
+    maxFreq = statisticsType.nameToId("maxFreq");
+    systemLoadAverage1 = statisticsType.nameToId("systemLoadAverage1");
+    systemLoadAverage5 = statisticsType.nameToId("systemLoadAverage5");
+    systemLoadAverage15 = statisticsType.nameToId("systemLoadAverage15");
+    systemCpuLoadTicksUSER = statisticsType.nameToId("systemCpuLoadTicksUSER");
+    systemCpuLoadTicksNICE = statisticsType.nameToId("systemCpuLoadTicksNICE");
+    systemCpuLoadTicksSYSTEM = statisticsType.nameToId("systemCpuLoadTicksSYSTEM");
+    systemCpuLoadTicksIDLE = statisticsType.nameToId("systemCpuLoadTicksIDLE");
+    systemCpuLoadTicksIOWAIT = statisticsType.nameToId("systemCpuLoadTicksIOWAIT");
+    systemCpuLoadTicksIRQ = statisticsType.nameToId("systemCpuLoadTicksIRQ");
+    systemCpuLoadTicksSOFTIRQ = statisticsType.nameToId("systemCpuLoadTicksSOFTIRQ");
+    systemCpuLoadTicksSTEAL = statisticsType.nameToId("systemCpuLoadTicksSTEAL");
+  }
+
+  private OshiSystemStats() {
+    // no instances allowed
+  }
+
+  public static @NotNull StatisticsType getType() {
+    return statisticsType;
+  }
+}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/beans/MemberMBeanBridge.java b/geode-core/src/main/java/org/apache/geode/management/internal/beans/MemberMBeanBridge.java
index 993c617..7888901 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/beans/MemberMBeanBridge.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/beans/MemberMBeanBridge.java
@@ -298,7 +298,7 @@ public class MemberMBeanBridge {
 
   private Statistics fetchSystemStats() {
     if (osStatisticsProvider.osStatsSupported()) {
-      Statistics[] systemStats = system.findStatisticsByType(LinuxSystemStats.getType());
+      Statistics[] systemStats = system.findStatisticsByType(OsStatisticsProvider.getSystemStatType());
 
       if (systemStats != null) {
         return systemStats[0];
diff --git a/geode-core/src/test/java/org/apache/geode/internal/statistics/platform/OshiStatisticsTest.java b/geode-core/src/test/java/org/apache/geode/internal/statistics/platform/OshiStatisticsTest.java
new file mode 100644
index 0000000..a8220d8
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/statistics/platform/OshiStatisticsTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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 static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.Test;
+import oshi.hardware.CentralProcessor;
+import oshi.hardware.HardwareAbstractionLayer;
+import oshi.software.os.OSProcess;
+import oshi.software.os.OperatingSystem;
+
+import org.apache.geode.internal.statistics.SuppliableStatistics;
+
+public class OshiStatisticsTest {
+
+  private final OSProcess process = mock(OSProcess.class);
+  private final OperatingSystem operatingSystem = mock(OperatingSystem.class);
+  private final HardwareAbstractionLayer hardwareAbstractionLayer = mock(HardwareAbstractionLayer.class);
+  private final OshiStatistics oshiStatistics = new OshiStatistics(operatingSystem, hardwareAbstractionLayer);
+
+
+  private final SuppliableStatistics stats = mock(SuppliableStatistics.class);
+
+  public OshiStatisticsTest() {
+    when(operatingSystem.getProcess(eq(1))).thenReturn(process);
+  }
+
+  @Test
+  public void testInit() {
+    assertThat(OshiStatistics.init()).isEqualTo(0);
+  }
+
+  @Test
+  public void updateProcessStats() {
+    when(process.getVirtualSize()).thenReturn(42L);
+    when(process.getResidentSetSize()).thenReturn(420L);
+    when(process.getThreadCount()).thenReturn(4200);
+    when(process.getKernelTime()).thenReturn(42000L);
+    when(process.getUserTime()).thenReturn(420000L);
+
+    oshiStatistics.updateProcessStats(1, stats);
+
+    verify(stats).setLong(eq(OshiProcessStats.virtualSize), eq(42L));
+    verify(stats).setLong(eq(OshiProcessStats.residentSetSize), eq(420L));
+    verify(stats).setLong(eq(OshiProcessStats.threadCount), eq(4200L));
+    verify(stats).setLong(eq(OshiProcessStats.kernelTime), eq(42000L));
+    verify(stats).setLong(eq(OshiProcessStats.userTime), eq(420000L));
+  }
+
+  @Test
+  public void updateSystemStats() {
+    when(operatingSystem.getProcessCount()).thenReturn(1);
+    when(operatingSystem.getThreadCount()).thenReturn(2);
+    final CentralProcessor centralProcessor = mock(CentralProcessor.class);
+    when(centralProcessor.getContextSwitches()).thenReturn(3L);
+    when(centralProcessor.getInterrupts()).thenReturn(4L);
+    when(centralProcessor.getPhysicalProcessorCount()).thenReturn(5);
+    when(centralProcessor.getLogicalProcessorCount()).thenReturn(6);
+    when(centralProcessor.getSystemLoadAverage(eq(3))).thenReturn(new double[]{1.0, 2.0, 3.0});
+    when(centralProcessor.getSystemCpuLoadTicks()).thenReturn(new long[]{1, 2, 3, 4, 5, 6, 7, 8});
+    when(hardwareAbstractionLayer.getProcessor()).thenReturn(centralProcessor);
+
+    oshiStatistics.updateSystemStats(stats);
+
+    verify(stats).setLong(eq(OshiSystemStats.processCount), eq(1L));
+    verify(stats).setLong(eq(OshiSystemStats.threadCount), eq(2L));
+    verify(stats).setLong(eq(OshiSystemStats.contextSwitches), eq(3L));
+    verify(stats).setLong(eq(OshiSystemStats.interrupts), eq(4L));
+    verify(stats).setLong(eq(OshiSystemStats.physicalProcessorCount), eq(5L));
+    verify(stats).setLong(eq(OshiSystemStats.logicalProcessorCount), eq(6L));
+    verify(stats).setDouble(eq(OshiSystemStats.systemLoadAverage1), eq(1.0));
+    verify(stats).setDouble(eq(OshiSystemStats.systemLoadAverage5), eq(2.0));
+    verify(stats).setDouble(eq(OshiSystemStats.systemLoadAverage15), eq(3.0));
+    verify(stats).setLong(eq(OshiSystemStats.systemCpuLoadTicksUSER), eq(1L));
+    verify(stats).setLong(eq(OshiSystemStats.systemCpuLoadTicksNICE), eq(2L));
+    verify(stats).setLong(eq(OshiSystemStats.systemCpuLoadTicksSYSTEM), eq(3L));
+    verify(stats).setLong(eq(OshiSystemStats.systemCpuLoadTicksIDLE), eq(4L));
+    verify(stats).setLong(eq(OshiSystemStats.systemCpuLoadTicksIOWAIT), eq(5L));
+    verify(stats).setLong(eq(OshiSystemStats.systemCpuLoadTicksIRQ), eq(6L));
+    verify(stats).setLong(eq(OshiSystemStats.systemCpuLoadTicksSOFTIRQ), eq(7L));
+    verify(stats).setLong(eq(OshiSystemStats.systemCpuLoadTicksSTEAL), eq(8L));
+  }
+
+}
\ No newline at end of file