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
|
# Exclude BreakIterator classes that are just used in compile process to generate
|
||||||
# data files and shouldn't go in the product
|
# data files and shouldn't go in the product
|
||||||
jdk.localedata_EXCLUDE_FILES += sun/text/resources/ext/BreakIteratorRules_th.java
|
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
|
# If this is an imported module that has prebuilt classes, only compile
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
# All valid JVM features, regardless of platform
|
# All valid JVM features, regardless of platform
|
||||||
VALID_JVM_FEATURES="compiler1 compiler2 zero minimal dtrace jvmti jvmci \
|
VALID_JVM_FEATURES="compiler1 compiler2 zero minimal dtrace jvmti jvmci \
|
||||||
graal vm-structs jni-check services management cmsgc g1gc parallelgc serialgc nmt cds \
|
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
|
# All valid JVM variants
|
||||||
VALID_JVM_VARIANTS="server client minimal core zero custom"
|
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'])
|
AC_MSG_ERROR([Specified JVM feature 'cmsgc' requires feature 'serialgc'])
|
||||||
fi
|
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
|
# Turn on additional features based on other parts of configure
|
||||||
if test "x$INCLUDE_DTRACE" = "xtrue"; then
|
if test "x$INCLUDE_DTRACE" = "xtrue"; then
|
||||||
JVM_FEATURES="$JVM_FEATURES dtrace"
|
JVM_FEATURES="$JVM_FEATURES dtrace"
|
||||||
@ -396,7 +401,7 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES],
|
|||||||
NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES cds"
|
NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES cds"
|
||||||
fi
|
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_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_client="compiler1 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci"
|
||||||
JVM_FEATURES_core="$NON_MINIMAL_FEATURES $JVM_FEATURES"
|
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
|
if test "x$OPENJDK_TARGET_OS" = xsolaris; then
|
||||||
BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lsocket -lsched -ldoor -ldemangle -lnsl \
|
BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lsocket -lsched -ldoor -ldemangle -lnsl \
|
||||||
-lrt"
|
-lrt -lkstat"
|
||||||
BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBCXX_JVM"
|
BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBCXX_JVM"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -59,7 +59,9 @@ BOOT_MODULES += \
|
|||||||
java.security.sasl \
|
java.security.sasl \
|
||||||
java.xml \
|
java.xml \
|
||||||
jdk.internal.vm.ci \
|
jdk.internal.vm.ci \
|
||||||
|
jdk.jfr \
|
||||||
jdk.management \
|
jdk.management \
|
||||||
|
jdk.management.jfr \
|
||||||
jdk.management.agent \
|
jdk.management.agent \
|
||||||
jdk.net \
|
jdk.net \
|
||||||
jdk.sctp \
|
jdk.sctp \
|
||||||
@ -152,6 +154,7 @@ DOCS_MODULES += \
|
|||||||
jdk.jdeps \
|
jdk.jdeps \
|
||||||
jdk.jdi \
|
jdk.jdi \
|
||||||
jdk.jdwp.agent \
|
jdk.jdwp.agent \
|
||||||
|
jdk.jfr \
|
||||||
jdk.jlink \
|
jdk.jlink \
|
||||||
jdk.jsobject \
|
jdk.jsobject \
|
||||||
jdk.jshell \
|
jdk.jshell \
|
||||||
@ -159,6 +162,7 @@ DOCS_MODULES += \
|
|||||||
jdk.localedata \
|
jdk.localedata \
|
||||||
jdk.management \
|
jdk.management \
|
||||||
jdk.management.agent \
|
jdk.management.agent \
|
||||||
|
jdk.management.jfr \
|
||||||
jdk.naming.dns \
|
jdk.naming.dns \
|
||||||
jdk.naming.rmi \
|
jdk.naming.rmi \
|
||||||
jdk.net \
|
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/GensrcAdlc.gmk
|
||||||
include gensrc/GensrcDtrace.gmk
|
include gensrc/GensrcDtrace.gmk
|
||||||
include gensrc/GensrcJvmti.gmk
|
include gensrc/GensrcJvmti.gmk
|
||||||
|
include gensrc/GensrcJfr.gmk
|
||||||
|
|
||||||
$(eval $(call IncludeCustomExtension, hotspot/gensrc/GenerateSources.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.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# 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
|
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,
|
# 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
|
# 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)
|
TARGETS += $(COPY_JVMTI_H)
|
||||||
endif
|
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
|
# If serial is disabled, we cannot use serial as OldGC in parallel
|
||||||
JVM_EXCLUDE_FILES += psMarkSweep.cpp psMarkSweepDecorator.cpp
|
JVM_EXCLUDE_FILES += psMarkSweep.cpp psMarkSweepDecorator.cpp
|
||||||
endif
|
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)
|
ifeq ($(call check-jvm-feature, link-time-opt), true)
|
||||||
|
@ -223,7 +223,7 @@ class BuildConfig {
|
|||||||
sysDefines.add("_WINDOWS");
|
sysDefines.add("_WINDOWS");
|
||||||
sysDefines.add("HOTSPOT_BUILD_USER=\\\""+System.getProperty("user.name")+"\\\"");
|
sysDefines.add("HOTSPOT_BUILD_USER=\\\""+System.getProperty("user.name")+"\\\"");
|
||||||
sysDefines.add("HOTSPOT_BUILD_TARGET=\\\""+get("Build")+"\\\"");
|
sysDefines.add("HOTSPOT_BUILD_TARGET=\\\""+get("Build")+"\\\"");
|
||||||
sysDefines.add("INCLUDE_TRACE=1");
|
sysDefines.add("INCLUDE_JFR=1");
|
||||||
sysDefines.add("_JNI_IMPLEMENTATION_");
|
sysDefines.add("_JNI_IMPLEMENTATION_");
|
||||||
if (vars.get("PlatformName").equals("Win32")) {
|
if (vars.get("PlatformName").equals("Win32")) {
|
||||||
sysDefines.add("HOTSPOT_LIB_ARCH=\\\"i386\\\"");
|
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.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# 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_instrument}, \
|
||||||
${my.test.target.set:TESTNAME=jdk_jmx}, \
|
${my.test.target.set:TESTNAME=jdk_jmx}, \
|
||||||
${my.test.target.set:TESTNAME=jdk_jdi}, \
|
${my.test.target.set:TESTNAME=jdk_jdi}, \
|
||||||
|
${my.test.target.set:TESTNAME=jdk_jfr}, \
|
||||||
${my.test.target.set:TESTNAME=svc_tools}, \
|
${my.test.target.set:TESTNAME=svc_tools}, \
|
||||||
${my.make.rule.test.targets.svc.extra}
|
${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.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# 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.nashornapi.javadoc.dir=${dist.javadoc.dir}/nashornapi
|
||||||
dist.dynalinkapi.javadoc.dir=${dist.javadoc.dir}/dynalinkapi
|
dist.dynalinkapi.javadoc.dir=${dist.javadoc.dir}/dynalinkapi
|
||||||
|
|
||||||
# configuration for java flight recorder
|
# configuration for flight recorder
|
||||||
run.test.jvmargs.jfr=-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=${build.dir},stackdepth=128
|
run.test.jvmargs.jfr=XX:StartFlightRecording=disk=true,dumponexit=true,dumponexitpath=${build.dir},stackdepth=128
|
||||||
|
|
||||||
# test library location
|
# test library location
|
||||||
test.lib=test/nashorn/lib
|
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,
|
# 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.
|
# 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=
|
jfr.args=
|
||||||
|
|
||||||
|
@ -2891,7 +2891,6 @@
|
|||||||
<in>stringUtils.hpp</in>
|
<in>stringUtils.hpp</in>
|
||||||
<in>ticks.cpp</in>
|
<in>ticks.cpp</in>
|
||||||
<in>ticks.hpp</in>
|
<in>ticks.hpp</in>
|
||||||
<in>ticks.inline.hpp</in>
|
|
||||||
<in>utf8.cpp</in>
|
<in>utf8.cpp</in>
|
||||||
<in>utf8.hpp</in>
|
<in>utf8.hpp</in>
|
||||||
<in>vmError.cpp</in>
|
<in>vmError.cpp</in>
|
||||||
@ -6887,7 +6886,7 @@
|
|||||||
<pElem>../../hotspot/src/share/vm/ci</pElem>
|
<pElem>../../hotspot/src/share/vm/ci</pElem>
|
||||||
<pElem>../../hotspot/src/share/vm/oops</pElem>
|
<pElem>../../hotspot/src/share/vm/oops</pElem>
|
||||||
<pElem>../../hotspot/src/share/vm/trace</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/parallel</pElem>
|
||||||
<pElem>../../hotspot/src/share/vm/gc/shared</pElem>
|
<pElem>../../hotspot/src/share/vm/gc/shared</pElem>
|
||||||
<pElem>../../hotspot/src/share/vm/classfile</pElem>
|
<pElem>../../hotspot/src/share/vm/classfile</pElem>
|
||||||
@ -15408,11 +15407,6 @@
|
|||||||
tool="3"
|
tool="3"
|
||||||
flavor2="0">
|
flavor2="0">
|
||||||
</item>
|
</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"
|
<item path="../../src/hotspot/share/utilities/utf8.cpp"
|
||||||
ex="false"
|
ex="false"
|
||||||
tool="1"
|
tool="1"
|
||||||
@ -29190,11 +29184,6 @@
|
|||||||
tool="3"
|
tool="3"
|
||||||
flavor2="0">
|
flavor2="0">
|
||||||
</item>
|
</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"
|
<item path="../../src/hotspot/share/utilities/utf8.cpp"
|
||||||
ex="false"
|
ex="false"
|
||||||
tool="1"
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include "runtime/os.hpp"
|
#include "runtime/os.hpp"
|
||||||
|
|
||||||
|
extern "C" jlong _raw_rdtsc(); // In .il file
|
||||||
|
|
||||||
inline jlong os::rdtsc() { return _raw_rdtsc(); }
|
inline jlong os::rdtsc() { return _raw_rdtsc(); }
|
||||||
|
|
||||||
#endif // OS_CPU_SOLARIS_X86_VM_OS_SOLARIS_X86_INLINE_HPP
|
#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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -33,6 +33,7 @@
|
|||||||
#include "c1/c1_ValueType.hpp"
|
#include "c1/c1_ValueType.hpp"
|
||||||
#include "compiler/compileBroker.hpp"
|
#include "compiler/compileBroker.hpp"
|
||||||
#include "interpreter/linkResolver.hpp"
|
#include "interpreter/linkResolver.hpp"
|
||||||
|
#include "jfr/support/jfrIntrinsics.hpp"
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
@ -41,6 +42,7 @@
|
|||||||
#include "runtime/interfaceSupport.inline.hpp"
|
#include "runtime/interfaceSupport.inline.hpp"
|
||||||
#include "runtime/sharedRuntime.hpp"
|
#include "runtime/sharedRuntime.hpp"
|
||||||
#include "utilities/bitMap.inline.hpp"
|
#include "utilities/bitMap.inline.hpp"
|
||||||
|
#include "utilities/macros.hpp"
|
||||||
|
|
||||||
|
|
||||||
Compiler::Compiler() : AbstractCompiler(compiler_c1) {
|
Compiler::Compiler() : AbstractCompiler(compiler_c1) {
|
||||||
@ -222,10 +224,10 @@ bool Compiler::is_intrinsic_supported(const methodHandle& method) {
|
|||||||
case vmIntrinsics::_compareAndSetObject:
|
case vmIntrinsics::_compareAndSetObject:
|
||||||
case vmIntrinsics::_getCharStringU:
|
case vmIntrinsics::_getCharStringU:
|
||||||
case vmIntrinsics::_putCharStringU:
|
case vmIntrinsics::_putCharStringU:
|
||||||
#ifdef TRACE_HAVE_INTRINSICS
|
#ifdef JFR_HAVE_INTRINSICS
|
||||||
case vmIntrinsics::_counterTime:
|
case vmIntrinsics::_counterTime:
|
||||||
case vmIntrinsics::_getBufferWriter:
|
case vmIntrinsics::_getEventWriter:
|
||||||
#if defined(_LP64) || !defined(TRACE_ID_CLASS_SHIFT)
|
#if defined(_LP64) || !defined(TRACE_ID_SHIFT)
|
||||||
case vmIntrinsics::_getClassId:
|
case vmIntrinsics::_getClassId:
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "ci/ciUtilities.inline.hpp"
|
#include "ci/ciUtilities.inline.hpp"
|
||||||
#include "compiler/compileBroker.hpp"
|
#include "compiler/compileBroker.hpp"
|
||||||
#include "interpreter/bytecode.hpp"
|
#include "interpreter/bytecode.hpp"
|
||||||
|
#include "jfr/jfrEvents.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "runtime/sharedRuntime.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) {
|
void GraphBuilder::print_inlining(ciMethod* callee, const char* msg, bool success) {
|
||||||
CompileLog* log = compilation()->log();
|
CompileLog* log = compilation()->log();
|
||||||
if (log != NULL) {
|
if (log != NULL) {
|
||||||
@ -4315,18 +4340,10 @@ void GraphBuilder::print_inlining(ciMethod* callee, const char* msg, bool succes
|
|||||||
log->inline_fail("reason unknown");
|
log->inline_fail("reason unknown");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if INCLUDE_TRACE
|
|
||||||
EventCompilerInlining event;
|
EventCompilerInlining event;
|
||||||
if (event.should_commit()) {
|
if (event.should_commit()) {
|
||||||
event.set_compileId(compilation()->env()->task()->compile_id());
|
post_inlining_event(&event, compilation()->env()->task()->compile_id(), msg, success, bci(), method(), callee);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
#endif // INCLUDE_TRACE
|
|
||||||
|
|
||||||
CompileTask::print_inlining_ul(callee, scope()->level(), bci(), msg);
|
CompileTask::print_inlining_ul(callee, scope()->level(), bci(), msg);
|
||||||
|
|
||||||
|
@ -42,9 +42,6 @@
|
|||||||
#include "runtime/vm_version.hpp"
|
#include "runtime/vm_version.hpp"
|
||||||
#include "utilities/bitMap.inline.hpp"
|
#include "utilities/bitMap.inline.hpp"
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#ifdef TRACE_HAVE_INTRINSICS
|
|
||||||
#include "trace/traceMacros.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
#define __ gen()->lir(__FILE__, __LINE__)->
|
#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()));
|
__ 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) {
|
void LIRGenerator::do_ClassIDIntrinsic(Intrinsic* x) {
|
||||||
CodeEmitInfo* info = state_for(x);
|
CodeEmitInfo* info = state_for(x);
|
||||||
CodeEmitInfo* info2 = new CodeEmitInfo(info); // Clone for the second null check
|
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);
|
LIR_Opr klass = new_register(T_METADATA);
|
||||||
__ move(new LIR_Address(arg.result(), java_lang_Class::klass_offset_in_bytes(), T_ADDRESS), klass, info);
|
__ move(new LIR_Address(arg.result(), java_lang_Class::klass_offset_in_bytes(), T_ADDRESS), klass, info);
|
||||||
LIR_Opr id = new_register(T_LONG);
|
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);
|
LIR_Address* trace_id_addr = new LIR_Address(klass, in_bytes(offset), T_LONG);
|
||||||
|
|
||||||
__ move(trace_id_addr, id);
|
__ move(trace_id_addr, id);
|
||||||
@ -2938,18 +2935,18 @@ void LIRGenerator::do_ClassIDIntrinsic(Intrinsic* x) {
|
|||||||
#ifdef TRACE_ID_META_BITS
|
#ifdef TRACE_ID_META_BITS
|
||||||
__ logical_and(id, LIR_OprFact::longConst(~TRACE_ID_META_BITS), id);
|
__ logical_and(id, LIR_OprFact::longConst(~TRACE_ID_META_BITS), id);
|
||||||
#endif
|
#endif
|
||||||
#ifdef TRACE_ID_CLASS_SHIFT
|
#ifdef TRACE_ID_SHIFT
|
||||||
__ unsigned_shift_right(id, TRACE_ID_CLASS_SHIFT, id);
|
__ unsigned_shift_right(id, TRACE_ID_SHIFT, id);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__ move(id, rlock_result(x));
|
__ move(id, rlock_result(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LIRGenerator::do_getBufferWriter(Intrinsic* x) {
|
void LIRGenerator::do_getEventWriter(Intrinsic* x) {
|
||||||
LabelObj* L_end = new LabelObj();
|
LabelObj* L_end = new LabelObj();
|
||||||
|
|
||||||
LIR_Address* jobj_addr = new LIR_Address(getThreadPointer(),
|
LIR_Address* jobj_addr = new LIR_Address(getThreadPointer(),
|
||||||
in_bytes(TRACE_THREAD_DATA_WRITER_OFFSET),
|
in_bytes(THREAD_LOCAL_WRITER_OFFSET_JFR),
|
||||||
T_OBJECT);
|
T_OBJECT);
|
||||||
LIR_Opr result = rlock_result(x);
|
LIR_Opr result = rlock_result(x);
|
||||||
__ move_wide(jobj_addr, result);
|
__ move_wide(jobj_addr, result);
|
||||||
@ -2987,15 +2984,15 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TRACE_HAVE_INTRINSICS
|
#ifdef JFR_HAVE_INTRINSICS
|
||||||
case vmIntrinsics::_getClassId:
|
case vmIntrinsics::_getClassId:
|
||||||
do_ClassIDIntrinsic(x);
|
do_ClassIDIntrinsic(x);
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_getBufferWriter:
|
case vmIntrinsics::_getEventWriter:
|
||||||
do_getBufferWriter(x);
|
do_getEventWriter(x);
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_counterTime:
|
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;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "c1/c1_LIR.hpp"
|
#include "c1/c1_LIR.hpp"
|
||||||
#include "ci/ciMethodData.hpp"
|
#include "ci/ciMethodData.hpp"
|
||||||
#include "gc/shared/barrierSet.hpp"
|
#include "gc/shared/barrierSet.hpp"
|
||||||
|
#include "jfr/support/jfrIntrinsics.hpp"
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#include "utilities/sizes.hpp"
|
#include "utilities/sizes.hpp"
|
||||||
|
|
||||||
@ -459,9 +460,9 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
|
|||||||
SwitchRangeArray* create_lookup_ranges(LookupSwitch* x);
|
SwitchRangeArray* create_lookup_ranges(LookupSwitch* x);
|
||||||
void do_SwitchRanges(SwitchRangeArray* x, LIR_Opr value, BlockBegin* default_sux);
|
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_ClassIDIntrinsic(Intrinsic* x);
|
||||||
void do_getBufferWriter(Intrinsic* x);
|
void do_getEventWriter(Intrinsic* x);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void do_RuntimeCall(address routine, Intrinsic* x);
|
void do_RuntimeCall(address routine, Intrinsic* x);
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include "gc/shared/collectedHeap.hpp"
|
#include "gc/shared/collectedHeap.hpp"
|
||||||
#include "interpreter/bytecode.hpp"
|
#include "interpreter/bytecode.hpp"
|
||||||
#include "interpreter/interpreter.hpp"
|
#include "interpreter/interpreter.hpp"
|
||||||
|
#include "jfr/support/jfrIntrinsics.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "memory/oopFactory.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, SharedRuntime::dtrace_method_exit);
|
||||||
FUNCTION_CASE(entry, is_instance_of);
|
FUNCTION_CASE(entry, is_instance_of);
|
||||||
FUNCTION_CASE(entry, trace_block_entry);
|
FUNCTION_CASE(entry, trace_block_entry);
|
||||||
#ifdef TRACE_HAVE_INTRINSICS
|
#ifdef JFR_HAVE_INTRINSICS
|
||||||
FUNCTION_CASE(entry, TRACE_TIME_METHOD);
|
FUNCTION_CASE(entry, JFR_TIME_FUNCTION);
|
||||||
#endif
|
#endif
|
||||||
FUNCTION_CASE(entry, StubRoutines::updateBytesCRC32());
|
FUNCTION_CASE(entry, StubRoutines::updateBytesCRC32());
|
||||||
FUNCTION_CASE(entry, StubRoutines::updateBytesCRC32C());
|
FUNCTION_CASE(entry, StubRoutines::updateBytesCRC32C());
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include "compiler/disassembler.hpp"
|
#include "compiler/disassembler.hpp"
|
||||||
#include "gc/shared/collectedHeap.inline.hpp"
|
#include "gc/shared/collectedHeap.inline.hpp"
|
||||||
#include "interpreter/linkResolver.hpp"
|
#include "interpreter/linkResolver.hpp"
|
||||||
|
#include "jfr/jfrEvents.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "memory/oopFactory.hpp"
|
#include "memory/oopFactory.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
@ -60,7 +61,6 @@
|
|||||||
#include "runtime/safepointVerifiers.hpp"
|
#include "runtime/safepointVerifiers.hpp"
|
||||||
#include "runtime/sharedRuntime.hpp"
|
#include "runtime/sharedRuntime.hpp"
|
||||||
#include "runtime/thread.inline.hpp"
|
#include "runtime/thread.inline.hpp"
|
||||||
#include "trace/tracing.hpp"
|
|
||||||
#include "utilities/dtrace.hpp"
|
#include "utilities/dtrace.hpp"
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#ifdef COMPILER1
|
#ifdef COMPILER1
|
||||||
@ -1144,7 +1144,6 @@ void ciEnv::record_failure(const char* reason) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ciEnv::report_failure(const char* reason) {
|
void ciEnv::report_failure(const char* reason) {
|
||||||
// Create and fire JFR event
|
|
||||||
EventCompilationFailure event;
|
EventCompilationFailure event;
|
||||||
if (event.should_commit()) {
|
if (event.should_commit()) {
|
||||||
event.set_compileId(compile_id());
|
event.set_compileId(compile_id());
|
||||||
|
@ -48,7 +48,6 @@
|
|||||||
#include "runtime/deoptimization.hpp"
|
#include "runtime/deoptimization.hpp"
|
||||||
#include "utilities/bitMap.inline.hpp"
|
#include "utilities/bitMap.inline.hpp"
|
||||||
#include "utilities/xmlstream.hpp"
|
#include "utilities/xmlstream.hpp"
|
||||||
#include "trace/tracing.hpp"
|
|
||||||
#ifdef COMPILER2
|
#ifdef COMPILER2
|
||||||
#include "ci/bcEscapeAnalyzer.hpp"
|
#include "ci/bcEscapeAnalyzer.hpp"
|
||||||
#include "ci/ciTypeFlow.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 "compiler/methodLiveness.hpp"
|
||||||
#include "prims/methodHandles.hpp"
|
#include "prims/methodHandles.hpp"
|
||||||
#include "utilities/bitMap.hpp"
|
#include "utilities/bitMap.hpp"
|
||||||
#include "trace/tracing.hpp"
|
|
||||||
|
|
||||||
class ciMethodBlocks;
|
class ciMethodBlocks;
|
||||||
class MethodLiveness;
|
class MethodLiveness;
|
||||||
@ -362,10 +361,6 @@ class ciMethod : public ciMetadata {
|
|||||||
void print_short_name(outputStream* st = tty);
|
void print_short_name(outputStream* st = tty);
|
||||||
|
|
||||||
static bool is_consistent_info(ciMethod* declared_method, ciMethod* resolved_method);
|
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
|
#endif // SHARE_VM_CI_CIMETHOD_HPP
|
||||||
|
@ -67,7 +67,6 @@
|
|||||||
#include "runtime/timer.hpp"
|
#include "runtime/timer.hpp"
|
||||||
#include "services/classLoadingService.hpp"
|
#include "services/classLoadingService.hpp"
|
||||||
#include "services/threadService.hpp"
|
#include "services/threadService.hpp"
|
||||||
#include "trace/traceMacros.hpp"
|
|
||||||
#include "utilities/align.hpp"
|
#include "utilities/align.hpp"
|
||||||
#include "utilities/bitMap.inline.hpp"
|
#include "utilities/bitMap.inline.hpp"
|
||||||
#include "utilities/copy.hpp"
|
#include "utilities/copy.hpp"
|
||||||
@ -80,6 +79,9 @@
|
|||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
#include "classfile/systemDictionaryShared.hpp"
|
#include "classfile/systemDictionaryShared.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
#if INCLUDE_JFR
|
||||||
|
#include "jfr/support/jfrTraceIdExtension.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
// We generally try to create the oops directly when parsing, rather than
|
// We generally try to create the oops directly when parsing, rather than
|
||||||
// allocating temporary data structures and copying the bytes twice. A
|
// 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.
|
// If we reach here, all is well.
|
||||||
// Now remove the InstanceKlass* from the _klass_to_deallocate field
|
// Now remove the InstanceKlass* from the _klass_to_deallocate field
|
||||||
|
@ -76,8 +76,10 @@
|
|||||||
#include "utilities/growableArray.hpp"
|
#include "utilities/growableArray.hpp"
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#include "utilities/ostream.hpp"
|
#include "utilities/ostream.hpp"
|
||||||
#if INCLUDE_TRACE
|
#include "utilities/ticks.hpp"
|
||||||
#include "trace/tracing.hpp"
|
#if INCLUDE_JFR
|
||||||
|
#include "jfr/jfr.hpp"
|
||||||
|
#include "jfr/jfrEvents.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
volatile size_t ClassLoaderDataGraph::_num_array_classes = 0;
|
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
|
NOT_PRODUCT(_dependency_count = 0); // number of class loader dependencies
|
||||||
|
|
||||||
TRACE_INIT_ID(this);
|
JFR_ONLY(INIT_ID(this);)
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() {
|
ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() {
|
||||||
@ -1276,6 +1278,28 @@ bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) {
|
|||||||
}
|
}
|
||||||
#endif // PRODUCT
|
#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
|
// Move class loader data from main list to the unloaded list for unloading
|
||||||
// and deallocation later.
|
// and deallocation later.
|
||||||
@ -1353,8 +1377,7 @@ bool ClassLoaderDataGraph::do_unloading(bool clean_previous_versions) {
|
|||||||
}
|
}
|
||||||
data = data->next();
|
data = data->next();
|
||||||
}
|
}
|
||||||
|
JFR_ONLY(post_class_unload_events();)
|
||||||
post_class_unload_events();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug(class, loader, data)("do_unloading: loaders processed %u, loaders removed %u", loaders_processed, loaders_removed);
|
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;
|
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()
|
ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic()
|
||||||
: _next_klass(NULL) {
|
: _next_klass(NULL) {
|
||||||
ClassLoaderData* cld = ClassLoaderDataGraph::_head;
|
ClassLoaderData* cld = ClassLoaderDataGraph::_head;
|
||||||
@ -1490,20 +1499,3 @@ void ClassLoaderDataGraph::print_on(outputStream * const out) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // PRODUCT
|
#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/oopHandle.hpp"
|
||||||
#include "oops/weakHandle.hpp"
|
#include "oops/weakHandle.hpp"
|
||||||
#include "runtime/mutex.hpp"
|
#include "runtime/mutex.hpp"
|
||||||
#include "trace/traceMacros.hpp"
|
|
||||||
#include "utilities/growableArray.hpp"
|
#include "utilities/growableArray.hpp"
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#if INCLUDE_TRACE
|
#if INCLUDE_JFR
|
||||||
#include "utilities/ticks.hpp"
|
#include "jfr/support/jfrTraceIdExtension.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// A class loader represents a linkset. Conceptually, a linkset identifies
|
// A class loader represents a linkset. Conceptually, a linkset identifies
|
||||||
// the complete transitive closure of resolved links that a dynamic linker can
|
// 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_to_graph(Handle class_loader, bool anonymous);
|
||||||
static ClassLoaderData* add(Handle class_loader, bool anonymous);
|
static ClassLoaderData* add(Handle class_loader, bool anonymous);
|
||||||
static void post_class_unload_events();
|
|
||||||
public:
|
public:
|
||||||
static ClassLoaderData* find_or_create(Handle class_loader);
|
static ClassLoaderData* find_or_create(Handle class_loader);
|
||||||
static void purge();
|
static void purge();
|
||||||
@ -167,12 +166,6 @@ class ClassLoaderDataGraph : public AllStatic {
|
|||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
static bool contains_loader_data(ClassLoaderData* loader_data);
|
static bool contains_loader_data(ClassLoaderData* loader_data);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if INCLUDE_TRACE
|
|
||||||
private:
|
|
||||||
static Ticks _class_unload_time;
|
|
||||||
static void class_unload_event(Klass* const k);
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ClassLoaderData class
|
// ClassLoaderData class
|
||||||
@ -268,7 +261,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
|||||||
// JFR support
|
// JFR support
|
||||||
Klass* _class_loader_klass;
|
Klass* _class_loader_klass;
|
||||||
Symbol* _class_loader_name;
|
Symbol* _class_loader_name;
|
||||||
TRACE_DEFINE_TRACE_ID_FIELD;
|
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
|
||||||
|
|
||||||
void set_next(ClassLoaderData* next) { _next = next; }
|
void set_next(ClassLoaderData* next) { _next = next; }
|
||||||
ClassLoaderData* next() const { return _next; }
|
ClassLoaderData* next() const { return _next; }
|
||||||
@ -410,7 +403,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
|||||||
|
|
||||||
Klass* class_loader_klass() const { return _class_loader_klass; }
|
Klass* class_loader_klass() const { return _class_loader_klass; }
|
||||||
Symbol* class_loader_name() const { return _class_loader_name; }
|
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.
|
// An iterator that distributes Klasses to parallel worker threads.
|
||||||
|
@ -35,7 +35,11 @@
|
|||||||
#include "prims/jvmtiEnvBase.hpp"
|
#include "prims/jvmtiEnvBase.hpp"
|
||||||
#include "prims/jvmtiRedefineClasses.hpp"
|
#include "prims/jvmtiRedefineClasses.hpp"
|
||||||
#include "runtime/handles.inline.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
|
// called during initial loading of a shared class
|
||||||
InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
|
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());
|
result->store_fingerprint(stream->compute_fingerprint());
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE_KLASS_CREATION(result, parser, THREAD);
|
JFR_ONLY(ON_KLASS_CREATION(result, parser, THREAD);)
|
||||||
|
|
||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
if (DumpSharedSpaces) {
|
if (DumpSharedSpaces) {
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
#include "oops/symbol.hpp"
|
#include "oops/symbol.hpp"
|
||||||
#include "runtime/handles.inline.hpp"
|
#include "runtime/handles.inline.hpp"
|
||||||
#include "runtime/safepoint.hpp"
|
#include "runtime/safepoint.hpp"
|
||||||
#include "trace/traceMacros.hpp"
|
|
||||||
#include "utilities/events.hpp"
|
#include "utilities/events.hpp"
|
||||||
#include "utilities/growableArray.hpp"
|
#include "utilities/growableArray.hpp"
|
||||||
#include "utilities/hashtable.inline.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_locked_or_safepoint(Module_lock);
|
||||||
assert(f != NULL, "invariant");
|
assert(f != NULL, "invariant");
|
||||||
|
|
||||||
@ -279,7 +278,7 @@ ModuleEntry* ModuleEntry::new_unnamed_module_entry(Handle module_handle, ClassLo
|
|||||||
entry->set_loader_data(cld);
|
entry->set_loader_data(cld);
|
||||||
entry->_is_open = true;
|
entry->_is_open = true;
|
||||||
|
|
||||||
TRACE_INIT_ID(entry);
|
JFR_ONLY(INIT_ID(entry);)
|
||||||
|
|
||||||
return 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;
|
return entry;
|
||||||
}
|
}
|
||||||
|
@ -32,10 +32,13 @@
|
|||||||
#include "oops/symbol.hpp"
|
#include "oops/symbol.hpp"
|
||||||
#include "runtime/jniHandles.hpp"
|
#include "runtime/jniHandles.hpp"
|
||||||
#include "runtime/mutexLocker.hpp"
|
#include "runtime/mutexLocker.hpp"
|
||||||
#include "trace/traceMacros.hpp"
|
|
||||||
#include "utilities/growableArray.hpp"
|
#include "utilities/growableArray.hpp"
|
||||||
#include "utilities/hashtable.hpp"
|
#include "utilities/hashtable.hpp"
|
||||||
|
#include "utilities/macros.hpp"
|
||||||
#include "utilities/ostream.hpp"
|
#include "utilities/ostream.hpp"
|
||||||
|
#if INCLUDE_JFR
|
||||||
|
#include "jfr/support/jfrTraceIdExtension.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define UNNAMED_MODULE "Unnamed Module"
|
#define UNNAMED_MODULE "Unnamed Module"
|
||||||
#define JAVAPKG "java"
|
#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 _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_open; // whether the packages in the module are all unqualifiedly exported
|
||||||
bool _is_patched; // whether the module is patched via --patch-module
|
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.
|
enum {MODULE_READS_SIZE = 101}; // Initial size of list of modules that the module can read.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -164,8 +167,6 @@ public:
|
|||||||
// iteration support for readability
|
// iteration support for readability
|
||||||
void module_reads_do(ModuleClosure* const f);
|
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.
|
// Purge dead weak references out of reads list when any given class loader is unloaded.
|
||||||
void purge_reads();
|
void purge_reads();
|
||||||
void delete_reads();
|
void delete_reads();
|
||||||
@ -178,12 +179,14 @@ public:
|
|||||||
|
|
||||||
void print(outputStream* st = tty);
|
void print(outputStream* st = tty);
|
||||||
void verify();
|
void verify();
|
||||||
|
|
||||||
|
JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Iterator interface
|
// Iterator interface
|
||||||
class ModuleClosure: public StackObj {
|
class ModuleClosure: public StackObj {
|
||||||
public:
|
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 "memory/resourceArea.hpp"
|
||||||
#include "oops/symbol.hpp"
|
#include "oops/symbol.hpp"
|
||||||
#include "runtime/handles.inline.hpp"
|
#include "runtime/handles.inline.hpp"
|
||||||
#include "trace/traceMacros.hpp"
|
|
||||||
#include "utilities/events.hpp"
|
#include "utilities/events.hpp"
|
||||||
#include "utilities/growableArray.hpp"
|
#include "utilities/growableArray.hpp"
|
||||||
#include "utilities/hashtable.inline.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");
|
assert(Module_lock->owned_by_self(), "should have the Module_lock");
|
||||||
PackageEntry* entry = (PackageEntry*)Hashtable<Symbol*, mtModule>::allocate_new_entry(hash, name);
|
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
|
// Initialize fields specific to a PackageEntry
|
||||||
entry->init();
|
entry->init();
|
||||||
@ -283,7 +282,7 @@ void PackageEntryTable::verify_javabase_packages(GrowableArray<Symbol*> *pkg_lis
|
|||||||
}
|
}
|
||||||
|
|
||||||
// iteration of qualified exports
|
// 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_locked_or_safepoint(Module_lock);
|
||||||
assert(f != NULL, "invariant");
|
assert(f != NULL, "invariant");
|
||||||
|
|
||||||
|
@ -29,7 +29,12 @@
|
|||||||
#include "oops/symbol.hpp"
|
#include "oops/symbol.hpp"
|
||||||
#include "utilities/growableArray.hpp"
|
#include "utilities/growableArray.hpp"
|
||||||
#include "utilities/hashtable.hpp"
|
#include "utilities/hashtable.hpp"
|
||||||
|
#include "utilities/macros.hpp"
|
||||||
#include "utilities/ostream.hpp"
|
#include "utilities/ostream.hpp"
|
||||||
|
#if INCLUDE_JFR
|
||||||
|
#include "jfr/support/jfrTraceIdExtension.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// A PackageEntry basically represents a Java package. It contains:
|
// A PackageEntry basically represents a Java package. It contains:
|
||||||
// - Symbol* containing the package's name.
|
// - Symbol* containing the package's name.
|
||||||
@ -104,7 +109,7 @@ private:
|
|||||||
// Contains list of modules this package is qualifiedly exported to. Access
|
// Contains list of modules this package is qualifiedly exported to. Access
|
||||||
// to this list is protected by the Module_lock.
|
// to this list is protected by the Module_lock.
|
||||||
GrowableArray<ModuleEntry*>* _qualified_exports;
|
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.
|
// Initial size of a package entry's list of qualified exports.
|
||||||
enum {QUAL_EXP_SIZE = 43};
|
enum {QUAL_EXP_SIZE = 43};
|
||||||
@ -197,9 +202,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// iteration of qualified exports
|
// 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.
|
// Purge dead weak references out of exported list when any given class loader is unloaded.
|
||||||
void purge_qualified_exports();
|
void purge_qualified_exports();
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include "gc/shared/oopStorage.inline.hpp"
|
#include "gc/shared/oopStorage.inline.hpp"
|
||||||
#include "interpreter/bytecodeStream.hpp"
|
#include "interpreter/bytecodeStream.hpp"
|
||||||
#include "interpreter/interpreter.hpp"
|
#include "interpreter/interpreter.hpp"
|
||||||
|
#include "jfr/jfrEvents.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "logging/logStream.hpp"
|
#include "logging/logStream.hpp"
|
||||||
#include "memory/filemap.hpp"
|
#include "memory/filemap.hpp"
|
||||||
@ -81,7 +82,6 @@
|
|||||||
#include "services/classLoadingService.hpp"
|
#include "services/classLoadingService.hpp"
|
||||||
#include "services/diagnosticCommand.hpp"
|
#include "services/diagnosticCommand.hpp"
|
||||||
#include "services/threadService.hpp"
|
#include "services/threadService.hpp"
|
||||||
#include "trace/tracing.hpp"
|
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
#include "classfile/systemDictionaryShared.hpp"
|
#include "classfile/systemDictionaryShared.hpp"
|
||||||
@ -623,32 +623,16 @@ InstanceKlass* SystemDictionary::handle_parallel_super_load(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void post_class_load_event(EventClassLoad* event,
|
static void post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) {
|
||||||
const InstanceKlass* k,
|
|
||||||
const ClassLoaderData* init_cld) {
|
|
||||||
#if INCLUDE_TRACE
|
|
||||||
assert(event != NULL, "invariant");
|
assert(event != NULL, "invariant");
|
||||||
assert(k != NULL, "invariant");
|
assert(k != NULL, "invariant");
|
||||||
if (event->should_commit()) {
|
assert(event->should_commit(), "invariant");
|
||||||
event->set_loadedClass(k);
|
event->set_loadedClass(k);
|
||||||
event->set_definingClassLoader(k->class_loader_data());
|
event->set_definingClassLoader(k->class_loader_data());
|
||||||
event->set_initiatingClassLoader(init_cld);
|
event->set_initiatingClassLoader(init_cld);
|
||||||
event->commit();
|
event->commit();
|
||||||
}
|
|
||||||
#endif // INCLUDE_TRACE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// Be careful when modifying this code: once you have run
|
||||||
// placeholders()->find_and_add(PlaceholderTable::LOAD_INSTANCE),
|
// 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) {
|
if (HAS_PENDING_EXCEPTION || k == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (class_load_start_event.should_commit()) {
|
||||||
post_class_load_event(&class_load_start_event, k, loader_data);
|
post_class_load_event(&class_load_start_event, k, loader_data);
|
||||||
|
}
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
{
|
{
|
||||||
ClassLoaderData* loader_data = k->class_loader_data();
|
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()");
|
assert(THREAD->is_Java_thread(), "thread->is_Java_thread()");
|
||||||
JvmtiExport::post_class_load((JavaThread *) THREAD, k);
|
JvmtiExport::post_class_load((JavaThread *) THREAD, k);
|
||||||
}
|
}
|
||||||
|
if (class_load_start_event.should_commit()) {
|
||||||
post_class_load_event(&class_load_start_event, k, loader_data);
|
post_class_load_event(&class_load_start_event, k, loader_data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
assert(host_klass != NULL || NULL == cp_patches,
|
assert(host_klass != NULL || NULL == cp_patches,
|
||||||
"cp_patches only found with host_klass");
|
"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) {
|
void SystemDictionary::define_instance_class(InstanceKlass* k, TRAPS) {
|
||||||
|
|
||||||
HandleMark hm(THREAD);
|
HandleMark hm(THREAD);
|
||||||
@ -1626,7 +1620,7 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, TRAPS) {
|
|||||||
JvmtiExport::post_class_load((JavaThread *) THREAD, k);
|
JvmtiExport::post_class_load((JavaThread *) THREAD, k);
|
||||||
|
|
||||||
}
|
}
|
||||||
class_define_event(k, loader_data);
|
post_class_define_event(k, loader_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Support parallel classloading
|
// Support parallel classloading
|
||||||
|
@ -350,7 +350,7 @@ vmIntrinsics::ID vmIntrinsics::for_raw_conversion(BasicType src, BasicType dest)
|
|||||||
bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) {
|
bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) {
|
||||||
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
|
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
|
||||||
switch(id) {
|
switch(id) {
|
||||||
#ifdef TRACE_HAVE_INTRINSICS
|
#ifdef JFR_HAVE_INTRINSICS
|
||||||
case vmIntrinsics::_counterTime:
|
case vmIntrinsics::_counterTime:
|
||||||
#endif
|
#endif
|
||||||
case vmIntrinsics::_currentTimeMillis:
|
case vmIntrinsics::_currentTimeMillis:
|
||||||
@ -388,7 +388,7 @@ bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) {
|
|||||||
bool vmIntrinsics::can_trap(vmIntrinsics::ID id) {
|
bool vmIntrinsics::can_trap(vmIntrinsics::ID id) {
|
||||||
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
|
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
|
||||||
switch(id) {
|
switch(id) {
|
||||||
#ifdef TRACE_HAVE_INTRINSICS
|
#ifdef JFR_HAVE_INTRINSICS
|
||||||
case vmIntrinsics::_counterTime:
|
case vmIntrinsics::_counterTime:
|
||||||
case vmIntrinsics::_getClassId:
|
case vmIntrinsics::_getClassId:
|
||||||
#endif
|
#endif
|
||||||
@ -424,7 +424,7 @@ bool vmIntrinsics::can_trap(vmIntrinsics::ID id) {
|
|||||||
bool vmIntrinsics::should_be_pinned(vmIntrinsics::ID id) {
|
bool vmIntrinsics::should_be_pinned(vmIntrinsics::ID id) {
|
||||||
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
|
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
|
||||||
switch(id) {
|
switch(id) {
|
||||||
#ifdef TRACE_HAVE_INTRINSICS
|
#ifdef JFR_HAVE_INTRINSICS
|
||||||
case vmIntrinsics::_counterTime:
|
case vmIntrinsics::_counterTime:
|
||||||
#endif
|
#endif
|
||||||
case vmIntrinsics::_currentTimeMillis:
|
case vmIntrinsics::_currentTimeMillis:
|
||||||
|
@ -26,10 +26,12 @@
|
|||||||
#define SHARE_VM_CLASSFILE_VMSYMBOLS_HPP
|
#define SHARE_VM_CLASSFILE_VMSYMBOLS_HPP
|
||||||
|
|
||||||
#include "classfile/moduleEntry.hpp"
|
#include "classfile/moduleEntry.hpp"
|
||||||
#include "oops/symbol.hpp"
|
#include "jfr/support/jfrIntrinsics.hpp"
|
||||||
#include "memory/iterator.hpp"
|
|
||||||
#include "trace/traceMacros.hpp"
|
|
||||||
#include "jvmci/vmSymbols_jvmci.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
|
// The class vmSymbols is a name space for fast lookup of
|
||||||
// symbols commonly used in the VM.
|
// symbols commonly used in the VM.
|
||||||
@ -640,8 +642,8 @@
|
|||||||
/* forEachRemaining support */ \
|
/* forEachRemaining support */ \
|
||||||
template(java_util_stream_StreamsRangeIntSpliterator, "java/util/stream/Streams$RangeIntSpliterator") \
|
template(java_util_stream_StreamsRangeIntSpliterator, "java/util/stream/Streams$RangeIntSpliterator") \
|
||||||
\
|
\
|
||||||
/* trace signatures */ \
|
/* jfr signatures */ \
|
||||||
TRACE_TEMPLATES(template) \
|
JFR_TEMPLATES(template) \
|
||||||
\
|
\
|
||||||
/* cds */ \
|
/* cds */ \
|
||||||
template(jdk_internal_loader_ClassLoaders, "jdk/internal/loader/ClassLoaders") \
|
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_intrinsic(_nanoTime, java_lang_System, nanoTime_name, void_long_signature, F_S) \
|
||||||
do_name( nanoTime_name, "nanoTime") \
|
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_intrinsic(_arraycopy, java_lang_System, arraycopy_name, arraycopy_signature, F_S) \
|
||||||
do_name( arraycopy_name, "arraycopy") \
|
do_name( arraycopy_name, "arraycopy") \
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "code/nmethod.hpp"
|
#include "code/nmethod.hpp"
|
||||||
#include "code/pcDesc.hpp"
|
#include "code/pcDesc.hpp"
|
||||||
#include "compiler/compileBroker.hpp"
|
#include "compiler/compileBroker.hpp"
|
||||||
|
#include "jfr/jfrEvents.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "logging/logStream.hpp"
|
#include "logging/logStream.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
@ -53,7 +54,6 @@
|
|||||||
#include "runtime/sweeper.hpp"
|
#include "runtime/sweeper.hpp"
|
||||||
#include "runtime/vmThread.hpp"
|
#include "runtime/vmThread.hpp"
|
||||||
#include "services/memoryService.hpp"
|
#include "services/memoryService.hpp"
|
||||||
#include "trace/tracing.hpp"
|
|
||||||
#include "utilities/align.hpp"
|
#include "utilities/align.hpp"
|
||||||
#include "utilities/vmError.hpp"
|
#include "utilities/vmError.hpp"
|
||||||
#include "utilities/xmlstream.hpp"
|
#include "utilities/xmlstream.hpp"
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "compiler/compilerOracle.hpp"
|
#include "compiler/compilerOracle.hpp"
|
||||||
#include "compiler/directivesParser.hpp"
|
#include "compiler/directivesParser.hpp"
|
||||||
#include "interpreter/linkResolver.hpp"
|
#include "interpreter/linkResolver.hpp"
|
||||||
|
#include "jfr/jfrEvents.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "logging/logStream.hpp"
|
#include "logging/logStream.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
@ -57,11 +58,11 @@
|
|||||||
#include "runtime/sweeper.hpp"
|
#include "runtime/sweeper.hpp"
|
||||||
#include "runtime/timerTrace.hpp"
|
#include "runtime/timerTrace.hpp"
|
||||||
#include "runtime/vframe.inline.hpp"
|
#include "runtime/vframe.inline.hpp"
|
||||||
#include "trace/tracing.hpp"
|
|
||||||
#include "utilities/debug.hpp"
|
#include "utilities/debug.hpp"
|
||||||
#include "utilities/dtrace.hpp"
|
#include "utilities/dtrace.hpp"
|
||||||
#include "utilities/events.hpp"
|
#include "utilities/events.hpp"
|
||||||
#include "utilities/formatBuffer.hpp"
|
#include "utilities/formatBuffer.hpp"
|
||||||
|
#include "utilities/macros.hpp"
|
||||||
#ifdef COMPILER1
|
#ifdef COMPILER1
|
||||||
#include "c1/c1_Compiler.hpp"
|
#include "c1/c1_Compiler.hpp"
|
||||||
#endif
|
#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) {
|
if (success) {
|
||||||
task->mark_success();
|
task->mark_success();
|
||||||
if (ci_env != NULL) {
|
if (ci_env != NULL) {
|
||||||
@ -1959,19 +1959,21 @@ void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, Even
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulate crash during compilation
|
// simulate crash during compilation
|
||||||
assert(task->compile_id() != CICrashAt, "just as planned");
|
assert(task->compile_id() != CICrashAt, "just as planned");
|
||||||
if (event.should_commit()) {
|
}
|
||||||
event.set_method(task->method());
|
|
||||||
event.set_compileId(task->compile_id());
|
static void post_compilation_event(EventCompilation* event, CompileTask* task) {
|
||||||
event.set_compileLevel(task->comp_level());
|
assert(event != NULL, "invariant");
|
||||||
event.set_succeded(task->is_success());
|
assert(event->should_commit(), "invariant");
|
||||||
event.set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci);
|
event->set_method(task->method());
|
||||||
event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
|
event->set_compileId(task->compile_id());
|
||||||
event.set_inlinedBytes(task->num_inlined_bytecodes());
|
event->set_compileLevel(task->comp_level());
|
||||||
event.commit();
|
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;
|
int DirectivesStack::_depth = 0;
|
||||||
@ -2066,7 +2068,10 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
|||||||
compilable = ciEnv::MethodCompilable_not_at_tier;
|
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
|
} else
|
||||||
#endif // INCLUDE_JVMCI
|
#endif // INCLUDE_JVMCI
|
||||||
@ -2123,7 +2128,10 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
|||||||
ci_env.report_failure(failure_reason);
|
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
|
// Remove the JNI handle block after the ciEnv destructor has run in
|
||||||
// the previous block.
|
// the previous block.
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
#include "compiler/compileTask.hpp"
|
#include "compiler/compileTask.hpp"
|
||||||
#include "compiler/compilerDirectives.hpp"
|
#include "compiler/compilerDirectives.hpp"
|
||||||
#include "runtime/perfData.hpp"
|
#include "runtime/perfData.hpp"
|
||||||
#include "trace/tracing.hpp"
|
|
||||||
#include "utilities/stack.hpp"
|
#include "utilities/stack.hpp"
|
||||||
#if INCLUDE_JVMCI
|
#if INCLUDE_JVMCI
|
||||||
#include "jvmci/jvmciCompiler.hpp"
|
#include "jvmci/jvmciCompiler.hpp"
|
||||||
@ -252,7 +251,7 @@ class CompileBroker: AllStatic {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void invoke_compiler_on_method(CompileTask* task);
|
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 set_last_compile(CompilerThread *thread, const methodHandle& method, bool is_osr, int comp_level);
|
||||||
static void push_jni_handle_block();
|
static void push_jni_handle_block();
|
||||||
static void pop_jni_handle_block();
|
static void pop_jni_handle_block();
|
||||||
|
@ -86,7 +86,6 @@ class STWGCTimer;
|
|||||||
class G1NewTracer;
|
class G1NewTracer;
|
||||||
class EvacuationFailedInfo;
|
class EvacuationFailedInfo;
|
||||||
class nmethod;
|
class nmethod;
|
||||||
class Ticks;
|
|
||||||
class WorkGang;
|
class WorkGang;
|
||||||
class G1Allocator;
|
class G1Allocator;
|
||||||
class G1ArchiveAllocator;
|
class G1ArchiveAllocator;
|
||||||
|
@ -23,12 +23,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
|
||||||
#include "gc/g1/g1_globals.hpp"
|
#include "gc/g1/g1_globals.hpp"
|
||||||
#include "gc/g1/g1EvacStats.hpp"
|
#include "gc/g1/g1EvacStats.hpp"
|
||||||
#include "gc/shared/gcId.hpp"
|
#include "gc/shared/gcId.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "trace/tracing.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
|
|
||||||
void G1EvacStats::log_plab_allocation() {
|
void G1EvacStats::log_plab_allocation() {
|
||||||
PLABStats::log_plab_allocation();
|
PLABStats::log_plab_allocation();
|
||||||
|
@ -34,7 +34,6 @@
|
|||||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||||
#include "gc/shared/referenceProcessor.hpp"
|
#include "gc/shared/referenceProcessor.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "utilities/ticks.inline.hpp"
|
|
||||||
|
|
||||||
class G1AdjustLiveClosure : public StackObj {
|
class G1AdjustLiveClosure : public StackObj {
|
||||||
G1AdjustClosure* _adjust_closure;
|
G1AdjustClosure* _adjust_closure;
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "utilities/ticks.inline.hpp"
|
#include "utilities/ticks.hpp"
|
||||||
|
|
||||||
class G1ResetHumongousClosure : public HeapRegionClosure {
|
class G1ResetHumongousClosure : public HeapRegionClosure {
|
||||||
G1CMBitMap* _bitmap;
|
G1CMBitMap* _bitmap;
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
#include "gc/g1/g1StringDedup.hpp"
|
#include "gc/g1/g1StringDedup.hpp"
|
||||||
#include "gc/g1/heapRegionManager.hpp"
|
#include "gc/g1/heapRegionManager.hpp"
|
||||||
#include "gc/shared/referenceProcessor.hpp"
|
#include "gc/shared/referenceProcessor.hpp"
|
||||||
#include "utilities/ticks.hpp"
|
|
||||||
|
|
||||||
class G1CollectedHeap;
|
class G1CollectedHeap;
|
||||||
class G1CMBitMap;
|
class G1CMBitMap;
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
#include "gc/shared/referenceProcessor.hpp"
|
#include "gc/shared/referenceProcessor.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "utilities/ticks.inline.hpp"
|
#include "utilities/ticks.hpp"
|
||||||
|
|
||||||
bool G1FullGCPrepareTask::G1CalculatePointersClosure::do_heap_region(HeapRegion* hr) {
|
bool G1FullGCPrepareTask::G1CalculatePointersClosure::do_heap_region(HeapRegion* hr) {
|
||||||
if (hr->is_humongous()) {
|
if (hr->is_humongous()) {
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
#include "gc/g1/g1StringDedup.hpp"
|
#include "gc/g1/g1StringDedup.hpp"
|
||||||
#include "gc/g1/heapRegionManager.hpp"
|
#include "gc/g1/heapRegionManager.hpp"
|
||||||
#include "gc/shared/referenceProcessor.hpp"
|
#include "gc/shared/referenceProcessor.hpp"
|
||||||
#include "utilities/ticks.hpp"
|
|
||||||
|
|
||||||
class G1CMBitMap;
|
class G1CMBitMap;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "gc/g1/g1FullGCTask.hpp"
|
#include "gc/g1/g1FullGCTask.hpp"
|
||||||
#include "logging/log.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) {
|
void G1FullGCTask::log_task(const char* name, uint worker_id, const Ticks& start, const Ticks& stop) {
|
||||||
Tickspan duration = stop - start;
|
Tickspan duration = stop - start;
|
||||||
|
@ -488,7 +488,7 @@ G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times,
|
|||||||
|
|
||||||
G1GCParPhaseTimesTracker::~G1GCParPhaseTimesTracker() {
|
G1GCParPhaseTimesTracker::~G1GCParPhaseTimesTracker() {
|
||||||
if (_phase_times != NULL) {
|
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) {
|
if (_phase_times != NULL) {
|
||||||
// Exclude trim time by increasing the start time.
|
// Exclude trim time by increasing the start time.
|
||||||
_start_time += _trim_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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -21,24 +21,15 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#ifndef SHARE_VM_TRACE_NOTRACEBACKEND_HPP
|
|
||||||
#define SHARE_VM_TRACE_NOTRACEBACKEND_HPP
|
|
||||||
|
|
||||||
#include "jni.h"
|
#ifndef SHARE_VM_GC_G1_G1HEAPREGIONEVENTSENDER_HPP
|
||||||
#include "trace/traceTime.hpp"
|
#define SHARE_VM_GC_G1_G1HEAPREGIONEVENTSENDER_HPP
|
||||||
|
|
||||||
class NoTraceBackend {
|
#include "memory/allocation.hpp"
|
||||||
|
|
||||||
|
class G1HeapRegionEventSender : public AllStatic {
|
||||||
public:
|
public:
|
||||||
static TracingTime time() {
|
static void send_events();
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class TraceThreadData {
|
#endif // SHARE_VM_GC_G1_G1HEAPREGIONEVENTSENDER_HPP
|
||||||
public:
|
|
||||||
TraceThreadData() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef NoTraceBackend Tracing;
|
|
||||||
|
|
||||||
#endif // SHARE_VM_TRACE_NOTRACEBACKEND_HPP
|
|
@ -29,7 +29,6 @@
|
|||||||
#include "gc/g1/g1RemSet.hpp"
|
#include "gc/g1/g1RemSet.hpp"
|
||||||
#include "oops/access.inline.hpp"
|
#include "oops/access.inline.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "utilities/ticks.inline.hpp"
|
|
||||||
|
|
||||||
template <class T> void G1ParScanThreadState::do_oop_evac(T* p) {
|
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.
|
// Reference should not be NULL here as such are never pushed to the task queue.
|
||||||
|
@ -44,11 +44,12 @@
|
|||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
#include "oops/access.inline.hpp"
|
#include "oops/access.inline.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
|
#include "runtime/os.hpp"
|
||||||
#include "utilities/align.hpp"
|
#include "utilities/align.hpp"
|
||||||
#include "utilities/globalDefinitions.hpp"
|
#include "utilities/globalDefinitions.hpp"
|
||||||
#include "utilities/intHisto.hpp"
|
#include "utilities/intHisto.hpp"
|
||||||
#include "utilities/stack.inline.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.
|
// Collects information about the overall remembered set scan progress during an evacuation.
|
||||||
class G1RemSetScanState : public CHeapObj<mtGC> {
|
class G1RemSetScanState : public CHeapObj<mtGC> {
|
||||||
@ -428,15 +429,15 @@ void G1RemSet::scan_rem_set(G1ParScanThreadState* pss, uint worker_i) {
|
|||||||
|
|
||||||
G1GCPhaseTimes* p = _g1p->phase_times();
|
G1GCPhaseTimes* p = _g1p->phase_times();
|
||||||
|
|
||||||
p->record_time_secs(G1GCPhaseTimes::ScanRS, worker_i, TicksToTimeHelper::seconds(cl.rem_set_root_scan_time()));
|
p->record_time_secs(G1GCPhaseTimes::ScanRS, worker_i, cl.rem_set_root_scan_time().seconds());
|
||||||
p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, TicksToTimeHelper::seconds(cl.rem_set_trim_partially_time()));
|
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_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_claimed(), G1GCPhaseTimes::ScanRSClaimedCards);
|
||||||
p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_skipped(), G1GCPhaseTimes::ScanRSSkippedCards);
|
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->record_time_secs(G1GCPhaseTimes::CodeRoots, worker_i, cl.strong_code_root_scan_time().seconds());
|
||||||
p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, TicksToTimeHelper::seconds(cl.strong_code_root_trim_partially_time()));
|
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.
|
// Closure used for updating rem sets. Only called during an evacuation pause.
|
||||||
@ -935,7 +936,7 @@ public:
|
|||||||
"TARS " PTR_FORMAT,
|
"TARS " PTR_FORMAT,
|
||||||
region_idx,
|
region_idx,
|
||||||
_cm->liveness(region_idx) * HeapWordSize,
|
_cm->liveness(region_idx) * HeapWordSize,
|
||||||
TicksToTimeHelper::seconds(time) * 1000.0,
|
time.seconds() * 1000.0,
|
||||||
marked_bytes,
|
marked_bytes,
|
||||||
p2i(hr->bottom()),
|
p2i(hr->bottom()),
|
||||||
p2i(top_at_mark_start),
|
p2i(top_at_mark_start),
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "gc/g1/heapRegionTracer.hpp"
|
#include "gc/g1/heapRegionTracer.hpp"
|
||||||
#include "trace/tracing.hpp"
|
#include "jfr/jfrEvents.hpp"
|
||||||
|
|
||||||
void HeapRegionTracer::send_region_type_change(uint index,
|
void HeapRegionTracer::send_region_type_change(uint index,
|
||||||
G1HeapRegionTraceType::Type from,
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,7 +25,7 @@
|
|||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "gc/shared/ageTableTracer.hpp"
|
#include "gc/shared/ageTableTracer.hpp"
|
||||||
#include "gc/shared/gcId.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) {
|
void AgeTableTracer::send_tenuring_distribution_event(uint age, size_t size) {
|
||||||
EventTenuringDistribution e;
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -24,13 +24,16 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "gc/shared/allocTracer.hpp"
|
#include "gc/shared/allocTracer.hpp"
|
||||||
|
#include "jfr/jfrEvents.hpp"
|
||||||
#include "runtime/handles.hpp"
|
#include "runtime/handles.hpp"
|
||||||
#include "trace/tracing.hpp"
|
|
||||||
#include "trace/traceMacros.hpp"
|
|
||||||
#include "utilities/globalDefinitions.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) {
|
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;
|
EventObjectAllocationOutsideTLAB event;
|
||||||
if (event.should_commit()) {
|
if (event.should_commit()) {
|
||||||
event.set_objectClass(klass);
|
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) {
|
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;
|
EventObjectAllocationInNewTLAB event;
|
||||||
if (event.should_commit()) {
|
if (event.should_commit()) {
|
||||||
event.set_objectClass(klass);
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,8 +25,8 @@
|
|||||||
#ifndef SHARE_VM_GC_SHARED_COPYFAILEDINFO_HPP
|
#ifndef SHARE_VM_GC_SHARED_COPYFAILEDINFO_HPP
|
||||||
#define SHARE_VM_GC_SHARED_COPYFAILEDINFO_HPP
|
#define SHARE_VM_GC_SHARED_COPYFAILEDINFO_HPP
|
||||||
|
|
||||||
|
#include "jfr/support/jfrThreadId.hpp"
|
||||||
#include "runtime/thread.hpp"
|
#include "runtime/thread.hpp"
|
||||||
#include "trace/traceMacros.hpp"
|
|
||||||
#include "utilities/globalDefinitions.hpp"
|
#include "utilities/globalDefinitions.hpp"
|
||||||
|
|
||||||
class CopyFailedInfo : public CHeapObj<mtGC> {
|
class CopyFailedInfo : public CHeapObj<mtGC> {
|
||||||
@ -72,9 +72,9 @@ class PromotionFailedInfo : public CopyFailedInfo {
|
|||||||
void register_copy_failure(size_t size) {
|
void register_copy_failure(size_t size) {
|
||||||
CopyFailedInfo::register_copy_failure(size);
|
CopyFailedInfo::register_copy_failure(size);
|
||||||
if (_thread_trace_id == 0) {
|
if (_thread_trace_id == 0) {
|
||||||
_thread_trace_id = THREAD_TRACE_ID(Thread::current());
|
_thread_trace_id = JFR_THREAD_ID(Thread::current());
|
||||||
} else {
|
} 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.");
|
"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 "precompiled.hpp"
|
||||||
#include "gc/shared/gcTimer.hpp"
|
#include "gc/shared/gcTimer.hpp"
|
||||||
#include "utilities/growableArray.hpp"
|
#include "utilities/growableArray.hpp"
|
||||||
#include "utilities/ticks.inline.hpp"
|
|
||||||
|
|
||||||
// the "time" parameter for most functions
|
// the "time" parameter for most functions
|
||||||
// has a default value set by Ticks::now()
|
// has a default value set by Ticks::now()
|
||||||
@ -376,7 +375,7 @@ public:
|
|||||||
GCTimer gc_timer;
|
GCTimer gc_timer;
|
||||||
gc_timer.register_gc_start(1);
|
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() {
|
static void gc_end() {
|
||||||
@ -384,7 +383,7 @@ public:
|
|||||||
gc_timer.register_gc_start(1);
|
gc_timer.register_gc_start(1);
|
||||||
gc_timer.register_gc_end(2);
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -35,7 +35,7 @@
|
|||||||
#include "runtime/os.hpp"
|
#include "runtime/os.hpp"
|
||||||
#include "utilities/globalDefinitions.hpp"
|
#include "utilities/globalDefinitions.hpp"
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#include "utilities/ticks.inline.hpp"
|
#include "utilities/ticks.hpp"
|
||||||
#if INCLUDE_G1GC
|
#if INCLUDE_G1GC
|
||||||
#include "gc/g1/evacuationInfo.hpp"
|
#include "gc/g1/evacuationInfo.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
@ -28,10 +28,8 @@
|
|||||||
#include "gc/shared/gcTimer.hpp"
|
#include "gc/shared/gcTimer.hpp"
|
||||||
#include "gc/shared/gcTrace.hpp"
|
#include "gc/shared/gcTrace.hpp"
|
||||||
#include "gc/shared/gcWhen.hpp"
|
#include "gc/shared/gcWhen.hpp"
|
||||||
|
#include "jfr/jfrEvents.hpp"
|
||||||
#include "runtime/os.hpp"
|
#include "runtime/os.hpp"
|
||||||
#include "trace/traceBackend.hpp"
|
|
||||||
#include "trace/tracing.hpp"
|
|
||||||
#include "tracefiles/traceEventClasses.hpp"
|
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#if INCLUDE_G1GC
|
#if INCLUDE_G1GC
|
||||||
#include "gc/g1/evacuationInfo.hpp"
|
#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) {
|
static JfrStructCopyFailed to_struct(const CopyFailedInfo& cf_info) {
|
||||||
TraceStructCopyFailed failed_info;
|
JfrStructCopyFailed failed_info;
|
||||||
failed_info.set_objectCount(cf_info.failed_count());
|
failed_info.set_objectCount(cf_info.failed_count());
|
||||||
failed_info.set_firstSize(cf_info.first_size());
|
failed_info.set_firstSize(cf_info.first_size());
|
||||||
failed_info.set_smallestSize(cf_info.smallest_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;
|
EventPromotionFailed e;
|
||||||
if (e.should_commit()) {
|
if (e.should_commit()) {
|
||||||
e.set_gcId(GCId::current());
|
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.set_thread(pf_info.thread_trace_id());
|
||||||
e.commit();
|
e.commit();
|
||||||
}
|
}
|
||||||
@ -231,14 +229,14 @@ void G1NewTracer::send_evacuation_failed_event(const EvacuationFailedInfo& ef_in
|
|||||||
EventEvacuationFailed e;
|
EventEvacuationFailed e;
|
||||||
if (e.should_commit()) {
|
if (e.should_commit()) {
|
||||||
e.set_gcId(GCId::current());
|
e.set_gcId(GCId::current());
|
||||||
e.set_evacuationFailed(to_trace_struct(ef_info));
|
e.set_evacuationFailed(to_struct(ef_info));
|
||||||
e.commit();
|
e.commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static TraceStructG1EvacuationStatistics
|
static JfrStructG1EvacuationStatistics
|
||||||
create_g1_evacstats(unsigned gcid, const G1EvacSummary& summary) {
|
create_g1_evacstats(unsigned gcid, const G1EvacSummary& summary) {
|
||||||
TraceStructG1EvacuationStatistics s;
|
JfrStructG1EvacuationStatistics s;
|
||||||
s.set_gcId(gcid);
|
s.set_gcId(gcid);
|
||||||
s.set_allocated(summary.allocated() * HeapWordSize);
|
s.set_allocated(summary.allocated() * HeapWordSize);
|
||||||
s.set_wasted(summary.wasted() * HeapWordSize);
|
s.set_wasted(summary.wasted() * HeapWordSize);
|
||||||
@ -313,8 +311,8 @@ void G1NewTracer::send_adaptive_ihop_statistics(size_t threshold,
|
|||||||
|
|
||||||
#endif // INCLUDE_G1GC
|
#endif // INCLUDE_G1GC
|
||||||
|
|
||||||
static TraceStructVirtualSpace to_trace_struct(const VirtualSpaceSummary& summary) {
|
static JfrStructVirtualSpace to_struct(const VirtualSpaceSummary& summary) {
|
||||||
TraceStructVirtualSpace space;
|
JfrStructVirtualSpace space;
|
||||||
space.set_start((TraceAddress)summary.start());
|
space.set_start((TraceAddress)summary.start());
|
||||||
space.set_committedEnd((TraceAddress)summary.committed_end());
|
space.set_committedEnd((TraceAddress)summary.committed_end());
|
||||||
space.set_committedSize(summary.committed_size());
|
space.set_committedSize(summary.committed_size());
|
||||||
@ -323,8 +321,8 @@ static TraceStructVirtualSpace to_trace_struct(const VirtualSpaceSummary& summar
|
|||||||
return space;
|
return space;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TraceStructObjectSpace to_trace_struct(const SpaceSummary& summary) {
|
static JfrStructObjectSpace to_struct(const SpaceSummary& summary) {
|
||||||
TraceStructObjectSpace space;
|
JfrStructObjectSpace space;
|
||||||
space.set_start((TraceAddress)summary.start());
|
space.set_start((TraceAddress)summary.start());
|
||||||
space.set_end((TraceAddress)summary.end());
|
space.set_end((TraceAddress)summary.end());
|
||||||
space.set_used(summary.used());
|
space.set_used(summary.used());
|
||||||
@ -344,7 +342,7 @@ class GCHeapSummaryEventSender : public GCHeapSummaryVisitor {
|
|||||||
if (e.should_commit()) {
|
if (e.should_commit()) {
|
||||||
e.set_gcId(GCId::current());
|
e.set_gcId(GCId::current());
|
||||||
e.set_when((u1)_when);
|
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.set_heapUsed(heap_summary->used());
|
||||||
e.commit();
|
e.commit();
|
||||||
}
|
}
|
||||||
@ -380,12 +378,12 @@ class GCHeapSummaryEventSender : public GCHeapSummaryVisitor {
|
|||||||
e.set_gcId(GCId::current());
|
e.set_gcId(GCId::current());
|
||||||
e.set_when((u1)_when);
|
e.set_when((u1)_when);
|
||||||
|
|
||||||
e.set_oldSpace(to_trace_struct(ps_heap_summary->old()));
|
e.set_oldSpace(to_struct(ps_heap_summary->old()));
|
||||||
e.set_oldObjectSpace(to_trace_struct(ps_heap_summary->old_space()));
|
e.set_oldObjectSpace(to_struct(ps_heap_summary->old_space()));
|
||||||
e.set_youngSpace(to_trace_struct(ps_heap_summary->young()));
|
e.set_youngSpace(to_struct(ps_heap_summary->young()));
|
||||||
e.set_edenSpace(to_trace_struct(ps_heap_summary->eden()));
|
e.set_edenSpace(to_struct(ps_heap_summary->eden()));
|
||||||
e.set_fromSpace(to_trace_struct(ps_heap_summary->from()));
|
e.set_fromSpace(to_struct(ps_heap_summary->from()));
|
||||||
e.set_toSpace(to_trace_struct(ps_heap_summary->to()));
|
e.set_toSpace(to_struct(ps_heap_summary->to()));
|
||||||
e.commit();
|
e.commit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -396,8 +394,8 @@ void GCTracer::send_gc_heap_summary_event(GCWhen::Type when, const GCHeapSummary
|
|||||||
heap_summary.accept(&visitor);
|
heap_summary.accept(&visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TraceStructMetaspaceSizes to_trace_struct(const MetaspaceSizes& sizes) {
|
static JfrStructMetaspaceSizes to_struct(const MetaspaceSizes& sizes) {
|
||||||
TraceStructMetaspaceSizes meta_sizes;
|
JfrStructMetaspaceSizes meta_sizes;
|
||||||
|
|
||||||
meta_sizes.set_committed(sizes.committed());
|
meta_sizes.set_committed(sizes.committed());
|
||||||
meta_sizes.set_used(sizes.used());
|
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_gcId(GCId::current());
|
||||||
e.set_when((u1) when);
|
e.set_when((u1) when);
|
||||||
e.set_gcThreshold(meta_space_summary.capacity_until_GC());
|
e.set_gcThreshold(meta_space_summary.capacity_until_GC());
|
||||||
e.set_metaspace(to_trace_struct(meta_space_summary.meta_space()));
|
e.set_metaspace(to_struct(meta_space_summary.meta_space()));
|
||||||
e.set_dataSpace(to_trace_struct(meta_space_summary.data_space()));
|
e.set_dataSpace(to_struct(meta_space_summary.data_space()));
|
||||||
e.set_classSpace(to_trace_struct(meta_space_summary.class_space()));
|
e.set_classSpace(to_struct(meta_space_summary.class_space()));
|
||||||
e.commit();
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -26,34 +26,50 @@
|
|||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "gc/shared/gcId.hpp"
|
#include "gc/shared/gcId.hpp"
|
||||||
#include "gc/shared/objectCountEventSender.hpp"
|
#include "gc/shared/objectCountEventSender.hpp"
|
||||||
|
#include "jfr/jfrEvents.hpp"
|
||||||
#include "memory/heapInspection.hpp"
|
#include "memory/heapInspection.hpp"
|
||||||
#include "trace/tracing.hpp"
|
|
||||||
#include "utilities/globalDefinitions.hpp"
|
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#include "utilities/ticks.hpp"
|
#include "utilities/ticks.hpp"
|
||||||
#if INCLUDE_SERVICES
|
#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() {
|
bool ObjectCountEventSender::should_send_event() {
|
||||||
#if INCLUDE_TRACE
|
#if INCLUDE_JFR
|
||||||
return Tracing::is_event_enabled(EventObjectCountAfterGC::eventId);
|
return _should_send_requestable_event || EventObjectCountAfterGC::is_enabled();
|
||||||
#else
|
#else
|
||||||
return false;
|
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
|
#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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -27,15 +27,25 @@
|
|||||||
|
|
||||||
#include "gc/shared/gcTrace.hpp"
|
#include "gc/shared/gcTrace.hpp"
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
|
#include "utilities/globalDefinitions.hpp"
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
|
#include "utilities/ticks.hpp"
|
||||||
|
|
||||||
#if INCLUDE_SERVICES
|
#if INCLUDE_SERVICES
|
||||||
|
|
||||||
class KlassInfoEntry;
|
class KlassInfoEntry;
|
||||||
class Ticks;
|
class Klass;
|
||||||
|
|
||||||
class ObjectCountEventSender : public AllStatic {
|
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:
|
public:
|
||||||
|
static void enable_requestable_event();
|
||||||
|
static void disable_requestable_event();
|
||||||
|
|
||||||
static void send(const KlassInfoEntry* entry, const Ticks& timestamp);
|
static void send(const KlassInfoEntry* entry, const Ticks& timestamp);
|
||||||
static bool should_send_event();
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -26,13 +26,15 @@
|
|||||||
#include "gc/shared/weakProcessor.hpp"
|
#include "gc/shared/weakProcessor.hpp"
|
||||||
#include "prims/jvmtiExport.hpp"
|
#include "prims/jvmtiExport.hpp"
|
||||||
#include "runtime/jniHandles.hpp"
|
#include "runtime/jniHandles.hpp"
|
||||||
#include "trace/tracing.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#include "trace/traceMacros.hpp"
|
#if INCLUDE_JFR
|
||||||
|
#include "jfr/jfr.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
void WeakProcessor::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive) {
|
void WeakProcessor::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive) {
|
||||||
JNIHandles::weak_oops_do(is_alive, keep_alive);
|
JNIHandles::weak_oops_do(is_alive, keep_alive);
|
||||||
JvmtiExport::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) {
|
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