Skip to content

Commit a3167a5

Browse files
authored
Split up GC Handlers, add support for Parallel (#201)
* WIP * Separate out young gen metrics * Add Parallel GC handlers * Align naming conventions * Tidy up with an instanceof pattern * Format snafu -instanceof pattern * Address Jack's comments from PR review * Fix minor nits from code review
1 parent 69b51e1 commit a3167a5

File tree

13 files changed

+329
-97
lines changed

13 files changed

+329
-97
lines changed

jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/HandlerRegistry.java

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,44 +12,70 @@
1212
import io.opentelemetry.contrib.jfr.metrics.internal.cpu.ContextSwitchRateHandler;
1313
import io.opentelemetry.contrib.jfr.metrics.internal.cpu.LongLockHandler;
1414
import io.opentelemetry.contrib.jfr.metrics.internal.cpu.OverallCPULoadHandler;
15-
import io.opentelemetry.contrib.jfr.metrics.internal.memory.G1GarbageCollectionHandler;
15+
import io.opentelemetry.contrib.jfr.metrics.internal.memory.G1HeapSummaryHandler;
1616
import io.opentelemetry.contrib.jfr.metrics.internal.memory.GCHeapSummaryHandler;
1717
import io.opentelemetry.contrib.jfr.metrics.internal.memory.ObjectAllocationInNewTLABHandler;
1818
import io.opentelemetry.contrib.jfr.metrics.internal.memory.ObjectAllocationOutsideTLABHandler;
19+
import io.opentelemetry.contrib.jfr.metrics.internal.memory.ParallelHeapSummaryHandler;
1920
import io.opentelemetry.contrib.jfr.metrics.internal.network.NetworkReadHandler;
2021
import io.opentelemetry.contrib.jfr.metrics.internal.network.NetworkWriteHandler;
22+
import java.lang.management.ManagementFactory;
2123
import java.util.ArrayList;
24+
import java.util.HashSet;
2225
import java.util.List;
26+
import java.util.Map;
27+
import java.util.function.Supplier;
2328

2429
final class HandlerRegistry {
2530
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.contrib.jfr";
2631
private static final String INSTRUMENTATION_VERSION = "1.7.0-SNAPSHOT";
2732

2833
private final List<RecordedEventHandler> mappers;
2934

35+
private static final Map<String, List<Supplier<RecordedEventHandler>>> HANDLERS_PER_GC =
36+
Map.of(
37+
"G1",
38+
List.of(G1HeapSummaryHandler::new),
39+
"Parallel",
40+
List.of(ParallelHeapSummaryHandler::new));
41+
3042
private HandlerRegistry(List<? extends RecordedEventHandler> mappers) {
3143
this.mappers = new ArrayList<>(mappers);
3244
}
3345

3446
static HandlerRegistry createDefault(MeterProvider meterProvider) {
35-
var meter =
36-
meterProvider
37-
.meterBuilder(INSTRUMENTATION_NAME)
38-
.setInstrumentationVersion(INSTRUMENTATION_VERSION)
39-
.build();
47+
var handlers = new ArrayList<RecordedEventHandler>();
48+
var seen = new HashSet<String>();
49+
for (var bean : ManagementFactory.getGarbageCollectorMXBeans()) {
50+
var name = bean.getName();
51+
for (var gcType : HANDLERS_PER_GC.keySet()) {
52+
if (name.contains(gcType)
53+
&& !seen.contains(gcType)
54+
&& HANDLERS_PER_GC.get(gcType) != null) {
55+
handlers.addAll(HANDLERS_PER_GC.get(gcType).stream().map(s -> s.get()).toList());
56+
seen.add(gcType);
57+
}
58+
}
59+
}
4060
var grouper = new ThreadGrouper();
41-
var handlers =
61+
var basicHandlers =
4262
List.of(
4363
new ObjectAllocationInNewTLABHandler(grouper),
4464
new ObjectAllocationOutsideTLABHandler(grouper),
4565
new NetworkReadHandler(grouper),
4666
new NetworkWriteHandler(grouper),
47-
new G1GarbageCollectionHandler(),
4867
new GCHeapSummaryHandler(),
4968
new ContextSwitchRateHandler(),
5069
new OverallCPULoadHandler(),
5170
new ContainerConfigurationHandler(),
5271
new LongLockHandler(grouper));
72+
handlers.addAll(basicHandlers);
73+
74+
var meter =
75+
meterProvider
76+
.meterBuilder(INSTRUMENTATION_NAME)
77+
.setInstrumentationVersion(INSTRUMENTATION_VERSION)
78+
.build();
5379
handlers.forEach(handler -> handler.initializeMeter(meter));
5480

5581
return new HandlerRegistry(handlers);

jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/Constants.java

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,30 @@ private Constants() {}
1919
public static final String SYSTEM = "system";
2020
public static final String MACHINE = "machine.total";
2121
public static final String G1 = "g1";
22-
public static final String USED = "used";
22+
public static final String TOTAL_USED = "total.used";
23+
public static final String EDEN_USED = "eden.used";
24+
public static final String EDEN_SIZE = "eden.size";
25+
public static final String EDEN_SIZE_DELTA = "eden.delta";
26+
public static final String SURVIVOR_SIZE = "survivor.size";
27+
public static final String REGION_COUNT = "region.count";
2328
public static final String COMMITTED = "committed";
29+
public static final String RESERVED = "reserved";
2430

25-
public static final String METRIC_NAME_NETWORK_BYTES = "runtime.jvm.network.io";
31+
public static final String METRIC_NAME_NETWORK_BYTES = "process.runtime.jvm.network.io";
2632
public static final String METRIC_DESCRIPTION_NETWORK_BYTES = "Network read/write bytes";
27-
public static final String NETWORK_DURATION_NAME = "runtime.jvm.network.duration";
28-
public static final String NETWORK_DURATION_DESCRIPTION = "Network read/write duration";
33+
public static final String METRIC_NAME_NETWORK_DURATION = "process.runtime.jvm.network.time";
34+
public static final String METRIC_DESCRIPTION_NETWORK_DURATION = "Network read/write duration";
2935
public static final String NETWORK_MODE_READ = "read";
3036
public static final String NETWORK_MODE_WRITE = "write";
3137

38+
public static final String METRIC_NAME_MEMORY_ALLOCATION =
39+
"process.runtime.jvm.memory.allocation";
40+
public static final String METRIC_DESCRIPTION_MEMORY_ALLOCATION = "Allocation";
41+
3242
public static final AttributeKey<String> ATTR_THREAD_NAME = AttributeKey.stringKey("thread.name");
3343
public static final AttributeKey<String> ATTR_ARENA_NAME = AttributeKey.stringKey("arena");
3444
public static final AttributeKey<String> ATTR_NETWORK_MODE = AttributeKey.stringKey("mode");
35-
public static final AttributeKey<String> ATTR_CPU_USAGE = AttributeKey.stringKey("usage.type");
45+
public static final AttributeKey<String> ATTR_USAGE = AttributeKey.stringKey("usage.type");
46+
public static final AttributeKey<String> ATTR_TYPE = AttributeKey.stringKey("type");
3647
public static final AttributeKey<String> ATTR_GC_COLLECTOR = AttributeKey.stringKey("name");
37-
public static final AttributeKey<String> ATTR_MEMORY_USAGE = AttributeKey.stringKey("usage.type");
38-
39-
public static final String METRIC_NAME_MEMORY_ALLOCATION = "runtime.jvm.memory.allocation";
40-
public static final String METRIC_DESCRIPTION_MEMORY_ALLOCATION = "Allocation";
4148
}

jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/container/ContainerConfigurationHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import jdk.jfr.consumer.RecordedEvent;
1414

1515
public final class ContainerConfigurationHandler implements RecordedEventHandler {
16-
private static final String METRIC_NAME = "runtime.jvm.cpu.limit";
16+
private static final String METRIC_NAME = "process.runtime.jvm.cpu.limit";
1717
private static final String EVENT_NAME = "jdk.ContainerConfiguration";
1818
private static final String EFFECTIVE_CPU_COUNT = "effectiveCpuCount";
1919

jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/ContextSwitchRateHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import jdk.jfr.consumer.RecordedEvent;
1616

1717
public final class ContextSwitchRateHandler implements RecordedEventHandler {
18-
private static final String METRIC_NAME = "runtime.jvm.cpu.context_switch";
18+
private static final String METRIC_NAME = "process.runtime.jvm.cpu.context_switch";
1919
private static final String EVENT_NAME = "jdk.ThreadContextSwitchRate";
2020

2121
private volatile double value = 0;

jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/LongLockHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import jdk.jfr.consumer.RecordedEvent;
2121

2222
public final class LongLockHandler extends AbstractThreadDispatchingHandler {
23-
private static final String METRIC_NAME = "runtime.jvm.cpu.longlock.time";
23+
private static final String METRIC_NAME = "process.runtime.jvm.cpu.longlock";
2424
private static final String METRIC_DESCRIPTION = "Long lock times";
2525
private static final String EVENT_NAME = "jdk.JavaMonitorWait";
2626

jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/cpu/OverallCPULoadHandler.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
package io.opentelemetry.contrib.jfr.metrics.internal.cpu;
77

8-
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_CPU_USAGE;
8+
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_USAGE;
99
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.MACHINE;
1010
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.PERCENTAGE;
1111
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.SYSTEM;
@@ -21,16 +21,16 @@
2121
import jdk.jfr.consumer.RecordedEvent;
2222

2323
public final class OverallCPULoadHandler implements RecordedEventHandler {
24-
private static final String METRIC_NAME = "runtime.jvm.cpu.utilization";
24+
private static final String METRIC_NAME = "process.runtime.jvm.cpu.used";
2525
private static final String METRIC_DESCRIPTION = "CPU Utilization";
2626
private static final String EVENT_NAME = "jdk.CPULoad";
2727
private static final String JVM_USER = "jvmUser";
2828
private static final String JVM_SYSTEM = "jvmSystem";
2929
private static final String MACHINE_TOTAL = "machineTotal";
3030

31-
private static final Attributes ATTR_USER = Attributes.of(ATTR_CPU_USAGE, USER);
32-
private static final Attributes ATTR_SYSTEM = Attributes.of(ATTR_CPU_USAGE, SYSTEM);
33-
private static final Attributes ATTR_MACHINE = Attributes.of(ATTR_CPU_USAGE, MACHINE);
31+
private static final Attributes ATTR_USER = Attributes.of(ATTR_USAGE, USER);
32+
private static final Attributes ATTR_SYSTEM = Attributes.of(ATTR_USAGE, SYSTEM);
33+
private static final Attributes ATTR_MACHINE = Attributes.of(ATTR_USAGE, MACHINE);
3434

3535
private DoubleHistogram histogram;
3636

jfr-streaming/src/main/java/io/opentelemetry/contrib/jfr/metrics/internal/memory/G1GarbageCollectionHandler.java

Lines changed: 0 additions & 52 deletions
This file was deleted.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.contrib.jfr.metrics.internal.memory;
7+
8+
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_USAGE;
9+
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.BYTES;
10+
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.EDEN_SIZE;
11+
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.EDEN_SIZE_DELTA;
12+
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.EDEN_USED;
13+
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.REGION_COUNT;
14+
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.SURVIVOR_SIZE;
15+
import static io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler.defaultMeter;
16+
17+
import io.opentelemetry.api.common.Attributes;
18+
import io.opentelemetry.api.metrics.DoubleHistogram;
19+
import io.opentelemetry.api.metrics.Meter;
20+
import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler;
21+
import java.util.HashMap;
22+
import java.util.Map;
23+
import java.util.logging.Logger;
24+
import jdk.jfr.consumer.RecordedEvent;
25+
26+
/**
27+
* This class handles G1HeapSummary JFR events. For GC purposes they come in pairs. Basic heap
28+
* values are sourced from GCHeapSummary - this is young generational details
29+
*/
30+
public final class G1HeapSummaryHandler implements RecordedEventHandler {
31+
private static final Logger logger = Logger.getLogger(G1HeapSummaryHandler.class.getName());
32+
33+
private static final String METRIC_NAME_MEMORY = "process.runtime.jvm.memory.used";
34+
private static final String METRIC_DESCRIPTION_MEMORY = "Heap utilization";
35+
private static final String EVENT_NAME = "jdk.G1HeapSummary";
36+
private static final String BEFORE = "Before GC";
37+
private static final String AFTER = "After GC";
38+
private static final String GC_ID = "gcId";
39+
private static final String WHEN = "when";
40+
private static final Attributes ATTR_MEMORY_EDEN_USED = Attributes.of(ATTR_USAGE, EDEN_USED);
41+
private static final Attributes ATTR_MEMORY_EDEN_SIZE = Attributes.of(ATTR_USAGE, EDEN_SIZE);
42+
private static final Attributes ATTR_MEMORY_EDEN_SIZE_DELTA =
43+
Attributes.of(ATTR_USAGE, EDEN_SIZE_DELTA);
44+
private static final Attributes ATTR_MEMORY_SURVIVOR_SIZE =
45+
Attributes.of(ATTR_USAGE, SURVIVOR_SIZE);
46+
private static final Attributes ATTR_MEMORY_REGIONS = Attributes.of(ATTR_USAGE, REGION_COUNT);
47+
48+
private final Map<Long, RecordedEvent> awaitingPairs = new HashMap<>();
49+
50+
private DoubleHistogram memoryHistogram;
51+
52+
public G1HeapSummaryHandler() {
53+
initializeMeter(defaultMeter());
54+
}
55+
56+
@Override
57+
public void initializeMeter(Meter meter) {
58+
memoryHistogram =
59+
meter
60+
.histogramBuilder(METRIC_NAME_MEMORY)
61+
.setDescription(METRIC_DESCRIPTION_MEMORY)
62+
.setUnit(BYTES)
63+
.build();
64+
}
65+
66+
@Override
67+
public String getEventName() {
68+
return EVENT_NAME;
69+
}
70+
71+
@Override
72+
public void accept(RecordedEvent ev) {
73+
String when;
74+
if (ev.hasField(WHEN)) {
75+
when = ev.getString(WHEN);
76+
} else {
77+
logger.fine(String.format("G1 GC Event seen without when: %s", ev));
78+
return;
79+
}
80+
if (!(BEFORE.equals(when) || AFTER.equals(when))) {
81+
logger.fine(String.format("G1 GC Event seen where when is neither before nor after: %s", ev));
82+
return;
83+
}
84+
85+
if (!ev.hasField(GC_ID)) {
86+
logger.fine(String.format("G1 GC Event seen without GC ID: %s", ev));
87+
return;
88+
}
89+
long gcId = ev.getLong(GC_ID);
90+
91+
var pair = awaitingPairs.remove(gcId);
92+
if (pair == null) {
93+
awaitingPairs.put(gcId, ev);
94+
} else {
95+
if (when.equals(BEFORE)) {
96+
recordValues(ev, pair);
97+
} else { // i.e. when.equals(AFTER)
98+
recordValues(pair, ev);
99+
}
100+
}
101+
}
102+
103+
private void recordValues(RecordedEvent before, RecordedEvent after) {
104+
if (after.hasField("edenUsedSize")) {
105+
memoryHistogram.record(after.getLong("edenUsedSize"), ATTR_MEMORY_EDEN_USED);
106+
if (before.hasField("edenUsedSize")) {
107+
memoryHistogram.record(
108+
after.getLong("edenUsedSize") - before.getLong("edenUsedSize"),
109+
ATTR_MEMORY_EDEN_SIZE_DELTA);
110+
}
111+
}
112+
if (after.hasField("edenTotalSize")) {
113+
memoryHistogram.record(after.getLong("edenTotalSize"), ATTR_MEMORY_EDEN_SIZE);
114+
}
115+
if (after.hasField("survivorUsedSize")) {
116+
memoryHistogram.record(after.getLong("survivorUsedSize"), ATTR_MEMORY_SURVIVOR_SIZE);
117+
}
118+
if (after.hasField("numberOfRegions")) {
119+
memoryHistogram.record(after.getLong("numberOfRegions"), ATTR_MEMORY_REGIONS);
120+
}
121+
}
122+
}

0 commit comments

Comments
 (0)