Skip to content
Permalink
Browse files
8238665: Add JFR event for direct memory statistics
Reviewed-by: egahlin, alanb
  • Loading branch information
Denghui Dong committed Apr 14, 2020
1 parent 1cc71b4 commit a62a0e5282ab692fb60826c4268a4884daa34754
Showing 13 changed files with 276 additions and 27 deletions.
@@ -26,10 +26,10 @@
package java.nio;

import jdk.internal.access.JavaLangRefAccess;
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.Unsafe;
import jdk.internal.misc.VM;
import jdk.internal.misc.VM.BufferPool;

import java.util.concurrent.atomic.AtomicLong;

@@ -210,7 +210,7 @@ static void unreserveMemory(long size, int cap) {
assert cnt >= 0 && reservedMem >= 0 && totalCap >= 0;
}

static final JavaNioAccess.BufferPool BUFFER_POOL = new JavaNioAccess.BufferPool() {
static final BufferPool BUFFER_POOL = new BufferPool() {
@Override
public String getName() {
return "direct";
@@ -30,6 +30,7 @@
import jdk.internal.access.SharedSecrets;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.misc.Unsafe;
import jdk.internal.misc.VM.BufferPool;
import jdk.internal.vm.annotation.ForceInline;

import java.util.Spliterator;
@@ -758,7 +759,7 @@ final void checkSegment() {
SharedSecrets.setJavaNioAccess(
new JavaNioAccess() {
@Override
public JavaNioAccess.BufferPool getDirectBufferPool() {
public BufferPool getDirectBufferPool() {
return Bits.BUFFER_POOL;
}

@@ -26,20 +26,16 @@
package jdk.internal.access;

import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.misc.VM.BufferPool;

import java.nio.Buffer;
import java.nio.ByteBuffer;

public interface JavaNioAccess {

/**
* Provides access to information on buffer usage.
* Used by {@code jdk.internal.misc.VM}.
*/
interface BufferPool {
String getName();
long getCount();
long getTotalCapacity();
long getMemoryUsed();
}
BufferPool getDirectBufferPool();

/**
@@ -27,10 +27,16 @@

import static java.lang.Thread.State.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import jdk.internal.access.SharedSecrets;

import sun.nio.ch.FileChannelImpl;

public class VM {

// the init level when the VM is fully initialized
@@ -414,4 +420,34 @@ public static boolean isSetUID() {
* object class in the archived graph.
*/
public static native void initializeFromArchive(Class<?> c);

/**
* Provides access to information on buffer usage.
*/
public interface BufferPool {
String getName();
long getCount();
long getTotalCapacity();
long getMemoryUsed();
}

private static class BufferPoolsHolder {
static final List<BufferPool> BUFFER_POOLS;

static {
ArrayList<BufferPool> bufferPools = new ArrayList<>(3);
bufferPools.add(SharedSecrets.getJavaNioAccess().getDirectBufferPool());
bufferPools.add(FileChannelImpl.getMappedBufferPool());
bufferPools.add(FileChannelImpl.getSyncMappedBufferPool());

BUFFER_POOLS = Collections.unmodifiableList(bufferPools);
}
}

/**
* @return the list of buffer pools.
*/
public static List<BufferPool> getBufferPools() {
return BufferPoolsHolder.BUFFER_POOLS;
}
}
@@ -45,11 +45,11 @@
import java.util.Objects;

import jdk.internal.access.JavaIOFileDescriptorAccess;
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.ExtendedMapMode;
import jdk.internal.misc.Unsafe;
import jdk.internal.misc.VM;
import jdk.internal.misc.VM.BufferPool;
import jdk.internal.ref.Cleaner;
import jdk.internal.ref.CleanerFactory;

@@ -1158,8 +1158,8 @@ private void checkMode(MapMode mode, int prot, boolean isSync) {
* Invoked by sun.management.ManagementFactoryHelper to create the management
* interface for mapped buffers.
*/
public static JavaNioAccess.BufferPool getMappedBufferPool() {
return new JavaNioAccess.BufferPool() {
public static BufferPool getMappedBufferPool() {
return new BufferPool() {
@Override
public String getName() {
return "mapped";
@@ -1183,8 +1183,8 @@ public long getMemoryUsed() {
* Invoked by sun.management.ManagementFactoryHelper to create the management
* interface for sync mapped buffers.
*/
public static JavaNioAccess.BufferPool getSyncMappedBufferPool() {
return new JavaNioAccess.BufferPool() {
public static BufferPool getSyncMappedBufferPool() {
return new BufferPool() {
@Override
public String getName() {
return "mapped - 'non-volatile memory'";
@@ -39,8 +39,9 @@
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;

import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.VM;
import jdk.internal.misc.VM.BufferPool;

import java.util.ArrayList;
import java.util.List;
@@ -52,6 +53,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
* ManagementFactoryHelper provides static factory methods to create
@@ -337,16 +339,16 @@ private static PlatformLoggingImpl getInstance() {
static final PlatformLoggingMXBean MBEAN = getInstance();
}

private static List<BufferPoolMXBean> bufferPools = null;
public static synchronized List<BufferPoolMXBean> getBufferPoolMXBeans() {
private static volatile List<BufferPoolMXBean> bufferPools;
public static List<BufferPoolMXBean> getBufferPoolMXBeans() {
if (bufferPools == null) {
bufferPools = new ArrayList<>(2);
bufferPools.add(createBufferPoolMXBean(SharedSecrets.getJavaNioAccess()
.getDirectBufferPool()));
bufferPools.add(createBufferPoolMXBean(sun.nio.ch.FileChannelImpl
.getMappedBufferPool()));
bufferPools.add(createBufferPoolMXBean(sun.nio.ch.FileChannelImpl
.getSyncMappedBufferPool()));
synchronized (ManagementFactoryHelper.class) {
if (bufferPools == null) {
bufferPools = VM.getBufferPools().stream()
.map(ManagementFactoryHelper::createBufferPoolMXBean)
.collect(Collectors.toList());
}
}
}
return bufferPools;
}
@@ -357,7 +359,7 @@ public static synchronized List<BufferPoolMXBean> getBufferPoolMXBeans() {
* Creates management interface for the given buffer pool.
*/
private static BufferPoolMXBean
createBufferPoolMXBean(final JavaNioAccess.BufferPool pool)
createBufferPoolMXBean(final BufferPool pool)
{
return new BufferPoolMXBean() {
private volatile ObjectName objname; // created lazily
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. 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.internal.misc.VM.BufferPool;

import jdk.jfr.*;
import jdk.jfr.internal.Type;

@Category({ "Java Application", "Statistics" })
public abstract class AbstractBufferStatisticsEvent extends AbstractJDKEvent {

AbstractBufferStatisticsEvent() {
BufferPool bufferPool = getBufferPool();

count = bufferPool.getCount();
totalCapacity = bufferPool.getTotalCapacity();
memoryUsed = bufferPool.getMemoryUsed();
}

@Label("Count")
public long count;

@Label("Total Capacity")
@DataAmount
public long totalCapacity;

@Label("Memory Used")
@DataAmount
public long memoryUsed;

abstract BufferPool getBufferPool();
}
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. 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.internal.misc.VM;
import jdk.internal.misc.VM.BufferPool;

import jdk.jfr.*;
import jdk.jfr.internal.Type;

@Name(Type.EVENT_NAME_PREFIX + "DirectBufferStatistics")
@Label("Direct Buffer Statistics")
@Description("Statistics of direct buffer")
public final class DirectBufferStatisticsEvent extends AbstractBufferStatisticsEvent {

private static final BufferPool DIRECT_BUFFER_POOL = VM.getBufferPools().stream()
.filter(p -> "direct".equals(p.getName()))
.findFirst().get();

public DirectBufferStatisticsEvent() {
this.maxCapacity = VM.maxDirectMemory();
}

@Label("Maximum Capacity")
@Description("Maximum direct buffer capacity the process can use")
@DataAmount
public long maxCapacity;

BufferPool getBufferPool() {
return DIRECT_BUFFER_POOL;
}
}
@@ -31,6 +31,7 @@
import jdk.jfr.Event;
import jdk.jfr.events.ActiveRecordingEvent;
import jdk.jfr.events.ActiveSettingEvent;
import jdk.jfr.events.DirectBufferStatisticsEvent;
import jdk.jfr.events.ErrorThrownEvent;
import jdk.jfr.events.ExceptionStatisticsEvent;
import jdk.jfr.events.ExceptionThrownEvent;
@@ -76,7 +77,8 @@ public final class JDKEvents {
jdk.internal.event.TLSHandshakeEvent.class,
jdk.internal.event.X509CertificateEvent.class,
jdk.internal.event.X509ValidationEvent.class,
jdk.internal.event.ProcessStartEvent.class
jdk.internal.event.ProcessStartEvent.class,
DirectBufferStatisticsEvent.class
};

// This is a list of the classes with instrumentation code that should be applied.
@@ -93,6 +95,7 @@ public final class JDKEvents {
private static final Class<?>[] targetClasses = new Class<?>[instrumentationClasses.length];
private static final JVM jvm = JVM.getJVM();
private static final Runnable emitExceptionStatistics = JDKEvents::emitExceptionStatistics;
private static final Runnable emitDirectBufferStatistics = JDKEvents::emitDirectBufferStatistics;
private static boolean initializationTriggered;

@SuppressWarnings("unchecked")
@@ -107,6 +110,7 @@ public synchronized static void initialize() {
}
initializationTriggered = true;
RequestEngine.addTrustedJDKHook(ExceptionStatisticsEvent.class, emitExceptionStatistics);
RequestEngine.addTrustedJDKHook(DirectBufferStatisticsEvent.class, emitDirectBufferStatistics);
}
} catch (Exception e) {
Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Could not initialize JDK events. " + e.getMessage());
@@ -163,5 +167,11 @@ public static byte[] retransformCallback(Class<?> klass, byte[] oldBytes) throws

public static void remove() {
RequestEngine.removeHook(JDKEvents::emitExceptionStatistics);
RequestEngine.removeHook(emitDirectBufferStatistics);
}

private static void emitDirectBufferStatistics() {
DirectBufferStatisticsEvent e = new DirectBufferStatisticsEvent();
e.commit();
}
}
@@ -768,6 +768,10 @@
<setting name="stackTrace">true</setting>
</event>

<event name="jdk.DirectBufferStatistics">
<setting name="enabled">true</setting>
<setting name="period">5 s</setting>
</event>



@@ -768,6 +768,10 @@
<setting name="stackTrace">true</setting>
</event>

<event name="jdk.DirectBufferStatistics">
<setting name="enabled">true</setting>
<setting name="period">5 s</setting>
</event>



0 comments on commit a62a0e5

Please sign in to comment.