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:
Erik Gahlin 2018-05-15 20:24:34 +02:00
parent f575533a17
commit a060be188d
1062 changed files with 119159 additions and 3164 deletions

View File

@ -509,6 +509,15 @@ jdk.localedata_COPY += _dict _th
# Exclude BreakIterator classes that are just used in compile process to generate
# data files and shouldn't go in the product
jdk.localedata_EXCLUDE_FILES += sun/text/resources/ext/BreakIteratorRules_th.java
################################################################################
# There is an issue in sjavac that triggers a warning in jdk.jfr that isn't
# triggered without sjavac.
ifeq ($(ENABLE_SJAVAC), yes)
jdk.jfr_SETUP := GENERATE_JDKBYTECODE_NOWARNINGS
endif
jdk.jfr_COPY := .xsd .xml .dtd
jdk.jfr_ADD_JAVAC_FLAGS := -XDstringConcat=inline -Xlint:-exports
################################################################################
# If this is an imported module that has prebuilt classes, only compile

View File

@ -26,7 +26,7 @@
# All valid JVM features, regardless of platform
VALID_JVM_FEATURES="compiler1 compiler2 zero minimal dtrace jvmti jvmci \
graal vm-structs jni-check services management cmsgc g1gc parallelgc serialgc nmt cds \
static-build link-time-opt aot"
static-build link-time-opt aot jfr"
# All valid JVM variants
VALID_JVM_VARIANTS="server client minimal core zero custom"
@ -309,6 +309,11 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES],
AC_MSG_ERROR([Specified JVM feature 'cmsgc' requires feature 'serialgc'])
fi
# Enable JFR by default, except on linux-sparcv9 and on minimal.
if test "x$OPENJDK_TARGET_OS" != xlinux || test "x$OPENJDK_TARGET_CPU" != xsparcv9; then
NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES jfr"
fi
# Turn on additional features based on other parts of configure
if test "x$INCLUDE_DTRACE" = "xtrue"; then
JVM_FEATURES="$JVM_FEATURES dtrace"
@ -396,7 +401,7 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES],
NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES cds"
fi
# Enable default features depending on variant.
# Enable features depending on variant.
JVM_FEATURES_server="compiler1 compiler2 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci $JVM_FEATURES_aot $JVM_FEATURES_graal"
JVM_FEATURES_client="compiler1 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci"
JVM_FEATURES_core="$NON_MINIMAL_FEATURES $JVM_FEATURES"

View File

@ -130,7 +130,7 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES],
if test "x$OPENJDK_TARGET_OS" = xsolaris; then
BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lsocket -lsched -ldoor -ldemangle -lnsl \
-lrt"
-lrt -lkstat"
BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBCXX_JVM"
fi

View File

@ -59,7 +59,9 @@ BOOT_MODULES += \
java.security.sasl \
java.xml \
jdk.internal.vm.ci \
jdk.jfr \
jdk.management \
jdk.management.jfr \
jdk.management.agent \
jdk.net \
jdk.sctp \
@ -152,6 +154,7 @@ DOCS_MODULES += \
jdk.jdeps \
jdk.jdi \
jdk.jdwp.agent \
jdk.jfr \
jdk.jlink \
jdk.jsobject \
jdk.jshell \
@ -159,6 +162,7 @@ DOCS_MODULES += \
jdk.localedata \
jdk.management \
jdk.management.agent \
jdk.management.jfr \
jdk.naming.dns \
jdk.naming.rmi \
jdk.net \

View 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)
################################################################################

View File

@ -38,6 +38,7 @@ include HotspotCommon.gmk
include gensrc/GensrcAdlc.gmk
include gensrc/GensrcDtrace.gmk
include gensrc/GensrcJvmti.gmk
include gensrc/GensrcJfr.gmk
$(eval $(call IncludeCustomExtension, hotspot/gensrc/GenerateSources.gmk))

View 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), \
))

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -50,7 +50,7 @@ TOOL_JVMTI_GEN := $(JAVA_SMALL) -cp $(JVMTI_TOOLS_OUTPUTDIR) jvmtiGen
TOOL_JVMTI_ENV_FILL := $(JAVA_SMALL) -cp $(JVMTI_TOOLS_OUTPUTDIR) jvmtiEnvFill
################################################################################
# Setup make rules for an xml transform for jvmti/trace file generation.
# Setup make rules for an xml transform for jvmti file generation.
#
# Parameter 1 is the name of the rule. This name is used as variable prefix,
# and the targets generated are listed in a variable by that name. This name is
@ -126,48 +126,3 @@ ifeq ($(JVM_VARIANT), $(firstword $(JVM_VARIANTS)))
TARGETS += $(COPY_JVMTI_H)
endif
################################################################################
# Create trace files in gensrc/tracefiles
TRACE_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/gensrc/tracefiles
TRACE_SRCDIR := $(TOPDIR)/src/hotspot/share/trace
# Append list of XSL files to search (might have been set by custom extensions)
TRACE_XSL_FILES += $(wildcard $(TRACE_SRCDIR)/*.xsl)
TRACE_XML ?= $(TRACE_SRCDIR)/trace.xml
# Changing these will trigger a rebuild of generated trace files.
TRACE_DEPS += \
$(TRACE_XML) \
$(TRACE_SRCDIR)/tracetypes.xml \
$(TRACE_SRCDIR)/tracerelationdecls.xml \
$(TRACE_SRCDIR)/traceevents.xml \
$(TRACE_SRCDIR)/trace.dtd \
$(TRACE_SRCDIR)/xinclude.mod \
#
# Setup rule for generating a trace file
#
# $1 is generated source file name in $(TRACE_OUTPUTDIR)
define SetupTraceGeneration
$$(eval $$(call SetupXslTransform, $1, \
XML_FILE := $$(TRACE_XML), \
XSL_FILE := $$(firstword $$(filter %/$$(basename $1).xsl, $$(TRACE_XSL_FILES))), \
OUTPUT_DIR := $$(TRACE_OUTPUTDIR), \
DEPS := $$(TRACE_DEPS), \
))
endef
# Append files to generated (might have been set by custom extensions)
TRACE_GENSRC_FILES += \
traceEventClasses.hpp \
traceEventIds.hpp \
traceTypes.hpp \
#
# Call SetupTraceGeneration for all trace gensrc files
$(foreach tracefile, $(TRACE_GENSRC_FILES), \
$(eval $(call SetupTraceGeneration, $(tracefile))) \
)

View File

@ -154,6 +154,12 @@ ifneq ($(call check-jvm-feature, serialgc), true)
# If serial is disabled, we cannot use serial as OldGC in parallel
JVM_EXCLUDE_FILES += psMarkSweep.cpp psMarkSweepDecorator.cpp
endif
ifneq ($(call check-jvm-feature, jfr), true)
JVM_CFLAGS_FEATURES += -DINCLUDE_JFR=0
JVM_EXCLUDE_PATTERNS += jfr
endif
################################################################################
ifeq ($(call check-jvm-feature, link-time-opt), true)

View File

@ -223,7 +223,7 @@ class BuildConfig {
sysDefines.add("_WINDOWS");
sysDefines.add("HOTSPOT_BUILD_USER=\\\""+System.getProperty("user.name")+"\\\"");
sysDefines.add("HOTSPOT_BUILD_TARGET=\\\""+get("Build")+"\\\"");
sysDefines.add("INCLUDE_TRACE=1");
sysDefines.add("INCLUDE_JFR=1");
sysDefines.add("_JNI_IMPLEMENTATION_");
if (vars.get("PlatformName").equals("Win32")) {
sysDefines.add("HOTSPOT_LIB_ARCH=\\\"i386\\\"");

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -273,6 +273,7 @@ my.make.rule.test.targets.svc= \
${my.test.target.set:TESTNAME=jdk_instrument}, \
${my.test.target.set:TESTNAME=jdk_jmx}, \
${my.test.target.set:TESTNAME=jdk_jdi}, \
${my.test.target.set:TESTNAME=jdk_jfr}, \
${my.test.target.set:TESTNAME=svc_tools}, \
${my.make.rule.test.targets.svc.extra}

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -98,8 +98,8 @@ dist.javadoc.dir=${dist.dir}/javadoc
dist.nashornapi.javadoc.dir=${dist.javadoc.dir}/nashornapi
dist.dynalinkapi.javadoc.dir=${dist.javadoc.dir}/dynalinkapi
# configuration for java flight recorder
run.test.jvmargs.jfr=-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=${build.dir},stackdepth=128
# configuration for flight recorder
run.test.jvmargs.jfr=XX:StartFlightRecording=disk=true,dumponexit=true,dumponexitpath=${build.dir},stackdepth=128
# test library location
test.lib=test/nashorn/lib
@ -354,7 +354,7 @@ run.test.xms=2G
# uncomment this jfr.args to enable light recordings. the stack needs to be cranked up to 1024 frames,
# or everything will as of the now drown in lambda forms and be cut off.
#
#jfr.args=-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath="test_suite.jfr",stackdepth=1024 \
#jfr.args=-XX:StartFlightRecording=disk=true,dumponexit=true,dumponexitpath="test_suite.jfr",stackdepth=1024
jfr.args=

View File

@ -2891,7 +2891,6 @@
<in>stringUtils.hpp</in>
<in>ticks.cpp</in>
<in>ticks.hpp</in>
<in>ticks.inline.hpp</in>
<in>utf8.cpp</in>
<in>utf8.hpp</in>
<in>vmError.cpp</in>
@ -6887,7 +6886,7 @@
<pElem>../../hotspot/src/share/vm/ci</pElem>
<pElem>../../hotspot/src/share/vm/oops</pElem>
<pElem>../../hotspot/src/share/vm/trace</pElem>
<pElem>../../build/macosx-x86_64-normal-server-release/hotspot/variant-server/gensrc/tracefiles</pElem>
<pElem>../../build/macosx-x86_64-normal-server-release/hotspot/variant-server/gensrc/jfrfiles</pElem>
<pElem>../../hotspot/src/share/vm/gc/parallel</pElem>
<pElem>../../hotspot/src/share/vm/gc/shared</pElem>
<pElem>../../hotspot/src/share/vm/classfile</pElem>
@ -15408,11 +15407,6 @@
tool="3"
flavor2="0">
</item>
<item path="../../src/hotspot/share/utilities/ticks.inline.hpp"
ex="false"
tool="3"
flavor2="0">
</item>
<item path="../../src/hotspot/share/utilities/utf8.cpp"
ex="false"
tool="1"
@ -29190,11 +29184,6 @@
tool="3"
flavor2="0">
</item>
<item path="../../src/hotspot/share/utilities/ticks.inline.hpp"
ex="false"
tool="3"
flavor2="0">
</item>
<item path="../../src/hotspot/share/utilities/utf8.cpp"
ex="false"
tool="1"

View 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;
}

View 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

View 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;
}

View 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

View 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;
}

View 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

View 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;
}

View 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

View 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",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
""
};

View 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

View 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(&current_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;
}

File diff suppressed because it is too large Load Diff

View 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;
}

File diff suppressed because it is too large Load Diff

View 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;
}

View 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,8 @@
#include "runtime/os.hpp"
extern "C" jlong _raw_rdtsc(); // In .il file
inline jlong os::rdtsc() { return _raw_rdtsc(); }
#endif // OS_CPU_SOLARIS_X86_VM_OS_SOLARIS_X86_INLINE_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -33,6 +33,7 @@
#include "c1/c1_ValueType.hpp"
#include "compiler/compileBroker.hpp"
#include "interpreter/linkResolver.hpp"
#include "jfr/support/jfrIntrinsics.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
@ -41,6 +42,7 @@
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/macros.hpp"
Compiler::Compiler() : AbstractCompiler(compiler_c1) {
@ -222,10 +224,10 @@ bool Compiler::is_intrinsic_supported(const methodHandle& method) {
case vmIntrinsics::_compareAndSetObject:
case vmIntrinsics::_getCharStringU:
case vmIntrinsics::_putCharStringU:
#ifdef TRACE_HAVE_INTRINSICS
#ifdef JFR_HAVE_INTRINSICS
case vmIntrinsics::_counterTime:
case vmIntrinsics::_getBufferWriter:
#if defined(_LP64) || !defined(TRACE_ID_CLASS_SHIFT)
case vmIntrinsics::_getEventWriter:
#if defined(_LP64) || !defined(TRACE_ID_SHIFT)
case vmIntrinsics::_getClassId:
#endif
#endif

View File

@ -35,6 +35,7 @@
#include "ci/ciUtilities.inline.hpp"
#include "compiler/compileBroker.hpp"
#include "interpreter/bytecode.hpp"
#include "jfr/jfrEvents.hpp"
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/sharedRuntime.hpp"
@ -4300,6 +4301,30 @@ void GraphBuilder::append_char_access(ciMethod* callee, bool is_store) {
}
}
static void post_inlining_event(EventCompilerInlining* event,
int compile_id,
const char* msg,
bool success,
int bci,
ciMethod* caller,
ciMethod* callee) {
assert(caller != NULL, "invariant");
assert(callee != NULL, "invariant");
assert(event != NULL, "invariant");
assert(event->should_commit(), "invariant");
JfrStructCalleeMethod callee_struct;
callee_struct.set_type(callee->holder()->name()->as_utf8());
callee_struct.set_name(callee->name()->as_utf8());
callee_struct.set_descriptor(callee->signature()->as_symbol()->as_utf8());
event->set_compileId(compile_id);
event->set_message(msg);
event->set_succeeded(success);
event->set_bci(bci);
event->set_caller(caller->get_Method());
event->set_callee(callee_struct);
event->commit();
}
void GraphBuilder::print_inlining(ciMethod* callee, const char* msg, bool success) {
CompileLog* log = compilation()->log();
if (log != NULL) {
@ -4315,18 +4340,10 @@ void GraphBuilder::print_inlining(ciMethod* callee, const char* msg, bool succes
log->inline_fail("reason unknown");
}
}
#if INCLUDE_TRACE
EventCompilerInlining event;
if (event.should_commit()) {
event.set_compileId(compilation()->env()->task()->compile_id());
event.set_message(msg);
event.set_succeeded(success);
event.set_bci(bci());
event.set_caller(method()->get_Method());
event.set_callee(callee->to_trace_struct());
event.commit();
post_inlining_event(&event, compilation()->env()->task()->compile_id(), msg, success, bci(), method(), callee);
}
#endif // INCLUDE_TRACE
CompileTask::print_inlining_ul(callee, scope()->level(), bci(), msg);

View File

@ -42,9 +42,6 @@
#include "runtime/vm_version.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/macros.hpp"
#ifdef TRACE_HAVE_INTRINSICS
#include "trace/traceMacros.hpp"
#endif
#ifdef ASSERT
#define __ gen()->lir(__FILE__, __LINE__)->
@ -2916,7 +2913,7 @@ void LIRGenerator::do_IfOp(IfOp* x) {
__ cmove(lir_cond(x->cond()), t_val.result(), f_val.result(), reg, as_BasicType(x->x()->type()));
}
#ifdef TRACE_HAVE_INTRINSICS
#ifdef JFR_HAVE_INTRINSICS
void LIRGenerator::do_ClassIDIntrinsic(Intrinsic* x) {
CodeEmitInfo* info = state_for(x);
CodeEmitInfo* info2 = new CodeEmitInfo(info); // Clone for the second null check
@ -2928,7 +2925,7 @@ void LIRGenerator::do_ClassIDIntrinsic(Intrinsic* x) {
LIR_Opr klass = new_register(T_METADATA);
__ move(new LIR_Address(arg.result(), java_lang_Class::klass_offset_in_bytes(), T_ADDRESS), klass, info);
LIR_Opr id = new_register(T_LONG);
ByteSize offset = TRACE_KLASS_TRACE_ID_OFFSET;
ByteSize offset = KLASS_TRACE_ID_OFFSET;
LIR_Address* trace_id_addr = new LIR_Address(klass, in_bytes(offset), T_LONG);
__ move(trace_id_addr, id);
@ -2938,18 +2935,18 @@ void LIRGenerator::do_ClassIDIntrinsic(Intrinsic* x) {
#ifdef TRACE_ID_META_BITS
__ logical_and(id, LIR_OprFact::longConst(~TRACE_ID_META_BITS), id);
#endif
#ifdef TRACE_ID_CLASS_SHIFT
__ unsigned_shift_right(id, TRACE_ID_CLASS_SHIFT, id);
#ifdef TRACE_ID_SHIFT
__ unsigned_shift_right(id, TRACE_ID_SHIFT, id);
#endif
__ move(id, rlock_result(x));
}
void LIRGenerator::do_getBufferWriter(Intrinsic* x) {
void LIRGenerator::do_getEventWriter(Intrinsic* x) {
LabelObj* L_end = new LabelObj();
LIR_Address* jobj_addr = new LIR_Address(getThreadPointer(),
in_bytes(TRACE_THREAD_DATA_WRITER_OFFSET),
in_bytes(THREAD_LOCAL_WRITER_OFFSET_JFR),
T_OBJECT);
LIR_Opr result = rlock_result(x);
__ move_wide(jobj_addr, result);
@ -2987,15 +2984,15 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
break;
}
#ifdef TRACE_HAVE_INTRINSICS
#ifdef JFR_HAVE_INTRINSICS
case vmIntrinsics::_getClassId:
do_ClassIDIntrinsic(x);
break;
case vmIntrinsics::_getBufferWriter:
do_getBufferWriter(x);
case vmIntrinsics::_getEventWriter:
do_getEventWriter(x);
break;
case vmIntrinsics::_counterTime:
do_RuntimeCall(CAST_FROM_FN_PTR(address, TRACE_TIME_METHOD), x);
do_RuntimeCall(CAST_FROM_FN_PTR(address, JFR_TIME_FUNCTION), x);
break;
#endif

View File

@ -30,6 +30,7 @@
#include "c1/c1_LIR.hpp"
#include "ci/ciMethodData.hpp"
#include "gc/shared/barrierSet.hpp"
#include "jfr/support/jfrIntrinsics.hpp"
#include "utilities/macros.hpp"
#include "utilities/sizes.hpp"
@ -459,9 +460,9 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
SwitchRangeArray* create_lookup_ranges(LookupSwitch* x);
void do_SwitchRanges(SwitchRangeArray* x, LIR_Opr value, BlockBegin* default_sux);
#ifdef TRACE_HAVE_INTRINSICS
#ifdef JFR_HAVE_INTRINSICS
void do_ClassIDIntrinsic(Intrinsic* x);
void do_getBufferWriter(Intrinsic* x);
void do_getEventWriter(Intrinsic* x);
#endif
void do_RuntimeCall(address routine, Intrinsic* x);

View File

@ -43,6 +43,7 @@
#include "gc/shared/collectedHeap.hpp"
#include "interpreter/bytecode.hpp"
#include "interpreter/interpreter.hpp"
#include "jfr/support/jfrIntrinsics.hpp"
#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/oopFactory.hpp"
@ -320,8 +321,8 @@ const char* Runtime1::name_for_address(address entry) {
FUNCTION_CASE(entry, SharedRuntime::dtrace_method_exit);
FUNCTION_CASE(entry, is_instance_of);
FUNCTION_CASE(entry, trace_block_entry);
#ifdef TRACE_HAVE_INTRINSICS
FUNCTION_CASE(entry, TRACE_TIME_METHOD);
#ifdef JFR_HAVE_INTRINSICS
FUNCTION_CASE(entry, JFR_TIME_FUNCTION);
#endif
FUNCTION_CASE(entry, StubRoutines::updateBytesCRC32());
FUNCTION_CASE(entry, StubRoutines::updateBytesCRC32C());

View File

@ -42,6 +42,7 @@
#include "compiler/disassembler.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
#include "interpreter/linkResolver.hpp"
#include "jfr/jfrEvents.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
@ -60,7 +61,6 @@
#include "runtime/safepointVerifiers.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/thread.inline.hpp"
#include "trace/tracing.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/macros.hpp"
#ifdef COMPILER1
@ -1144,7 +1144,6 @@ void ciEnv::record_failure(const char* reason) {
}
void ciEnv::report_failure(const char* reason) {
// Create and fire JFR event
EventCompilationFailure event;
if (event.should_commit()) {
event.set_compileId(compile_id());

View File

@ -48,7 +48,6 @@
#include "runtime/deoptimization.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/xmlstream.hpp"
#include "trace/tracing.hpp"
#ifdef COMPILER2
#include "ci/bcEscapeAnalyzer.hpp"
#include "ci/ciTypeFlow.hpp"
@ -1495,13 +1494,3 @@ bool ciMethod::is_consistent_info(ciMethod* declared_method, ciMethod* resolved_
}
// ------------------------------------------------------------------
#if INCLUDE_TRACE
TraceStructCalleeMethod ciMethod::to_trace_struct() const {
TraceStructCalleeMethod result;
result.set_type(holder()->name()->as_utf8());
result.set_name(name()->as_utf8());
result.set_descriptor(signature()->as_symbol()->as_utf8());
return result;
}
#endif

View File

@ -32,7 +32,6 @@
#include "compiler/methodLiveness.hpp"
#include "prims/methodHandles.hpp"
#include "utilities/bitMap.hpp"
#include "trace/tracing.hpp"
class ciMethodBlocks;
class MethodLiveness;
@ -362,10 +361,6 @@ class ciMethod : public ciMetadata {
void print_short_name(outputStream* st = tty);
static bool is_consistent_info(ciMethod* declared_method, ciMethod* resolved_method);
#if INCLUDE_TRACE
TraceStructCalleeMethod to_trace_struct() const;
#endif
};
#endif // SHARE_VM_CI_CIMETHOD_HPP

View File

@ -67,7 +67,6 @@
#include "runtime/timer.hpp"
#include "services/classLoadingService.hpp"
#include "services/threadService.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/align.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/copy.hpp"
@ -80,6 +79,9 @@
#if INCLUDE_CDS
#include "classfile/systemDictionaryShared.hpp"
#endif
#if INCLUDE_JFR
#include "jfr/support/jfrTraceIdExtension.hpp"
#endif
// We generally try to create the oops directly when parsing, rather than
// allocating temporary data structures and copying the bytes twice. A
@ -5639,7 +5641,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
}
}
TRACE_INIT_ID(ik);
JFR_ONLY(INIT_ID(ik);)
// If we reach here, all is well.
// Now remove the InstanceKlass* from the _klass_to_deallocate field

View File

@ -76,8 +76,10 @@
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
#if INCLUDE_TRACE
#include "trace/tracing.hpp"
#include "utilities/ticks.hpp"
#if INCLUDE_JFR
#include "jfr/jfr.hpp"
#include "jfr/jfrEvents.hpp"
#endif
volatile size_t ClassLoaderDataGraph::_num_array_classes = 0;
@ -161,7 +163,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) :
NOT_PRODUCT(_dependency_count = 0); // number of class loader dependencies
TRACE_INIT_ID(this);
JFR_ONLY(INIT_ID(this);)
}
ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() {
@ -1276,6 +1278,28 @@ bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) {
}
#endif // PRODUCT
#if INCLUDE_JFR
static Ticks class_unload_time;
static void post_class_unload_event(Klass* const k) {
assert(k != NULL, "invariant");
EventClassUnload event(UNTIMED);
event.set_endtime(class_unload_time);
event.set_unloadedClass(k);
event.set_definingClassLoader(k->class_loader_data());
event.commit();
}
static void post_class_unload_events() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
if (Jfr::is_enabled()) {
if (EventClassUnload::is_enabled()) {
class_unload_time = Ticks::now();
ClassLoaderDataGraph::classes_unloading_do(&post_class_unload_event);
}
Jfr::on_unloading_classes();
}
}
#endif // INCLUDE_JFR
// Move class loader data from main list to the unloaded list for unloading
// and deallocation later.
@ -1353,8 +1377,7 @@ bool ClassLoaderDataGraph::do_unloading(bool clean_previous_versions) {
}
data = data->next();
}
post_class_unload_events();
JFR_ONLY(post_class_unload_events();)
}
log_debug(class, loader, data)("do_unloading: loaders processed %u, loaders removed %u", loaders_processed, loaders_removed);
@ -1393,20 +1416,6 @@ int ClassLoaderDataGraph::resize_if_needed() {
return resized;
}
void ClassLoaderDataGraph::post_class_unload_events() {
#if INCLUDE_TRACE
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
if (Tracing::enabled()) {
if (Tracing::is_event_enabled(TraceClassUnloadEvent)) {
assert(_unloading != NULL, "need class loader data unload list!");
_class_unload_time = Ticks::now();
classes_unloading_do(&class_unload_event);
}
Tracing::on_unloading_classes();
}
#endif
}
ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic()
: _next_klass(NULL) {
ClassLoaderData* cld = ClassLoaderDataGraph::_head;
@ -1490,20 +1499,3 @@ void ClassLoaderDataGraph::print_on(outputStream * const out) {
}
}
#endif // PRODUCT
#if INCLUDE_TRACE
Ticks ClassLoaderDataGraph::_class_unload_time;
void ClassLoaderDataGraph::class_unload_event(Klass* const k) {
assert(k != NULL, "invariant");
// post class unload event
EventClassUnload event(UNTIMED);
event.set_endtime(_class_unload_time);
event.set_unloadedClass(k);
event.set_definingClassLoader(k->class_loader_data());
event.commit();
}
#endif // INCLUDE_TRACE

View File

@ -31,13 +31,13 @@
#include "oops/oopHandle.hpp"
#include "oops/weakHandle.hpp"
#include "runtime/mutex.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_TRACE
#include "utilities/ticks.hpp"
#if INCLUDE_JFR
#include "jfr/support/jfrTraceIdExtension.hpp"
#endif
//
// A class loader represents a linkset. Conceptually, a linkset identifies
// the complete transitive closure of resolved links that a dynamic linker can
@ -85,7 +85,6 @@ class ClassLoaderDataGraph : public AllStatic {
static ClassLoaderData* add_to_graph(Handle class_loader, bool anonymous);
static ClassLoaderData* add(Handle class_loader, bool anonymous);
static void post_class_unload_events();
public:
static ClassLoaderData* find_or_create(Handle class_loader);
static void purge();
@ -167,12 +166,6 @@ class ClassLoaderDataGraph : public AllStatic {
#ifndef PRODUCT
static bool contains_loader_data(ClassLoaderData* loader_data);
#endif
#if INCLUDE_TRACE
private:
static Ticks _class_unload_time;
static void class_unload_event(Klass* const k);
#endif
};
// ClassLoaderData class
@ -268,7 +261,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
// JFR support
Klass* _class_loader_klass;
Symbol* _class_loader_name;
TRACE_DEFINE_TRACE_ID_FIELD;
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
void set_next(ClassLoaderData* next) { _next = next; }
ClassLoaderData* next() const { return _next; }
@ -410,7 +403,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
Klass* class_loader_klass() const { return _class_loader_klass; }
Symbol* class_loader_name() const { return _class_loader_name; }
TRACE_DEFINE_TRACE_ID_METHODS;
JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
};
// An iterator that distributes Klasses to parallel worker threads.

View File

@ -35,7 +35,11 @@
#include "prims/jvmtiEnvBase.hpp"
#include "prims/jvmtiRedefineClasses.hpp"
#include "runtime/handles.inline.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_JFR
#include "jfr/support/jfrKlassExtension.hpp"
#endif
// called during initial loading of a shared class
InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
@ -228,7 +232,7 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
result->store_fingerprint(stream->compute_fingerprint());
}
TRACE_KLASS_CREATION(result, parser, THREAD);
JFR_ONLY(ON_KLASS_CREATION(result, parser, THREAD);)
#if INCLUDE_CDS
if (DumpSharedSpaces) {

View File

@ -33,7 +33,6 @@
#include "oops/symbol.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/safepoint.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/events.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/hashtable.inline.hpp"
@ -215,7 +214,7 @@ void ModuleEntry::purge_reads() {
}
}
void ModuleEntry::module_reads_do(ModuleClosure* const f) {
void ModuleEntry::module_reads_do(ModuleClosure* f) {
assert_locked_or_safepoint(Module_lock);
assert(f != NULL, "invariant");
@ -279,7 +278,7 @@ ModuleEntry* ModuleEntry::new_unnamed_module_entry(Handle module_handle, ClassLo
entry->set_loader_data(cld);
entry->_is_open = true;
TRACE_INIT_ID(entry);
JFR_ONLY(INIT_ID(entry);)
return entry;
}
@ -367,7 +366,7 @@ ModuleEntry* ModuleEntryTable::new_entry(unsigned int hash, Handle module_handle
}
}
TRACE_INIT_ID(entry);
JFR_ONLY(INIT_ID(entry);)
return entry;
}

View File

@ -32,10 +32,13 @@
#include "oops/symbol.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/mutexLocker.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/hashtable.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
#if INCLUDE_JFR
#include "jfr/support/jfrTraceIdExtension.hpp"
#endif
#define UNNAMED_MODULE "Unnamed Module"
#define JAVAPKG "java"
@ -69,7 +72,7 @@ private:
bool _must_walk_reads; // walk module's reads list at GC safepoints to purge out dead modules
bool _is_open; // whether the packages in the module are all unqualifiedly exported
bool _is_patched; // whether the module is patched via --patch-module
TRACE_DEFINE_TRACE_ID_FIELD;
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
enum {MODULE_READS_SIZE = 101}; // Initial size of list of modules that the module can read.
public:
@ -164,8 +167,6 @@ public:
// iteration support for readability
void module_reads_do(ModuleClosure* const f);
TRACE_DEFINE_TRACE_ID_METHODS;
// Purge dead weak references out of reads list when any given class loader is unloaded.
void purge_reads();
void delete_reads();
@ -178,12 +179,14 @@ public:
void print(outputStream* st = tty);
void verify();
JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
};
// Iterator interface
class ModuleClosure: public StackObj {
public:
virtual void do_module(ModuleEntry* const module) = 0;
virtual void do_module(ModuleEntry* module) = 0;
};

View File

@ -29,7 +29,6 @@
#include "memory/resourceArea.hpp"
#include "oops/symbol.hpp"
#include "runtime/handles.inline.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/events.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/hashtable.inline.hpp"
@ -200,7 +199,7 @@ PackageEntry* PackageEntryTable::new_entry(unsigned int hash, Symbol* name, Modu
assert(Module_lock->owned_by_self(), "should have the Module_lock");
PackageEntry* entry = (PackageEntry*)Hashtable<Symbol*, mtModule>::allocate_new_entry(hash, name);
TRACE_INIT_ID(entry);
JFR_ONLY(INIT_ID(entry);)
// Initialize fields specific to a PackageEntry
entry->init();
@ -283,7 +282,7 @@ void PackageEntryTable::verify_javabase_packages(GrowableArray<Symbol*> *pkg_lis
}
// iteration of qualified exports
void PackageEntry::package_exports_do(ModuleClosure* const f) {
void PackageEntry::package_exports_do(ModuleClosure* f) {
assert_locked_or_safepoint(Module_lock);
assert(f != NULL, "invariant");

View File

@ -29,7 +29,12 @@
#include "oops/symbol.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/hashtable.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
#if INCLUDE_JFR
#include "jfr/support/jfrTraceIdExtension.hpp"
#endif
// A PackageEntry basically represents a Java package. It contains:
// - Symbol* containing the package's name.
@ -104,7 +109,7 @@ private:
// Contains list of modules this package is qualifiedly exported to. Access
// to this list is protected by the Module_lock.
GrowableArray<ModuleEntry*>* _qualified_exports;
TRACE_DEFINE_TRACE_ID_FIELD;
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
// Initial size of a package entry's list of qualified exports.
enum {QUAL_EXP_SIZE = 43};
@ -197,9 +202,9 @@ public:
}
// iteration of qualified exports
void package_exports_do(ModuleClosure* const f);
void package_exports_do(ModuleClosure* f);
TRACE_DEFINE_TRACE_ID_METHODS;
JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
// Purge dead weak references out of exported list when any given class loader is unloaded.
void purge_qualified_exports();

View File

@ -47,6 +47,7 @@
#include "gc/shared/oopStorage.inline.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/interpreter.hpp"
#include "jfr/jfrEvents.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/filemap.hpp"
@ -81,7 +82,6 @@
#include "services/classLoadingService.hpp"
#include "services/diagnosticCommand.hpp"
#include "services/threadService.hpp"
#include "trace/tracing.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_CDS
#include "classfile/systemDictionaryShared.hpp"
@ -623,32 +623,16 @@ InstanceKlass* SystemDictionary::handle_parallel_super_load(
return NULL;
}
static void post_class_load_event(EventClassLoad* event,
const InstanceKlass* k,
const ClassLoaderData* init_cld) {
#if INCLUDE_TRACE
static void post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) {
assert(event != NULL, "invariant");
assert(k != NULL, "invariant");
if (event->should_commit()) {
event->set_loadedClass(k);
event->set_definingClassLoader(k->class_loader_data());
event->set_initiatingClassLoader(init_cld);
event->commit();
}
#endif // INCLUDE_TRACE
assert(event->should_commit(), "invariant");
event->set_loadedClass(k);
event->set_definingClassLoader(k->class_loader_data());
event->set_initiatingClassLoader(init_cld);
event->commit();
}
static void class_define_event(InstanceKlass* k,
const ClassLoaderData* def_cld) {
#if INCLUDE_TRACE
EventClassDefine event;
if (event.should_commit()) {
event.set_definedClass(k);
event.set_definingClassLoader(def_cld);
event.commit();
}
#endif // INCLUDE_TRACE
}
// Be careful when modifying this code: once you have run
// placeholders()->find_and_add(PlaceholderTable::LOAD_INSTANCE),
@ -881,9 +865,9 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
if (HAS_PENDING_EXCEPTION || k == NULL) {
return NULL;
}
post_class_load_event(&class_load_start_event, k, loader_data);
if (class_load_start_event.should_commit()) {
post_class_load_event(&class_load_start_event, k, loader_data);
}
#ifdef ASSERT
{
ClassLoaderData* loader_data = k->class_loader_data();
@ -1045,8 +1029,9 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
assert(THREAD->is_Java_thread(), "thread->is_Java_thread()");
JvmtiExport::post_class_load((JavaThread *) THREAD, k);
}
post_class_load_event(&class_load_start_event, k, loader_data);
if (class_load_start_event.should_commit()) {
post_class_load_event(&class_load_start_event, k, loader_data);
}
}
assert(host_klass != NULL || NULL == cp_patches,
"cp_patches only found with host_klass");
@ -1558,6 +1543,15 @@ InstanceKlass* SystemDictionary::load_instance_class(Symbol* class_name, Handle
}
}
static void post_class_define_event(InstanceKlass* k, const ClassLoaderData* def_cld) {
EventClassDefine event;
if (event.should_commit()) {
event.set_definedClass(k);
event.set_definingClassLoader(def_cld);
event.commit();
}
}
void SystemDictionary::define_instance_class(InstanceKlass* k, TRAPS) {
HandleMark hm(THREAD);
@ -1626,7 +1620,7 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, TRAPS) {
JvmtiExport::post_class_load((JavaThread *) THREAD, k);
}
class_define_event(k, loader_data);
post_class_define_event(k, loader_data);
}
// Support parallel classloading

View File

@ -350,7 +350,7 @@ vmIntrinsics::ID vmIntrinsics::for_raw_conversion(BasicType src, BasicType dest)
bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) {
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
switch(id) {
#ifdef TRACE_HAVE_INTRINSICS
#ifdef JFR_HAVE_INTRINSICS
case vmIntrinsics::_counterTime:
#endif
case vmIntrinsics::_currentTimeMillis:
@ -388,7 +388,7 @@ bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) {
bool vmIntrinsics::can_trap(vmIntrinsics::ID id) {
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
switch(id) {
#ifdef TRACE_HAVE_INTRINSICS
#ifdef JFR_HAVE_INTRINSICS
case vmIntrinsics::_counterTime:
case vmIntrinsics::_getClassId:
#endif
@ -424,7 +424,7 @@ bool vmIntrinsics::can_trap(vmIntrinsics::ID id) {
bool vmIntrinsics::should_be_pinned(vmIntrinsics::ID id) {
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
switch(id) {
#ifdef TRACE_HAVE_INTRINSICS
#ifdef JFR_HAVE_INTRINSICS
case vmIntrinsics::_counterTime:
#endif
case vmIntrinsics::_currentTimeMillis:

View File

@ -26,10 +26,12 @@
#define SHARE_VM_CLASSFILE_VMSYMBOLS_HPP
#include "classfile/moduleEntry.hpp"
#include "oops/symbol.hpp"
#include "memory/iterator.hpp"
#include "trace/traceMacros.hpp"
#include "jfr/support/jfrIntrinsics.hpp"
#include "jvmci/vmSymbols_jvmci.hpp"
#include "memory/iterator.hpp"
#include "oops/symbol.hpp"
#include "utilities/macros.hpp"
// The class vmSymbols is a name space for fast lookup of
// symbols commonly used in the VM.
@ -640,8 +642,8 @@
/* forEachRemaining support */ \
template(java_util_stream_StreamsRangeIntSpliterator, "java/util/stream/Streams$RangeIntSpliterator") \
\
/* trace signatures */ \
TRACE_TEMPLATES(template) \
/* jfr signatures */ \
JFR_TEMPLATES(template) \
\
/* cds */ \
template(jdk_internal_loader_ClassLoaders, "jdk/internal/loader/ClassLoaders") \
@ -827,7 +829,7 @@
do_intrinsic(_nanoTime, java_lang_System, nanoTime_name, void_long_signature, F_S) \
do_name( nanoTime_name, "nanoTime") \
\
TRACE_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias) \
JFR_INTRINSICS(do_intrinsic, do_class, do_name, do_signature, do_alias) \
\
do_intrinsic(_arraycopy, java_lang_System, arraycopy_name, arraycopy_signature, F_S) \
do_name( arraycopy_name, "arraycopy") \

View File

@ -33,6 +33,7 @@
#include "code/nmethod.hpp"
#include "code/pcDesc.hpp"
#include "compiler/compileBroker.hpp"
#include "jfr/jfrEvents.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
@ -53,7 +54,6 @@
#include "runtime/sweeper.hpp"
#include "runtime/vmThread.hpp"
#include "services/memoryService.hpp"
#include "trace/tracing.hpp"
#include "utilities/align.hpp"
#include "utilities/vmError.hpp"
#include "utilities/xmlstream.hpp"

View File

@ -35,6 +35,7 @@
#include "compiler/compilerOracle.hpp"
#include "compiler/directivesParser.hpp"
#include "interpreter/linkResolver.hpp"
#include "jfr/jfrEvents.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
@ -57,11 +58,11 @@
#include "runtime/sweeper.hpp"
#include "runtime/timerTrace.hpp"
#include "runtime/vframe.inline.hpp"
#include "trace/tracing.hpp"
#include "utilities/debug.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
#include "utilities/formatBuffer.hpp"
#include "utilities/macros.hpp"
#ifdef COMPILER1
#include "c1/c1_Compiler.hpp"
#endif
@ -1945,8 +1946,7 @@ static void codecache_print(outputStream* out, bool detailed) {
}
}
void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env) {
void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, bool success, ciEnv* ci_env) {
if (success) {
task->mark_success();
if (ci_env != NULL) {
@ -1959,19 +1959,21 @@ void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, Even
}
}
}
// simulate crash during compilation
assert(task->compile_id() != CICrashAt, "just as planned");
if (event.should_commit()) {
event.set_method(task->method());
event.set_compileId(task->compile_id());
event.set_compileLevel(task->comp_level());
event.set_succeded(task->is_success());
event.set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci);
event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
event.set_inlinedBytes(task->num_inlined_bytecodes());
event.commit();
}
}
static void post_compilation_event(EventCompilation* event, CompileTask* task) {
assert(event != NULL, "invariant");
assert(event->should_commit(), "invariant");
event->set_method(task->method());
event->set_compileId(task->compile_id());
event->set_compileLevel(task->comp_level());
event->set_succeded(task->is_success());
event->set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci);
event->set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
event->set_inlinedBytes(task->num_inlined_bytecodes());
event->commit();
}
int DirectivesStack::_depth = 0;
@ -2066,7 +2068,10 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
compilable = ciEnv::MethodCompilable_not_at_tier;
}
}
post_compile(thread, task, event, task->code() != NULL, NULL);
post_compile(thread, task, task->code() != NULL, NULL);
if (event.should_commit()) {
post_compilation_event(&event, task);
}
} else
#endif // INCLUDE_JVMCI
@ -2123,7 +2128,10 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
ci_env.report_failure(failure_reason);
}
post_compile(thread, task, event, !ci_env.failing(), &ci_env);
post_compile(thread, task, !ci_env.failing(), &ci_env);
if (event.should_commit()) {
post_compilation_event(&event, task);
}
}
// Remove the JNI handle block after the ciEnv destructor has run in
// the previous block.

View File

@ -30,7 +30,6 @@
#include "compiler/compileTask.hpp"
#include "compiler/compilerDirectives.hpp"
#include "runtime/perfData.hpp"
#include "trace/tracing.hpp"
#include "utilities/stack.hpp"
#if INCLUDE_JVMCI
#include "jvmci/jvmciCompiler.hpp"
@ -252,7 +251,7 @@ class CompileBroker: AllStatic {
#endif
static void invoke_compiler_on_method(CompileTask* task);
static void post_compile(CompilerThread* thread, CompileTask* task, EventCompilation& event, bool success, ciEnv* ci_env);
static void post_compile(CompilerThread* thread, CompileTask* task, bool success, ciEnv* ci_env);
static void set_last_compile(CompilerThread *thread, const methodHandle& method, bool is_osr, int comp_level);
static void push_jni_handle_block();
static void pop_jni_handle_block();

View File

@ -86,7 +86,6 @@ class STWGCTimer;
class G1NewTracer;
class EvacuationFailedInfo;
class nmethod;
class Ticks;
class WorkGang;
class G1Allocator;
class G1ArchiveAllocator;

View File

@ -23,12 +23,11 @@
*/
#include "precompiled.hpp"
#include "memory/allocation.inline.hpp"
#include "gc/g1/g1_globals.hpp"
#include "gc/g1/g1EvacStats.hpp"
#include "gc/shared/gcId.hpp"
#include "logging/log.hpp"
#include "trace/tracing.hpp"
#include "memory/allocation.inline.hpp"
void G1EvacStats::log_plab_allocation() {
PLABStats::log_plab_allocation();

View File

@ -34,7 +34,6 @@
#include "gc/shared/gcTraceTime.inline.hpp"
#include "gc/shared/referenceProcessor.hpp"
#include "logging/log.hpp"
#include "utilities/ticks.inline.hpp"
class G1AdjustLiveClosure : public StackObj {
G1AdjustClosure* _adjust_closure;

View File

@ -32,7 +32,7 @@
#include "gc/shared/gcTraceTime.inline.hpp"
#include "logging/log.hpp"
#include "oops/oop.inline.hpp"
#include "utilities/ticks.inline.hpp"
#include "utilities/ticks.hpp"
class G1ResetHumongousClosure : public HeapRegionClosure {
G1CMBitMap* _bitmap;

View File

@ -31,7 +31,6 @@
#include "gc/g1/g1StringDedup.hpp"
#include "gc/g1/heapRegionManager.hpp"
#include "gc/shared/referenceProcessor.hpp"
#include "utilities/ticks.hpp"
class G1CollectedHeap;
class G1CMBitMap;

View File

@ -36,7 +36,7 @@
#include "gc/shared/referenceProcessor.hpp"
#include "logging/log.hpp"
#include "oops/oop.inline.hpp"
#include "utilities/ticks.inline.hpp"
#include "utilities/ticks.hpp"
bool G1FullGCPrepareTask::G1CalculatePointersClosure::do_heap_region(HeapRegion* hr) {
if (hr->is_humongous()) {

View File

@ -32,7 +32,6 @@
#include "gc/g1/g1StringDedup.hpp"
#include "gc/g1/heapRegionManager.hpp"
#include "gc/shared/referenceProcessor.hpp"
#include "utilities/ticks.hpp"
class G1CMBitMap;

View File

@ -25,7 +25,7 @@
#include "precompiled.hpp"
#include "gc/g1/g1FullGCTask.hpp"
#include "logging/log.hpp"
#include "utilities/ticks.inline.hpp"
#include "utilities/ticks.hpp"
void G1FullGCTask::log_task(const char* name, uint worker_id, const Ticks& start, const Ticks& stop) {
Tickspan duration = stop - start;

View File

@ -488,7 +488,7 @@ G1GCParPhaseTimesTracker::G1GCParPhaseTimesTracker(G1GCPhaseTimes* phase_times,
G1GCParPhaseTimesTracker::~G1GCParPhaseTimesTracker() {
if (_phase_times != NULL) {
_phase_times->record_time_secs(_phase, _worker_id, TicksToTimeHelper::seconds(Ticks::now() - _start_time));
_phase_times->record_time_secs(_phase, _worker_id, (Ticks::now() - _start_time).seconds());
}
}
@ -506,7 +506,7 @@ G1EvacPhaseTimesTracker::~G1EvacPhaseTimesTracker() {
if (_phase_times != NULL) {
// Exclude trim time by increasing the start time.
_start_time += _trim_time;
_phase_times->record_or_add_objcopy_time_secs(_worker_id, TicksToTimeHelper::seconds(_trim_time));
_phase_times->record_or_add_objcopy_time_secs(_worker_id, _trim_time.seconds());
}
}

View 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);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -21,24 +21,15 @@
* questions.
*
*/
#ifndef SHARE_VM_TRACE_NOTRACEBACKEND_HPP
#define SHARE_VM_TRACE_NOTRACEBACKEND_HPP
#include "jni.h"
#include "trace/traceTime.hpp"
#ifndef SHARE_VM_GC_G1_G1HEAPREGIONEVENTSENDER_HPP
#define SHARE_VM_GC_G1_G1HEAPREGIONEVENTSENDER_HPP
class NoTraceBackend {
#include "memory/allocation.hpp"
class G1HeapRegionEventSender : public AllStatic {
public:
static TracingTime time() {
return 0;
}
static void send_events();
};
class TraceThreadData {
public:
TraceThreadData() {}
};
typedef NoTraceBackend Tracing;
#endif // SHARE_VM_TRACE_NOTRACEBACKEND_HPP
#endif // SHARE_VM_GC_G1_G1HEAPREGIONEVENTSENDER_HPP

View File

@ -29,7 +29,6 @@
#include "gc/g1/g1RemSet.hpp"
#include "oops/access.inline.hpp"
#include "oops/oop.inline.hpp"
#include "utilities/ticks.inline.hpp"
template <class T> void G1ParScanThreadState::do_oop_evac(T* p) {
// Reference should not be NULL here as such are never pushed to the task queue.

View File

@ -44,11 +44,12 @@
#include "memory/resourceArea.hpp"
#include "oops/access.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/os.hpp"
#include "utilities/align.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/intHisto.hpp"
#include "utilities/stack.inline.hpp"
#include "utilities/ticks.inline.hpp"
#include "utilities/ticks.hpp"
// Collects information about the overall remembered set scan progress during an evacuation.
class G1RemSetScanState : public CHeapObj<mtGC> {
@ -428,15 +429,15 @@ void G1RemSet::scan_rem_set(G1ParScanThreadState* pss, uint worker_i) {
G1GCPhaseTimes* p = _g1p->phase_times();
p->record_time_secs(G1GCPhaseTimes::ScanRS, worker_i, TicksToTimeHelper::seconds(cl.rem_set_root_scan_time()));
p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, TicksToTimeHelper::seconds(cl.rem_set_trim_partially_time()));
p->record_time_secs(G1GCPhaseTimes::ScanRS, worker_i, cl.rem_set_root_scan_time().seconds());
p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, cl.rem_set_trim_partially_time().seconds());
p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_scanned(), G1GCPhaseTimes::ScanRSScannedCards);
p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_claimed(), G1GCPhaseTimes::ScanRSClaimedCards);
p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_skipped(), G1GCPhaseTimes::ScanRSSkippedCards);
p->record_time_secs(G1GCPhaseTimes::CodeRoots, worker_i, TicksToTimeHelper::seconds(cl.strong_code_root_scan_time()));
p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, TicksToTimeHelper::seconds(cl.strong_code_root_trim_partially_time()));
p->record_time_secs(G1GCPhaseTimes::CodeRoots, worker_i, cl.strong_code_root_scan_time().seconds());
p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, cl.strong_code_root_trim_partially_time().seconds());
}
// Closure used for updating rem sets. Only called during an evacuation pause.
@ -935,7 +936,7 @@ public:
"TARS " PTR_FORMAT,
region_idx,
_cm->liveness(region_idx) * HeapWordSize,
TicksToTimeHelper::seconds(time) * 1000.0,
time.seconds() * 1000.0,
marked_bytes,
p2i(hr->bottom()),
p2i(top_at_mark_start),

View File

@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "gc/g1/heapRegionTracer.hpp"
#include "trace/tracing.hpp"
#include "jfr/jfrEvents.hpp"
void HeapRegionTracer::send_region_type_change(uint index,
G1HeapRegionTraceType::Type from,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,7 +25,7 @@
#include "precompiled.hpp"
#include "gc/shared/ageTableTracer.hpp"
#include "gc/shared/gcId.hpp"
#include "trace/tracing.hpp"
#include "jfr/jfrEvents.hpp"
void AgeTableTracer::send_tenuring_distribution_event(uint age, size_t size) {
EventTenuringDistribution e;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,13 +24,16 @@
#include "precompiled.hpp"
#include "gc/shared/allocTracer.hpp"
#include "jfr/jfrEvents.hpp"
#include "runtime/handles.hpp"
#include "trace/tracing.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_JFR
#include "jfr/support/jfrAllocationTracer.hpp"
#endif
void AllocTracer::send_allocation_outside_tlab(Klass* klass, HeapWord* obj, size_t alloc_size, Thread* thread) {
TRACE_ALLOCATION(obj, alloc_size, thread);
JFR_ONLY(JfrAllocationTracer tracer(obj, alloc_size, thread);)
EventObjectAllocationOutsideTLAB event;
if (event.should_commit()) {
event.set_objectClass(klass);
@ -40,7 +43,7 @@ void AllocTracer::send_allocation_outside_tlab(Klass* klass, HeapWord* obj, size
}
void AllocTracer::send_allocation_in_new_tlab(Klass* klass, HeapWord* obj, size_t tlab_size, size_t alloc_size, Thread* thread) {
TRACE_ALLOCATION(obj, tlab_size, thread);
JFR_ONLY(JfrAllocationTracer tracer(obj, alloc_size, thread);)
EventObjectAllocationInNewTLAB event;
if (event.should_commit()) {
event.set_objectClass(klass);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,8 +25,8 @@
#ifndef SHARE_VM_GC_SHARED_COPYFAILEDINFO_HPP
#define SHARE_VM_GC_SHARED_COPYFAILEDINFO_HPP
#include "jfr/support/jfrThreadId.hpp"
#include "runtime/thread.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/globalDefinitions.hpp"
class CopyFailedInfo : public CHeapObj<mtGC> {
@ -72,9 +72,9 @@ class PromotionFailedInfo : public CopyFailedInfo {
void register_copy_failure(size_t size) {
CopyFailedInfo::register_copy_failure(size);
if (_thread_trace_id == 0) {
_thread_trace_id = THREAD_TRACE_ID(Thread::current());
_thread_trace_id = JFR_THREAD_ID(Thread::current());
} else {
assert(THREAD_TRACE_ID(Thread::current()) == _thread_trace_id,
assert(JFR_THREAD_ID(Thread::current()) == _thread_trace_id,
"The PromotionFailedInfo should be thread local.");
}
}

View 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;
}

View 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

View File

@ -25,7 +25,6 @@
#include "precompiled.hpp"
#include "gc/shared/gcTimer.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/ticks.inline.hpp"
// the "time" parameter for most functions
// has a default value set by Ticks::now()
@ -376,7 +375,7 @@ public:
GCTimer gc_timer;
gc_timer.register_gc_start(1);
assert(gc_timer.gc_start() == 1, "Incorrect");
assert(gc_timer.gc_start() == Ticks(1), "Incorrect");
}
static void gc_end() {
@ -384,7 +383,7 @@ public:
gc_timer.register_gc_start(1);
gc_timer.register_gc_end(2);
assert(gc_timer.gc_end() == 2, "Incorrect");
assert(gc_timer.gc_end() == Ticks(2), "Incorrect");
}
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,7 +35,7 @@
#include "runtime/os.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
#include "utilities/ticks.inline.hpp"
#include "utilities/ticks.hpp"
#if INCLUDE_G1GC
#include "gc/g1/evacuationInfo.hpp"
#endif

View File

@ -28,10 +28,8 @@
#include "gc/shared/gcTimer.hpp"
#include "gc/shared/gcTrace.hpp"
#include "gc/shared/gcWhen.hpp"
#include "jfr/jfrEvents.hpp"
#include "runtime/os.hpp"
#include "trace/traceBackend.hpp"
#include "trace/tracing.hpp"
#include "tracefiles/traceEventClasses.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_G1GC
#include "gc/g1/evacuationInfo.hpp"
@ -160,8 +158,8 @@ void OldGCTracer::send_old_gc_event() const {
}
}
static TraceStructCopyFailed to_trace_struct(const CopyFailedInfo& cf_info) {
TraceStructCopyFailed failed_info;
static JfrStructCopyFailed to_struct(const CopyFailedInfo& cf_info) {
JfrStructCopyFailed failed_info;
failed_info.set_objectCount(cf_info.failed_count());
failed_info.set_firstSize(cf_info.first_size());
failed_info.set_smallestSize(cf_info.smallest_size());
@ -173,7 +171,7 @@ void YoungGCTracer::send_promotion_failed_event(const PromotionFailedInfo& pf_in
EventPromotionFailed e;
if (e.should_commit()) {
e.set_gcId(GCId::current());
e.set_promotionFailed(to_trace_struct(pf_info));
e.set_promotionFailed(to_struct(pf_info));
e.set_thread(pf_info.thread_trace_id());
e.commit();
}
@ -231,14 +229,14 @@ void G1NewTracer::send_evacuation_failed_event(const EvacuationFailedInfo& ef_in
EventEvacuationFailed e;
if (e.should_commit()) {
e.set_gcId(GCId::current());
e.set_evacuationFailed(to_trace_struct(ef_info));
e.set_evacuationFailed(to_struct(ef_info));
e.commit();
}
}
static TraceStructG1EvacuationStatistics
static JfrStructG1EvacuationStatistics
create_g1_evacstats(unsigned gcid, const G1EvacSummary& summary) {
TraceStructG1EvacuationStatistics s;
JfrStructG1EvacuationStatistics s;
s.set_gcId(gcid);
s.set_allocated(summary.allocated() * HeapWordSize);
s.set_wasted(summary.wasted() * HeapWordSize);
@ -313,8 +311,8 @@ void G1NewTracer::send_adaptive_ihop_statistics(size_t threshold,
#endif // INCLUDE_G1GC
static TraceStructVirtualSpace to_trace_struct(const VirtualSpaceSummary& summary) {
TraceStructVirtualSpace space;
static JfrStructVirtualSpace to_struct(const VirtualSpaceSummary& summary) {
JfrStructVirtualSpace space;
space.set_start((TraceAddress)summary.start());
space.set_committedEnd((TraceAddress)summary.committed_end());
space.set_committedSize(summary.committed_size());
@ -323,8 +321,8 @@ static TraceStructVirtualSpace to_trace_struct(const VirtualSpaceSummary& summar
return space;
}
static TraceStructObjectSpace to_trace_struct(const SpaceSummary& summary) {
TraceStructObjectSpace space;
static JfrStructObjectSpace to_struct(const SpaceSummary& summary) {
JfrStructObjectSpace space;
space.set_start((TraceAddress)summary.start());
space.set_end((TraceAddress)summary.end());
space.set_used(summary.used());
@ -344,7 +342,7 @@ class GCHeapSummaryEventSender : public GCHeapSummaryVisitor {
if (e.should_commit()) {
e.set_gcId(GCId::current());
e.set_when((u1)_when);
e.set_heapSpace(to_trace_struct(heap_space));
e.set_heapSpace(to_struct(heap_space));
e.set_heapUsed(heap_summary->used());
e.commit();
}
@ -380,12 +378,12 @@ class GCHeapSummaryEventSender : public GCHeapSummaryVisitor {
e.set_gcId(GCId::current());
e.set_when((u1)_when);
e.set_oldSpace(to_trace_struct(ps_heap_summary->old()));
e.set_oldObjectSpace(to_trace_struct(ps_heap_summary->old_space()));
e.set_youngSpace(to_trace_struct(ps_heap_summary->young()));
e.set_edenSpace(to_trace_struct(ps_heap_summary->eden()));
e.set_fromSpace(to_trace_struct(ps_heap_summary->from()));
e.set_toSpace(to_trace_struct(ps_heap_summary->to()));
e.set_oldSpace(to_struct(ps_heap_summary->old()));
e.set_oldObjectSpace(to_struct(ps_heap_summary->old_space()));
e.set_youngSpace(to_struct(ps_heap_summary->young()));
e.set_edenSpace(to_struct(ps_heap_summary->eden()));
e.set_fromSpace(to_struct(ps_heap_summary->from()));
e.set_toSpace(to_struct(ps_heap_summary->to()));
e.commit();
}
}
@ -396,8 +394,8 @@ void GCTracer::send_gc_heap_summary_event(GCWhen::Type when, const GCHeapSummary
heap_summary.accept(&visitor);
}
static TraceStructMetaspaceSizes to_trace_struct(const MetaspaceSizes& sizes) {
TraceStructMetaspaceSizes meta_sizes;
static JfrStructMetaspaceSizes to_struct(const MetaspaceSizes& sizes) {
JfrStructMetaspaceSizes meta_sizes;
meta_sizes.set_committed(sizes.committed());
meta_sizes.set_used(sizes.used());
@ -412,9 +410,9 @@ void GCTracer::send_meta_space_summary_event(GCWhen::Type when, const MetaspaceS
e.set_gcId(GCId::current());
e.set_when((u1) when);
e.set_gcThreshold(meta_space_summary.capacity_until_GC());
e.set_metaspace(to_trace_struct(meta_space_summary.meta_space()));
e.set_dataSpace(to_trace_struct(meta_space_summary.data_space()));
e.set_classSpace(to_trace_struct(meta_space_summary.class_space()));
e.set_metaspace(to_struct(meta_space_summary.meta_space()));
e.set_dataSpace(to_struct(meta_space_summary.data_space()));
e.set_classSpace(to_struct(meta_space_summary.class_space()));
e.commit();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,34 +26,50 @@
#include "precompiled.hpp"
#include "gc/shared/gcId.hpp"
#include "gc/shared/objectCountEventSender.hpp"
#include "jfr/jfrEvents.hpp"
#include "memory/heapInspection.hpp"
#include "trace/tracing.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
#include "utilities/ticks.hpp"
#if INCLUDE_SERVICES
void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& timestamp) {
#if INCLUDE_TRACE
assert(Tracing::is_event_enabled(EventObjectCountAfterGC::eventId),
"Only call this method if the event is enabled");
EventObjectCountAfterGC event(UNTIMED);
event.set_gcId(GCId::current());
event.set_objectClass(entry->klass());
event.set_count(entry->count());
event.set_totalSize(entry->words() * BytesPerWord);
event.set_endtime(timestamp);
event.commit();
#endif // INCLUDE_TRACE
}
bool ObjectCountEventSender::should_send_event() {
#if INCLUDE_TRACE
return Tracing::is_event_enabled(EventObjectCountAfterGC::eventId);
#if INCLUDE_JFR
return _should_send_requestable_event || EventObjectCountAfterGC::is_enabled();
#else
return false;
#endif // INCLUDE_TRACE
#endif // INCLUDE_JFR
}
bool ObjectCountEventSender::_should_send_requestable_event = false;
void ObjectCountEventSender::enable_requestable_event() {
_should_send_requestable_event = true;
}
void ObjectCountEventSender::disable_requestable_event() {
_should_send_requestable_event = false;
}
template <typename T>
void ObjectCountEventSender::send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp) {
T event(UNTIMED);
if (event.should_commit()) {
event.set_gcId(GCId::current());
event.set_objectClass(klass);
event.set_count(count);
event.set_totalSize(size);
event.set_endtime(timestamp);
event.commit();
}
}
void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& timestamp) {
Klass* klass = entry->klass();
jlong count = entry->count();
julong total_size = entry->words() * BytesPerWord;
send_event_if_enabled<EventObjectCount>(klass, count, total_size, timestamp);
send_event_if_enabled<EventObjectCountAfterGC>(klass, count, total_size, timestamp);
}
#endif // INCLUDE_SERVICES

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,15 +27,25 @@
#include "gc/shared/gcTrace.hpp"
#include "memory/allocation.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
#include "utilities/ticks.hpp"
#if INCLUDE_SERVICES
class KlassInfoEntry;
class Ticks;
class Klass;
class ObjectCountEventSender : public AllStatic {
static bool _should_send_requestable_event;
template <typename T>
static void send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp);
public:
static void enable_requestable_event();
static void disable_requestable_event();
static void send(const KlassInfoEntry* entry, const Ticks& timestamp);
static bool should_send_event();
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,13 +26,15 @@
#include "gc/shared/weakProcessor.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/jniHandles.hpp"
#include "trace/tracing.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_JFR
#include "jfr/jfr.hpp"
#endif
void WeakProcessor::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive) {
JNIHandles::weak_oops_do(is_alive, keep_alive);
JvmtiExport::weak_oops_do(is_alive, keep_alive);
TRACE_WEAK_OOPS_DO(is_alive, keep_alive);
JFR_ONLY(Jfr::weak_oops_do(is_alive, keep_alive);)
}
void WeakProcessor::oops_do(OopClosure* closure) {

View 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;
}

View 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

File diff suppressed because it is too large Load Diff

View File

@ -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

View 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;
}
}

View 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

View 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();
}

View 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

View 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

View 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);
}

View 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

View 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);
}

View 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

View 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;
}

View 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

View 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

View 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

View 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);
}
}

View 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

View 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;
}

View 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

View 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);
}
}

View 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