Skip to content

Commit

Permalink
Use reflection to get metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
coderzc committed Jul 29, 2022
1 parent 10b4d9b commit 38bc31c
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 36 deletions.
3 changes: 0 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1772,9 +1772,6 @@ flexible messaging model and an intuitive client API.</description>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<release>${pulsar.broker.compiler.release}</release>
<compilerArgs>
<arg>--add-opens java.base/jdk.internal.platform=ALL-UNNAMED</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import com.google.common.base.Charsets;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand All @@ -29,11 +30,10 @@
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.platform.Container;
import jdk.internal.platform.Metrics;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.SystemUtils;
Expand All @@ -49,10 +49,29 @@ public class LinuxInfoUtils {
private static final int ARPHRD_ETHER = 1;
private static final String NIC_SPEED_TEMPLATE = "/sys/class/net/%s/speed";

private static final Metrics METRICS;
private static Object /*jdk.internal.platform.Metrics*/ metrics;
private static Method getMetricsProviderMethod;
private static Method getCpuQuotaMethod;
private static Method getCpuPeriodMethod;
private static Method getCpuUsageMethod;

static {
METRICS = Container.metrics();
try {
metrics = Class.forName("jdk.internal.platform.Container").getMethod("metrics")
.invoke(null);
if (metrics != null) {
getMetricsProviderMethod = metrics.getClass().getMethod("getProvider");
getMetricsProviderMethod.setAccessible(true);
getCpuQuotaMethod = metrics.getClass().getMethod("getCpuQuota");
getCpuQuotaMethod.setAccessible(true);
getCpuPeriodMethod = metrics.getClass().getMethod("getCpuPeriod");
getCpuPeriodMethod.setAccessible(true);
getCpuUsageMethod = metrics.getClass().getMethod("getCpuUsage");
getCpuUsageMethod.setAccessible(true);
}
} catch (Throwable e) {
log.warn("Failed to get runtime metrics", e);
}
}

/**
Expand All @@ -68,10 +87,10 @@ public static boolean isLinux() {
*/
public static boolean isCGroupEnabled() {
try {
if (METRICS == null) {
if (metrics == null) {
return false;
}
String provider = METRICS.getProvider();
String provider = (String) getMetricsProviderMethod.invoke(metrics);
log.info("[LinuxInfo] The system metrics provider is: {}", provider);
return provider.contains("cgroup");
} catch (Exception e) {
Expand All @@ -85,10 +104,11 @@ public static boolean isCGroupEnabled() {
* @param isCGroupsEnabled Whether CGroup is enabled
* @return Total cpu limit
*/
@SneakyThrows
public static double getTotalCpuLimit(boolean isCGroupsEnabled) {
if (isCGroupsEnabled) {
long quota = METRICS.getCpuQuota();
long period = METRICS.getCpuPeriod();
long quota = (long) getCpuQuotaMethod.invoke(metrics);
long period = (long) getCpuPeriodMethod.invoke(metrics);
if (quota > 0) {
return 100.0 * quota / period;
}
Expand All @@ -101,8 +121,12 @@ public static double getTotalCpuLimit(boolean isCGroupsEnabled) {
* Get CGroup cpu usage.
* @return Cpu usage
*/
public static double getCpuUsageForCGroup() {
return METRICS.getCpuUsage();
@SneakyThrows
public static long getCpuUsageForCGroup() {
if (getCpuUsageMethod == null) {
return -1;
}
return (long) getCpuUsageMethod.invoke(metrics);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ private double getTotalCpuUsage(double elapsedTimeSeconds) {
}

private double getTotalCpuUsageForCGroup(double elapsedTimeSeconds) {
double usage = getCpuUsageForCGroup();
double usage = (double) getCpuUsageForCGroup();
double currentUsage = usage - lastCpuUsage;
lastCpuUsage = usage;
return 100 * currentUsage / elapsedTimeSeconds / TimeUnit.SECONDS.toNanos(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,12 @@
import static org.mockito.Mockito.spy;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import com.google.common.base.Charsets;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.SystemUtils;
import org.apache.pulsar.broker.PulsarServerException;
import org.apache.pulsar.broker.PulsarService;
import org.apache.pulsar.broker.ServiceConfiguration;
Expand Down Expand Up @@ -106,36 +103,23 @@ public void testNoNICSpeed() throws Exception {

@Test
public void testCGroupMetrics() throws IOException {
if (!SystemUtils.IS_OS_LINUX) {
if (!LinuxInfoUtils.isLinux()) {
return;
}

boolean existsCGroup = Files.exists(Paths.get("/sys/fs/cgroup/cpu/cpuacct.usage"));
boolean existsCGroup = Files.exists(Paths.get("/sys/fs/cgroup"));
boolean cGroupEnabled = LinuxInfoUtils.isCGroupEnabled();
Assert.assertEquals(cGroupEnabled, existsCGroup);

double totalCpuLimit = LinuxInfoUtils.getTotalCpuLimit(cGroupEnabled);
double expectTotalCpuLimit = getTotalCpuLimit(cGroupEnabled);
Assert.assertEquals(totalCpuLimit, expectTotalCpuLimit);
log.info("totalCpuLimit: {}", totalCpuLimit);
Assert.assertTrue(totalCpuLimit > 0.0);

if (cGroupEnabled) {
double cpuUsageForCGroup = LinuxInfoUtils.getCpuUsageForCGroup();
long cpuUsageForCGroup = LinuxInfoUtils.getCpuUsageForCGroup();
log.info("cpuUsageForCGroup: {}", cpuUsageForCGroup);
Assert.assertTrue(cpuUsageForCGroup > 0);
}
}

public static double getTotalCpuLimit(boolean isCGroupsEnabled) throws IOException {
if (isCGroupsEnabled) {
long quota = Long.parseLong(
Files.readString(Path.of("/sys/fs/cgroup/cpu/cpu.cfs_quota_us"), Charsets.UTF_8).trim());
long period = Long.parseLong(
Files.readString(Path.of("/sys/fs/cgroup/cpu/cpu.cfs_period_us"), Charsets.UTF_8).trim());
if (quota > 0) {
return 100.0 * quota / period;
}
}
// Fallback to JVM reported CPU quota
return 100 * Runtime.getRuntime().availableProcessors();
}

}

0 comments on commit 38bc31c

Please sign in to comment.