Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JvmMonitor: Handle more generation and collector scenarios. #12469

Merged
merged 5 commits into from
Apr 27, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
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.emitter.service.ServiceEmitter;
Expand All @@ -40,10 +42,15 @@
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;
Expand Down Expand Up @@ -170,12 +177,42 @@ private GcCounters tryCreateGcCounters()
// 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"
+ " add --add-exports=java.base/jdk.internal.perf=ALL-UNNAMED"
+ " to the JVM arguments to enable GC counters.");
}
return null;
}

@VisibleForTesting
static IntSet getGcGenerations(final Set<String> jStatCounterNames)
{
final IntSet retVal = new IntRBTreeSet();

for (final String counterName : jStatCounterNames) {
final Matcher m = PATTERN_GC_GENERATION.matcher(counterName);
if (m.matches()) {
retVal.add(Integer.parseInt(m.group(1)));
}
}

return retVal;
}

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/
Expand All @@ -191,11 +228,8 @@ private class GcCounters
final JStatData jStatData = JStatData.connect(pid);
final Map<String, JStatData.Counter<?>> jStatCounters = jStatData.getAllCounters();

generations.add(new GcGeneration(jStatCounters, 0, "young"));
generations.add(new GcGeneration(jStatCounters, 1, "old"));
// Removed in Java 8 but still actual for previous Java versions
if (jStatCounters.containsKey("sun.gc.generation.2.name")) {
generations.add(new GcGeneration(jStatCounters, 2, "perm"));
for (int genIndex : getGcGenerations(jStatCounters.keySet())) {
generations.add(new GcGeneration(jStatCounters, genIndex, getGcGenerationName(genIndex)));
}
}

Expand All @@ -210,18 +244,21 @@ void emit(ServiceEmitter emitter, Map<String, String[]> dimensions)
private class GcGeneration
{
private final String name;
@Nullable
private final GcGenerationCollector collector;
private final List<GcGenerationSpace> spaces = new ArrayList<>();

GcGeneration(Map<String, JStatData.Counter<?>> jStatCounters, long genIndex, String name)
{
this.name = StringUtils.toLowerCase(name);

long spacesCount = ((JStatData.LongCounter) jStatCounters.get(
StringUtils.format("sun.gc.generation.%d.spaces", genIndex)
)).getLong();
for (long spaceIndex = 0; spaceIndex < spacesCount; spaceIndex++) {
spaces.add(new GcGenerationSpace(jStatCounters, genIndex, spaceIndex));
final String spacesCountKey = StringUtils.format("sun.gc.generation.%d.spaces", genIndex);

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));
}
}

if (jStatCounters.containsKey(StringUtils.format("sun.gc.collector.%d.name", genIndex))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

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;
Expand Down Expand Up @@ -56,6 +58,31 @@ public void testGcCounts() throws InterruptedException
}
}

@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"
)
)
);
}

private static class GcTrackingEmitter implements Emitter
{
private Number oldGcCount;
Expand Down