8199712: Flight Recorder
Co-authored-by: Markus Gronlund <markus.gronlund@oracle.com> Reviewed-by: coleenp, ihse, erikj, dsamersoff, mseledtsov, egahlin, mgronlun
This commit is contained in:
parent
f575533a17
commit
a060be188d
@ -509,6 +509,15 @@ jdk.localedata_COPY += _dict _th
|
||||
# Exclude BreakIterator classes that are just used in compile process to generate
|
||||
# data files and shouldn't go in the product
|
||||
jdk.localedata_EXCLUDE_FILES += sun/text/resources/ext/BreakIteratorRules_th.java
|
||||
################################################################################
|
||||
|
||||
# There is an issue in sjavac that triggers a warning in jdk.jfr that isn't
|
||||
# triggered without sjavac.
|
||||
ifeq ($(ENABLE_SJAVAC), yes)
|
||||
jdk.jfr_SETUP := GENERATE_JDKBYTECODE_NOWARNINGS
|
||||
endif
|
||||
jdk.jfr_COPY := .xsd .xml .dtd
|
||||
jdk.jfr_ADD_JAVAC_FLAGS := -XDstringConcat=inline -Xlint:-exports
|
||||
|
||||
################################################################################
|
||||
# If this is an imported module that has prebuilt classes, only compile
|
||||
|
@ -26,7 +26,7 @@
|
||||
# All valid JVM features, regardless of platform
|
||||
VALID_JVM_FEATURES="compiler1 compiler2 zero minimal dtrace jvmti jvmci \
|
||||
graal vm-structs jni-check services management cmsgc g1gc parallelgc serialgc nmt cds \
|
||||
static-build link-time-opt aot"
|
||||
static-build link-time-opt aot jfr"
|
||||
|
||||
# All valid JVM variants
|
||||
VALID_JVM_VARIANTS="server client minimal core zero custom"
|
||||
@ -309,6 +309,11 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES],
|
||||
AC_MSG_ERROR([Specified JVM feature 'cmsgc' requires feature 'serialgc'])
|
||||
fi
|
||||
|
||||
# Enable JFR by default, except on linux-sparcv9 and on minimal.
|
||||
if test "x$OPENJDK_TARGET_OS" != xlinux || test "x$OPENJDK_TARGET_CPU" != xsparcv9; then
|
||||
NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES jfr"
|
||||
fi
|
||||
|
||||
# Turn on additional features based on other parts of configure
|
||||
if test "x$INCLUDE_DTRACE" = "xtrue"; then
|
||||
JVM_FEATURES="$JVM_FEATURES dtrace"
|
||||
@ -396,7 +401,7 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES],
|
||||
NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES cds"
|
||||
fi
|
||||
|
||||
# Enable default features depending on variant.
|
||||
# Enable features depending on variant.
|
||||
JVM_FEATURES_server="compiler1 compiler2 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci $JVM_FEATURES_aot $JVM_FEATURES_graal"
|
||||
JVM_FEATURES_client="compiler1 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci"
|
||||
JVM_FEATURES_core="$NON_MINIMAL_FEATURES $JVM_FEATURES"
|
||||
|
@ -130,7 +130,7 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
|
||||
|
||||
if test "x$OPENJDK_TARGET_OS" = xsolaris; then
|
||||
BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lsocket -lsched -ldoor -ldemangle -lnsl \
|
||||
-lrt"
|
||||
-lrt -lkstat"
|
||||
BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBCXX_JVM"
|
||||
fi
|
||||
|
||||
|
@ -59,7 +59,9 @@ BOOT_MODULES += \
|
||||
java.security.sasl \
|
||||
java.xml \
|
||||
jdk.internal.vm.ci \
|
||||
jdk.jfr \
|
||||
jdk.management \
|
||||
jdk.management.jfr \
|
||||
jdk.management.agent \
|
||||
jdk.net \
|
||||
jdk.sctp \
|
||||
@ -152,6 +154,7 @@ DOCS_MODULES += \
|
||||
jdk.jdeps \
|
||||
jdk.jdi \
|
||||
jdk.jdwp.agent \
|
||||
jdk.jfr \
|
||||
jdk.jlink \
|
||||
jdk.jsobject \
|
||||
jdk.jshell \
|
||||
@ -159,6 +162,7 @@ DOCS_MODULES += \
|
||||
jdk.localedata \
|
||||
jdk.management \
|
||||
jdk.management.agent \
|
||||
jdk.management.jfr \
|
||||
jdk.naming.dns \
|
||||
jdk.naming.rmi \
|
||||
jdk.net \
|
||||
|
46
make/copy/Copy-jdk.jfr.gmk
Normal file
46
make/copy/Copy-jdk.jfr.gmk
Normal file
@ -0,0 +1,46 @@
|
||||
#
|
||||
# Copyright (c) 2014, 2018, 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.
|
||||
#
|
||||
|
||||
include CopyCommon.gmk
|
||||
|
||||
################################################################################
|
||||
|
||||
$(eval $(call SetupCopyFiles, COPY_JFR_METADATA, \
|
||||
SRC := $(TOPDIR)/src/hotspot/share/jfr/metadata, \
|
||||
DEST := $(JDK_OUTPUTDIR)/modules/jdk.jfr/jdk/jfr/internal/types, \
|
||||
FILES := metadata.xml \
|
||||
))
|
||||
|
||||
TARGETS += $(COPY_JFR_METADATA)
|
||||
|
||||
JFR_CONF_DIR := $(TOPDIR)/src/jdk.jfr/share/conf/jfr
|
||||
$(eval $(call SetupCopyFiles, COPY_JFR_CONF, \
|
||||
DEST := $(LIB_DST_DIR)/jfr, \
|
||||
FILES := $(wildcard $(JFR_CONF_DIR)/*.jfc), \
|
||||
FLATTEN := true, \
|
||||
))
|
||||
TARGETS += $(COPY_JFR_CONF)
|
||||
|
||||
################################################################################
|
@ -38,6 +38,7 @@ include HotspotCommon.gmk
|
||||
include gensrc/GensrcAdlc.gmk
|
||||
include gensrc/GensrcDtrace.gmk
|
||||
include gensrc/GensrcJvmti.gmk
|
||||
include gensrc/GensrcJfr.gmk
|
||||
|
||||
$(eval $(call IncludeCustomExtension, hotspot/gensrc/GenerateSources.gmk))
|
||||
|
||||
|
94
make/hotspot/gensrc/GensrcJfr.gmk
Normal file
94
make/hotspot/gensrc/GensrcJfr.gmk
Normal file
@ -0,0 +1,94 @@
|
||||
#
|
||||
# Copyright (c) 2013, 2018, 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.
|
||||
#
|
||||
|
||||
$(eval $(call IncludeCustomExtension, hotspot/gensrc/GensrcJfr.gmk))
|
||||
|
||||
################################################################################
|
||||
# Build tools needed for the Jfr source code generation
|
||||
|
||||
JFR_TOOLS_SRCDIR := $(TOPDIR)/src/hotspot/share/jfr/metadata
|
||||
JFR_TOOLS_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/tools/jfr
|
||||
|
||||
$(eval $(call SetupJavaCompiler, GENERATE_JFRBYTECODE, \
|
||||
JAVAC := $(JAVAC), \
|
||||
FLAGS := $(DISABLE_WARNINGS), \
|
||||
SERVER_DIR := $(SJAVAC_SERVER_DIR), \
|
||||
SERVER_JVM := $(SJAVAC_SERVER_JAVA), \
|
||||
DISABLE_SJAVAC := true, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupJavaCompilation, BUILD_JFR_TOOLS, \
|
||||
SETUP := GENERATE_JFRBYTECODE, \
|
||||
SRC := $(JFR_TOOLS_SRCDIR), \
|
||||
INCLUDE_FILES := GenerateJfrFiles.java, \
|
||||
BIN := $(JFR_TOOLS_OUTPUTDIR), \
|
||||
))
|
||||
|
||||
TOOL_JFR_GEN := $(JAVA_SMALL) -cp $(JFR_TOOLS_OUTPUTDIR) GenerateJfrFiles
|
||||
|
||||
################################################################################
|
||||
# Setup make rules for Jfr file file generation.
|
||||
#
|
||||
# Parameter 1 is the name of the rule. This name is used as variable prefix,
|
||||
# and the targets generated are listed in a variable by that name. This name is
|
||||
# also used as the name of the output file.
|
||||
#
|
||||
# Remaining parameters are named arguments. These include:
|
||||
# XML_FILE -- The input source file to use
|
||||
# XSD_FILE -- The input schema for validation
|
||||
# OUTPUT_DIR -- The directory to put the generated file in
|
||||
SetupJfrGeneration = $(NamedParamsMacroTemplate)
|
||||
define SetupJfrGenerationBody
|
||||
$$($1_OUTPUT_DIR)/$1: $$($1_XML_FILE) $$($1_XSD_FILE) $$(BUILD_JFR_TOOLS)
|
||||
$$(call LogInfo, Generating $$(@F))
|
||||
$$(call MakeDir, $$(@D))
|
||||
$$(call ExecuteWithLog, $$@, $$(TOOL_JFR_GEN) $$($1_XML_FILE) $$($1_XSD_FILE) $$($1_OUTPUT_DIR))
|
||||
test -f $$@
|
||||
|
||||
TARGETS += $$($1_OUTPUT_DIR)/$1
|
||||
|
||||
endef
|
||||
|
||||
################################################################################
|
||||
# Create files in gensrc/jfrfiles
|
||||
|
||||
JFR_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/gensrc/jfrfiles
|
||||
JFR_SRCDIR := $(TOPDIR)/src/hotspot/share/jfr/metadata
|
||||
|
||||
METADATA_XML ?= $(JFR_SRCDIR)/metadata.xml
|
||||
METADATA_XSD ?= $(JFR_SRCDIR)/metadata.xsd
|
||||
|
||||
# Changing these will trigger a rebuild of generated jfr files.
|
||||
JFR_DEPS += \
|
||||
$(METADATA_XML) \
|
||||
$(METADATA_XSD) \
|
||||
#
|
||||
|
||||
# our generator will generate all files in one go, so only need to setup one target rule
|
||||
$(eval $(call SetupJfrGeneration, jfrEventClasses.hpp, \
|
||||
XML_FILE := $(METADATA_XML), \
|
||||
XSD_FILE := $(METADATA_XSD), \
|
||||
OUTPUT_DIR := $(JFR_OUTPUTDIR), \
|
||||
))
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2013, 2018, 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
|
||||
@ -50,7 +50,7 @@ TOOL_JVMTI_GEN := $(JAVA_SMALL) -cp $(JVMTI_TOOLS_OUTPUTDIR) jvmtiGen
|
||||
TOOL_JVMTI_ENV_FILL := $(JAVA_SMALL) -cp $(JVMTI_TOOLS_OUTPUTDIR) jvmtiEnvFill
|
||||
|
||||
################################################################################
|
||||
# Setup make rules for an xml transform for jvmti/trace file generation.
|
||||
# Setup make rules for an xml transform for jvmti file generation.
|
||||
#
|
||||
# Parameter 1 is the name of the rule. This name is used as variable prefix,
|
||||
# and the targets generated are listed in a variable by that name. This name is
|
||||
@ -126,48 +126,3 @@ ifeq ($(JVM_VARIANT), $(firstword $(JVM_VARIANTS)))
|
||||
|
||||
TARGETS += $(COPY_JVMTI_H)
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# Create trace files in gensrc/tracefiles
|
||||
|
||||
TRACE_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/gensrc/tracefiles
|
||||
TRACE_SRCDIR := $(TOPDIR)/src/hotspot/share/trace
|
||||
|
||||
# Append list of XSL files to search (might have been set by custom extensions)
|
||||
TRACE_XSL_FILES += $(wildcard $(TRACE_SRCDIR)/*.xsl)
|
||||
|
||||
TRACE_XML ?= $(TRACE_SRCDIR)/trace.xml
|
||||
|
||||
# Changing these will trigger a rebuild of generated trace files.
|
||||
TRACE_DEPS += \
|
||||
$(TRACE_XML) \
|
||||
$(TRACE_SRCDIR)/tracetypes.xml \
|
||||
$(TRACE_SRCDIR)/tracerelationdecls.xml \
|
||||
$(TRACE_SRCDIR)/traceevents.xml \
|
||||
$(TRACE_SRCDIR)/trace.dtd \
|
||||
$(TRACE_SRCDIR)/xinclude.mod \
|
||||
#
|
||||
|
||||
# Setup rule for generating a trace file
|
||||
#
|
||||
# $1 is generated source file name in $(TRACE_OUTPUTDIR)
|
||||
define SetupTraceGeneration
|
||||
$$(eval $$(call SetupXslTransform, $1, \
|
||||
XML_FILE := $$(TRACE_XML), \
|
||||
XSL_FILE := $$(firstword $$(filter %/$$(basename $1).xsl, $$(TRACE_XSL_FILES))), \
|
||||
OUTPUT_DIR := $$(TRACE_OUTPUTDIR), \
|
||||
DEPS := $$(TRACE_DEPS), \
|
||||
))
|
||||
endef
|
||||
|
||||
# Append files to generated (might have been set by custom extensions)
|
||||
TRACE_GENSRC_FILES += \
|
||||
traceEventClasses.hpp \
|
||||
traceEventIds.hpp \
|
||||
traceTypes.hpp \
|
||||
#
|
||||
|
||||
# Call SetupTraceGeneration for all trace gensrc files
|
||||
$(foreach tracefile, $(TRACE_GENSRC_FILES), \
|
||||
$(eval $(call SetupTraceGeneration, $(tracefile))) \
|
||||
)
|
||||
|
@ -154,6 +154,12 @@ ifneq ($(call check-jvm-feature, serialgc), true)
|
||||
# If serial is disabled, we cannot use serial as OldGC in parallel
|
||||
JVM_EXCLUDE_FILES += psMarkSweep.cpp psMarkSweepDecorator.cpp
|
||||
endif
|
||||
|
||||
ifneq ($(call check-jvm-feature, jfr), true)
|
||||
JVM_CFLAGS_FEATURES += -DINCLUDE_JFR=0
|
||||
JVM_EXCLUDE_PATTERNS += jfr
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
|
||||
ifeq ($(call check-jvm-feature, link-time-opt), true)
|
||||
|
@ -223,7 +223,7 @@ class BuildConfig {
|
||||
sysDefines.add("_WINDOWS");
|
||||
sysDefines.add("HOTSPOT_BUILD_USER=\\\""+System.getProperty("user.name")+"\\\"");
|
||||
sysDefines.add("HOTSPOT_BUILD_TARGET=\\\""+get("Build")+"\\\"");
|
||||
sysDefines.add("INCLUDE_TRACE=1");
|
||||
sysDefines.add("INCLUDE_JFR=1");
|
||||
sysDefines.add("_JNI_IMPLEMENTATION_");
|
||||
if (vars.get("PlatformName").equals("Win32")) {
|
||||
sysDefines.add("HOTSPOT_LIB_ARCH=\\\"i386\\\"");
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2006, 2018, 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
|
||||
@ -273,6 +273,7 @@ my.make.rule.test.targets.svc= \
|
||||
${my.test.target.set:TESTNAME=jdk_instrument}, \
|
||||
${my.test.target.set:TESTNAME=jdk_jmx}, \
|
||||
${my.test.target.set:TESTNAME=jdk_jdi}, \
|
||||
${my.test.target.set:TESTNAME=jdk_jfr}, \
|
||||
${my.test.target.set:TESTNAME=svc_tools}, \
|
||||
${my.make.rule.test.targets.svc.extra}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2010, 2018, 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
|
||||
@ -98,8 +98,8 @@ dist.javadoc.dir=${dist.dir}/javadoc
|
||||
dist.nashornapi.javadoc.dir=${dist.javadoc.dir}/nashornapi
|
||||
dist.dynalinkapi.javadoc.dir=${dist.javadoc.dir}/dynalinkapi
|
||||
|
||||
# configuration for java flight recorder
|
||||
run.test.jvmargs.jfr=-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=${build.dir},stackdepth=128
|
||||
# configuration for flight recorder
|
||||
run.test.jvmargs.jfr=XX:StartFlightRecording=disk=true,dumponexit=true,dumponexitpath=${build.dir},stackdepth=128
|
||||
|
||||
# test library location
|
||||
test.lib=test/nashorn/lib
|
||||
@ -354,7 +354,7 @@ run.test.xms=2G
|
||||
# uncomment this jfr.args to enable light recordings. the stack needs to be cranked up to 1024 frames,
|
||||
# or everything will as of the now drown in lambda forms and be cut off.
|
||||
#
|
||||
#jfr.args=-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath="test_suite.jfr",stackdepth=1024 \
|
||||
#jfr.args=-XX:StartFlightRecording=disk=true,dumponexit=true,dumponexitpath="test_suite.jfr",stackdepth=1024
|
||||
|
||||
jfr.args=
|
||||
|
||||
|
@ -2891,7 +2891,6 @@
|
||||
<in>stringUtils.hpp</in>
|
||||
<in>ticks.cpp</in>
|
||||
<in>ticks.hpp</in>
|
||||
<in>ticks.inline.hpp</in>
|
||||
<in>utf8.cpp</in>
|
||||
<in>utf8.hpp</in>
|
||||
<in>vmError.cpp</in>
|
||||
@ -6887,7 +6886,7 @@
|
||||
<pElem>../../hotspot/src/share/vm/ci</pElem>
|
||||
<pElem>../../hotspot/src/share/vm/oops</pElem>
|
||||
<pElem>../../hotspot/src/share/vm/trace</pElem>
|
||||
<pElem>../../build/macosx-x86_64-normal-server-release/hotspot/variant-server/gensrc/tracefiles</pElem>
|
||||
<pElem>../../build/macosx-x86_64-normal-server-release/hotspot/variant-server/gensrc/jfrfiles</pElem>
|
||||
<pElem>../../hotspot/src/share/vm/gc/parallel</pElem>
|
||||
<pElem>../../hotspot/src/share/vm/gc/shared</pElem>
|
||||
<pElem>../../hotspot/src/share/vm/classfile</pElem>
|
||||
@ -15408,11 +15407,6 @@
|
||||
tool="3"
|
||||
flavor2="0">
|
||||
</item>
|
||||
<item path="../../src/hotspot/share/utilities/ticks.inline.hpp"
|
||||
ex="false"
|
||||
tool="3"
|
||||
flavor2="0">
|
||||
</item>
|
||||
<item path="../../src/hotspot/share/utilities/utf8.cpp"
|
||||
ex="false"
|
||||
tool="1"
|
||||
@ -29190,11 +29184,6 @@
|
||||
tool="3"
|
||||
flavor2="0">
|
||||
</item>
|
||||
<item path="../../src/hotspot/share/utilities/ticks.inline.hpp"
|
||||
ex="false"
|
||||
tool="3"
|
||||
flavor2="0">
|
||||
</item>
|
||||
<item path="../../src/hotspot/share/utilities/utf8.cpp"
|
||||
ex="false"
|
||||
tool="1"
|
||||
|
90
src/hotspot/cpu/aarch64/vm_version_ext_aarch64.cpp
Normal file
90
src/hotspot/cpu/aarch64/vm_version_ext_aarch64.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "runtime/os.inline.hpp"
|
||||
#include "vm_version_ext_aarch64.hpp"
|
||||
|
||||
// VM_Version_Ext statics
|
||||
int VM_Version_Ext::_no_of_threads = 0;
|
||||
int VM_Version_Ext::_no_of_cores = 0;
|
||||
int VM_Version_Ext::_no_of_sockets = 0;
|
||||
bool VM_Version_Ext::_initialized = false;
|
||||
char VM_Version_Ext::_cpu_name[CPU_TYPE_DESC_BUF_SIZE] = {0};
|
||||
char VM_Version_Ext::_cpu_desc[CPU_DETAILED_DESC_BUF_SIZE] = {0};
|
||||
|
||||
void VM_Version_Ext::initialize_cpu_information(void) {
|
||||
// do nothing if cpu info has been initialized
|
||||
if (_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
int core_id = -1;
|
||||
int chip_id = -1;
|
||||
int len = 0;
|
||||
char* src_string = NULL;
|
||||
|
||||
_no_of_cores = os::processor_count();
|
||||
_no_of_threads = _no_of_cores;
|
||||
_no_of_sockets = _no_of_cores;
|
||||
snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "AArch64");
|
||||
snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _features_string);
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
int VM_Version_Ext::number_of_threads(void) {
|
||||
initialize_cpu_information();
|
||||
return _no_of_threads;
|
||||
}
|
||||
|
||||
int VM_Version_Ext::number_of_cores(void) {
|
||||
initialize_cpu_information();
|
||||
return _no_of_cores;
|
||||
}
|
||||
|
||||
int VM_Version_Ext::number_of_sockets(void) {
|
||||
initialize_cpu_information();
|
||||
return _no_of_sockets;
|
||||
}
|
||||
|
||||
const char* VM_Version_Ext::cpu_name(void) {
|
||||
initialize_cpu_information();
|
||||
char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_TYPE_DESC_BUF_SIZE, mtTracing);
|
||||
if (NULL == tmp) {
|
||||
return NULL;
|
||||
}
|
||||
strncpy(tmp, _cpu_name, CPU_TYPE_DESC_BUF_SIZE);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const char* VM_Version_Ext::cpu_description(void) {
|
||||
initialize_cpu_information();
|
||||
char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_DETAILED_DESC_BUF_SIZE, mtTracing);
|
||||
if (NULL == tmp) {
|
||||
return NULL;
|
||||
}
|
||||
strncpy(tmp, _cpu_desc, CPU_DETAILED_DESC_BUF_SIZE);
|
||||
return tmp;
|
||||
}
|
54
src/hotspot/cpu/aarch64/vm_version_ext_aarch64.hpp
Normal file
54
src/hotspot/cpu/aarch64/vm_version_ext_aarch64.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_AARCH64_VM_VM_VERSION_EXT_AARCH64_HPP
|
||||
#define CPU_AARCH64_VM_VM_VERSION_EXT_AARCH64_HPP
|
||||
|
||||
#include "utilities/macros.hpp"
|
||||
#include "vm_version_aarch64.hpp"
|
||||
|
||||
class VM_Version_Ext : public VM_Version {
|
||||
private:
|
||||
static const size_t CPU_TYPE_DESC_BUF_SIZE = 256;
|
||||
static const size_t CPU_DETAILED_DESC_BUF_SIZE = 4096;
|
||||
|
||||
static int _no_of_threads;
|
||||
static int _no_of_cores;
|
||||
static int _no_of_sockets;
|
||||
static bool _initialized;
|
||||
static char _cpu_name[CPU_TYPE_DESC_BUF_SIZE];
|
||||
static char _cpu_desc[CPU_DETAILED_DESC_BUF_SIZE];
|
||||
|
||||
public:
|
||||
static int number_of_threads(void);
|
||||
static int number_of_cores(void);
|
||||
static int number_of_sockets(void);
|
||||
|
||||
static const char* cpu_name(void);
|
||||
static const char* cpu_description(void);
|
||||
static void initialize_cpu_information(void);
|
||||
|
||||
};
|
||||
|
||||
#endif // CPU_AARCH64_VM_VM_VERSION_EXT_AARCH64_HPP
|
94
src/hotspot/cpu/arm/vm_version_ext_arm.cpp
Normal file
94
src/hotspot/cpu/arm/vm_version_ext_arm.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "runtime/os.inline.hpp"
|
||||
#include "vm_version_ext_arm.hpp"
|
||||
|
||||
// VM_Version_Ext statics
|
||||
int VM_Version_Ext::_no_of_threads = 0;
|
||||
int VM_Version_Ext::_no_of_cores = 0;
|
||||
int VM_Version_Ext::_no_of_sockets = 0;
|
||||
bool VM_Version_Ext::_initialized = false;
|
||||
char VM_Version_Ext::_cpu_name[CPU_TYPE_DESC_BUF_SIZE] = {0};
|
||||
char VM_Version_Ext::_cpu_desc[CPU_DETAILED_DESC_BUF_SIZE] = {0};
|
||||
|
||||
void VM_Version_Ext::initialize_cpu_information(void) {
|
||||
// do nothing if cpu info has been initialized
|
||||
if (_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
int core_id = -1;
|
||||
int chip_id = -1;
|
||||
int len = 0;
|
||||
char* src_string = NULL;
|
||||
|
||||
_no_of_cores = os::processor_count();
|
||||
_no_of_threads = _no_of_cores;
|
||||
_no_of_sockets = _no_of_cores;
|
||||
#ifdef AARCH64
|
||||
snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "AArch64");
|
||||
#else
|
||||
snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "ARM%d", _arm_arch);
|
||||
#endif
|
||||
snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _features_string);
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
int VM_Version_Ext::number_of_threads(void) {
|
||||
initialize_cpu_information();
|
||||
return _no_of_threads;
|
||||
}
|
||||
|
||||
int VM_Version_Ext::number_of_cores(void) {
|
||||
initialize_cpu_information();
|
||||
return _no_of_cores;
|
||||
}
|
||||
|
||||
int VM_Version_Ext::number_of_sockets(void) {
|
||||
initialize_cpu_information();
|
||||
return _no_of_sockets;
|
||||
}
|
||||
|
||||
const char* VM_Version_Ext::cpu_name(void) {
|
||||
initialize_cpu_information();
|
||||
char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_TYPE_DESC_BUF_SIZE, mtTracing);
|
||||
if (NULL == tmp) {
|
||||
return NULL;
|
||||
}
|
||||
strncpy(tmp, _cpu_name, CPU_TYPE_DESC_BUF_SIZE);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const char* VM_Version_Ext::cpu_description(void) {
|
||||
initialize_cpu_information();
|
||||
char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_DETAILED_DESC_BUF_SIZE, mtTracing);
|
||||
if (NULL == tmp) {
|
||||
return NULL;
|
||||
}
|
||||
strncpy(tmp, _cpu_desc, CPU_DETAILED_DESC_BUF_SIZE);
|
||||
return tmp;
|
||||
}
|
54
src/hotspot/cpu/arm/vm_version_ext_arm.hpp
Normal file
54
src/hotspot/cpu/arm/vm_version_ext_arm.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_ARM_VM_VM_VERSION_EXT_ARM_HPP
|
||||
#define CPU_ARM_VM_VM_VERSION_EXT_ARM_HPP
|
||||
|
||||
#include "utilities/macros.hpp"
|
||||
#include "vm_version_arm.hpp"
|
||||
|
||||
class VM_Version_Ext : public VM_Version {
|
||||
private:
|
||||
static const size_t CPU_TYPE_DESC_BUF_SIZE = 256;
|
||||
static const size_t CPU_DETAILED_DESC_BUF_SIZE = 4096;
|
||||
|
||||
static int _no_of_threads;
|
||||
static int _no_of_cores;
|
||||
static int _no_of_sockets;
|
||||
static bool _initialized;
|
||||
static char _cpu_name[CPU_TYPE_DESC_BUF_SIZE];
|
||||
static char _cpu_desc[CPU_DETAILED_DESC_BUF_SIZE];
|
||||
|
||||
public:
|
||||
static int number_of_threads(void);
|
||||
static int number_of_cores(void);
|
||||
static int number_of_sockets(void);
|
||||
|
||||
static const char* cpu_name(void);
|
||||
static const char* cpu_description(void);
|
||||
static void initialize_cpu_information(void);
|
||||
|
||||
};
|
||||
|
||||
#endif // CPU_ARM_VM_VM_VERSION_EXT_ARM_HPP
|
185
src/hotspot/cpu/sparc/vm_version_ext_sparc.cpp
Normal file
185
src/hotspot/cpu/sparc/vm_version_ext_sparc.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "jvm.h"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "vm_version_ext_sparc.hpp"
|
||||
|
||||
// VM_Version_Ext statics
|
||||
int VM_Version_Ext::_no_of_threads = 0;
|
||||
int VM_Version_Ext::_no_of_cores = 0;
|
||||
int VM_Version_Ext::_no_of_sockets = 0;
|
||||
kid_t VM_Version_Ext::_kcid = -1;
|
||||
char VM_Version_Ext::_cpu_name[CPU_TYPE_DESC_BUF_SIZE] = {0};
|
||||
char VM_Version_Ext::_cpu_desc[CPU_DETAILED_DESC_BUF_SIZE] = {0};
|
||||
|
||||
// get cpu information. It takes into account if the kstat chain id
|
||||
// has been changed and update the info if necessary.
|
||||
bool VM_Version_Ext::initialize_cpu_information(void) {
|
||||
|
||||
int core_id = -1;
|
||||
int chip_id = -1;
|
||||
int len = 0;
|
||||
char* src_string = NULL;
|
||||
kstat_ctl_t* kc = kstat_open();
|
||||
if (!kc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if kstat chain has been updated
|
||||
kid_t kcid = kstat_chain_update(kc);
|
||||
if (kcid == -1) {
|
||||
kstat_close(kc);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool updated = ((kcid > 0) && (kcid != _kcid)) ||
|
||||
((kcid == 0) && (_kcid == -1));
|
||||
if (!updated) {
|
||||
kstat_close(kc);
|
||||
return true;
|
||||
}
|
||||
|
||||
// update the cached _kcid
|
||||
_kcid = kcid;
|
||||
|
||||
// find the number of online processors
|
||||
// for modern processsors, it is also known as the
|
||||
// hardware threads.
|
||||
_no_of_threads = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
|
||||
if (_no_of_threads <= 0 ) {
|
||||
kstat_close(kc);
|
||||
return false;
|
||||
}
|
||||
|
||||
_no_of_cores = 0;
|
||||
_no_of_sockets = 0;
|
||||
|
||||
// loop through the kstat chain
|
||||
kstat_t* ksp = NULL;
|
||||
for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
|
||||
// only interested in "cpu_info"
|
||||
if (strcmp(ksp->ks_module, (char*)CPU_INFO) == 0) {
|
||||
if (kstat_read(kc, ksp, NULL) == -1) {
|
||||
kstat_close(kc);
|
||||
return false;
|
||||
}
|
||||
if (ksp->ks_data != NULL) {
|
||||
kstat_named_t* knm = (kstat_named_t *)ksp->ks_data;
|
||||
// loop through the number of fields in each record
|
||||
for (int i = 0; i < ksp->ks_ndata; i++) {
|
||||
// set cpu type if it hasn't been already set
|
||||
if ((strcmp((const char*)&(knm[i].name), CPU_TYPE) == 0) &&
|
||||
(_cpu_name[0] == '\0')) {
|
||||
if (knm[i].data_type == KSTAT_DATA_STRING) {
|
||||
src_string = (char*)KSTAT_NAMED_STR_PTR(&knm[i]);
|
||||
} else {
|
||||
src_string = (char*)&(knm[i].value.c[0]);
|
||||
}
|
||||
len = strlen(src_string);
|
||||
if (len < CPU_TYPE_DESC_BUF_SIZE) {
|
||||
jio_snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE,
|
||||
"%s", src_string);
|
||||
}
|
||||
}
|
||||
|
||||
// set cpu description if it hasn't been already set
|
||||
if ((strcmp((const char*)&(knm[i].name), CPU_DESCRIPTION) == 0) &&
|
||||
(_cpu_desc[0] == '\0')) {
|
||||
if (knm[i].data_type == KSTAT_DATA_STRING) {
|
||||
src_string = (char*)KSTAT_NAMED_STR_PTR(&knm[i]);
|
||||
} else {
|
||||
src_string = (char*)&(knm[i].value.c[0]);
|
||||
}
|
||||
len = strlen(src_string);
|
||||
if (len < CPU_DETAILED_DESC_BUF_SIZE) {
|
||||
jio_snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE,
|
||||
"%s", src_string);
|
||||
}
|
||||
}
|
||||
|
||||
// count the number of sockets based on the chip id
|
||||
if (strcmp((const char*)&(knm[i].name), CHIP_ID) == 0) {
|
||||
if (chip_id != knm[i].value.l) {
|
||||
chip_id = knm[i].value.l;
|
||||
_no_of_sockets++;
|
||||
}
|
||||
}
|
||||
|
||||
// count the number of cores based on the core id
|
||||
if (strcmp((const char*)&(knm[i].name), CORE_ID) == 0) {
|
||||
if (core_id != knm[i].value.l) {
|
||||
core_id = knm[i].value.l;
|
||||
_no_of_cores++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kstat_close(kc);
|
||||
return true;
|
||||
}
|
||||
|
||||
int VM_Version_Ext::number_of_threads(void) {
|
||||
initialize_cpu_information();
|
||||
return _no_of_threads;
|
||||
}
|
||||
|
||||
int VM_Version_Ext::number_of_cores(void) {
|
||||
initialize_cpu_information();
|
||||
return _no_of_cores;
|
||||
}
|
||||
|
||||
int VM_Version_Ext::number_of_sockets(void) {
|
||||
initialize_cpu_information();
|
||||
return _no_of_sockets;
|
||||
}
|
||||
|
||||
const char* VM_Version_Ext::cpu_name(void) {
|
||||
if (!initialize_cpu_information()) {
|
||||
return NULL;
|
||||
}
|
||||
char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_TYPE_DESC_BUF_SIZE, mtTracing);
|
||||
if (NULL == tmp) {
|
||||
return NULL;
|
||||
}
|
||||
strncpy(tmp, _cpu_name, CPU_TYPE_DESC_BUF_SIZE);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const char* VM_Version_Ext::cpu_description(void) {
|
||||
if (!initialize_cpu_information()) {
|
||||
return NULL;
|
||||
}
|
||||
char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_DETAILED_DESC_BUF_SIZE, mtTracing);
|
||||
if (NULL == tmp) {
|
||||
return NULL;
|
||||
}
|
||||
strncpy(tmp, _cpu_desc, CPU_DETAILED_DESC_BUF_SIZE);
|
||||
return tmp;
|
||||
}
|
64
src/hotspot/cpu/sparc/vm_version_ext_sparc.hpp
Normal file
64
src/hotspot/cpu/sparc/vm_version_ext_sparc.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_SPARC_VM_VM_VERSION_EXT_SPARC_HPP
|
||||
#define CPU_SPARC_VM_VM_VERSION_EXT_SPARC_HPP
|
||||
|
||||
#include "utilities/macros.hpp"
|
||||
#include "vm_version_sparc.hpp"
|
||||
#include <kstat.h>
|
||||
#include <sys/processor.h>
|
||||
|
||||
#define CPU_INFO "cpu_info"
|
||||
#define CPU_TYPE "fpu_type"
|
||||
#define CPU_DESCRIPTION "implementation"
|
||||
#define CHIP_ID "chip_id"
|
||||
#define CORE_ID "core_id"
|
||||
|
||||
class VM_Version_Ext : public VM_Version {
|
||||
private:
|
||||
|
||||
static const size_t CPU_TYPE_DESC_BUF_SIZE = 256;
|
||||
static const size_t CPU_DETAILED_DESC_BUF_SIZE = 4096;
|
||||
|
||||
static int _no_of_threads;
|
||||
static int _no_of_cores;
|
||||
static int _no_of_sockets;
|
||||
static kid_t _kcid;
|
||||
static char _cpu_name[CPU_TYPE_DESC_BUF_SIZE];
|
||||
static char _cpu_desc[CPU_DETAILED_DESC_BUF_SIZE];
|
||||
|
||||
static bool initialize_cpu_information(void);
|
||||
|
||||
public:
|
||||
|
||||
static int number_of_threads(void);
|
||||
static int number_of_cores(void);
|
||||
static int number_of_sockets(void);
|
||||
|
||||
static const char* cpu_name(void);
|
||||
static const char* cpu_description(void);
|
||||
};
|
||||
|
||||
#endif // CPU_SPARC_VM_VM_VERSION_EXT_SPARC_HPP
|
210
src/hotspot/cpu/x86/rdtsc_x86.cpp
Normal file
210
src/hotspot/cpu/x86/rdtsc_x86.cpp
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "rdtsc_x86.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "vm_version_ext_x86.hpp"
|
||||
|
||||
// The following header contains the implementations of rdtsc()
|
||||
#include OS_CPU_HEADER_INLINE(os)
|
||||
|
||||
static jlong _epoch = 0;
|
||||
static bool rdtsc_elapsed_counter_enabled = false;
|
||||
static jlong tsc_frequency = 0;
|
||||
|
||||
static jlong set_epoch() {
|
||||
assert(0 == _epoch, "invariant");
|
||||
_epoch = os::rdtsc();
|
||||
return _epoch;
|
||||
}
|
||||
|
||||
// Base loop to estimate ticks frequency for tsc counter from user mode.
|
||||
// Volatiles and sleep() are used to prevent compiler from applying optimizations.
|
||||
static void do_time_measurements(volatile jlong& time_base,
|
||||
volatile jlong& time_fast,
|
||||
volatile jlong& time_base_elapsed,
|
||||
volatile jlong& time_fast_elapsed) {
|
||||
static const unsigned int FT_SLEEP_MILLISECS = 1;
|
||||
const unsigned int loopcount = 3;
|
||||
|
||||
volatile jlong start = 0;
|
||||
volatile jlong fstart = 0;
|
||||
volatile jlong end = 0;
|
||||
volatile jlong fend = 0;
|
||||
|
||||
// Figure out the difference between rdtsc and os provided timer.
|
||||
// base algorithm adopted from JRockit.
|
||||
for (unsigned int times = 0; times < loopcount; times++) {
|
||||
start = os::elapsed_counter();
|
||||
OrderAccess::fence();
|
||||
fstart = os::rdtsc();
|
||||
|
||||
// use sleep to prevent compiler from optimizing
|
||||
os::sleep(Thread::current(), FT_SLEEP_MILLISECS, true);
|
||||
|
||||
end = os::elapsed_counter();
|
||||
OrderAccess::fence();
|
||||
fend = os::rdtsc();
|
||||
|
||||
time_base += end - start;
|
||||
time_fast += fend - fstart;
|
||||
|
||||
// basis for calculating the os tick start
|
||||
// to fast time tick start offset
|
||||
time_base_elapsed += end;
|
||||
time_fast_elapsed += (fend - _epoch);
|
||||
}
|
||||
|
||||
time_base /= loopcount;
|
||||
time_fast /= loopcount;
|
||||
time_base_elapsed /= loopcount;
|
||||
time_fast_elapsed /= loopcount;
|
||||
}
|
||||
|
||||
static jlong initialize_frequency() {
|
||||
assert(0 == tsc_frequency, "invariant");
|
||||
assert(0 == _epoch, "invariant");
|
||||
const jlong initial_counter = set_epoch();
|
||||
if (initial_counter == 0) {
|
||||
return 0;
|
||||
}
|
||||
// os time frequency
|
||||
static double os_freq = (double)os::elapsed_frequency();
|
||||
assert(os_freq > 0, "os_elapsed frequency corruption!");
|
||||
|
||||
double tsc_freq = .0;
|
||||
double os_to_tsc_conv_factor = 1.0;
|
||||
|
||||
// if platform supports invariant tsc,
|
||||
// apply higher resolution and granularity for conversion calculations
|
||||
if (VM_Version_Ext::supports_tscinv_ext()) {
|
||||
// for invariant tsc platforms, take the maximum qualified cpu frequency
|
||||
tsc_freq = (double)VM_Version_Ext::maximum_qualified_cpu_frequency();
|
||||
os_to_tsc_conv_factor = tsc_freq / os_freq;
|
||||
} else {
|
||||
// use measurements to estimate
|
||||
// a conversion factor and the tsc frequency
|
||||
|
||||
volatile jlong time_base = 0;
|
||||
volatile jlong time_fast = 0;
|
||||
volatile jlong time_base_elapsed = 0;
|
||||
volatile jlong time_fast_elapsed = 0;
|
||||
|
||||
// do measurements to get base data
|
||||
// on os timer and fast ticks tsc time relation.
|
||||
do_time_measurements(time_base, time_fast, time_base_elapsed, time_fast_elapsed);
|
||||
|
||||
// if invalid measurements, cannot proceed
|
||||
if (time_fast == 0 || time_base == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
os_to_tsc_conv_factor = (double)time_fast / (double)time_base;
|
||||
if (os_to_tsc_conv_factor > 1) {
|
||||
// estimate on tsc counter frequency
|
||||
tsc_freq = os_to_tsc_conv_factor * os_freq;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tsc_freq < 0) || (tsc_freq > 0 && tsc_freq <= os_freq) || (os_to_tsc_conv_factor <= 1)) {
|
||||
// safer to run with normal os time
|
||||
tsc_freq = .0;
|
||||
}
|
||||
|
||||
// frequency of the tsc_counter
|
||||
return (jlong)tsc_freq;
|
||||
}
|
||||
|
||||
static bool initialize_elapsed_counter() {
|
||||
tsc_frequency = initialize_frequency();
|
||||
return tsc_frequency != 0 && _epoch != 0;
|
||||
}
|
||||
|
||||
static bool ergonomics() {
|
||||
const bool invtsc_support = Rdtsc::is_supported();
|
||||
if (FLAG_IS_DEFAULT(UseFastUnorderedTimeStamps) && invtsc_support) {
|
||||
FLAG_SET_ERGO(bool, UseFastUnorderedTimeStamps, true);
|
||||
}
|
||||
|
||||
bool ft_enabled = UseFastUnorderedTimeStamps && invtsc_support;
|
||||
|
||||
if (!ft_enabled) {
|
||||
if (UseFastUnorderedTimeStamps && VM_Version::supports_tsc()) {
|
||||
warning("\nThe hardware does not support invariant tsc (INVTSC) register and/or cannot guarantee tsc synchronization between sockets at startup.\n"\
|
||||
"Values returned via rdtsc() are not guaranteed to be accurate, esp. when comparing values from cross sockets reads. Enabling UseFastUnorderedTimeStamps on non-invariant tsc hardware should be considered experimental.\n");
|
||||
ft_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ft_enabled) {
|
||||
// Warn if unable to support command-line flag
|
||||
if (UseFastUnorderedTimeStamps && !VM_Version::supports_tsc()) {
|
||||
warning("Ignoring UseFastUnorderedTimeStamps, hardware does not support normal tsc");
|
||||
}
|
||||
}
|
||||
|
||||
return ft_enabled;
|
||||
}
|
||||
|
||||
bool Rdtsc::is_supported() {
|
||||
return VM_Version_Ext::supports_tscinv_ext();
|
||||
}
|
||||
|
||||
bool Rdtsc::is_elapsed_counter_enabled() {
|
||||
return rdtsc_elapsed_counter_enabled;
|
||||
}
|
||||
|
||||
jlong Rdtsc::frequency() {
|
||||
return tsc_frequency;
|
||||
}
|
||||
|
||||
jlong Rdtsc::elapsed_counter() {
|
||||
return os::rdtsc() - _epoch;
|
||||
}
|
||||
|
||||
jlong Rdtsc::epoch() {
|
||||
return _epoch;
|
||||
}
|
||||
|
||||
jlong Rdtsc::raw() {
|
||||
return os::rdtsc();
|
||||
}
|
||||
|
||||
bool Rdtsc::initialize() {
|
||||
static bool initialized = false;
|
||||
if (!initialized) {
|
||||
assert(!rdtsc_elapsed_counter_enabled, "invariant");
|
||||
VM_Version_Ext::initialize();
|
||||
assert(0 == tsc_frequency, "invariant");
|
||||
assert(0 == _epoch, "invariant");
|
||||
bool result = initialize_elapsed_counter(); // init hw
|
||||
if (result) {
|
||||
result = ergonomics(); // check logical state
|
||||
}
|
||||
rdtsc_elapsed_counter_enabled = result;
|
||||
initialized = true;
|
||||
}
|
||||
return rdtsc_elapsed_counter_enabled;
|
||||
}
|
50
src/hotspot/cpu/x86/rdtsc_x86.hpp
Normal file
50
src/hotspot/cpu/x86/rdtsc_x86.hpp
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_X86_VM_RDTSC_X86_HPP
|
||||
#define CPU_X86_VM_RDTSC_X86_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
// Interface to the x86 rdtsc() time counter, if available.
|
||||
// Not guaranteed to be synchronized across hardware threads and
|
||||
// therefore software threads, and can be updated asynchronously
|
||||
// by software. elapsed_counter() can jump backwards
|
||||
// as well as jump forward when threads query different cores/sockets.
|
||||
// Very much not recommended for general use.
|
||||
// INVTSC is a minimal requirement for auto-enablement.
|
||||
|
||||
class Rdtsc : AllStatic {
|
||||
public:
|
||||
static jlong elapsed_counter(); // provides quick time stamps
|
||||
static jlong frequency(); // tsc register
|
||||
static bool is_supported(); // InvariantTSC
|
||||
static jlong raw(); // direct rdtsc() access
|
||||
static bool is_elapsed_counter_enabled(); // turn off with -XX:-UseFastUnorderedTimeStamps
|
||||
static jlong epoch();
|
||||
static bool initialize();
|
||||
};
|
||||
|
||||
#endif // CPU_X86_VM_RDTSC_X86_HPP
|
967
src/hotspot/cpu/x86/vm_version_ext_x86.cpp
Normal file
967
src/hotspot/cpu/x86/vm_version_ext_x86.cpp
Normal file
@ -0,0 +1,967 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "jvm.h"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/stubCodeGenerator.hpp"
|
||||
#include "vm_version_ext_x86.hpp"
|
||||
|
||||
typedef enum {
|
||||
CPU_FAMILY_8086_8088 = 0,
|
||||
CPU_FAMILY_INTEL_286 = 2,
|
||||
CPU_FAMILY_INTEL_386 = 3,
|
||||
CPU_FAMILY_INTEL_486 = 4,
|
||||
CPU_FAMILY_PENTIUM = 5,
|
||||
CPU_FAMILY_PENTIUMPRO = 6, // Same family several models
|
||||
CPU_FAMILY_PENTIUM_4 = 0xF
|
||||
} FamilyFlag;
|
||||
|
||||
typedef enum {
|
||||
RDTSCP_FLAG = 0x08000000, // bit 27
|
||||
INTEL64_FLAG = 0x20000000 // bit 29
|
||||
} _featureExtendedEdxFlag;
|
||||
|
||||
#define CPUID_STANDARD_FN 0x0
|
||||
#define CPUID_STANDARD_FN_1 0x1
|
||||
#define CPUID_STANDARD_FN_4 0x4
|
||||
#define CPUID_STANDARD_FN_B 0xb
|
||||
|
||||
#define CPUID_EXTENDED_FN 0x80000000
|
||||
#define CPUID_EXTENDED_FN_1 0x80000001
|
||||
#define CPUID_EXTENDED_FN_2 0x80000002
|
||||
#define CPUID_EXTENDED_FN_3 0x80000003
|
||||
#define CPUID_EXTENDED_FN_4 0x80000004
|
||||
#define CPUID_EXTENDED_FN_7 0x80000007
|
||||
#define CPUID_EXTENDED_FN_8 0x80000008
|
||||
|
||||
typedef enum {
|
||||
FPU_FLAG = 0x00000001,
|
||||
VME_FLAG = 0x00000002,
|
||||
DE_FLAG = 0x00000004,
|
||||
PSE_FLAG = 0x00000008,
|
||||
TSC_FLAG = 0x00000010,
|
||||
MSR_FLAG = 0x00000020,
|
||||
PAE_FLAG = 0x00000040,
|
||||
MCE_FLAG = 0x00000080,
|
||||
CX8_FLAG = 0x00000100,
|
||||
APIC_FLAG = 0x00000200,
|
||||
SEP_FLAG = 0x00000800,
|
||||
MTRR_FLAG = 0x00001000,
|
||||
PGE_FLAG = 0x00002000,
|
||||
MCA_FLAG = 0x00004000,
|
||||
CMOV_FLAG = 0x00008000,
|
||||
PAT_FLAG = 0x00010000,
|
||||
PSE36_FLAG = 0x00020000,
|
||||
PSNUM_FLAG = 0x00040000,
|
||||
CLFLUSH_FLAG = 0x00080000,
|
||||
DTS_FLAG = 0x00200000,
|
||||
ACPI_FLAG = 0x00400000,
|
||||
MMX_FLAG = 0x00800000,
|
||||
FXSR_FLAG = 0x01000000,
|
||||
SSE_FLAG = 0x02000000,
|
||||
SSE2_FLAG = 0x04000000,
|
||||
SS_FLAG = 0x08000000,
|
||||
HTT_FLAG = 0x10000000,
|
||||
TM_FLAG = 0x20000000
|
||||
} FeatureEdxFlag;
|
||||
|
||||
static BufferBlob* cpuid_brand_string_stub_blob;
|
||||
static const int cpuid_brand_string_stub_size = 550;
|
||||
|
||||
extern "C" {
|
||||
typedef void (*getCPUIDBrandString_stub_t)(void*);
|
||||
}
|
||||
|
||||
static getCPUIDBrandString_stub_t getCPUIDBrandString_stub = NULL;
|
||||
|
||||
class VM_Version_Ext_StubGenerator: public StubCodeGenerator {
|
||||
public:
|
||||
|
||||
VM_Version_Ext_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
|
||||
|
||||
address generate_getCPUIDBrandString(void) {
|
||||
// Flags to test CPU type.
|
||||
const uint32_t HS_EFL_AC = 0x40000;
|
||||
const uint32_t HS_EFL_ID = 0x200000;
|
||||
// Values for when we don't have a CPUID instruction.
|
||||
const int CPU_FAMILY_SHIFT = 8;
|
||||
const uint32_t CPU_FAMILY_386 = (3 << CPU_FAMILY_SHIFT);
|
||||
const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT);
|
||||
|
||||
Label detect_486, cpu486, detect_586, done, ext_cpuid;
|
||||
|
||||
StubCodeMark mark(this, "VM_Version_Ext", "getCPUIDNameInfo_stub");
|
||||
# define __ _masm->
|
||||
|
||||
address start = __ pc();
|
||||
|
||||
//
|
||||
// void getCPUIDBrandString(VM_Version::CpuidInfo* cpuid_info);
|
||||
//
|
||||
// LP64: rcx and rdx are first and second argument registers on windows
|
||||
|
||||
__ push(rbp);
|
||||
#ifdef _LP64
|
||||
__ mov(rbp, c_rarg0); // cpuid_info address
|
||||
#else
|
||||
__ movptr(rbp, Address(rsp, 8)); // cpuid_info address
|
||||
#endif
|
||||
__ push(rbx);
|
||||
__ push(rsi);
|
||||
__ pushf(); // preserve rbx, and flags
|
||||
__ pop(rax);
|
||||
__ push(rax);
|
||||
__ mov(rcx, rax);
|
||||
//
|
||||
// if we are unable to change the AC flag, we have a 386
|
||||
//
|
||||
__ xorl(rax, HS_EFL_AC);
|
||||
__ push(rax);
|
||||
__ popf();
|
||||
__ pushf();
|
||||
__ pop(rax);
|
||||
__ cmpptr(rax, rcx);
|
||||
__ jccb(Assembler::notEqual, detect_486);
|
||||
|
||||
__ movl(rax, CPU_FAMILY_386);
|
||||
__ jmp(done);
|
||||
|
||||
//
|
||||
// If we are unable to change the ID flag, we have a 486 which does
|
||||
// not support the "cpuid" instruction.
|
||||
//
|
||||
__ bind(detect_486);
|
||||
__ mov(rax, rcx);
|
||||
__ xorl(rax, HS_EFL_ID);
|
||||
__ push(rax);
|
||||
__ popf();
|
||||
__ pushf();
|
||||
__ pop(rax);
|
||||
__ cmpptr(rcx, rax);
|
||||
__ jccb(Assembler::notEqual, detect_586);
|
||||
|
||||
__ bind(cpu486);
|
||||
__ movl(rax, CPU_FAMILY_486);
|
||||
__ jmp(done);
|
||||
|
||||
//
|
||||
// At this point, we have a chip which supports the "cpuid" instruction
|
||||
//
|
||||
__ bind(detect_586);
|
||||
__ xorl(rax, rax);
|
||||
__ cpuid();
|
||||
__ orl(rax, rax);
|
||||
__ jcc(Assembler::equal, cpu486); // if cpuid doesn't support an input
|
||||
// value of at least 1, we give up and
|
||||
// assume a 486
|
||||
|
||||
//
|
||||
// Extended cpuid(0x80000000) for processor brand string detection
|
||||
//
|
||||
__ bind(ext_cpuid);
|
||||
__ movl(rax, CPUID_EXTENDED_FN);
|
||||
__ cpuid();
|
||||
__ cmpl(rax, CPUID_EXTENDED_FN_4);
|
||||
__ jcc(Assembler::below, done);
|
||||
|
||||
//
|
||||
// Extended cpuid(0x80000002) // first 16 bytes in brand string
|
||||
//
|
||||
__ movl(rax, CPUID_EXTENDED_FN_2);
|
||||
__ cpuid();
|
||||
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_0_offset())));
|
||||
__ movl(Address(rsi, 0), rax);
|
||||
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_1_offset())));
|
||||
__ movl(Address(rsi, 0), rbx);
|
||||
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_2_offset())));
|
||||
__ movl(Address(rsi, 0), rcx);
|
||||
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_3_offset())));
|
||||
__ movl(Address(rsi,0), rdx);
|
||||
|
||||
//
|
||||
// Extended cpuid(0x80000003) // next 16 bytes in brand string
|
||||
//
|
||||
__ movl(rax, CPUID_EXTENDED_FN_3);
|
||||
__ cpuid();
|
||||
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_4_offset())));
|
||||
__ movl(Address(rsi, 0), rax);
|
||||
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_5_offset())));
|
||||
__ movl(Address(rsi, 0), rbx);
|
||||
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_6_offset())));
|
||||
__ movl(Address(rsi, 0), rcx);
|
||||
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_7_offset())));
|
||||
__ movl(Address(rsi,0), rdx);
|
||||
|
||||
//
|
||||
// Extended cpuid(0x80000004) // last 16 bytes in brand string
|
||||
//
|
||||
__ movl(rax, CPUID_EXTENDED_FN_4);
|
||||
__ cpuid();
|
||||
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_8_offset())));
|
||||
__ movl(Address(rsi, 0), rax);
|
||||
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_9_offset())));
|
||||
__ movl(Address(rsi, 0), rbx);
|
||||
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_10_offset())));
|
||||
__ movl(Address(rsi, 0), rcx);
|
||||
__ lea(rsi, Address(rbp, in_bytes(VM_Version_Ext::proc_name_11_offset())));
|
||||
__ movl(Address(rsi,0), rdx);
|
||||
|
||||
//
|
||||
// return
|
||||
//
|
||||
__ bind(done);
|
||||
__ popf();
|
||||
__ pop(rsi);
|
||||
__ pop(rbx);
|
||||
__ pop(rbp);
|
||||
__ ret(0);
|
||||
|
||||
# undef __
|
||||
|
||||
return start;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// VM_Version_Ext statics
|
||||
const size_t VM_Version_Ext::VENDOR_LENGTH = 13;
|
||||
const size_t VM_Version_Ext::CPU_EBS_MAX_LENGTH = (3 * 4 * 4 + 1);
|
||||
const size_t VM_Version_Ext::CPU_TYPE_DESC_BUF_SIZE = 256;
|
||||
const size_t VM_Version_Ext::CPU_DETAILED_DESC_BUF_SIZE = 4096;
|
||||
char* VM_Version_Ext::_cpu_brand_string = NULL;
|
||||
jlong VM_Version_Ext::_max_qualified_cpu_frequency = 0;
|
||||
|
||||
int VM_Version_Ext::_no_of_threads = 0;
|
||||
int VM_Version_Ext::_no_of_cores = 0;
|
||||
int VM_Version_Ext::_no_of_packages = 0;
|
||||
|
||||
void VM_Version_Ext::initialize(void) {
|
||||
ResourceMark rm;
|
||||
|
||||
cpuid_brand_string_stub_blob = BufferBlob::create("getCPUIDBrandString_stub", cpuid_brand_string_stub_size);
|
||||
if (cpuid_brand_string_stub_blob == NULL) {
|
||||
vm_exit_during_initialization("Unable to allocate getCPUIDBrandString_stub");
|
||||
}
|
||||
CodeBuffer c(cpuid_brand_string_stub_blob);
|
||||
VM_Version_Ext_StubGenerator g(&c);
|
||||
getCPUIDBrandString_stub = CAST_TO_FN_PTR(getCPUIDBrandString_stub_t,
|
||||
g.generate_getCPUIDBrandString());
|
||||
}
|
||||
|
||||
const char* VM_Version_Ext::cpu_model_description(void) {
|
||||
uint32_t cpu_family = extended_cpu_family();
|
||||
uint32_t cpu_model = extended_cpu_model();
|
||||
const char* model = NULL;
|
||||
|
||||
if (cpu_family == CPU_FAMILY_PENTIUMPRO) {
|
||||
for (uint32_t i = 0; i <= cpu_model; i++) {
|
||||
model = _model_id_pentium_pro[i];
|
||||
if (model == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
const char* VM_Version_Ext::cpu_brand_string(void) {
|
||||
if (_cpu_brand_string == NULL) {
|
||||
_cpu_brand_string = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_EBS_MAX_LENGTH, mtInternal);
|
||||
if (NULL == _cpu_brand_string) {
|
||||
return NULL;
|
||||
}
|
||||
int ret_val = cpu_extended_brand_string(_cpu_brand_string, CPU_EBS_MAX_LENGTH);
|
||||
if (ret_val != OS_OK) {
|
||||
FREE_C_HEAP_ARRAY(char, _cpu_brand_string);
|
||||
_cpu_brand_string = NULL;
|
||||
}
|
||||
}
|
||||
return _cpu_brand_string;
|
||||
}
|
||||
|
||||
const char* VM_Version_Ext::cpu_brand(void) {
|
||||
const char* brand = NULL;
|
||||
|
||||
if ((_cpuid_info.std_cpuid1_ebx.value & 0xFF) > 0) {
|
||||
int brand_num = _cpuid_info.std_cpuid1_ebx.value & 0xFF;
|
||||
brand = _brand_id[0];
|
||||
for (int i = 0; brand != NULL && i <= brand_num; i += 1) {
|
||||
brand = _brand_id[i];
|
||||
}
|
||||
}
|
||||
return brand;
|
||||
}
|
||||
|
||||
bool VM_Version_Ext::cpu_is_em64t(void) {
|
||||
return ((_cpuid_info.ext_cpuid1_edx.value & INTEL64_FLAG) == INTEL64_FLAG);
|
||||
}
|
||||
|
||||
bool VM_Version_Ext::is_netburst(void) {
|
||||
return (is_intel() && (extended_cpu_family() == CPU_FAMILY_PENTIUM_4));
|
||||
}
|
||||
|
||||
bool VM_Version_Ext::supports_tscinv_ext(void) {
|
||||
if (!supports_tscinv_bit()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_intel()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_amd()) {
|
||||
return !is_amd_Barcelona();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void VM_Version_Ext::resolve_cpu_information_details(void) {
|
||||
|
||||
// in future we want to base this information on proper cpu
|
||||
// and cache topology enumeration such as:
|
||||
// Intel 64 Architecture Processor Topology Enumeration
|
||||
// which supports system cpu and cache topology enumeration
|
||||
// either using 2xAPICIDs or initial APICIDs
|
||||
|
||||
// currently only rough cpu information estimates
|
||||
// which will not necessarily reflect the exact configuration of the system
|
||||
|
||||
// this is the number of logical hardware threads
|
||||
// visible to the operating system
|
||||
_no_of_threads = os::processor_count();
|
||||
|
||||
// find out number of threads per cpu package
|
||||
int threads_per_package = threads_per_core() * cores_per_cpu();
|
||||
|
||||
// use amount of threads visible to the process in order to guess number of sockets
|
||||
_no_of_packages = _no_of_threads / threads_per_package;
|
||||
|
||||
// process might only see a subset of the total number of threads
|
||||
// from a single processor package. Virtualization/resource management for example.
|
||||
// If so then just write a hard 1 as num of pkgs.
|
||||
if (0 == _no_of_packages) {
|
||||
_no_of_packages = 1;
|
||||
}
|
||||
|
||||
// estimate the number of cores
|
||||
_no_of_cores = cores_per_cpu() * _no_of_packages;
|
||||
}
|
||||
|
||||
int VM_Version_Ext::number_of_threads(void) {
|
||||
if (_no_of_threads == 0) {
|
||||
resolve_cpu_information_details();
|
||||
}
|
||||
return _no_of_threads;
|
||||
}
|
||||
|
||||
int VM_Version_Ext::number_of_cores(void) {
|
||||
if (_no_of_cores == 0) {
|
||||
resolve_cpu_information_details();
|
||||
}
|
||||
return _no_of_cores;
|
||||
}
|
||||
|
||||
int VM_Version_Ext::number_of_sockets(void) {
|
||||
if (_no_of_packages == 0) {
|
||||
resolve_cpu_information_details();
|
||||
}
|
||||
return _no_of_packages;
|
||||
}
|
||||
|
||||
const char* VM_Version_Ext::cpu_family_description(void) {
|
||||
int cpu_family_id = extended_cpu_family();
|
||||
if (is_amd()) {
|
||||
return _family_id_amd[cpu_family_id];
|
||||
}
|
||||
if (is_intel()) {
|
||||
if (cpu_family_id == CPU_FAMILY_PENTIUMPRO) {
|
||||
return cpu_model_description();
|
||||
}
|
||||
return _family_id_intel[cpu_family_id];
|
||||
}
|
||||
return "Unknown x86";
|
||||
}
|
||||
|
||||
int VM_Version_Ext::cpu_type_description(char* const buf, size_t buf_len) {
|
||||
assert(buf != NULL, "buffer is NULL!");
|
||||
assert(buf_len >= CPU_TYPE_DESC_BUF_SIZE, "buffer len should at least be == CPU_TYPE_DESC_BUF_SIZE!");
|
||||
|
||||
const char* cpu_type = NULL;
|
||||
const char* x64 = NULL;
|
||||
|
||||
if (is_intel()) {
|
||||
cpu_type = "Intel";
|
||||
x64 = cpu_is_em64t() ? " Intel64" : "";
|
||||
} else if (is_amd()) {
|
||||
cpu_type = "AMD";
|
||||
x64 = cpu_is_em64t() ? " AMD64" : "";
|
||||
} else {
|
||||
cpu_type = "Unknown x86";
|
||||
x64 = cpu_is_em64t() ? " x86_64" : "";
|
||||
}
|
||||
|
||||
jio_snprintf(buf, buf_len, "%s %s%s SSE SSE2%s%s%s%s%s%s%s%s",
|
||||
cpu_type,
|
||||
cpu_family_description(),
|
||||
supports_ht() ? " (HT)" : "",
|
||||
supports_sse3() ? " SSE3" : "",
|
||||
supports_ssse3() ? " SSSE3" : "",
|
||||
supports_sse4_1() ? " SSE4.1" : "",
|
||||
supports_sse4_2() ? " SSE4.2" : "",
|
||||
supports_sse4a() ? " SSE4A" : "",
|
||||
is_netburst() ? " Netburst" : "",
|
||||
is_intel_family_core() ? " Core" : "",
|
||||
x64);
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
int VM_Version_Ext::cpu_extended_brand_string(char* const buf, size_t buf_len) {
|
||||
assert(buf != NULL, "buffer is NULL!");
|
||||
assert(buf_len >= CPU_EBS_MAX_LENGTH, "buffer len should at least be == CPU_EBS_MAX_LENGTH!");
|
||||
assert(getCPUIDBrandString_stub != NULL, "not initialized");
|
||||
|
||||
// invoke newly generated asm code to fetch CPU Brand String
|
||||
getCPUIDBrandString_stub(&_cpuid_info);
|
||||
|
||||
// fetch results into buffer
|
||||
*((uint32_t*) &buf[0]) = _cpuid_info.proc_name_0;
|
||||
*((uint32_t*) &buf[4]) = _cpuid_info.proc_name_1;
|
||||
*((uint32_t*) &buf[8]) = _cpuid_info.proc_name_2;
|
||||
*((uint32_t*) &buf[12]) = _cpuid_info.proc_name_3;
|
||||
*((uint32_t*) &buf[16]) = _cpuid_info.proc_name_4;
|
||||
*((uint32_t*) &buf[20]) = _cpuid_info.proc_name_5;
|
||||
*((uint32_t*) &buf[24]) = _cpuid_info.proc_name_6;
|
||||
*((uint32_t*) &buf[28]) = _cpuid_info.proc_name_7;
|
||||
*((uint32_t*) &buf[32]) = _cpuid_info.proc_name_8;
|
||||
*((uint32_t*) &buf[36]) = _cpuid_info.proc_name_9;
|
||||
*((uint32_t*) &buf[40]) = _cpuid_info.proc_name_10;
|
||||
*((uint32_t*) &buf[44]) = _cpuid_info.proc_name_11;
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
size_t VM_Version_Ext::cpu_write_support_string(char* const buf, size_t buf_len) {
|
||||
assert(buf != NULL, "buffer is NULL!");
|
||||
assert(buf_len > 0, "buffer len not enough!");
|
||||
|
||||
unsigned int flag = 0;
|
||||
unsigned int fi = 0;
|
||||
size_t written = 0;
|
||||
const char* prefix = "";
|
||||
|
||||
#define WRITE_TO_BUF(string) \
|
||||
{ \
|
||||
int res = jio_snprintf(&buf[written], buf_len - written, "%s%s", prefix, string); \
|
||||
if (res < 0 || (size_t) res >= buf_len - 1) { \
|
||||
buf[buf_len-1] = '\0'; \
|
||||
return buf_len - 1; \
|
||||
} \
|
||||
written += res; \
|
||||
if (prefix[0] == '\0') { \
|
||||
prefix = ", "; \
|
||||
} \
|
||||
}
|
||||
|
||||
for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) {
|
||||
if (flag == HTT_FLAG && (((_cpuid_info.std_cpuid1_ebx.value >> 16) & 0xff) <= 1)) {
|
||||
continue; /* no hyperthreading */
|
||||
} else if (flag == SEP_FLAG && (cpu_family() == CPU_FAMILY_PENTIUMPRO && ((_cpuid_info.std_cpuid1_eax.value & 0xff) < 0x33))) {
|
||||
continue; /* no fast system call */
|
||||
}
|
||||
if ((_cpuid_info.std_cpuid1_edx.value & flag) && strlen(_feature_edx_id[fi]) > 0) {
|
||||
WRITE_TO_BUF(_feature_edx_id[fi]);
|
||||
}
|
||||
}
|
||||
|
||||
for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) {
|
||||
if ((_cpuid_info.std_cpuid1_ecx.value & flag) && strlen(_feature_ecx_id[fi]) > 0) {
|
||||
WRITE_TO_BUF(_feature_ecx_id[fi]);
|
||||
}
|
||||
}
|
||||
|
||||
for (flag = 1, fi = 0; flag <= 0x20000000 ; flag <<= 1, fi++) {
|
||||
if ((_cpuid_info.ext_cpuid1_ecx.value & flag) && strlen(_feature_extended_ecx_id[fi]) > 0) {
|
||||
WRITE_TO_BUF(_feature_extended_ecx_id[fi]);
|
||||
}
|
||||
}
|
||||
|
||||
for (flag = 1, fi = 0; flag <= 0x20000000; flag <<= 1, fi++) {
|
||||
if ((_cpuid_info.ext_cpuid1_edx.value & flag) && strlen(_feature_extended_edx_id[fi]) > 0) {
|
||||
WRITE_TO_BUF(_feature_extended_edx_id[fi]);
|
||||
}
|
||||
}
|
||||
|
||||
if (supports_tscinv_bit()) {
|
||||
WRITE_TO_BUF("Invariant TSC");
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a detailed description of the cpu to a given buffer, including
|
||||
* feature set.
|
||||
*/
|
||||
int VM_Version_Ext::cpu_detailed_description(char* const buf, size_t buf_len) {
|
||||
assert(buf != NULL, "buffer is NULL!");
|
||||
assert(buf_len >= CPU_DETAILED_DESC_BUF_SIZE, "buffer len should at least be == CPU_DETAILED_DESC_BUF_SIZE!");
|
||||
|
||||
static const char* unknown = "<unknown>";
|
||||
char vendor_id[VENDOR_LENGTH];
|
||||
const char* family = NULL;
|
||||
const char* model = NULL;
|
||||
const char* brand = NULL;
|
||||
int outputLen = 0;
|
||||
|
||||
family = cpu_family_description();
|
||||
if (family == NULL) {
|
||||
family = unknown;
|
||||
}
|
||||
|
||||
model = cpu_model_description();
|
||||
if (model == NULL) {
|
||||
model = unknown;
|
||||
}
|
||||
|
||||
brand = cpu_brand_string();
|
||||
|
||||
if (brand == NULL) {
|
||||
brand = cpu_brand();
|
||||
if (brand == NULL) {
|
||||
brand = unknown;
|
||||
}
|
||||
}
|
||||
|
||||
*((uint32_t*) &vendor_id[0]) = _cpuid_info.std_vendor_name_0;
|
||||
*((uint32_t*) &vendor_id[4]) = _cpuid_info.std_vendor_name_2;
|
||||
*((uint32_t*) &vendor_id[8]) = _cpuid_info.std_vendor_name_1;
|
||||
vendor_id[VENDOR_LENGTH-1] = '\0';
|
||||
|
||||
outputLen = jio_snprintf(buf, buf_len, "Brand: %s, Vendor: %s\n"
|
||||
"Family: %s (0x%x), Model: %s (0x%x), Stepping: 0x%x\n"
|
||||
"Ext. family: 0x%x, Ext. model: 0x%x, Type: 0x%x, Signature: 0x%8.8x\n"
|
||||
"Features: ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n"
|
||||
"Ext. features: eax: 0x%8.8x, ebx: 0x%8.8x, ecx: 0x%8.8x, edx: 0x%8.8x\n"
|
||||
"Supports: ",
|
||||
brand,
|
||||
vendor_id,
|
||||
family,
|
||||
extended_cpu_family(),
|
||||
model,
|
||||
extended_cpu_model(),
|
||||
cpu_stepping(),
|
||||
_cpuid_info.std_cpuid1_eax.bits.ext_family,
|
||||
_cpuid_info.std_cpuid1_eax.bits.ext_model,
|
||||
_cpuid_info.std_cpuid1_eax.bits.proc_type,
|
||||
_cpuid_info.std_cpuid1_eax.value,
|
||||
_cpuid_info.std_cpuid1_ebx.value,
|
||||
_cpuid_info.std_cpuid1_ecx.value,
|
||||
_cpuid_info.std_cpuid1_edx.value,
|
||||
_cpuid_info.ext_cpuid1_eax,
|
||||
_cpuid_info.ext_cpuid1_ebx,
|
||||
_cpuid_info.ext_cpuid1_ecx,
|
||||
_cpuid_info.ext_cpuid1_edx);
|
||||
|
||||
if (outputLen < 0 || (size_t) outputLen >= buf_len - 1) {
|
||||
buf[buf_len-1] = '\0';
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
cpu_write_support_string(&buf[outputLen], buf_len - outputLen);
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
const char* VM_Version_Ext::cpu_name(void) {
|
||||
char cpu_type_desc[CPU_TYPE_DESC_BUF_SIZE];
|
||||
size_t cpu_desc_len = sizeof(cpu_type_desc);
|
||||
|
||||
cpu_type_description(cpu_type_desc, cpu_desc_len);
|
||||
char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, cpu_desc_len, mtTracing);
|
||||
if (NULL == tmp) {
|
||||
return NULL;
|
||||
}
|
||||
strncpy(tmp, cpu_type_desc, cpu_desc_len);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const char* VM_Version_Ext::cpu_description(void) {
|
||||
char cpu_detailed_desc_buffer[CPU_DETAILED_DESC_BUF_SIZE];
|
||||
size_t cpu_detailed_desc_len = sizeof(cpu_detailed_desc_buffer);
|
||||
|
||||
cpu_detailed_description(cpu_detailed_desc_buffer, cpu_detailed_desc_len);
|
||||
|
||||
char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, cpu_detailed_desc_len, mtTracing);
|
||||
|
||||
if (NULL == tmp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strncpy(tmp, cpu_detailed_desc_buffer, cpu_detailed_desc_len);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* See Intel Application note 485 (chapter 10) for details
|
||||
* on frequency extraction from cpu brand string.
|
||||
* http://www.intel.com/content/dam/www/public/us/en/documents/application-notes/processor-identification-cpuid-instruction-note.pdf
|
||||
*
|
||||
*/
|
||||
jlong VM_Version_Ext::max_qualified_cpu_freq_from_brand_string(void) {
|
||||
// get brand string
|
||||
const char* const brand_string = cpu_brand_string();
|
||||
if (brand_string == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u8 MEGA = 1000000;
|
||||
u8 multiplier = 0;
|
||||
jlong frequency = 0;
|
||||
|
||||
// the frequency information in the cpu brand string
|
||||
// is given in either of two formats "x.xxyHz" or "xxxxyHz",
|
||||
// where y=M,G,T and x is digits
|
||||
const char* Hz_location = strchr(brand_string, 'H');
|
||||
|
||||
if (Hz_location != NULL) {
|
||||
if (*(Hz_location + 1) == 'z') {
|
||||
// switch on y in "yHz"
|
||||
switch(*(Hz_location - 1)) {
|
||||
case 'M' :
|
||||
// Set multiplier to frequency is in Hz
|
||||
multiplier = MEGA;
|
||||
break;
|
||||
case 'G' :
|
||||
multiplier = MEGA * 1000;
|
||||
break;
|
||||
case 'T' :
|
||||
multiplier = MEGA * 1000 * 1000;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (multiplier > 0) {
|
||||
// compute frequency (in Hz) from brand string
|
||||
if (*(Hz_location - 4) == '.') { // if format is "x.xx"
|
||||
frequency = (jlong)(*(Hz_location - 5) - '0') * (multiplier);
|
||||
frequency += (jlong)(*(Hz_location - 3) - '0') * (multiplier / 10);
|
||||
frequency += (jlong)(*(Hz_location - 2) - '0') * (multiplier / 100);
|
||||
} else { // format is "xxxx"
|
||||
frequency = (jlong)(*(Hz_location - 5) - '0') * 1000;
|
||||
frequency += (jlong)(*(Hz_location - 4) - '0') * 100;
|
||||
frequency += (jlong)(*(Hz_location - 3) - '0') * 10;
|
||||
frequency += (jlong)(*(Hz_location - 2) - '0');
|
||||
frequency *= multiplier;
|
||||
}
|
||||
}
|
||||
return frequency;
|
||||
}
|
||||
|
||||
|
||||
jlong VM_Version_Ext::maximum_qualified_cpu_frequency(void) {
|
||||
if (_max_qualified_cpu_frequency == 0) {
|
||||
_max_qualified_cpu_frequency = max_qualified_cpu_freq_from_brand_string();
|
||||
}
|
||||
return _max_qualified_cpu_frequency;
|
||||
}
|
||||
|
||||
const char* const VM_Version_Ext::_family_id_intel[] = {
|
||||
"8086/8088",
|
||||
"",
|
||||
"286",
|
||||
"386",
|
||||
"486",
|
||||
"Pentium",
|
||||
"Pentium Pro", //or Pentium-M/Woodcrest depeding on model
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Pentium 4"
|
||||
};
|
||||
|
||||
const char* const VM_Version_Ext::_family_id_amd[] = {
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"5x86",
|
||||
"K5/K6",
|
||||
"Athlon/AthlonXP",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Opteron/Athlon64",
|
||||
"Opteron QC/Phenom" // Barcelona et.al.
|
||||
};
|
||||
// Partially from Intel 64 and IA-32 Architecture Software Developer's Manual,
|
||||
// September 2013, Vol 3C Table 35-1
|
||||
const char* const VM_Version_Ext::_model_id_pentium_pro[] = {
|
||||
"",
|
||||
"Pentium Pro",
|
||||
"",
|
||||
"Pentium II model 3",
|
||||
"",
|
||||
"Pentium II model 5/Xeon/Celeron",
|
||||
"Celeron",
|
||||
"Pentium III/Pentium III Xeon",
|
||||
"Pentium III/Pentium III Xeon",
|
||||
"Pentium M model 9", // Yonah
|
||||
"Pentium III, model A",
|
||||
"Pentium III, model B",
|
||||
"",
|
||||
"Pentium M model D", // Dothan
|
||||
"",
|
||||
"Core 2", // 0xf Woodcrest/Conroe/Merom/Kentsfield/Clovertown
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Celeron", // 0x16 Celeron 65nm
|
||||
"Core 2", // 0x17 Penryn / Harpertown
|
||||
"",
|
||||
"",
|
||||
"Core i7", // 0x1A CPU_MODEL_NEHALEM_EP
|
||||
"Atom", // 0x1B Z5xx series Silverthorn
|
||||
"",
|
||||
"Core 2", // 0x1D Dunnington (6-core)
|
||||
"Nehalem", // 0x1E CPU_MODEL_NEHALEM
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Westmere", // 0x25 CPU_MODEL_WESTMERE
|
||||
"",
|
||||
"",
|
||||
"", // 0x28
|
||||
"",
|
||||
"Sandy Bridge", // 0x2a "2nd Generation Intel Core i7, i5, i3"
|
||||
"",
|
||||
"Westmere-EP", // 0x2c CPU_MODEL_WESTMERE_EP
|
||||
"Sandy Bridge-EP", // 0x2d CPU_MODEL_SANDYBRIDGE_EP
|
||||
"Nehalem-EX", // 0x2e CPU_MODEL_NEHALEM_EX
|
||||
"Westmere-EX", // 0x2f CPU_MODEL_WESTMERE_EX
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Ivy Bridge", // 0x3a
|
||||
"",
|
||||
"Haswell", // 0x3c "4th Generation Intel Core Processor"
|
||||
"", // 0x3d "Next Generation Intel Core Processor"
|
||||
"Ivy Bridge-EP", // 0x3e "Next Generation Intel Xeon Processor E7 Family"
|
||||
"", // 0x3f "Future Generation Intel Xeon Processor"
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Haswell", // 0x45 "4th Generation Intel Core Processor"
|
||||
"Haswell", // 0x46 "4th Generation Intel Core Processor"
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Brand ID is for back compability
|
||||
* Newer CPUs uses the extended brand string */
|
||||
const char* const VM_Version_Ext::_brand_id[] = {
|
||||
"",
|
||||
"Celeron processor",
|
||||
"Pentium III processor",
|
||||
"Intel Pentium III Xeon processor",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Intel Pentium 4 processor",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
const char* const VM_Version_Ext::_feature_edx_id[] = {
|
||||
"On-Chip FPU",
|
||||
"Virtual Mode Extensions",
|
||||
"Debugging Extensions",
|
||||
"Page Size Extensions",
|
||||
"Time Stamp Counter",
|
||||
"Model Specific Registers",
|
||||
"Physical Address Extension",
|
||||
"Machine Check Exceptions",
|
||||
"CMPXCHG8B Instruction",
|
||||
"On-Chip APIC",
|
||||
"",
|
||||
"Fast System Call",
|
||||
"Memory Type Range Registers",
|
||||
"Page Global Enable",
|
||||
"Machine Check Architecture",
|
||||
"Conditional Mov Instruction",
|
||||
"Page Attribute Table",
|
||||
"36-bit Page Size Extension",
|
||||
"Processor Serial Number",
|
||||
"CLFLUSH Instruction",
|
||||
"",
|
||||
"Debug Trace Store feature",
|
||||
"ACPI registers in MSR space",
|
||||
"Intel Architecture MMX Technology",
|
||||
"Fast Float Point Save and Restore",
|
||||
"Streaming SIMD extensions",
|
||||
"Streaming SIMD extensions 2",
|
||||
"Self-Snoop",
|
||||
"Hyper Threading",
|
||||
"Thermal Monitor",
|
||||
"",
|
||||
"Pending Break Enable"
|
||||
};
|
||||
|
||||
const char* const VM_Version_Ext::_feature_extended_edx_id[] = {
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"SYSCALL/SYSRET",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Execute Disable Bit",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"RDTSCP",
|
||||
"",
|
||||
"Intel 64 Architecture",
|
||||
"",
|
||||
""
|
||||
};
|
||||
|
||||
const char* const VM_Version_Ext::_feature_ecx_id[] = {
|
||||
"Streaming SIMD Extensions 3",
|
||||
"PCLMULQDQ",
|
||||
"64-bit DS Area",
|
||||
"MONITOR/MWAIT instructions",
|
||||
"CPL Qualified Debug Store",
|
||||
"Virtual Machine Extensions",
|
||||
"Safer Mode Extensions",
|
||||
"Enhanced Intel SpeedStep technology",
|
||||
"Thermal Monitor 2",
|
||||
"Supplemental Streaming SIMD Extensions 3",
|
||||
"L1 Context ID",
|
||||
"",
|
||||
"Fused Multiply-Add",
|
||||
"CMPXCHG16B",
|
||||
"xTPR Update Control",
|
||||
"Perfmon and Debug Capability",
|
||||
"",
|
||||
"Process-context identifiers",
|
||||
"Direct Cache Access",
|
||||
"Streaming SIMD extensions 4.1",
|
||||
"Streaming SIMD extensions 4.2",
|
||||
"x2APIC",
|
||||
"MOVBE",
|
||||
"Popcount instruction",
|
||||
"TSC-Deadline",
|
||||
"AESNI",
|
||||
"XSAVE",
|
||||
"OSXSAVE",
|
||||
"AVX",
|
||||
"F16C",
|
||||
"RDRAND",
|
||||
""
|
||||
};
|
||||
|
||||
const char* const VM_Version_Ext::_feature_extended_ecx_id[] = {
|
||||
"LAHF/SAHF instruction support",
|
||||
"Core multi-processor leagacy mode",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"Advanced Bit Manipulations: LZCNT",
|
||||
"SSE4A: MOVNTSS, MOVNTSD, EXTRQ, INSERTQ",
|
||||
"Misaligned SSE mode",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
""
|
||||
};
|
99
src/hotspot/cpu/x86/vm_version_ext_x86.hpp
Normal file
99
src/hotspot/cpu/x86/vm_version_ext_x86.hpp
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPU_X86_VM_VM_VERSION_EXT_X86_HPP
|
||||
#define CPU_X86_VM_VM_VERSION_EXT_X86_HPP
|
||||
|
||||
#include "utilities/macros.hpp"
|
||||
#include "vm_version_x86.hpp"
|
||||
|
||||
class VM_Version_Ext : public VM_Version {
|
||||
private:
|
||||
static const size_t VENDOR_LENGTH;
|
||||
static const size_t CPU_EBS_MAX_LENGTH;
|
||||
static const size_t CPU_TYPE_DESC_BUF_SIZE;
|
||||
static const size_t CPU_DETAILED_DESC_BUF_SIZE;
|
||||
|
||||
static const char* const _family_id_intel[];
|
||||
static const char* const _family_id_amd[];
|
||||
static const char* const _brand_id[];
|
||||
static const char* const _model_id_pentium_pro[];
|
||||
|
||||
static const char* const _feature_edx_id[];
|
||||
static const char* const _feature_extended_edx_id[];
|
||||
static const char* const _feature_ecx_id[];
|
||||
static const char* const _feature_extended_ecx_id[];
|
||||
|
||||
static int _no_of_threads;
|
||||
static int _no_of_cores;
|
||||
static int _no_of_packages;
|
||||
static char* _cpu_brand_string;
|
||||
static jlong _max_qualified_cpu_frequency;
|
||||
|
||||
static const char* cpu_family_description(void);
|
||||
static const char* cpu_model_description(void);
|
||||
static const char* cpu_brand(void);
|
||||
static const char* cpu_brand_string(void);
|
||||
|
||||
static int cpu_type_description(char* const buf, size_t buf_len);
|
||||
static int cpu_detailed_description(char* const buf, size_t buf_len);
|
||||
static int cpu_extended_brand_string(char* const buf, size_t buf_len);
|
||||
|
||||
static bool cpu_is_em64t(void);
|
||||
static bool is_netburst(void);
|
||||
|
||||
static size_t cpu_write_support_string(char* const buf, size_t buf_len);
|
||||
static void resolve_cpu_information_details(void);
|
||||
static jlong max_qualified_cpu_freq_from_brand_string(void);
|
||||
|
||||
public:
|
||||
// Offsets for cpuid asm stub brand string
|
||||
static ByteSize proc_name_0_offset() { return byte_offset_of(CpuidInfo, proc_name_0); }
|
||||
static ByteSize proc_name_1_offset() { return byte_offset_of(CpuidInfo, proc_name_1); }
|
||||
static ByteSize proc_name_2_offset() { return byte_offset_of(CpuidInfo, proc_name_2); }
|
||||
static ByteSize proc_name_3_offset() { return byte_offset_of(CpuidInfo, proc_name_3); }
|
||||
static ByteSize proc_name_4_offset() { return byte_offset_of(CpuidInfo, proc_name_4); }
|
||||
static ByteSize proc_name_5_offset() { return byte_offset_of(CpuidInfo, proc_name_5); }
|
||||
static ByteSize proc_name_6_offset() { return byte_offset_of(CpuidInfo, proc_name_6); }
|
||||
static ByteSize proc_name_7_offset() { return byte_offset_of(CpuidInfo, proc_name_7); }
|
||||
static ByteSize proc_name_8_offset() { return byte_offset_of(CpuidInfo, proc_name_8); }
|
||||
static ByteSize proc_name_9_offset() { return byte_offset_of(CpuidInfo, proc_name_9); }
|
||||
static ByteSize proc_name_10_offset() { return byte_offset_of(CpuidInfo, proc_name_10); }
|
||||
static ByteSize proc_name_11_offset() { return byte_offset_of(CpuidInfo, proc_name_11); }
|
||||
|
||||
static int number_of_threads(void);
|
||||
static int number_of_cores(void);
|
||||
static int number_of_sockets(void);
|
||||
|
||||
static jlong maximum_qualified_cpu_frequency(void);
|
||||
|
||||
static bool supports_tscinv_ext(void);
|
||||
|
||||
static const char* cpu_name(void);
|
||||
static const char* cpu_description(void);
|
||||
|
||||
static void initialize();
|
||||
};
|
||||
|
||||
#endif // CPU_X86_VM_VM_VERSION_EXT_X86_HPP
|
405
src/hotspot/os/bsd/os_perf_bsd.cpp
Normal file
405
src/hotspot/os/bsd/os_perf_bsd.cpp
Normal file
@ -0,0 +1,405 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/os_perf.hpp"
|
||||
#include "vm_version_ext_x86.hpp"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#import <libproc.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/task_info.h>
|
||||
#endif
|
||||
|
||||
static const double NANOS_PER_SEC = 1000000000.0;
|
||||
|
||||
class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
|
||||
friend class CPUPerformanceInterface;
|
||||
private:
|
||||
long _total_cpu_nanos;
|
||||
long _total_csr_nanos;
|
||||
long _jvm_user_nanos;
|
||||
long _jvm_system_nanos;
|
||||
long _jvm_context_switches;
|
||||
long _used_ticks;
|
||||
long _total_ticks;
|
||||
int _active_processor_count;
|
||||
|
||||
bool now_in_nanos(long* resultp) {
|
||||
timeval current_time;
|
||||
if (gettimeofday(¤t_time, NULL) != 0) {
|
||||
// Error getting current time
|
||||
return false;
|
||||
}
|
||||
*resultp = current_time.tv_sec * NANOS_PER_SEC + 1000L * current_time.tv_usec;
|
||||
return true;
|
||||
}
|
||||
|
||||
double normalize(double value) {
|
||||
return MIN2<double>(MAX2<double>(value, 0.0), 1.0);
|
||||
}
|
||||
int cpu_load(int which_logical_cpu, double* cpu_load);
|
||||
int context_switch_rate(double* rate);
|
||||
int cpu_load_total_process(double* cpu_load);
|
||||
int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
|
||||
|
||||
CPUPerformance(const CPUPerformance& rhs); // no impl
|
||||
CPUPerformance& operator=(const CPUPerformance& rhs); // no impl
|
||||
public:
|
||||
CPUPerformance();
|
||||
bool initialize();
|
||||
~CPUPerformance();
|
||||
};
|
||||
|
||||
CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
|
||||
_total_cpu_nanos= 0;
|
||||
_total_csr_nanos= 0;
|
||||
_jvm_context_switches = 0;
|
||||
_jvm_user_nanos = 0;
|
||||
_jvm_system_nanos = 0;
|
||||
_used_ticks = 0;
|
||||
_total_ticks = 0;
|
||||
_active_processor_count = 0;
|
||||
}
|
||||
|
||||
bool CPUPerformanceInterface::CPUPerformance::initialize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
|
||||
return FUNCTIONALITY_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
|
||||
#ifdef __APPLE__
|
||||
host_name_port_t host = mach_host_self();
|
||||
host_flavor_t flavor = HOST_CPU_LOAD_INFO;
|
||||
mach_msg_type_number_t host_info_count = HOST_CPU_LOAD_INFO_COUNT;
|
||||
host_cpu_load_info_data_t cpu_load_info;
|
||||
|
||||
kern_return_t kr = host_statistics(host, flavor, (host_info_t)&cpu_load_info, &host_info_count);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
long used_ticks = cpu_load_info.cpu_ticks[CPU_STATE_USER] + cpu_load_info.cpu_ticks[CPU_STATE_NICE] + cpu_load_info.cpu_ticks[CPU_STATE_SYSTEM];
|
||||
long total_ticks = used_ticks + cpu_load_info.cpu_ticks[CPU_STATE_IDLE];
|
||||
|
||||
if (_used_ticks == 0 || _total_ticks == 0) {
|
||||
// First call, just set the values
|
||||
_used_ticks = used_ticks;
|
||||
_total_ticks = total_ticks;
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
long used_delta = used_ticks - _used_ticks;
|
||||
long total_delta = total_ticks - _total_ticks;
|
||||
|
||||
_used_ticks = used_ticks;
|
||||
_total_ticks = total_ticks;
|
||||
|
||||
if (total_delta == 0) {
|
||||
// Avoid division by zero
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
*cpu_load = (double)used_delta / total_delta;
|
||||
|
||||
return OS_OK;
|
||||
#else
|
||||
return FUNCTIONALITY_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
|
||||
#ifdef __APPLE__
|
||||
int result = cpu_load_total_process(psystemTotalLoad);
|
||||
mach_port_t task = mach_task_self();
|
||||
mach_msg_type_number_t task_info_count = TASK_INFO_MAX;
|
||||
task_info_data_t task_info_data;
|
||||
kern_return_t kr = task_info(task, TASK_ABSOLUTETIME_INFO, (task_info_t)task_info_data, &task_info_count);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
return OS_ERR;
|
||||
}
|
||||
task_absolutetime_info_t absolutetime_info = (task_absolutetime_info_t)task_info_data;
|
||||
|
||||
int active_processor_count = os::active_processor_count();
|
||||
long jvm_user_nanos = absolutetime_info->total_user;
|
||||
long jvm_system_nanos = absolutetime_info->total_system;
|
||||
|
||||
long total_cpu_nanos;
|
||||
if(!now_in_nanos(&total_cpu_nanos)) {
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
if (_total_cpu_nanos == 0 || active_processor_count != _active_processor_count) {
|
||||
// First call or change in active processor count
|
||||
result = OS_ERR;
|
||||
}
|
||||
|
||||
long delta_nanos = active_processor_count * (total_cpu_nanos - _total_cpu_nanos);
|
||||
if (delta_nanos == 0) {
|
||||
// Avoid division by zero
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
*pjvmUserLoad = normalize((double)(jvm_user_nanos - _jvm_user_nanos)/delta_nanos);
|
||||
*pjvmKernelLoad = normalize((double)(jvm_system_nanos - _jvm_system_nanos)/delta_nanos);
|
||||
|
||||
_active_processor_count = active_processor_count;
|
||||
_total_cpu_nanos = total_cpu_nanos;
|
||||
_jvm_user_nanos = jvm_user_nanos;
|
||||
_jvm_system_nanos = jvm_system_nanos;
|
||||
|
||||
return result;
|
||||
#else
|
||||
return FUNCTIONALITY_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
|
||||
#ifdef __APPLE__
|
||||
mach_port_t task = mach_task_self();
|
||||
mach_msg_type_number_t task_info_count = TASK_INFO_MAX;
|
||||
task_info_data_t task_info_data;
|
||||
kern_return_t kr = task_info(task, TASK_EVENTS_INFO, (task_info_t)task_info_data, &task_info_count);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
int result = OS_OK;
|
||||
if (_total_csr_nanos == 0 || _jvm_context_switches == 0) {
|
||||
// First call just set initial values.
|
||||
result = OS_ERR;
|
||||
}
|
||||
|
||||
long jvm_context_switches = ((task_events_info_t)task_info_data)->csw;
|
||||
|
||||
long total_csr_nanos;
|
||||
if(!now_in_nanos(&total_csr_nanos)) {
|
||||
return OS_ERR;
|
||||
}
|
||||
double delta_in_sec = (double)(total_csr_nanos - _total_csr_nanos) / NANOS_PER_SEC;
|
||||
if (delta_in_sec == 0.0) {
|
||||
// Avoid division by zero
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
*rate = (jvm_context_switches - _jvm_context_switches) / delta_in_sec;
|
||||
|
||||
_jvm_context_switches = jvm_context_switches;
|
||||
_total_csr_nanos = total_csr_nanos;
|
||||
|
||||
return result;
|
||||
#else
|
||||
return FUNCTIONALITY_NOT_IMPLEMENTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
CPUPerformanceInterface::CPUPerformanceInterface() {
|
||||
_impl = NULL;
|
||||
}
|
||||
|
||||
bool CPUPerformanceInterface::initialize() {
|
||||
_impl = new CPUPerformanceInterface::CPUPerformance();
|
||||
return _impl != NULL && _impl->initialize();
|
||||
}
|
||||
|
||||
CPUPerformanceInterface::~CPUPerformanceInterface() {
|
||||
if (_impl != NULL) {
|
||||
delete _impl;
|
||||
}
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
|
||||
return _impl->cpu_load(which_logical_cpu, cpu_load);
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
|
||||
return _impl->cpu_load_total_process(cpu_load);
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {
|
||||
return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::context_switch_rate(double* rate) const {
|
||||
return _impl->context_switch_rate(rate);
|
||||
}
|
||||
|
||||
class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
|
||||
friend class SystemProcessInterface;
|
||||
private:
|
||||
SystemProcesses();
|
||||
bool initialize();
|
||||
SystemProcesses(const SystemProcesses& rhs); // no impl
|
||||
SystemProcesses& operator=(const SystemProcesses& rhs); // no impl
|
||||
~SystemProcesses();
|
||||
|
||||
//information about system processes
|
||||
int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
|
||||
};
|
||||
|
||||
SystemProcessInterface::SystemProcesses::SystemProcesses() {
|
||||
}
|
||||
|
||||
bool SystemProcessInterface::SystemProcesses::initialize() {
|
||||
return true;
|
||||
}
|
||||
|
||||
SystemProcessInterface::SystemProcesses::~SystemProcesses() {
|
||||
}
|
||||
int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {
|
||||
assert(system_processes != NULL, "system_processes pointer is NULL!");
|
||||
assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!");
|
||||
#ifdef __APPLE__
|
||||
pid_t* pids = NULL;
|
||||
int pid_count = 0;
|
||||
ResourceMark rm;
|
||||
|
||||
int try_count = 0;
|
||||
while (pids == NULL) {
|
||||
// Find out buffer size
|
||||
size_t pids_bytes = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
|
||||
if (pids_bytes <= 0) {
|
||||
return OS_ERR;
|
||||
}
|
||||
pid_count = pids_bytes / sizeof(pid_t);
|
||||
pids = NEW_RESOURCE_ARRAY(pid_t, pid_count);
|
||||
memset(pids, 0, pids_bytes);
|
||||
|
||||
pids_bytes = proc_listpids(PROC_ALL_PIDS, 0, pids, pids_bytes);
|
||||
if (pids_bytes <= 0) {
|
||||
// couldn't fit buffer, retry.
|
||||
FREE_RESOURCE_ARRAY(pid_t, pids, pid_count);
|
||||
pids = NULL;
|
||||
try_count++;
|
||||
if (try_count > 3) {
|
||||
return OS_ERR;
|
||||
}
|
||||
} else {
|
||||
pid_count = pids_bytes / sizeof(pid_t);
|
||||
}
|
||||
}
|
||||
|
||||
int process_count = 0;
|
||||
SystemProcess* next = NULL;
|
||||
for (int i = 0; i < pid_count; i++) {
|
||||
pid_t pid = pids[i];
|
||||
if (pid != 0) {
|
||||
char buffer[PROC_PIDPATHINFO_MAXSIZE];
|
||||
memset(buffer, 0 , sizeof(buffer));
|
||||
if (proc_pidpath(pid, buffer, sizeof(buffer)) != -1) {
|
||||
int length = strlen(buffer);
|
||||
if (length > 0) {
|
||||
SystemProcess* current = new SystemProcess();
|
||||
char * path = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal);
|
||||
strcpy(path, buffer);
|
||||
current->set_path(path);
|
||||
current->set_pid((int)pid);
|
||||
current->set_next(next);
|
||||
next = current;
|
||||
process_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*no_of_sys_processes = process_count;
|
||||
*system_processes = next;
|
||||
|
||||
return OS_OK;
|
||||
#endif
|
||||
return FUNCTIONALITY_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
|
||||
return _impl->system_processes(system_procs, no_of_sys_processes);
|
||||
}
|
||||
|
||||
SystemProcessInterface::SystemProcessInterface() {
|
||||
_impl = NULL;
|
||||
}
|
||||
|
||||
bool SystemProcessInterface::initialize() {
|
||||
_impl = new SystemProcessInterface::SystemProcesses();
|
||||
return _impl != NULL && _impl->initialize();
|
||||
}
|
||||
|
||||
SystemProcessInterface::~SystemProcessInterface() {
|
||||
if (_impl != NULL) {
|
||||
delete _impl;
|
||||
}
|
||||
}
|
||||
|
||||
CPUInformationInterface::CPUInformationInterface() {
|
||||
_cpu_info = NULL;
|
||||
}
|
||||
|
||||
bool CPUInformationInterface::initialize() {
|
||||
_cpu_info = new CPUInformation();
|
||||
|
||||
if (NULL == _cpu_info) {
|
||||
return false;
|
||||
}
|
||||
_cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
|
||||
_cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
|
||||
_cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
|
||||
_cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
|
||||
_cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CPUInformationInterface::~CPUInformationInterface() {
|
||||
if (_cpu_info != NULL) {
|
||||
if (_cpu_info->cpu_name() != NULL) {
|
||||
const char* cpu_name = _cpu_info->cpu_name();
|
||||
FREE_C_HEAP_ARRAY(char, cpu_name);
|
||||
_cpu_info->set_cpu_name(NULL);
|
||||
}
|
||||
if (_cpu_info->cpu_description() != NULL) {
|
||||
const char* cpu_desc = _cpu_info->cpu_description();
|
||||
FREE_C_HEAP_ARRAY(char, cpu_desc);
|
||||
_cpu_info->set_cpu_description(NULL);
|
||||
}
|
||||
delete _cpu_info;
|
||||
}
|
||||
}
|
||||
|
||||
int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
|
||||
if (NULL == _cpu_info) {
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
cpu_info = *_cpu_info; // shallow copy assignment
|
||||
return OS_OK;
|
||||
}
|
1060
src/hotspot/os/linux/os_perf_linux.cpp
Normal file
1060
src/hotspot/os/linux/os_perf_linux.cpp
Normal file
File diff suppressed because it is too large
Load Diff
756
src/hotspot/os/solaris/os_perf_solaris.cpp
Normal file
756
src/hotspot/os/solaris/os_perf_solaris.cpp
Normal file
@ -0,0 +1,756 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "jvm.h"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/os_perf.hpp"
|
||||
#include "os_solaris.inline.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
#include CPU_HEADER(vm_version_ext)
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <procfs.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <kstat.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/lwp.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#include <utmpx.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/loadavg.h>
|
||||
#include <limits.h>
|
||||
|
||||
static const double NANOS_PER_SEC = 1000000000.0;
|
||||
|
||||
struct CPUPerfTicks {
|
||||
kstat_t* kstat;
|
||||
uint64_t last_idle;
|
||||
uint64_t last_total;
|
||||
double last_ratio;
|
||||
};
|
||||
|
||||
struct CPUPerfCounters {
|
||||
int nProcs;
|
||||
CPUPerfTicks* jvmTicks;
|
||||
kstat_ctl_t* kstat_ctrl;
|
||||
};
|
||||
|
||||
static int get_info(const char* path, void* info, size_t s, off_t o) {
|
||||
assert(path != NULL, "path is NULL!");
|
||||
assert(info != NULL, "info is NULL!");
|
||||
|
||||
int fd = -1;
|
||||
|
||||
if ((fd = open(path, O_RDONLY)) < 0) {
|
||||
return OS_ERR;
|
||||
}
|
||||
if (pread(fd, info, s, o) != s) {
|
||||
close(fd);
|
||||
return OS_ERR;
|
||||
}
|
||||
close(fd);
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
static int get_psinfo2(void* info, size_t s, off_t o) {
|
||||
return get_info("/proc/self/psinfo", info, s, o);
|
||||
}
|
||||
|
||||
static int get_psinfo(psinfo_t* info) {
|
||||
return get_psinfo2(info, sizeof(*info), 0);
|
||||
}
|
||||
|
||||
static int get_psinfo(char* file, psinfo_t* info) {
|
||||
assert(file != NULL, "file is NULL!");
|
||||
assert(info != NULL, "info is NULL!");
|
||||
return get_info(file, info, sizeof(*info), 0);
|
||||
}
|
||||
|
||||
|
||||
static int get_usage(prusage_t* usage) {
|
||||
assert(usage != NULL, "usage is NULL!");
|
||||
return get_info("/proc/self/usage", usage, sizeof(*usage), 0);
|
||||
}
|
||||
|
||||
static int read_cpustat(kstat_ctl_t* kstat_ctrl, CPUPerfTicks* load, cpu_stat_t* cpu_stat) {
|
||||
assert(kstat_ctrl != NULL, "kstat_ctrl pointer is NULL!");
|
||||
assert(load != NULL, "load pointer is NULL!");
|
||||
assert(cpu_stat != NULL, "cpu_stat pointer is NULL!");
|
||||
|
||||
if (load->kstat == NULL) {
|
||||
// no handle.
|
||||
return OS_ERR;
|
||||
}
|
||||
if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == OS_ERR) {
|
||||
// disable handle for this CPU
|
||||
load->kstat = NULL;
|
||||
return OS_ERR;
|
||||
}
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters) {
|
||||
assert(counters != NULL, "counters pointer is NULL!");
|
||||
|
||||
cpu_stat_t cpu_stat = {0};
|
||||
|
||||
if (which_logical_cpu >= counters->nProcs) {
|
||||
return .0;
|
||||
}
|
||||
|
||||
CPUPerfTicks load = counters->jvmTicks[which_logical_cpu];
|
||||
if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) != OS_OK) {
|
||||
return .0;
|
||||
}
|
||||
|
||||
uint_t* usage = cpu_stat.cpu_sysinfo.cpu;
|
||||
if (usage == NULL) {
|
||||
return .0;
|
||||
}
|
||||
|
||||
uint64_t c_idle = usage[CPU_IDLE];
|
||||
uint64_t c_total = 0;
|
||||
|
||||
for (int i = 0; i < CPU_STATES; i++) {
|
||||
c_total += usage[i];
|
||||
}
|
||||
|
||||
// Calculate diff against previous snapshot
|
||||
uint64_t d_idle = c_idle - load.last_idle;
|
||||
uint64_t d_total = c_total - load.last_total;
|
||||
|
||||
/** update if weve moved */
|
||||
if (d_total > 0) {
|
||||
// Save current values for next time around
|
||||
load.last_idle = c_idle;
|
||||
load.last_total = c_total;
|
||||
load.last_ratio = (double) (d_total - d_idle) / d_total;
|
||||
}
|
||||
|
||||
return load.last_ratio;
|
||||
}
|
||||
|
||||
static int get_boot_time(uint64_t* time) {
|
||||
assert(time != NULL, "time pointer is NULL!");
|
||||
setutxent();
|
||||
for(;;) {
|
||||
struct utmpx* u;
|
||||
if ((u = getutxent()) == NULL) {
|
||||
break;
|
||||
}
|
||||
if (u->ut_type == BOOT_TIME) {
|
||||
*time = u->ut_xtime;
|
||||
endutxent();
|
||||
return OS_OK;
|
||||
}
|
||||
}
|
||||
endutxent();
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
static int get_noof_context_switches(CPUPerfCounters* counters, uint64_t* switches) {
|
||||
assert(switches != NULL, "switches pointer is NULL!");
|
||||
assert(counters != NULL, "counter pointer is NULL!");
|
||||
*switches = 0;
|
||||
uint64_t s = 0;
|
||||
|
||||
// Collect data from all CPUs
|
||||
for (int i = 0; i < counters->nProcs; i++) {
|
||||
cpu_stat_t cpu_stat = {0};
|
||||
CPUPerfTicks load = counters->jvmTicks[i];
|
||||
|
||||
if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) == OS_OK) {
|
||||
s += cpu_stat.cpu_sysinfo.pswitch;
|
||||
} else {
|
||||
//fail fast...
|
||||
return OS_ERR;
|
||||
}
|
||||
}
|
||||
*switches = s;
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
static int perf_context_switch_rate(CPUPerfCounters* counters, double* rate) {
|
||||
assert(counters != NULL, "counters is NULL!");
|
||||
assert(rate != NULL, "rate pointer is NULL!");
|
||||
static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static uint64_t lastTime = 0;
|
||||
static uint64_t lastSwitches = 0;
|
||||
static double lastRate = 0.0;
|
||||
|
||||
uint64_t lt = 0;
|
||||
int res = 0;
|
||||
|
||||
if (lastTime == 0) {
|
||||
uint64_t tmp;
|
||||
if (get_boot_time(&tmp) < 0) {
|
||||
return OS_ERR;
|
||||
}
|
||||
lt = tmp * 1000;
|
||||
}
|
||||
|
||||
res = OS_OK;
|
||||
|
||||
pthread_mutex_lock(&contextSwitchLock);
|
||||
{
|
||||
|
||||
uint64_t sw = 0;
|
||||
clock_t t, d;
|
||||
|
||||
if (lastTime == 0) {
|
||||
lastTime = lt;
|
||||
}
|
||||
|
||||
t = clock();
|
||||
d = t - lastTime;
|
||||
|
||||
if (d == 0) {
|
||||
*rate = lastRate;
|
||||
} else if (get_noof_context_switches(counters, &sw)== OS_OK) {
|
||||
*rate = ((double)(sw - lastSwitches) / d) * 1000;
|
||||
lastRate = *rate;
|
||||
lastSwitches = sw;
|
||||
lastTime = t;
|
||||
} else {
|
||||
*rate = 0.0;
|
||||
res = OS_ERR;
|
||||
}
|
||||
if (*rate < 0.0) {
|
||||
*rate = 0.0;
|
||||
lastRate = 0.0;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&contextSwitchLock);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
|
||||
friend class CPUPerformanceInterface;
|
||||
private:
|
||||
CPUPerfCounters _counters;
|
||||
int cpu_load(int which_logical_cpu, double* cpu_load);
|
||||
int context_switch_rate(double* rate);
|
||||
int cpu_load_total_process(double* cpu_load);
|
||||
int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
|
||||
|
||||
CPUPerformance();
|
||||
~CPUPerformance();
|
||||
bool initialize();
|
||||
};
|
||||
|
||||
CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
|
||||
_counters.nProcs = 0;
|
||||
_counters.jvmTicks = NULL;
|
||||
_counters.kstat_ctrl = NULL;
|
||||
}
|
||||
|
||||
bool CPUPerformanceInterface::CPUPerformance::initialize() {
|
||||
// initialize kstat control structure,
|
||||
_counters.kstat_ctrl = kstat_open();
|
||||
assert(_counters.kstat_ctrl != NULL, "error initializing kstat control structure!");
|
||||
|
||||
if (NULL == _counters.kstat_ctrl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get number of CPU(s)
|
||||
if ((_counters.nProcs = sysconf(_SC_NPROCESSORS_ONLN)) == OS_ERR) {
|
||||
// ignore error?
|
||||
_counters.nProcs = 1;
|
||||
}
|
||||
|
||||
assert(_counters.nProcs > 0, "no CPUs detected in sysconf call!");
|
||||
if (_counters.nProcs == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Data structure(s) for saving CPU load (one per CPU)
|
||||
size_t tick_array_size = _counters.nProcs * sizeof(CPUPerfTicks);
|
||||
_counters.jvmTicks = (CPUPerfTicks*)NEW_C_HEAP_ARRAY(char, tick_array_size, mtInternal);
|
||||
if (NULL == _counters.jvmTicks) {
|
||||
return false;
|
||||
}
|
||||
memset(_counters.jvmTicks, 0, tick_array_size);
|
||||
|
||||
// Get kstat cpu_stat counters for every CPU
|
||||
// loop over kstat to find our cpu_stat(s)
|
||||
int i = 0;
|
||||
for (kstat_t* kstat = _counters.kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) {
|
||||
if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) {
|
||||
if (kstat_read(_counters.kstat_ctrl, kstat, NULL) == OS_ERR) {
|
||||
continue;
|
||||
}
|
||||
if (i == _counters.nProcs) {
|
||||
// more cpu_stats than reported CPUs
|
||||
break;
|
||||
}
|
||||
_counters.jvmTicks[i++].kstat = kstat;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
|
||||
if (_counters.jvmTicks != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, _counters.jvmTicks);
|
||||
}
|
||||
if (_counters.kstat_ctrl != NULL) {
|
||||
kstat_close(_counters.kstat_ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
|
||||
assert(cpu_load != NULL, "cpu_load pointer is NULL!");
|
||||
double t = .0;
|
||||
if (-1 == which_logical_cpu) {
|
||||
for (int i = 0; i < _counters.nProcs; i++) {
|
||||
t += get_cpu_load(i, &_counters);
|
||||
}
|
||||
// Cap total systemload to 1.0
|
||||
t = MIN2<double>((t / _counters.nProcs), 1.0);
|
||||
} else {
|
||||
t = MIN2<double>(get_cpu_load(which_logical_cpu, &_counters), 1.0);
|
||||
}
|
||||
|
||||
*cpu_load = t;
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
|
||||
assert(cpu_load != NULL, "cpu_load pointer is NULL!");
|
||||
|
||||
psinfo_t info;
|
||||
|
||||
// Get the percentage of "recent cpu usage" from all the lwp:s in the JVM:s
|
||||
// process. This is returned as a value between 0.0 and 1.0 multiplied by 0x8000.
|
||||
if (get_psinfo2(&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) != 0) {
|
||||
*cpu_load = 0.0;
|
||||
return OS_ERR;
|
||||
}
|
||||
*cpu_load = (double) info.pr_pctcpu / 0x8000;
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
|
||||
assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited");
|
||||
assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited");
|
||||
assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited");
|
||||
|
||||
static uint64_t lastTime;
|
||||
static uint64_t lastUser, lastKernel;
|
||||
static double lastUserRes, lastKernelRes;
|
||||
|
||||
pstatus_t pss;
|
||||
psinfo_t info;
|
||||
|
||||
*pjvmKernelLoad = *pjvmUserLoad = *psystemTotalLoad = 0;
|
||||
if (get_info("/proc/self/status", &pss.pr_utime, sizeof(timestruc_t)*2, offsetof(pstatus_t, pr_utime)) != 0) {
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
if (get_psinfo(&info) != 0) {
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
// get the total time in user, kernel and total time
|
||||
// check ratios for 'lately' and multiply the 'recent load'.
|
||||
uint64_t time = (info.pr_time.tv_sec * NANOS_PER_SEC) + info.pr_time.tv_nsec;
|
||||
uint64_t user = (pss.pr_utime.tv_sec * NANOS_PER_SEC) + pss.pr_utime.tv_nsec;
|
||||
uint64_t kernel = (pss.pr_stime.tv_sec * NANOS_PER_SEC) + pss.pr_stime.tv_nsec;
|
||||
uint64_t diff = time - lastTime;
|
||||
double load = (double) info.pr_pctcpu / 0x8000;
|
||||
|
||||
if (diff > 0) {
|
||||
lastUserRes = (load * (user - lastUser)) / diff;
|
||||
lastKernelRes = (load * (kernel - lastKernel)) / diff;
|
||||
|
||||
// BUG9182835 - patch for clamping these values to sane ones.
|
||||
lastUserRes = MIN2<double>(1, lastUserRes);
|
||||
lastUserRes = MAX2<double>(0, lastUserRes);
|
||||
lastKernelRes = MIN2<double>(1, lastKernelRes);
|
||||
lastKernelRes = MAX2<double>(0, lastKernelRes);
|
||||
}
|
||||
|
||||
double t = .0;
|
||||
cpu_load(-1, &t);
|
||||
// clamp at user+system and 1.0
|
||||
if (lastUserRes + lastKernelRes > t) {
|
||||
t = MIN2<double>(lastUserRes + lastKernelRes, 1.0);
|
||||
}
|
||||
|
||||
*pjvmUserLoad = lastUserRes;
|
||||
*pjvmKernelLoad = lastKernelRes;
|
||||
*psystemTotalLoad = t;
|
||||
|
||||
lastTime = time;
|
||||
lastUser = user;
|
||||
lastKernel = kernel;
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
|
||||
return perf_context_switch_rate(&_counters, rate);
|
||||
}
|
||||
|
||||
CPUPerformanceInterface::CPUPerformanceInterface() {
|
||||
_impl = NULL;
|
||||
}
|
||||
|
||||
bool CPUPerformanceInterface::initialize() {
|
||||
_impl = new CPUPerformanceInterface::CPUPerformance();
|
||||
return _impl != NULL && _impl->initialize();
|
||||
}
|
||||
|
||||
CPUPerformanceInterface::~CPUPerformanceInterface(void) {
|
||||
if (_impl != NULL) {
|
||||
delete _impl;
|
||||
}
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
|
||||
return _impl->cpu_load(which_logical_cpu, cpu_load);
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
|
||||
return _impl->cpu_load_total_process(cpu_load);
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {
|
||||
return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
|
||||
}
|
||||
|
||||
int CPUPerformanceInterface::context_switch_rate(double* rate) const {
|
||||
return _impl->context_switch_rate(rate);
|
||||
}
|
||||
|
||||
class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
|
||||
friend class SystemProcessInterface;
|
||||
private:
|
||||
class ProcessIterator : public CHeapObj<mtInternal> {
|
||||
friend class SystemProcessInterface::SystemProcesses;
|
||||
private:
|
||||
DIR* _dir;
|
||||
struct dirent* _entry;
|
||||
bool _valid;
|
||||
|
||||
ProcessIterator();
|
||||
~ProcessIterator();
|
||||
bool initialize();
|
||||
|
||||
bool is_valid() const { return _valid; }
|
||||
bool is_valid_entry(struct dirent* const entry) const;
|
||||
bool is_dir(const char* const name) const;
|
||||
char* allocate_string(const char* const str) const;
|
||||
int current(SystemProcess* const process_info);
|
||||
int next_process();
|
||||
};
|
||||
|
||||
ProcessIterator* _iterator;
|
||||
SystemProcesses();
|
||||
bool initialize();
|
||||
~SystemProcesses();
|
||||
|
||||
//information about system processes
|
||||
int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
|
||||
};
|
||||
|
||||
bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const {
|
||||
struct stat64 mystat;
|
||||
int ret_val = 0;
|
||||
|
||||
ret_val = ::stat64(name, &mystat);
|
||||
|
||||
if (ret_val < 0) {
|
||||
return false;
|
||||
}
|
||||
ret_val = S_ISDIR(mystat.st_mode);
|
||||
return ret_val > 0;
|
||||
}
|
||||
|
||||
// if it has a numeric name, is a directory and has a 'psinfo' file in it
|
||||
bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const {
|
||||
// ignore the "." and ".." directories
|
||||
if ((strcmp(entry->d_name, ".") == 0) ||
|
||||
(strcmp(entry->d_name, "..") == 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char buffer[PATH_MAX] = {0};
|
||||
uint64_t size = 0;
|
||||
bool result = false;
|
||||
FILE *fp = NULL;
|
||||
|
||||
if (atoi(entry->d_name) != 0) {
|
||||
jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);
|
||||
|
||||
if (is_dir(buffer)) {
|
||||
memset(buffer, 0, PATH_MAX);
|
||||
jio_snprintf(buffer, PATH_MAX, "/proc/%s/psinfo", entry->d_name);
|
||||
if ((fp = fopen(buffer, "r")) != NULL) {
|
||||
int nread = 0;
|
||||
psinfo_t psinfo_data;
|
||||
if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) != -1) {
|
||||
// only considering system process owned by root
|
||||
if (psinfo_data.pr_uid == 0) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fp != NULL) {
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
|
||||
if (str != NULL) {
|
||||
size_t len = strlen(str);
|
||||
char* tmp = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
|
||||
strncpy(tmp, str, len);
|
||||
tmp[len] = '\0';
|
||||
return tmp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {
|
||||
if (!is_valid()) {
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
char psinfo_path[PATH_MAX] = {0};
|
||||
jio_snprintf(psinfo_path, PATH_MAX, "/proc/%s/psinfo", _entry->d_name);
|
||||
|
||||
FILE *fp = NULL;
|
||||
if ((fp = fopen(psinfo_path, "r")) == NULL) {
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
int nread = 0;
|
||||
psinfo_t psinfo_data;
|
||||
if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) == -1) {
|
||||
fclose(fp);
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
char *exe_path = NULL;
|
||||
if ((psinfo_data.pr_fname != NULL) &&
|
||||
(psinfo_data.pr_psargs != NULL)) {
|
||||
char *path_substring = strstr(psinfo_data.pr_psargs, psinfo_data.pr_fname);
|
||||
if (path_substring != NULL) {
|
||||
int len = path_substring - psinfo_data.pr_psargs;
|
||||
exe_path = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
|
||||
if (exe_path != NULL) {
|
||||
jio_snprintf(exe_path, len, "%s", psinfo_data.pr_psargs);
|
||||
exe_path[len] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process_info->set_pid(atoi(_entry->d_name));
|
||||
process_info->set_name(allocate_string(psinfo_data.pr_fname));
|
||||
process_info->set_path(allocate_string(exe_path));
|
||||
process_info->set_command_line(allocate_string(psinfo_data.pr_psargs));
|
||||
|
||||
if (exe_path != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, exe_path);
|
||||
}
|
||||
|
||||
if (fp != NULL) {
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
|
||||
struct dirent* entry;
|
||||
|
||||
if (!is_valid()) {
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
do {
|
||||
if ((entry = os::readdir(_dir, _entry)) == NULL) {
|
||||
// error
|
||||
_valid = false;
|
||||
return OS_ERR;
|
||||
}
|
||||
} while(!is_valid_entry(_entry));
|
||||
|
||||
_valid = true;
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
|
||||
_dir = NULL;
|
||||
_entry = NULL;
|
||||
_valid = false;
|
||||
}
|
||||
|
||||
bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {
|
||||
_dir = opendir("/proc");
|
||||
_entry = (struct dirent*)NEW_C_HEAP_ARRAY(char, sizeof(struct dirent) + _PC_NAME_MAX + 1, mtInternal);
|
||||
if (NULL == _entry) {
|
||||
return false;
|
||||
}
|
||||
_valid = true;
|
||||
next_process();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {
|
||||
if (_entry != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, _entry);
|
||||
}
|
||||
|
||||
if (_dir != NULL) {
|
||||
closedir(_dir);
|
||||
}
|
||||
}
|
||||
|
||||
SystemProcessInterface::SystemProcesses::SystemProcesses() {
|
||||
_iterator = NULL;
|
||||
}
|
||||
|
||||
bool SystemProcessInterface::SystemProcesses::initialize() {
|
||||
_iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
|
||||
return _iterator != NULL && _iterator->initialize();
|
||||
}
|
||||
|
||||
SystemProcessInterface::SystemProcesses::~SystemProcesses() {
|
||||
if (_iterator != NULL) {
|
||||
delete _iterator;
|
||||
}
|
||||
}
|
||||
|
||||
int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {
|
||||
assert(system_processes != NULL, "system_processes pointer is NULL!");
|
||||
assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!");
|
||||
assert(_iterator != NULL, "iterator is NULL!");
|
||||
|
||||
// initialize pointers
|
||||
*no_of_sys_processes = 0;
|
||||
*system_processes = NULL;
|
||||
|
||||
while (_iterator->is_valid()) {
|
||||
SystemProcess* tmp = new SystemProcess();
|
||||
_iterator->current(tmp);
|
||||
|
||||
//if already existing head
|
||||
if (*system_processes != NULL) {
|
||||
//move "first to second"
|
||||
tmp->set_next(*system_processes);
|
||||
}
|
||||
// new head
|
||||
*system_processes = tmp;
|
||||
// increment
|
||||
(*no_of_sys_processes)++;
|
||||
// step forward
|
||||
_iterator->next_process();
|
||||
}
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
|
||||
return _impl->system_processes(system_procs, no_of_sys_processes);
|
||||
}
|
||||
|
||||
SystemProcessInterface::SystemProcessInterface() {
|
||||
_impl = NULL;
|
||||
}
|
||||
|
||||
bool SystemProcessInterface::initialize() {
|
||||
_impl = new SystemProcessInterface::SystemProcesses();
|
||||
return _impl != NULL && _impl->initialize();
|
||||
|
||||
}
|
||||
|
||||
SystemProcessInterface::~SystemProcessInterface() {
|
||||
if (_impl != NULL) {
|
||||
delete _impl;
|
||||
}
|
||||
}
|
||||
|
||||
CPUInformationInterface::CPUInformationInterface() {
|
||||
_cpu_info = NULL;
|
||||
}
|
||||
|
||||
bool CPUInformationInterface::initialize() {
|
||||
_cpu_info = new CPUInformation();
|
||||
if (_cpu_info == NULL) {
|
||||
return false;
|
||||
}
|
||||
_cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
|
||||
_cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
|
||||
_cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
|
||||
_cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
|
||||
_cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
|
||||
return true;
|
||||
}
|
||||
|
||||
CPUInformationInterface::~CPUInformationInterface() {
|
||||
if (_cpu_info != NULL) {
|
||||
if (_cpu_info->cpu_name() != NULL) {
|
||||
const char* cpu_name = _cpu_info->cpu_name();
|
||||
FREE_C_HEAP_ARRAY(char, cpu_name);
|
||||
_cpu_info->set_cpu_name(NULL);
|
||||
}
|
||||
if (_cpu_info->cpu_description() != NULL) {
|
||||
const char* cpu_desc = _cpu_info->cpu_description();
|
||||
FREE_C_HEAP_ARRAY(char, cpu_desc);
|
||||
_cpu_info->set_cpu_description(NULL);
|
||||
}
|
||||
delete _cpu_info;
|
||||
}
|
||||
}
|
||||
|
||||
int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
|
||||
if (_cpu_info == NULL) {
|
||||
return OS_ERR;
|
||||
}
|
||||
|
||||
cpu_info = *_cpu_info; // shallow copy assignment
|
||||
return OS_OK;
|
||||
}
|
1332
src/hotspot/os/windows/os_perf_windows.cpp
Normal file
1332
src/hotspot/os/windows/os_perf_windows.cpp
Normal file
File diff suppressed because it is too large
Load Diff
165
src/hotspot/os/windows/pdh_interface.cpp
Normal file
165
src/hotspot/os/windows/pdh_interface.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "pdh_interface.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
// PDH API
|
||||
typedef PDH_STATUS (WINAPI *PdhAddCounter_Fn)(HQUERY, LPCSTR, DWORD, HCOUNTER*);
|
||||
typedef PDH_STATUS (WINAPI *PdhOpenQuery_Fn)(LPCWSTR, DWORD, HQUERY*);
|
||||
typedef DWORD (WINAPI *PdhCloseQuery_Fn)(HQUERY);
|
||||
typedef PDH_STATUS (WINAPI *PdhCollectQueryData_Fn)(HQUERY);
|
||||
typedef DWORD (WINAPI *PdhGetFormattedCounterValue_Fn)(HCOUNTER, DWORD, LPDWORD, PPDH_FMT_COUNTERVALUE);
|
||||
typedef PDH_STATUS (WINAPI *PdhEnumObjectItems_Fn)(LPCTSTR, LPCTSTR, LPCTSTR, LPTSTR, LPDWORD, LPTSTR, LPDWORD, DWORD, DWORD);
|
||||
typedef PDH_STATUS (WINAPI *PdhRemoveCounter_Fn)(HCOUNTER);
|
||||
typedef PDH_STATUS (WINAPI *PdhLookupPerfNameByIndex_Fn)(LPCSTR, DWORD, LPSTR, LPDWORD);
|
||||
typedef PDH_STATUS (WINAPI *PdhMakeCounterPath_Fn)(PDH_COUNTER_PATH_ELEMENTS*, LPTSTR, LPDWORD, DWORD);
|
||||
|
||||
PdhAddCounter_Fn PdhDll::_PdhAddCounter = NULL;
|
||||
PdhOpenQuery_Fn PdhDll::_PdhOpenQuery = NULL;
|
||||
PdhCloseQuery_Fn PdhDll::_PdhCloseQuery = NULL;
|
||||
PdhCollectQueryData_Fn PdhDll::_PdhCollectQueryData = NULL;
|
||||
PdhGetFormattedCounterValue_Fn PdhDll::_PdhGetFormattedCounterValue = NULL;
|
||||
PdhEnumObjectItems_Fn PdhDll::_PdhEnumObjectItems = NULL;
|
||||
PdhRemoveCounter_Fn PdhDll::_PdhRemoveCounter = NULL;
|
||||
PdhLookupPerfNameByIndex_Fn PdhDll::_PdhLookupPerfNameByIndex = NULL;
|
||||
PdhMakeCounterPath_Fn PdhDll::_PdhMakeCounterPath = NULL;
|
||||
|
||||
LONG PdhDll::_critical_section = 0;
|
||||
LONG PdhDll::_initialized = 0;
|
||||
LONG PdhDll::_pdh_reference_count = 0;
|
||||
HMODULE PdhDll::_hModule = NULL;
|
||||
|
||||
void PdhDll::initialize(void) {
|
||||
_hModule = os::win32::load_Windows_dll("pdh.dll", NULL, 0);
|
||||
if (NULL == _hModule) {
|
||||
return;
|
||||
}
|
||||
// The 'A' at the end means the ANSI (not the UNICODE) vesions of the methods
|
||||
_PdhAddCounter = (PdhAddCounter_Fn)::GetProcAddress(_hModule, "PdhAddCounterA");
|
||||
_PdhOpenQuery = (PdhOpenQuery_Fn)::GetProcAddress(_hModule, "PdhOpenQueryA");
|
||||
_PdhCloseQuery = (PdhCloseQuery_Fn)::GetProcAddress(_hModule, "PdhCloseQuery");
|
||||
_PdhCollectQueryData = (PdhCollectQueryData_Fn)::GetProcAddress(_hModule, "PdhCollectQueryData");
|
||||
_PdhGetFormattedCounterValue = (PdhGetFormattedCounterValue_Fn)::GetProcAddress(_hModule, "PdhGetFormattedCounterValue");
|
||||
_PdhEnumObjectItems = (PdhEnumObjectItems_Fn)::GetProcAddress(_hModule, "PdhEnumObjectItemsA");
|
||||
_PdhRemoveCounter = (PdhRemoveCounter_Fn)::GetProcAddress(_hModule, "PdhRemoveCounter");
|
||||
_PdhLookupPerfNameByIndex = (PdhLookupPerfNameByIndex_Fn)::GetProcAddress(_hModule, "PdhLookupPerfNameByIndexA");
|
||||
_PdhMakeCounterPath = (PdhMakeCounterPath_Fn)::GetProcAddress(_hModule, "PdhMakeCounterPathA");
|
||||
InterlockedExchange(&_initialized, 1);
|
||||
}
|
||||
|
||||
bool PdhDll::PdhDetach(void) {
|
||||
LONG prev_ref_count = InterlockedExchangeAdd(&_pdh_reference_count, -1);
|
||||
BOOL ret = false;
|
||||
if (1 == prev_ref_count) {
|
||||
if (_initialized && _hModule != NULL) {
|
||||
ret = FreeLibrary(_hModule);
|
||||
if (ret) {
|
||||
_hModule = NULL;
|
||||
_PdhAddCounter = NULL;
|
||||
_PdhOpenQuery = NULL;
|
||||
_PdhCloseQuery = NULL;
|
||||
_PdhCollectQueryData = NULL;
|
||||
_PdhGetFormattedCounterValue = NULL;
|
||||
_PdhEnumObjectItems = NULL;
|
||||
_PdhRemoveCounter = NULL;
|
||||
_PdhLookupPerfNameByIndex = NULL;
|
||||
_PdhMakeCounterPath = NULL;
|
||||
InterlockedExchange(&_initialized, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret != 0;
|
||||
}
|
||||
|
||||
bool PdhDll::PdhAttach(void) {
|
||||
InterlockedExchangeAdd(&_pdh_reference_count, 1);
|
||||
if (1 == _initialized) {
|
||||
return true;
|
||||
}
|
||||
while (InterlockedCompareExchange(&_critical_section, 1, 0) == 1);
|
||||
if (0 == _initialized) {
|
||||
initialize();
|
||||
}
|
||||
while (InterlockedCompareExchange(&_critical_section, 0, 1) == 0);
|
||||
return (_PdhAddCounter != NULL && _PdhOpenQuery != NULL
|
||||
&& _PdhCloseQuery != NULL && PdhCollectQueryData != NULL
|
||||
&& _PdhGetFormattedCounterValue != NULL && _PdhEnumObjectItems != NULL
|
||||
&& _PdhRemoveCounter != NULL && PdhLookupPerfNameByIndex != NULL
|
||||
&& _PdhMakeCounterPath != NULL);
|
||||
}
|
||||
|
||||
PDH_STATUS PdhDll::PdhAddCounter(HQUERY hQuery, LPCSTR szFullCounterPath, DWORD dwUserData, HCOUNTER* phCounter) {
|
||||
assert(_initialized && _PdhAddCounter != NULL, "PdhAvailable() not yet called");
|
||||
return _PdhAddCounter(hQuery, szFullCounterPath, dwUserData, phCounter);
|
||||
}
|
||||
|
||||
PDH_STATUS PdhDll::PdhOpenQuery(LPCWSTR szDataSource, DWORD dwUserData, HQUERY* phQuery) {
|
||||
assert(_initialized && _PdhOpenQuery != NULL, "PdhAvailable() not yet called");
|
||||
return _PdhOpenQuery(szDataSource, dwUserData, phQuery);
|
||||
}
|
||||
|
||||
DWORD PdhDll::PdhCloseQuery(HQUERY hQuery) {
|
||||
assert(_initialized && _PdhCloseQuery != NULL, "PdhAvailable() not yet called");
|
||||
return _PdhCloseQuery(hQuery);
|
||||
}
|
||||
|
||||
PDH_STATUS PdhDll::PdhCollectQueryData(HQUERY hQuery) {
|
||||
assert(_initialized && _PdhCollectQueryData != NULL, "PdhAvailable() not yet called");
|
||||
return _PdhCollectQueryData(hQuery);
|
||||
}
|
||||
|
||||
DWORD PdhDll::PdhGetFormattedCounterValue(HCOUNTER hCounter, DWORD dwFormat, LPDWORD lpdwType, PPDH_FMT_COUNTERVALUE pValue) {
|
||||
assert(_initialized && _PdhGetFormattedCounterValue != NULL, "PdhAvailable() not yet called");
|
||||
return _PdhGetFormattedCounterValue(hCounter, dwFormat, lpdwType, pValue);
|
||||
}
|
||||
|
||||
PDH_STATUS PdhDll::PdhEnumObjectItems(LPCTSTR szDataSource, LPCTSTR szMachineName, LPCTSTR szObjectName,
|
||||
LPTSTR mszCounterList, LPDWORD pcchCounterListLength, LPTSTR mszInstanceList,
|
||||
LPDWORD pcchInstanceListLength, DWORD dwDetailLevel, DWORD dwFlags) {
|
||||
assert(_initialized && _PdhEnumObjectItems != NULL, "PdhAvailable() not yet called");
|
||||
return _PdhEnumObjectItems(szDataSource, szMachineName, szObjectName, mszCounterList, pcchCounterListLength,
|
||||
mszInstanceList, pcchInstanceListLength, dwDetailLevel, dwFlags);
|
||||
}
|
||||
|
||||
PDH_STATUS PdhDll::PdhRemoveCounter(HCOUNTER hCounter) {
|
||||
assert(_initialized && _PdhRemoveCounter != NULL, "PdhAvailable() not yet called");
|
||||
return _PdhRemoveCounter(hCounter);
|
||||
}
|
||||
|
||||
PDH_STATUS PdhDll::PdhLookupPerfNameByIndex(LPCSTR szMachineName, DWORD dwNameIndex, LPSTR szNameBuffer, LPDWORD pcchNameBufferSize) {
|
||||
assert(_initialized && _PdhLookupPerfNameByIndex != NULL, "PdhAvailable() not yet called");
|
||||
return _PdhLookupPerfNameByIndex(szMachineName, dwNameIndex, szNameBuffer, pcchNameBufferSize);
|
||||
}
|
||||
|
||||
PDH_STATUS PdhDll::PdhMakeCounterPath(PDH_COUNTER_PATH_ELEMENTS* pCounterPathElements, LPTSTR szFullPathBuffer, LPDWORD pcchBufferSize, DWORD dwFlags) {
|
||||
assert(_initialized && _PdhMakeCounterPath != NULL, "PdhAvailable() not yet called");
|
||||
return _PdhMakeCounterPath(pCounterPathElements, szFullPathBuffer, pcchBufferSize, dwFlags);
|
||||
}
|
||||
|
||||
bool PdhDll::PdhStatusFail(PDH_STATUS pdhStat) {
|
||||
return pdhStat != ERROR_SUCCESS && pdhStat != PDH_MORE_DATA;
|
||||
}
|
64
src/hotspot/os/windows/pdh_interface.hpp
Normal file
64
src/hotspot/os/windows/pdh_interface.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef OS_WINDOWS_VM_PDH_INTERFACE_HPP
|
||||
#define OS_WINDOWS_VM_PDH_INTERFACE_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include <pdh.h>
|
||||
#include <pdhmsg.h>
|
||||
|
||||
class PdhDll: public AllStatic {
|
||||
private:
|
||||
static LONG _pdh_reference_count;
|
||||
static LONG _critical_section;
|
||||
static LONG _initialized;
|
||||
static HMODULE _hModule;
|
||||
static void initialize();
|
||||
static PDH_STATUS (WINAPI *_PdhAddCounter)(HQUERY, LPCSTR, DWORD, HCOUNTER*);
|
||||
static PDH_STATUS (WINAPI *_PdhOpenQuery)(LPCWSTR, DWORD, HQUERY*);
|
||||
static DWORD (WINAPI *_PdhCloseQuery)(HQUERY);
|
||||
static PDH_STATUS (WINAPI *_PdhCollectQueryData)(HQUERY);
|
||||
static DWORD (WINAPI *_PdhGetFormattedCounterValue)(HCOUNTER, DWORD, LPDWORD, PPDH_FMT_COUNTERVALUE);
|
||||
static PDH_STATUS (WINAPI *_PdhEnumObjectItems)(LPCTSTR, LPCTSTR, LPCTSTR, LPTSTR, LPDWORD, LPTSTR, LPDWORD, DWORD, DWORD);
|
||||
static PDH_STATUS (WINAPI *_PdhRemoveCounter)(HCOUNTER);
|
||||
static PDH_STATUS (WINAPI *_PdhLookupPerfNameByIndex)(LPCSTR, DWORD, LPSTR, LPDWORD);
|
||||
static PDH_STATUS (WINAPI *_PdhMakeCounterPath)(PPDH_COUNTER_PATH_ELEMENTS, LPTSTR, LPDWORD, DWORD);
|
||||
|
||||
public:
|
||||
static PDH_STATUS PdhAddCounter(HQUERY, LPCSTR, DWORD, HCOUNTER*);
|
||||
static PDH_STATUS PdhOpenQuery(LPCWSTR, DWORD, HQUERY*);
|
||||
static DWORD PdhCloseQuery(HQUERY);
|
||||
static PDH_STATUS PdhCollectQueryData(HQUERY);
|
||||
static DWORD PdhGetFormattedCounterValue(HCOUNTER, DWORD, LPDWORD, PPDH_FMT_COUNTERVALUE);
|
||||
static PDH_STATUS PdhEnumObjectItems(LPCTSTR, LPCTSTR, LPCTSTR, LPTSTR, LPDWORD, LPTSTR, LPDWORD, DWORD, DWORD);
|
||||
static PDH_STATUS PdhRemoveCounter(HCOUNTER);
|
||||
static PDH_STATUS PdhLookupPerfNameByIndex(LPCSTR, DWORD, LPSTR, LPDWORD);
|
||||
static PDH_STATUS PdhMakeCounterPath(PPDH_COUNTER_PATH_ELEMENTS, LPTSTR, LPDWORD, DWORD);
|
||||
static bool PdhStatusFail(PDH_STATUS pdhStat);
|
||||
static bool PdhAttach();
|
||||
static bool PdhDetach();
|
||||
};
|
||||
|
||||
#endif // OS_WINDOWS_VM_PDH_INTERFACE_HPP
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2018, 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
|
||||
@ -27,6 +27,8 @@
|
||||
|
||||
#include "runtime/os.hpp"
|
||||
|
||||
extern "C" jlong _raw_rdtsc(); // In .il file
|
||||
|
||||
inline jlong os::rdtsc() { return _raw_rdtsc(); }
|
||||
|
||||
#endif // OS_CPU_SOLARIS_X86_VM_OS_SOLARIS_X86_INLINE_HPP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2018, 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
|
||||
@ -33,6 +33,7 @@
|
||||
#include "c1/c1_ValueType.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
#include "jfr/support/jfrIntrinsics.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
@ -41,6 +42,7 @@
|
||||
#include "runtime/interfaceSupport.inline.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "utilities/bitMap.inline.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
|
||||
Compiler::Compiler() : AbstractCompiler(compiler_c1) {
|
||||
@ -222,10 +224,10 @@ bool Compiler::is_intrinsic_supported(const methodHandle& method) {
|
||||
case vmIntrinsics::_compareAndSetObject:
|
||||
case vmIntrinsics::_getCharStringU:
|
||||
case vmIntrinsics::_putCharStringU:
|
||||
#ifdef TRACE_HAVE_INTRINSICS
|
||||
#ifdef JFR_HAVE_INTRINSICS
|
||||
case vmIntrinsics::_counterTime:
|
||||
case vmIntrinsics::_getBufferWriter:
|
||||
#if defined(_LP64) || !defined(TRACE_ID_CLASS_SHIFT)
|
||||
case vmIntrinsics::_getEventWriter:
|
||||
#if defined(_LP64) || !defined(TRACE_ID_SHIFT)
|
||||
case vmIntrinsics::_getClassId:
|
||||
#endif
|
||||
#endif
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "ci/ciUtilities.inline.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "interpreter/bytecode.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
@ -4300,6 +4301,30 @@ void GraphBuilder::append_char_access(ciMethod* callee, bool is_store) {
|
||||
}
|
||||
}
|
||||
|
||||
static void post_inlining_event(EventCompilerInlining* event,
|
||||
int compile_id,
|
||||
const char* msg,
|
||||
bool success,
|
||||
int bci,
|
||||
ciMethod* caller,
|
||||
ciMethod* callee) {
|
||||
assert(caller != NULL, "invariant");
|
||||
assert(callee != NULL, "invariant");
|
||||
assert(event != NULL, "invariant");
|
||||
assert(event->should_commit(), "invariant");
|
||||
JfrStructCalleeMethod callee_struct;
|
||||
callee_struct.set_type(callee->holder()->name()->as_utf8());
|
||||
callee_struct.set_name(callee->name()->as_utf8());
|
||||
callee_struct.set_descriptor(callee->signature()->as_symbol()->as_utf8());
|
||||
event->set_compileId(compile_id);
|
||||
event->set_message(msg);
|
||||
event->set_succeeded(success);
|
||||
event->set_bci(bci);
|
||||
event->set_caller(caller->get_Method());
|
||||
event->set_callee(callee_struct);
|
||||
event->commit();
|
||||
}
|
||||
|
||||
void GraphBuilder::print_inlining(ciMethod* callee, const char* msg, bool success) {
|
||||
CompileLog* log = compilation()->log();
|
||||
if (log != NULL) {
|
||||
@ -4315,18 +4340,10 @@ void GraphBuilder::print_inlining(ciMethod* callee, const char* msg, bool succes
|
||||
log->inline_fail("reason unknown");
|
||||
}
|
||||
}
|
||||
#if INCLUDE_TRACE
|
||||
EventCompilerInlining event;
|
||||
if (event.should_commit()) {
|
||||
event.set_compileId(compilation()->env()->task()->compile_id());
|
||||
event.set_message(msg);
|
||||
event.set_succeeded(success);
|
||||
event.set_bci(bci());
|
||||
event.set_caller(method()->get_Method());
|
||||
event.set_callee(callee->to_trace_struct());
|
||||
event.commit();
|
||||
post_inlining_event(&event, compilation()->env()->task()->compile_id(), msg, success, bci(), method(), callee);
|
||||
}
|
||||
#endif // INCLUDE_TRACE
|
||||
|
||||
CompileTask::print_inlining_ul(callee, scope()->level(), bci(), msg);
|
||||
|
||||
|
@ -42,9 +42,6 @@
|
||||
#include "runtime/vm_version.hpp"
|
||||
#include "utilities/bitMap.inline.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#ifdef TRACE_HAVE_INTRINSICS
|
||||
#include "trace/traceMacros.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef ASSERT
|
||||
#define __ gen()->lir(__FILE__, __LINE__)->
|
||||
@ -2916,7 +2913,7 @@ void LIRGenerator::do_IfOp(IfOp* x) {
|
||||
__ cmove(lir_cond(x->cond()), t_val.result(), f_val.result(), reg, as_BasicType(x->x()->type()));
|
||||
}
|
||||
|
||||
#ifdef TRACE_HAVE_INTRINSICS
|
||||
#ifdef JFR_HAVE_INTRINSICS
|
||||
void LIRGenerator::do_ClassIDIntrinsic(Intrinsic* x) {
|
||||
CodeEmitInfo* info = state_for(x);
|
||||
CodeEmitInfo* info2 = new CodeEmitInfo(info); // Clone for the second null check
|
||||
@ -2928,7 +2925,7 @@ void LIRGenerator::do_ClassIDIntrinsic(Intrinsic* x) {
|
||||
LIR_Opr klass = new_register(T_METADATA);
|
||||
__ move(new LIR_Address(arg.result(), java_lang_Class::klass_offset_in_bytes(), T_ADDRESS), klass, info);
|
||||
LIR_Opr id = new_register(T_LONG);
|
||||
ByteSize offset = TRACE_KLASS_TRACE_ID_OFFSET;
|
||||
ByteSize offset = KLASS_TRACE_ID_OFFSET;
|
||||
LIR_Address* trace_id_addr = new LIR_Address(klass, in_bytes(offset), T_LONG);
|
||||
|
||||
__ move(trace_id_addr, id);
|
||||
@ -2938,18 +2935,18 @@ void LIRGenerator::do_ClassIDIntrinsic(Intrinsic* x) {
|
||||
#ifdef TRACE_ID_META_BITS
|
||||
__ logical_and(id, LIR_OprFact::longConst(~TRACE_ID_META_BITS), id);
|
||||
#endif
|
||||
#ifdef TRACE_ID_CLASS_SHIFT
|
||||
__ unsigned_shift_right(id, TRACE_ID_CLASS_SHIFT, id);
|
||||
#ifdef TRACE_ID_SHIFT
|
||||
__ unsigned_shift_right(id, TRACE_ID_SHIFT, id);
|
||||
#endif
|
||||
|
||||
__ move(id, rlock_result(x));
|
||||
}
|
||||
|
||||
void LIRGenerator::do_getBufferWriter(Intrinsic* x) {
|
||||
void LIRGenerator::do_getEventWriter(Intrinsic* x) {
|
||||
LabelObj* L_end = new LabelObj();
|
||||
|
||||
LIR_Address* jobj_addr = new LIR_Address(getThreadPointer(),
|
||||
in_bytes(TRACE_THREAD_DATA_WRITER_OFFSET),
|
||||
in_bytes(THREAD_LOCAL_WRITER_OFFSET_JFR),
|
||||
T_OBJECT);
|
||||
LIR_Opr result = rlock_result(x);
|
||||
__ move_wide(jobj_addr, result);
|
||||
@ -2987,15 +2984,15 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef TRACE_HAVE_INTRINSICS
|
||||
#ifdef JFR_HAVE_INTRINSICS
|
||||
case vmIntrinsics::_getClassId:
|
||||
do_ClassIDIntrinsic(x);
|
||||
break;
|
||||
case vmIntrinsics::_getBufferWriter:
|
||||
do_getBufferWriter(x);
|
||||
case vmIntrinsics::_getEventWriter:
|
||||
do_getEventWriter(x);
|
||||
break;
|
||||
case vmIntrinsics::_counterTime:
|
||||
do_RuntimeCall(CAST_FROM_FN_PTR(address, TRACE_TIME_METHOD), x);
|
||||
do_RuntimeCall(CAST_FROM_FN_PTR(address, JFR_TIME_FUNCTION), x);
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "c1/c1_LIR.hpp"
|
||||
#include "ci/ciMethodData.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "jfr/support/jfrIntrinsics.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/sizes.hpp"
|
||||
|
||||
@ -459,9 +460,9 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
|
||||
SwitchRangeArray* create_lookup_ranges(LookupSwitch* x);
|
||||
void do_SwitchRanges(SwitchRangeArray* x, LIR_Opr value, BlockBegin* default_sux);
|
||||
|
||||
#ifdef TRACE_HAVE_INTRINSICS
|
||||
#ifdef JFR_HAVE_INTRINSICS
|
||||
void do_ClassIDIntrinsic(Intrinsic* x);
|
||||
void do_getBufferWriter(Intrinsic* x);
|
||||
void do_getEventWriter(Intrinsic* x);
|
||||
#endif
|
||||
|
||||
void do_RuntimeCall(address routine, Intrinsic* x);
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "interpreter/bytecode.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "jfr/support/jfrIntrinsics.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
@ -320,8 +321,8 @@ const char* Runtime1::name_for_address(address entry) {
|
||||
FUNCTION_CASE(entry, SharedRuntime::dtrace_method_exit);
|
||||
FUNCTION_CASE(entry, is_instance_of);
|
||||
FUNCTION_CASE(entry, trace_block_entry);
|
||||
#ifdef TRACE_HAVE_INTRINSICS
|
||||
FUNCTION_CASE(entry, TRACE_TIME_METHOD);
|
||||
#ifdef JFR_HAVE_INTRINSICS
|
||||
FUNCTION_CASE(entry, JFR_TIME_FUNCTION);
|
||||
#endif
|
||||
FUNCTION_CASE(entry, StubRoutines::updateBytesCRC32());
|
||||
FUNCTION_CASE(entry, StubRoutines::updateBytesCRC32C());
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "gc/shared/collectedHeap.inline.hpp"
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
@ -60,7 +61,6 @@
|
||||
#include "runtime/safepointVerifiers.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
#include "utilities/dtrace.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#ifdef COMPILER1
|
||||
@ -1144,7 +1144,6 @@ void ciEnv::record_failure(const char* reason) {
|
||||
}
|
||||
|
||||
void ciEnv::report_failure(const char* reason) {
|
||||
// Create and fire JFR event
|
||||
EventCompilationFailure event;
|
||||
if (event.should_commit()) {
|
||||
event.set_compileId(compile_id());
|
||||
|
@ -48,7 +48,6 @@
|
||||
#include "runtime/deoptimization.hpp"
|
||||
#include "utilities/bitMap.inline.hpp"
|
||||
#include "utilities/xmlstream.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
#ifdef COMPILER2
|
||||
#include "ci/bcEscapeAnalyzer.hpp"
|
||||
#include "ci/ciTypeFlow.hpp"
|
||||
@ -1495,13 +1494,3 @@ bool ciMethod::is_consistent_info(ciMethod* declared_method, ciMethod* resolved_
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
#if INCLUDE_TRACE
|
||||
TraceStructCalleeMethod ciMethod::to_trace_struct() const {
|
||||
TraceStructCalleeMethod result;
|
||||
result.set_type(holder()->name()->as_utf8());
|
||||
result.set_name(name()->as_utf8());
|
||||
result.set_descriptor(signature()->as_symbol()->as_utf8());
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include "compiler/methodLiveness.hpp"
|
||||
#include "prims/methodHandles.hpp"
|
||||
#include "utilities/bitMap.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
|
||||
class ciMethodBlocks;
|
||||
class MethodLiveness;
|
||||
@ -362,10 +361,6 @@ class ciMethod : public ciMetadata {
|
||||
void print_short_name(outputStream* st = tty);
|
||||
|
||||
static bool is_consistent_info(ciMethod* declared_method, ciMethod* resolved_method);
|
||||
|
||||
#if INCLUDE_TRACE
|
||||
TraceStructCalleeMethod to_trace_struct() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CI_CIMETHOD_HPP
|
||||
|
@ -67,7 +67,6 @@
|
||||
#include "runtime/timer.hpp"
|
||||
#include "services/classLoadingService.hpp"
|
||||
#include "services/threadService.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/bitMap.inline.hpp"
|
||||
#include "utilities/copy.hpp"
|
||||
@ -80,6 +79,9 @@
|
||||
#if INCLUDE_CDS
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
#endif
|
||||
#if INCLUDE_JFR
|
||||
#include "jfr/support/jfrTraceIdExtension.hpp"
|
||||
#endif
|
||||
|
||||
// We generally try to create the oops directly when parsing, rather than
|
||||
// allocating temporary data structures and copying the bytes twice. A
|
||||
@ -5639,7 +5641,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_INIT_ID(ik);
|
||||
JFR_ONLY(INIT_ID(ik);)
|
||||
|
||||
// If we reach here, all is well.
|
||||
// Now remove the InstanceKlass* from the _klass_to_deallocate field
|
||||
|
@ -76,8 +76,10 @@
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
#if INCLUDE_TRACE
|
||||
#include "trace/tracing.hpp"
|
||||
#include "utilities/ticks.hpp"
|
||||
#if INCLUDE_JFR
|
||||
#include "jfr/jfr.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#endif
|
||||
|
||||
volatile size_t ClassLoaderDataGraph::_num_array_classes = 0;
|
||||
@ -161,7 +163,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) :
|
||||
|
||||
NOT_PRODUCT(_dependency_count = 0); // number of class loader dependencies
|
||||
|
||||
TRACE_INIT_ID(this);
|
||||
JFR_ONLY(INIT_ID(this);)
|
||||
}
|
||||
|
||||
ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() {
|
||||
@ -1276,6 +1278,28 @@ bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) {
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
||||
#if INCLUDE_JFR
|
||||
static Ticks class_unload_time;
|
||||
static void post_class_unload_event(Klass* const k) {
|
||||
assert(k != NULL, "invariant");
|
||||
EventClassUnload event(UNTIMED);
|
||||
event.set_endtime(class_unload_time);
|
||||
event.set_unloadedClass(k);
|
||||
event.set_definingClassLoader(k->class_loader_data());
|
||||
event.commit();
|
||||
}
|
||||
|
||||
static void post_class_unload_events() {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
|
||||
if (Jfr::is_enabled()) {
|
||||
if (EventClassUnload::is_enabled()) {
|
||||
class_unload_time = Ticks::now();
|
||||
ClassLoaderDataGraph::classes_unloading_do(&post_class_unload_event);
|
||||
}
|
||||
Jfr::on_unloading_classes();
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_JFR
|
||||
|
||||
// Move class loader data from main list to the unloaded list for unloading
|
||||
// and deallocation later.
|
||||
@ -1353,8 +1377,7 @@ bool ClassLoaderDataGraph::do_unloading(bool clean_previous_versions) {
|
||||
}
|
||||
data = data->next();
|
||||
}
|
||||
|
||||
post_class_unload_events();
|
||||
JFR_ONLY(post_class_unload_events();)
|
||||
}
|
||||
|
||||
log_debug(class, loader, data)("do_unloading: loaders processed %u, loaders removed %u", loaders_processed, loaders_removed);
|
||||
@ -1393,20 +1416,6 @@ int ClassLoaderDataGraph::resize_if_needed() {
|
||||
return resized;
|
||||
}
|
||||
|
||||
void ClassLoaderDataGraph::post_class_unload_events() {
|
||||
#if INCLUDE_TRACE
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
|
||||
if (Tracing::enabled()) {
|
||||
if (Tracing::is_event_enabled(TraceClassUnloadEvent)) {
|
||||
assert(_unloading != NULL, "need class loader data unload list!");
|
||||
_class_unload_time = Ticks::now();
|
||||
classes_unloading_do(&class_unload_event);
|
||||
}
|
||||
Tracing::on_unloading_classes();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic()
|
||||
: _next_klass(NULL) {
|
||||
ClassLoaderData* cld = ClassLoaderDataGraph::_head;
|
||||
@ -1490,20 +1499,3 @@ void ClassLoaderDataGraph::print_on(outputStream * const out) {
|
||||
}
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
||||
#if INCLUDE_TRACE
|
||||
|
||||
Ticks ClassLoaderDataGraph::_class_unload_time;
|
||||
|
||||
void ClassLoaderDataGraph::class_unload_event(Klass* const k) {
|
||||
assert(k != NULL, "invariant");
|
||||
|
||||
// post class unload event
|
||||
EventClassUnload event(UNTIMED);
|
||||
event.set_endtime(_class_unload_time);
|
||||
event.set_unloadedClass(k);
|
||||
event.set_definingClassLoader(k->class_loader_data());
|
||||
event.commit();
|
||||
}
|
||||
|
||||
#endif // INCLUDE_TRACE
|
||||
|
@ -31,13 +31,13 @@
|
||||
#include "oops/oopHandle.hpp"
|
||||
#include "oops/weakHandle.hpp"
|
||||
#include "runtime/mutex.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#if INCLUDE_TRACE
|
||||
#include "utilities/ticks.hpp"
|
||||
#if INCLUDE_JFR
|
||||
#include "jfr/support/jfrTraceIdExtension.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// A class loader represents a linkset. Conceptually, a linkset identifies
|
||||
// the complete transitive closure of resolved links that a dynamic linker can
|
||||
@ -85,7 +85,6 @@ class ClassLoaderDataGraph : public AllStatic {
|
||||
|
||||
static ClassLoaderData* add_to_graph(Handle class_loader, bool anonymous);
|
||||
static ClassLoaderData* add(Handle class_loader, bool anonymous);
|
||||
static void post_class_unload_events();
|
||||
public:
|
||||
static ClassLoaderData* find_or_create(Handle class_loader);
|
||||
static void purge();
|
||||
@ -167,12 +166,6 @@ class ClassLoaderDataGraph : public AllStatic {
|
||||
#ifndef PRODUCT
|
||||
static bool contains_loader_data(ClassLoaderData* loader_data);
|
||||
#endif
|
||||
|
||||
#if INCLUDE_TRACE
|
||||
private:
|
||||
static Ticks _class_unload_time;
|
||||
static void class_unload_event(Klass* const k);
|
||||
#endif
|
||||
};
|
||||
|
||||
// ClassLoaderData class
|
||||
@ -268,7 +261,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
// JFR support
|
||||
Klass* _class_loader_klass;
|
||||
Symbol* _class_loader_name;
|
||||
TRACE_DEFINE_TRACE_ID_FIELD;
|
||||
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
|
||||
|
||||
void set_next(ClassLoaderData* next) { _next = next; }
|
||||
ClassLoaderData* next() const { return _next; }
|
||||
@ -410,7 +403,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
|
||||
Klass* class_loader_klass() const { return _class_loader_klass; }
|
||||
Symbol* class_loader_name() const { return _class_loader_name; }
|
||||
TRACE_DEFINE_TRACE_ID_METHODS;
|
||||
JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
|
||||
};
|
||||
|
||||
// An iterator that distributes Klasses to parallel worker threads.
|
||||
|
@ -35,7 +35,11 @@
|
||||
#include "prims/jvmtiEnvBase.hpp"
|
||||
#include "prims/jvmtiRedefineClasses.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#if INCLUDE_JFR
|
||||
#include "jfr/support/jfrKlassExtension.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
// called during initial loading of a shared class
|
||||
InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
|
||||
@ -228,7 +232,7 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
|
||||
result->store_fingerprint(stream->compute_fingerprint());
|
||||
}
|
||||
|
||||
TRACE_KLASS_CREATION(result, parser, THREAD);
|
||||
JFR_ONLY(ON_KLASS_CREATION(result, parser, THREAD);)
|
||||
|
||||
#if INCLUDE_CDS
|
||||
if (DumpSharedSpaces) {
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include "oops/symbol.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/hashtable.inline.hpp"
|
||||
@ -215,7 +214,7 @@ void ModuleEntry::purge_reads() {
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleEntry::module_reads_do(ModuleClosure* const f) {
|
||||
void ModuleEntry::module_reads_do(ModuleClosure* f) {
|
||||
assert_locked_or_safepoint(Module_lock);
|
||||
assert(f != NULL, "invariant");
|
||||
|
||||
@ -279,7 +278,7 @@ ModuleEntry* ModuleEntry::new_unnamed_module_entry(Handle module_handle, ClassLo
|
||||
entry->set_loader_data(cld);
|
||||
entry->_is_open = true;
|
||||
|
||||
TRACE_INIT_ID(entry);
|
||||
JFR_ONLY(INIT_ID(entry);)
|
||||
|
||||
return entry;
|
||||
}
|
||||
@ -367,7 +366,7 @@ ModuleEntry* ModuleEntryTable::new_entry(unsigned int hash, Handle module_handle
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_INIT_ID(entry);
|
||||
JFR_ONLY(INIT_ID(entry);)
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
@ -32,10 +32,13 @@
|
||||
#include "oops/symbol.hpp"
|
||||
#include "runtime/jniHandles.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/hashtable.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
#if INCLUDE_JFR
|
||||
#include "jfr/support/jfrTraceIdExtension.hpp"
|
||||
#endif
|
||||
|
||||
#define UNNAMED_MODULE "Unnamed Module"
|
||||
#define JAVAPKG "java"
|
||||
@ -69,7 +72,7 @@ private:
|
||||
bool _must_walk_reads; // walk module's reads list at GC safepoints to purge out dead modules
|
||||
bool _is_open; // whether the packages in the module are all unqualifiedly exported
|
||||
bool _is_patched; // whether the module is patched via --patch-module
|
||||
TRACE_DEFINE_TRACE_ID_FIELD;
|
||||
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
|
||||
enum {MODULE_READS_SIZE = 101}; // Initial size of list of modules that the module can read.
|
||||
|
||||
public:
|
||||
@ -164,8 +167,6 @@ public:
|
||||
// iteration support for readability
|
||||
void module_reads_do(ModuleClosure* const f);
|
||||
|
||||
TRACE_DEFINE_TRACE_ID_METHODS;
|
||||
|
||||
// Purge dead weak references out of reads list when any given class loader is unloaded.
|
||||
void purge_reads();
|
||||
void delete_reads();
|
||||
@ -178,12 +179,14 @@ public:
|
||||
|
||||
void print(outputStream* st = tty);
|
||||
void verify();
|
||||
|
||||
JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
|
||||
};
|
||||
|
||||
// Iterator interface
|
||||
class ModuleClosure: public StackObj {
|
||||
public:
|
||||
virtual void do_module(ModuleEntry* const module) = 0;
|
||||
virtual void do_module(ModuleEntry* module) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/hashtable.inline.hpp"
|
||||
@ -200,7 +199,7 @@ PackageEntry* PackageEntryTable::new_entry(unsigned int hash, Symbol* name, Modu
|
||||
assert(Module_lock->owned_by_self(), "should have the Module_lock");
|
||||
PackageEntry* entry = (PackageEntry*)Hashtable<Symbol*, mtModule>::allocate_new_entry(hash, name);
|
||||
|
||||
TRACE_INIT_ID(entry);
|
||||
JFR_ONLY(INIT_ID(entry);)
|
||||
|
||||
// Initialize fields specific to a PackageEntry
|
||||
entry->init();
|
||||
@ -283,7 +282,7 @@ void PackageEntryTable::verify_javabase_packages(GrowableArray<Symbol*> *pkg_lis
|
||||
}
|
||||
|
||||
// iteration of qualified exports
|
||||
void PackageEntry::package_exports_do(ModuleClosure* const f) {
|
||||
void PackageEntry::package_exports_do(ModuleClosure* f) {
|
||||
assert_locked_or_safepoint(Module_lock);
|
||||
assert(f != NULL, "invariant");
|
||||
|
||||
|
@ -29,7 +29,12 @@
|
||||
#include "oops/symbol.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/hashtable.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
#if INCLUDE_JFR
|
||||
#include "jfr/support/jfrTraceIdExtension.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
// A PackageEntry basically represents a Java package. It contains:
|
||||
// - Symbol* containing the package's name.
|
||||
@ -104,7 +109,7 @@ private:
|
||||
// Contains list of modules this package is qualifiedly exported to. Access
|
||||
// to this list is protected by the Module_lock.
|
||||
GrowableArray<ModuleEntry*>* _qualified_exports;
|
||||
TRACE_DEFINE_TRACE_ID_FIELD;
|
||||
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
|
||||
|
||||
// Initial size of a package entry's list of qualified exports.
|
||||
enum {QUAL_EXP_SIZE = 43};
|
||||
@ -197,9 +202,9 @@ public:
|
||||
}
|
||||
|
||||
// iteration of qualified exports
|
||||
void package_exports_do(ModuleClosure* const f);
|
||||
void package_exports_do(ModuleClosure* f);
|
||||
|
||||
TRACE_DEFINE_TRACE_ID_METHODS;
|
||||
JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
|
||||
|
||||
// Purge dead weak references out of exported list when any given class loader is unloaded.
|
||||
void purge_qualified_exports();
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "gc/shared/oopStorage.inline.hpp"
|
||||
#include "interpreter/bytecodeStream.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/filemap.hpp"
|
||||
@ -81,7 +82,6 @@
|
||||
#include "services/classLoadingService.hpp"
|
||||
#include "services/diagnosticCommand.hpp"
|
||||
#include "services/threadService.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#if INCLUDE_CDS
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
@ -623,32 +623,16 @@ InstanceKlass* SystemDictionary::handle_parallel_super_load(
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void post_class_load_event(EventClassLoad* event,
|
||||
const InstanceKlass* k,
|
||||
const ClassLoaderData* init_cld) {
|
||||
#if INCLUDE_TRACE
|
||||
static void post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) {
|
||||
assert(event != NULL, "invariant");
|
||||
assert(k != NULL, "invariant");
|
||||
if (event->should_commit()) {
|
||||
event->set_loadedClass(k);
|
||||
event->set_definingClassLoader(k->class_loader_data());
|
||||
event->set_initiatingClassLoader(init_cld);
|
||||
event->commit();
|
||||
}
|
||||
#endif // INCLUDE_TRACE
|
||||
assert(event->should_commit(), "invariant");
|
||||
event->set_loadedClass(k);
|
||||
event->set_definingClassLoader(k->class_loader_data());
|
||||
event->set_initiatingClassLoader(init_cld);
|
||||
event->commit();
|
||||
}
|
||||
|
||||
static void class_define_event(InstanceKlass* k,
|
||||
const ClassLoaderData* def_cld) {
|
||||
#if INCLUDE_TRACE
|
||||
EventClassDefine event;
|
||||
if (event.should_commit()) {
|
||||
event.set_definedClass(k);
|
||||
event.set_definingClassLoader(def_cld);
|
||||
event.commit();
|
||||
}
|
||||
#endif // INCLUDE_TRACE
|
||||
}
|
||||
|
||||
// Be careful when modifying this code: once you have run
|
||||
// placeholders()->find_and_add(PlaceholderTable::LOAD_INSTANCE),
|
||||
@ -881,9 +865,9 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
|
||||
if (HAS_PENDING_EXCEPTION || k == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
post_class_load_event(&class_load_start_event, k, loader_data);
|
||||
|
||||
if (class_load_start_event.should_commit()) {
|
||||
post_class_load_event(&class_load_start_event, k, loader_data);
|
||||
}
|
||||
#ifdef ASSERT
|
||||
{
|
||||
ClassLoaderData* loader_data = k->class_loader_data();
|
||||
@ -1045,8 +1029,9 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
|
||||
assert(THREAD->is_Java_thread(), "thread->is_Java_thread()");
|
||||
JvmtiExport::post_class_load((JavaThread *) THREAD, k);
|
||||
}
|
||||
|
||||
post_class_load_event(&class_load_start_event, k, loader_data);
|
||||
if (class_load_start_event.should_commit()) {
|
||||
post_class_load_event(&class_load_start_event, k, loader_data);
|
||||
}
|
||||
}
|
||||
assert(host_klass != NULL || NULL == cp_patches,
|
||||
"cp_patches only found with host_klass");
|
||||
@ -1558,6 +1543,15 @@ InstanceKlass* SystemDictionary::load_instance_class(Symbol* class_name, Handle
|
||||
}
|
||||
}
|
||||
|
||||
static void post_class_define_event(InstanceKlass* k, const ClassLoaderData* def_cld) {
|
||||
EventClassDefine event;
|
||||
if (event.should_commit()) {
|
||||
event.set_definedClass(k);
|
||||
event.set_definingClassLoader(def_cld);
|
||||
event.commit();
|
||||
}
|
||||
}
|
||||
|
||||
void SystemDictionary::define_instance_class(InstanceKlass* k, TRAPS) {
|
||||
|
||||
HandleMark hm(THREAD);
|
||||
@ -1626,7 +1620,7 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, TRAPS) {
|
||||
JvmtiExport::post_class_load((JavaThread *) THREAD, k);
|
||||
|
||||
}
|
||||
class_define_event(k, loader_data);
|
||||
post_class_define_event(k, loader_data);
|
||||
}
|
||||
|
||||
// Support parallel classloading
|
||||
|
@ -350,7 +350,7 @@ vmIntrinsics::ID vmIntrinsics::for_raw_conversion(BasicType src, BasicType dest)
|
||||
bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) {
|
||||
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
|
||||
switch(id) {
|
||||
#ifdef TRACE_HAVE_INTRINSICS
|
||||
#ifdef JFR_HAVE_INTRINSICS
|
||||
case vmIntrinsics::_counterTime:
|
||||
#endif
|
||||
case vmIntrinsics::_currentTimeMillis:
|
||||
@ -388,7 +388,7 @@ bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) {
|
||||
bool vmIntrinsics::can_trap(vmIntrinsics::ID id) {
|
||||
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
|
||||
switch(id) {
|
||||
#ifdef TRACE_HAVE_INTRINSICS
|
||||
#ifdef JFR_HAVE_INTRINSICS
|
||||
case vmIntrinsics::_counterTime:
|
||||
case vmIntrinsics::_getClassId:
|
||||
#endif
|
||||
@ -424,7 +424,7 @@ bool vmIntrinsics::can_trap(vmIntrinsics::ID id) {
|
||||
bool vmIntrinsics::should_be_pinned(vmIntrinsics::ID id) {
|
||||
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
|
||||
switch(id) {
|
||||
#ifdef TRACE_HAVE_INTRINSICS
|
||||
#ifdef JFR_HAVE_INTRINSICS
|
||||
case vmIntrinsics::_counterTime:
|
||||
#endif
|
||||
case vmIntrinsics::_currentTimeMillis:
|
||||
|
@ -26,10 +26,12 @@
|
||||
#define SHARE_VM_CLASSFILE_VMSYMBOLS_HPP
|
||||
|
||||
#include "classfile/moduleEntry.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
#include "memory/iterator.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
#include "jfr/support/jfrIntrinsics.hpp"
|
||||
#include "jvmci/vmSymbols_jvmci.hpp"
|
||||
#include "memory/iterator.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
|
||||
// The class vmSymbols is a name space for fast lookup of
|
||||
// symbols commonly used in the VM.
|
||||
@ -640,8 +642,8 @@
|
||||
/* forEachRemaining support */ \
|
||||
template(java_util_stream_StreamsRangeIntSpliterator, "java/util/stream/Streams$RangeIntSpliterator") \
|
||||
\
|
||||
/* trace signatures */ \
|
||||
TRACE_TEMPLATES(template) \
|
||||
/* jfr signatures */ \
|
||||
JFR_TEMPLATES(template) \
|
||||
\
|
||||
/* cds */ \
|
||||
template(jdk_internal_loader_ClassLoaders, "jdk/internal/loader/ClassLoaders") \
|
||||
@ -827,7 +829,7 @@
|
||||
do_intrinsic(_nanoTime, java_lang_System, nanoTime_name, void_long_signature, F_S) \
|
||||
do_name( nanoTime_name, "nanoTime") \
|
||||
\
|
||||
TRACE_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias) \
|
||||
JFR_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias) \
|
||||
\
|
||||
do_intrinsic(_arraycopy, java_lang_System, arraycopy_name, arraycopy_signature, F_S) \
|
||||
do_name( arraycopy_name, "arraycopy") \
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "code/nmethod.hpp"
|
||||
#include "code/pcDesc.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
@ -53,7 +54,6 @@
|
||||
#include "runtime/sweeper.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "services/memoryService.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/vmError.hpp"
|
||||
#include "utilities/xmlstream.hpp"
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "compiler/compilerOracle.hpp"
|
||||
#include "compiler/directivesParser.hpp"
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
@ -57,11 +58,11 @@
|
||||
#include "runtime/sweeper.hpp"
|
||||
#include "runtime/timerTrace.hpp"
|
||||
#include "runtime/vframe.inline.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/dtrace.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
#include "utilities/formatBuffer.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#ifdef COMPILER1
|
||||
#include "c1/c1_Compiler.hpp"
|
||||
#endif
|
||||
@ -1945,8 +1946,7 @@ static void codecache_print(outputStream* out, bool detailed) {
|
||||
}
|
||||
}
|
||||
|
||||
void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env) {
|
||||
|
||||
void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, bool success, ciEnv* ci_env) {
|
||||
if (success) {
|
||||
task->mark_success();
|
||||
if (ci_env != NULL) {
|
||||
@ -1959,19 +1959,21 @@ void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, Even
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// simulate crash during compilation
|
||||
assert(task->compile_id() != CICrashAt, "just as planned");
|
||||
if (event.should_commit()) {
|
||||
event.set_method(task->method());
|
||||
event.set_compileId(task->compile_id());
|
||||
event.set_compileLevel(task->comp_level());
|
||||
event.set_succeded(task->is_success());
|
||||
event.set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci);
|
||||
event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
|
||||
event.set_inlinedBytes(task->num_inlined_bytecodes());
|
||||
event.commit();
|
||||
}
|
||||
}
|
||||
|
||||
static void post_compilation_event(EventCompilation* event, CompileTask* task) {
|
||||
assert(event != NULL, "invariant");
|
||||
assert(event->should_commit(), "invariant");
|
||||
event->set_method(task->method());
|
||||
event->set_compileId(task->compile_id());
|
||||
event->set_compileLevel(task->comp_level());
|
||||
event->set_succeded(task->is_success());
|
||||
event->set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci);
|
||||
event->set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
|
||||
event->set_inlinedBytes(task->num_inlined_bytecodes());
|
||||
event->commit();
|
||||
}
|
||||
|
||||
int DirectivesStack::_depth = 0;
|
||||
@ -2066,7 +2068,10 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
||||
compilable = ciEnv::MethodCompilable_not_at_tier;
|
||||
}
|
||||
}
|
||||
post_compile(thread, task, event, task->code() != NULL, NULL);
|
||||
post_compile(thread, task, task->code() != NULL, NULL);
|
||||
if (event.should_commit()) {
|
||||
post_compilation_event(&event, task);
|
||||
}
|
||||
|
||||
} else
|
||||
#endif // INCLUDE_JVMCI
|
||||
@ -2123,7 +2128,10 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
||||
ci_env.report_failure(failure_reason);
|
||||
}
|
||||
|
||||
post_compile(thread, task, event, !ci_env.failing(), &ci_env);
|
||||
post_compile(thread, task, !ci_env.failing(), &ci_env);
|
||||
if (event.should_commit()) {
|
||||
post_compilation_event(&event, task);
|
||||
}
|
||||
}
|
||||
// Remove the JNI handle block after the ciEnv destructor has run in
|
||||
// the previous block.
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include "compiler/compileTask.hpp"
|
||||
#include "compiler/compilerDirectives.hpp"
|
||||
#include "runtime/perfData.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
#include "utilities/stack.hpp"
|
||||
#if INCLUDE_JVMCI
|
||||
#include "jvmci/jvmciCompiler.hpp"
|
||||
@ -252,7 +251,7 @@ class CompileBroker: AllStatic {
|
||||
#endif
|
||||
|
||||
static void invoke_compiler_on_method(CompileTask* task);
|
||||
static void post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env);
|
||||
static void post_compile(CompilerThread* thread, CompileTask* task, bool success, ciEnv* ci_env);
|
||||
static void set_last_compile(CompilerThread *thread, const methodHandle& method, bool is_osr, int comp_level);
|
||||
static void push_jni_handle_block();
|
||||
static void pop_jni_handle_block();
|
||||
|
@ -86,7 +86,6 @@ class STWGCTimer;
|
||||
class G1NewTracer;
|
||||
class EvacuationFailedInfo;
|
||||
class nmethod;
|
||||
class Ticks;
|
||||
class WorkGang;
|
||||
class G1Allocator;
|
||||
class G1ArchiveAllocator;
|
||||
|
@ -23,12 +23,11 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "gc/g1/g1_globals.hpp"
|
||||
#include "gc/g1/g1EvacStats.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
|
||||
void G1EvacStats::log_plab_allocation() {
|
||||
PLABStats::log_plab_allocation();
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "gc/shared/referenceProcessor.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "utilities/ticks.inline.hpp"
|
||||
|
||||
class G1AdjustLiveClosure : public StackObj {
|
||||
G1AdjustClosure* _adjust_closure;
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "utilities/ticks.inline.hpp"
|
||||
#include "utilities/ticks.hpp"
|
||||
|
||||
class G1ResetHumongousClosure : public HeapRegionClosure {
|
||||
G1CMBitMap* _bitmap;
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include "gc/g1/g1StringDedup.hpp"
|
||||
#include "gc/g1/heapRegionManager.hpp"
|
||||
#include "gc/shared/referenceProcessor.hpp"
|
||||
#include "utilities/ticks.hpp"
|
||||
|
||||
class G1CollectedHeap;
|
||||
class G1CMBitMap;
|
||||
|
@ -36,7 +36,7 @@
|
||||
#include "gc/shared/referenceProcessor.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "utilities/ticks.inline.hpp"
|
||||
#include "utilities/ticks.hpp"
|
||||
|
||||
bool G1FullGCPrepareTask::G1CalculatePointersClosure::do_heap_region(HeapRegion* hr) {
|
||||
if (hr->is_humongous()) {
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include "gc/g1/g1StringDedup.hpp"
|
||||
#include "gc/g1/heapRegionManager.hpp"
|
||||
#include "gc/shared/referenceProcessor.hpp"
|
||||
#include "utilities/ticks.hpp"
|
||||
|
||||
class G1CMBitMap;
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/g1FullGCTask.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "utilities/ticks.inline.hpp"
|
||||
#include "utilities/ticks.hpp"
|
||||
|
||||
void G1FullGCTask::log_task(const char* name, uint worker_id, const Ticks& start, const Ticks& stop) {
|
||||
Tickspan duration = stop - start;
|
||||
|
@ -488,7 +488,7 @@ G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times,
|
||||
|
||||
G1GCParPhaseTimesTracker::~G1GCParPhaseTimesTracker() {
|
||||
if (_phase_times != NULL) {
|
||||
_phase_times->record_time_secs(_phase, _worker_id, TicksToTimeHelper::seconds(Ticks::now() - _start_time));
|
||||
_phase_times->record_time_secs(_phase, _worker_id, (Ticks::now() - _start_time).seconds());
|
||||
}
|
||||
}
|
||||
|
||||
@ -506,7 +506,7 @@ G1EvacPhaseTimesTracker::~G1EvacPhaseTimesTracker() {
|
||||
if (_phase_times != NULL) {
|
||||
// Exclude trim time by increasing the start time.
|
||||
_start_time += _trim_time;
|
||||
_phase_times->record_or_add_objcopy_time_secs(_worker_id, TicksToTimeHelper::seconds(_trim_time));
|
||||
_phase_times->record_or_add_objcopy_time_secs(_worker_id, _trim_time.seconds());
|
||||
}
|
||||
}
|
||||
|
||||
|
49
src/hotspot/share/gc/g1/g1HeapRegionEventSender.cpp
Normal file
49
src/hotspot/share/gc/g1/g1HeapRegionEventSender.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.hpp"
|
||||
#include "gc/g1/heapRegion.hpp"
|
||||
#include "g1HeapRegionEventSender.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
|
||||
class DumpEventInfoClosure : public HeapRegionClosure {
|
||||
public:
|
||||
bool do_heap_region(HeapRegion* r) {
|
||||
EventG1HeapRegionInformation evt;
|
||||
evt.set_index(r->hrm_index());
|
||||
evt.set_type(r->get_trace_type());
|
||||
evt.set_start((uintptr_t)r->bottom());
|
||||
evt.set_used(r->used());
|
||||
evt.commit();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void G1HeapRegionEventSender::send_events() {
|
||||
DumpEventInfoClosure c;
|
||||
|
||||
G1CollectedHeap::heap()->heap_region_iterate(&c);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
@ -21,24 +21,15 @@
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_TRACE_NOTRACEBACKEND_HPP
|
||||
#define SHARE_VM_TRACE_NOTRACEBACKEND_HPP
|
||||
|
||||
#include "jni.h"
|
||||
#include "trace/traceTime.hpp"
|
||||
#ifndef SHARE_VM_GC_G1_G1HEAPREGIONEVENTSENDER_HPP
|
||||
#define SHARE_VM_GC_G1_G1HEAPREGIONEVENTSENDER_HPP
|
||||
|
||||
class NoTraceBackend {
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class G1HeapRegionEventSender : public AllStatic {
|
||||
public:
|
||||
static TracingTime time() {
|
||||
return 0;
|
||||
}
|
||||
static void send_events();
|
||||
};
|
||||
|
||||
class TraceThreadData {
|
||||
public:
|
||||
TraceThreadData() {}
|
||||
};
|
||||
|
||||
typedef NoTraceBackend Tracing;
|
||||
|
||||
#endif // SHARE_VM_TRACE_NOTRACEBACKEND_HPP
|
||||
#endif // SHARE_VM_GC_G1_G1HEAPREGIONEVENTSENDER_HPP
|
@ -29,7 +29,6 @@
|
||||
#include "gc/g1/g1RemSet.hpp"
|
||||
#include "oops/access.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "utilities/ticks.inline.hpp"
|
||||
|
||||
template <class T> void G1ParScanThreadState::do_oop_evac(T* p) {
|
||||
// Reference should not be NULL here as such are never pushed to the task queue.
|
||||
|
@ -44,11 +44,12 @@
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/access.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/intHisto.hpp"
|
||||
#include "utilities/stack.inline.hpp"
|
||||
#include "utilities/ticks.inline.hpp"
|
||||
#include "utilities/ticks.hpp"
|
||||
|
||||
// Collects information about the overall remembered set scan progress during an evacuation.
|
||||
class G1RemSetScanState : public CHeapObj<mtGC> {
|
||||
@ -428,15 +429,15 @@ void G1RemSet::scan_rem_set(G1ParScanThreadState* pss, uint worker_i) {
|
||||
|
||||
G1GCPhaseTimes* p = _g1p->phase_times();
|
||||
|
||||
p->record_time_secs(G1GCPhaseTimes::ScanRS, worker_i, TicksToTimeHelper::seconds(cl.rem_set_root_scan_time()));
|
||||
p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, TicksToTimeHelper::seconds(cl.rem_set_trim_partially_time()));
|
||||
p->record_time_secs(G1GCPhaseTimes::ScanRS, worker_i, cl.rem_set_root_scan_time().seconds());
|
||||
p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, cl.rem_set_trim_partially_time().seconds());
|
||||
|
||||
p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_scanned(), G1GCPhaseTimes::ScanRSScannedCards);
|
||||
p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_claimed(), G1GCPhaseTimes::ScanRSClaimedCards);
|
||||
p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_skipped(), G1GCPhaseTimes::ScanRSSkippedCards);
|
||||
|
||||
p->record_time_secs(G1GCPhaseTimes::CodeRoots, worker_i, TicksToTimeHelper::seconds(cl.strong_code_root_scan_time()));
|
||||
p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, TicksToTimeHelper::seconds(cl.strong_code_root_trim_partially_time()));
|
||||
p->record_time_secs(G1GCPhaseTimes::CodeRoots, worker_i, cl.strong_code_root_scan_time().seconds());
|
||||
p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, cl.strong_code_root_trim_partially_time().seconds());
|
||||
}
|
||||
|
||||
// Closure used for updating rem sets. Only called during an evacuation pause.
|
||||
@ -935,7 +936,7 @@ public:
|
||||
"TARS " PTR_FORMAT,
|
||||
region_idx,
|
||||
_cm->liveness(region_idx) * HeapWordSize,
|
||||
TicksToTimeHelper::seconds(time) * 1000.0,
|
||||
time.seconds() * 1000.0,
|
||||
marked_bytes,
|
||||
p2i(hr->bottom()),
|
||||
p2i(top_at_mark_start),
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/heapRegionTracer.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
|
||||
void HeapRegionTracer::send_region_type_change(uint index,
|
||||
G1HeapRegionTraceType::Type from,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2018, 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
|
||||
@ -25,7 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/ageTableTracer.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
|
||||
void AgeTableTracer::send_tenuring_distribution_event(uint age, size_t size) {
|
||||
EventTenuringDistribution e;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2018, 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
|
||||
@ -24,13 +24,16 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/allocTracer.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#if INCLUDE_JFR
|
||||
#include "jfr/support/jfrAllocationTracer.hpp"
|
||||
#endif
|
||||
|
||||
void AllocTracer::send_allocation_outside_tlab(Klass* klass, HeapWord* obj, size_t alloc_size, Thread* thread) {
|
||||
TRACE_ALLOCATION(obj, alloc_size, thread);
|
||||
JFR_ONLY(JfrAllocationTracer tracer(obj, alloc_size, thread);)
|
||||
EventObjectAllocationOutsideTLAB event;
|
||||
if (event.should_commit()) {
|
||||
event.set_objectClass(klass);
|
||||
@ -40,7 +43,7 @@ void AllocTracer::send_allocation_outside_tlab(Klass* klass, HeapWord* obj, size
|
||||
}
|
||||
|
||||
void AllocTracer::send_allocation_in_new_tlab(Klass* klass, HeapWord* obj, size_t tlab_size, size_t alloc_size, Thread* thread) {
|
||||
TRACE_ALLOCATION(obj, tlab_size, thread);
|
||||
JFR_ONLY(JfrAllocationTracer tracer(obj, alloc_size, thread);)
|
||||
EventObjectAllocationInNewTLAB event;
|
||||
if (event.should_commit()) {
|
||||
event.set_objectClass(klass);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
@ -25,8 +25,8 @@
|
||||
#ifndef SHARE_VM_GC_SHARED_COPYFAILEDINFO_HPP
|
||||
#define SHARE_VM_GC_SHARED_COPYFAILEDINFO_HPP
|
||||
|
||||
#include "jfr/support/jfrThreadId.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class CopyFailedInfo : public CHeapObj<mtGC> {
|
||||
@ -72,9 +72,9 @@ class PromotionFailedInfo : public CopyFailedInfo {
|
||||
void register_copy_failure(size_t size) {
|
||||
CopyFailedInfo::register_copy_failure(size);
|
||||
if (_thread_trace_id == 0) {
|
||||
_thread_trace_id = THREAD_TRACE_ID(Thread::current());
|
||||
_thread_trace_id = JFR_THREAD_ID(Thread::current());
|
||||
} else {
|
||||
assert(THREAD_TRACE_ID(Thread::current()) == _thread_trace_id,
|
||||
assert(JFR_THREAD_ID(Thread::current()) == _thread_trace_id,
|
||||
"The PromotionFailedInfo should be thread local.");
|
||||
}
|
||||
}
|
||||
|
159
src/hotspot/share/gc/shared/gcConfiguration.cpp
Normal file
159
src/hotspot/share/gc/shared/gcConfiguration.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "gc/shared/gcConfiguration.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
GCName GCConfiguration::young_collector() const {
|
||||
if (UseG1GC) {
|
||||
return G1New;
|
||||
}
|
||||
|
||||
if (UseParallelGC) {
|
||||
return ParallelScavenge;
|
||||
}
|
||||
|
||||
if (UseConcMarkSweepGC) {
|
||||
return ParNew;
|
||||
}
|
||||
|
||||
return DefNew;
|
||||
}
|
||||
|
||||
GCName GCConfiguration::old_collector() const {
|
||||
if (UseG1GC) {
|
||||
return G1Old;
|
||||
}
|
||||
|
||||
if (UseConcMarkSweepGC) {
|
||||
return ConcurrentMarkSweep;
|
||||
}
|
||||
|
||||
if (UseParallelOldGC) {
|
||||
return ParallelOld;
|
||||
}
|
||||
|
||||
return SerialOld;
|
||||
}
|
||||
|
||||
uint GCConfiguration::num_parallel_gc_threads() const {
|
||||
return ParallelGCThreads;
|
||||
}
|
||||
|
||||
uint GCConfiguration::num_concurrent_gc_threads() const {
|
||||
return ConcGCThreads;
|
||||
}
|
||||
|
||||
bool GCConfiguration::uses_dynamic_gc_threads() const {
|
||||
return UseDynamicNumberOfGCThreads;
|
||||
}
|
||||
|
||||
bool GCConfiguration::is_explicit_gc_concurrent() const {
|
||||
return ExplicitGCInvokesConcurrent;
|
||||
}
|
||||
|
||||
bool GCConfiguration::is_explicit_gc_disabled() const {
|
||||
return DisableExplicitGC;
|
||||
}
|
||||
|
||||
bool GCConfiguration::has_pause_target_default_value() const {
|
||||
return FLAG_IS_DEFAULT(MaxGCPauseMillis);
|
||||
}
|
||||
|
||||
uintx GCConfiguration::pause_target() const {
|
||||
return MaxGCPauseMillis;
|
||||
}
|
||||
|
||||
uintx GCConfiguration::gc_time_ratio() const {
|
||||
return GCTimeRatio;
|
||||
}
|
||||
|
||||
bool GCTLABConfiguration::uses_tlabs() const {
|
||||
return UseTLAB;
|
||||
}
|
||||
|
||||
size_t GCTLABConfiguration::min_tlab_size() const {
|
||||
return MinTLABSize;
|
||||
}
|
||||
|
||||
uint GCTLABConfiguration::tlab_refill_waste_limit() const {
|
||||
return TLABRefillWasteFraction;
|
||||
}
|
||||
|
||||
intx GCSurvivorConfiguration::max_tenuring_threshold() const {
|
||||
return MaxTenuringThreshold;
|
||||
}
|
||||
|
||||
intx GCSurvivorConfiguration::initial_tenuring_threshold() const {
|
||||
return InitialTenuringThreshold;
|
||||
}
|
||||
|
||||
size_t GCHeapConfiguration::max_size() const {
|
||||
return MaxHeapSize;
|
||||
}
|
||||
|
||||
size_t GCHeapConfiguration::min_size() const {
|
||||
return Arguments::min_heap_size();
|
||||
}
|
||||
|
||||
size_t GCHeapConfiguration::initial_size() const {
|
||||
return InitialHeapSize;
|
||||
}
|
||||
|
||||
bool GCHeapConfiguration::uses_compressed_oops() const {
|
||||
return UseCompressedOops;
|
||||
}
|
||||
|
||||
Universe::NARROW_OOP_MODE GCHeapConfiguration::narrow_oop_mode() const {
|
||||
return Universe::narrow_oop_mode();
|
||||
}
|
||||
|
||||
uint GCHeapConfiguration::object_alignment_in_bytes() const {
|
||||
return ObjectAlignmentInBytes;
|
||||
}
|
||||
|
||||
int GCHeapConfiguration::heap_address_size_in_bits() const {
|
||||
return BitsPerHeapOop;
|
||||
}
|
||||
|
||||
bool GCYoungGenerationConfiguration::has_max_size_default_value() const {
|
||||
return FLAG_IS_DEFAULT(MaxNewSize);
|
||||
}
|
||||
|
||||
uintx GCYoungGenerationConfiguration::max_size() const {
|
||||
return MaxNewSize;
|
||||
}
|
||||
|
||||
uintx GCYoungGenerationConfiguration::min_size() const {
|
||||
return NewSize;
|
||||
}
|
||||
|
||||
intx GCYoungGenerationConfiguration::new_ratio() const {
|
||||
return NewRatio;
|
||||
}
|
80
src/hotspot/share/gc/shared/gcConfiguration.hpp
Normal file
80
src/hotspot/share/gc/shared/gcConfiguration.hpp
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_GC_SHARED_GCCONFIGURATION_HPP
|
||||
#define SHARE_VM_GC_SHARED_GCCONFIGURATION_HPP
|
||||
|
||||
#include "gc/shared/gcName.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class GCConfiguration {
|
||||
public:
|
||||
GCName young_collector() const;
|
||||
GCName old_collector() const;
|
||||
uint num_parallel_gc_threads() const;
|
||||
uint num_concurrent_gc_threads() const;
|
||||
bool uses_dynamic_gc_threads() const;
|
||||
bool is_explicit_gc_concurrent() const;
|
||||
bool is_explicit_gc_disabled() const;
|
||||
uintx gc_time_ratio() const;
|
||||
|
||||
bool has_pause_target_default_value() const;
|
||||
uintx pause_target() const;
|
||||
};
|
||||
|
||||
class GCTLABConfiguration {
|
||||
public:
|
||||
bool uses_tlabs() const;
|
||||
size_t min_tlab_size() const;
|
||||
uint tlab_refill_waste_limit() const;
|
||||
};
|
||||
|
||||
class GCSurvivorConfiguration {
|
||||
public:
|
||||
intx initial_tenuring_threshold() const;
|
||||
intx max_tenuring_threshold() const;
|
||||
};
|
||||
|
||||
class GCHeapConfiguration {
|
||||
public:
|
||||
size_t max_size() const;
|
||||
size_t min_size() const;
|
||||
size_t initial_size() const;
|
||||
bool uses_compressed_oops() const;
|
||||
Universe::NARROW_OOP_MODE narrow_oop_mode() const;
|
||||
uint object_alignment_in_bytes() const;
|
||||
int heap_address_size_in_bits() const;
|
||||
};
|
||||
|
||||
class GCYoungGenerationConfiguration {
|
||||
public:
|
||||
bool has_max_size_default_value() const;
|
||||
uintx max_size() const;
|
||||
|
||||
uintx min_size() const;
|
||||
intx new_ratio() const;
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_GC_SHARED_GCCONFIGURATION_HPP
|
@ -25,7 +25,6 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/gcTimer.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/ticks.inline.hpp"
|
||||
|
||||
// the "time" parameter for most functions
|
||||
// has a default value set by Ticks::now()
|
||||
@ -376,7 +375,7 @@ public:
|
||||
GCTimer gc_timer;
|
||||
gc_timer.register_gc_start(1);
|
||||
|
||||
assert(gc_timer.gc_start() == 1, "Incorrect");
|
||||
assert(gc_timer.gc_start() == Ticks(1), "Incorrect");
|
||||
}
|
||||
|
||||
static void gc_end() {
|
||||
@ -384,7 +383,7 @@ public:
|
||||
gc_timer.register_gc_start(1);
|
||||
gc_timer.register_gc_end(2);
|
||||
|
||||
assert(gc_timer.gc_end() == 2, "Incorrect");
|
||||
assert(gc_timer.gc_end() == Ticks(2), "Incorrect");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
@ -35,7 +35,7 @@
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/ticks.inline.hpp"
|
||||
#include "utilities/ticks.hpp"
|
||||
#if INCLUDE_G1GC
|
||||
#include "gc/g1/evacuationInfo.hpp"
|
||||
#endif
|
||||
|
@ -28,10 +28,8 @@
|
||||
#include "gc/shared/gcTimer.hpp"
|
||||
#include "gc/shared/gcTrace.hpp"
|
||||
#include "gc/shared/gcWhen.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "trace/traceBackend.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
#include "tracefiles/traceEventClasses.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#if INCLUDE_G1GC
|
||||
#include "gc/g1/evacuationInfo.hpp"
|
||||
@ -160,8 +158,8 @@ void OldGCTracer::send_old_gc_event() const {
|
||||
}
|
||||
}
|
||||
|
||||
static TraceStructCopyFailed to_trace_struct(const CopyFailedInfo& cf_info) {
|
||||
TraceStructCopyFailed failed_info;
|
||||
static JfrStructCopyFailed to_struct(const CopyFailedInfo& cf_info) {
|
||||
JfrStructCopyFailed failed_info;
|
||||
failed_info.set_objectCount(cf_info.failed_count());
|
||||
failed_info.set_firstSize(cf_info.first_size());
|
||||
failed_info.set_smallestSize(cf_info.smallest_size());
|
||||
@ -173,7 +171,7 @@ void YoungGCTracer::send_promotion_failed_event(const PromotionFailedInfo& pf_in
|
||||
EventPromotionFailed e;
|
||||
if (e.should_commit()) {
|
||||
e.set_gcId(GCId::current());
|
||||
e.set_promotionFailed(to_trace_struct(pf_info));
|
||||
e.set_promotionFailed(to_struct(pf_info));
|
||||
e.set_thread(pf_info.thread_trace_id());
|
||||
e.commit();
|
||||
}
|
||||
@ -231,14 +229,14 @@ void G1NewTracer::send_evacuation_failed_event(const EvacuationFailedInfo& ef_in
|
||||
EventEvacuationFailed e;
|
||||
if (e.should_commit()) {
|
||||
e.set_gcId(GCId::current());
|
||||
e.set_evacuationFailed(to_trace_struct(ef_info));
|
||||
e.set_evacuationFailed(to_struct(ef_info));
|
||||
e.commit();
|
||||
}
|
||||
}
|
||||
|
||||
static TraceStructG1EvacuationStatistics
|
||||
static JfrStructG1EvacuationStatistics
|
||||
create_g1_evacstats(unsigned gcid, const G1EvacSummary& summary) {
|
||||
TraceStructG1EvacuationStatistics s;
|
||||
JfrStructG1EvacuationStatistics s;
|
||||
s.set_gcId(gcid);
|
||||
s.set_allocated(summary.allocated() * HeapWordSize);
|
||||
s.set_wasted(summary.wasted() * HeapWordSize);
|
||||
@ -313,8 +311,8 @@ void G1NewTracer::send_adaptive_ihop_statistics(size_t threshold,
|
||||
|
||||
#endif // INCLUDE_G1GC
|
||||
|
||||
static TraceStructVirtualSpace to_trace_struct(const VirtualSpaceSummary& summary) {
|
||||
TraceStructVirtualSpace space;
|
||||
static JfrStructVirtualSpace to_struct(const VirtualSpaceSummary& summary) {
|
||||
JfrStructVirtualSpace space;
|
||||
space.set_start((TraceAddress)summary.start());
|
||||
space.set_committedEnd((TraceAddress)summary.committed_end());
|
||||
space.set_committedSize(summary.committed_size());
|
||||
@ -323,8 +321,8 @@ static TraceStructVirtualSpace to_trace_struct(const VirtualSpaceSummary& summar
|
||||
return space;
|
||||
}
|
||||
|
||||
static TraceStructObjectSpace to_trace_struct(const SpaceSummary& summary) {
|
||||
TraceStructObjectSpace space;
|
||||
static JfrStructObjectSpace to_struct(const SpaceSummary& summary) {
|
||||
JfrStructObjectSpace space;
|
||||
space.set_start((TraceAddress)summary.start());
|
||||
space.set_end((TraceAddress)summary.end());
|
||||
space.set_used(summary.used());
|
||||
@ -344,7 +342,7 @@ class GCHeapSummaryEventSender : public GCHeapSummaryVisitor {
|
||||
if (e.should_commit()) {
|
||||
e.set_gcId(GCId::current());
|
||||
e.set_when((u1)_when);
|
||||
e.set_heapSpace(to_trace_struct(heap_space));
|
||||
e.set_heapSpace(to_struct(heap_space));
|
||||
e.set_heapUsed(heap_summary->used());
|
||||
e.commit();
|
||||
}
|
||||
@ -380,12 +378,12 @@ class GCHeapSummaryEventSender : public GCHeapSummaryVisitor {
|
||||
e.set_gcId(GCId::current());
|
||||
e.set_when((u1)_when);
|
||||
|
||||
e.set_oldSpace(to_trace_struct(ps_heap_summary->old()));
|
||||
e.set_oldObjectSpace(to_trace_struct(ps_heap_summary->old_space()));
|
||||
e.set_youngSpace(to_trace_struct(ps_heap_summary->young()));
|
||||
e.set_edenSpace(to_trace_struct(ps_heap_summary->eden()));
|
||||
e.set_fromSpace(to_trace_struct(ps_heap_summary->from()));
|
||||
e.set_toSpace(to_trace_struct(ps_heap_summary->to()));
|
||||
e.set_oldSpace(to_struct(ps_heap_summary->old()));
|
||||
e.set_oldObjectSpace(to_struct(ps_heap_summary->old_space()));
|
||||
e.set_youngSpace(to_struct(ps_heap_summary->young()));
|
||||
e.set_edenSpace(to_struct(ps_heap_summary->eden()));
|
||||
e.set_fromSpace(to_struct(ps_heap_summary->from()));
|
||||
e.set_toSpace(to_struct(ps_heap_summary->to()));
|
||||
e.commit();
|
||||
}
|
||||
}
|
||||
@ -396,8 +394,8 @@ void GCTracer::send_gc_heap_summary_event(GCWhen::Type when, const GCHeapSummary
|
||||
heap_summary.accept(&visitor);
|
||||
}
|
||||
|
||||
static TraceStructMetaspaceSizes to_trace_struct(const MetaspaceSizes& sizes) {
|
||||
TraceStructMetaspaceSizes meta_sizes;
|
||||
static JfrStructMetaspaceSizes to_struct(const MetaspaceSizes& sizes) {
|
||||
JfrStructMetaspaceSizes meta_sizes;
|
||||
|
||||
meta_sizes.set_committed(sizes.committed());
|
||||
meta_sizes.set_used(sizes.used());
|
||||
@ -412,9 +410,9 @@ void GCTracer::send_meta_space_summary_event(GCWhen::Type when, const MetaspaceS
|
||||
e.set_gcId(GCId::current());
|
||||
e.set_when((u1) when);
|
||||
e.set_gcThreshold(meta_space_summary.capacity_until_GC());
|
||||
e.set_metaspace(to_trace_struct(meta_space_summary.meta_space()));
|
||||
e.set_dataSpace(to_trace_struct(meta_space_summary.data_space()));
|
||||
e.set_classSpace(to_trace_struct(meta_space_summary.class_space()));
|
||||
e.set_metaspace(to_struct(meta_space_summary.meta_space()));
|
||||
e.set_dataSpace(to_struct(meta_space_summary.data_space()));
|
||||
e.set_classSpace(to_struct(meta_space_summary.class_space()));
|
||||
e.commit();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2018, 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
|
||||
@ -26,34 +26,50 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "gc/shared/objectCountEventSender.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/ticks.hpp"
|
||||
#if INCLUDE_SERVICES
|
||||
|
||||
void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& timestamp) {
|
||||
#if INCLUDE_TRACE
|
||||
assert(Tracing::is_event_enabled(EventObjectCountAfterGC::eventId),
|
||||
"Only call this method if the event is enabled");
|
||||
|
||||
EventObjectCountAfterGC event(UNTIMED);
|
||||
event.set_gcId(GCId::current());
|
||||
event.set_objectClass(entry->klass());
|
||||
event.set_count(entry->count());
|
||||
event.set_totalSize(entry->words() * BytesPerWord);
|
||||
event.set_endtime(timestamp);
|
||||
event.commit();
|
||||
#endif // INCLUDE_TRACE
|
||||
}
|
||||
|
||||
bool ObjectCountEventSender::should_send_event() {
|
||||
#if INCLUDE_TRACE
|
||||
return Tracing::is_event_enabled(EventObjectCountAfterGC::eventId);
|
||||
#if INCLUDE_JFR
|
||||
return _should_send_requestable_event || EventObjectCountAfterGC::is_enabled();
|
||||
#else
|
||||
return false;
|
||||
#endif // INCLUDE_TRACE
|
||||
#endif // INCLUDE_JFR
|
||||
}
|
||||
|
||||
bool ObjectCountEventSender::_should_send_requestable_event = false;
|
||||
|
||||
void ObjectCountEventSender::enable_requestable_event() {
|
||||
_should_send_requestable_event = true;
|
||||
}
|
||||
|
||||
void ObjectCountEventSender::disable_requestable_event() {
|
||||
_should_send_requestable_event = false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ObjectCountEventSender::send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp) {
|
||||
T event(UNTIMED);
|
||||
if (event.should_commit()) {
|
||||
event.set_gcId(GCId::current());
|
||||
event.set_objectClass(klass);
|
||||
event.set_count(count);
|
||||
event.set_totalSize(size);
|
||||
event.set_endtime(timestamp);
|
||||
event.commit();
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& timestamp) {
|
||||
Klass* klass = entry->klass();
|
||||
jlong count = entry->count();
|
||||
julong total_size = entry->words() * BytesPerWord;
|
||||
|
||||
send_event_if_enabled<EventObjectCount>(klass, count, total_size, timestamp);
|
||||
send_event_if_enabled<EventObjectCountAfterGC>(klass, count, total_size, timestamp);
|
||||
}
|
||||
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2018, 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
|
||||
@ -27,15 +27,25 @@
|
||||
|
||||
#include "gc/shared/gcTrace.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/ticks.hpp"
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
|
||||
class KlassInfoEntry;
|
||||
class Ticks;
|
||||
class Klass;
|
||||
|
||||
class ObjectCountEventSender : public AllStatic {
|
||||
static bool _should_send_requestable_event;
|
||||
|
||||
template <typename T>
|
||||
static void send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp);
|
||||
|
||||
public:
|
||||
static void enable_requestable_event();
|
||||
static void disable_requestable_event();
|
||||
|
||||
static void send(const KlassInfoEntry* entry, const Ticks& timestamp);
|
||||
static bool should_send_event();
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, 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
|
||||
@ -26,13 +26,15 @@
|
||||
#include "gc/shared/weakProcessor.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "runtime/jniHandles.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
#include "trace/traceMacros.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#if INCLUDE_JFR
|
||||
#include "jfr/jfr.hpp"
|
||||
#endif
|
||||
|
||||
void WeakProcessor::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive) {
|
||||
JNIHandles::weak_oops_do(is_alive, keep_alive);
|
||||
JvmtiExport::weak_oops_do(is_alive, keep_alive);
|
||||
TRACE_WEAK_OOPS_DO(is_alive, keep_alive);
|
||||
JFR_ONLY(Jfr::weak_oops_do(is_alive, keep_alive);)
|
||||
}
|
||||
|
||||
void WeakProcessor::oops_do(OopClosure* closure) {
|
||||
|
633
src/hotspot/share/jfr/dcmd/jfrDcmds.cpp
Normal file
633
src/hotspot/share/jfr/dcmd/jfrDcmds.cpp
Normal file
@ -0,0 +1,633 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "jfr/jfr.hpp"
|
||||
#include "jfr/dcmd/jfrDcmds.hpp"
|
||||
#include "jfr/jni/jfrJavaSupport.hpp"
|
||||
#include "jfr/recorder/jfrRecorder.hpp"
|
||||
#include "jfr/recorder/service/jfrOptionSet.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "services/diagnosticArgument.hpp"
|
||||
#include "services/diagnosticFramework.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#define JFR_FILENAME_EXAMPLE "C:\\Users\\user\\My Recording.jfr"
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define JFR_FILENAME_EXAMPLE "/Users/user/My Recording.jfr"
|
||||
#endif
|
||||
|
||||
#ifndef JFR_FILENAME_EXAMPLE
|
||||
#define JFR_FILENAME_EXAMPLE "/home/user/My Recording.jfr"
|
||||
#endif
|
||||
|
||||
// JNIHandle management
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// push_jni_handle_block
|
||||
//
|
||||
// Push on a new block of JNI handles.
|
||||
static void push_jni_handle_block(Thread* const thread) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
|
||||
|
||||
// Allocate a new block for JNI handles.
|
||||
// Inlined code from jni_PushLocalFrame()
|
||||
JNIHandleBlock* prev_handles = thread->active_handles();
|
||||
JNIHandleBlock* entry_handles = JNIHandleBlock::allocate_block(thread);
|
||||
assert(entry_handles != NULL && prev_handles != NULL, "should not be NULL");
|
||||
entry_handles->set_pop_frame_link(prev_handles); // make sure prev handles get gc'd.
|
||||
thread->set_active_handles(entry_handles);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// pop_jni_handle_block
|
||||
//
|
||||
// Pop off the current block of JNI handles.
|
||||
static void pop_jni_handle_block(Thread* const thread) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
|
||||
|
||||
// Release our JNI handle block
|
||||
JNIHandleBlock* entry_handles = thread->active_handles();
|
||||
JNIHandleBlock* prev_handles = entry_handles->pop_frame_link();
|
||||
// restore
|
||||
thread->set_active_handles(prev_handles);
|
||||
entry_handles->set_pop_frame_link(NULL);
|
||||
JNIHandleBlock::release_block(entry_handles, thread); // may block
|
||||
}
|
||||
|
||||
class JNIHandleBlockManager : public StackObj {
|
||||
private:
|
||||
Thread* const _thread;
|
||||
public:
|
||||
JNIHandleBlockManager(Thread* thread) : _thread(thread) {
|
||||
push_jni_handle_block(_thread);
|
||||
}
|
||||
|
||||
~JNIHandleBlockManager() {
|
||||
pop_jni_handle_block(_thread);
|
||||
}
|
||||
};
|
||||
|
||||
static bool is_module_available(outputStream* output, TRAPS) {
|
||||
return JfrJavaSupport::is_jdk_jfr_module_available(output, THREAD);
|
||||
}
|
||||
|
||||
static bool is_disabled(outputStream* output) {
|
||||
if (Jfr::is_disabled()) {
|
||||
if (output != NULL) {
|
||||
output->print_cr("Flight Recorder is disabled.\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_recorder_instance_created(outputStream* output) {
|
||||
if (!JfrRecorder::is_created()) {
|
||||
if (output != NULL) {
|
||||
output->print_cr("No available recordings.\n");
|
||||
output->print_cr("Use JFR.start to start a recording.\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool invalid_state(outputStream* out, TRAPS) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
return is_disabled(out) || !is_module_available(out, THREAD);
|
||||
}
|
||||
|
||||
static void print_pending_exception(outputStream* output, oop throwable) {
|
||||
assert(throwable != NULL, "invariant");
|
||||
|
||||
oop msg = java_lang_Throwable::message(throwable);
|
||||
|
||||
if (msg != NULL) {
|
||||
char* text = java_lang_String::as_utf8_string(msg);
|
||||
output->print_raw_cr(text);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_message(outputStream* output, const char* message) {
|
||||
if (message != NULL) {
|
||||
output->print_raw(message);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_dcmd_result(outputStream* output,
|
||||
const oop result,
|
||||
const DCmdSource source,
|
||||
TRAPS) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
assert(output != NULL, "invariant");
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
print_pending_exception(output, PENDING_EXCEPTION);
|
||||
// Don't clear excption on startup, JVM should fail initialization.
|
||||
if (DCmd_Source_Internal != source) {
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!HAS_PENDING_EXCEPTION, "invariant");
|
||||
|
||||
if (result != NULL) {
|
||||
const char* result_chars = java_lang_String::as_utf8_string(result);
|
||||
print_message(output, result_chars);
|
||||
}
|
||||
}
|
||||
|
||||
static oop construct_dcmd_instance(JfrJavaArguments* args, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
assert(args->klass() != NULL, "invariant");
|
||||
args->set_name("<init>", CHECK_NULL);
|
||||
args->set_signature("()V", CHECK_NULL);
|
||||
JfrJavaSupport::new_object(args, CHECK_NULL);
|
||||
return (oop)args->result()->get_jobject();
|
||||
}
|
||||
|
||||
JfrDumpFlightRecordingDCmd::JfrDumpFlightRecordingDCmd(outputStream* output,
|
||||
bool heap) : DCmdWithParser(output, heap),
|
||||
_name("name", "Recording name, e.g. \\\"My Recording\\\"", "STRING", true, NULL),
|
||||
_filename("filename", "Copy recording data to file, i.e \\\"" JFR_FILENAME_EXAMPLE "\\\"", "STRING", true),
|
||||
_path_to_gc_roots("path-to-gc-roots", "Collect path to GC roots", "BOOLEAN", false, "false") {
|
||||
_dcmdparser.add_dcmd_option(&_name);
|
||||
_dcmdparser.add_dcmd_option(&_filename);
|
||||
_dcmdparser.add_dcmd_option(&_path_to_gc_roots);
|
||||
};
|
||||
|
||||
int JfrDumpFlightRecordingDCmd::num_arguments() {
|
||||
ResourceMark rm;
|
||||
JfrDumpFlightRecordingDCmd* dcmd = new JfrDumpFlightRecordingDCmd(NULL, false);
|
||||
if (dcmd != NULL) {
|
||||
DCmdMark mark(dcmd);
|
||||
return dcmd->_dcmdparser.num_arguments();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void JfrDumpFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
|
||||
if (invalid_state(output(), THREAD) || !is_recorder_instance_created(output())) {
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceMark rm(THREAD);
|
||||
HandleMark hm(THREAD);
|
||||
JNIHandleBlockManager jni_handle_management(THREAD);
|
||||
|
||||
JavaValue result(T_OBJECT);
|
||||
JfrJavaArguments constructor_args(&result);
|
||||
constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdDump", CHECK);
|
||||
const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
|
||||
Handle h_dcmd_instance(THREAD, dcmd);
|
||||
assert(h_dcmd_instance.not_null(), "invariant");
|
||||
|
||||
jstring name = NULL;
|
||||
if (_name.is_set() && _name.value() != NULL) {
|
||||
name = JfrJavaSupport::new_string(_name.value(), CHECK);
|
||||
}
|
||||
|
||||
jstring filepath = NULL;
|
||||
if (_filename.is_set() && _filename.value() != NULL) {
|
||||
filepath = JfrJavaSupport::new_string(_filename.value(), CHECK);
|
||||
}
|
||||
|
||||
jobject path_to_gc_roots = NULL;
|
||||
if (_path_to_gc_roots.is_set()) {
|
||||
path_to_gc_roots = JfrJavaSupport::new_java_lang_Boolean(_path_to_gc_roots.value(), CHECK);
|
||||
}
|
||||
|
||||
static const char klass[] = "jdk/jfr/internal/dcmd/DCmdDump";
|
||||
static const char method[] = "execute";
|
||||
static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)Ljava/lang/String;";
|
||||
|
||||
JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
|
||||
execute_args.set_receiver(h_dcmd_instance);
|
||||
|
||||
// arguments
|
||||
execute_args.push_jobject(name);
|
||||
execute_args.push_jobject(filepath);
|
||||
execute_args.push_jobject(path_to_gc_roots);
|
||||
|
||||
JfrJavaSupport::call_virtual(&execute_args, THREAD);
|
||||
handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
|
||||
}
|
||||
|
||||
JfrCheckFlightRecordingDCmd::JfrCheckFlightRecordingDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap),
|
||||
_name("name","Recording text, e.g. \\\"My Recording\\\" or omit to see all recordings","STRING",false, NULL),
|
||||
_verbose("verbose","Print event settings for the recording(s)","BOOLEAN",
|
||||
false, "false") {
|
||||
_dcmdparser.add_dcmd_option(&_name);
|
||||
_dcmdparser.add_dcmd_option(&_verbose);
|
||||
};
|
||||
|
||||
int JfrCheckFlightRecordingDCmd::num_arguments() {
|
||||
ResourceMark rm;
|
||||
JfrCheckFlightRecordingDCmd* dcmd = new JfrCheckFlightRecordingDCmd(NULL, false);
|
||||
if (dcmd != NULL) {
|
||||
DCmdMark mark(dcmd);
|
||||
return dcmd->_dcmdparser.num_arguments();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void JfrCheckFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
|
||||
if (invalid_state(output(), THREAD) || !is_recorder_instance_created(output())) {
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceMark rm(THREAD);
|
||||
HandleMark hm(THREAD);
|
||||
JNIHandleBlockManager jni_handle_management(THREAD);
|
||||
|
||||
JavaValue result(T_OBJECT);
|
||||
JfrJavaArguments constructor_args(&result);
|
||||
constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdCheck", CHECK);
|
||||
const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
|
||||
Handle h_dcmd_instance(THREAD, dcmd);
|
||||
assert(h_dcmd_instance.not_null(), "invariant");
|
||||
|
||||
jstring name = NULL;
|
||||
if (_name.is_set() && _name.value() != NULL) {
|
||||
name = JfrJavaSupport::new_string(_name.value(), CHECK);
|
||||
}
|
||||
|
||||
jobject verbose = NULL;
|
||||
if (_verbose.is_set()) {
|
||||
verbose = JfrJavaSupport::new_java_lang_Boolean(_verbose.value(), CHECK);
|
||||
}
|
||||
|
||||
static const char klass[] = "jdk/jfr/internal/dcmd/DCmdCheck";
|
||||
static const char method[] = "execute";
|
||||
static const char signature[] = "(Ljava/lang/String;Ljava/lang/Boolean;)Ljava/lang/String;";
|
||||
|
||||
JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
|
||||
execute_args.set_receiver(h_dcmd_instance);
|
||||
|
||||
// arguments
|
||||
execute_args.push_jobject(name);
|
||||
execute_args.push_jobject(verbose);
|
||||
|
||||
JfrJavaSupport::call_virtual(&execute_args, THREAD);
|
||||
handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
|
||||
}
|
||||
|
||||
JfrStartFlightRecordingDCmd::JfrStartFlightRecordingDCmd(outputStream* output,
|
||||
bool heap) : DCmdWithParser(output, heap),
|
||||
_name("name", "Name that can be used to identify recording, e.g. \\\"My Recording\\\"", "STRING", false, NULL),
|
||||
_settings("settings", "Settings file(s), e.g. profile or default. See JRE_HOME/lib/jfr", "STRING SET", false),
|
||||
_delay("delay", "Delay recording start with (s)econds, (m)inutes), (h)ours), or (d)ays, e.g. 5h.", "NANOTIME", false, "0"),
|
||||
_duration("duration", "Duration of recording in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 300s.", "NANOTIME", false, "0"),
|
||||
_filename("filename", "Resulting recording filename, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"", "STRING", false),
|
||||
_disk("disk", "Recording should be persisted to disk", "BOOLEAN", false),
|
||||
_maxage("maxage", "Maximum time to keep recorded data (on disk) in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 60m, or 0 for no limit", "NANOTIME", false, "0"),
|
||||
_maxsize("maxsize", "Maximum amount of bytes to keep (on disk) in (k)B, (M)B or (G)B, e.g. 500M, or 0 for no limit", "MEMORY SIZE", false, "0"),
|
||||
_dump_on_exit("dumponexit", "Dump running recording when JVM shuts down", "BOOLEAN", false),
|
||||
_path_to_gc_roots("path-to-gc-roots", "Collect path to GC roots", "BOOLEAN", false, "false") {
|
||||
_dcmdparser.add_dcmd_option(&_name);
|
||||
_dcmdparser.add_dcmd_option(&_settings);
|
||||
_dcmdparser.add_dcmd_option(&_delay);
|
||||
_dcmdparser.add_dcmd_option(&_duration);
|
||||
_dcmdparser.add_dcmd_option(&_disk);
|
||||
_dcmdparser.add_dcmd_option(&_filename);
|
||||
_dcmdparser.add_dcmd_option(&_maxage);
|
||||
_dcmdparser.add_dcmd_option(&_maxsize);
|
||||
_dcmdparser.add_dcmd_option(&_dump_on_exit);
|
||||
_dcmdparser.add_dcmd_option(&_path_to_gc_roots);
|
||||
};
|
||||
|
||||
int JfrStartFlightRecordingDCmd::num_arguments() {
|
||||
ResourceMark rm;
|
||||
JfrStartFlightRecordingDCmd* dcmd = new JfrStartFlightRecordingDCmd(NULL, false);
|
||||
if (dcmd != NULL) {
|
||||
DCmdMark mark(dcmd);
|
||||
return dcmd->_dcmdparser.num_arguments();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void JfrStartFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
|
||||
if (invalid_state(output(), THREAD)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceMark rm(THREAD);
|
||||
HandleMark hm(THREAD);
|
||||
JNIHandleBlockManager jni_handle_management(THREAD);
|
||||
|
||||
JavaValue result(T_OBJECT);
|
||||
JfrJavaArguments constructor_args(&result);
|
||||
constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdStart", THREAD);
|
||||
const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
|
||||
Handle h_dcmd_instance(THREAD, dcmd);
|
||||
assert(h_dcmd_instance.not_null(), "invariant");
|
||||
|
||||
jstring name = NULL;
|
||||
if (_name.is_set() && _name.value() != NULL) {
|
||||
name = JfrJavaSupport::new_string(_name.value(), CHECK);
|
||||
}
|
||||
|
||||
jstring filename = NULL;
|
||||
if (_filename.is_set() && _filename.value() != NULL) {
|
||||
filename = JfrJavaSupport::new_string(_filename.value(), CHECK);
|
||||
}
|
||||
|
||||
jobject maxage = NULL;
|
||||
if (_maxage.is_set()) {
|
||||
maxage = JfrJavaSupport::new_java_lang_Long(_maxage.value()._nanotime, CHECK);
|
||||
}
|
||||
|
||||
jobject maxsize = NULL;
|
||||
if (_maxsize.is_set()) {
|
||||
maxsize = JfrJavaSupport::new_java_lang_Long(_maxsize.value()._size, CHECK);
|
||||
}
|
||||
|
||||
jobject duration = NULL;
|
||||
if (_duration.is_set()) {
|
||||
duration = JfrJavaSupport::new_java_lang_Long(_duration.value()._nanotime, CHECK);
|
||||
}
|
||||
|
||||
jobject delay = NULL;
|
||||
if (_delay.is_set()) {
|
||||
delay = JfrJavaSupport::new_java_lang_Long(_delay.value()._nanotime, CHECK);
|
||||
}
|
||||
|
||||
jobject disk = NULL;
|
||||
if (_disk.is_set()) {
|
||||
disk = JfrJavaSupport::new_java_lang_Boolean(_disk.value(), CHECK);
|
||||
}
|
||||
|
||||
jobject dump_on_exit = NULL;
|
||||
if (_dump_on_exit.is_set()) {
|
||||
dump_on_exit = JfrJavaSupport::new_java_lang_Boolean(_dump_on_exit.value(), CHECK);
|
||||
}
|
||||
|
||||
jobject path_to_gc_roots = NULL;
|
||||
if (_path_to_gc_roots.is_set()) {
|
||||
path_to_gc_roots = JfrJavaSupport::new_java_lang_Boolean(_path_to_gc_roots.value(), CHECK);
|
||||
}
|
||||
|
||||
jobjectArray settings = NULL;
|
||||
if (_settings.is_set()) {
|
||||
const int length = _settings.value()->array()->length();
|
||||
settings = JfrJavaSupport::new_string_array(length, CHECK);
|
||||
assert(settings != NULL, "invariant");
|
||||
for (int i = 0; i < length; ++i) {
|
||||
jobject element = JfrJavaSupport::new_string(_settings.value()->array()->at(i), CHECK);
|
||||
assert(element != NULL, "invariant");
|
||||
JfrJavaSupport::set_array_element(settings, element, i, CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
static const char klass[] = "jdk/jfr/internal/dcmd/DCmdStart";
|
||||
static const char method[] = "execute";
|
||||
static const char signature[] = "(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/Long;"
|
||||
"Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/String;"
|
||||
"Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/lang/String;";
|
||||
|
||||
JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
|
||||
execute_args.set_receiver(h_dcmd_instance);
|
||||
|
||||
// arguments
|
||||
execute_args.push_jobject(name);
|
||||
execute_args.push_jobject(settings);
|
||||
execute_args.push_jobject(delay);
|
||||
execute_args.push_jobject(duration);
|
||||
execute_args.push_jobject(disk);
|
||||
execute_args.push_jobject(filename);
|
||||
execute_args.push_jobject(maxage);
|
||||
execute_args.push_jobject(maxsize);
|
||||
execute_args.push_jobject(dump_on_exit);
|
||||
execute_args.push_jobject(path_to_gc_roots);
|
||||
|
||||
JfrJavaSupport::call_virtual(&execute_args, THREAD);
|
||||
handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
|
||||
}
|
||||
|
||||
JfrStopFlightRecordingDCmd::JfrStopFlightRecordingDCmd(outputStream* output,
|
||||
bool heap) : DCmdWithParser(output, heap),
|
||||
_name("name", "Recording text,.e.g \\\"My Recording\\\"", "STRING", false, NULL),
|
||||
_filename("filename", "Copy recording data to file, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"", "STRING", false, NULL) {
|
||||
_dcmdparser.add_dcmd_option(&_name);
|
||||
_dcmdparser.add_dcmd_option(&_filename);
|
||||
};
|
||||
|
||||
int JfrStopFlightRecordingDCmd::num_arguments() {
|
||||
ResourceMark rm;
|
||||
JfrStopFlightRecordingDCmd* dcmd = new JfrStopFlightRecordingDCmd(NULL, false);
|
||||
if (dcmd != NULL) {
|
||||
DCmdMark mark(dcmd);
|
||||
return dcmd->_dcmdparser.num_arguments();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void JfrStopFlightRecordingDCmd::execute(DCmdSource source, TRAPS) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
|
||||
if (invalid_state(output(), THREAD) || !is_recorder_instance_created(output())) {
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceMark rm(THREAD);
|
||||
HandleMark hm(THREAD);
|
||||
JNIHandleBlockManager jni_handle_management(THREAD);
|
||||
|
||||
JavaValue result(T_OBJECT);
|
||||
JfrJavaArguments constructor_args(&result);
|
||||
constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdStop", CHECK);
|
||||
const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
|
||||
Handle h_dcmd_instance(THREAD, dcmd);
|
||||
assert(h_dcmd_instance.not_null(), "invariant");
|
||||
|
||||
jstring name = NULL;
|
||||
if (_name.is_set() && _name.value() != NULL) {
|
||||
name = JfrJavaSupport::new_string(_name.value(), CHECK);
|
||||
}
|
||||
|
||||
jstring filepath = NULL;
|
||||
if (_filename.is_set() && _filename.value() != NULL) {
|
||||
filepath = JfrJavaSupport::new_string(_filename.value(), CHECK);
|
||||
}
|
||||
|
||||
static const char klass[] = "jdk/jfr/internal/dcmd/DCmdStop";
|
||||
static const char method[] = "execute";
|
||||
static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;";
|
||||
|
||||
JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
|
||||
execute_args.set_receiver(h_dcmd_instance);
|
||||
|
||||
// arguments
|
||||
execute_args.push_jobject(name);
|
||||
execute_args.push_jobject(filepath);
|
||||
|
||||
JfrJavaSupport::call_virtual(&execute_args, THREAD);
|
||||
handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
|
||||
}
|
||||
|
||||
JfrConfigureFlightRecorderDCmd::JfrConfigureFlightRecorderDCmd(outputStream* output,
|
||||
bool heap) : DCmdWithParser(output, heap),
|
||||
_repository_path("repositorypath", "Path to repository,.e.g \\\"My Repository\\\"", "STRING", false, NULL),
|
||||
_dump_path("dumppath", "Path to dump,.e.g \\\"My Dump path\\\"", "STRING", false, NULL),
|
||||
_stack_depth("stackdepth", "Stack Depth", "JLONG", false, "64"),
|
||||
_global_buffer_count("globalbuffercount", "Number of global buffers,", "JLONG", false, "32"),
|
||||
_global_buffer_size("globalbuffersize", "Size of a global buffers,", "JLONG", false, "524288"),
|
||||
_thread_buffer_size("thread_buffer_size", "Size of a thread buffer", "JLONG", false, "8192"),
|
||||
_memory_size("memorysize", "Overall memory size, ", "JLONG", false, "16777216"),
|
||||
_max_chunk_size("maxchunksize", "Size of an individual disk chunk", "JLONG", false, "12582912"),
|
||||
_sample_threads("samplethreads", "Activate Thread sampling", "BOOLEAN", false, "true") {
|
||||
_dcmdparser.add_dcmd_option(&_repository_path);
|
||||
_dcmdparser.add_dcmd_option(&_dump_path);
|
||||
_dcmdparser.add_dcmd_option(&_stack_depth);
|
||||
_dcmdparser.add_dcmd_option(&_global_buffer_count);
|
||||
_dcmdparser.add_dcmd_option(&_global_buffer_size);
|
||||
_dcmdparser.add_dcmd_option(&_thread_buffer_size);
|
||||
_dcmdparser.add_dcmd_option(&_memory_size);
|
||||
_dcmdparser.add_dcmd_option(&_max_chunk_size);
|
||||
_dcmdparser.add_dcmd_option(&_sample_threads);
|
||||
};
|
||||
|
||||
int JfrConfigureFlightRecorderDCmd::num_arguments() {
|
||||
ResourceMark rm;
|
||||
JfrConfigureFlightRecorderDCmd* dcmd = new JfrConfigureFlightRecorderDCmd(NULL, false);
|
||||
if (dcmd != NULL) {
|
||||
DCmdMark mark(dcmd);
|
||||
return dcmd->_dcmdparser.num_arguments();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void JfrConfigureFlightRecorderDCmd::execute(DCmdSource source, TRAPS) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
|
||||
if (invalid_state(output(), THREAD)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceMark rm(THREAD);
|
||||
HandleMark hm(THREAD);
|
||||
JNIHandleBlockManager jni_handle_management(THREAD);
|
||||
|
||||
JavaValue result(T_OBJECT);
|
||||
JfrJavaArguments constructor_args(&result);
|
||||
constructor_args.set_klass("jdk/jfr/internal/dcmd/DCmdConfigure", CHECK);
|
||||
const oop dcmd = construct_dcmd_instance(&constructor_args, CHECK);
|
||||
Handle h_dcmd_instance(THREAD, dcmd);
|
||||
assert(h_dcmd_instance.not_null(), "invariant");
|
||||
|
||||
jstring repository_path = NULL;
|
||||
if (_repository_path.is_set() && _repository_path.value() != NULL) {
|
||||
repository_path = JfrJavaSupport::new_string(_repository_path.value(), CHECK);
|
||||
}
|
||||
|
||||
jstring dump_path = NULL;
|
||||
if (_dump_path.is_set() && _dump_path.value() != NULL) {
|
||||
dump_path = JfrJavaSupport::new_string(_dump_path.value(), CHECK);
|
||||
}
|
||||
|
||||
jobject stack_depth = NULL;
|
||||
if (_stack_depth.is_set()) {
|
||||
stack_depth = JfrJavaSupport::new_java_lang_Integer((jint)_stack_depth.value(), CHECK);
|
||||
}
|
||||
|
||||
jobject global_buffer_count = NULL;
|
||||
if (_global_buffer_count.is_set()) {
|
||||
global_buffer_count = JfrJavaSupport::new_java_lang_Long(_global_buffer_count.value(), CHECK);
|
||||
}
|
||||
|
||||
jobject global_buffer_size = NULL;
|
||||
if (_global_buffer_size.is_set()) {
|
||||
global_buffer_size = JfrJavaSupport::new_java_lang_Long(_global_buffer_size.value(), CHECK);
|
||||
}
|
||||
|
||||
jobject thread_buffer_size = NULL;
|
||||
if (_thread_buffer_size.is_set()) {
|
||||
thread_buffer_size = JfrJavaSupport::new_java_lang_Long(_thread_buffer_size.value(), CHECK);
|
||||
}
|
||||
|
||||
jobject max_chunk_size = NULL;
|
||||
if (_max_chunk_size.is_set()) {
|
||||
max_chunk_size = JfrJavaSupport::new_java_lang_Long(_max_chunk_size.value(), CHECK);
|
||||
}
|
||||
|
||||
jobject memory_size = NULL;
|
||||
if (_memory_size.is_set()) {
|
||||
memory_size = JfrJavaSupport::new_java_lang_Long(_memory_size.value(), CHECK);
|
||||
}
|
||||
|
||||
jobject sample_threads = NULL;
|
||||
if (_sample_threads.is_set()) {
|
||||
sample_threads = JfrJavaSupport::new_java_lang_Boolean(_sample_threads.value(), CHECK);
|
||||
}
|
||||
|
||||
static const char klass[] = "jdk/jfr/internal/dcmd/DCmdConfigure";
|
||||
static const char method[] = "execute";
|
||||
static const char signature[] = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;"
|
||||
"Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;"
|
||||
"Ljava/lang/Long;Ljava/lang/Boolean;)Ljava/lang/String;";
|
||||
|
||||
JfrJavaArguments execute_args(&result, klass, method, signature, CHECK);
|
||||
execute_args.set_receiver(h_dcmd_instance);
|
||||
|
||||
// params
|
||||
execute_args.push_jobject(repository_path);
|
||||
execute_args.push_jobject(dump_path);
|
||||
execute_args.push_jobject(stack_depth);
|
||||
execute_args.push_jobject(global_buffer_count);
|
||||
execute_args.push_jobject(global_buffer_size);
|
||||
execute_args.push_jobject(thread_buffer_size);
|
||||
execute_args.push_jobject(memory_size);
|
||||
execute_args.push_jobject(max_chunk_size);
|
||||
execute_args.push_jobject(sample_threads);
|
||||
|
||||
JfrJavaSupport::call_virtual(&execute_args, THREAD);
|
||||
handle_dcmd_result(output(), (oop)result.get_jobject(), source, THREAD);
|
||||
}
|
||||
|
||||
bool register_jfr_dcmds() {
|
||||
uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI | DCmd_Source_MBean;
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrCheckFlightRecordingDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrDumpFlightRecordingDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrStartFlightRecordingDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrStopFlightRecordingDCmd>(full_export, true, false));
|
||||
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JfrConfigureFlightRecorderDCmd>(full_export, true, false));
|
||||
return true;
|
||||
}
|
||||
|
171
src/hotspot/share/jfr/dcmd/jfrDcmds.hpp
Normal file
171
src/hotspot/share/jfr/dcmd/jfrDcmds.hpp
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_JFR_JFRDCMDS_HPP
|
||||
#define SHARE_VM_JFR_JFRDCMDS_HPP
|
||||
|
||||
#include "services/diagnosticCommand.hpp"
|
||||
|
||||
class JfrDumpFlightRecordingDCmd : public DCmdWithParser {
|
||||
protected:
|
||||
DCmdArgument<char*> _name;
|
||||
DCmdArgument<char*> _filename;
|
||||
DCmdArgument<bool> _path_to_gc_roots;
|
||||
|
||||
public:
|
||||
JfrDumpFlightRecordingDCmd(outputStream* output, bool heap);
|
||||
static const char* name() {
|
||||
return "JFR.dump";
|
||||
}
|
||||
static const char* description() {
|
||||
return "Copies contents of a JFR recording to file. Either the name or the recording id must be specified.";
|
||||
}
|
||||
static const char* impact() {
|
||||
return "Low";
|
||||
}
|
||||
static const JavaPermission permission() {
|
||||
JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL};
|
||||
return p;
|
||||
}
|
||||
static int num_arguments();
|
||||
virtual void execute(DCmdSource source, TRAPS);
|
||||
};
|
||||
|
||||
class JfrCheckFlightRecordingDCmd : public DCmdWithParser {
|
||||
protected:
|
||||
DCmdArgument<char*> _name;
|
||||
DCmdArgument<bool> _verbose;
|
||||
|
||||
public:
|
||||
JfrCheckFlightRecordingDCmd(outputStream* output, bool heap);
|
||||
static const char* name() {
|
||||
return "JFR.check";
|
||||
}
|
||||
static const char* description() {
|
||||
return "Checks running JFR recording(s)";
|
||||
}
|
||||
static const char* impact() {
|
||||
return "Low";
|
||||
}
|
||||
static const JavaPermission permission() {
|
||||
JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL};
|
||||
return p;
|
||||
}
|
||||
static int num_arguments();
|
||||
virtual void execute(DCmdSource source, TRAPS);
|
||||
};
|
||||
|
||||
class JfrStartFlightRecordingDCmd : public DCmdWithParser {
|
||||
protected:
|
||||
DCmdArgument<char*> _name;
|
||||
DCmdArgument<StringArrayArgument*> _settings;
|
||||
DCmdArgument<NanoTimeArgument> _delay;
|
||||
DCmdArgument<NanoTimeArgument> _duration;
|
||||
DCmdArgument<bool> _disk;
|
||||
DCmdArgument<char*> _filename;
|
||||
DCmdArgument<NanoTimeArgument> _maxage;
|
||||
DCmdArgument<MemorySizeArgument> _maxsize;
|
||||
DCmdArgument<bool> _dump_on_exit;
|
||||
DCmdArgument<bool> _path_to_gc_roots;
|
||||
|
||||
public:
|
||||
JfrStartFlightRecordingDCmd(outputStream* output, bool heap);
|
||||
static const char* name() {
|
||||
return "JFR.start";
|
||||
}
|
||||
static const char* description() {
|
||||
return "Starts a new JFR recording";
|
||||
}
|
||||
static const char* impact() {
|
||||
return "Medium: Depending on the settings for a recording, the impact can range from low to high.";
|
||||
}
|
||||
static const JavaPermission permission() {
|
||||
JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL};
|
||||
return p;
|
||||
}
|
||||
static int num_arguments();
|
||||
virtual void execute(DCmdSource source, TRAPS);
|
||||
};
|
||||
|
||||
class JfrStopFlightRecordingDCmd : public DCmdWithParser {
|
||||
protected:
|
||||
DCmdArgument<char*> _name;
|
||||
DCmdArgument<char*> _filename;
|
||||
|
||||
public:
|
||||
JfrStopFlightRecordingDCmd(outputStream* output, bool heap);
|
||||
static const char* name() {
|
||||
return "JFR.stop";
|
||||
}
|
||||
static const char* description() {
|
||||
return "Stops a JFR recording";
|
||||
}
|
||||
static const char* impact() {
|
||||
return "Low";
|
||||
}
|
||||
static const JavaPermission permission() {
|
||||
JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL};
|
||||
return p;
|
||||
}
|
||||
static int num_arguments();
|
||||
virtual void execute(DCmdSource source, TRAPS);
|
||||
};
|
||||
|
||||
class JfrRuntimeOptions;
|
||||
|
||||
class JfrConfigureFlightRecorderDCmd : public DCmdWithParser {
|
||||
friend class JfrOptionSet;
|
||||
protected:
|
||||
DCmdArgument<char*> _repository_path;
|
||||
DCmdArgument<char*> _dump_path;
|
||||
DCmdArgument<jlong> _stack_depth;
|
||||
DCmdArgument<jlong> _global_buffer_count;
|
||||
DCmdArgument<jlong> _global_buffer_size;
|
||||
DCmdArgument<jlong> _thread_buffer_size;
|
||||
DCmdArgument<jlong> _memory_size;
|
||||
DCmdArgument<jlong> _max_chunk_size;
|
||||
DCmdArgument<bool> _sample_threads;
|
||||
|
||||
public:
|
||||
JfrConfigureFlightRecorderDCmd(outputStream* output, bool heap);
|
||||
static const char* name() {
|
||||
return "JFR.configure";
|
||||
}
|
||||
static const char* description() {
|
||||
return "Configure JFR";
|
||||
}
|
||||
static const char* impact() {
|
||||
return "Low";
|
||||
}
|
||||
static const JavaPermission permission() {
|
||||
JavaPermission p = {"java.lang.management.ManagementPermission", "monitor", NULL};
|
||||
return p;
|
||||
}
|
||||
static int num_arguments();
|
||||
virtual void execute(DCmdSource source, TRAPS);
|
||||
};
|
||||
|
||||
bool register_jfr_dcmds();
|
||||
|
||||
#endif // SHARE_VM_JFR_JFRDCMDS_HPP
|
1556
src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp
Normal file
1556
src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_JFR_INSTRUMENTATION_JFREVENTCLASSTRANSFORMER_HPP
|
||||
#define SHARE_VM_JFR_INSTRUMENTATION_JFREVENTCLASSTRANSFORMER_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
|
||||
class ClassFileParser;
|
||||
class InstanceKlass;
|
||||
|
||||
//
|
||||
// Intercepts the initial class load of jdk.jfr.Event and subclasses.
|
||||
// Will replace the sent in InstanceKlass* with a class file schema extended InstanceKlass*.
|
||||
//
|
||||
class JfrEventClassTransformer : AllStatic {
|
||||
public:
|
||||
static void on_klass_creation(InstanceKlass*& ik, ClassFileParser& parser, TRAPS);
|
||||
static void set_force_instrumentation(bool force_instrumentation);
|
||||
static bool is_force_instrumentation();
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_JFR_INSTRUMENTATION_JFREVENTCLASSTRANSFORMER_HPP
|
279
src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp
Normal file
279
src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.cpp
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "jvm.h"
|
||||
#include "jfr/instrumentation/jfrJvmtiAgent.hpp"
|
||||
#include "jfr/jni/jfrJavaSupport.hpp"
|
||||
#include "jfr/jni/jfrUpcalls.hpp"
|
||||
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
|
||||
#include "jfr/recorder/service/jfrOptionSet.hpp"
|
||||
#include "jfr/support/jfrEventClass.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "runtime/interfaceSupport.inline.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
|
||||
static const size_t ERROR_MSG_BUFFER_SIZE = 256;
|
||||
static JfrJvmtiAgent* agent = NULL;
|
||||
static jvmtiEnv* jfr_jvmti_env = NULL;
|
||||
|
||||
static void check_jvmti_error(jvmtiEnv* jvmti, jvmtiError errnum, const char* str) {
|
||||
if (errnum != JVMTI_ERROR_NONE) {
|
||||
char* errnum_str = NULL;
|
||||
jvmti->GetErrorName(errnum, &errnum_str);
|
||||
log_error(jfr, system)("ERROR: JfrJvmtiAgent: " INT32_FORMAT " (%s): %s\n",
|
||||
errnum,
|
||||
NULL == errnum_str ? "Unknown" : errnum_str,
|
||||
NULL == str ? "" : str);
|
||||
}
|
||||
}
|
||||
|
||||
static jvmtiError set_event_notification_mode(jvmtiEventMode mode,
|
||||
jvmtiEvent event,
|
||||
jthread event_thread,
|
||||
...) {
|
||||
if (jfr_jvmti_env == NULL) {
|
||||
return JVMTI_ERROR_NONE;
|
||||
}
|
||||
const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventNotificationMode(mode, event, event_thread);
|
||||
check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventNotificationMode");
|
||||
return jvmti_ret_code;
|
||||
}
|
||||
|
||||
static jvmtiError update_class_file_load_hook_event(jvmtiEventMode mode) {
|
||||
return set_event_notification_mode(mode, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
|
||||
}
|
||||
|
||||
static JavaThread* current_java_thread() {
|
||||
Thread* this_thread = Thread::current();
|
||||
assert(this_thread != NULL && this_thread->is_Java_thread(), "invariant");
|
||||
return static_cast<JavaThread*>(this_thread);
|
||||
}
|
||||
|
||||
// jvmti event callbacks require C linkage
|
||||
extern "C" void JNICALL jfr_on_class_file_load_hook(jvmtiEnv *jvmti_env,
|
||||
JNIEnv* jni_env,
|
||||
jclass class_being_redefined,
|
||||
jobject loader,
|
||||
const char* name,
|
||||
jobject protection_domain,
|
||||
jint class_data_len,
|
||||
const unsigned char* class_data,
|
||||
jint* new_class_data_len,
|
||||
unsigned char** new_class_data) {
|
||||
if (class_being_redefined == NULL) {
|
||||
return;
|
||||
}
|
||||
JavaThread* jt = JavaThread::thread_from_jni_environment(jni_env);
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));;
|
||||
ThreadInVMfromNative tvmfn(jt);
|
||||
JfrUpcalls::on_retransform(JfrTraceId::get(class_being_redefined),
|
||||
class_being_redefined,
|
||||
class_data_len,
|
||||
class_data,
|
||||
new_class_data_len,
|
||||
new_class_data,
|
||||
jt);
|
||||
}
|
||||
|
||||
// caller needs ResourceMark
|
||||
static jclass* create_classes_array(jint classes_count, TRAPS) {
|
||||
assert(classes_count > 0, "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
|
||||
ThreadInVMfromNative tvmfn((JavaThread*)THREAD);
|
||||
jclass* const classes = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, jclass, classes_count);
|
||||
if (NULL == classes) {
|
||||
char error_buffer[ERROR_MSG_BUFFER_SIZE];
|
||||
jio_snprintf(error_buffer, ERROR_MSG_BUFFER_SIZE,
|
||||
"Thread local allocation (native) of " SIZE_FORMAT " bytes failed "
|
||||
"in retransform classes", sizeof(jclass) * classes_count);
|
||||
log_error(jfr, system)("%s", error_buffer);
|
||||
JfrJavaSupport::throw_out_of_memory_error(error_buffer, CHECK_NULL);
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
static void log_and_throw(TRAPS) {
|
||||
if (!HAS_PENDING_EXCEPTION) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
|
||||
ThreadInVMfromNative tvmfn((JavaThread*)THREAD);
|
||||
log_error(jfr, system)("JfrJvmtiAgent::retransformClasses failed");
|
||||
JfrJavaSupport::throw_class_format_error("JfrJvmtiAgent::retransformClasses failed", THREAD);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_exception_and_log(JNIEnv* env, TRAPS) {
|
||||
assert(env != NULL, "invariant");
|
||||
if (env->ExceptionOccurred()) {
|
||||
// array index out of bound
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
|
||||
ThreadInVMfromNative tvmfn((JavaThread*)THREAD);
|
||||
log_error(jfr, system)("GetObjectArrayElement threw an exception");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void JfrJvmtiAgent::retransform_classes(JNIEnv* env, jobjectArray classes_array, TRAPS) {
|
||||
assert(env != NULL, "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
|
||||
if (classes_array == NULL) {
|
||||
return;
|
||||
}
|
||||
const jint classes_count = env->GetArrayLength(classes_array);
|
||||
if (classes_count <= 0) {
|
||||
return;
|
||||
}
|
||||
ResourceMark rm(THREAD);
|
||||
jclass* const classes = create_classes_array(classes_count, CHECK);
|
||||
assert(classes != NULL, "invariant");
|
||||
for (jint i = 0; i < classes_count; i++) {
|
||||
jclass clz = (jclass)env->GetObjectArrayElement(classes_array, i);
|
||||
check_exception_and_log(env, THREAD);
|
||||
|
||||
// inspecting the oop/klass requires a thread transition
|
||||
{
|
||||
ThreadInVMfromNative transition((JavaThread*)THREAD);
|
||||
if (JdkJfrEvent::is_a(clz)) {
|
||||
// should have been tagged already
|
||||
assert(JdkJfrEvent::is_subklass(clz), "invariant");
|
||||
} else {
|
||||
// outside the event hierarchy
|
||||
JdkJfrEvent::tag_as_host(clz);
|
||||
}
|
||||
}
|
||||
|
||||
classes[i] = clz;
|
||||
}
|
||||
if (jfr_jvmti_env->RetransformClasses(classes_count, classes) != JVMTI_ERROR_NONE) {
|
||||
log_and_throw(THREAD);
|
||||
}
|
||||
}
|
||||
|
||||
static jvmtiError register_callbacks(JavaThread* jt) {
|
||||
assert(jfr_jvmti_env != NULL, "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
|
||||
jvmtiEventCallbacks callbacks;
|
||||
/* Set callbacks */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.ClassFileLoadHook = jfr_on_class_file_load_hook;
|
||||
const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
|
||||
check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks");
|
||||
return jvmti_ret_code;
|
||||
}
|
||||
|
||||
static jvmtiError register_capabilities(JavaThread* jt) {
|
||||
assert(jfr_jvmti_env != NULL, "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
|
||||
jvmtiCapabilities capabilities;
|
||||
/* Add JVMTI capabilities */
|
||||
(void)memset(&capabilities, 0, sizeof(capabilities));
|
||||
capabilities.can_retransform_classes = 1;
|
||||
capabilities.can_retransform_any_class = 1;
|
||||
const jvmtiError jvmti_ret_code = jfr_jvmti_env->AddCapabilities(&capabilities);
|
||||
check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "Add Capabilities");
|
||||
return jvmti_ret_code;
|
||||
}
|
||||
|
||||
static jint create_jvmti_env(JavaThread* jt) {
|
||||
assert(jfr_jvmti_env == NULL, "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
|
||||
extern struct JavaVM_ main_vm;
|
||||
JavaVM* vm = &main_vm;
|
||||
return vm->GetEnv((void **)&jfr_jvmti_env, JVMTI_VERSION);
|
||||
}
|
||||
|
||||
static jvmtiError unregister_callbacks(JavaThread* jt) {
|
||||
if (jfr_jvmti_env == NULL) {
|
||||
return JVMTI_ERROR_NONE;
|
||||
}
|
||||
jvmtiEventCallbacks callbacks;
|
||||
/* Set empty callbacks */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
|
||||
check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks");
|
||||
return jvmti_ret_code;
|
||||
}
|
||||
|
||||
JfrJvmtiAgent::JfrJvmtiAgent() {}
|
||||
|
||||
JfrJvmtiAgent::~JfrJvmtiAgent() {
|
||||
JavaThread* jt = current_java_thread();
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
|
||||
ThreadToNativeFromVM transition(jt);
|
||||
update_class_file_load_hook_event(JVMTI_DISABLE);
|
||||
unregister_callbacks(jt);
|
||||
if (jfr_jvmti_env != NULL) {
|
||||
jfr_jvmti_env->DisposeEnvironment();
|
||||
jfr_jvmti_env = NULL;
|
||||
}
|
||||
agent = NULL;
|
||||
}
|
||||
|
||||
static bool initialize() {
|
||||
JavaThread* const jt = current_java_thread();
|
||||
assert(jt != NULL, "invariant");
|
||||
assert(jt->thread_state() == _thread_in_vm, "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
|
||||
ThreadToNativeFromVM transition(jt);
|
||||
if (create_jvmti_env(jt) != JNI_OK) {
|
||||
assert(jfr_jvmti_env == NULL, "invariant");
|
||||
return false;
|
||||
}
|
||||
assert(jfr_jvmti_env != NULL, "invariant");
|
||||
if (register_capabilities(jt) != JVMTI_ERROR_NONE) {
|
||||
return false;
|
||||
}
|
||||
if (register_callbacks(jt) != JVMTI_ERROR_NONE) {
|
||||
return false;
|
||||
}
|
||||
if (update_class_file_load_hook_event(JVMTI_ENABLE) != JVMTI_ERROR_NONE) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JfrJvmtiAgent::create() {
|
||||
assert(jfr_jvmti_env == NULL, "invariant");
|
||||
agent = new JfrJvmtiAgent();
|
||||
if (agent == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (!initialize()) {
|
||||
delete agent;
|
||||
agent = NULL;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void JfrJvmtiAgent::destroy() {
|
||||
if (agent != NULL) {
|
||||
delete agent;
|
||||
agent = NULL;
|
||||
}
|
||||
}
|
||||
|
41
src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.hpp
Normal file
41
src/hotspot/share/jfr/instrumentation/jfrJvmtiAgent.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_JFR_INSTRUMENTATION_JFRJVMTIAGENT_HPP
|
||||
#define SHARE_VM_JFR_INSTRUMENTATION_JFRJVMTIAGENT_HPP
|
||||
|
||||
#include "jfr/utilities/jfrAllocation.hpp"
|
||||
|
||||
class JfrJvmtiAgent : public JfrCHeapObj {
|
||||
friend class JfrRecorder;
|
||||
private:
|
||||
JfrJvmtiAgent();
|
||||
~JfrJvmtiAgent();
|
||||
static bool create();
|
||||
static void destroy();
|
||||
public:
|
||||
static void retransform_classes(JNIEnv* env, jobjectArray classes, TRAPS);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_JFR_INSTRUMENTATION_JFRJVMTIAGENT_HPP
|
98
src/hotspot/share/jfr/jfr.cpp
Normal file
98
src/hotspot/share/jfr/jfr.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "jfr/jfr.hpp"
|
||||
#include "jfr/leakprofiler/leakProfiler.hpp"
|
||||
#include "jfr/periodic/sampling/jfrThreadSampler.hpp"
|
||||
#include "jfr/recorder/service/jfrOptionSet.hpp"
|
||||
#include "jfr/recorder/jfrRecorder.hpp"
|
||||
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
|
||||
#include "jfr/recorder/repository/jfrEmergencyDump.hpp"
|
||||
#include "jfr/support/jfrThreadLocal.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
|
||||
bool Jfr::is_enabled() {
|
||||
return JfrRecorder::is_enabled();
|
||||
}
|
||||
|
||||
bool Jfr::is_disabled() {
|
||||
return JfrRecorder::is_disabled();
|
||||
}
|
||||
|
||||
bool Jfr::is_recording() {
|
||||
return JfrRecorder::is_recording();
|
||||
}
|
||||
|
||||
void Jfr::on_vm_init() {
|
||||
if (!JfrRecorder::on_vm_init()) {
|
||||
vm_exit_during_initialization("Failure when starting JFR on_vm_init");
|
||||
}
|
||||
}
|
||||
|
||||
void Jfr::on_vm_start() {
|
||||
if (!JfrRecorder::on_vm_start()) {
|
||||
vm_exit_during_initialization("Failure when starting JFR on_vm_start");
|
||||
}
|
||||
}
|
||||
|
||||
void Jfr::on_unloading_classes() {
|
||||
if (JfrRecorder::is_created()) {
|
||||
JfrCheckpointManager::write_type_set_for_unloaded_classes();
|
||||
}
|
||||
}
|
||||
|
||||
void Jfr::on_thread_exit(JavaThread* thread) {
|
||||
if (JfrRecorder::is_recording()) {
|
||||
JfrThreadLocal::on_exit(thread);
|
||||
}
|
||||
}
|
||||
|
||||
void Jfr::on_thread_destruct(Thread* thread) {
|
||||
if (JfrRecorder::is_created()) {
|
||||
JfrThreadLocal::on_destruct(thread);
|
||||
}
|
||||
}
|
||||
|
||||
void Jfr::on_vm_shutdown(bool exception_handler) {
|
||||
if (JfrRecorder::is_recording()) {
|
||||
JfrEmergencyDump::on_vm_shutdown(exception_handler);
|
||||
}
|
||||
}
|
||||
|
||||
void Jfr::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
|
||||
LeakProfiler::oops_do(is_alive, f);
|
||||
}
|
||||
|
||||
bool Jfr::on_start_flight_recording_option(const JavaVMOption** option, char* tail) {
|
||||
return JfrOptionSet::parse_start_flight_recording_option(option, tail);
|
||||
}
|
||||
|
||||
bool Jfr::on_flight_recorder_option(const JavaVMOption** option, char* tail) {
|
||||
return JfrOptionSet::parse_flight_recorder_option(option, tail);
|
||||
}
|
||||
|
||||
Thread* Jfr::sampler_thread() {
|
||||
return JfrThreadSampling::sampler_thread();
|
||||
}
|
58
src/hotspot/share/jfr/jfr.hpp
Normal file
58
src/hotspot/share/jfr/jfr.hpp
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_JFR_JFR_HPP
|
||||
#define SHARE_VM_JFR_JFR_HPP
|
||||
|
||||
#include "jni.h"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class BoolObjectClosure;
|
||||
class JavaThread;
|
||||
class OopClosure;
|
||||
class Thread;
|
||||
|
||||
extern "C" void JNICALL jfr_register_natives(JNIEnv*, jclass);
|
||||
|
||||
//
|
||||
// The VM interface to Flight Recorder.
|
||||
//
|
||||
class Jfr : AllStatic {
|
||||
public:
|
||||
static bool is_enabled();
|
||||
static bool is_disabled();
|
||||
static bool is_recording();
|
||||
static void on_vm_init();
|
||||
static void on_vm_start();
|
||||
static void on_unloading_classes();
|
||||
static void on_thread_exit(JavaThread* thread);
|
||||
static void on_thread_destruct(Thread* thread);
|
||||
static void on_vm_shutdown(bool exception_handler = false);
|
||||
static bool on_start_flight_recording_option(const JavaVMOption** option, char* tail);
|
||||
static bool on_flight_recorder_option(const JavaVMOption** option, char* tail);
|
||||
static void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f);
|
||||
static Thread* sampler_thread();
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_JFR_JFR_HPP
|
35
src/hotspot/share/jfr/jfrEvents.hpp
Normal file
35
src/hotspot/share/jfr/jfrEvents.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_JFR_JFREVENTS_HPP
|
||||
#define SHARE_VM_JFR_JFREVENTS_HPP
|
||||
/*
|
||||
* Declare your event in jfr/metadata/metadata.xml.
|
||||
*
|
||||
* Include this header to access the machine generated event class.
|
||||
*/
|
||||
#include "jfrfiles/jfrEventClasses.hpp"
|
||||
#include "jfrfiles/jfrEventIds.hpp"
|
||||
|
||||
#endif // SHARE_VM_JFR_JFREVENTS_HPP
|
190
src/hotspot/share/jfr/jni/jfrGetAllEventClasses.cpp
Normal file
190
src/hotspot/share/jfr/jni/jfrGetAllEventClasses.cpp
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/javaClasses.inline.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "jfr/jni/jfrGetAllEventClasses.hpp"
|
||||
#include "jfr/jni/jfrJavaSupport.hpp"
|
||||
#include "jfr/support/jfrEventClass.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/stack.inline.hpp"
|
||||
|
||||
// incremented during class unloading (safepoint) for each unloaded event class
|
||||
static jlong unloaded_event_classes = 0;
|
||||
|
||||
jlong JfrEventClasses::unloaded_event_classes_count() {
|
||||
return unloaded_event_classes;
|
||||
}
|
||||
|
||||
void JfrEventClasses::increment_unloaded_event_class() {
|
||||
// incremented during class unloading (safepoint) for each unloaded event class
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
|
||||
++unloaded_event_classes;
|
||||
}
|
||||
|
||||
static jobject empty_java_util_arraylist = NULL;
|
||||
|
||||
static oop new_java_util_arraylist(TRAPS) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
JavaValue result(T_OBJECT);
|
||||
JfrJavaArguments args(&result, "java/util/ArrayList", "<init>", "()V", CHECK_NULL);
|
||||
JfrJavaSupport::new_object(&args, CHECK_NULL);
|
||||
return (oop)result.get_jobject();
|
||||
}
|
||||
|
||||
static bool initialize(TRAPS) {
|
||||
static bool initialized = false;
|
||||
if (!initialized) {
|
||||
unloaded_event_classes = 0;
|
||||
assert(NULL == empty_java_util_arraylist, "invariant");
|
||||
const oop array_list = new_java_util_arraylist(CHECK_false);
|
||||
empty_java_util_arraylist = JfrJavaSupport::global_jni_handle(array_list, THREAD);
|
||||
initialized = empty_java_util_arraylist != NULL;
|
||||
}
|
||||
return initialized;
|
||||
}
|
||||
|
||||
/*
|
||||
* Abstract klasses are filtered out unconditionally.
|
||||
* If a klass is not yet initialized, i.e yet to run its <clinit>
|
||||
* it is also filtered out so we don't accidentally
|
||||
* trigger initialization.
|
||||
*/
|
||||
static bool is_whitelisted(const Klass* k) {
|
||||
assert(k != NULL, "invariant");
|
||||
return !(k->is_abstract() || k->should_be_initialized());
|
||||
}
|
||||
|
||||
static void fill_klasses(GrowableArray<const void*>& event_subklasses, const Klass* event_klass, Thread* thread) {
|
||||
assert(event_subklasses.length() == 0, "invariant");
|
||||
assert(event_klass != NULL, "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
|
||||
|
||||
Stack<const Klass*, mtTracing> mark_stack;
|
||||
MutexLocker ml(Compile_lock, thread);
|
||||
mark_stack.push(event_klass->subklass());
|
||||
|
||||
while (!mark_stack.is_empty()) {
|
||||
const Klass* const current = mark_stack.pop();
|
||||
assert(current != NULL, "null element in stack!");
|
||||
|
||||
if (is_whitelisted(current)) {
|
||||
event_subklasses.append(current);
|
||||
}
|
||||
|
||||
// subclass (depth)
|
||||
const Klass* next_klass = current->subklass();
|
||||
if (next_klass != NULL) {
|
||||
mark_stack.push(next_klass);
|
||||
}
|
||||
|
||||
// siblings (breadth)
|
||||
next_klass = current->next_sibling();
|
||||
if (next_klass != NULL) {
|
||||
mark_stack.push(next_klass);
|
||||
}
|
||||
}
|
||||
assert(mark_stack.is_empty(), "invariant");
|
||||
}
|
||||
|
||||
static void transform_klasses_to_local_jni_handles(GrowableArray<const void*>& event_subklasses, Thread* thread) {
|
||||
assert(event_subklasses.is_nonempty(), "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(thread));
|
||||
|
||||
for (int i = 0; i < event_subklasses.length(); ++i) {
|
||||
const InstanceKlass* k = static_cast<const InstanceKlass*>(event_subklasses.at(i));
|
||||
assert(is_whitelisted(k), "invariant");
|
||||
event_subklasses.at_put(i, JfrJavaSupport::local_jni_handle(k->java_mirror(), thread));
|
||||
}
|
||||
}
|
||||
|
||||
static const int initial_size_growable_array = 64;
|
||||
|
||||
jobject JfrEventClasses::get_all_event_classes(TRAPS) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
initialize(THREAD);
|
||||
assert(empty_java_util_arraylist != NULL, "should have been setup already!");
|
||||
static const char jdk_jfr_event_name[] = "jdk/jfr/Event";
|
||||
unsigned int unused_hash = 0;
|
||||
Symbol* const event_klass_name = SymbolTable::lookup_only(jdk_jfr_event_name, sizeof jdk_jfr_event_name - 1, unused_hash);
|
||||
|
||||
if (NULL == event_klass_name) {
|
||||
// not loaded yet
|
||||
return empty_java_util_arraylist;
|
||||
}
|
||||
|
||||
const Klass* const klass = SystemDictionary::resolve_or_null(event_klass_name, THREAD);
|
||||
assert(klass != NULL, "invariant");
|
||||
assert(JdkJfrEvent::is(klass), "invariant");
|
||||
|
||||
if (klass->subklass() == NULL) {
|
||||
return empty_java_util_arraylist;
|
||||
}
|
||||
|
||||
ResourceMark rm(THREAD);
|
||||
GrowableArray<const void*> event_subklasses(THREAD, initial_size_growable_array);
|
||||
fill_klasses(event_subklasses, klass, THREAD);
|
||||
|
||||
if (event_subklasses.is_empty()) {
|
||||
return empty_java_util_arraylist;
|
||||
}
|
||||
|
||||
transform_klasses_to_local_jni_handles(event_subklasses, THREAD);
|
||||
|
||||
Handle h_array_list(THREAD, new_java_util_arraylist(THREAD));
|
||||
assert(h_array_list.not_null(), "invariant");
|
||||
|
||||
static const char add_method_name[] = "add";
|
||||
static const char add_method_signature[] = "(Ljava/lang/Object;)Z";
|
||||
const Klass* const array_list_klass = JfrJavaSupport::klass(empty_java_util_arraylist);
|
||||
assert(array_list_klass != NULL, "invariant");
|
||||
|
||||
const Symbol* const add_method_sym = SymbolTable::lookup(add_method_name, sizeof add_method_name - 1, THREAD);
|
||||
assert(add_method_sym != NULL, "invariant");
|
||||
|
||||
const Symbol* const add_method_sig_sym = SymbolTable::lookup(add_method_signature, sizeof add_method_signature - 1, THREAD);
|
||||
assert(add_method_signature != NULL, "invariant");
|
||||
|
||||
JavaValue result(T_BOOLEAN);
|
||||
for (int i = 0; i < event_subklasses.length(); ++i) {
|
||||
const jclass clazz = (const jclass)event_subklasses.at(i);
|
||||
assert(JdkJfrEvent::is_subklass(clazz), "invariant");
|
||||
JfrJavaArguments args(&result, array_list_klass, add_method_sym, add_method_sig_sym);
|
||||
args.set_receiver(h_array_list());
|
||||
args.push_jobject(clazz);
|
||||
JfrJavaSupport::call_virtual(&args, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION || JNI_FALSE == result.get_jboolean()) {
|
||||
return empty_java_util_arraylist;
|
||||
}
|
||||
}
|
||||
return JfrJavaSupport::local_jni_handle(h_array_list(), THREAD);
|
||||
}
|
41
src/hotspot/share/jfr/jni/jfrGetAllEventClasses.hpp
Normal file
41
src/hotspot/share/jfr/jni/jfrGetAllEventClasses.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef SHARE_VM_JFR_JNI_JFRGETALLEVENTCLASSES_HPP
|
||||
#define SHARE_VM_JFR_JNI_JFRGETALLEVENTCLASSES_HPP
|
||||
|
||||
#include "jni.h"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
|
||||
//
|
||||
// Responsible for the delivery of currently loaded jdk.jfr.Event subklasses to Java.
|
||||
//
|
||||
class JfrEventClasses : AllStatic {
|
||||
public:
|
||||
static void increment_unloaded_event_class();
|
||||
static jlong unloaded_event_classes_count();
|
||||
static jobject get_all_event_classes(TRAPS);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_JFR_JNI_JFRGETALLEVENTCLASSES_HPP
|
380
src/hotspot/share/jfr/jni/jfrJavaCall.cpp
Normal file
380
src/hotspot/share/jfr/jni/jfrJavaCall.cpp
Normal file
@ -0,0 +1,380 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "jfr/jni/jfrJavaCall.hpp"
|
||||
#include "jfr/jni/jfrJavaSupport.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
#ifdef ASSERT
|
||||
static bool is_large_value(const JavaValue& value) {
|
||||
return value.get_type() == T_LONG || value.get_type() == T_DOUBLE;
|
||||
}
|
||||
#endif // ASSERT
|
||||
|
||||
static Symbol* resolve(const char* str, TRAPS) {
|
||||
assert(str != NULL, "invariant");
|
||||
return SymbolTable::lookup(str, (int)strlen(str), THREAD);
|
||||
}
|
||||
|
||||
static Klass* resolve(Symbol* k_sym, TRAPS) {
|
||||
assert(k_sym != NULL, "invariant");
|
||||
return SystemDictionary::resolve_or_fail(k_sym, true, THREAD);
|
||||
}
|
||||
|
||||
JfrJavaArguments::Parameters::Parameters() : _storage_index(0), _java_stack_slots(0) {
|
||||
JavaValue value(T_VOID);
|
||||
push(value);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::Parameters::push(const JavaValue& value) {
|
||||
assert(_storage != NULL, "invariant");
|
||||
assert(!is_large_value(value), "invariant");
|
||||
assert(_storage_index < SIZE, "invariant");
|
||||
_storage[_storage_index++] = value;
|
||||
_java_stack_slots++;
|
||||
}
|
||||
|
||||
void JfrJavaArguments::Parameters::push_large(const JavaValue& value) {
|
||||
assert(_storage != NULL, "invariant");
|
||||
assert(is_large_value(value), "invariant");
|
||||
assert(_storage_index < SIZE, "invariant");
|
||||
_storage[_storage_index++] = value;
|
||||
_java_stack_slots += 2;
|
||||
}
|
||||
|
||||
void JfrJavaArguments::Parameters::set_receiver(const oop receiver) {
|
||||
assert(_storage != NULL, "invariant");
|
||||
assert(receiver != NULL, "invariant");
|
||||
JavaValue value(T_OBJECT);
|
||||
value.set_jobject((jobject)receiver);
|
||||
_storage[0] = value;
|
||||
}
|
||||
|
||||
void JfrJavaArguments::Parameters::set_receiver(Handle receiver) {
|
||||
set_receiver(receiver());
|
||||
}
|
||||
|
||||
oop JfrJavaArguments::Parameters::receiver() const {
|
||||
assert(has_receiver(), "invariant");
|
||||
assert(_storage[0].get_type() == T_OBJECT, "invariant");
|
||||
return (oop)_storage[0].get_jobject();
|
||||
}
|
||||
|
||||
bool JfrJavaArguments::Parameters::has_receiver() const {
|
||||
assert(_storage != NULL, "invariant");
|
||||
assert(_storage_index >= 1, "invariant");
|
||||
assert(_java_stack_slots >= 1, "invariant");
|
||||
return _storage[0].get_type() == T_OBJECT;
|
||||
}
|
||||
|
||||
void JfrJavaArguments::Parameters::push_oop(const oop obj) {
|
||||
JavaValue value(T_OBJECT);
|
||||
value.set_jobject((jobject)obj);
|
||||
push(value);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::Parameters::push_oop(Handle h_obj) {
|
||||
push_oop(h_obj());
|
||||
}
|
||||
|
||||
void JfrJavaArguments::Parameters::push_jobject(jobject h) {
|
||||
JavaValue value(T_ADDRESS);
|
||||
value.set_jobject(h);
|
||||
push(value);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::Parameters::push_jint(jint i) {
|
||||
JavaValue value(T_INT);
|
||||
value.set_jint(i);
|
||||
push(value);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::Parameters::push_jfloat(jfloat f) {
|
||||
JavaValue value(T_FLOAT);
|
||||
value.set_jfloat(f);
|
||||
push(value);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::Parameters::push_jdouble(jdouble d) {
|
||||
JavaValue value(T_DOUBLE);
|
||||
value.set_jdouble(d);
|
||||
push_large(value);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::Parameters::push_jlong(jlong l) {
|
||||
JavaValue value(T_LONG);
|
||||
value.set_jlong(l);
|
||||
push_large(value);
|
||||
}
|
||||
|
||||
// including receiver (even if there is none)
|
||||
inline int JfrJavaArguments::Parameters::length() const {
|
||||
assert(_storage_index >= 1, "invariant");
|
||||
return _storage_index;
|
||||
}
|
||||
|
||||
inline int JfrJavaArguments::Parameters::java_stack_slots() const {
|
||||
return _java_stack_slots;
|
||||
}
|
||||
|
||||
const JavaValue& JfrJavaArguments::Parameters::values(int idx) const {
|
||||
assert(idx >= 0, "invariant");
|
||||
assert(idx < SIZE, "invariant");
|
||||
return _storage[idx];
|
||||
}
|
||||
|
||||
void JfrJavaArguments::Parameters::copy(JavaCallArguments& args, TRAPS) const {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
if (has_receiver()) {
|
||||
args.set_receiver(Handle(THREAD, receiver()));
|
||||
}
|
||||
for (int i = 1; i < length(); ++i) {
|
||||
switch(values(i).get_type()) {
|
||||
case T_BOOLEAN:
|
||||
case T_CHAR:
|
||||
case T_SHORT:
|
||||
case T_INT:
|
||||
args.push_int(values(i).get_jint());
|
||||
break;
|
||||
case T_LONG:
|
||||
args.push_long(values(i).get_jlong());
|
||||
break;
|
||||
case T_FLOAT:
|
||||
args.push_float(values(i).get_jfloat());
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
args.push_double(values(i).get_jdouble());
|
||||
break;
|
||||
case T_OBJECT:
|
||||
args.push_oop(Handle(THREAD, (oop)values(i).get_jobject()));
|
||||
break;
|
||||
case T_ADDRESS:
|
||||
args.push_jobject(values(i).get_jobject());
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JfrJavaArguments::JfrJavaArguments(JavaValue* result) : _result(result), _klass(NULL), _name(NULL), _signature(NULL), _array_length(0) {
|
||||
assert(result != NULL, "invariant");
|
||||
}
|
||||
|
||||
JfrJavaArguments::JfrJavaArguments(JavaValue* result, const char* klass_name, const char* name, const char* signature, TRAPS) :
|
||||
_result(result),
|
||||
_klass(NULL),
|
||||
_name(NULL),
|
||||
_signature(NULL),
|
||||
_array_length(0) {
|
||||
assert(result != NULL, "invariant");
|
||||
if (klass_name != NULL) {
|
||||
set_klass(klass_name, CHECK);
|
||||
}
|
||||
if (name != NULL) {
|
||||
set_name(name, CHECK);
|
||||
}
|
||||
if (signature != NULL) {
|
||||
set_signature(signature, THREAD);
|
||||
}
|
||||
}
|
||||
|
||||
JfrJavaArguments::JfrJavaArguments(JavaValue* result, const Klass* klass, const Symbol* name, const Symbol* signature) : _result(result),
|
||||
_klass(NULL),
|
||||
_name(NULL),
|
||||
_signature(NULL),
|
||||
_array_length(0) {
|
||||
assert(result != NULL, "invariant");
|
||||
if (klass != NULL) {
|
||||
set_klass(klass);
|
||||
}
|
||||
if (name != NULL) {
|
||||
set_name(name);
|
||||
}
|
||||
if (signature != NULL) {
|
||||
set_signature(signature);
|
||||
}
|
||||
}
|
||||
|
||||
Klass* JfrJavaArguments::klass() const {
|
||||
assert(_klass != NULL, "invariant");
|
||||
return const_cast<Klass*>(_klass);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::set_klass(const char* klass_name, TRAPS) {
|
||||
assert(klass_name != NULL, "invariant");
|
||||
Symbol* const k_sym = resolve(klass_name, CHECK);
|
||||
assert(k_sym != NULL, "invariant");
|
||||
const Klass* const klass = resolve(k_sym, CHECK);
|
||||
set_klass(klass);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::set_klass(const Klass* klass) {
|
||||
assert(klass != NULL, "invariant");
|
||||
_klass = klass;
|
||||
}
|
||||
|
||||
Symbol* JfrJavaArguments::name() const {
|
||||
assert(_name != NULL, "invariant");
|
||||
return const_cast<Symbol*>(_name);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::set_name(const char* name, TRAPS) {
|
||||
assert(name != NULL, "invariant");
|
||||
const Symbol* const sym = resolve(name, CHECK);
|
||||
set_name(sym);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::set_name(const Symbol* name) {
|
||||
assert(name != NULL, "invariant");
|
||||
_name = name;
|
||||
}
|
||||
|
||||
Symbol* JfrJavaArguments::signature() const {
|
||||
assert(_signature != NULL, "invariant");
|
||||
return const_cast<Symbol*>(_signature);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::set_signature(const char* signature, TRAPS) {
|
||||
assert(signature != NULL, "invariant");
|
||||
const Symbol* const sym = resolve(signature, CHECK);
|
||||
set_signature(sym);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::set_signature(const Symbol* signature) {
|
||||
assert(signature != NULL, "invariant");
|
||||
_signature = signature;
|
||||
}
|
||||
|
||||
int JfrJavaArguments::array_length() const {
|
||||
return _array_length;
|
||||
}
|
||||
|
||||
void JfrJavaArguments::set_array_length(int length) {
|
||||
assert(length >= 0, "invariant");
|
||||
_array_length = length;
|
||||
}
|
||||
|
||||
JavaValue* JfrJavaArguments::result() const {
|
||||
assert(_result != NULL, "invariant");
|
||||
return const_cast<JavaValue*>(_result);
|
||||
}
|
||||
|
||||
int JfrJavaArguments::length() const {
|
||||
return _params.length();
|
||||
}
|
||||
|
||||
bool JfrJavaArguments::has_receiver() const {
|
||||
return _params.has_receiver();
|
||||
}
|
||||
|
||||
oop JfrJavaArguments::receiver() const {
|
||||
return _params.receiver();
|
||||
}
|
||||
|
||||
void JfrJavaArguments::set_receiver(const oop receiver) {
|
||||
_params.set_receiver(receiver);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::set_receiver(Handle receiver) {
|
||||
_params.set_receiver(receiver);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::push_oop(const oop obj) {
|
||||
_params.push_oop(obj);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::push_oop(Handle h_obj) {
|
||||
_params.push_oop(h_obj);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::push_jobject(jobject h) {
|
||||
_params.push_jobject(h);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::push_int(jint i) {
|
||||
_params.push_jint(i);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::push_float(jfloat f) {
|
||||
_params.push_jfloat(f);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::push_double(jdouble d) {
|
||||
_params.push_jdouble(d);
|
||||
}
|
||||
|
||||
void JfrJavaArguments::push_long(jlong l) {
|
||||
_params.push_jlong(l);
|
||||
}
|
||||
|
||||
const JavaValue& JfrJavaArguments::param(int idx) const {
|
||||
return _params.values(idx);
|
||||
}
|
||||
|
||||
int JfrJavaArguments::java_call_arg_slots() const {
|
||||
return _params.java_stack_slots();
|
||||
}
|
||||
|
||||
void JfrJavaArguments::copy(JavaCallArguments& args, TRAPS) {
|
||||
_params.copy(args, THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaCall::call_static(JfrJavaArguments* args, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
ResourceMark rm(THREAD);
|
||||
HandleMark hm(THREAD);
|
||||
JavaCallArguments jcas(args->java_call_arg_slots());
|
||||
args->copy(jcas, CHECK);
|
||||
JavaCalls::call_static(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaCall::call_special(JfrJavaArguments* args, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
assert(args->has_receiver(), "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
ResourceMark rm(THREAD);
|
||||
HandleMark hm(THREAD);
|
||||
JavaCallArguments jcas(args->java_call_arg_slots());
|
||||
args->copy(jcas, CHECK);
|
||||
JavaCalls::call_special(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaCall::call_virtual(JfrJavaArguments* args, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
assert(args->has_receiver(), "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
ResourceMark rm(THREAD);
|
||||
HandleMark hm(THREAD);
|
||||
JavaCallArguments jcas(args->java_call_arg_slots());
|
||||
args->copy(jcas, CHECK);
|
||||
JavaCalls::call_virtual(args->result(), args->klass(), args->name(), args->signature(), &jcas, THREAD);
|
||||
}
|
134
src/hotspot/share/jfr/jni/jfrJavaCall.hpp
Normal file
134
src/hotspot/share/jfr/jni/jfrJavaCall.hpp
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_JFR_JNI_JFRJAVACALL_HPP
|
||||
#define SHARE_VM_JFR_JNI_JFRJAVACALL_HPP
|
||||
|
||||
#include "jni.h"
|
||||
#include "jfr/utilities/jfrAllocation.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
|
||||
class JavaCallArguments;
|
||||
class JavaThread;
|
||||
class JavaValue;
|
||||
class Klass;
|
||||
class Symbol;
|
||||
|
||||
class JfrJavaArguments : public StackObj {
|
||||
friend class JfrJavaCall;
|
||||
public:
|
||||
JfrJavaArguments(JavaValue* result);
|
||||
JfrJavaArguments(JavaValue* result, const char* klass_name, const char* name, const char* signature, TRAPS);
|
||||
JfrJavaArguments(JavaValue* result, const Klass* klass, const Symbol* name, const Symbol* signature);
|
||||
|
||||
Klass* klass() const;
|
||||
void set_klass(const char* klass_name, TRAPS);
|
||||
void set_klass(const Klass* klass);
|
||||
|
||||
Symbol* name() const;
|
||||
void set_name(const char* name, TRAPS);
|
||||
void set_name(const Symbol* name);
|
||||
|
||||
Symbol* signature() const;
|
||||
void set_signature(const char* signature, TRAPS);
|
||||
void set_signature(const Symbol* signature);
|
||||
|
||||
int array_length() const;
|
||||
void set_array_length(int length);
|
||||
|
||||
JavaValue* result() const;
|
||||
|
||||
bool has_receiver() const;
|
||||
void set_receiver(const oop receiver);
|
||||
void set_receiver(Handle receiver);
|
||||
oop receiver() const;
|
||||
|
||||
// parameters
|
||||
void push_oop(const oop obj);
|
||||
void push_oop(Handle h_obj);
|
||||
void push_jobject(jobject h);
|
||||
void push_int(jint i);
|
||||
void push_double(jdouble d);
|
||||
void push_long(jlong l);
|
||||
void push_float(jfloat f);
|
||||
|
||||
int length() const;
|
||||
const JavaValue& param(int idx) const;
|
||||
|
||||
private:
|
||||
class Parameters {
|
||||
friend class JfrJavaArguments;
|
||||
private:
|
||||
enum { SIZE = 16};
|
||||
JavaValue _storage[SIZE];
|
||||
int _storage_index;
|
||||
int _java_stack_slots;
|
||||
|
||||
Parameters();
|
||||
Parameters(const Parameters&); // no impl
|
||||
Parameters& operator=(const Parameters&); // no impl
|
||||
|
||||
void push(const JavaValue& value);
|
||||
void push_large(const JavaValue& value);
|
||||
|
||||
void push_oop(const oop obj);
|
||||
void push_oop(Handle h_obj);
|
||||
void push_jobject(jobject h);
|
||||
void push_jint(jint i);
|
||||
void push_jdouble(jdouble d);
|
||||
void push_jlong(jlong l);
|
||||
void push_jfloat(jfloat f);
|
||||
|
||||
bool has_receiver() const;
|
||||
void set_receiver(const oop receiver);
|
||||
void set_receiver(Handle receiver);
|
||||
oop receiver() const;
|
||||
|
||||
int length() const;
|
||||
int java_stack_slots() const;
|
||||
|
||||
void copy(JavaCallArguments& args, TRAPS) const;
|
||||
const JavaValue& values(int idx) const;
|
||||
};
|
||||
|
||||
Parameters _params;
|
||||
const JavaValue* const _result;
|
||||
const Klass* _klass;
|
||||
const Symbol* _name;
|
||||
const Symbol* _signature;
|
||||
int _array_length;
|
||||
|
||||
int java_call_arg_slots() const;
|
||||
void copy(JavaCallArguments& args, TRAPS);
|
||||
};
|
||||
|
||||
class JfrJavaCall : public AllStatic {
|
||||
friend class JfrJavaSupport;
|
||||
private:
|
||||
static void call_static(JfrJavaArguments* args, TRAPS);
|
||||
static void call_special(JfrJavaArguments* args, TRAPS);
|
||||
static void call_virtual(JfrJavaArguments* args, TRAPS);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_JFR_JNI_JFRJAVACALL_HPP
|
612
src/hotspot/share/jfr/jni/jfrJavaSupport.cpp
Normal file
612
src/hotspot/share/jfr/jni/jfrJavaSupport.cpp
Normal file
@ -0,0 +1,612 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "jni.h"
|
||||
#include "classfile/javaClasses.inline.hpp"
|
||||
#include "classfile/modules.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "jfr/jni/jfrJavaCall.hpp"
|
||||
#include "jfr/jni/jfrJavaSupport.hpp"
|
||||
#include "jfr/support/jfrThreadId.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/instanceOop.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/objArrayKlass.hpp"
|
||||
#include "oops/objArrayOop.inline.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/fieldDescriptor.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/jniHandles.inline.hpp"
|
||||
#include "runtime/synchronizer.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
|
||||
#ifdef ASSERT
|
||||
void JfrJavaSupport::check_java_thread_in_vm(Thread* t) {
|
||||
assert(t != NULL, "invariant");
|
||||
assert(t->is_Java_thread(), "invariant");
|
||||
assert(((JavaThread*)t)->thread_state() == _thread_in_vm, "invariant");
|
||||
}
|
||||
|
||||
void JfrJavaSupport::check_java_thread_in_native(Thread* t) {
|
||||
assert(t != NULL, "invariant");
|
||||
assert(t->is_Java_thread(), "invariant");
|
||||
assert(((JavaThread*)t)->thread_state() == _thread_in_native, "invariant");
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handles and references
|
||||
*/
|
||||
jobject JfrJavaSupport::local_jni_handle(const oop obj, Thread* t) {
|
||||
DEBUG_ONLY(check_java_thread_in_vm(t));
|
||||
return t->active_handles()->allocate_handle(obj);
|
||||
}
|
||||
|
||||
jobject JfrJavaSupport::local_jni_handle(const jobject handle, Thread* t) {
|
||||
DEBUG_ONLY(check_java_thread_in_vm(t));
|
||||
const oop obj = JNIHandles::resolve(handle);
|
||||
return obj == NULL ? NULL : local_jni_handle(obj, t);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::destroy_local_jni_handle(jobject handle) {
|
||||
JNIHandles::destroy_local(handle);
|
||||
}
|
||||
|
||||
jobject JfrJavaSupport::global_jni_handle(const oop obj, Thread* t) {
|
||||
DEBUG_ONLY(check_java_thread_in_vm(t));
|
||||
HandleMark hm(t);
|
||||
return JNIHandles::make_global(Handle(t, obj));
|
||||
}
|
||||
|
||||
jobject JfrJavaSupport::global_jni_handle(const jobject handle, Thread* t) {
|
||||
const oop obj = JNIHandles::resolve(handle);
|
||||
return obj == NULL ? NULL : global_jni_handle(obj, t);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::destroy_global_jni_handle(jobject handle) {
|
||||
JNIHandles::destroy_global(handle);
|
||||
}
|
||||
|
||||
oop JfrJavaSupport::resolve_non_null(jobject obj) {
|
||||
return JNIHandles::resolve_non_null(obj);
|
||||
}
|
||||
|
||||
/*
|
||||
* Method invocation
|
||||
*/
|
||||
void JfrJavaSupport::call_static(JfrJavaArguments* args, TRAPS) {
|
||||
JfrJavaCall::call_static(args, THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::call_special(JfrJavaArguments* args, TRAPS) {
|
||||
JfrJavaCall::call_special(args, THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::call_virtual(JfrJavaArguments* args, TRAPS) {
|
||||
JfrJavaCall::call_virtual(args, THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::notify_all(jobject object, TRAPS) {
|
||||
assert(object != NULL, "invariant");
|
||||
DEBUG_ONLY(check_java_thread_in_vm(THREAD));
|
||||
HandleMark hm(THREAD);
|
||||
Handle h_obj(THREAD, resolve_non_null(object));
|
||||
assert(h_obj.not_null(), "invariant");
|
||||
ObjectSynchronizer::jni_enter(h_obj, THREAD);
|
||||
ObjectSynchronizer::notifyall(h_obj, THREAD);
|
||||
ObjectSynchronizer::jni_exit(h_obj(), THREAD);
|
||||
DEBUG_ONLY(check_java_thread_in_vm(THREAD));
|
||||
}
|
||||
|
||||
/*
|
||||
* Object construction
|
||||
*/
|
||||
static void object_construction(JfrJavaArguments* args, JavaValue* result, InstanceKlass* klass, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
assert(result != NULL, "invariant");
|
||||
assert(klass != NULL, "invariant");
|
||||
assert(klass->is_initialized(), "invariant");
|
||||
|
||||
HandleMark hm(THREAD);
|
||||
instanceOop obj = klass->allocate_instance(CHECK);
|
||||
instanceHandle h_obj(THREAD, obj);
|
||||
assert(h_obj.not_null(), "invariant");
|
||||
args->set_receiver(h_obj);
|
||||
result->set_type(T_VOID); // constructor result type
|
||||
JfrJavaSupport::call_special(args, CHECK);
|
||||
result->set_type(T_OBJECT); // set back to original result type
|
||||
result->set_jobject((jobject)h_obj());
|
||||
}
|
||||
|
||||
static void array_construction(JfrJavaArguments* args, JavaValue* result, InstanceKlass* klass, int array_length, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
assert(result != NULL, "invariant");
|
||||
assert(klass != NULL, "invariant");
|
||||
assert(klass->is_initialized(), "invariant");
|
||||
|
||||
Klass* const ak = klass->array_klass(THREAD);
|
||||
ObjArrayKlass::cast(ak)->initialize(THREAD);
|
||||
HandleMark hm(THREAD);
|
||||
objArrayOop arr = ObjArrayKlass::cast(ak)->allocate(array_length, CHECK);
|
||||
result->set_jobject((jobject)arr);
|
||||
}
|
||||
|
||||
static void create_object(JfrJavaArguments* args, JavaValue* result, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
assert(result != NULL, "invariant");
|
||||
assert(result->get_type() == T_OBJECT, "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
|
||||
InstanceKlass* const klass = static_cast<InstanceKlass*>(args->klass());
|
||||
klass->initialize(CHECK);
|
||||
|
||||
const int array_length = args->array_length();
|
||||
|
||||
if (array_length > 0) {
|
||||
array_construction(args, result, klass, array_length, CHECK);
|
||||
} else {
|
||||
object_construction(args, result, klass, THREAD);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_result(JavaValue* result, bool global_ref, Thread* t) {
|
||||
assert(result != NULL, "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(t));
|
||||
const oop result_oop = (const oop)result->get_jobject();
|
||||
if (result_oop == NULL) {
|
||||
return;
|
||||
}
|
||||
result->set_jobject(global_ref ?
|
||||
JfrJavaSupport::global_jni_handle(result_oop, t) :
|
||||
JfrJavaSupport::local_jni_handle(result_oop, t));
|
||||
}
|
||||
|
||||
void JfrJavaSupport::new_object(JfrJavaArguments* args, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
DEBUG_ONLY(check_java_thread_in_vm(THREAD));
|
||||
create_object(args, args->result(), THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::new_object_local_ref(JfrJavaArguments* args, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
DEBUG_ONLY(check_java_thread_in_vm(THREAD));
|
||||
JavaValue* const result = args->result();
|
||||
assert(result != NULL, "invariant");
|
||||
create_object(args, result, CHECK);
|
||||
handle_result(result, false, THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::new_object_global_ref(JfrJavaArguments* args, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
DEBUG_ONLY(check_java_thread_in_vm(THREAD));
|
||||
JavaValue* const result = args->result();
|
||||
assert(result != NULL, "invariant");
|
||||
create_object(args, result, CHECK);
|
||||
handle_result(result, true, THREAD);
|
||||
}
|
||||
|
||||
jstring JfrJavaSupport::new_string(const char* c_str, TRAPS) {
|
||||
assert(c_str != NULL, "invariant");
|
||||
DEBUG_ONLY(check_java_thread_in_vm(THREAD));
|
||||
const oop result = java_lang_String::create_oop_from_str(c_str, THREAD);
|
||||
return (jstring)local_jni_handle(result, THREAD);
|
||||
}
|
||||
|
||||
jobjectArray JfrJavaSupport::new_string_array(int length, TRAPS) {
|
||||
DEBUG_ONLY(check_java_thread_in_vm(THREAD));
|
||||
JavaValue result(T_OBJECT);
|
||||
JfrJavaArguments args(&result, "java/lang/String", "<init>", "()V", CHECK_NULL);
|
||||
args.set_array_length(length);
|
||||
new_object_local_ref(&args, THREAD);
|
||||
return (jobjectArray)args.result()->get_jobject();
|
||||
}
|
||||
|
||||
jobject JfrJavaSupport::new_java_lang_Boolean(bool value, TRAPS) {
|
||||
DEBUG_ONLY(check_java_thread_in_vm(THREAD));
|
||||
JavaValue result(T_OBJECT);
|
||||
JfrJavaArguments args(&result, "java/lang/Boolean", "<init>", "(Z)V", CHECK_NULL);
|
||||
args.push_int(value ? (jint)JNI_TRUE : (jint)JNI_FALSE);
|
||||
new_object_local_ref(&args, THREAD);
|
||||
return args.result()->get_jobject();
|
||||
}
|
||||
|
||||
jobject JfrJavaSupport::new_java_lang_Integer(jint value, TRAPS) {
|
||||
DEBUG_ONLY(check_java_thread_in_vm(THREAD));
|
||||
JavaValue result(T_OBJECT);
|
||||
JfrJavaArguments args(&result, "java/lang/Integer", "<init>", "(I)V", CHECK_NULL);
|
||||
args.push_int(value);
|
||||
new_object_local_ref(&args, THREAD);
|
||||
return args.result()->get_jobject();
|
||||
}
|
||||
|
||||
jobject JfrJavaSupport::new_java_lang_Long(jlong value, TRAPS) {
|
||||
DEBUG_ONLY(check_java_thread_in_vm(THREAD));
|
||||
JavaValue result(T_OBJECT);
|
||||
JfrJavaArguments args(&result, "java/lang/Long", "<init>", "(J)V", CHECK_NULL);
|
||||
args.push_long(value);
|
||||
new_object_local_ref(&args, THREAD);
|
||||
return args.result()->get_jobject();
|
||||
}
|
||||
|
||||
void JfrJavaSupport::set_array_element(jobjectArray arr, jobject element, int index, Thread* t) {
|
||||
assert(arr != NULL, "invariant");
|
||||
DEBUG_ONLY(check_java_thread_in_vm(t));
|
||||
HandleMark hm(t);
|
||||
objArrayHandle a(t, (objArrayOop)resolve_non_null(arr));
|
||||
a->obj_at_put(index, resolve_non_null(element));
|
||||
}
|
||||
|
||||
/*
|
||||
* Field access
|
||||
*/
|
||||
static void write_int_field(const Handle& h_oop, fieldDescriptor* fd, jint value) {
|
||||
assert(h_oop.not_null(), "invariant");
|
||||
assert(fd != NULL, "invariant");
|
||||
h_oop->int_field_put(fd->offset(), value);
|
||||
}
|
||||
|
||||
static void write_float_field(const Handle& h_oop, fieldDescriptor* fd, jfloat value) {
|
||||
assert(h_oop.not_null(), "invariant");
|
||||
assert(fd != NULL, "invariant");
|
||||
h_oop->float_field_put(fd->offset(), value);
|
||||
}
|
||||
|
||||
static void write_double_field(const Handle& h_oop, fieldDescriptor* fd, jdouble value) {
|
||||
assert(h_oop.not_null(), "invariant");
|
||||
assert(fd != NULL, "invariant");
|
||||
h_oop->double_field_put(fd->offset(), value);
|
||||
}
|
||||
|
||||
static void write_long_field(const Handle& h_oop, fieldDescriptor* fd, jlong value) {
|
||||
assert(h_oop.not_null(), "invariant");
|
||||
assert(fd != NULL, "invariant");
|
||||
h_oop->long_field_put(fd->offset(), value);
|
||||
}
|
||||
|
||||
static void write_oop_field(const Handle& h_oop, fieldDescriptor* fd, const oop value) {
|
||||
assert(h_oop.not_null(), "invariant");
|
||||
assert(fd != NULL, "invariant");
|
||||
h_oop->obj_field_put(fd->offset(), value);
|
||||
}
|
||||
|
||||
static void write_specialized_field(JfrJavaArguments* args, const Handle& h_oop, fieldDescriptor* fd, bool static_field) {
|
||||
assert(args != NULL, "invariant");
|
||||
assert(h_oop.not_null(), "invariant");
|
||||
assert(fd != NULL, "invariant");
|
||||
assert(fd->offset() > 0, "invariant");
|
||||
assert(args->length() >= 1, "invariant");
|
||||
|
||||
// attempt must set a real value
|
||||
assert(args->param(1).get_type() != T_VOID, "invariant");
|
||||
|
||||
switch(fd->field_type()) {
|
||||
case T_BOOLEAN:
|
||||
case T_CHAR:
|
||||
case T_SHORT:
|
||||
case T_INT:
|
||||
write_int_field(h_oop, fd, args->param(1).get_jint());
|
||||
break;
|
||||
case T_FLOAT:
|
||||
write_float_field(h_oop, fd, args->param(1).get_jfloat());
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
write_double_field(h_oop, fd, args->param(1).get_jdouble());
|
||||
break;
|
||||
case T_LONG:
|
||||
write_long_field(h_oop, fd, args->param(1).get_jlong());
|
||||
break;
|
||||
case T_OBJECT:
|
||||
write_oop_field(h_oop, fd, (oop)args->param(1).get_jobject());
|
||||
break;
|
||||
case T_ADDRESS:
|
||||
write_oop_field(h_oop, fd, JfrJavaSupport::resolve_non_null(args->param(1).get_jobject()));
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
static void read_specialized_field(JavaValue* result, const Handle& h_oop, fieldDescriptor* fd) {
|
||||
assert(result != NULL, "invariant");
|
||||
assert(h_oop.not_null(), "invariant");
|
||||
assert(fd != NULL, "invariant");
|
||||
assert(fd->offset() > 0, "invariant");
|
||||
|
||||
switch(fd->field_type()) {
|
||||
case T_BOOLEAN:
|
||||
case T_CHAR:
|
||||
case T_SHORT:
|
||||
case T_INT:
|
||||
result->set_jint(h_oop->int_field(fd->offset()));
|
||||
break;
|
||||
case T_FLOAT:
|
||||
result->set_jfloat(h_oop->float_field(fd->offset()));
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
result->set_jdouble(h_oop->double_field(fd->offset()));
|
||||
break;
|
||||
case T_LONG:
|
||||
result->set_jlong(h_oop->long_field(fd->offset()));
|
||||
break;
|
||||
case T_OBJECT:
|
||||
result->set_jobject((jobject)h_oop->obj_field(fd->offset()));
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
static bool find_field(InstanceKlass* ik,
|
||||
Symbol* name_symbol,
|
||||
Symbol* signature_symbol,
|
||||
fieldDescriptor* fd,
|
||||
bool is_static = false,
|
||||
bool allow_super = false) {
|
||||
if (allow_super || is_static) {
|
||||
return ik->find_field(name_symbol, signature_symbol, is_static, fd) != NULL;
|
||||
}
|
||||
return ik->find_local_field(name_symbol, signature_symbol, fd);
|
||||
}
|
||||
|
||||
static void lookup_field(JfrJavaArguments* args, InstanceKlass* klass, fieldDescriptor* fd, bool static_field) {
|
||||
assert(args != NULL, "invariant");
|
||||
assert(klass != NULL, "invariant");
|
||||
assert(klass->is_initialized(), "invariant");
|
||||
assert(fd != NULL, "invariant");
|
||||
find_field(klass, args->name(), args->signature(), fd, static_field, true);
|
||||
}
|
||||
|
||||
static void read_field(JfrJavaArguments* args, JavaValue* result, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
assert(result != NULL, "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
|
||||
InstanceKlass* const klass = static_cast<InstanceKlass*>(args->klass());
|
||||
klass->initialize(CHECK);
|
||||
const bool static_field = !args->has_receiver();
|
||||
fieldDescriptor fd;
|
||||
lookup_field(args, klass, &fd, static_field);
|
||||
assert(fd.offset() > 0, "invariant");
|
||||
|
||||
HandleMark hm(THREAD);
|
||||
Handle h_oop(static_field ? Handle(THREAD, klass->java_mirror()) : Handle(THREAD, args->receiver()));
|
||||
read_specialized_field(result, h_oop, &fd);
|
||||
}
|
||||
|
||||
static void write_field(JfrJavaArguments* args, JavaValue* result, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
assert(result != NULL, "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
|
||||
InstanceKlass* const klass = static_cast<InstanceKlass*>(args->klass());
|
||||
klass->initialize(CHECK);
|
||||
|
||||
const bool static_field = !args->has_receiver();
|
||||
fieldDescriptor fd;
|
||||
lookup_field(args, klass, &fd, static_field);
|
||||
assert(fd.offset() > 0, "invariant");
|
||||
|
||||
HandleMark hm(THREAD);
|
||||
Handle h_oop(static_field ? Handle(THREAD, klass->java_mirror()) : Handle(THREAD, args->receiver()));
|
||||
write_specialized_field(args, h_oop, &fd, static_field);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::set_field(JfrJavaArguments* args, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
write_field(args, args->result(), THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::get_field(JfrJavaArguments* args, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
read_field(args, args->result(), THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::get_field_local_ref(JfrJavaArguments* args, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
DEBUG_ONLY(check_java_thread_in_vm(THREAD));
|
||||
|
||||
JavaValue* const result = args->result();
|
||||
assert(result != NULL, "invariant");
|
||||
assert(result->get_type() == T_OBJECT, "invariant");
|
||||
|
||||
read_field(args, result, CHECK);
|
||||
const oop obj = (const oop)result->get_jobject();
|
||||
|
||||
if (obj != NULL) {
|
||||
result->set_jobject(local_jni_handle(obj, THREAD));
|
||||
}
|
||||
}
|
||||
|
||||
void JfrJavaSupport::get_field_global_ref(JfrJavaArguments* args, TRAPS) {
|
||||
assert(args != NULL, "invariant");
|
||||
DEBUG_ONLY(check_java_thread_in_vm(THREAD));
|
||||
|
||||
JavaValue* const result = args->result();
|
||||
assert(result != NULL, "invariant");
|
||||
assert(result->get_type() == T_OBJECT, "invariant");
|
||||
read_field(args, result, CHECK);
|
||||
const oop obj = (const oop)result->get_jobject();
|
||||
if (obj != NULL) {
|
||||
result->set_jobject(global_jni_handle(obj, THREAD));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Misc
|
||||
*/
|
||||
Klass* JfrJavaSupport::klass(const jobject handle) {
|
||||
const oop obj = resolve_non_null(handle);
|
||||
assert(obj != NULL, "invariant");
|
||||
return obj->klass();
|
||||
}
|
||||
|
||||
// caller needs ResourceMark
|
||||
const char* JfrJavaSupport::c_str(jstring string, Thread* t) {
|
||||
DEBUG_ONLY(check_java_thread_in_vm(t));
|
||||
if (string == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
const char* temp = NULL;
|
||||
const oop java_string = resolve_non_null(string);
|
||||
if (java_lang_String::value(java_string) != NULL) {
|
||||
const size_t length = java_lang_String::utf8_length(java_string);
|
||||
temp = NEW_RESOURCE_ARRAY_IN_THREAD(t, const char, (length + 1));
|
||||
if (temp == NULL) {
|
||||
JfrJavaSupport::throw_out_of_memory_error("Unable to allocate thread local native memory", t);
|
||||
return NULL;
|
||||
}
|
||||
assert(temp != NULL, "invariant");
|
||||
java_lang_String::as_utf8_string(java_string, const_cast<char*>(temp), (int) length + 1);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Exceptions and errors
|
||||
*/
|
||||
static void create_and_throw(Symbol* name, const char* message, TRAPS) {
|
||||
assert(name != NULL, "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
assert(!HAS_PENDING_EXCEPTION, "invariant");
|
||||
THROW_MSG(name, message);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::throw_illegal_state_exception(const char* message, TRAPS) {
|
||||
create_and_throw(vmSymbols::java_lang_IllegalStateException(), message, THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::throw_internal_error(const char* message, TRAPS) {
|
||||
create_and_throw(vmSymbols::java_lang_InternalError(), message, THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::throw_illegal_argument_exception(const char* message, TRAPS) {
|
||||
create_and_throw(vmSymbols::java_lang_IllegalArgumentException(), message, THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::throw_out_of_memory_error(const char* message, TRAPS) {
|
||||
create_and_throw(vmSymbols::java_lang_OutOfMemoryError(), message, THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::throw_class_format_error(const char* message, TRAPS) {
|
||||
create_and_throw(vmSymbols::java_lang_ClassFormatError(), message, THREAD);
|
||||
}
|
||||
|
||||
void JfrJavaSupport::abort(jstring errorMsg, Thread* t) {
|
||||
DEBUG_ONLY(check_java_thread_in_vm(t));
|
||||
|
||||
ResourceMark rm(t);
|
||||
const char* const error_msg = c_str(errorMsg, t);
|
||||
if (error_msg != NULL) {
|
||||
log_error(jfr, system)("%s",error_msg);
|
||||
}
|
||||
log_error(jfr, system)("%s", "An irrecoverable error in Jfr. Shutting down VM...");
|
||||
vm_abort();
|
||||
}
|
||||
|
||||
JfrJavaSupport::CAUSE JfrJavaSupport::_cause = JfrJavaSupport::VM_ERROR;
|
||||
void JfrJavaSupport::set_cause(jthrowable throwable, Thread* t) {
|
||||
DEBUG_ONLY(check_java_thread_in_vm(t));
|
||||
|
||||
HandleMark hm(t);
|
||||
Handle ex(t, JNIHandles::resolve_external_guard(throwable));
|
||||
|
||||
if (ex.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ex->is_a(SystemDictionary::OutOfMemoryError_klass())) {
|
||||
_cause = OUT_OF_MEMORY;
|
||||
return;
|
||||
}
|
||||
if (ex->is_a(SystemDictionary::StackOverflowError_klass())) {
|
||||
_cause = STACK_OVERFLOW;
|
||||
return;
|
||||
}
|
||||
if (ex->is_a(SystemDictionary::Error_klass())) {
|
||||
_cause = VM_ERROR;
|
||||
return;
|
||||
}
|
||||
if (ex->is_a(SystemDictionary::RuntimeException_klass())) {
|
||||
_cause = RUNTIME_EXCEPTION;
|
||||
return;
|
||||
}
|
||||
if (ex->is_a(SystemDictionary::Exception_klass())) {
|
||||
_cause = UNKNOWN;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void JfrJavaSupport::uncaught_exception(jthrowable throwable, Thread* t) {
|
||||
DEBUG_ONLY(check_java_thread_in_vm(t));
|
||||
assert(throwable != NULL, "invariant");
|
||||
set_cause(throwable, t);
|
||||
}
|
||||
|
||||
JfrJavaSupport::CAUSE JfrJavaSupport::cause() {
|
||||
return _cause;
|
||||
}
|
||||
|
||||
const char* const JDK_JFR_MODULE_NAME = "jdk.jfr";
|
||||
const char* const JDK_JFR_PACKAGE_NAME = "jdk/jfr";
|
||||
|
||||
static bool is_jdk_jfr_module_in_readability_graph() {
|
||||
Thread* const t = Thread::current();
|
||||
// take one of the packages in the module to be located and query for its definition.
|
||||
TempNewSymbol pkg_sym = SymbolTable::new_symbol(JDK_JFR_PACKAGE_NAME, t);
|
||||
return Modules::is_package_defined(pkg_sym, Handle(), t);
|
||||
}
|
||||
|
||||
static void print_module_resolution_error(outputStream* stream) {
|
||||
assert(stream != NULL, "invariant");
|
||||
stream->print_cr("%s not found.", JDK_JFR_MODULE_NAME);
|
||||
stream->print_cr("Flight Recorder can not be enabled.");
|
||||
stream->print_cr("To use Flight Recorder, you might need to add" \
|
||||
" \"--add-modules %s\" to the VM command-line options.", JDK_JFR_MODULE_NAME);
|
||||
}
|
||||
|
||||
bool JfrJavaSupport::is_jdk_jfr_module_available() {
|
||||
return is_jdk_jfr_module_in_readability_graph();
|
||||
}
|
||||
|
||||
bool JfrJavaSupport::is_jdk_jfr_module_available(outputStream* stream, TRAPS) {
|
||||
if (!JfrJavaSupport::is_jdk_jfr_module_available()) {
|
||||
if (stream != NULL) {
|
||||
print_module_resolution_error(stream);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
jlong JfrJavaSupport::jfr_thread_id(jobject target_thread) {
|
||||
ThreadsListHandle tlh;
|
||||
JavaThread* native_thread = NULL;
|
||||
(void)tlh.cv_internal_thread_to_JavaThread(target_thread, &native_thread, NULL);
|
||||
return native_thread != NULL ? JFR_THREAD_ID(native_thread) : 0;
|
||||
}
|
114
src/hotspot/share/jfr/jni/jfrJavaSupport.hpp
Normal file
114
src/hotspot/share/jfr/jni/jfrJavaSupport.hpp
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_JFR_JNI_JFRJAVASUPPORT_HPP
|
||||
#define SHARE_VM_JFR_JNI_JFRJAVASUPPORT_HPP
|
||||
|
||||
#include "jfr/jni/jfrJavaCall.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
|
||||
class Klass;
|
||||
class JavaThread;
|
||||
class outputStream;
|
||||
|
||||
class JfrJavaSupport : public AllStatic {
|
||||
public:
|
||||
static jobject local_jni_handle(const oop obj, Thread* t);
|
||||
static jobject local_jni_handle(const jobject handle, Thread* t);
|
||||
static void destroy_local_jni_handle(const jobject handle);
|
||||
|
||||
static jobject global_jni_handle(const oop obj, Thread* t);
|
||||
static jobject global_jni_handle(const jobject handle, Thread* t);
|
||||
static void destroy_global_jni_handle(const jobject handle);
|
||||
|
||||
static oop resolve_non_null(jobject obj);
|
||||
static void notify_all(jobject obj, TRAPS);
|
||||
static void set_array_element(jobjectArray arr, jobject element, int index, Thread* t);
|
||||
|
||||
// naked oop result
|
||||
static void call_static(JfrJavaArguments* args, TRAPS);
|
||||
static void call_special(JfrJavaArguments* args, TRAPS);
|
||||
static void call_virtual(JfrJavaArguments* args, TRAPS);
|
||||
|
||||
static void set_field(JfrJavaArguments* args, TRAPS);
|
||||
static void get_field(JfrJavaArguments* args, TRAPS);
|
||||
static void new_object(JfrJavaArguments* args, TRAPS);
|
||||
|
||||
// global jni handle result
|
||||
static void new_object_global_ref(JfrJavaArguments* args, TRAPS);
|
||||
static void get_field_global_ref(JfrJavaArguments* args, TRAPS);
|
||||
|
||||
// local jni handle result
|
||||
static void new_object_local_ref(JfrJavaArguments* args, TRAPS);
|
||||
static void get_field_local_ref(JfrJavaArguments* args, TRAPS);
|
||||
|
||||
static jstring new_string(const char* c_str, TRAPS);
|
||||
static jobjectArray new_string_array(int length, TRAPS);
|
||||
|
||||
static jobject new_java_lang_Boolean(bool value, TRAPS);
|
||||
static jobject new_java_lang_Integer(jint value, TRAPS);
|
||||
static jobject new_java_lang_Long(jlong value, TRAPS);
|
||||
|
||||
// misc
|
||||
static Klass* klass(const jobject handle);
|
||||
// caller needs ResourceMark
|
||||
static const char* c_str(jstring string, Thread* jt);
|
||||
|
||||
// exceptions
|
||||
static void throw_illegal_state_exception(const char* message, TRAPS);
|
||||
static void throw_illegal_argument_exception(const char* message, TRAPS);
|
||||
static void throw_internal_error(const char* message, TRAPS);
|
||||
static void throw_out_of_memory_error(const char* message, TRAPS);
|
||||
static void throw_class_format_error(const char* message, TRAPS);
|
||||
|
||||
static bool is_jdk_jfr_module_available();
|
||||
static bool is_jdk_jfr_module_available(outputStream* stream, TRAPS);
|
||||
|
||||
static jlong jfr_thread_id(jobject target_thread);
|
||||
|
||||
// critical
|
||||
static void abort(jstring errorMsg, TRAPS);
|
||||
static void uncaught_exception(jthrowable throwable, Thread* t);
|
||||
|
||||
// asserts
|
||||
DEBUG_ONLY(static void check_java_thread_in_vm(Thread* t);)
|
||||
DEBUG_ONLY(static void check_java_thread_in_native(Thread* t);)
|
||||
|
||||
enum CAUSE {
|
||||
VM_ERROR,
|
||||
OUT_OF_MEMORY,
|
||||
STACK_OVERFLOW,
|
||||
RUNTIME_EXCEPTION,
|
||||
UNKNOWN,
|
||||
NOF_CAUSES
|
||||
};
|
||||
|
||||
static CAUSE cause();
|
||||
|
||||
private:
|
||||
static CAUSE _cause;
|
||||
static void set_cause(jthrowable throwable, Thread* t);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_JFR_JNI_JFRJAVASUPPORT_HPP
|
310
src/hotspot/share/jfr/jni/jfrJniMethod.cpp
Normal file
310
src/hotspot/share/jfr/jni/jfrJniMethod.cpp
Normal file
@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "jni.h"
|
||||
#include "jvm.h"
|
||||
#include "jfr/jfr.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#include "jfr/periodic/sampling/jfrThreadSampler.hpp"
|
||||
#include "jfr/recorder/jfrEventSetting.hpp"
|
||||
#include "jfr/recorder/jfrRecorder.hpp"
|
||||
#include "jfr/recorder/checkpoint/jfrMetadataEvent.hpp"
|
||||
#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
|
||||
#include "jfr/recorder/repository/jfrRepository.hpp"
|
||||
#include "jfr/recorder/repository/jfrChunkSizeNotifier.hpp"
|
||||
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
|
||||
#include "jfr/recorder/service/jfrOptionSet.hpp"
|
||||
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
|
||||
#include "jfr/recorder/stringpool/jfrStringPool.hpp"
|
||||
#include "jfr/jni/jfrGetAllEventClasses.hpp"
|
||||
#include "jfr/jni/jfrJavaSupport.hpp"
|
||||
#include "jfr/jni/jfrJniMethodRegistration.hpp"
|
||||
#include "jfr/instrumentation/jfrEventClassTransformer.hpp"
|
||||
#include "jfr/instrumentation/jfrJvmtiAgent.hpp"
|
||||
#include "jfr/leakprofiler/leakProfiler.hpp"
|
||||
#include "jfr/utilities/jfrJavaLog.hpp"
|
||||
#include "jfr/utilities/jfrTimeConverter.hpp"
|
||||
#include "jfr/utilities/jfrTime.hpp"
|
||||
#include "jfr/writers/jfrJavaEventWriter.hpp"
|
||||
#include "jfrfiles/jfrPeriodic.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/interfaceSupport.inline.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
#define NO_TRANSITION(result_type, header) extern "C" { result_type JNICALL header {
|
||||
#define NO_TRANSITION_END } }
|
||||
|
||||
/*
|
||||
* NO_TRANSITION entries
|
||||
*
|
||||
* Thread remains _thread_in_native
|
||||
*/
|
||||
|
||||
NO_TRANSITION(void, jfr_register_natives(JNIEnv* env, jclass jvmclass))
|
||||
JfrJniMethodRegistration register_native_methods(env);
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(jboolean, jfr_is_enabled())
|
||||
return Jfr::is_enabled() ? JNI_TRUE : JNI_FALSE;
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(jboolean, jfr_is_disabled())
|
||||
return Jfr::is_disabled() ? JNI_TRUE : JNI_FALSE;
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(jboolean, jfr_is_started())
|
||||
return JfrRecorder::is_created() ? JNI_TRUE : JNI_FALSE;
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(jstring, jfr_get_pid(JNIEnv* env, jobject jvm))
|
||||
char pid_buf[32] = { 0 };
|
||||
jio_snprintf(pid_buf, sizeof(pid_buf), "%d", os::current_process_id());
|
||||
jstring pid_string = env->NewStringUTF(pid_buf);
|
||||
return pid_string; // exception pending if NULL
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(jlong, jfr_elapsed_frequency(JNIEnv* env, jobject jvm))
|
||||
return JfrTime::frequency();
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(jlong, jfr_elapsed_counter(JNIEnv* env, jobject jvm))
|
||||
return JfrTicks::now();
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(void, jfr_retransform_classes(JNIEnv* env, jobject jvm, jobjectArray classes))
|
||||
JfrJvmtiAgent::retransform_classes(env, classes, JavaThread::thread_from_jni_environment(env));
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(void, jfr_set_enabled(JNIEnv* env, jobject jvm, jlong event_type_id, jboolean enabled))
|
||||
JfrEventSetting::set_enabled(event_type_id, JNI_TRUE == enabled);
|
||||
if (EventOldObjectSample::eventId == event_type_id) {
|
||||
ThreadInVMfromNative transition(JavaThread::thread_from_jni_environment(env));
|
||||
if (JNI_TRUE == enabled) {
|
||||
LeakProfiler::start(JfrOptionSet::old_object_queue_size());
|
||||
} else {
|
||||
LeakProfiler::stop();
|
||||
}
|
||||
}
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(void, jfr_set_file_notification(JNIEnv* env, jobject jvm, jlong threshold))
|
||||
JfrChunkSizeNotifier::set_chunk_size_threshold((size_t)threshold);
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(void, jfr_set_sample_threads(JNIEnv* env, jobject jvm, jboolean sampleThreads))
|
||||
JfrOptionSet::set_sample_threads(sampleThreads);
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(void, jfr_set_stack_depth(JNIEnv* env, jobject jvm, jint depth))
|
||||
JfrOptionSet::set_stackdepth((jlong)depth);
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(void, jfr_set_stacktrace_enabled(JNIEnv* env, jobject jvm, jlong event_type_id, jboolean enabled))
|
||||
JfrEventSetting::set_stacktrace(event_type_id, JNI_TRUE == enabled);
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(void, jfr_set_global_buffer_count(JNIEnv* env, jobject jvm, jlong count))
|
||||
JfrOptionSet::set_num_global_buffers(count);
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(void, jfr_set_global_buffer_size(JNIEnv* env, jobject jvm, jlong size))
|
||||
JfrOptionSet::set_global_buffer_size(size);
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(void, jfr_set_thread_buffer_size(JNIEnv* env, jobject jvm, jlong size))
|
||||
JfrOptionSet::set_thread_buffer_size(size);
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(void, jfr_set_memory_size(JNIEnv* env, jobject jvm, jlong size))
|
||||
JfrOptionSet::set_memory_size(size);
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(jboolean, jfr_set_threshold(JNIEnv* env, jobject jvm, jlong event_type_id, jlong thresholdTicks))
|
||||
return JfrEventSetting::set_threshold(event_type_id, thresholdTicks) ? JNI_TRUE : JNI_FALSE;
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(jboolean, jfr_allow_event_retransforms(JNIEnv* env, jobject jvm))
|
||||
return JfrOptionSet::allow_event_retransforms() ? JNI_TRUE : JNI_FALSE;
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(jboolean, jfr_is_available(JNIEnv* env, jclass jvm))
|
||||
return !Jfr::is_disabled() ? JNI_TRUE : JNI_FALSE;
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(jlong, jfr_get_epoch_address(JNIEnv* env, jobject jvm))
|
||||
return JfrTraceIdEpoch::epoch_address();
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(jlong, jfr_get_unloaded_event_classes_count(JNIEnv* env, jobject jvm))
|
||||
return JfrEventClasses::unloaded_event_classes_count();
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(jdouble, jfr_time_conv_factor(JNIEnv* env, jobject jvm))
|
||||
return (jdouble)JfrTimeConverter::nano_to_counter_multiplier();
|
||||
NO_TRANSITION_END
|
||||
|
||||
NO_TRANSITION(jboolean, jfr_set_cutoff(JNIEnv* env, jobject jvm, jlong event_type_id, jlong cutoff_ticks))
|
||||
return JfrEventSetting::set_cutoff(event_type_id, cutoff_ticks) ? JNI_TRUE : JNI_FALSE;
|
||||
NO_TRANSITION_END
|
||||
|
||||
|
||||
/*
|
||||
* JVM_ENTRY_NO_ENV entries
|
||||
*
|
||||
* Transitions:
|
||||
* Entry: _thread_in_native -> _thread_in_vm
|
||||
* Exit: _thread_in_vm -> _thread_in_native
|
||||
*
|
||||
* Current JavaThread available as "thread" variable
|
||||
*/
|
||||
|
||||
JVM_ENTRY_NO_ENV(jboolean, jfr_create_jfr(JNIEnv* env, jobject jvm, jboolean simulate_failure))
|
||||
if (JfrRecorder::is_created()) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
if (!JfrRecorder::create(simulate_failure == JNI_TRUE)) {
|
||||
JfrJavaSupport::throw_illegal_state_exception("Unable to start Jfr", thread);
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JNI_TRUE;
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(jboolean, jfr_destroy_jfr(JNIEnv* env, jobject jvm))
|
||||
JfrRecorder::destroy();
|
||||
return JNI_TRUE;
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(void, jfr_begin_recording(JNIEnv* env, jobject jvm))
|
||||
if (JfrRecorder::is_recording()) {
|
||||
return;
|
||||
}
|
||||
JfrRecorder::start_recording();
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(void, jfr_end_recording(JNIEnv* env, jobject jvm))
|
||||
if (!JfrRecorder::is_recording()) {
|
||||
return;
|
||||
}
|
||||
JfrRecorder::stop_recording();
|
||||
JVM_END
|
||||
|
||||
|
||||
JVM_ENTRY_NO_ENV(jboolean, jfr_emit_event(JNIEnv* env, jobject jvm, jlong eventTypeId, jlong timeStamp, jlong when))
|
||||
JfrPeriodicEventSet::requestEvent((JfrEventId)eventTypeId);
|
||||
return thread->has_pending_exception() ? JNI_FALSE : JNI_TRUE;
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(jobject, jfr_get_all_event_classes(JNIEnv* env, jobject jvm))
|
||||
return JfrEventClasses::get_all_event_classes(thread);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(jlong, jfr_class_id(JNIEnv* env, jclass jvm, jclass jc))
|
||||
return JfrTraceId::use(jc);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(jlong, jfr_stacktrace_id(JNIEnv* env, jobject jvm, jint skip))
|
||||
return JfrStackTraceRepository::record(thread, skip);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(void, jfr_log(JNIEnv* env, jobject jvm, jint tag_set, jint level, jstring message))
|
||||
JfrJavaLog::log(tag_set, level, message, thread);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(void, jfr_subscribe_log_level(JNIEnv* env, jobject jvm, jobject log_tag, jint id))
|
||||
JfrJavaLog::subscribe_log_level(log_tag, id, thread);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(void, jfr_set_output(JNIEnv* env, jobject jvm, jstring path))
|
||||
JfrRepository::set_chunk_path(path, thread);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(void, jfr_set_method_sampling_interval(JNIEnv* env, jobject jvm, jlong type, jlong intervalMillis))
|
||||
if (intervalMillis < 0) {
|
||||
intervalMillis = 0;
|
||||
}
|
||||
JfrEventId typed_event_id = (JfrEventId)type;
|
||||
assert(EventExecutionSample::eventId == typed_event_id || EventNativeMethodSample::eventId == typed_event_id, "invariant");
|
||||
if (intervalMillis > 0) {
|
||||
JfrEventSetting::set_enabled(typed_event_id, true); // ensure sampling event is enabled
|
||||
}
|
||||
if (EventExecutionSample::eventId == type) {
|
||||
JfrThreadSampling::set_java_sample_interval(intervalMillis);
|
||||
} else {
|
||||
JfrThreadSampling::set_native_sample_interval(intervalMillis);
|
||||
}
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(void, jfr_store_metadata_descriptor(JNIEnv* env, jobject jvm, jbyteArray descriptor))
|
||||
JfrMetadataEvent::update(descriptor);
|
||||
JVM_END
|
||||
|
||||
// trace thread id for a thread object
|
||||
JVM_ENTRY_NO_ENV(jlong, jfr_id_for_thread(JNIEnv* env, jobject jvm, jobject t))
|
||||
return JfrJavaSupport::jfr_thread_id(t);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(jobject, jfr_get_event_writer(JNIEnv* env, jclass cls))
|
||||
return JfrJavaEventWriter::event_writer(thread);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(jobject, jfr_new_event_writer(JNIEnv* env, jclass cls))
|
||||
return JfrJavaEventWriter::new_event_writer(thread);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(jboolean, jfr_event_writer_flush(JNIEnv* env, jclass cls, jobject writer, jint used_size, jint requested_size))
|
||||
return JfrJavaEventWriter::flush(writer, used_size, requested_size, thread);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(void, jfr_set_repository_location(JNIEnv* env, jobject repo, jstring location))
|
||||
return JfrRepository::set_path(location, thread);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(void, jfr_uncaught_exception(JNIEnv* env, jobject jvm, jobject t, jthrowable throwable))
|
||||
JfrJavaSupport::uncaught_exception(throwable, thread);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(void, jfr_abort(JNIEnv* env, jobject jvm, jstring errorMsg))
|
||||
JfrJavaSupport::abort(errorMsg, thread);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(jlong, jfr_type_id(JNIEnv* env, jobject jvm, jclass jc))
|
||||
return JfrTraceId::get(jc);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(jboolean, jfr_add_string_constant(JNIEnv* env, jclass jvm, jboolean epoch, jlong id, jstring string))
|
||||
return JfrStringPool::add(epoch == JNI_TRUE, id, string, thread);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(void, jfr_set_force_instrumentation(JNIEnv* env, jobject jvm, jboolean force_instrumentation))
|
||||
JfrEventClassTransformer::set_force_instrumentation(force_instrumentation == JNI_TRUE ? true : false);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY_NO_ENV(void, jfr_emit_old_object_samples(JNIEnv* env, jobject jvm, jlong cutoff_ticks, jboolean emit_all))
|
||||
LeakProfiler::emit_events(cutoff_ticks, emit_all == JNI_TRUE);
|
||||
JVM_END
|
136
src/hotspot/share/jfr/jni/jfrJniMethod.hpp
Normal file
136
src/hotspot/share/jfr/jni/jfrJniMethod.hpp
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_JFR_JNI_JFRJNIMETHOD_HPP
|
||||
#define SHARE_VM_JFR_JNI_JFRJNIMETHOD_HPP
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
/*
|
||||
* Native methods for jdk.jfr.internal.JVM
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
jboolean JNICALL jfr_is_enabled();
|
||||
|
||||
jboolean JNICALL jfr_is_disabled();
|
||||
|
||||
jboolean JNICALL jfr_is_started();
|
||||
|
||||
jlong JNICALL jfr_elapsed_counter(JNIEnv* env, jobject jvm);
|
||||
|
||||
jboolean JNICALL jfr_create_jfr(JNIEnv* env, jobject jvm, jboolean simulate_failure);
|
||||
|
||||
jboolean JNICALL jfr_destroy_jfr(JNIEnv* env, jobject jvm);
|
||||
|
||||
void JNICALL jfr_begin_recording(JNIEnv* env, jobject jvm);
|
||||
|
||||
void JNICALL jfr_end_recording(JNIEnv* env, jobject jvm);
|
||||
|
||||
jboolean JNICALL jfr_emit_event(JNIEnv* env, jobject jvm, jlong eventTypeId, jlong timeStamp, jlong when);
|
||||
|
||||
jobject JNICALL jfr_get_all_event_classes(JNIEnv* env, jobject jvm);
|
||||
|
||||
jlong JNICALL jfr_class_id(JNIEnv* env, jclass jvm, jclass jc);
|
||||
|
||||
jstring JNICALL jfr_get_pid(JNIEnv* env, jobject jvm);
|
||||
|
||||
jlong JNICALL jfr_stacktrace_id(JNIEnv* env, jobject jvm, jint skip);
|
||||
|
||||
jlong JNICALL jfr_elapsed_frequency(JNIEnv* env, jobject jvm);
|
||||
|
||||
void JNICALL jfr_subscribe_log_level(JNIEnv* env, jobject jvm, jobject log_tag, jint id);
|
||||
|
||||
void JNICALL jfr_log(JNIEnv* env, jobject jvm, jint tag_set, jint level, jstring message);
|
||||
|
||||
void JNICALL jfr_retransform_classes(JNIEnv* env, jobject jvm, jobjectArray classes);
|
||||
|
||||
void JNICALL jfr_set_enabled(JNIEnv* env, jobject jvm, jlong event_type_id, jboolean enabled);
|
||||
|
||||
void JNICALL jfr_set_file_notification(JNIEnv* env, jobject jvm, jlong delta);
|
||||
|
||||
void JNICALL jfr_set_global_buffer_count(JNIEnv* env, jobject jvm, jlong count);
|
||||
|
||||
void JNICALL jfr_set_global_buffer_size(JNIEnv* env, jobject jvm, jlong size);
|
||||
|
||||
void JNICALL jfr_set_method_sampling_interval(JNIEnv* env, jobject jvm, jlong type, jlong intervalMillis);
|
||||
|
||||
void JNICALL jfr_set_output(JNIEnv* env, jobject jvm, jstring path);
|
||||
|
||||
void JNICALL jfr_set_sample_threads(JNIEnv* env, jobject jvm, jboolean sampleThreads);
|
||||
|
||||
void JNICALL jfr_set_stack_depth(JNIEnv* env, jobject jvm, jint depth);
|
||||
|
||||
void JNICALL jfr_set_stacktrace_enabled(JNIEnv* env, jobject jvm, jlong event_type_id, jboolean enabled);
|
||||
|
||||
void JNICALL jfr_set_thread_buffer_size(JNIEnv* env, jobject jvm, jlong size);
|
||||
|
||||
void JNICALL jfr_set_memory_size(JNIEnv* env, jobject jvm, jlong size);
|
||||
|
||||
jboolean JNICALL jfr_set_threshold(JNIEnv* env, jobject jvm, jlong event_type_id, jlong thresholdTicks);
|
||||
|
||||
void JNICALL jfr_store_metadata_descriptor(JNIEnv* env, jobject jvm, jbyteArray descriptor);
|
||||
|
||||
jlong JNICALL jfr_id_for_thread(JNIEnv* env, jobject jvm, jobject t);
|
||||
|
||||
jboolean JNICALL jfr_allow_event_retransforms(JNIEnv* env, jobject jvm);
|
||||
|
||||
jboolean JNICALL jfr_is_available(JNIEnv* env, jclass jvm);
|
||||
|
||||
jdouble JNICALL jfr_time_conv_factor(JNIEnv* env, jobject jvm);
|
||||
|
||||
jlong JNICALL jfr_type_id(JNIEnv* env, jobject jvm, jclass jc);
|
||||
|
||||
void JNICALL jfr_set_repository_location(JNIEnv* env, jobject repo, jstring location);
|
||||
|
||||
jobject JNICALL jfr_get_event_writer(JNIEnv* env, jclass cls);
|
||||
|
||||
jobject JNICALL jfr_new_event_writer(JNIEnv* env, jclass cls);
|
||||
|
||||
jboolean JNICALL jfr_event_writer_flush(JNIEnv* env, jclass cls, jobject writer, jint used_size, jint requested_size);
|
||||
|
||||
void JNICALL jfr_abort(JNIEnv* env, jobject jvm, jstring errorMsg);
|
||||
|
||||
jlong JNICALL jfr_get_epoch_address(JNIEnv* env, jobject jvm);
|
||||
|
||||
jlong JNICALL jfr_add_string_constant(JNIEnv* env, jclass jvm, jlong gen, jlong id, jstring string);
|
||||
|
||||
void JNICALL jfr_uncaught_exception(JNIEnv* env, jobject jvm, jobject thread, jthrowable throwable);
|
||||
|
||||
void JNICALL jfr_set_force_instrumentation(JNIEnv* env, jobject jvm, jboolean force);
|
||||
|
||||
jlong JNICALL jfr_get_unloaded_event_classes_count(JNIEnv* env, jobject jvm);
|
||||
|
||||
jboolean JNICALL jfr_set_cutoff(JNIEnv* env, jobject jvm, jlong event_type_id, jlong cutoff_ticks);
|
||||
|
||||
void JNICALL jfr_emit_old_object_samples(JNIEnv* env, jobject jvm, jlong cutoff_ticks, jboolean);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SHARE_VM_JFR_JNI_JFRJNIMETHOD_HPP
|
94
src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp
Normal file
94
src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "jfr/jni/jfrJniMethod.hpp"
|
||||
#include "jfr/jni/jfrJniMethodRegistration.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/interfaceSupport.inline.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
|
||||
JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) {
|
||||
assert(env != NULL, "invariant");
|
||||
jclass jfr_clz = env->FindClass("jdk/jfr/internal/JVM");
|
||||
if (jfr_clz != NULL) {
|
||||
JNINativeMethod method[] = {
|
||||
(char*)"beginRecording", (char*)"()V", (void*)jfr_begin_recording,
|
||||
(char*)"endRecording", (char*)"()V", (void*)jfr_end_recording,
|
||||
(char*)"counterTime", (char*)"()J", (void*)jfr_elapsed_counter,
|
||||
(char*)"createJFR", (char*)"(Z)Z", (void*)jfr_create_jfr,
|
||||
(char*)"destroyJFR", (char*)"()Z", (void*)jfr_destroy_jfr,
|
||||
(char*)"emitEvent", (char*)"(JJJ)Z", (void*)jfr_emit_event,
|
||||
(char*)"getAllEventClasses", (char*)"()Ljava/util/List;", (void*)jfr_get_all_event_classes,
|
||||
(char*)"getClassIdNonIntrinsic", (char*)"(Ljava/lang/Class;)J", (void*)jfr_class_id,
|
||||
(char*)"getPid", (char*)"()Ljava/lang/String;", (void*)jfr_get_pid,
|
||||
(char*)"getStackTraceId", (char*)"(I)J", (void*)jfr_stacktrace_id,
|
||||
(char*)"getThreadId", (char*)"(Ljava/lang/Thread;)J", (void*)jfr_id_for_thread,
|
||||
(char*)"getTicksFrequency", (char*)"()J", (void*)jfr_elapsed_frequency,
|
||||
(char*)"subscribeLogLevel", (char*)"(Ljdk/jfr/internal/LogTag;I)V", (void*)jfr_subscribe_log_level,
|
||||
(char*)"log", (char*)"(IILjava/lang/String;)V", (void*)jfr_log,
|
||||
(char*)"retransformClasses", (char*)"([Ljava/lang/Class;)V", (void*)jfr_retransform_classes,
|
||||
(char*)"setEnabled", (char*)"(JZ)V", (void*)jfr_set_enabled,
|
||||
(char*)"setFileNotification", (char*)"(J)V", (void*)jfr_set_file_notification,
|
||||
(char*)"setGlobalBufferCount", (char*)"(J)V", (void*)jfr_set_global_buffer_count,
|
||||
(char*)"setGlobalBufferSize", (char*)"(J)V", (void*)jfr_set_global_buffer_size,
|
||||
(char*)"setMethodSamplingInterval", (char*)"(JJ)V", (void*)jfr_set_method_sampling_interval,
|
||||
(char*)"setOutput", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_output,
|
||||
(char*)"setSampleThreads", (char*)"(Z)V", (void*)jfr_set_sample_threads,
|
||||
(char*)"setStackDepth", (char*)"(I)V", (void*)jfr_set_stack_depth,
|
||||
(char*)"setStackTraceEnabled", (char*)"(JZ)V", (void*)jfr_set_stacktrace_enabled,
|
||||
(char*)"setThreadBufferSize", (char*)"(J)V", (void*)jfr_set_thread_buffer_size,
|
||||
(char*)"setMemorySize", (char*)"(J)V", (void*)jfr_set_memory_size,
|
||||
(char*)"setThreshold", (char*)"(JJ)Z", (void*)jfr_set_threshold,
|
||||
(char*)"storeMetadataDescriptor", (char*)"([B)V", (void*)jfr_store_metadata_descriptor,
|
||||
(char*)"getAllowedToDoEventRetransforms", (char*)"()Z", (void*)jfr_allow_event_retransforms,
|
||||
(char*)"isAvailable", (char*)"()Z", (void*)jfr_is_available,
|
||||
(char*)"getTimeConversionFactor", (char*)"()D", (void*)jfr_time_conv_factor,
|
||||
(char*)"getTypeId", (char*)"(Ljava/lang/Class;)J", (void*)jfr_type_id,
|
||||
(char*)"getEventWriter", (char*)"()Ljava/lang/Object;", (void*)jfr_get_event_writer,
|
||||
(char*)"newEventWriter", (char*)"()Ljdk/jfr/internal/EventWriter;", (void*)jfr_new_event_writer,
|
||||
(char*)"flush", (char*)"(Ljdk/jfr/internal/EventWriter;II)Z", (void*)jfr_event_writer_flush,
|
||||
(char*)"setRepositoryLocation", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_repository_location,
|
||||
(char*)"abort", (char*)"(Ljava/lang/String;)V", (void*)jfr_abort,
|
||||
(char*)"getEpochAddress", (char*)"()J",(void*)jfr_get_epoch_address,
|
||||
(char*)"addStringConstant", (char*)"(ZJLjava/lang/String;)Z", (void*)jfr_add_string_constant,
|
||||
(char*)"uncaughtException", (char*)"(Ljava/lang/Thread;Ljava/lang/Throwable;)V", (void*)jfr_uncaught_exception,
|
||||
(char*)"setForceInstrumentation", (char*)"(Z)V", (void*)jfr_set_force_instrumentation,
|
||||
(char*)"getUnloadedEventClassCount", (char*)"()J", (void*)jfr_get_unloaded_event_classes_count,
|
||||
(char*)"setCutoff", (char*)"(JJ)Z", (void*)jfr_set_cutoff,
|
||||
(char*)"emitOldObjectSamples", (char*)"(JZ)V", (void*)jfr_emit_old_object_samples
|
||||
};
|
||||
|
||||
const size_t method_array_length = sizeof(method) / sizeof(JNINativeMethod);
|
||||
if (env->RegisterNatives(jfr_clz, method, (jint)method_array_length) != JNI_OK) {
|
||||
JavaThread* jt = JavaThread::thread_from_jni_environment(env);
|
||||
assert(jt != NULL, "invariant");
|
||||
assert(jt->thread_state() == _thread_in_native, "invariant");
|
||||
ThreadInVMfromNative transition(jt);
|
||||
log_error(jfr, system)("RegisterNatives for JVM class failed!");
|
||||
}
|
||||
env->DeleteLocalRef(jfr_clz);
|
||||
}
|
||||
}
|
39
src/hotspot/share/jfr/jni/jfrJniMethodRegistration.hpp
Normal file
39
src/hotspot/share/jfr/jni/jfrJniMethodRegistration.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_JFR_JNI_JFRJNIMETHODREGISTRATION_HPP
|
||||
#define SHARE_VM_JFR_JNI_JFRJNIMETHODREGISTRATION_HPP
|
||||
|
||||
#include "jni.h"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
//
|
||||
// RegisterNatives for jdk.jfr.internal.JVM
|
||||
//
|
||||
class JfrJniMethodRegistration : public StackObj {
|
||||
public:
|
||||
JfrJniMethodRegistration(JNIEnv* env);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_JFR_JNI_JFRJNIMETHODREGISTRATION_HPP
|
180
src/hotspot/share/jfr/jni/jfrUpcalls.cpp
Normal file
180
src/hotspot/share/jfr/jni/jfrUpcalls.cpp
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "jfr/jni/jfrJavaSupport.hpp"
|
||||
#include "jfr/jni/jfrUpcalls.hpp"
|
||||
#include "jfr/support/jfrEventClass.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/typeArrayKlass.hpp"
|
||||
#include "oops/typeArrayOop.inline.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
|
||||
static Symbol* jvm_upcalls_class_sym = NULL;
|
||||
static Symbol* on_retransform_method_sym = NULL;
|
||||
static Symbol* on_retransform_signature_sym = NULL;
|
||||
static Symbol* bytes_for_eager_instrumentation_sym = NULL;
|
||||
static Symbol* bytes_for_eager_instrumentation_sig_sym = NULL;
|
||||
|
||||
static bool initialize(TRAPS) {
|
||||
static bool initialized = false;
|
||||
if (!initialized) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
jvm_upcalls_class_sym = SymbolTable::new_permanent_symbol("jdk/jfr/internal/JVMUpcalls", CHECK_false);
|
||||
on_retransform_method_sym = SymbolTable::new_permanent_symbol("onRetransform", CHECK_false);
|
||||
on_retransform_signature_sym = SymbolTable::new_permanent_symbol("(JZLjava/lang/Class;[B)[B", CHECK_false);
|
||||
bytes_for_eager_instrumentation_sym = SymbolTable::new_permanent_symbol("bytesForEagerInstrumentation", CHECK_false);
|
||||
bytes_for_eager_instrumentation_sig_sym = SymbolTable::new_permanent_symbol("(JZLjava/lang/Class;[B)[B", THREAD);
|
||||
initialized = bytes_for_eager_instrumentation_sig_sym != NULL;
|
||||
}
|
||||
return initialized;
|
||||
}
|
||||
|
||||
static const typeArrayOop invoke(jlong trace_id,
|
||||
jboolean force_instrumentation,
|
||||
jclass class_being_redefined,
|
||||
jint class_data_len,
|
||||
const unsigned char* class_data,
|
||||
Symbol* method_sym,
|
||||
Symbol* signature_sym,
|
||||
jint& new_bytes_length,
|
||||
TRAPS) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
const Klass* klass = SystemDictionary::resolve_or_fail(jvm_upcalls_class_sym, true, CHECK_NULL);
|
||||
assert(klass != NULL, "invariant");
|
||||
typeArrayOop old_byte_array = oopFactory::new_byteArray(class_data_len, CHECK_NULL);
|
||||
memcpy(old_byte_array->byte_at_addr(0), class_data, class_data_len);
|
||||
JavaValue result(T_OBJECT);
|
||||
JfrJavaArguments args(&result, klass, method_sym, signature_sym);
|
||||
args.push_long(trace_id);
|
||||
args.push_int(force_instrumentation);
|
||||
args.push_jobject(class_being_redefined);
|
||||
args.push_oop(old_byte_array);
|
||||
JfrJavaSupport::call_static(&args, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
log_error(jfr, system)("JfrUpcall failed");
|
||||
return NULL;
|
||||
}
|
||||
// The result should be a [B
|
||||
const oop res = (oop)result.get_jobject();
|
||||
assert(res != NULL, "invariant");
|
||||
assert(res->is_typeArray(), "invariant");
|
||||
assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "invariant");
|
||||
const typeArrayOop new_byte_array = typeArrayOop(res);
|
||||
new_bytes_length = (jint)new_byte_array->length();
|
||||
return new_byte_array;
|
||||
}
|
||||
|
||||
static const size_t ERROR_MSG_BUFFER_SIZE = 256;
|
||||
static void log_error_and_throw_oom(jint new_bytes_length, TRAPS) {
|
||||
char error_buffer[ERROR_MSG_BUFFER_SIZE];
|
||||
jio_snprintf(error_buffer, ERROR_MSG_BUFFER_SIZE,
|
||||
"Thread local allocation (native) for " SIZE_FORMAT " bytes failed in JfrUpcalls", (size_t)new_bytes_length);
|
||||
log_error(jfr, system)("%s", error_buffer);
|
||||
JfrJavaSupport::throw_out_of_memory_error(error_buffer, CHECK);
|
||||
}
|
||||
|
||||
void JfrUpcalls::on_retransform(jlong trace_id,
|
||||
jclass class_being_redefined,
|
||||
jint class_data_len,
|
||||
const unsigned char* class_data,
|
||||
jint* new_class_data_len,
|
||||
unsigned char** new_class_data,
|
||||
TRAPS) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
assert(class_being_redefined != NULL, "invariant");
|
||||
assert(class_data != NULL, "invariant");
|
||||
assert(new_class_data_len != NULL, "invariant");
|
||||
assert(new_class_data != NULL, "invariant");
|
||||
if (!JdkJfrEvent::is_visible(class_being_redefined)) {
|
||||
return;
|
||||
}
|
||||
jint new_bytes_length = 0;
|
||||
initialize(THREAD);
|
||||
const typeArrayOop new_byte_array = invoke(trace_id,
|
||||
false,
|
||||
class_being_redefined,
|
||||
class_data_len,
|
||||
class_data,
|
||||
on_retransform_method_sym,
|
||||
on_retransform_signature_sym,
|
||||
new_bytes_length,
|
||||
CHECK);
|
||||
assert(new_byte_array != NULL, "invariant");
|
||||
assert(new_bytes_length > 0, "invariant");
|
||||
// memory space must be malloced as mtInternal
|
||||
// as it will be deallocated by JVMTI routines
|
||||
unsigned char* const new_bytes = (unsigned char* const)os::malloc(new_bytes_length, mtInternal);
|
||||
if (new_bytes == NULL) {
|
||||
log_error_and_throw_oom(new_bytes_length, THREAD); // unwinds
|
||||
}
|
||||
assert(new_bytes != NULL, "invariant");
|
||||
memcpy(new_bytes, new_byte_array->byte_at_addr(0), (size_t)new_bytes_length);
|
||||
*new_class_data_len = new_bytes_length;
|
||||
*new_class_data = new_bytes;
|
||||
}
|
||||
|
||||
void JfrUpcalls::new_bytes_eager_instrumentation(jlong trace_id,
|
||||
jboolean force_instrumentation,
|
||||
jclass super,
|
||||
jint class_data_len,
|
||||
const unsigned char* class_data,
|
||||
jint* new_class_data_len,
|
||||
unsigned char** new_class_data,
|
||||
TRAPS) {
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
|
||||
assert(super != NULL, "invariant");
|
||||
assert(class_data != NULL, "invariant");
|
||||
assert(new_class_data_len != NULL, "invariant");
|
||||
assert(new_class_data != NULL, "invariant");
|
||||
jint new_bytes_length = 0;
|
||||
initialize(THREAD);
|
||||
const typeArrayOop new_byte_array = invoke(trace_id,
|
||||
force_instrumentation,
|
||||
super,
|
||||
class_data_len,
|
||||
class_data,
|
||||
bytes_for_eager_instrumentation_sym,
|
||||
bytes_for_eager_instrumentation_sig_sym,
|
||||
new_bytes_length,
|
||||
CHECK);
|
||||
assert(new_byte_array != NULL, "invariant");
|
||||
assert(new_bytes_length > 0, "invariant");
|
||||
unsigned char* const new_bytes = NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(THREAD, unsigned char, new_bytes_length);
|
||||
if (new_bytes == NULL) {
|
||||
log_error_and_throw_oom(new_bytes_length, THREAD); // this unwinds
|
||||
}
|
||||
assert(new_bytes != NULL, "invariant");
|
||||
memcpy(new_bytes, new_byte_array->byte_at_addr(0), (size_t)new_bytes_length);
|
||||
*new_class_data_len = new_bytes_length;
|
||||
*new_class_data = new_bytes;
|
||||
}
|
58
src/hotspot/share/jfr/jni/jfrUpcalls.hpp
Normal file
58
src/hotspot/share/jfr/jni/jfrUpcalls.hpp
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_JFR_JNI_JFRUPCALLS_HPP
|
||||
#define SHARE_VM_JFR_JNI_JFRUPCALLS_HPP
|
||||
|
||||
#include "jni.h"
|
||||
#include "jfr/utilities/jfrAllocation.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
|
||||
class JavaThread;
|
||||
|
||||
//
|
||||
// Upcalls to Java for instrumentation purposes.
|
||||
// Targets are located in jdk.jfr.internal.JVMUpcalls.
|
||||
//
|
||||
class JfrUpcalls : AllStatic {
|
||||
public:
|
||||
static void new_bytes_eager_instrumentation(jlong trace_id,
|
||||
jboolean force_instrumentation,
|
||||
jclass super,
|
||||
jint class_data_len,
|
||||
const unsigned char* class_data,
|
||||
jint* new_class_data_len,
|
||||
unsigned char** new_class_data,
|
||||
TRAPS);
|
||||
|
||||
static void on_retransform(jlong trace_id,
|
||||
jclass class_being_redefined,
|
||||
jint class_data_len,
|
||||
const unsigned char* class_data,
|
||||
jint* new_class_data_len,
|
||||
unsigned char** new_class_data,
|
||||
TRAPS);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_JFR_JNI_JFRUPCALLS_HPP
|
242
src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp
Normal file
242
src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.cpp
Normal file
@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "jfr/leakprofiler/chains/bitset.hpp"
|
||||
#include "jfr/leakprofiler/chains/bfsClosure.hpp"
|
||||
#include "jfr/leakprofiler/chains/dfsClosure.hpp"
|
||||
#include "jfr/leakprofiler/chains/edge.hpp"
|
||||
#include "jfr/leakprofiler/chains/edgeStore.hpp"
|
||||
#include "jfr/leakprofiler/chains/edgeQueue.hpp"
|
||||
#include "jfr/leakprofiler/utilities/granularTimer.hpp"
|
||||
#include "jfr/leakprofiler/utilities/unifiedOop.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/access.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
|
||||
BFSClosure::BFSClosure(EdgeQueue* edge_queue, EdgeStore* edge_store, BitSet* mark_bits) :
|
||||
_edge_queue(edge_queue),
|
||||
_edge_store(edge_store),
|
||||
_mark_bits(mark_bits),
|
||||
_current_parent(NULL),
|
||||
_current_frontier_level(0),
|
||||
_next_frontier_idx(0),
|
||||
_prev_frontier_idx(0),
|
||||
_dfs_fallback_idx(0),
|
||||
_use_dfs(false) {
|
||||
}
|
||||
|
||||
static void log_frontier_level_summary(size_t level,
|
||||
size_t high_idx,
|
||||
size_t low_idx,
|
||||
size_t edge_size) {
|
||||
const size_t nof_edges_in_frontier = high_idx - low_idx;
|
||||
log_trace(jfr, system)(
|
||||
"BFS front: " SIZE_FORMAT " edges: " SIZE_FORMAT " size: " SIZE_FORMAT " [KB]",
|
||||
level,
|
||||
nof_edges_in_frontier,
|
||||
(nof_edges_in_frontier * edge_size) / K
|
||||
);
|
||||
}
|
||||
|
||||
void BFSClosure::log_completed_frontier() const {
|
||||
log_frontier_level_summary(_current_frontier_level,
|
||||
_next_frontier_idx,
|
||||
_prev_frontier_idx,
|
||||
_edge_queue->sizeof_edge());
|
||||
}
|
||||
|
||||
void BFSClosure::log_dfs_fallback() const {
|
||||
const size_t edge_size = _edge_queue->sizeof_edge();
|
||||
// first complete summary for frontier in progress
|
||||
log_frontier_level_summary(_current_frontier_level,
|
||||
_next_frontier_idx,
|
||||
_prev_frontier_idx,
|
||||
edge_size);
|
||||
|
||||
// and then also complete the last frontier
|
||||
log_frontier_level_summary(_current_frontier_level + 1,
|
||||
_edge_queue->bottom(),
|
||||
_next_frontier_idx,
|
||||
edge_size);
|
||||
|
||||
// additional information about DFS fallover
|
||||
log_trace(jfr, system)(
|
||||
"BFS front: " SIZE_FORMAT " filled edge queue at edge: " SIZE_FORMAT,
|
||||
_current_frontier_level,
|
||||
_dfs_fallback_idx
|
||||
);
|
||||
|
||||
const size_t nof_dfs_completed_edges = _edge_queue->bottom() - _dfs_fallback_idx;
|
||||
log_trace(jfr, system)(
|
||||
"DFS to complete " SIZE_FORMAT " edges size: " SIZE_FORMAT " [KB]",
|
||||
nof_dfs_completed_edges,
|
||||
(nof_dfs_completed_edges * edge_size) / K
|
||||
);
|
||||
}
|
||||
|
||||
void BFSClosure::process() {
|
||||
|
||||
process_root_set();
|
||||
process_queue();
|
||||
}
|
||||
|
||||
void BFSClosure::process_root_set() {
|
||||
for (size_t idx = _edge_queue->bottom(); idx < _edge_queue->top(); ++idx) {
|
||||
const Edge* edge = _edge_queue->element_at(idx);
|
||||
assert(edge->parent() == NULL, "invariant");
|
||||
process(edge->reference(), edge->pointee());
|
||||
}
|
||||
}
|
||||
|
||||
void BFSClosure::process(const oop* reference, const oop pointee) {
|
||||
closure_impl(reference, pointee);
|
||||
}
|
||||
void BFSClosure::closure_impl(const oop* reference, const oop pointee) {
|
||||
assert(reference != NULL, "invariant");
|
||||
assert(UnifiedOop::dereference(reference) == pointee, "invariant");
|
||||
|
||||
if (GranularTimer::is_finished()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_use_dfs) {
|
||||
assert(_current_parent != NULL, "invariant");
|
||||
DFSClosure::find_leaks_from_edge(_edge_store, _mark_bits, _current_parent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_mark_bits->is_marked(pointee)) {
|
||||
_mark_bits->mark_obj(pointee);
|
||||
// is the pointee a sample object?
|
||||
if (NULL == pointee->mark()) {
|
||||
add_chain(reference, pointee);
|
||||
}
|
||||
|
||||
// if we are processinig initial root set, don't add to queue
|
||||
if (_current_parent != NULL) {
|
||||
assert(_current_parent->distance_to_root() == _current_frontier_level, "invariant");
|
||||
_edge_queue->add(_current_parent, reference);
|
||||
}
|
||||
|
||||
if (_edge_queue->is_full()) {
|
||||
dfs_fallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BFSClosure::add_chain(const oop* reference, const oop pointee) {
|
||||
assert(pointee != NULL, "invariant");
|
||||
assert(NULL == pointee->mark(), "invariant");
|
||||
|
||||
const size_t length = _current_parent == NULL ? 1 : _current_parent->distance_to_root() + 2;
|
||||
ResourceMark rm;
|
||||
Edge* const chain = NEW_RESOURCE_ARRAY(Edge, length);
|
||||
size_t idx = 0;
|
||||
chain[idx++] = Edge(NULL, reference);
|
||||
// aggregate from breadth-first search
|
||||
const Edge* current = _current_parent;
|
||||
while (current != NULL) {
|
||||
chain[idx++] = Edge(NULL, current->reference());
|
||||
current = current->parent();
|
||||
}
|
||||
assert(length == idx, "invariant");
|
||||
_edge_store->add_chain(chain, length);
|
||||
}
|
||||
|
||||
void BFSClosure::dfs_fallback() {
|
||||
assert(_edge_queue->is_full(), "invariant");
|
||||
_use_dfs = true;
|
||||
_dfs_fallback_idx = _edge_queue->bottom();
|
||||
while (!_edge_queue->is_empty()) {
|
||||
const Edge* edge = _edge_queue->remove();
|
||||
if (edge->pointee() != NULL) {
|
||||
DFSClosure::find_leaks_from_edge(_edge_store, _mark_bits, edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BFSClosure::process_queue() {
|
||||
assert(_current_frontier_level == 0, "invariant");
|
||||
assert(_next_frontier_idx == 0, "invariant");
|
||||
assert(_prev_frontier_idx == 0, "invariant");
|
||||
|
||||
_next_frontier_idx = _edge_queue->top();
|
||||
while (!is_complete()) {
|
||||
iterate(_edge_queue->remove()); // edge_queue.remove() increments bottom
|
||||
}
|
||||
}
|
||||
|
||||
void BFSClosure::step_frontier() const {
|
||||
log_completed_frontier();
|
||||
++_current_frontier_level;
|
||||
_prev_frontier_idx = _next_frontier_idx;
|
||||
_next_frontier_idx = _edge_queue->top();
|
||||
}
|
||||
|
||||
bool BFSClosure::is_complete() const {
|
||||
if (_edge_queue->bottom() < _next_frontier_idx) {
|
||||
return false;
|
||||
}
|
||||
if (_edge_queue->bottom() > _next_frontier_idx) {
|
||||
// fallback onto DFS as part of processing the frontier
|
||||
assert(_dfs_fallback_idx >= _prev_frontier_idx, "invariant");
|
||||
assert(_dfs_fallback_idx < _next_frontier_idx, "invariant");
|
||||
log_dfs_fallback();
|
||||
return true;
|
||||
}
|
||||
assert(_edge_queue->bottom() == _next_frontier_idx, "invariant");
|
||||
if (_edge_queue->is_empty()) {
|
||||
return true;
|
||||
}
|
||||
step_frontier();
|
||||
return false;
|
||||
}
|
||||
|
||||
void BFSClosure::iterate(const Edge* parent) {
|
||||
assert(parent != NULL, "invariant");
|
||||
const oop pointee = parent->pointee();
|
||||
assert(pointee != NULL, "invariant");
|
||||
_current_parent = parent;
|
||||
pointee->oop_iterate(this);
|
||||
}
|
||||
|
||||
void BFSClosure::do_oop(oop* ref) {
|
||||
assert(ref != NULL, "invariant");
|
||||
assert(is_aligned(ref, HeapWordSize), "invariant");
|
||||
const oop pointee = *ref;
|
||||
if (pointee != NULL) {
|
||||
closure_impl(ref, pointee);
|
||||
}
|
||||
}
|
||||
|
||||
void BFSClosure::do_oop(narrowOop* ref) {
|
||||
assert(ref != NULL, "invariant");
|
||||
assert(is_aligned(ref, sizeof(narrowOop)), "invariant");
|
||||
const oop pointee = RawAccess<>::oop_load(ref);
|
||||
if (pointee != NULL) {
|
||||
closure_impl(UnifiedOop::encode(ref), pointee);
|
||||
}
|
||||
}
|
73
src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.hpp
Normal file
73
src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.hpp
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018, 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_JFR_LEAKPROFILER_CHAINS_BFSCLOSURE_HPP
|
||||
#define SHARE_VM_JFR_LEAKPROFILER_CHAINS_BFSCLOSURE_HPP
|
||||
|
||||
#include "memory/iterator.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
|
||||
class BitSet;
|
||||
class Edge;
|
||||
class EdgeStore;
|
||||
class EdgeQueue;
|
||||
|
||||
// Class responsible for iterating the heap breadth-first
|
||||
class BFSClosure : public ExtendedOopClosure {
|
||||
private:
|
||||
EdgeQueue* _edge_queue;
|
||||
EdgeStore* _edge_store;
|
||||
BitSet* _mark_bits;
|
||||
const Edge* _current_parent;
|
||||
mutable size_t _current_frontier_level;
|
||||
mutable size_t _next_frontier_idx;
|
||||
mutable size_t _prev_frontier_idx;
|
||||
size_t _dfs_fallback_idx;
|
||||
bool _use_dfs;
|
||||
|
||||
void log_completed_frontier() const;
|
||||
void log_dfs_fallback() const;
|
||||
|
||||
bool is_complete() const;
|
||||
void step_frontier() const;
|
||||
|
||||
void closure_impl(const oop* reference, const oop pointee);
|
||||
void add_chain(const oop* reference, const oop pointee);
|
||||
void dfs_fallback();
|
||||
|
||||
void iterate(const Edge* parent);
|
||||
void process(const oop* reference, const oop pointee);
|
||||
|
||||
void process_root_set();
|
||||
void process_queue();
|
||||
|
||||
public:
|
||||
BFSClosure(EdgeQueue* edge_queue, EdgeStore* edge_store, BitSet* mark_bits);
|
||||
void process();
|
||||
|
||||
virtual void do_oop(oop* ref);
|
||||
virtual void do_oop(narrowOop* ref);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_JFR_LEAKPROFILER_CHAINS_BFSCLOSURE_HPP
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user