This is an automated email from the ASF dual-hosted git repository.
frankchen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new 4574dea5e9 Use MXBeans to get GC metrics #12476 (#12481)
4574dea5e9 is described below
commit 4574dea5e92beb72d93e1d6900ce1a63627330d0
Author: Jianhuan Liu <[email protected]>
AuthorDate: Fri Jul 8 14:32:06 2022 +0800
Use MXBeans to get GC metrics #12476 (#12481)
* jvm gc to mxbeans
* add zgc and shenandoah #12476
* remove tryCreateGcCounter
* separate the space collector
* blend GcGenerationCollector into GcCollector
* add jdk surefire argLine
---
.../apache/druid/java/util/metrics/JvmMonitor.java | 304 ++++++++-------------
.../druid/java/util/metrics/JvmMonitorTest.java | 39 +--
pom.xml | 1 -
processing/pom.xml | 1 -
4 files changed, 114 insertions(+), 231 deletions(-)
diff --git
a/core/src/main/java/org/apache/druid/java/util/metrics/JvmMonitor.java
b/core/src/main/java/org/apache/druid/java/util/metrics/JvmMonitor.java
index 77f4033a3d..7c9f6be99d 100644
--- a/core/src/main/java/org/apache/druid/java/util/metrics/JvmMonitor.java
+++ b/core/src/main/java/org/apache/druid/java/util/metrics/JvmMonitor.java
@@ -22,19 +22,13 @@ package org.apache.druid.java.util.metrics;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
-import it.unimi.dsi.fastutil.ints.IntRBTreeSet;
-import it.unimi.dsi.fastutil.ints.IntSet;
-import org.apache.druid.java.util.common.StringUtils;
-import org.apache.druid.java.util.common.logger.Logger;
+import org.apache.druid.java.util.common.Pair;
import org.apache.druid.java.util.emitter.service.ServiceEmitter;
import org.apache.druid.java.util.emitter.service.ServiceMetricEvent;
-import org.gridkit.lab.jvm.perfdata.JStatData;
-import org.gridkit.lab.jvm.perfdata.JStatData.LongCounter;
-import org.gridkit.lab.jvm.perfdata.JStatData.StringCounter;
-import org.gridkit.lab.jvm.perfdata.JStatData.TickCounter;
import javax.annotation.Nullable;
import java.lang.management.BufferPoolMXBean;
+import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryType;
@@ -42,22 +36,15 @@ import java.lang.management.MemoryUsage;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
public class JvmMonitor extends FeedDefiningMonitor
{
- private static final Logger log = new Logger(JvmMonitor.class);
- private static final Pattern PATTERN_GC_GENERATION =
- Pattern.compile("^sun\\.gc\\.(?:generation|collector)\\.(\\d+)\\..*");
private final Map<String, String[]> dimensions;
- private final long pid;
@VisibleForTesting
@Nullable
- final GcCounters gcCounters;
+ final GcCollectors gcCollectors;
@Nullable
private final AllocationMetricCollector collector;
@@ -73,18 +60,12 @@ public class JvmMonitor extends FeedDefiningMonitor
}
public JvmMonitor(Map<String, String[]> dimensions, String feed)
- {
- this(dimensions, feed, JvmPidDiscoverer.instance());
- }
-
- public JvmMonitor(Map<String, String[]> dimensions, String feed,
PidDiscoverer pidDiscoverer)
{
super(feed);
Preconditions.checkNotNull(dimensions);
this.dimensions = ImmutableMap.copyOf(dimensions);
- this.pid = Preconditions.checkNotNull(pidDiscoverer).getPid();
this.collector = AllocationMetricCollectors.getAllocationMetricCollector();
- this.gcCounters = tryCreateGcCounters();
+ this.gcCollectors = new GcCollectors();
}
@Override
@@ -162,199 +143,152 @@ public class JvmMonitor extends FeedDefiningMonitor
private void emitGcMetrics(ServiceEmitter emitter)
{
- if (gcCounters != null) {
- gcCounters.emit(emitter, dimensions);
- }
- }
-
- @Nullable
- private GcCounters tryCreateGcCounters()
- {
- try {
- return new GcCounters();
- }
- catch (RuntimeException e) {
- // in JDK11 jdk.internal.perf.Perf is not accessible, unless
- // --add-exports java.base/jdk.internal.perf=ALL-UNNAMED is set
- log.warn("Cannot initialize GC counters. If running JDK11 and above,"
- + " add --add-exports=java.base/jdk.internal.perf=ALL-UNNAMED"
- + " to the JVM arguments to enable GC counters.");
- }
- return null;
+ gcCollectors.emit(emitter, dimensions);
}
- @VisibleForTesting
- static IntSet getGcGenerations(final Set<String> jStatCounterNames)
+ private class GcCollectors
{
- final IntSet retVal = new IntRBTreeSet();
+ private final List<GcGenerationCollector> generationCollectors = new
ArrayList<>();
+ private final List<GcSpaceCollector> spaceCollectors = new ArrayList<>();
- for (final String counterName : jStatCounterNames) {
- final Matcher m = PATTERN_GC_GENERATION.matcher(counterName);
- if (m.matches()) {
- retVal.add(Integer.parseInt(m.group(1)));
+ GcCollectors()
+ {
+ List<GarbageCollectorMXBean> collectorMxBeans =
ManagementFactory.getGarbageCollectorMXBeans();
+ for (GarbageCollectorMXBean collectorMxBean : collectorMxBeans) {
+ generationCollectors.add(new GcGenerationCollector(collectorMxBean));
}
- }
- return retVal;
- }
+ List<MemoryPoolMXBean> memoryPoolMxBeans =
ManagementFactory.getMemoryPoolMXBeans();
+ for (MemoryPoolMXBean memoryPoolMxBean : memoryPoolMxBeans) {
+ MemoryUsage collectionUsage = memoryPoolMxBean.getCollectionUsage();
+ if (collectionUsage != null) {
+ spaceCollectors.add(new GcSpaceCollector(collectionUsage,
memoryPoolMxBean.getName()));
+ }
+ }
- @VisibleForTesting
- static String getGcGenerationName(final int genIndex)
- {
- switch (genIndex) {
- case 0:
- return "young";
- case 1:
- return "old";
- case 2:
- // Removed in Java 8 but still actual for previous Java versions
- return "perm";
- default:
- return String.valueOf(genIndex);
}
- }
- /**
- * The following GC-related code is partially based on
- *
https://github.com/aragozin/jvm-tools/blob/e0e37692648951440aa1a4ea5046261cb360df70/
- *
sjk-core/src/main/java/org/gridkit/jvmtool/PerfCounterGcCpuUsageMonitor.java
- */
- private class GcCounters
- {
- private final List<GcGeneration> generations = new ArrayList<>();
-
- GcCounters()
+ void emit(ServiceEmitter emitter, Map<String, String[]> dimensions)
{
- // connect to itself
- final JStatData jStatData = JStatData.connect(pid);
- final Map<String, JStatData.Counter<?>> jStatCounters =
jStatData.getAllCounters();
-
- for (int genIndex : getGcGenerations(jStatCounters.keySet())) {
- generations.add(new GcGeneration(jStatCounters, genIndex,
getGcGenerationName(genIndex)));
+ for (GcGenerationCollector generationCollector : generationCollectors) {
+ generationCollector.emit(emitter, dimensions);
}
- }
- void emit(ServiceEmitter emitter, Map<String, String[]> dimensions)
- {
- for (GcGeneration generation : generations) {
- generation.emit(emitter, dimensions);
+ for (GcSpaceCollector spaceCollector : spaceCollectors) {
+ spaceCollector.emit(emitter, dimensions);
}
}
}
- private class GcGeneration
+ private class GcGenerationCollector
{
- private final String name;
- @Nullable
- private final GcGenerationCollector collector;
- private final List<GcGenerationSpace> spaces = new ArrayList<>();
+ private final String generation;
+ private final String collectorName;
+ private final GarbageCollectorMXBean gcBean;
- GcGeneration(Map<String, JStatData.Counter<?>> jStatCounters, long
genIndex, String name)
- {
- this.name = StringUtils.toLowerCase(name);
+ private long lastInvocations = 0;
+ private long lastCpuNanos = 0;
- final String spacesCountKey =
StringUtils.format("sun.gc.generation.%d.spaces", genIndex);
+ private static final String GC_YOUNG_GENERATION_NAME = "young";
+ private static final String GC_OLD_GENERATION_NAME = "old";
+ private static final String GC_ZGC_GENERATION_NAME = "zgc";
- if (jStatCounters.containsKey(spacesCountKey)) {
- final long spacesCount = ((JStatData.LongCounter)
jStatCounters.get(spacesCountKey)).getLong();
- for (long spaceIndex = 0; spaceIndex < spacesCount; spaceIndex++) {
- spaces.add(new GcGenerationSpace(jStatCounters, genIndex,
spaceIndex));
- }
- }
+ private static final String CMS_COLLECTOR_NAME = "cms";
+ private static final String G1_COLLECTOR_NAME = "g1";
+ private static final String PARALLEL_COLLECTOR_NAME = "parallel";
+ private static final String SERIAL_COLLECTOR_NAME = "serial";
+ private static final String ZGC_COLLECTOR_NAME = "zgc";
+ private static final String SHENANDOAN_COLLECTOR_NAME = "shenandoah";
- if
(jStatCounters.containsKey(StringUtils.format("sun.gc.collector.%d.name",
genIndex))) {
- collector = new GcGenerationCollector(jStatCounters, genIndex);
- } else {
- collector = null;
- }
+ GcGenerationCollector(GarbageCollectorMXBean gcBean)
+ {
+ Pair<String, String> gcNamePair = getReadableName(gcBean.getName());
+ this.generation = gcNamePair.lhs;
+ this.collectorName = gcNamePair.rhs;
+ this.gcBean = gcBean;
}
- void emit(ServiceEmitter emitter, Map<String, String[]> dimensions)
+ private Pair<String, String> getReadableName(String name)
{
- ImmutableMap.Builder<String, String[]> dimensionsCopyBuilder =
ImmutableMap
- .<String, String[]>builder()
- .putAll(dimensions)
- .put("gcGen", new String[]{name});
-
- if (collector != null) {
- dimensionsCopyBuilder.put("gcName", new String[]{collector.name});
- }
+ switch (name) {
+ //CMS
+ case "ParNew":
+ return new Pair<>(GC_YOUNG_GENERATION_NAME, CMS_COLLECTOR_NAME);
+ case "ConcurrentMarkSweep":
+ return new Pair<>(GC_OLD_GENERATION_NAME, CMS_COLLECTOR_NAME);
+
+ // G1
+ case "G1 Young Generation":
+ return new Pair<>(GC_YOUNG_GENERATION_NAME, G1_COLLECTOR_NAME);
+ case "G1 Old Generation":
+ return new Pair<>(GC_OLD_GENERATION_NAME, G1_COLLECTOR_NAME);
+
+ // Parallel
+ case "PS Scavenge":
+ return new Pair<>(GC_YOUNG_GENERATION_NAME, PARALLEL_COLLECTOR_NAME);
+ case "PS MarkSweep":
+ return new Pair<>(GC_OLD_GENERATION_NAME, PARALLEL_COLLECTOR_NAME);
+
+ // Serial
+ case "Copy":
+ return new Pair<>(GC_YOUNG_GENERATION_NAME, SERIAL_COLLECTOR_NAME);
+ case "MarkSweepCompact":
+ return new Pair<>(GC_OLD_GENERATION_NAME, SERIAL_COLLECTOR_NAME);
- Map<String, String[]> dimensionsCopy = dimensionsCopyBuilder.build();
+ //zgc
+ case "ZGC":
+ return new Pair<>(GC_ZGC_GENERATION_NAME, ZGC_COLLECTOR_NAME);
- if (collector != null) {
- collector.emit(emitter, dimensionsCopy);
- }
+ //Shenandoah
+ case "Shenandoah Cycles":
+ return new Pair<>(GC_YOUNG_GENERATION_NAME,
SHENANDOAN_COLLECTOR_NAME);
+ case "Shenandoah Pauses":
+ return new Pair<>(GC_OLD_GENERATION_NAME, SHENANDOAN_COLLECTOR_NAME);
- for (GcGenerationSpace space : spaces) {
- space.emit(emitter, dimensionsCopy);
+ default:
+ return new Pair<>(name, name);
}
}
- }
- private class GcGenerationCollector
- {
- private final String name;
- private final LongCounter invocationsCounter;
- private final TickCounter cpuCounter;
- private long lastInvocations = 0;
- private long lastCpuNanos = 0;
-
- GcGenerationCollector(Map<String, JStatData.Counter<?>> jStatCounters,
long genIndex)
+ void emit(ServiceEmitter emitter, Map<String, String[]> dimensions)
{
- String collectorKeyPrefix = StringUtils.format("sun.gc.collector.%d",
genIndex);
+ ImmutableMap.Builder<String, String[]> dimensionsCopyBuilder =
ImmutableMap
+ .<String, String[]>builder()
+ .putAll(dimensions)
+ .put("gcGen", new String[]{generation});
- String nameKey = StringUtils.format("%s.name", collectorKeyPrefix);
- StringCounter nameCounter = (StringCounter) jStatCounters.get(nameKey);
- name = getReadableName(nameCounter.getString());
+ dimensionsCopyBuilder.put("gcName", new String[]{collectorName});
- invocationsCounter = (LongCounter)
jStatCounters.get(StringUtils.format("%s.invocations", collectorKeyPrefix));
- cpuCounter = (TickCounter)
jStatCounters.get(StringUtils.format("%s.time", collectorKeyPrefix));
- }
+ Map<String, String[]> dimensionsCopy = dimensionsCopyBuilder.build();
- void emit(ServiceEmitter emitter, Map<String, String[]> dimensions)
- {
final ServiceMetricEvent.Builder builder = builder();
- MonitorUtils.addDimensionsToBuilder(builder, dimensions);
+ MonitorUtils.addDimensionsToBuilder(builder, dimensionsCopy);
- long newInvocations = invocationsCounter.getLong();
+ long newInvocations = gcBean.getCollectionCount();
emitter.emit(builder.build("jvm/gc/count", newInvocations -
lastInvocations));
lastInvocations = newInvocations;
- long newCpuNanos = cpuCounter.getNanos();
+ long newCpuNanos = gcBean.getCollectionTime();
emitter.emit(builder.build("jvm/gc/cpu", newCpuNanos - lastCpuNanos));
lastCpuNanos = newCpuNanos;
+
}
+ }
- private String getReadableName(String name)
+ private class GcSpaceCollector
+ {
+
+ private final List<GcGenerationSpace> spaces = new ArrayList<>();
+
+ public GcSpaceCollector(MemoryUsage collectionUsage, String name)
{
- switch (name) {
- // Young gen
- case "Copy":
- return "serial";
- case "PSScavenge":
- return "parallel";
- case "PCopy":
- return "cms";
- case "G1 incremental collections":
- return "g1";
- case "Shenandoah partial":
- return "shenandoah";
-
- // Old gen
- case "MCS":
- return "serial";
- case "PSParallelCompact":
- return "parallel";
- case "CMS":
- return "cms";
- case "G1 stop-the-world full collections":
- return "g1";
- case "Shenandoah full":
- return "shenandoah";
+ spaces.add(new GcGenerationSpace(collectionUsage, name));
+ }
- default:
- return name;
+ void emit(ServiceEmitter emitter, Map<String, String[]> dimensions)
+ {
+ for (GcGenerationSpace space : spaces) {
+ space.emit(emitter, dimensions);
}
}
}
@@ -362,24 +296,12 @@ public class JvmMonitor extends FeedDefiningMonitor
private class GcGenerationSpace
{
private final String name;
+ private final MemoryUsage memoryUsage;
- private final LongCounter maxCounter;
- private final LongCounter capacityCounter;
- private final LongCounter usedCounter;
- private final LongCounter initCounter;
-
- GcGenerationSpace(Map<String, JStatData.Counter<?>> jStatCounters, long
genIndex, long spaceIndex)
+ public GcGenerationSpace(MemoryUsage memoryUsage, String name)
{
- String spaceKeyPrefix =
StringUtils.format("sun.gc.generation.%d.space.%d", genIndex, spaceIndex);
-
- String nameKey = StringUtils.format("%s.name", spaceKeyPrefix);
- StringCounter nameCounter = (StringCounter) jStatCounters.get(nameKey);
- name = StringUtils.toLowerCase(nameCounter.toString());
-
- maxCounter = (LongCounter)
jStatCounters.get(StringUtils.format("%s.maxCapacity", spaceKeyPrefix));
- capacityCounter = (LongCounter)
jStatCounters.get(StringUtils.format("%s.capacity", spaceKeyPrefix));
- usedCounter = (LongCounter)
jStatCounters.get(StringUtils.format("%s.used", spaceKeyPrefix));
- initCounter = (LongCounter)
jStatCounters.get(StringUtils.format("%s.initCapacity", spaceKeyPrefix));
+ this.memoryUsage = memoryUsage;
+ this.name = name;
}
void emit(ServiceEmitter emitter, Map<String, String[]> dimensions)
@@ -389,10 +311,10 @@ public class JvmMonitor extends FeedDefiningMonitor
builder.setDimension("gcGenSpaceName", name);
- emitter.emit(builder.build("jvm/gc/mem/max", maxCounter.getLong()));
- emitter.emit(builder.build("jvm/gc/mem/capacity",
capacityCounter.getLong()));
- emitter.emit(builder.build("jvm/gc/mem/used", usedCounter.getLong()));
- emitter.emit(builder.build("jvm/gc/mem/init", initCounter.getLong()));
+ emitter.emit(builder.build("jvm/gc/mem/max", memoryUsage.getMax()));
+ emitter.emit(builder.build("jvm/gc/mem/capacity",
memoryUsage.getCommitted()));
+ emitter.emit(builder.build("jvm/gc/mem/used", memoryUsage.getUsed()));
+ emitter.emit(builder.build("jvm/gc/mem/init", memoryUsage.getInit()));
}
}
}
diff --git
a/core/src/test/java/org/apache/druid/java/util/metrics/JvmMonitorTest.java
b/core/src/test/java/org/apache/druid/java/util/metrics/JvmMonitorTest.java
index d5a2890e08..24af5db4c5 100644
--- a/core/src/test/java/org/apache/druid/java/util/metrics/JvmMonitorTest.java
+++ b/core/src/test/java/org/apache/druid/java/util/metrics/JvmMonitorTest.java
@@ -19,8 +19,6 @@
package org.apache.druid.java.util.metrics;
-import com.google.common.collect.ImmutableSet;
-import it.unimi.dsi.fastutil.ints.IntSet;
import org.apache.druid.java.util.emitter.core.Emitter;
import org.apache.druid.java.util.emitter.core.Event;
import org.apache.druid.java.util.emitter.service.ServiceEmitter;
@@ -43,7 +41,7 @@ public class JvmMonitorTest
serviceEmitter.start();
final JvmMonitor jvmMonitor = new JvmMonitor();
// skip tests if gc counters fail to initialize with this JDK
- Assume.assumeNotNull(jvmMonitor.gcCounters);
+ Assume.assumeNotNull(jvmMonitor.gcCollectors);
while (true) {
// generate some garbage to see gc counters incremented
@@ -58,41 +56,6 @@ public class JvmMonitorTest
}
}
- @Test
- public void testGetGcGenerations()
- {
- Assert.assertEquals(
- IntSet.of(0, 1),
- JvmMonitor.getGcGenerations(
- ImmutableSet.of(
- "sun.gc.collector.0.name",
- "sun.gc.collector.1.name",
- "sun.gc.generation.1.spaces"
- )
- )
- );
-
- Assert.assertEquals(
- IntSet.of(1, 2),
- JvmMonitor.getGcGenerations(
- ImmutableSet.of(
- "sun.gc.generation.1.spaces",
- "sun.gc.collector.2.name",
- "sun.gc.somethingelse.3.name"
- )
- )
- );
- }
-
- @Test
- public void testGetGcGenerationName()
- {
- Assert.assertEquals("young", JvmMonitor.getGcGenerationName(0));
- Assert.assertEquals("old", JvmMonitor.getGcGenerationName(1));
- Assert.assertEquals("perm", JvmMonitor.getGcGenerationName(2));
- Assert.assertEquals("3", JvmMonitor.getGcGenerationName(3));
- }
-
private static class GcTrackingEmitter implements Emitter
{
private Number oldGcCount;
diff --git a/pom.xml b/pom.xml
index fce189172b..5d29c54cb8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1757,7 +1757,6 @@
<!-- locale settings must be set on the command
line before startup -->
<!-- set heap size to work around
https://github.com/travis-ci/travis-ci/issues/3396 -->
<argLine>
- ${jdk.surefire.argLine}
-Xmx768m -Duser.language=en -Duser.country=US
-Dfile.encoding=UTF-8
-XX:+ExitOnOutOfMemoryError
-XX:+HeapDumpOnOutOfMemoryError
diff --git a/processing/pom.xml b/processing/pom.xml
index 80a8c80016..da5e9a7638 100644
--- a/processing/pom.xml
+++ b/processing/pom.xml
@@ -300,7 +300,6 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
- ${jdk.surefire.argLine}
-server -Xms3G -Xmx3G
-Djub.consumers=CONSOLE,H2 -Djub.db.file=benchmarks/benchmarks
-XX:+ExitOnOutOfMemoryError
-XX:+HeapDumpOnOutOfMemoryError
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]