8203359: Container level resources events
Reviewed-by: sgehwolf, egahlin
This commit is contained in:
parent
b5d32bbfc7
commit
ee2651b9e5
@ -218,7 +218,8 @@ module java.base {
|
||||
jdk.management.agent,
|
||||
jdk.internal.jvmstat;
|
||||
exports jdk.internal.platform to
|
||||
jdk.management;
|
||||
jdk.management,
|
||||
jdk.jfr;
|
||||
exports jdk.internal.ref to
|
||||
java.desktop,
|
||||
jdk.incubator.foreign;
|
||||
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, DataDog. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.DataAmount;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Enabled;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.Period;
|
||||
import jdk.jfr.StackTrace;
|
||||
import jdk.jfr.Threshold;
|
||||
import jdk.jfr.Timespan;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "ContainerCPUThrottling")
|
||||
@Label("CPU Throttling")
|
||||
@Category({"Operating System", "Processor"})
|
||||
@Description("Container CPU throttling related information")
|
||||
public class ContainerCPUThrottlingEvent extends AbstractJDKEvent {
|
||||
@Label("CPU Elapsed Slices")
|
||||
@Description("Number of time-slice periods that have elapsed if a CPU quota has been setup for the container")
|
||||
public long cpuElapsedSlices;
|
||||
|
||||
@Label("CPU Throttled Slices")
|
||||
@Description("Number of time-slice periods that the CPU has been throttled or limited due to exceeding CPU quota")
|
||||
public long cpuThrottledSlices;
|
||||
|
||||
@Label("CPU Throttled Time")
|
||||
@Description("Total time duration, in nanoseconds, that the CPU has been throttled or limited due to exceeding CPU quota")
|
||||
@Timespan
|
||||
public long cpuThrottledTime;
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, DataDog. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.DataAmount;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Enabled;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.Period;
|
||||
import jdk.jfr.StackTrace;
|
||||
import jdk.jfr.Threshold;
|
||||
import jdk.jfr.Timespan;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "ContainerCPUUsage")
|
||||
@Label("CPU Usage")
|
||||
@Category({"Operating System", "Processor"})
|
||||
@Description("Container CPU usage related information")
|
||||
public class ContainerCPUUsageEvent extends AbstractJDKEvent {
|
||||
@Label("CPU Time")
|
||||
@Description("Aggregate time consumed by all tasks in the container")
|
||||
@Timespan
|
||||
public long cpuTime;
|
||||
|
||||
@Label("CPU User Time")
|
||||
@Description("Aggregate user time consumed by all tasks in the container")
|
||||
@Timespan
|
||||
public long cpuUserTime;
|
||||
|
||||
@Label("CPU System Time")
|
||||
@Description("Aggregate system time consumed by all tasks in the container")
|
||||
@Timespan
|
||||
public long cpuSystemTime;
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, DataDog. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.DataAmount;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Enabled;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.Period;
|
||||
import jdk.jfr.StackTrace;
|
||||
import jdk.jfr.Threshold;
|
||||
import jdk.jfr.Timespan;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "ContainerConfiguration")
|
||||
@Label("Container Configuration")
|
||||
@Category({"Operating System"})
|
||||
@Description("A set of container specific attributes")
|
||||
public final class ContainerConfigurationEvent extends AbstractJDKEvent {
|
||||
@Label("Container Type")
|
||||
@Description("Container type information")
|
||||
public String containerType;
|
||||
|
||||
@Label("CPU Slice Period")
|
||||
@Description("Length of the scheduling period for processes within the container")
|
||||
@Timespan(Timespan.MICROSECONDS)
|
||||
public long cpuSlicePeriod;
|
||||
|
||||
@Label("CPU Quota")
|
||||
@Description("Total available run-time allowed during each scheduling period for all tasks in the container")
|
||||
@Timespan(Timespan.MICROSECONDS)
|
||||
public long cpuQuota;
|
||||
|
||||
@Label("CPU Shares")
|
||||
@Description("Relative weighting of processes with the container used for prioritizing the scheduling of processes across " +
|
||||
"all containers running on a host")
|
||||
public long cpuShares;
|
||||
|
||||
@Label("Effective CPU Count")
|
||||
@Description("Number of effective processors that this container has available to it")
|
||||
public long effectiveCpuCount;
|
||||
|
||||
@Label("Memory Soft Limit")
|
||||
@Description("Hint to the operating system that allows groups to specify the minimum required amount of physical memory")
|
||||
@DataAmount
|
||||
public long memorySoftLimit;
|
||||
|
||||
@Label("Memory Limit")
|
||||
@Description("Maximum amount of physical memory that can be allocated in the container")
|
||||
@DataAmount
|
||||
public long memoryLimit;
|
||||
|
||||
@Label("Memory and Swap Limit")
|
||||
@Description("Maximum amount of physical memory and swap space, in bytes, that can be allocated in the container")
|
||||
@DataAmount
|
||||
public long swapMemoryLimit;
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, DataDog. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.DataAmount;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Enabled;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.Period;
|
||||
import jdk.jfr.StackTrace;
|
||||
import jdk.jfr.Threshold;
|
||||
import jdk.jfr.Timespan;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "ContainerIOUsage")
|
||||
@Label("Container IO Usage")
|
||||
@Category({"Operating System", "File System"})
|
||||
@Description("Container IO usage related information")
|
||||
public class ContainerIOUsageEvent extends AbstractJDKEvent {
|
||||
|
||||
@Label("Block IO Request Count")
|
||||
@Description("Number of block IO requests to the disk that have been issued by the container")
|
||||
public long serviceRequests;
|
||||
|
||||
@Label("Block IO Transfer")
|
||||
@Description("Number of block IO bytes that have been transferred to/from the disk by the container")
|
||||
@DataAmount
|
||||
public long dataTransferred;
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, DataDog. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.events;
|
||||
|
||||
import jdk.jfr.Category;
|
||||
import jdk.jfr.DataAmount;
|
||||
import jdk.jfr.Description;
|
||||
import jdk.jfr.Enabled;
|
||||
import jdk.jfr.Label;
|
||||
import jdk.jfr.Name;
|
||||
import jdk.jfr.Period;
|
||||
import jdk.jfr.StackTrace;
|
||||
import jdk.jfr.Threshold;
|
||||
import jdk.jfr.Timespan;
|
||||
import jdk.jfr.internal.Type;
|
||||
|
||||
@Name(Type.EVENT_NAME_PREFIX + "ContainerMemoryUsage")
|
||||
@Label("Container Memory Usage")
|
||||
@Category({"Operating System", "Memory"})
|
||||
@Description("Container memory usage related information")
|
||||
public final class ContainerMemoryUsageEvent extends AbstractJDKEvent {
|
||||
@Label("Memory Fail Count")
|
||||
@Description("Number of times that user memory requests in the container have exceeded the memory limit")
|
||||
public long memoryFailCount;
|
||||
|
||||
@Label("Memory Usage")
|
||||
@Description("Amount of physical memory, in bytes, that is currently allocated in the current container")
|
||||
@DataAmount
|
||||
public long memoryUsage;
|
||||
|
||||
@Label("Memory and Swap Usage")
|
||||
@Description("Amount of physical memory and swap space, in bytes, that is currently allocated in the current container")
|
||||
@DataAmount
|
||||
public long swapMemoryUsage;
|
||||
}
|
@ -56,6 +56,7 @@ import java.util.Objects;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
|
||||
import jdk.internal.platform.Metrics;
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.FlightRecorderPermission;
|
||||
import jdk.jfr.Recording;
|
||||
@ -90,6 +91,11 @@ public final class Utils {
|
||||
private static final int BASE = 10;
|
||||
private static long THROTTLE_OFF = -2;
|
||||
|
||||
/*
|
||||
* This field will be lazily initialized and the access is not synchronized.
|
||||
* The possible data race is benign and is worth of not introducing any contention here.
|
||||
*/
|
||||
private static Metrics[] metrics;
|
||||
|
||||
public static void checkAccessFlightRecorder() throws SecurityException {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
@ -720,6 +726,20 @@ public final class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean shouldSkipBytecode(String eventName, Class<?> superClass) {
|
||||
if (superClass.getClassLoader() != null || !superClass.getName().equals("jdk.jfr.events.AbstractJDKEvent")) {
|
||||
return false;
|
||||
}
|
||||
return eventName.startsWith("jdk.Container") && getMetrics() == null;
|
||||
}
|
||||
|
||||
private static Metrics getMetrics() {
|
||||
if (metrics == null) {
|
||||
metrics = new Metrics[]{Metrics.systemMetrics()};
|
||||
}
|
||||
return metrics[0];
|
||||
}
|
||||
|
||||
private static String formatPositiveDuration(Duration d){
|
||||
if (d.compareTo(MICRO_SECOND) < 0) {
|
||||
// 0.000001 ms - 0.000999 ms
|
||||
|
@ -27,10 +27,16 @@ package jdk.jfr.internal.instrument;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.jfr.Event;
|
||||
import jdk.jfr.events.ActiveRecordingEvent;
|
||||
import jdk.jfr.events.ActiveSettingEvent;
|
||||
import jdk.jfr.events.ContainerIOUsageEvent;
|
||||
import jdk.jfr.events.ContainerConfigurationEvent;
|
||||
import jdk.jfr.events.ContainerCPUUsageEvent;
|
||||
import jdk.jfr.events.ContainerCPUThrottlingEvent;
|
||||
import jdk.jfr.events.ContainerMemoryUsageEvent;
|
||||
import jdk.jfr.events.DirectBufferStatisticsEvent;
|
||||
import jdk.jfr.events.ErrorThrownEvent;
|
||||
import jdk.jfr.events.ExceptionStatisticsEvent;
|
||||
@ -53,8 +59,10 @@ import jdk.jfr.internal.Logger;
|
||||
import jdk.jfr.internal.RequestEngine;
|
||||
import jdk.jfr.internal.SecuritySupport;
|
||||
|
||||
public final class JDKEvents {
|
||||
import jdk.internal.platform.Container;
|
||||
import jdk.internal.platform.Metrics;
|
||||
|
||||
public final class JDKEvents {
|
||||
private static final Class<?>[] mirrorEventClasses = {
|
||||
DeserializationEvent.class,
|
||||
ProcessStartEvent.class,
|
||||
@ -100,6 +108,12 @@ public final class JDKEvents {
|
||||
private static final JVM jvm = JVM.getJVM();
|
||||
private static final Runnable emitExceptionStatistics = JDKEvents::emitExceptionStatistics;
|
||||
private static final Runnable emitDirectBufferStatistics = JDKEvents::emitDirectBufferStatistics;
|
||||
private static final Runnable emitContainerConfiguration = JDKEvents::emitContainerConfiguration;
|
||||
private static final Runnable emitContainerCPUUsage = JDKEvents::emitContainerCPUUsage;
|
||||
private static final Runnable emitContainerCPUThrottling = JDKEvents::emitContainerCPUThrottling;
|
||||
private static final Runnable emitContainerMemoryUsage = JDKEvents::emitContainerMemoryUsage;
|
||||
private static final Runnable emitContainerIOUsage = JDKEvents::emitContainerIOUsage;
|
||||
private static Metrics containerMetrics = null;
|
||||
private static boolean initializationTriggered;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -112,9 +126,12 @@ public final class JDKEvents {
|
||||
for (Class<?> eventClass : eventClasses) {
|
||||
SecuritySupport.registerEvent((Class<? extends Event>) eventClass);
|
||||
}
|
||||
initializationTriggered = true;
|
||||
|
||||
RequestEngine.addTrustedJDKHook(ExceptionStatisticsEvent.class, emitExceptionStatistics);
|
||||
RequestEngine.addTrustedJDKHook(DirectBufferStatisticsEvent.class, emitDirectBufferStatistics);
|
||||
|
||||
initializeContainerEvents();
|
||||
initializationTriggered = true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Could not initialize JDK events. " + e.getMessage());
|
||||
@ -141,12 +158,84 @@ public final class JDKEvents {
|
||||
}
|
||||
}
|
||||
|
||||
private static void initializeContainerEvents() {
|
||||
containerMetrics = Container.metrics();
|
||||
SecuritySupport.registerEvent(ContainerConfigurationEvent.class);
|
||||
SecuritySupport.registerEvent(ContainerCPUUsageEvent.class);
|
||||
SecuritySupport.registerEvent(ContainerCPUThrottlingEvent.class);
|
||||
SecuritySupport.registerEvent(ContainerMemoryUsageEvent.class);
|
||||
SecuritySupport.registerEvent(ContainerIOUsageEvent.class);
|
||||
|
||||
RequestEngine.addTrustedJDKHook(ContainerConfigurationEvent.class, emitContainerConfiguration);
|
||||
RequestEngine.addTrustedJDKHook(ContainerCPUUsageEvent.class, emitContainerCPUUsage);
|
||||
RequestEngine.addTrustedJDKHook(ContainerCPUThrottlingEvent.class, emitContainerCPUThrottling);
|
||||
RequestEngine.addTrustedJDKHook(ContainerMemoryUsageEvent.class, emitContainerMemoryUsage);
|
||||
RequestEngine.addTrustedJDKHook(ContainerIOUsageEvent.class, emitContainerIOUsage);
|
||||
}
|
||||
|
||||
private static void emitExceptionStatistics() {
|
||||
ExceptionStatisticsEvent t = new ExceptionStatisticsEvent();
|
||||
t.throwables = ThrowableTracer.numThrowables();
|
||||
t.commit();
|
||||
}
|
||||
|
||||
private static void emitContainerConfiguration() {
|
||||
if (containerMetrics != null) {
|
||||
ContainerConfigurationEvent t = new ContainerConfigurationEvent();
|
||||
t.containerType = containerMetrics.getProvider();
|
||||
t.cpuSlicePeriod = containerMetrics.getCpuPeriod();
|
||||
t.cpuQuota = containerMetrics.getCpuQuota();
|
||||
t.cpuShares = containerMetrics.getCpuShares();
|
||||
t.effectiveCpuCount = containerMetrics.getEffectiveCpuCount();
|
||||
t.memorySoftLimit = containerMetrics.getMemorySoftLimit();
|
||||
t.memoryLimit = containerMetrics.getMemoryLimit();
|
||||
t.swapMemoryLimit = containerMetrics.getMemoryAndSwapLimit();
|
||||
t.commit();
|
||||
}
|
||||
}
|
||||
|
||||
private static void emitContainerCPUUsage() {
|
||||
if (containerMetrics != null) {
|
||||
ContainerCPUUsageEvent event = new ContainerCPUUsageEvent();
|
||||
|
||||
event.cpuTime = containerMetrics.getCpuUsage();
|
||||
event.cpuSystemTime = containerMetrics.getCpuSystemUsage();
|
||||
event.cpuUserTime = containerMetrics.getCpuUserUsage();
|
||||
event.commit();
|
||||
}
|
||||
}
|
||||
private static void emitContainerMemoryUsage() {
|
||||
if (containerMetrics != null) {
|
||||
ContainerMemoryUsageEvent event = new ContainerMemoryUsageEvent();
|
||||
|
||||
event.memoryFailCount = containerMetrics.getMemoryFailCount();
|
||||
event.memoryUsage = containerMetrics.getMemoryUsage();
|
||||
event.swapMemoryUsage = containerMetrics.getMemoryAndSwapUsage();
|
||||
event.commit();
|
||||
}
|
||||
}
|
||||
|
||||
private static void emitContainerIOUsage() {
|
||||
if (containerMetrics != null) {
|
||||
ContainerIOUsageEvent event = new ContainerIOUsageEvent();
|
||||
|
||||
event.serviceRequests = containerMetrics.getBlkIOServiceCount();
|
||||
event.dataTransferred = containerMetrics.getBlkIOServiced();
|
||||
event.commit();
|
||||
}
|
||||
}
|
||||
|
||||
private static void emitContainerCPUThrottling() {
|
||||
if (containerMetrics != null) {
|
||||
ContainerCPUThrottlingEvent event = new ContainerCPUThrottlingEvent();
|
||||
|
||||
event.cpuElapsedSlices = containerMetrics.getCpuNumPeriods();
|
||||
event.cpuThrottledSlices = containerMetrics.getCpuNumThrottled();
|
||||
event.cpuThrottledTime = containerMetrics.getCpuThrottledTime();
|
||||
event.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static byte[] retransformCallback(Class<?> klass, byte[] oldBytes) throws Throwable {
|
||||
if (java.lang.Throwable.class == klass) {
|
||||
@ -172,8 +261,14 @@ public final class JDKEvents {
|
||||
}
|
||||
|
||||
public static void remove() {
|
||||
RequestEngine.removeHook(JDKEvents::emitExceptionStatistics);
|
||||
RequestEngine.removeHook(emitExceptionStatistics);
|
||||
RequestEngine.removeHook(emitDirectBufferStatistics);
|
||||
|
||||
RequestEngine.removeHook(emitContainerConfiguration);
|
||||
RequestEngine.removeHook(emitContainerCPUUsage);
|
||||
RequestEngine.removeHook(emitContainerCPUThrottling);
|
||||
RequestEngine.removeHook(emitContainerMemoryUsage);
|
||||
RequestEngine.removeHook(emitContainerIOUsage);
|
||||
}
|
||||
|
||||
private static void emitDirectBufferStatistics() {
|
||||
|
@ -554,6 +554,31 @@
|
||||
<setting name="period">beginChunk</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ContainerConfiguration">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">beginChunk</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ContainerCPUUsage">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">30 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ContainerCPUThrottling">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">30 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ContainerMemoryUsage">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">30 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ContainerIOUsage">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">30 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.CPUInformation">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">beginChunk</setting>
|
||||
|
@ -554,6 +554,31 @@
|
||||
<setting name="period">beginChunk</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ContainerConfiguration">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">beginChunk</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ContainerCPUUsage">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">30 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ContainerCPUThrottling">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">30 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ContainerMemoryUsage">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">30 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ContainerIOUsage">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">30 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.CPUInformation">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">beginChunk</setting>
|
||||
|
@ -25,6 +25,7 @@
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import jdk.jfr.Recording;
|
||||
import jdk.jfr.EventSettings;
|
||||
import jdk.jfr.ValueDescriptor;
|
||||
import jdk.jfr.consumer.RecordedEvent;
|
||||
import jdk.jfr.consumer.RecordingFile;
|
||||
@ -34,7 +35,11 @@ public class JfrReporter {
|
||||
public static void main(String[] args) throws Exception {
|
||||
String eventName = args[0];
|
||||
try(Recording r = new Recording()) {
|
||||
r.enable(eventName);
|
||||
EventSettings es = r.enable(eventName);
|
||||
for (int i = 1; i < args.length; i++) {
|
||||
String[] kv = args[i].split("=");
|
||||
es = es.with(kv[0], kv[1]);
|
||||
}
|
||||
r.start();
|
||||
r.stop();
|
||||
Path p = Paths.get("/", "tmp", eventName + ".jfr");
|
||||
|
@ -70,31 +70,114 @@ public class TestJFREvents {
|
||||
testProcessInfo();
|
||||
|
||||
testEnvironmentVariables();
|
||||
|
||||
containerInfoTestCase();
|
||||
testCpuUsage();
|
||||
testCpuThrottling();
|
||||
testMemoryUsage();
|
||||
testIOUsage();
|
||||
} finally {
|
||||
DockerTestUtils.removeDockerImage(imageName);
|
||||
}
|
||||
}
|
||||
|
||||
// This test case is currently not in use.
|
||||
// Once new Container events are available, this test case can be used to test
|
||||
// processor-related configuration such as active processor count (see JDK-8203359).
|
||||
private static void cpuTestCase() throws Exception {
|
||||
private static void containerInfoTestCase() throws Exception {
|
||||
// leave one CPU for system and tools, otherwise this test may be unstable
|
||||
int maxNrOfAvailableCpus = availableCPUs - 1;
|
||||
for (int i=1; i < maxNrOfAvailableCpus; i = i * 2) {
|
||||
testCPUInfo("jdk.ContainerConfiguration", i, i);
|
||||
for (int j=64; j <= 256; j *= 2) {
|
||||
testContainerInfo(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testCPUInfo(String eventName, int valueToSet, int expectedValue) throws Exception {
|
||||
Common.logNewTestCase("CPUInfo: --cpus = " + valueToSet);
|
||||
String fieldName = "activeProcessorCount";
|
||||
private static void testContainerInfo(int expectedCPUs, int expectedMemoryMB) throws Exception {
|
||||
Common.logNewTestCase("ContainerInfo: --cpus = " + expectedCPUs + " --memory=" + expectedMemoryMB + "m");
|
||||
String eventName = "jdk.ContainerConfiguration";
|
||||
long expectedSlicePeriod = 100000; // default slice period
|
||||
long expectedMemoryLimit = expectedMemoryMB * 1024 * 1024;
|
||||
|
||||
String cpuCountFld = "effectiveCpuCount";
|
||||
String cpuQuotaFld = "cpuQuota";
|
||||
String cpuSlicePeriodFld = "cpuSlicePeriod";
|
||||
String memoryLimitFld = "memoryLimit";
|
||||
|
||||
DockerTestUtils.dockerRunJava(
|
||||
commonDockerOpts()
|
||||
.addDockerOpts("--cpus=" + valueToSet)
|
||||
.addDockerOpts("--cpus=" + expectedCPUs)
|
||||
.addDockerOpts("--memory=" + expectedMemoryMB + "m")
|
||||
.addClassOptions(eventName))
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain(fieldName + " = " + expectedValue);
|
||||
.shouldContain(cpuCountFld + " = " + expectedCPUs)
|
||||
.shouldContain(cpuSlicePeriodFld + " = " + expectedSlicePeriod)
|
||||
.shouldContain(cpuQuotaFld + " = " + expectedCPUs * expectedSlicePeriod)
|
||||
.shouldContain(memoryLimitFld + " = " + expectedMemoryLimit);
|
||||
}
|
||||
|
||||
private static void testCpuUsage() throws Exception {
|
||||
Common.logNewTestCase("CPU Usage");
|
||||
String eventName = "jdk.ContainerCPUUsage";
|
||||
|
||||
String cpuTimeFld = "cpuTime";
|
||||
String cpuUserTimeFld = "cpuUserTime";
|
||||
String cpuSystemTimeFld = "cpuSystemTime";
|
||||
|
||||
DockerTestUtils.dockerRunJava(
|
||||
commonDockerOpts()
|
||||
.addClassOptions(eventName, "period=endChunk"))
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldNotContain(cpuTimeFld + " = " + 0)
|
||||
.shouldNotContain(cpuUserTimeFld + " = " + 0)
|
||||
.shouldNotContain(cpuSystemTimeFld + " = " + 0);
|
||||
}
|
||||
|
||||
private static void testMemoryUsage() throws Exception {
|
||||
Common.logNewTestCase("Memory Usage");
|
||||
String eventName = "jdk.ContainerMemoryUsage";
|
||||
|
||||
String memoryFailCountFld = "memoryFailCount";
|
||||
String memoryUsageFld = "memoryUsage";
|
||||
String swapMemoryUsageFld = "swapMemoryUsage";
|
||||
|
||||
DockerTestUtils.dockerRunJava(
|
||||
commonDockerOpts()
|
||||
.addClassOptions(eventName, "period=endChunk"))
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain(memoryFailCountFld)
|
||||
.shouldContain(memoryUsageFld)
|
||||
.shouldContain(swapMemoryUsageFld);
|
||||
}
|
||||
|
||||
private static void testIOUsage() throws Exception {
|
||||
Common.logNewTestCase("I/O Usage");
|
||||
String eventName = "jdk.ContainerIOUsage";
|
||||
|
||||
String serviceRequestsFld = "serviceRequests";
|
||||
String dataTransferredFld = "dataTransferred";
|
||||
|
||||
DockerTestUtils.dockerRunJava(
|
||||
commonDockerOpts()
|
||||
.addClassOptions(eventName, "period=endChunk"))
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain(serviceRequestsFld)
|
||||
.shouldContain(dataTransferredFld);
|
||||
}
|
||||
|
||||
private static void testCpuThrottling() throws Exception {
|
||||
Common.logNewTestCase("CPU Throttling");
|
||||
String eventName = "jdk.ContainerCPUThrottling";
|
||||
|
||||
String cpuElapsedSlicesFld = "cpuElapsedSlices";
|
||||
String cpuThrottledSlicesFld = "cpuThrottledSlices";
|
||||
String cpuThrottledTimeFld = "cpuThrottledTime";
|
||||
|
||||
DockerTestUtils.dockerRunJava(
|
||||
commonDockerOpts()
|
||||
.addClassOptions(eventName, "period=endChunk"))
|
||||
.shouldHaveExitValue(0)
|
||||
.shouldContain(cpuElapsedSlicesFld)
|
||||
.shouldContain(cpuThrottledSlicesFld)
|
||||
.shouldContain(cpuThrottledTimeFld);
|
||||
}
|
||||
|
||||
|
||||
@ -118,7 +201,6 @@ public class TestJFREvents {
|
||||
.shouldContain("pid = 1");
|
||||
}
|
||||
|
||||
|
||||
private static DockerRunOptions commonDockerOpts() {
|
||||
return new DockerRunOptions(imageName, "/jdk/bin/java", "JfrReporter")
|
||||
.addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/")
|
||||
|
@ -71,6 +71,13 @@ public class TestLookForUntestedEvents {
|
||||
"GCPhasePauseLevel4")
|
||||
);
|
||||
|
||||
// Container events are tested in hotspot/jtreg/containers/docker/TestJFREvents.java
|
||||
private static final Set<String> coveredContainerEvents = new HashSet<>(
|
||||
Arrays.asList(
|
||||
"ContainerConfiguration", "ContainerCPUUsage", "ContainerCPUThrottling",
|
||||
"ContainerMemoryUsage", "ContainerIOUsage")
|
||||
);
|
||||
|
||||
// This is a "known failure list" for this test.
|
||||
// NOTE: if the event is not covered, a bug should be open, and bug number
|
||||
// noted in the comments for this set.
|
||||
@ -115,6 +122,7 @@ public class TestLookForUntestedEvents {
|
||||
// Account for hard-to-test, experimental and GC tested events
|
||||
eventsNotCoveredByTest.removeAll(hardToTestEvents);
|
||||
eventsNotCoveredByTest.removeAll(coveredGcEvents);
|
||||
eventsNotCoveredByTest.removeAll(coveredContainerEvents);
|
||||
eventsNotCoveredByTest.removeAll(knownNotCoveredEvents);
|
||||
|
||||
if (!eventsNotCoveredByTest.isEmpty()) {
|
||||
|
@ -201,6 +201,12 @@ public class EventNames {
|
||||
public final static String DirectBufferStatistics = PREFIX + "DirectBufferStatistics";
|
||||
public final static String Deserialization = PREFIX + "Deserialization";
|
||||
|
||||
// Containers
|
||||
public static final String ContainerConfiguration = PREFIX + "ContainerConfiguration";
|
||||
public static final String ContainerCPUUsage = PREFIX + "ContainerCPUUsage";
|
||||
public static final String ContainerCPUThrottling = PREFIX + "ContainerCPUThrottling";
|
||||
public static final String ContainerMemoryUsage = PREFIX + "ContainerMemoryUsage";
|
||||
public static final String ContainerIOUsage = PREFIX + "ContainerIOUsage";
|
||||
|
||||
// Flight Recorder
|
||||
public final static String DumpReason = PREFIX + "DumpReason";
|
||||
|
Loading…
x
Reference in New Issue
Block a user