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

Split up GC Handlers, add support for Parallel #201

Merged
merged 11 commits into from
Jan 24, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -12,44 +12,70 @@
import io.opentelemetry.contrib.jfr.metrics.internal.cpu.ContextSwitchRateHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.cpu.LongLockHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.cpu.OverallCPULoadHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.memory.G1GarbageCollectionHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.memory.G1HeapSummaryHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.memory.GCHeapSummaryHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.memory.ObjectAllocationInNewTLABHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.memory.ObjectAllocationOutsideTLABHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.memory.ParallelHeapSummaryHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.network.NetworkReadHandler;
import io.opentelemetry.contrib.jfr.metrics.internal.network.NetworkWriteHandler;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

final class HandlerRegistry {
private static final String INSTRUMENTATION_NAME = "io.opentelemetry.contrib.jfr";
private static final String INSTRUMENTATION_VERSION = "1.7.0-SNAPSHOT";
kittylyst marked this conversation as resolved.
Show resolved Hide resolved

private final List<RecordedEventHandler> mappers;

private static final Map<String, List<Supplier<RecordedEventHandler>>> HANDLERS_PER_GC =
Map.of(
"G1",
List.of(G1HeapSummaryHandler::new),
kittylyst marked this conversation as resolved.
Show resolved Hide resolved
"Parallel",
List.of(ParallelHeapSummaryHandler::new));

private HandlerRegistry(List<? extends RecordedEventHandler> mappers) {
this.mappers = new ArrayList<>(mappers);
}

static HandlerRegistry createDefault(MeterProvider meterProvider) {
var meter =
meterProvider
.meterBuilder(INSTRUMENTATION_NAME)
.setInstrumentationVersion(INSTRUMENTATION_VERSION)
.build();
var handlers = new ArrayList<RecordedEventHandler>();
var seen = new HashSet<String>();
for (var bean : ManagementFactory.getGarbageCollectorMXBeans()) {
var name = bean.getName();
for (var gcType : HANDLERS_PER_GC.keySet()) {
if (name.contains(gcType)
kittylyst marked this conversation as resolved.
Show resolved Hide resolved
&& !seen.contains(gcType)
&& HANDLERS_PER_GC.get(gcType) != null) {
kittylyst marked this conversation as resolved.
Show resolved Hide resolved
handlers.addAll(HANDLERS_PER_GC.get(gcType).stream().map(s -> s.get()).toList());
kittylyst marked this conversation as resolved.
Show resolved Hide resolved
seen.add(gcType);
}
}
}
var grouper = new ThreadGrouper();
var handlers =
var basicHandlers =
List.of(
new ObjectAllocationInNewTLABHandler(grouper),
new ObjectAllocationOutsideTLABHandler(grouper),
new NetworkReadHandler(grouper),
new NetworkWriteHandler(grouper),
new G1GarbageCollectionHandler(),
new GCHeapSummaryHandler(),
new ContextSwitchRateHandler(),
new OverallCPULoadHandler(),
new ContainerConfigurationHandler(),
new LongLockHandler(grouper));
handlers.addAll(basicHandlers);

var meter =
meterProvider
.meterBuilder(INSTRUMENTATION_NAME)
.setInstrumentationVersion(INSTRUMENTATION_VERSION)
.build();
handlers.forEach(handler -> handler.initializeMeter(meter));

return new HandlerRegistry(handlers);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,30 @@ private Constants() {}
public static final String SYSTEM = "system";
public static final String MACHINE = "machine.total";
public static final String G1 = "g1";
public static final String USED = "used";
public static final String TOTAL_USED = "total.used";
public static final String EDEN_USED = "eden.used";
public static final String EDEN_SIZE = "eden.size";
public static final String EDEN_SIZE_DELTA = "eden.delta";
public static final String SURVIVOR_SIZE = "survivor.size";
public static final String REGION_COUNT = "region.count";
public static final String COMMITTED = "committed";
public static final String RESERVED = "reserved";

public static final String METRIC_NAME_NETWORK_BYTES = "runtime.jvm.network.io";
public static final String METRIC_NAME_NETWORK_BYTES = "process.runtime.jvm.network.io";
public static final String METRIC_DESCRIPTION_NETWORK_BYTES = "Network read/write bytes";
public static final String NETWORK_DURATION_NAME = "runtime.jvm.network.duration";
public static final String NETWORK_DURATION_DESCRIPTION = "Network read/write duration";
public static final String METRIC_NAME_NETWORK_DURATION = "process.runtime.jvm.network.time";
public static final String METRIC_DESCRIPTION_NETWORK_DURATION = "Network read/write duration";
public static final String NETWORK_MODE_READ = "read";
public static final String NETWORK_MODE_WRITE = "write";

public static final String METRIC_NAME_MEMORY_ALLOCATION =
"process.runtime.jvm.memory.allocation";
public static final String METRIC_DESCRIPTION_MEMORY_ALLOCATION = "Allocation";

public static final AttributeKey<String> ATTR_THREAD_NAME = AttributeKey.stringKey("thread.name");
public static final AttributeKey<String> ATTR_ARENA_NAME = AttributeKey.stringKey("arena");
public static final AttributeKey<String> ATTR_NETWORK_MODE = AttributeKey.stringKey("mode");
public static final AttributeKey<String> ATTR_CPU_USAGE = AttributeKey.stringKey("usage.type");
public static final AttributeKey<String> ATTR_USAGE = AttributeKey.stringKey("usage.type");
public static final AttributeKey<String> ATTR_TYPE = AttributeKey.stringKey("type");
public static final AttributeKey<String> ATTR_GC_COLLECTOR = AttributeKey.stringKey("name");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unused.

public static final AttributeKey<String> ATTR_MEMORY_USAGE = AttributeKey.stringKey("usage.type");

public static final String METRIC_NAME_MEMORY_ALLOCATION = "runtime.jvm.memory.allocation";
public static final String METRIC_DESCRIPTION_MEMORY_ALLOCATION = "Allocation";
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import jdk.jfr.consumer.RecordedEvent;

public final class ContainerConfigurationHandler implements RecordedEventHandler {
private static final String METRIC_NAME = "runtime.jvm.cpu.limit";
private static final String METRIC_NAME = "process.runtime.jvm.cpu.limit";
private static final String EVENT_NAME = "jdk.ContainerConfiguration";
private static final String EFFECTIVE_CPU_COUNT = "effectiveCpuCount";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import jdk.jfr.consumer.RecordedEvent;

public final class ContextSwitchRateHandler implements RecordedEventHandler {
private static final String METRIC_NAME = "runtime.jvm.cpu.context_switch";
private static final String METRIC_NAME = "process.runtime.jvm.cpu.context_switch";
private static final String EVENT_NAME = "jdk.ThreadContextSwitchRate";

private volatile double value = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import jdk.jfr.consumer.RecordedEvent;

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

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

import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_CPU_USAGE;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_USAGE;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.MACHINE;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.PERCENTAGE;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.SYSTEM;
Expand All @@ -21,16 +21,16 @@
import jdk.jfr.consumer.RecordedEvent;

public final class OverallCPULoadHandler implements RecordedEventHandler {
private static final String METRIC_NAME = "runtime.jvm.cpu.utilization";
private static final String METRIC_NAME = "process.runtime.jvm.cpu.used";
private static final String METRIC_DESCRIPTION = "CPU Utilization";
private static final String EVENT_NAME = "jdk.CPULoad";
private static final String JVM_USER = "jvmUser";
private static final String JVM_SYSTEM = "jvmSystem";
private static final String MACHINE_TOTAL = "machineTotal";
kittylyst marked this conversation as resolved.
Show resolved Hide resolved

private static final Attributes ATTR_USER = Attributes.of(ATTR_CPU_USAGE, USER);
private static final Attributes ATTR_SYSTEM = Attributes.of(ATTR_CPU_USAGE, SYSTEM);
private static final Attributes ATTR_MACHINE = Attributes.of(ATTR_CPU_USAGE, MACHINE);
private static final Attributes ATTR_USER = Attributes.of(ATTR_USAGE, USER);
private static final Attributes ATTR_SYSTEM = Attributes.of(ATTR_USAGE, SYSTEM);
private static final Attributes ATTR_MACHINE = Attributes.of(ATTR_USAGE, MACHINE);

private DoubleHistogram histogram;

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.contrib.jfr.metrics.internal.memory;

import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.ATTR_USAGE;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.BYTES;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.EDEN_SIZE;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.EDEN_SIZE_DELTA;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.EDEN_USED;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.REGION_COUNT;
import static io.opentelemetry.contrib.jfr.metrics.internal.Constants.SURVIVOR_SIZE;
import static io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler.defaultMeter;

import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.metrics.DoubleHistogram;
import io.opentelemetry.api.metrics.Meter;
import io.opentelemetry.contrib.jfr.metrics.internal.RecordedEventHandler;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import jdk.jfr.consumer.RecordedEvent;

/**
* This class handles G1HeapSummary JFR events. For GC purposes they come in pairs. Basic heap
* values are sourced from GCHeapSummary - this is young generational details
*/
public final class G1HeapSummaryHandler implements RecordedEventHandler {
private static final Logger logger = Logger.getLogger(G1HeapSummaryHandler.class.getName());

private static final String METRIC_NAME_MEMORY = "process.runtime.jvm.memory.used";
private static final String METRIC_DESCRIPTION_MEMORY = "Heap utilization";
private static final String EVENT_NAME = "jdk.G1HeapSummary";
private static final String BEFORE = "Before GC";
private static final String AFTER = "After GC";
private static final String GC_ID = "gcId";
private static final String WHEN = "when";
private static final Attributes ATTR_MEMORY_EDEN_USED = Attributes.of(ATTR_USAGE, EDEN_USED);
private static final Attributes ATTR_MEMORY_EDEN_SIZE = Attributes.of(ATTR_USAGE, EDEN_SIZE);
private static final Attributes ATTR_MEMORY_EDEN_SIZE_DELTA =
Attributes.of(ATTR_USAGE, EDEN_SIZE_DELTA);
private static final Attributes ATTR_MEMORY_SURVIVOR_SIZE =
Attributes.of(ATTR_USAGE, SURVIVOR_SIZE);
private static final Attributes ATTR_MEMORY_REGIONS = Attributes.of(ATTR_USAGE, REGION_COUNT);

private final Map<Long, RecordedEvent> awaitingPairs = new HashMap<>();

private DoubleHistogram memoryHistogram;

public G1HeapSummaryHandler() {
initializeMeter(defaultMeter());
}

@Override
public void initializeMeter(Meter meter) {
memoryHistogram =
meter
.histogramBuilder(METRIC_NAME_MEMORY)
.setDescription(METRIC_DESCRIPTION_MEMORY)
.setUnit(BYTES)
.build();
}

@Override
public String getEventName() {
return EVENT_NAME;
}

@Override
public void accept(RecordedEvent ev) {
String when;
if (ev.hasField(WHEN)) {
when = ev.getString(WHEN);
} else {
logger.fine(String.format("G1 GC Event seen without when: %s", ev));
return;
}
if (!(when.equals(BEFORE) || when.equals(AFTER))) {
kittylyst marked this conversation as resolved.
Show resolved Hide resolved
logger.fine(String.format("G1 GC Event seen where when is neither before nor after: %s", ev));
return;
}

if (!ev.hasField(GC_ID)) {
return;
}
long gcId = ev.getLong(GC_ID);

var pair = awaitingPairs.remove(gcId);
if (pair == null) {
awaitingPairs.put(gcId, ev);
} else {
if (when.equals(BEFORE)) {
recordValues(ev, pair);
} else { // i.e. when.equals(AFTER)
kittylyst marked this conversation as resolved.
Show resolved Hide resolved
recordValues(pair, ev);
}
}
}

private void recordValues(RecordedEvent before, RecordedEvent after) {
if (after.hasField("edenUsedSize")) {
memoryHistogram.record(after.getLong("edenUsedSize"), ATTR_MEMORY_EDEN_USED);
if (before.hasField("edenUsedSize")) {
memoryHistogram.record(
after.getLong("edenUsedSize") - before.getLong("edenUsedSize"),
ATTR_MEMORY_EDEN_SIZE_DELTA);
}
}
if (after.hasField("edenTotalSize")) {
memoryHistogram.record(after.getLong("edenTotalSize"), ATTR_MEMORY_EDEN_SIZE);
}
if (after.hasField("survivorUsedSize")) {
memoryHistogram.record(after.getLong("survivorUsedSize"), ATTR_MEMORY_SURVIVOR_SIZE);
}
if (after.hasField("numberOfRegions")) {
memoryHistogram.record(after.getLong("numberOfRegions"), ATTR_MEMORY_REGIONS);
}
kittylyst marked this conversation as resolved.
Show resolved Hide resolved
}
}
Loading