--- a/hotspot/make/aix/adlc_updater Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/make/aix/adlc_updater Sat Mar 19 01:23:46 2016 +0100
@@ -9,12 +9,15 @@
#
fix_lines() {
# repair bare #line directives in $1 to refer to $2
- awk < $1 > $1+ '
+ # and add an override of __FILE__ with just the basename on the
+ # first line of the file.
+ awk < $1 > $1+ -v F2=$2 '
+ BEGIN { print "#line 1 \"" F2 "\""; }
/^#line 999999$/ {print "#line " (NR+1) " \"" F2 "\""; next}
{print}
- ' F2=$2
+ '
mv $1+ $1
}
-fix_lines $2/$1 $3/$1
+fix_lines $2/$1 $1
[ -f $3/$1 ] && cmp -s $2/$1 $3/$1 || \
( [ -f $3/$1 ] && echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 )
--- a/hotspot/make/aix/makefiles/trace.make Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/make/aix/makefiles/trace.make Sat Mar 19 01:23:46 2016 +0100
@@ -27,14 +27,17 @@
#
# It knows how to build and run the tools to generate trace files.
-include $(GAMMADIR)/make/linux/makefiles/rules.make
+include $(GAMMADIR)/make/aix/makefiles/rules.make
include $(GAMMADIR)/make/altsrc.make
# #########################################################################
-HAS_ALT_SRC:=$(shell if [ -d $(HS_ALT_SRC)/share/vm/trace ]; then \
- echo "true"; else echo "false";\
- fi)
+HAS_ALT_SRC := false
+ifndef OPENJDK
+ ifneq ($(wildcard $(HS_ALT_SRC)/share/vm/trace), )
+ HAS_ALT_SRC := true
+ endif
+endif
TOPDIR = $(shell echo `pwd`)
GENERATED = $(TOPDIR)/../generated
@@ -50,23 +53,30 @@
TraceGeneratedNames = \
traceEventClasses.hpp \
- traceEventIds.hpp \
- traceTypes.hpp
+ traceEventIds.hpp \
+ traceTypes.hpp
ifeq ($(HAS_ALT_SRC), true)
-TraceGeneratedNames += \
- traceRequestables.hpp \
- traceEventControl.hpp
+ TraceGeneratedNames += \
+ traceRequestables.hpp \
+ traceEventControl.hpp
endif
TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%)
XSLT = $(REMOTE) $(RUN.JAVA) -classpath $(JvmtiOutDir) jvmtiGen
-XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \
- $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod
+TraceXml = $(TraceSrcDir)/trace.xml
ifeq ($(HAS_ALT_SRC), true)
- XML_DEPS += $(TraceAltSrcDir)/traceevents.xml
+ TraceXml = $(TraceAltSrcDir)/trace.xml
+endif
+
+XML_DEPS = $(TraceXml) $(TraceSrcDir)/tracetypes.xml \
+ $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod \
+ $(TraceSrcDir)/tracerelationdecls.xml $(TraceSrcDir)/traceevents.xml
+ifeq ($(HAS_ALT_SRC), true)
+ XML_DEPS += $(TraceAltSrcDir)/traceeventscustom.xml \
+ $(TraceAltSrcDir)/traceeventtypes.xml
endif
.PHONY: all clean cleanall
@@ -79,26 +89,26 @@
$(QUIETLY) echo $(LOG_INFO) Generating $@; \
$(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@
-$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventIds.hpp: $(TraceXml) $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
$(GENERATE_CODE)
-$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS)
+$(TraceOutDir)/traceTypes.hpp: $(TraceXml) $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS)
$(GENERATE_CODE)
ifeq ($(HAS_ALT_SRC), false)
-$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS)
$(GENERATE_CODE)
else
-$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS)
$(GENERATE_CODE)
-$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS)
+$(TraceOutDir)/traceRequestables.hpp: $(TraceXml) $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS)
$(GENERATE_CODE)
-$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventControl.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS)
$(GENERATE_CODE)
endif
--- a/hotspot/make/bsd/adlc_updater Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/make/bsd/adlc_updater Sat Mar 19 01:23:46 2016 +0100
@@ -9,12 +9,15 @@
#
fix_lines() {
# repair bare #line directives in $1 to refer to $2
- awk < $1 > $1+ '
+ # and add an override of __FILE__ with just the basename on the
+ # first line of the file.
+ awk < $1 > $1+ -v F2=$2 '
+ BEGIN { print "#line 1 \"" F2 "\""; }
/^#line 999999$/ {print "#line " (NR+1) " \"" F2 "\""; next}
{print}
- ' F2=$2
+ '
mv $1+ $1
}
-fix_lines $2/$1 $3/$1
+fix_lines $2/$1 $1
[ -f $3/$1 ] && cmp -s $2/$1 $3/$1 || \
( [ -f $3/$1 ] && echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 )
--- a/hotspot/make/bsd/makefiles/trace.make Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/make/bsd/makefiles/trace.make Sat Mar 19 01:23:46 2016 +0100
@@ -32,9 +32,12 @@
# #########################################################################
-HAS_ALT_SRC:=$(shell if [ -d $(HS_ALT_SRC)/share/vm/trace ]; then \
- echo "true"; else echo "false";\
- fi)
+HAS_ALT_SRC := false
+ifndef OPENJDK
+ ifneq ($(wildcard $(HS_ALT_SRC)/share/vm/trace), )
+ HAS_ALT_SRC := true
+ endif
+endif
TOPDIR = $(shell echo `pwd`)
GENERATED = $(TOPDIR)/../generated
@@ -50,24 +53,30 @@
TraceGeneratedNames = \
traceEventClasses.hpp \
- traceEventIds.hpp \
- traceTypes.hpp
+ traceEventIds.hpp \
+ traceTypes.hpp
ifeq ($(HAS_ALT_SRC), true)
-TraceGeneratedNames += \
- traceRequestables.hpp \
- traceEventControl.hpp
+ TraceGeneratedNames += \
+ traceRequestables.hpp \
+ traceEventControl.hpp
endif
-
TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%)
XSLT = $(REMOTE) $(RUN.JAVA) -classpath $(JvmtiOutDir) jvmtiGen
-XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \
- $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod
+TraceXml = $(TraceSrcDir)/trace.xml
ifeq ($(HAS_ALT_SRC), true)
- XML_DEPS += $(TraceAltSrcDir)/traceevents.xml
+ TraceXml = $(TraceAltSrcDir)/trace.xml
+endif
+
+XML_DEPS = $(TraceXml) $(TraceSrcDir)/tracetypes.xml \
+ $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod \
+ $(TraceSrcDir)/tracerelationdecls.xml $(TraceSrcDir)/traceevents.xml
+ifeq ($(HAS_ALT_SRC), true)
+ XML_DEPS += $(TraceAltSrcDir)/traceeventscustom.xml \
+ $(TraceAltSrcDir)/traceeventtypes.xml
endif
.PHONY: all clean cleanall
@@ -80,32 +89,31 @@
$(QUIETLY) echo $(LOG_INFO) Generating $@; \
$(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@
-$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventIds.hpp: $(TraceXml) $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
$(GENERATE_CODE)
-$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS)
+$(TraceOutDir)/traceTypes.hpp: $(TraceXml) $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS)
$(GENERATE_CODE)
ifeq ($(HAS_ALT_SRC), false)
-$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS)
$(GENERATE_CODE)
else
-$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS)
$(GENERATE_CODE)
-$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS)
+$(TraceOutDir)/traceRequestables.hpp: $(TraceXml) $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS)
$(GENERATE_CODE)
-$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventControl.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS)
$(GENERATE_CODE)
endif
# #########################################################################
-
clean cleanall:
rm $(TraceGeneratedFiles)
--- a/hotspot/make/linux/adlc_updater Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/make/linux/adlc_updater Sat Mar 19 01:23:46 2016 +0100
@@ -9,12 +9,15 @@
#
fix_lines() {
# repair bare #line directives in $1 to refer to $2
- awk < $1 > $1+ '
+ # and add an override of __FILE__ with just the basename on the
+ # first line of the file.
+ awk < $1 > $1+ -v F2=$2 '
+ BEGIN { print "#line 1 \"" F2 "\""; }
/^#line 999999$/ {print "#line " (NR+1) " \"" F2 "\""; next}
{print}
- ' F2=$2
+ '
mv $1+ $1
}
-fix_lines $2/$1 $3/$1
+fix_lines $2/$1 $1
[ -f $3/$1 ] && cmp -s $2/$1 $3/$1 || \
( [ -f $3/$1 ] && echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 )
--- a/hotspot/make/linux/makefiles/trace.make Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/make/linux/makefiles/trace.make Sat Mar 19 01:23:46 2016 +0100
@@ -32,9 +32,12 @@
# #########################################################################
-HAS_ALT_SRC:=$(shell if [ -d $(HS_ALT_SRC)/share/vm/trace ]; then \
- echo "true"; else echo "false";\
- fi)
+HAS_ALT_SRC := false
+ifndef OPENJDK
+ ifneq ($(wildcard $(HS_ALT_SRC)/share/vm/trace), )
+ HAS_ALT_SRC := true
+ endif
+endif
TOPDIR = $(shell echo `pwd`)
GENERATED = $(TOPDIR)/../generated
@@ -50,23 +53,30 @@
TraceGeneratedNames = \
traceEventClasses.hpp \
- traceEventIds.hpp \
- traceTypes.hpp
+ traceEventIds.hpp \
+ traceTypes.hpp
ifeq ($(HAS_ALT_SRC), true)
-TraceGeneratedNames += \
- traceRequestables.hpp \
- traceEventControl.hpp
+ TraceGeneratedNames += \
+ traceRequestables.hpp \
+ traceEventControl.hpp
endif
TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%)
XSLT = $(REMOTE) $(RUN.JAVA) -classpath $(JvmtiOutDir) jvmtiGen
-XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \
- $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod
+TraceXml = $(TraceSrcDir)/trace.xml
ifeq ($(HAS_ALT_SRC), true)
- XML_DEPS += $(TraceAltSrcDir)/traceevents.xml
+ TraceXml = $(TraceAltSrcDir)/trace.xml
+endif
+
+XML_DEPS = $(TraceXml) $(TraceSrcDir)/tracetypes.xml \
+ $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod \
+ $(TraceSrcDir)/tracerelationdecls.xml $(TraceSrcDir)/traceevents.xml
+ifeq ($(HAS_ALT_SRC), true)
+ XML_DEPS += $(TraceAltSrcDir)/traceeventscustom.xml \
+ $(TraceAltSrcDir)/traceeventtypes.xml
endif
.PHONY: all clean cleanall
@@ -79,26 +89,26 @@
$(QUIETLY) echo $(LOG_INFO) Generating $@; \
$(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@
-$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventIds.hpp: $(TraceXml) $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
$(GENERATE_CODE)
-$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS)
+$(TraceOutDir)/traceTypes.hpp: $(TraceXml) $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS)
$(GENERATE_CODE)
ifeq ($(HAS_ALT_SRC), false)
-$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS)
$(GENERATE_CODE)
else
-$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS)
$(GENERATE_CODE)
-$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS)
+$(TraceOutDir)/traceRequestables.hpp: $(TraceXml) $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS)
$(GENERATE_CODE)
-$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventControl.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS)
$(GENERATE_CODE)
endif
@@ -107,5 +117,3 @@
clean cleanall:
rm $(TraceGeneratedFiles)
-
-
--- a/hotspot/make/share/makefiles/mapfile-vers Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/make/share/makefiles/mapfile-vers Sat Mar 19 01:23:46 2016 +0100
@@ -109,8 +109,7 @@
JVM_GetPrimitiveArrayElement;
JVM_GetProtectionDomain;
JVM_GetStackAccessControlContext;
- JVM_GetStackTraceDepth;
- JVM_GetStackTraceElement;
+ JVM_GetStackTraceElements;
JVM_GetSystemPackage;
JVM_GetSystemPackages;
JVM_GetTemporaryDirectory;
--- a/hotspot/make/solaris/adlc_updater Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/make/solaris/adlc_updater Sat Mar 19 01:23:46 2016 +0100
@@ -9,12 +9,15 @@
#
fix_lines() {
# repair bare #line directives in $1 to refer to $2
- awk < $1 > $1+ '
+ # and add an override of __FILE__ with just the basename on the
+ # first line of the file.
+ nawk < $1 > $1+ -v F2=$2 '
+ BEGIN { print "#line 1 \"" F2 "\""; }
/^#line 999999$/ {print "#line " (NR+1) " \"" F2 "\""; next}
{print}
- ' F2=$2
+ '
mv $1+ $1
}
-fix_lines $2/$1 $3/$1
+fix_lines $2/$1 $1
[ -f $3/$1 ] && cmp -s $2/$1 $3/$1 || \
( [ -f $3/$1 ] && echo Updating $3/$1 ; touch $2/made-change ; mv $2/$1 $3/$1 )
--- a/hotspot/make/solaris/makefiles/trace.make Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/make/solaris/makefiles/trace.make Sat Mar 19 01:23:46 2016 +0100
@@ -32,9 +32,12 @@
# #########################################################################
-HAS_ALT_SRC:=$(shell if [ -d $(HS_ALT_SRC)/share/vm/trace ]; then \
- echo "true"; else echo "false";\
- fi)
+HAS_ALT_SRC := false
+ifndef OPENJDK
+ ifneq ($(wildcard $(HS_ALT_SRC)/share/vm/trace), )
+ HAS_ALT_SRC := true
+ endif
+endif
TOPDIR = $(shell echo `pwd`)
GENERATED = $(TOPDIR)/../generated
@@ -50,23 +53,30 @@
TraceGeneratedNames = \
traceEventClasses.hpp \
- traceEventIds.hpp \
- traceTypes.hpp
+ traceEventIds.hpp \
+ traceTypes.hpp
ifeq ($(HAS_ALT_SRC), true)
-TraceGeneratedNames += \
- traceRequestables.hpp \
- traceEventControl.hpp
+ TraceGeneratedNames += \
+ traceRequestables.hpp \
+ traceEventControl.hpp
endif
TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%)
XSLT = $(REMOTE) $(RUN.JAVA) -classpath $(JvmtiOutDir) jvmtiGen
-XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \
- $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod
+TraceXml = $(TraceSrcDir)/trace.xml
ifeq ($(HAS_ALT_SRC), true)
- XML_DEPS += $(TraceAltSrcDir)/traceevents.xml
+ TraceXml = $(TraceAltSrcDir)/trace.xml
+endif
+
+XML_DEPS = $(TraceXml) $(TraceSrcDir)/tracetypes.xml \
+ $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod \
+ $(TraceSrcDir)/tracerelationdecls.xml $(TraceSrcDir)/traceevents.xml
+ifeq ($(HAS_ALT_SRC), true)
+ XML_DEPS += $(TraceAltSrcDir)/traceeventscustom.xml \
+ $(TraceAltSrcDir)/traceeventtypes.xml
endif
.PHONY: all clean cleanall
@@ -79,26 +89,26 @@
$(QUIETLY) echo $(LOG_INFO) Generating $@; \
$(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@
-$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventIds.hpp: $(TraceXml) $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
$(GENERATE_CODE)
-$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS)
+$(TraceOutDir)/traceTypes.hpp: $(TraceXml) $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS)
$(GENERATE_CODE)
ifeq ($(HAS_ALT_SRC), false)
-$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS)
$(GENERATE_CODE)
else
-$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS)
$(GENERATE_CODE)
-$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS)
+$(TraceOutDir)/traceRequestables.hpp: $(TraceXml) $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS)
$(GENERATE_CODE)
-$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventControl.hpp: $(TraceXml) $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS)
$(GENERATE_CODE)
endif
--- a/hotspot/make/windows/build.make Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/make/windows/build.make Sat Mar 19 01:23:46 2016 +0100
@@ -114,11 +114,15 @@
# Define HOTSPOT_VM_DISTRO based on settings in make/openjdk_distro
# or make/hotspot_distro.
!ifndef HOTSPOT_VM_DISTRO
+!ifndef OPENJDK
!if exists($(WorkSpace)\src\closed)
!include $(WorkSpace)\make\hotspot_distro
!else
!include $(WorkSpace)\make\openjdk_distro
!endif
+!else
+!include $(WorkSpace)\make\openjdk_distro
+!endif
!endif
HS_FILEDESC=$(HOTSPOT_VM_DISTRO) $(ARCH_TEXT) $(VARIANT_TEXT) VM
--- a/hotspot/make/windows/create_obj_files.sh Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/make/windows/create_obj_files.sh Sat Mar 19 01:23:46 2016 +0100
@@ -55,7 +55,11 @@
ALTSRC_REL=src/closed # Change this to pick up alt sources from somewhere else
COMMONSRC=${WorkSpace}/${COMMONSRC_REL}
-ALTSRC=${WorkSpace}/${ALTSRC_REL}
+if [ "x$OPENJDK" != "xtrue" ]; then
+ ALTSRC=${WorkSpace}/${ALTSRC_REL}
+else
+ ALTSRC=PATH_THAT_DOES_NOT_EXIST
+fi
BASE_PATHS="`if [ -d ${ALTSRC}/share/vm ]; then $FIND ${ALTSRC}/share/vm ! -name vm -prune -type d \! \( -name adlc -o -name c1 -o -name gc -o -name opto -o -name shark -o -name libadt \); fi`"
BASE_PATHS="${BASE_PATHS} ` $FIND ${COMMONSRC}/share/vm ! -name vm -prune -type d \! \( -name adlc -o -name c1 -o -name gc -o -name opto -o -name shark -o -name libadt \)`"
@@ -158,6 +162,6 @@
fi
Obj_Files="${Obj_Files}$o "
done
-Obj_Files=`echo ${Obj_Files} | tr ' ' '\n' | sort`
+Obj_Files=`echo ${Obj_Files} | tr ' ' '\n' | LC_ALL=C sort`
echo Obj_Files=${Obj_Files}
--- a/hotspot/make/windows/makefiles/defs.make Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/make/windows/makefiles/defs.make Sat Mar 19 01:23:46 2016 +0100
@@ -276,3 +276,7 @@
MAKE_ARGS += MT="$(subst /,\\,$(MT))"
endif
endif
+
+ifdef OPENJDK
+ MAKE_ARGS += OPENJDK="$(OPENJDK)"
+endif
--- a/hotspot/make/windows/makefiles/trace.make Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/make/windows/makefiles/trace.make Sat Mar 19 01:23:46 2016 +0100
@@ -32,15 +32,21 @@
# #########################################################################
-TraceAltSrcDir = $(WorkSpace)/src/closed/share/vm/trace
-TraceSrcDir = $(WorkSpace)/src/share/vm/trace
+TraceAltSrcDir = $(WorkSpace)\src\closed\share\vm\trace
+TraceSrcDir = $(WorkSpace)\src\share\vm\trace
+
+!ifndef OPENJDK
+!if EXISTS($(TraceAltSrcDir))
+HAS_ALT_SRC = true
+!endif
+!endif
TraceGeneratedNames = \
traceEventClasses.hpp \
traceEventIds.hpp \
traceTypes.hpp
-!if EXISTS($(TraceAltSrcDir))
+!ifdef HAS_ALT_SRC
TraceGeneratedNames = $(TraceGeneratedNames) \
traceRequestables.hpp \
traceEventControl.hpp
@@ -51,22 +57,30 @@
#Should be equivalent to "TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%)"
TraceGeneratedFiles = \
$(TraceOutDir)/traceEventClasses.hpp \
- $(TraceOutDir)/traceEventIds.hpp \
- $(TraceOutDir)/traceTypes.hpp
+ $(TraceOutDir)/traceEventIds.hpp \
+ $(TraceOutDir)/traceTypes.hpp
-!if EXISTS($(TraceAltSrcDir))
+!ifdef HAS_ALT_SRC
TraceGeneratedFiles = $(TraceGeneratedFiles) \
- $(TraceOutDir)/traceRequestables.hpp \
+ $(TraceOutDir)/traceRequestables.hpp \
$(TraceOutDir)/traceEventControl.hpp
!endif
XSLT = $(QUIETLY) $(REMOTE) $(RUN_JAVA) -classpath $(JvmtiOutDir) jvmtiGen
-XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \
- $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod
+TraceXml = $(TraceSrcDir)/trace.xml
+
+!ifdef HAS_ALT_SRC
+TraceXml = $(TraceAltSrcDir)/trace.xml
+!endif
-!if EXISTS($(TraceAltSrcDir))
-XML_DEPS = $(XML_DEPS) $(TraceAltSrcDir)/traceevents.xml
+XML_DEPS = $(TraceXml) $(TraceSrcDir)/tracetypes.xml \
+ $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod \
+ $(TraceSrcDir)/tracerelationdecls.xml $(TraceSrcDir)/traceevents.xml
+
+!ifdef HAS_ALT_SRC
+XML_DEPS = $(XML_DEPS) $(TraceAltSrcDir)/traceeventscustom.xml \
+ $(TraceAltSrcDir)/traceeventtypes.xml
!endif
.PHONY: all clean cleanall
@@ -76,33 +90,33 @@
default::
@if not exist $(TraceOutDir) mkdir $(TraceOutDir)
-$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
@echo Generating $@
- @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceSrcDir)/traceEventIds.xsl -OUT $(TraceOutDir)/traceEventIds.hpp
+ $(XSLT) -IN $(TraceXml) -XSL $(TraceSrcDir)/traceEventIds.xsl -OUT $(TraceOutDir)/traceEventIds.hpp
-$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS)
+$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS)
@echo Generating $@
- @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceSrcDir)/traceTypes.xsl -OUT $(TraceOutDir)/traceTypes.hpp
+ $(XSLT) -IN $(TraceXml) -XSL $(TraceSrcDir)/traceTypes.xsl -OUT $(TraceOutDir)/traceTypes.hpp
-!if !EXISTS($(TraceAltSrcDir))
+!ifndef HAS_ALT_SRC
-$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS)
@echo Generating OpenJDK $@
- @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceSrcDir)/traceEventClasses.xsl -OUT $(TraceOutDir)/traceEventClasses.hpp
+ $(XSLT) -IN $(TraceXml) -XSL $(TraceSrcDir)/traceEventClasses.xsl -OUT $(TraceOutDir)/traceEventClasses.hpp
!else
-$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS)
@echo Generating AltSrc $@
- @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceEventClasses.xsl -OUT $(TraceOutDir)/traceEventClasses.hpp
+ $(XSLT) -IN $(TraceXml) -XSL $(TraceAltSrcDir)/traceEventClasses.xsl -OUT $(TraceOutDir)/traceEventClasses.hpp
-$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS)
+$(TraceOutDir)/traceRequestables.hpp: $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS)
@echo Generating AltSrc $@
- @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceRequestables.xsl -OUT $(TraceOutDir)/traceRequestables.hpp
+ $(XSLT) -IN $(TraceXml) -XSL $(TraceAltSrcDir)/traceRequestables.xsl -OUT $(TraceOutDir)/traceRequestables.hpp
-$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS)
+$(TraceOutDir)/traceEventControl.hpp: $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS)
@echo Generating AltSrc $@
- @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceEventControl.xsl -OUT $(TraceOutDir)/traceEventControl.hpp
+ $(XSLT) -IN $(TraceXml) -XSL $(TraceAltSrcDir)/traceEventControl.xsl -OUT $(TraceOutDir)/traceEventControl.hpp
!endif
@@ -110,5 +124,3 @@
cleanall :
rm $(TraceGeneratedFiles)
-
-
--- a/hotspot/make/windows/makefiles/vm.make Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/make/windows/makefiles/vm.make Sat Mar 19 01:23:46 2016 +0100
@@ -118,6 +118,7 @@
CXX_INCLUDE_DIRS=/I "..\generated"
+!ifndef OPENJDK
!if exists($(ALTSRC)\share\vm)
CXX_INCLUDE_DIRS=$(CXX_INCLUDE_DIRS) /I "$(ALTSRC)\share\vm"
!endif
@@ -133,6 +134,7 @@
!if exists($(ALTSRC)\cpu\$(Platform_arch)\vm)
CXX_INCLUDE_DIRS=$(CXX_INCLUDE_DIRS) /I "$(ALTSRC)\cpu\$(Platform_arch)\vm"
!endif
+!endif # OPENJDK
CXX_INCLUDE_DIRS=$(CXX_INCLUDE_DIRS) \
/I "$(COMMONSRC)\share\vm" \
@@ -187,10 +189,12 @@
VM_PATH=$(VM_PATH);$(WorkSpace)/src/cpu/$(Platform_arch)/vm
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/opto
+!ifndef OPENJDK
!if exists($(ALTSRC)\share\vm\jfr)
VM_PATH=$(VM_PATH);$(ALTSRC)/share/vm/jfr
VM_PATH=$(VM_PATH);$(ALTSRC)/share/vm/jfr/buffers
!endif
+!endif # OPENJDK
VM_PATH={$(VM_PATH)}
@@ -310,6 +314,7 @@
{$(COMMONSRC)\os_cpu\windows_$(Platform_arch)\vm}.cpp.obj::
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
+!ifndef OPENJDK
{$(ALTSRC)\share\vm\c1}.cpp.obj::
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
@@ -392,6 +397,13 @@
{$(ALTSRC)\os_cpu\windows_$(Platform_arch)\vm}.cpp.obj::
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
+{$(ALTSRC)\share\vm\jfr}.cpp.obj::
+ $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
+
+{$(ALTSRC)\share\vm\jfr\buffers}.cpp.obj::
+ $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
+!endif
+
{..\generated\incls}.cpp.obj::
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
@@ -404,12 +416,6 @@
{..\generated\tracefiles}.cpp.obj::
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
-{$(ALTSRC)\share\vm\jfr}.cpp.obj::
- $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
-
-{$(ALTSRC)\share\vm\jfr\buffers}.cpp.obj::
- $(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
-
default::
_build_pch_file.obj:
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetopt.java Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SAGetopt.java Sat Mar 19 01:23:46 2016 +0100
@@ -84,7 +84,11 @@
}
else {
// Mixed style options --file name
- extractOptarg(ca[0]);
+ try {
+ extractOptarg(ca[0]);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new RuntimeException("Argument is expected for '" + ca[0] + "'");
+ }
}
return ca[0];
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java Sat Mar 19 01:23:46 2016 +0100
@@ -30,6 +30,7 @@
import sun.jvm.hotspot.tools.JStack;
import sun.jvm.hotspot.tools.JMap;
import sun.jvm.hotspot.tools.JInfo;
+import sun.jvm.hotspot.tools.JSnap;
public class SALauncher {
@@ -39,6 +40,7 @@
System.out.println(" jstack --help\tto get more information");
System.out.println(" jmap --help\tto get more information");
System.out.println(" jinfo --help\tto get more information");
+ System.out.println(" jsnap --help\tto get more information");
return false;
}
@@ -85,6 +87,11 @@
return commonHelp();
}
+ private static boolean jsnapHelp() {
+ System.out.println(" <no option>\tdump performance counters");
+ return commonHelp();
+ }
+
private static boolean toolHelp(String toolName) {
if (toolName.equals("jstack")) {
return jstackHelp();
@@ -95,24 +102,62 @@
if (toolName.equals("jmap")) {
return jmapHelp();
}
+ if (toolName.equals("jsnap")) {
+ return jsnapHelp();
+ }
if (toolName.equals("hsdb") || toolName.equals("clhsdb")) {
return commonHelp();
}
return launcherHelp();
}
+ private static void buildAttachArgs(ArrayList<String> newArgs,
+ String pid, String exe, String core) {
+ if ((pid == null) && (exe == null)) {
+ throw new IllegalArgumentException(
+ "You have to set --pid or --exe.");
+ }
+
+ if (pid != null) { // Attach to live process
+ if (exe != null) {
+ throw new IllegalArgumentException(
+ "Unnecessary argument: --exe");
+ } else if (core != null) {
+ throw new IllegalArgumentException(
+ "Unnecessary argument: --core");
+ } else if (!pid.matches("^\\d+$")) {
+ throw new IllegalArgumentException("Invalid pid: " + pid);
+ }
+
+ newArgs.add(pid);
+ } else {
+ if (exe.length() == 0) {
+ throw new IllegalArgumentException("You have to set --exe.");
+ }
+
+ newArgs.add(exe);
+
+ if ((core == null) || (core.length() == 0)) {
+ throw new IllegalArgumentException("You have to set --core.");
+ }
+
+ newArgs.add(core);
+ }
+ }
+
private static void runCLHSDB(String[] oldArgs) {
SAGetopt sg = new SAGetopt(oldArgs);
String[] longOpts = {"exe=", "core=", "pid="};
ArrayList<String> newArgs = new ArrayList();
- String exeORpid = null;
+ String pid = null;
+ String exe = null;
String core = null;
String s = null;
while((s = sg.next(null, longOpts)) != null) {
if (s.equals("exe")) {
- exeORpid = sg.getOptarg();
+ exe = sg.getOptarg();
continue;
}
if (s.equals("core")) {
@@ -120,17 +165,12 @@
continue;
}
if (s.equals("pid")) {
- exeORpid = sg.getOptarg();
+ pid = sg.getOptarg();
continue;
}
}
- if (exeORpid != null) {
- newArgs.add(exeORpid);
- if (core != null) {
- newArgs.add(core);
- }
- }
+ buildAttachArgs(newArgs, pid, exe, core);
CLHSDB.main(newArgs.toArray(new String[newArgs.size()]));
}
@@ -139,13 +179,14 @@
String[] longOpts = {"exe=", "core=", "pid="};
ArrayList<String> newArgs = new ArrayList();
- String exeORpid = null;
+ String pid = null;
+ String exe = null;
String core = null;
String s = null;
while((s = sg.next(null, longOpts)) != null) {
if (s.equals("exe")) {
- exeORpid = sg.getOptarg();
+ exe = sg.getOptarg();
continue;
}
if (s.equals("core")) {
@@ -153,17 +194,12 @@
continue;
}
if (s.equals("pid")) {
- exeORpid = sg.getOptarg();
+ pid = sg.getOptarg();
continue;
}
}
- if (exeORpid != null) {
- newArgs.add(exeORpid);
- if (core != null) {
- newArgs.add(core);
- }
- }
+ buildAttachArgs(newArgs, pid, exe, core);
HSDB.main(newArgs.toArray(new String[newArgs.size()]));
}
@@ -173,13 +209,14 @@
"mixed", "locks"};
ArrayList<String> newArgs = new ArrayList();
- String exeORpid = null;
+ String pid = null;
+ String exe = null;
String core = null;
String s = null;
while((s = sg.next(null, longOpts)) != null) {
if (s.equals("exe")) {
- exeORpid = sg.getOptarg();
+ exe = sg.getOptarg();
continue;
}
if (s.equals("core")) {
@@ -187,7 +224,7 @@
continue;
}
if (s.equals("pid")) {
- exeORpid = sg.getOptarg();
+ pid = sg.getOptarg();
continue;
}
if (s.equals("mixed")) {
@@ -200,13 +237,7 @@
}
}
- if (exeORpid != null) {
- newArgs.add(exeORpid);
- if (core != null) {
- newArgs.add(core);
- }
- }
-
+ buildAttachArgs(newArgs, pid, exe, core);
JStack.main(newArgs.toArray(new String[newArgs.size()]));
}
@@ -216,13 +247,14 @@
"heap", "binaryheap", "histo", "clstats", "finalizerinfo"};
ArrayList<String> newArgs = new ArrayList();
- String exeORpid = null;
+ String pid = null;
+ String exe = null;
String core = null;
String s = null;
while((s = sg.next(null, longOpts)) != null) {
if (s.equals("exe")) {
- exeORpid = sg.getOptarg();
+ exe = sg.getOptarg();
continue;
}
if (s.equals("core")) {
@@ -230,7 +262,7 @@
continue;
}
if (s.equals("pid")) {
- exeORpid = sg.getOptarg();
+ pid = sg.getOptarg();
continue;
}
if (s.equals("heap")) {
@@ -255,13 +287,7 @@
}
}
- if (exeORpid != null) {
- newArgs.add(exeORpid);
- if (core != null) {
- newArgs.add(core);
- }
- }
-
+ buildAttachArgs(newArgs, pid, exe, core);
JMap.main(newArgs.toArray(new String[newArgs.size()]));
}
@@ -271,13 +297,14 @@
"flags", "sysprops"};
ArrayList<String> newArgs = new ArrayList();
- String exeORpid = null;
+ String exe = null;
+ String pid = null;
String core = null;
String s = null;
while((s = sg.next(null, longOpts)) != null) {
if (s.equals("exe")) {
- exeORpid = sg.getOptarg();
+ exe = sg.getOptarg();
continue;
}
if (s.equals("core")) {
@@ -285,7 +312,7 @@
continue;
}
if (s.equals("pid")) {
- exeORpid = sg.getOptarg();
+ pid = sg.getOptarg();
continue;
}
if (s.equals("flags")) {
@@ -298,14 +325,37 @@
}
}
- if (exeORpid != null) {
- newArgs.add(exeORpid);
- if (core != null) {
- newArgs.add(core);
+ buildAttachArgs(newArgs, pid, exe, core);
+ JInfo.main(newArgs.toArray(new String[newArgs.size()]));
+ }
+
+ private static void runJSNAP(String[] oldArgs) {
+ SAGetopt sg = new SAGetopt(oldArgs);
+ String[] longOpts = {"exe=", "core=", "pid="};
+
+ ArrayList<String> newArgs = new ArrayList();
+ String exe = null;
+ String pid = null;
+ String core = null;
+ String s = null;
+
+ while((s = sg.next(null, longOpts)) != null) {
+ if (s.equals("exe")) {
+ exe = sg.getOptarg();
+ continue;
+ }
+ if (s.equals("core")) {
+ core = sg.getOptarg();
+ continue;
+ }
+ if (s.equals("pid")) {
+ pid = sg.getOptarg();
+ continue;
}
}
- JInfo.main(newArgs.toArray(new String[newArgs.size()]));
+ buildAttachArgs(newArgs, pid, exe, core);
+ JSnap.main(newArgs.toArray(new String[newArgs.size()]));
}
public static void main(String[] args) {
@@ -329,31 +379,43 @@
String[] oldArgs = Arrays.copyOfRange(args, 1, args.length);
- // Run SA interactive mode
- if (args[0].equals("clhsdb")) {
- runCLHSDB(oldArgs);
- return;
- }
+ try {
+ // Run SA interactive mode
+ if (args[0].equals("clhsdb")) {
+ runCLHSDB(oldArgs);
+ return;
+ }
- if (args[0].equals("hsdb")) {
- runHSDB(oldArgs);
- return;
- }
+ if (args[0].equals("hsdb")) {
+ runHSDB(oldArgs);
+ return;
+ }
+
+ // Run SA tmtools mode
+ if (args[0].equals("jstack")) {
+ runJSTACK(oldArgs);
+ return;
+ }
- // Run SA tmtools mode
- if (args[0].equals("jstack")) {
- runJSTACK(oldArgs);
- return;
- }
+ if (args[0].equals("jmap")) {
+ runJMAP(oldArgs);
+ return;
+ }
+
+ if (args[0].equals("jinfo")) {
+ runJINFO(oldArgs);
+ return;
+ }
- if (args[0].equals("jmap")) {
- runJMAP(oldArgs);
- return;
- }
+ if (args[0].equals("jsnap")) {
+ runJSNAP(oldArgs);
+ return;
+ }
- if (args[0].equals("jinfo")) {
- runJINFO(oldArgs);
- return;
+ throw new IllegalArgumentException("Unknown tool: " + args[0]);
+ } catch (Exception e) {
+ System.err.println(e.getMessage());
+ toolHelp(args[0]);
}
}
}
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCCause.java Sat Mar 19 01:23:46 2016 +0100
@@ -35,6 +35,11 @@
_gc_locker ("GCLocker Initiated GC"),
_heap_inspection ("Heap Inspection Initiated GC"),
_heap_dump ("Heap Dump Initiated GC"),
+ _wb_young_gc ("WhiteBox Initiated Young GC"),
+ _wb_conc_mark ("WhiteBox Initiated Concurrent Mark"),
+ _wb_full_gc ("WhiteBox Initiated Full GC"),
+ _update_allocation_context_stats_inc ("Update Allocation Context Stats"),
+ _update_allocation_context_stats_full ("Update Allocation Context Stats"),
_no_gc ("No GC"),
_no_cause_specified ("Unknown GCCause"),
@@ -42,6 +47,7 @@
_tenured_generation_full ("Tenured Generation Full"),
_metadata_GC_threshold ("Metadata GC Threshold"),
+ _metadata_GC_clear_soft_refs ("Metadata GC Clear Soft References"),
_cms_generation_full ("CMS Generation Full"),
_cms_initial_mark ("CMS Initial Mark"),
@@ -55,7 +61,8 @@
_g1_inc_collection_pause ("G1 Evacuation Pause"),
_g1_humongous_allocation ("G1 Humongous Allocation"),
- _last_ditch_collection ("Last ditch collection"),
+ _dcmd_gc_run ("Diagnostic Command"),
+
_last_gc_cause ("ILLEGAL VALUE - last gc cause - ILLEGAL VALUE");
private final String value;
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, 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
@@ -130,7 +130,7 @@
virtualConstructor.addMapping("CodeCacheSweeperThread", CodeCacheSweeperThread.class);
}
// for now, use JavaThread itself. fix it later with appropriate class if needed
- virtualConstructor.addMapping("SurrogateLockerThread", JavaThread.class);
+ virtualConstructor.addMapping("ReferencePendingListLockerThread", JavaThread.class);
virtualConstructor.addMapping("JvmtiAgentThread", JvmtiAgentThread.class);
virtualConstructor.addMapping("ServiceThread", ServiceThread.class);
}
@@ -172,7 +172,7 @@
return thread;
} catch (Exception e) {
throw new RuntimeException("Unable to deduce type of thread from address " + threadAddr +
- " (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread, SurrogateLockerThread, or CodeCacheSweeperThread)", e);
+ " (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread, ReferencePendingListLockerThread, or CodeCacheSweeperThread)", e);
}
}
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/CompactHashTable.java Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/CompactHashTable.java Sat Mar 19 01:23:46 2016 +0100
@@ -81,6 +81,12 @@
}
public Symbol probe(byte[] name, long hash) {
+
+ if (bucketCount() == 0) {
+ // The table is invalid, so don't try to lookup
+ return null;
+ }
+
long symOffset;
Symbol sym;
Address baseAddress = baseAddressField.getValue(addr);
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2016, 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
@@ -837,7 +837,7 @@
vmType2Class["JavaThread"] = sapkg.runtime.JavaThread;
vmType2Class["CompilerThread"] = sapkg.runtime.CompilerThread;
vmType2Class["CodeCacheSweeperThread"] = sapkg.runtime.CodeCacheSweeperThread;
-vmType2Class["SurrogateLockerThread"] = sapkg.runtime.JavaThread;
+vmType2Class["ReferencePendingListLockerThread"] = sapkg.runtime.JavaThread;
vmType2Class["DebuggerThread"] = sapkg.runtime.DebuggerThread;
// gc
--- a/hotspot/src/os/aix/vm/os_aix.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/os/aix/vm/os_aix.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -910,8 +910,8 @@
log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ",
(uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
} else {
- log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.",
- strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
+ log_warning(os, thread)("Failed to start thread - pthread_create failed (%d=%s) for attributes: %s.",
+ ret, os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
}
pthread_attr_destroy(&attr);
@@ -1178,7 +1178,7 @@
size_t os::lasterror(char *buf, size_t len) {
if (errno == 0) return 0;
- const char *s = ::strerror(errno);
+ const char *s = os::strerror(errno);
size_t n = ::strlen(s);
if (n >= len) {
n = len - 1;
@@ -1714,14 +1714,14 @@
if (os::Aix::on_aix()) {
int rc = ::sem_post(&sig_sem);
if (rc == -1 && !warn_only_once) {
- trcVerbose("sem_post failed (errno = %d, %s)", errno, strerror(errno));
+ trcVerbose("sem_post failed (errno = %d, %s)", errno, os::errno_name(errno));
warn_only_once = true;
}
} else {
guarantee0(p_sig_msem != NULL);
int rc = ::msem_unlock(p_sig_msem, 0);
if (rc == -1 && !warn_only_once) {
- trcVerbose("msem_unlock failed (errno = %d, %s)", errno, strerror(errno));
+ trcVerbose("msem_unlock failed (errno = %d, %s)", errno, os::errno_name(errno));
warn_only_once = true;
}
}
@@ -1732,14 +1732,14 @@
if (os::Aix::on_aix()) {
int rc = ::sem_wait(&sig_sem);
if (rc == -1 && !warn_only_once) {
- trcVerbose("sem_wait failed (errno = %d, %s)", errno, strerror(errno));
+ trcVerbose("sem_wait failed (errno = %d, %s)", errno, os::errno_name(errno));
warn_only_once = true;
}
} else {
guarantee0(p_sig_msem != NULL); // must init before use
int rc = ::msem_lock(p_sig_msem, 0);
if (rc == -1 && !warn_only_once) {
- trcVerbose("msem_lock failed (errno = %d, %s)", errno, strerror(errno));
+ trcVerbose("msem_lock failed (errno = %d, %s)", errno, os::errno_name(errno));
warn_only_once = true;
}
}
@@ -2203,7 +2203,7 @@
int err) {
warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT
", %d) failed; error='%s' (errno=%d)", addr, size, exec,
- strerror(err), err);
+ os::errno_name(err), err);
}
#endif
@@ -2412,7 +2412,7 @@
bool rc = ::mprotect(addr, size, prot) == 0 ? true : false;
if (!rc) {
- const char* const s_errno = strerror(errno);
+ const char* const s_errno = os::errno_name(errno);
warning("mprotect(" PTR_FORMAT "-" PTR_FORMAT ", 0x%X) failed (%s).", addr, addr + size, prot, s_errno);
return false;
}
@@ -2634,7 +2634,7 @@
if (ret != 0) {
trcVerbose("Could not change priority for thread %d to %d (error %d, %s)",
- (int)thr, newpri, ret, strerror(ret));
+ (int)thr, newpri, ret, os::errno_name(ret));
}
return (ret == 0) ? OS_OK : OS_ERR;
}
--- a/hotspot/src/os/aix/vm/perfMemory_aix.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/os/aix/vm/perfMemory_aix.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -30,6 +30,7 @@
#include "oops/oop.inline.hpp"
#include "os_aix.inline.hpp"
#include "runtime/handles.inline.hpp"
+#include "runtime/os.hpp"
#include "runtime/perfMemory.hpp"
#include "services/memTracker.hpp"
#include "utilities/exceptions.hpp"
@@ -101,7 +102,7 @@
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
warning("Could not create Perfdata save file: %s: %s\n",
- destfile, strerror(errno));
+ destfile, os::strerror(errno));
}
} else {
int fd = result;
@@ -112,7 +113,7 @@
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
warning("Could not write Perfdata save file: %s: %s\n",
- destfile, strerror(errno));
+ destfile, os::strerror(errno));
}
break;
}
@@ -124,7 +125,7 @@
result = ::close(fd);
if (PrintMiscellaneous && Verbose) {
if (result == OS_ERR) {
- warning("Could not close %s: %s\n", destfile, strerror(errno));
+ warning("Could not close %s: %s\n", destfile, os::strerror(errno));
}
}
}
@@ -397,7 +398,7 @@
if (errno == ELOOP) {
warning("directory %s is a symlink and is not secure\n", dirname);
} else {
- warning("could not open directory %s: %s\n", dirname, strerror(errno));
+ warning("could not open directory %s: %s\n", dirname, os::strerror(errno));
}
}
return dirp;
@@ -507,7 +508,7 @@
RESTARTABLE(::fstat(fd, &statbuf), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("fstat failed on %s: %s\n", filename, strerror(errno));
+ warning("fstat failed on %s: %s\n", filename, os::strerror(errno));
}
return false;
}
@@ -543,7 +544,7 @@
if (PrintMiscellaneous && Verbose) {
if (result != 0) {
warning("Could not retrieve passwd entry: %s\n",
- strerror(result));
+ os::strerror(result));
}
else if (p == NULL) {
// this check is added to protect against an observed problem
@@ -557,7 +558,7 @@
// Bug Id 89052 was opened with RedHat.
//
warning("Could not retrieve passwd entry: %s\n",
- strerror(errno));
+ os::strerror(errno));
}
else {
warning("Could not determine user name: %s\n",
@@ -593,7 +594,7 @@
"Process not found");
}
else /* EPERM */ {
- THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno));
+ THROW_MSG_0(vmSymbols::java_io_IOException(), os::strerror(errno));
}
}
@@ -746,7 +747,7 @@
if (PrintMiscellaneous && Verbose && result == OS_ERR) {
if (errno != ENOENT) {
warning("Could not unlink shared memory backing"
- " store file %s : %s\n", path, strerror(errno));
+ " store file %s : %s\n", path, os::strerror(errno));
}
}
}
@@ -849,7 +850,7 @@
//
if (PrintMiscellaneous && Verbose) {
warning("could not create directory %s: %s\n",
- dirname, strerror(errno));
+ dirname, os::strerror(errno));
}
return false;
}
@@ -900,7 +901,7 @@
if (errno == ELOOP) {
warning("file %s is a symlink and is not secure\n", filename);
} else {
- warning("could not create file %s: %s\n", filename, strerror(errno));
+ warning("could not create file %s: %s\n", filename, os::strerror(errno));
}
}
// Close the directory and reset the current working directory.
@@ -924,7 +925,7 @@
RESTARTABLE(::ftruncate(fd, (off_t)0), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("could not truncate shared memory file: %s\n", strerror(errno));
+ warning("could not truncate shared memory file: %s\n", os::strerror(errno));
}
::close(fd);
return -1;
@@ -933,7 +934,7 @@
RESTARTABLE(::ftruncate(fd, (off_t)size), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("could not set shared memory file size: %s\n", strerror(errno));
+ warning("could not set shared memory file size: %s\n", os::strerror(errno));
}
::close(fd);
return -1;
@@ -968,7 +969,7 @@
"Permission denied");
}
else {
- THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno));
+ THROW_MSG_0(vmSymbols::java_io_IOException(), os::strerror(errno));
}
}
int fd = result;
@@ -1041,7 +1042,7 @@
if (mapAddress == MAP_FAILED) {
if (PrintMiscellaneous && Verbose) {
- warning("mmap failed - %s\n", strerror(errno));
+ warning("mmap failed - %s\n", os::strerror(errno));
}
remove_file(filename);
FREE_C_HEAP_ARRAY(char, filename);
@@ -1109,7 +1110,7 @@
RESTARTABLE(::fstat(fd, &statbuf), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("fstat failed: %s\n", strerror(errno));
+ warning("fstat failed: %s\n", os::strerror(errno));
}
THROW_MSG_0(vmSymbols::java_io_IOException(),
"Could not determine PerfMemory size");
@@ -1231,7 +1232,7 @@
if (mapAddress == MAP_FAILED) {
if (PrintMiscellaneous && Verbose) {
- warning("mmap failed: %s\n", strerror(errno));
+ warning("mmap failed: %s\n", os::strerror(errno));
}
THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
"Could not map PerfMemory");
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -789,7 +789,7 @@
(uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
} else {
log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.",
- strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
+ os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
}
pthread_attr_destroy(&attr);
@@ -1122,7 +1122,7 @@
size_t os::lasterror(char *buf, size_t len) {
if (errno == 0) return 0;
- const char *s = ::strerror(errno);
+ const char *s = os::strerror(errno);
size_t n = ::strlen(s);
if (n >= len) {
n = len - 1;
@@ -2141,7 +2141,7 @@
int err) {
warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT
", %d) failed; error='%s' (errno=%d)", addr, size, exec,
- strerror(err), err);
+ os::errno_name(err), err);
}
// NOTE: Bsd kernel does not really reserve the pages for us.
@@ -3422,7 +3422,7 @@
Bsd::set_page_size(getpagesize());
if (Bsd::page_size() == -1) {
- fatal("os_bsd.cpp: os::init: sysconf failed (%s)", strerror(errno));
+ fatal("os_bsd.cpp: os::init: sysconf failed (%s)", os::strerror(errno));
}
init_page_sizes((size_t) Bsd::page_size());
--- a/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/os/bsd/vm/perfMemory_bsd.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -29,6 +29,7 @@
#include "oops/oop.inline.hpp"
#include "os_bsd.inline.hpp"
#include "runtime/handles.inline.hpp"
+#include "runtime/os.hpp"
#include "runtime/perfMemory.hpp"
#include "services/memTracker.hpp"
#include "utilities/exceptions.hpp"
@@ -100,7 +101,7 @@
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
warning("Could not create Perfdata save file: %s: %s\n",
- destfile, strerror(errno));
+ destfile, os::strerror(errno));
}
} else {
int fd = result;
@@ -111,7 +112,7 @@
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
warning("Could not write Perfdata save file: %s: %s\n",
- destfile, strerror(errno));
+ destfile, os::strerror(errno));
}
break;
}
@@ -123,7 +124,7 @@
result = ::close(fd);
if (PrintMiscellaneous && Verbose) {
if (result == OS_ERR) {
- warning("Could not close %s: %s\n", destfile, strerror(errno));
+ warning("Could not close %s: %s\n", destfile, os::strerror(errno));
}
}
}
@@ -309,7 +310,7 @@
if (errno == ELOOP) {
warning("directory %s is a symlink and is not secure\n", dirname);
} else {
- warning("could not open directory %s: %s\n", dirname, strerror(errno));
+ warning("could not open directory %s: %s\n", dirname, os::strerror(errno));
}
}
return dirp;
@@ -420,7 +421,7 @@
RESTARTABLE(::fstat(fd, &statbuf), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("fstat failed on %s: %s\n", filename, strerror(errno));
+ warning("fstat failed on %s: %s\n", filename, os::strerror(errno));
}
return false;
}
@@ -459,7 +460,7 @@
if (PrintMiscellaneous && Verbose) {
if (result != 0) {
warning("Could not retrieve passwd entry: %s\n",
- strerror(result));
+ os::strerror(result));
}
else if (p == NULL) {
// this check is added to protect against an observed problem
@@ -473,7 +474,7 @@
// Bug Id 89052 was opened with RedHat.
//
warning("Could not retrieve passwd entry: %s\n",
- strerror(errno));
+ os::strerror(errno));
}
else {
warning("Could not determine user name: %s\n",
@@ -509,7 +510,7 @@
"Process not found");
}
else /* EPERM */ {
- THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno));
+ THROW_MSG_0(vmSymbols::java_io_IOException(), os::strerror(errno));
}
}
@@ -652,7 +653,7 @@
if (PrintMiscellaneous && Verbose && result == OS_ERR) {
if (errno != ENOENT) {
warning("Could not unlink shared memory backing"
- " store file %s : %s\n", path, strerror(errno));
+ " store file %s : %s\n", path, os::strerror(errno));
}
}
}
@@ -762,7 +763,7 @@
//
if (PrintMiscellaneous && Verbose) {
warning("could not create directory %s: %s\n",
- dirname, strerror(errno));
+ dirname, os::strerror(errno));
}
return false;
}
@@ -804,7 +805,7 @@
if (errno == ELOOP) {
warning("file %s is a symlink and is not secure\n", filename);
} else {
- warning("could not create file %s: %s\n", filename, strerror(errno));
+ warning("could not create file %s: %s\n", filename, os::strerror(errno));
}
}
// close the directory and reset the current working directory
@@ -828,7 +829,7 @@
RESTARTABLE(::ftruncate(fd, (off_t)0), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("could not truncate shared memory file: %s\n", strerror(errno));
+ warning("could not truncate shared memory file: %s\n", os::strerror(errno));
}
::close(fd);
return -1;
@@ -837,7 +838,7 @@
RESTARTABLE(::ftruncate(fd, (off_t)size), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("could not set shared memory file size: %s\n", strerror(errno));
+ warning("could not set shared memory file size: %s\n", os::strerror(errno));
}
::close(fd);
return -1;
@@ -887,7 +888,7 @@
"Permission denied", OS_ERR);
}
else {
- THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR);
+ THROW_MSG_(vmSymbols::java_io_IOException(), os::strerror(errno), OS_ERR);
}
}
int fd = result;
@@ -961,7 +962,7 @@
if (mapAddress == MAP_FAILED) {
if (PrintMiscellaneous && Verbose) {
- warning("mmap failed - %s\n", strerror(errno));
+ warning("mmap failed - %s\n", os::strerror(errno));
}
remove_file(filename);
FREE_C_HEAP_ARRAY(char, filename);
@@ -1025,7 +1026,7 @@
RESTARTABLE(::fstat(fd, &statbuf), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("fstat failed: %s\n", strerror(errno));
+ warning("fstat failed: %s\n", os::strerror(errno));
}
THROW_MSG_0(vmSymbols::java_io_IOException(),
"Could not determine PerfMemory size");
@@ -1136,7 +1137,7 @@
if (mapAddress == MAP_FAILED) {
if (PrintMiscellaneous && Verbose) {
- warning("mmap failed: %s\n", strerror(errno));
+ warning("mmap failed: %s\n", os::strerror(errno));
}
THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
"Could not map PerfMemory");
--- a/hotspot/src/os/linux/vm/os_linux.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -594,15 +594,7 @@
// _expand_stack_to() assumes its frame size is less than page size, which
// should always be true if the function is not inlined.
-#if __GNUC__ < 3 // gcc 2.x does not support noinline attribute
- #define NOINLINE
-#else
- #define NOINLINE __attribute__ ((noinline))
-#endif
-
-static void _expand_stack_to(address bottom) NOINLINE;
-
-static void _expand_stack_to(address bottom) {
+static void NOINLINE _expand_stack_to(address bottom) {
address sp;
size_t size;
volatile char *p;
@@ -769,7 +761,7 @@
(uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
} else {
log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.",
- strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
+ os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
}
pthread_attr_destroy(&attr);
@@ -890,6 +882,13 @@
assert(osthread != NULL, "osthread not set");
if (Thread::current()->osthread() == osthread) {
+#ifdef ASSERT
+ sigset_t current;
+ sigemptyset(¤t);
+ pthread_sigmask(SIG_SETMASK, NULL, ¤t);
+ assert(!sigismember(¤t, SR_signum), "SR signal should not be blocked!");
+#endif
+
// Restore caller's signal mask
sigset_t sigmask = osthread->caller_sigmask();
pthread_sigmask(SIG_SETMASK, &sigmask, NULL);
@@ -1395,7 +1394,7 @@
size_t os::lasterror(char *buf, size_t len) {
if (errno == 0) return 0;
- const char *s = ::strerror(errno);
+ const char *s = os::strerror(errno);
size_t n = ::strlen(s);
if (n >= len) {
n = len - 1;
@@ -2601,7 +2600,7 @@
int err) {
warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT
", %d) failed; error='%s' (errno=%d)", p2i(addr), size, exec,
- strerror(err), err);
+ os::strerror(err), err);
}
static void warn_fail_commit_memory(char* addr, size_t size,
@@ -2609,7 +2608,7 @@
int err) {
warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT
", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", p2i(addr), size,
- alignment_hint, exec, strerror(err), err);
+ alignment_hint, exec, os::strerror(err), err);
}
// NOTE: Linux kernel does not really reserve the pages for us.
@@ -3912,7 +3911,8 @@
// after sigsuspend.
int old_errno = errno;
- Thread* thread = Thread::current();
+ Thread* thread = Thread::current_or_null_safe();
+ assert(thread != NULL, "Missing current thread in SR_handler");
OSThread* osthread = thread->osthread();
assert(thread->is_VM_thread() || thread->is_Java_thread(), "Must be VMThread or JavaThread");
@@ -3924,7 +3924,7 @@
os::SuspendResume::State state = osthread->sr.suspended();
if (state == os::SuspendResume::SR_SUSPENDED) {
sigset_t suspend_set; // signals for sigsuspend()
-
+ sigemptyset(&suspend_set);
// get current set of blocked signals and unblock resume signal
pthread_sigmask(SIG_BLOCK, NULL, &suspend_set);
sigdelset(&suspend_set, SR_signum);
@@ -4178,6 +4178,7 @@
// try to honor the signal mask
sigset_t oset;
+ sigemptyset(&oset);
pthread_sigmask(SIG_SETMASK, &(actp->sa_mask), &oset);
// call into the chained handler
@@ -4188,7 +4189,7 @@
}
// restore the signal mask
- pthread_sigmask(SIG_SETMASK, &oset, 0);
+ pthread_sigmask(SIG_SETMASK, &oset, NULL);
}
// Tell jvm's signal handler the signal is taken care of.
return true;
@@ -4615,7 +4616,7 @@
Linux::set_page_size(sysconf(_SC_PAGESIZE));
if (Linux::page_size() == -1) {
fatal("os_linux.cpp: os::init: sysconf failed (%s)",
- strerror(errno));
+ os::strerror(errno));
}
init_page_sizes((size_t) Linux::page_size());
@@ -4633,7 +4634,7 @@
int status;
pthread_condattr_t* _condattr = os::Linux::condAttr();
if ((status = pthread_condattr_init(_condattr)) != 0) {
- fatal("pthread_condattr_init: %s", strerror(status));
+ fatal("pthread_condattr_init: %s", os::strerror(status));
}
// Only set the clock if CLOCK_MONOTONIC is available
if (os::supports_monotonic_clock()) {
@@ -4642,7 +4643,7 @@
warning("Unable to use monotonic clock with relative timed-waits" \
" - changes to the time-of-day clock may have adverse affects");
} else {
- fatal("pthread_condattr_setclock: %s", strerror(status));
+ fatal("pthread_condattr_setclock: %s", os::strerror(status));
}
}
}
@@ -4888,7 +4889,7 @@
log_trace(os)("active_processor_count: "
"CPU_ALLOC failed (%s) - using "
"online processor count: %d",
- strerror(errno), online_cpus);
+ os::strerror(errno), online_cpus);
return online_cpus;
}
}
@@ -4918,7 +4919,7 @@
else {
cpu_count = ::sysconf(_SC_NPROCESSORS_ONLN);
warning("sched_getaffinity failed (%s)- using online processor count (%d) "
- "which may exceed available processors", strerror(errno), cpu_count);
+ "which may exceed available processors", os::strerror(errno), cpu_count);
}
if (cpus_p != &cpus) { // can only be true when CPU_ALLOC used
@@ -5769,6 +5770,7 @@
// Don't catch signals while blocked; let the running threads have the signals.
// (This allows a debugger to break into the running thread.)
sigset_t oldsigs;
+ sigemptyset(&oldsigs);
sigset_t* allowdebug_blocked = os::Linux::allowdebug_blocked_signals();
pthread_sigmask(SIG_BLOCK, allowdebug_blocked, &oldsigs);
#endif
--- a/hotspot/src/os/linux/vm/perfMemory_linux.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/os/linux/vm/perfMemory_linux.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -29,6 +29,7 @@
#include "oops/oop.inline.hpp"
#include "os_linux.inline.hpp"
#include "runtime/handles.inline.hpp"
+#include "runtime/os.hpp"
#include "runtime/perfMemory.hpp"
#include "services/memTracker.hpp"
#include "utilities/exceptions.hpp"
@@ -100,7 +101,7 @@
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
warning("Could not create Perfdata save file: %s: %s\n",
- destfile, strerror(errno));
+ destfile, os::strerror(errno));
}
} else {
int fd = result;
@@ -111,7 +112,7 @@
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
warning("Could not write Perfdata save file: %s: %s\n",
- destfile, strerror(errno));
+ destfile, os::strerror(errno));
}
break;
}
@@ -123,7 +124,7 @@
result = ::close(fd);
if (PrintMiscellaneous && Verbose) {
if (result == OS_ERR) {
- warning("Could not close %s: %s\n", destfile, strerror(errno));
+ warning("Could not close %s: %s\n", destfile, os::strerror(errno));
}
}
}
@@ -308,7 +309,7 @@
if (errno == ELOOP) {
warning("directory %s is a symlink and is not secure\n", dirname);
} else {
- warning("could not open directory %s: %s\n", dirname, strerror(errno));
+ warning("could not open directory %s: %s\n", dirname, os::strerror(errno));
}
}
return dirp;
@@ -419,7 +420,7 @@
RESTARTABLE(::fstat(fd, &statbuf), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("fstat failed on %s: %s\n", filename, strerror(errno));
+ warning("fstat failed on %s: %s\n", filename, os::strerror(errno));
}
return false;
}
@@ -459,7 +460,7 @@
if (PrintMiscellaneous && Verbose) {
if (result != 0) {
warning("Could not retrieve passwd entry: %s\n",
- strerror(result));
+ os::strerror(result));
}
else if (p == NULL) {
// this check is added to protect against an observed problem
@@ -473,7 +474,7 @@
// Bug Id 89052 was opened with RedHat.
//
warning("Could not retrieve passwd entry: %s\n",
- strerror(errno));
+ os::strerror(errno));
}
else {
warning("Could not determine user name: %s\n",
@@ -509,7 +510,7 @@
"Process not found");
}
else /* EPERM */ {
- THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno));
+ THROW_MSG_0(vmSymbols::java_io_IOException(), os::strerror(errno));
}
}
@@ -664,7 +665,7 @@
if (PrintMiscellaneous && Verbose && result == OS_ERR) {
if (errno != ENOENT) {
warning("Could not unlink shared memory backing"
- " store file %s : %s\n", path, strerror(errno));
+ " store file %s : %s\n", path, os::strerror(errno));
}
}
}
@@ -772,7 +773,7 @@
//
if (PrintMiscellaneous && Verbose) {
warning("could not create directory %s: %s\n",
- dirname, strerror(errno));
+ dirname, os::strerror(errno));
}
return false;
}
@@ -814,7 +815,7 @@
if (errno == ELOOP) {
warning("file %s is a symlink and is not secure\n", filename);
} else {
- warning("could not create file %s: %s\n", filename, strerror(errno));
+ warning("could not create file %s: %s\n", filename, os::strerror(errno));
}
}
// close the directory and reset the current working directory
@@ -838,7 +839,7 @@
RESTARTABLE(::ftruncate(fd, (off_t)0), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("could not truncate shared memory file: %s\n", strerror(errno));
+ warning("could not truncate shared memory file: %s\n", os::strerror(errno));
}
::close(fd);
return -1;
@@ -847,7 +848,7 @@
RESTARTABLE(::ftruncate(fd, (off_t)size), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("could not set shared memory file size: %s\n", strerror(errno));
+ warning("could not set shared memory file size: %s\n", os::strerror(errno));
}
::close(fd);
return -1;
@@ -897,7 +898,7 @@
"Permission denied", OS_ERR);
}
else {
- THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR);
+ THROW_MSG_(vmSymbols::java_io_IOException(), os::strerror(errno), OS_ERR);
}
}
int fd = result;
@@ -970,7 +971,7 @@
if (mapAddress == MAP_FAILED) {
if (PrintMiscellaneous && Verbose) {
- warning("mmap failed - %s\n", strerror(errno));
+ warning("mmap failed - %s\n", os::strerror(errno));
}
remove_file(filename);
FREE_C_HEAP_ARRAY(char, filename);
@@ -1034,7 +1035,7 @@
RESTARTABLE(::fstat(fd, &statbuf), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("fstat failed: %s\n", strerror(errno));
+ warning("fstat failed: %s\n", os::strerror(errno));
}
THROW_MSG_0(vmSymbols::java_io_IOException(),
"Could not determine PerfMemory size");
@@ -1151,7 +1152,7 @@
if (mapAddress == MAP_FAILED) {
if (PrintMiscellaneous && Verbose) {
- warning("mmap failed: %s\n", strerror(errno));
+ warning("mmap failed: %s\n", os::strerror(errno));
}
THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
"Could not map PerfMemory");
--- a/hotspot/src/os/posix/vm/os_posix.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/os/posix/vm/os_posix.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1144,7 +1144,8 @@
#define check_with_errno(check_type, cond, msg) \
do { \
int err = errno; \
- check_type(cond, "%s; error='%s' (errno=%d)", msg, strerror(err), err); \
+ check_type(cond, "%s; error='%s' (errno=%s)", msg, os::strerror(err), \
+ os::errno_name(err)); \
} while (false)
#define assert_with_errno(cond, msg) check_with_errno(assert, cond, msg)
--- a/hotspot/src/os/solaris/vm/attachListener_solaris.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/os/solaris/vm/attachListener_solaris.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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
@@ -461,7 +461,7 @@
while ((res = ::sema_wait(wakeup())) == EINTR)
;
if (res) {
- warning("sema_wait failed: %s", strerror(res));
+ warning("sema_wait failed: %s", os::strerror(res));
return NULL;
}
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1009,7 +1009,7 @@
(uintx) tid, describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags));
} else {
log_warning(os, thread)("Failed to start thread - thr_create failed (%s) for attributes: %s.",
- strerror(status), describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags));
+ os::errno_name(status), describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags));
}
if (status != 0) {
@@ -1354,7 +1354,7 @@
jlong os::javaTimeMillis() {
timeval t;
if (gettimeofday(&t, NULL) == -1) {
- fatal("os::javaTimeMillis: gettimeofday (%s)", strerror(errno));
+ fatal("os::javaTimeMillis: gettimeofday (%s)", os::strerror(errno));
}
return jlong(t.tv_sec) * 1000 + jlong(t.tv_usec) / 1000;
}
@@ -1362,7 +1362,7 @@
void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) {
timeval t;
if (gettimeofday(&t, NULL) == -1) {
- fatal("os::javaTimeSystemUTC: gettimeofday (%s)", strerror(errno));
+ fatal("os::javaTimeSystemUTC: gettimeofday (%s)", os::strerror(errno));
}
seconds = jlong(t.tv_sec);
nanos = jlong(t.tv_usec) * 1000;
@@ -1892,21 +1892,39 @@
static bool check_addr0(outputStream* st) {
jboolean status = false;
+ const int read_chunk = 200;
+ int ret = 0;
+ int nmap = 0;
int fd = ::open("/proc/self/map",O_RDONLY);
if (fd >= 0) {
- prmap_t p;
- while (::read(fd, &p, sizeof(p)) > 0) {
- if (p.pr_vaddr == 0x0) {
- st->print("Warning: Address: 0x%x, Size: %dK, ",p.pr_vaddr, p.pr_size/1024, p.pr_mapname);
- st->print("Mapped file: %s, ", p.pr_mapname[0] == '\0' ? "None" : p.pr_mapname);
- st->print("Access:");
- st->print("%s",(p.pr_mflags & MA_READ) ? "r" : "-");
- st->print("%s",(p.pr_mflags & MA_WRITE) ? "w" : "-");
- st->print("%s",(p.pr_mflags & MA_EXEC) ? "x" : "-");
- st->cr();
- status = true;
+ prmap_t *p = NULL;
+ char *mbuff = (char *) calloc(read_chunk, sizeof(prmap_t));
+ if (NULL == mbuff) {
+ ::close(fd);
+ return status;
+ }
+ while ((ret = ::read(fd, mbuff, read_chunk*sizeof(prmap_t))) > 0) {
+ //check if read() has not read partial data
+ if( 0 != ret % sizeof(prmap_t)){
+ break;
+ }
+ nmap = ret / sizeof(prmap_t);
+ p = (prmap_t *)mbuff;
+ for(int i = 0; i < nmap; i++){
+ if (p->pr_vaddr == 0x0) {
+ st->print("Warning: Address: " PTR_FORMAT ", Size: " SIZE_FORMAT "K, ",p->pr_vaddr, p->pr_size/1024);
+ st->print("Mapped file: %s, ", p->pr_mapname[0] == '\0' ? "None" : p->pr_mapname);
+ st->print("Access: ");
+ st->print("%s",(p->pr_mflags & MA_READ) ? "r" : "-");
+ st->print("%s",(p->pr_mflags & MA_WRITE) ? "w" : "-");
+ st->print("%s",(p->pr_mflags & MA_EXEC) ? "x" : "-");
+ st->cr();
+ status = true;
+ }
+ p++;
}
}
+ free(mbuff);
::close(fd);
}
return status;
@@ -2142,7 +2160,7 @@
size_t os::lasterror(char *buf, size_t len) {
if (errno == 0) return 0;
- const char *s = ::strerror(errno);
+ const char *s = os::strerror(errno);
size_t n = ::strlen(s);
if (n >= len) {
n = len - 1;
@@ -2351,7 +2369,7 @@
int err) {
warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT
", %d) failed; error='%s' (errno=%d)", addr, bytes, exec,
- strerror(err), err);
+ os::strerror(err), err);
}
static void warn_fail_commit_memory(char* addr, size_t bytes,
@@ -2359,7 +2377,7 @@
int err) {
warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT
", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", addr, bytes,
- alignment_hint, exec, strerror(err), err);
+ alignment_hint, exec, os::strerror(err), err);
}
int os::Solaris::commit_memory_impl(char* addr, size_t bytes, bool exec) {
@@ -2740,7 +2758,7 @@
char buf[256];
buf[0] = '\0';
if (addr == NULL) {
- jio_snprintf(buf, sizeof(buf), ": %s", strerror(err));
+ jio_snprintf(buf, sizeof(buf), ": %s", os::strerror(err));
}
warning("attempt_reserve_memory_at: couldn't reserve " SIZE_FORMAT " bytes at "
PTR_FORMAT ": reserve_memory_helper returned " PTR_FORMAT
@@ -4354,7 +4372,7 @@
page_size = sysconf(_SC_PAGESIZE);
if (page_size == -1) {
- fatal("os_solaris.cpp: os::init: sysconf failed (%s)", strerror(errno));
+ fatal("os_solaris.cpp: os::init: sysconf failed (%s)", os::strerror(errno));
}
init_page_sizes((size_t) page_size);
@@ -4366,7 +4384,7 @@
int fd = ::open("/dev/zero", O_RDWR);
if (fd < 0) {
- fatal("os::init: cannot open /dev/zero (%s)", strerror(errno));
+ fatal("os::init: cannot open /dev/zero (%s)", os::strerror(errno));
} else {
Solaris::set_dev_zero_fd(fd);
@@ -5607,7 +5625,7 @@
if (pid < 0) {
// fork failed
- warning("fork failed: %s", strerror(errno));
+ warning("fork failed: %s", os::strerror(errno));
return -1;
} else if (pid == 0) {
--- a/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/os/solaris/vm/perfMemory_solaris.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -102,7 +102,7 @@
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
warning("Could not create Perfdata save file: %s: %s\n",
- destfile, strerror(errno));
+ destfile, os::strerror(errno));
}
} else {
@@ -114,7 +114,7 @@
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
warning("Could not write Perfdata save file: %s: %s\n",
- destfile, strerror(errno));
+ destfile, os::strerror(errno));
}
break;
}
@@ -125,7 +125,7 @@
result = ::close(fd);
if (PrintMiscellaneous && Verbose) {
if (result == OS_ERR) {
- warning("Could not close %s: %s\n", destfile, strerror(errno));
+ warning("Could not close %s: %s\n", destfile, os::strerror(errno));
}
}
}
@@ -311,7 +311,7 @@
if (errno == ELOOP) {
warning("directory %s is a symlink and is not secure\n", dirname);
} else {
- warning("could not open directory %s: %s\n", dirname, strerror(errno));
+ warning("could not open directory %s: %s\n", dirname, os::strerror(errno));
}
}
return dirp;
@@ -422,7 +422,7 @@
RESTARTABLE(::fstat(fd, &statbuf), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("fstat failed on %s: %s\n", filename, strerror(errno));
+ warning("fstat failed on %s: %s\n", filename, os::strerror(errno));
}
return false;
}
@@ -464,7 +464,7 @@
if (PrintMiscellaneous && Verbose) {
if (p == NULL) {
warning("Could not retrieve passwd entry: %s\n",
- strerror(errno));
+ os::strerror(errno));
}
else {
warning("Could not determine user name: %s\n",
@@ -500,7 +500,7 @@
"Process not found");
}
else /* EPERM */ {
- THROW_MSG_0(vmSymbols::java_io_IOException(), strerror(errno));
+ THROW_MSG_0(vmSymbols::java_io_IOException(), os::strerror(errno));
}
}
@@ -657,7 +657,7 @@
// In this case, the psinfo file for the process id existed,
// but we didn't have permission to access it.
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
- strerror(errno));
+ os::strerror(errno));
}
// at this point, we don't know if the process id itself doesn't
@@ -703,7 +703,7 @@
if (PrintMiscellaneous && Verbose && result == OS_ERR) {
if (errno != ENOENT) {
warning("Could not unlink shared memory backing"
- " store file %s : %s\n", path, strerror(errno));
+ " store file %s : %s\n", path, os::strerror(errno));
}
}
}
@@ -813,7 +813,7 @@
//
if (PrintMiscellaneous && Verbose) {
warning("could not create directory %s: %s\n",
- dirname, strerror(errno));
+ dirname, os::strerror(errno));
}
return false;
}
@@ -855,7 +855,7 @@
if (errno == ELOOP) {
warning("file %s is a symlink and is not secure\n", filename);
} else {
- warning("could not create file %s: %s\n", filename, strerror(errno));
+ warning("could not create file %s: %s\n", filename, os::strerror(errno));
}
}
// close the directory and reset the current working directory
@@ -879,7 +879,7 @@
RESTARTABLE(::ftruncate(fd, (off_t)0), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("could not truncate shared memory file: %s\n", strerror(errno));
+ warning("could not truncate shared memory file: %s\n", os::strerror(errno));
}
::close(fd);
return -1;
@@ -888,7 +888,7 @@
RESTARTABLE(::ftruncate(fd, (off_t)size), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("could not set shared memory file size: %s\n", strerror(errno));
+ warning("could not set shared memory file size: %s\n", os::strerror(errno));
}
::close(fd);
return -1;
@@ -916,7 +916,7 @@
"Permission denied", OS_ERR);
}
else {
- THROW_MSG_(vmSymbols::java_io_IOException(), strerror(errno), OS_ERR);
+ THROW_MSG_(vmSymbols::java_io_IOException(), os::strerror(errno), OS_ERR);
}
}
int fd = result;
@@ -990,7 +990,7 @@
if (mapAddress == MAP_FAILED) {
if (PrintMiscellaneous && Verbose) {
- warning("mmap failed - %s\n", strerror(errno));
+ warning("mmap failed - %s\n", os::strerror(errno));
}
remove_file(filename);
FREE_C_HEAP_ARRAY(char, filename);
@@ -1055,7 +1055,7 @@
RESTARTABLE(::fstat(fd, &statbuf), result);
if (result == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("fstat failed: %s\n", strerror(errno));
+ warning("fstat failed: %s\n", os::strerror(errno));
}
THROW_MSG_0(vmSymbols::java_io_IOException(),
"Could not determine PerfMemory size");
@@ -1172,7 +1172,7 @@
if (mapAddress == MAP_FAILED) {
if (PrintMiscellaneous && Verbose) {
- warning("mmap failed: %s\n", strerror(errno));
+ warning("mmap failed: %s\n", os::strerror(errno));
}
THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
"Could not map PerfMemory");
--- a/hotspot/src/os/solaris/vm/threadCritical_solaris.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/os/solaris/vm/threadCritical_solaris.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "runtime/os.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/threadCritical.hpp"
@@ -49,7 +50,7 @@
if (global_mut_owner != owner) {
if (os::Solaris::mutex_lock(&global_mut))
fatal("ThreadCritical::ThreadCritical: mutex_lock failed (%s)",
- strerror(errno));
+ os::strerror(errno));
assert(global_mut_count == 0, "must have clean count");
assert(global_mut_owner == -1, "must have clean owner");
}
@@ -68,7 +69,7 @@
if (global_mut_count == 0) {
global_mut_owner = -1;
if (os::Solaris::mutex_unlock(&global_mut))
- fatal("ThreadCritical::~ThreadCritical: mutex_unlock failed (%s)", strerror(errno));
+ fatal("ThreadCritical::~ThreadCritical: mutex_unlock failed (%s)", os::strerror(errno));
}
} else {
assert (Threads::number_of_threads() == 0, "valid only during initialization");
--- a/hotspot/src/os/windows/vm/os_windows.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -642,7 +642,7 @@
thread_id, describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag));
} else {
log_warning(os, thread)("Failed to start thread - _beginthreadex failed (%s) for attributes: %s.",
- strerror(errno), describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag));
+ os::errno_name(errno), describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag));
}
if (thread_handle == NULL) {
@@ -1898,7 +1898,7 @@
if (errno != 0) {
// C runtime error that has no corresponding DOS error code
- const char* s = strerror(errno);
+ const char* s = os::strerror(errno);
size_t n = strlen(s);
if (n >= len) n = len - 1;
strncpy(buf, s, n);
@@ -2186,13 +2186,6 @@
// Windows Vista/2008 heap corruption check
#define EXCEPTION_HEAP_CORRUPTION 0xC0000374
-#define def_excpt(val) #val, val
-
-struct siglabel {
- char *name;
- int number;
-};
-
// All Visual C++ exceptions thrown from code generated by the Microsoft Visual
// C++ compiler contain this error code. Because this is a compiler-generated
// error, the code is not listed in the Win32 API header files.
@@ -2202,8 +2195,9 @@
#define EXCEPTION_UNCAUGHT_CXX_EXCEPTION 0xE06D7363
-
-struct siglabel exceptlabels[] = {
+#define def_excpt(val) { #val, (val) }
+
+static const struct { char* name; uint number; } exceptlabels[] = {
def_excpt(EXCEPTION_ACCESS_VIOLATION),
def_excpt(EXCEPTION_DATATYPE_MISALIGNMENT),
def_excpt(EXCEPTION_BREAKPOINT),
@@ -2228,16 +2222,18 @@
def_excpt(EXCEPTION_GUARD_PAGE),
def_excpt(EXCEPTION_INVALID_HANDLE),
def_excpt(EXCEPTION_UNCAUGHT_CXX_EXCEPTION),
- def_excpt(EXCEPTION_HEAP_CORRUPTION),
+ def_excpt(EXCEPTION_HEAP_CORRUPTION)
#ifdef _M_IA64
- def_excpt(EXCEPTION_REG_NAT_CONSUMPTION),
+ , def_excpt(EXCEPTION_REG_NAT_CONSUMPTION)
#endif
- NULL, 0
};
+#undef def_excpt
+
const char* os::exception_name(int exception_code, char *buf, size_t size) {
- for (int i = 0; exceptlabels[i].name != NULL; i++) {
- if (exceptlabels[i].number == exception_code) {
+ uint code = static_cast<uint>(exception_code);
+ for (uint i = 0; i < ARRAY_SIZE(exceptlabels); ++i) {
+ if (exceptlabels[i].number == code) {
jio_snprintf(buf, size, "%s", exceptlabels[i].name);
return buf;
}
@@ -2445,7 +2441,7 @@
jio_snprintf(buf, sizeof(buf), "Execution protection violation "
"at " INTPTR_FORMAT
", unguarding " INTPTR_FORMAT ": %s", addr,
- page_start, (res ? "success" : strerror(errno)));
+ page_start, (res ? "success" : os::strerror(errno)));
tty->print_raw_cr(buf);
}
@@ -5638,9 +5634,11 @@
"TERM", SIGTERM, // software term signal from kill
"BREAK", SIGBREAK, // Ctrl-Break sequence
"ILL", SIGILL}; // illegal instruction
- for(int i=0;i<sizeof(siglabels)/sizeof(struct siglabel);i++)
- if(!strcmp(name, siglabels[i].name))
+ for (unsigned i = 0; i < ARRAY_SIZE(siglabels); ++i) {
+ if (strcmp(name, siglabels[i].name) == 0) {
return siglabels[i].number;
+ }
+ }
return -1;
}
--- a/hotspot/src/os/windows/vm/perfMemory_windows.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/os/windows/vm/perfMemory_windows.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -96,7 +96,7 @@
if (fd == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
warning("Could not create Perfdata save file: %s: %s\n",
- destfile, strerror(errno));
+ destfile, os::strerror(errno));
}
} else {
for (size_t remaining = size; remaining > 0;) {
@@ -105,7 +105,7 @@
if (nbytes == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
warning("Could not write Perfdata save file: %s: %s\n",
- destfile, strerror(errno));
+ destfile, os::strerror(errno));
}
break;
}
@@ -117,7 +117,7 @@
int result = ::_close(fd);
if (PrintMiscellaneous && Verbose) {
if (result == OS_ERR) {
- warning("Could not close %s: %s\n", destfile, strerror(errno));
+ warning("Could not close %s: %s\n", destfile, os::strerror(errno));
}
}
}
@@ -497,7 +497,7 @@
if (PrintMiscellaneous && Verbose) {
if (errno != ENOENT) {
warning("Could not unlink shared memory backing"
- " store file %s : %s\n", path, strerror(errno));
+ " store file %s : %s\n", path, os::strerror(errno));
}
}
}
@@ -1358,7 +1358,7 @@
if (ret_code == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
warning("Could not get status information from file %s: %s\n",
- filename, strerror(errno));
+ filename, os::strerror(errno));
}
CloseHandle(fmh);
CloseHandle(fh);
@@ -1553,7 +1553,7 @@
//
if (::stat(filename, &statbuf) == OS_ERR) {
if (PrintMiscellaneous && Verbose) {
- warning("stat %s failed: %s\n", filename, strerror(errno));
+ warning("stat %s failed: %s\n", filename, os::strerror(errno));
}
THROW_MSG_0(vmSymbols::java_io_IOException(),
"Could not determine PerfMemory size");
--- a/hotspot/src/share/vm/ci/ciReplay.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/ci/ciReplay.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,4 +1,5 @@
-/* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+/*
+ * Copyright (c) 2013, 2016, 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
@@ -28,6 +29,7 @@
#include "ci/ciKlass.hpp"
#include "ci/ciUtilities.hpp"
#include "compiler/compileBroker.hpp"
+#include "gc/shared/referencePendingListLocker.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
@@ -574,7 +576,7 @@
Method* method = parse_method(CHECK);
if (had_error()) return;
/* just copied from Method, to build interpret data*/
- if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) {
+ if (ReferencePendingListLocker::is_locked_by_self()) {
return;
}
// To be properly initialized, some profiling in the MDO needs the
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -5358,12 +5358,12 @@
ik->print_loading_log(LogLevel::Debug, _loader_data, _stream);
}
- if (log_is_enabled(Info, classresolve)) {
+ if (log_is_enabled(Debug, classresolve)) {
ResourceMark rm;
// print out the superclass.
const char * from = ik->external_name();
if (ik->java_super() != NULL) {
- log_info(classresolve)("%s %s (super)",
+ log_debug(classresolve)("%s %s (super)",
from,
ik->java_super()->external_name());
}
@@ -5374,7 +5374,7 @@
for (int i = 0; i < length; i++) {
const Klass* const k = local_interfaces->at(i);
const char * to = k->external_name();
- log_info(classresolve)("%s %s (interface)", from, to);
+ log_debug(classresolve)("%s %s (interface)", from, to);
}
}
}
@@ -5684,15 +5684,16 @@
}
if (!is_internal()) {
- if (TraceClassLoadingPreorder) {
- tty->print("[Loading %s",
- _class_name->as_klass_external_name());
-
+ if (log_is_enabled(Debug, classload, preorder)){
+ ResourceMark rm(THREAD);
+ outputStream* log = LogHandle(classload, preorder)::debug_stream();
+ log->print("%s", _class_name->as_klass_external_name());
if (stream->source() != NULL) {
- tty->print(" from %s", stream->source());
+ log->print(" source: %s", stream->source());
}
- tty->print_cr("]");
+ log->cr();
}
+
#if INCLUDE_CDS
if (DumpLoadedClassList != NULL && stream->source() != NULL && classlist_file->is_open()) {
// Only dump the classes that can be stored into CDS archive
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1439,6 +1439,12 @@
compute_offset(_ngroups_offset, k, vmSymbols::ngroups_name(), vmSymbols::int_signature());
}
+
+void java_lang_Throwable::compute_offsets() {
+ Klass* k = SystemDictionary::Throwable_klass();
+ compute_offset(depth_offset, k, vmSymbols::depth_name(), vmSymbols::int_signature());
+}
+
oop java_lang_Throwable::unassigned_stacktrace() {
InstanceKlass* ik = SystemDictionary::Throwable_klass();
address addr = ik->static_field_addr(static_unassigned_stacktrace_offset);
@@ -1458,11 +1464,13 @@
throwable->release_obj_field_put(backtrace_offset, value);
}
-
-oop java_lang_Throwable::message(oop throwable) {
- return throwable->obj_field(detailMessage_offset);
-}
-
+int java_lang_Throwable::depth(oop throwable) {
+ return throwable->int_field(depth_offset);
+}
+
+void java_lang_Throwable::set_depth(oop throwable, int value) {
+ throwable->int_field_put(depth_offset, value);
+}
oop java_lang_Throwable::message(Handle throwable) {
return throwable->obj_field(detailMessage_offset);
@@ -1512,10 +1520,12 @@
return method != NULL && (method->constants()->version() == version);
}
+
// This class provides a simple wrapper over the internal structure of
// exception backtrace to insulate users of the backtrace from needing
// to know what it looks like.
class BacktraceBuilder: public StackObj {
+ friend class BacktraceIterator;
private:
Handle _backtrace;
objArrayOop _head;
@@ -1526,8 +1536,6 @@
int _index;
NoSafepointVerifier _nsv;
- public:
-
enum {
trace_methods_offset = java_lang_Throwable::trace_methods_offset,
trace_bcis_offset = java_lang_Throwable::trace_bcis_offset,
@@ -1560,6 +1568,8 @@
return cprefs;
}
+ public:
+
// constructor for new backtrace
BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _mirrors(NULL), _cprefs(NULL) {
expand(CHECK);
@@ -1645,9 +1655,68 @@
};
+struct BacktraceElement : public StackObj {
+ int _method_id;
+ int _bci;
+ int _version;
+ int _cpref;
+ Handle _mirror;
+ BacktraceElement(Handle mirror, int mid, int version, int bci, int cpref) :
+ _mirror(mirror), _method_id(mid), _version(version), _bci(bci), _cpref(cpref) {}
+};
+
+class BacktraceIterator : public StackObj {
+ int _index;
+ objArrayHandle _result;
+ objArrayHandle _mirrors;
+ typeArrayHandle _methods;
+ typeArrayHandle _bcis;
+ typeArrayHandle _cprefs;
+
+ void init(objArrayHandle result, Thread* thread) {
+ // Get method id, bci, version and mirror from chunk
+ _result = result;
+ if (_result.not_null()) {
+ _methods = typeArrayHandle(thread, BacktraceBuilder::get_methods(_result));
+ _bcis = typeArrayHandle(thread, BacktraceBuilder::get_bcis(_result));
+ _mirrors = objArrayHandle(thread, BacktraceBuilder::get_mirrors(_result));
+ _cprefs = typeArrayHandle(thread, BacktraceBuilder::get_cprefs(_result));
+ _index = 0;
+ }
+ }
+ public:
+ BacktraceIterator(objArrayHandle result, Thread* thread) {
+ init(result, thread);
+ assert(_methods.is_null() || _methods->length() == java_lang_Throwable::trace_chunk_size, "lengths don't match");
+ }
+
+ BacktraceElement next(Thread* thread) {
+ BacktraceElement e (Handle(thread, _mirrors->obj_at(_index)),
+ _methods->short_at(_index),
+ Backtrace::version_at(_bcis->int_at(_index)),
+ Backtrace::bci_at(_bcis->int_at(_index)),
+ _cprefs->short_at(_index));
+ _index++;
+
+ if (_index >= java_lang_Throwable::trace_chunk_size) {
+ int next_offset = java_lang_Throwable::trace_next_offset;
+ // Get next chunk
+ objArrayHandle result (thread, objArrayOop(_result->obj_at(next_offset)));
+ init(result, thread);
+ }
+ return e;
+ }
+
+ bool repeat() {
+ return _result.not_null() && _mirrors->obj_at(_index) != NULL;
+ }
+};
+
+
// Print stack trace element to resource allocated buffer
-char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror,
- int method_id, int version, int bci, int cpref) {
+static void print_stack_element_to_stream(outputStream* st, Handle mirror, int method_id,
+ int version, int bci, int cpref) {
+ ResourceMark rm;
// Get strings and string lengths
InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror()));
@@ -1698,26 +1767,16 @@
}
}
- return buf;
-}
-
-void java_lang_Throwable::print_stack_element(outputStream *st, Handle mirror,
- int method_id, int version, int bci, int cpref) {
- ResourceMark rm;
- char* buf = print_stack_element_to_buffer(mirror, method_id, version, bci, cpref);
st->print_cr("%s", buf);
}
+
void java_lang_Throwable::print_stack_element(outputStream *st, const methodHandle& method, int bci) {
Handle mirror = method->method_holder()->java_mirror();
int method_id = method->orig_method_idnum();
int version = method->constants()->version();
int cpref = method->name_index();
- print_stack_element(st, mirror, method_id, version, bci, cpref);
-}
-
-const char* java_lang_Throwable::no_stack_trace_message() {
- return "\t<<no stack trace available>>";
+ print_stack_element_to_stream(st, mirror, method_id, version, bci, cpref);
}
/**
@@ -1734,32 +1793,17 @@
while (throwable.not_null()) {
objArrayHandle result (THREAD, objArrayOop(backtrace(throwable())));
if (result.is_null()) {
- st->print_raw_cr(no_stack_trace_message());
+ st->print_raw_cr("\t<<no stack trace available>>");
return;
}
-
- while (result.not_null()) {
- // Get method id, bci, version and mirror from chunk
- typeArrayHandle methods (THREAD, BacktraceBuilder::get_methods(result));
- typeArrayHandle bcis (THREAD, BacktraceBuilder::get_bcis(result));
- objArrayHandle mirrors (THREAD, BacktraceBuilder::get_mirrors(result));
- typeArrayHandle cprefs (THREAD, BacktraceBuilder::get_cprefs(result));
-
- int length = methods()->length();
- for (int index = 0; index < length; index++) {
- Handle mirror(THREAD, mirrors->obj_at(index));
- // NULL mirror means end of stack trace
- if (mirror.is_null()) goto handle_cause;
- int method = methods->short_at(index);
- int version = Backtrace::version_at(bcis->int_at(index));
- int bci = Backtrace::bci_at(bcis->int_at(index));
- int cpref = cprefs->short_at(index);
- print_stack_element(st, mirror, method, version, bci, cpref);
- }
- result = objArrayHandle(THREAD, objArrayOop(result->obj_at(trace_next_offset)));
+ BacktraceIterator iter(result, THREAD);
+
+ while (iter.repeat()) {
+ BacktraceElement bte = iter.next(THREAD);
+ print_stack_element_to_stream(st, bte._mirror, bte._method_id, bte._version, bte._bci, bte._cpref);
}
- handle_cause:
{
+ // Call getCause() which doesn't necessarily return the _cause field.
EXCEPTION_MARK;
JavaValue cause(T_OBJECT);
JavaCalls::call_virtual(&cause,
@@ -1811,6 +1855,7 @@
int max_depth = MaxJavaStackTraceDepth;
JavaThread* thread = (JavaThread*)THREAD;
+
BacktraceBuilder bt(CHECK);
// If there is no Java frame just return the method that was being called
@@ -1818,6 +1863,8 @@
if (!thread->has_last_Java_frame()) {
if (max_depth >= 1 && method() != NULL) {
bt.push(method(), 0, CHECK);
+ log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), 1);
+ set_depth(throwable(), 1);
set_backtrace(throwable(), bt.backtrace());
}
return;
@@ -1925,8 +1972,11 @@
total_count++;
}
+ log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), total_count);
+
// Put completed stack trace into throwable object
set_backtrace(throwable(), bt.backtrace());
+ set_depth(throwable(), total_count);
}
void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHandle& method) {
@@ -1980,94 +2030,60 @@
// methods as preallocated errors aren't created by "java" code.
// fill in as much stack trace as possible
- typeArrayOop methods = BacktraceBuilder::get_methods(backtrace);
- int max_chunks = MIN2(methods->length(), (int)MaxJavaStackTraceDepth);
int chunk_count = 0;
-
for (;!st.at_end(); st.next()) {
bt.push(st.method(), st.bci(), CHECK);
chunk_count++;
// Bail-out for deep stacks
- if (chunk_count >= max_chunks) break;
+ if (chunk_count >= trace_chunk_size) break;
}
+ set_depth(throwable(), chunk_count);
+ log_info(stacktrace)("%s, %d", throwable->klass()->external_name(), chunk_count);
// We support the Throwable immutability protocol defined for Java 7.
java_lang_Throwable::set_stacktrace(throwable(), java_lang_Throwable::unassigned_stacktrace());
assert(java_lang_Throwable::unassigned_stacktrace() != NULL, "not initialized");
}
-
-int java_lang_Throwable::get_stack_trace_depth(oop throwable, TRAPS) {
- if (throwable == NULL) {
- THROW_0(vmSymbols::java_lang_NullPointerException());
+void java_lang_Throwable::get_stack_trace_elements(Handle throwable,
+ objArrayHandle stack_trace_array_h, TRAPS) {
+
+ if (throwable.is_null() || stack_trace_array_h.is_null()) {
+ THROW(vmSymbols::java_lang_NullPointerException());
}
- objArrayOop chunk = objArrayOop(backtrace(throwable));
- int depth = 0;
- if (chunk != NULL) {
- // Iterate over chunks and count full ones
- while (true) {
- objArrayOop next = objArrayOop(chunk->obj_at(trace_next_offset));
- if (next == NULL) break;
- depth += trace_chunk_size;
- chunk = next;
- }
- assert(chunk != NULL && chunk->obj_at(trace_next_offset) == NULL, "sanity check");
- // Count element in remaining partial chunk. NULL value for mirror
- // marks the end of the stack trace elements that are saved.
- objArrayOop mirrors = BacktraceBuilder::get_mirrors(chunk);
- assert(mirrors != NULL, "sanity check");
- for (int i = 0; i < mirrors->length(); i++) {
- if (mirrors->obj_at(i) == NULL) break;
- depth++;
- }
- }
- return depth;
-}
-
-
-oop java_lang_Throwable::get_stack_trace_element(oop throwable, int index, TRAPS) {
- if (throwable == NULL) {
- THROW_0(vmSymbols::java_lang_NullPointerException());
- }
- if (index < 0) {
- THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL);
+
+ assert(stack_trace_array_h->is_objArray(), "Stack trace array should be an array of StackTraceElenent");
+
+ if (stack_trace_array_h->length() != depth(throwable())) {
+ THROW(vmSymbols::java_lang_IndexOutOfBoundsException());
}
- // Compute how many chunks to skip and index into actual chunk
- objArrayOop chunk = objArrayOop(backtrace(throwable));
- int skip_chunks = index / trace_chunk_size;
- int chunk_index = index % trace_chunk_size;
- while (chunk != NULL && skip_chunks > 0) {
- chunk = objArrayOop(chunk->obj_at(trace_next_offset));
- skip_chunks--;
- }
- if (chunk == NULL) {
- THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL);
+
+ objArrayHandle result(THREAD, objArrayOop(backtrace(throwable())));
+ BacktraceIterator iter(result, THREAD);
+
+ int index = 0;
+ while (iter.repeat()) {
+ BacktraceElement bte = iter.next(THREAD);
+
+ Handle stack_trace_element(THREAD, stack_trace_array_h->obj_at(index++));
+
+ if (stack_trace_element.is_null()) {
+ THROW(vmSymbols::java_lang_NullPointerException());
+ }
+
+ InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(bte._mirror()));
+ methodHandle method (THREAD, holder->method_with_orig_idnum(bte._method_id, bte._version));
+
+ java_lang_StackTraceElement::fill_in(stack_trace_element, holder,
+ method,
+ bte._version,
+ bte._bci,
+ bte._cpref, CHECK);
}
- // Get method id, bci, version, mirror and cpref from chunk
- typeArrayOop methods = BacktraceBuilder::get_methods(chunk);
- typeArrayOop bcis = BacktraceBuilder::get_bcis(chunk);
- objArrayOop mirrors = BacktraceBuilder::get_mirrors(chunk);
- typeArrayOop cprefs = BacktraceBuilder::get_cprefs(chunk);
-
- assert(methods != NULL && bcis != NULL && mirrors != NULL, "sanity check");
-
- int method = methods->short_at(chunk_index);
- int version = Backtrace::version_at(bcis->int_at(chunk_index));
- int bci = Backtrace::bci_at(bcis->int_at(chunk_index));
- int cpref = cprefs->short_at(chunk_index);
- Handle mirror(THREAD, mirrors->obj_at(chunk_index));
-
- // Chunk can be partial full
- if (mirror.is_null()) {
- THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL);
- }
- oop element = java_lang_StackTraceElement::create(mirror, method, version, bci, cpref, CHECK_0);
- return element;
-}
-
-oop java_lang_StackTraceElement::create(Handle mirror, int method_id,
- int version, int bci, int cpref, TRAPS) {
+}
+
+oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, TRAPS) {
// Allocate java.lang.StackTraceElement instance
Klass* k = SystemDictionary::StackTraceElement_klass();
assert(k != NULL, "must be loaded in 1.4+");
@@ -2078,23 +2094,31 @@
Handle element = ik->allocate_instance_handle(CHECK_0);
+ int cpref = method->name_index();
+ int version = method->constants()->version();
+ fill_in(element, method->method_holder(), method, version, bci, cpref, CHECK_0);
+ return element();
+}
+
+void java_lang_StackTraceElement::fill_in(Handle element,
+ InstanceKlass* holder, const methodHandle& method,
+ int version, int bci, int cpref, TRAPS) {
+ assert(element->is_a(SystemDictionary::StackTraceElement_klass()), "sanity check");
+
// Fill in class name
ResourceMark rm(THREAD);
- InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror()));
const char* str = holder->external_name();
- oop classname = StringTable::intern((char*) str, CHECK_0);
+ oop classname = StringTable::intern((char*) str, CHECK);
java_lang_StackTraceElement::set_declaringClass(element(), classname);
- Method* method = holder->method_with_orig_idnum(method_id, version);
-
// The method can be NULL if the requested class version is gone
- Symbol* sym = (method != NULL) ? method->name() : holder->constants()->symbol_at(cpref);
+ Symbol* sym = !method.is_null() ? method->name() : holder->constants()->symbol_at(cpref);
// Fill in method name
- oop methodname = StringTable::intern(sym, CHECK_0);
+ oop methodname = StringTable::intern(sym, CHECK);
java_lang_StackTraceElement::set_methodName(element(), methodname);
- if (!version_matches(method, version)) {
+ if (!version_matches(method(), version)) {
// The method was redefined, accurate line number information isn't available
java_lang_StackTraceElement::set_fileName(element(), NULL);
java_lang_StackTraceElement::set_lineNumber(element(), -1);
@@ -2103,20 +2127,12 @@
Symbol* source = Backtrace::get_source_file_name(holder, version);
if (ShowHiddenFrames && source == NULL)
source = vmSymbols::unknown_class_name();
- oop filename = StringTable::intern(source, CHECK_0);
+ oop filename = StringTable::intern(source, CHECK);
java_lang_StackTraceElement::set_fileName(element(), filename);
int line_number = Backtrace::get_line_number(method, bci);
java_lang_StackTraceElement::set_lineNumber(element(), line_number);
}
- return element();
-}
-
-oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, TRAPS) {
- Handle mirror (THREAD, method->method_holder()->java_mirror());
- int method_id = method->orig_method_idnum();
- int cpref = method->name_index();
- return create(mirror, method_id, method->constants()->version(), bci, cpref, THREAD);
}
Method* java_lang_StackFrameInfo::get_method(Handle stackFrame, InstanceKlass* holder, TRAPS) {
@@ -3477,8 +3493,8 @@
GrowableArray<Klass*>* java_lang_Class::_fixup_mirror_list = NULL;
int java_lang_Throwable::backtrace_offset;
int java_lang_Throwable::detailMessage_offset;
-int java_lang_Throwable::cause_offset;
int java_lang_Throwable::stackTrace_offset;
+int java_lang_Throwable::depth_offset;
int java_lang_Throwable::static_unassigned_stacktrace_offset;
int java_lang_reflect_AccessibleObject::override_offset;
int java_lang_reflect_Method::clazz_offset;
@@ -3679,7 +3695,6 @@
// Throwable Class
java_lang_Throwable::backtrace_offset = java_lang_Throwable::hc_backtrace_offset * x + header;
java_lang_Throwable::detailMessage_offset = java_lang_Throwable::hc_detailMessage_offset * x + header;
- java_lang_Throwable::cause_offset = java_lang_Throwable::hc_cause_offset * x + header;
java_lang_Throwable::stackTrace_offset = java_lang_Throwable::hc_stackTrace_offset * x + header;
java_lang_Throwable::static_unassigned_stacktrace_offset = java_lang_Throwable::hc_static_unassigned_stacktrace_offset * x;
@@ -3730,6 +3745,7 @@
void JavaClasses::compute_offsets() {
// java_lang_Class::compute_offsets was called earlier in bootstrap
java_lang_ClassLoader::compute_offsets();
+ java_lang_Throwable::compute_offsets();
java_lang_Thread::compute_offsets();
java_lang_ThreadGroup::compute_offsets();
java_lang_invoke_MethodHandle::compute_offsets();
@@ -3883,8 +3899,8 @@
CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, backtrace, "Ljava/lang/Object;");
CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, detailMessage, "Ljava/lang/String;");
- CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, cause, "Ljava/lang/Throwable;");
CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, stackTrace, "[Ljava/lang/StackTraceElement;");
+ CHECK_OFFSET("java/lang/Throwable", java_lang_Throwable, depth, "I");
// Boxed primitive objects (java_lang_boxing_object)
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -440,6 +440,7 @@
class java_lang_Throwable: AllStatic {
friend class BacktraceBuilder;
+ friend class BacktraceIterator;
private:
// Offsets
@@ -465,16 +466,12 @@
static int backtrace_offset;
static int detailMessage_offset;
- static int cause_offset;
static int stackTrace_offset;
+ static int depth_offset;
static int static_unassigned_stacktrace_offset;
- // Printing
- static char* print_stack_element_to_buffer(Handle mirror, int method, int version, int bci, int cpref);
// StackTrace (programmatic access, new since 1.4)
static void clear_stacktrace(oop throwable);
- // No stack trace available
- static const char* no_stack_trace_message();
// Stacktrace (post JDK 1.7.0 to allow immutability protocol to be followed)
static void set_stacktrace(oop throwable, oop st_element_array);
static oop unassigned_stacktrace();
@@ -483,19 +480,20 @@
// Backtrace
static oop backtrace(oop throwable);
static void set_backtrace(oop throwable, oop value);
+ static int depth(oop throwable);
+ static void set_depth(oop throwable, int value);
// Needed by JVMTI to filter out this internal field.
static int get_backtrace_offset() { return backtrace_offset;}
static int get_detailMessage_offset() { return detailMessage_offset;}
// Message
- static oop message(oop throwable);
static oop message(Handle throwable);
static void set_message(oop throwable, oop value);
static Symbol* detail_message(oop throwable);
- static void print_stack_element(outputStream *st, Handle mirror, int method,
- int version, int bci, int cpref);
static void print_stack_element(outputStream *st, const methodHandle& method, int bci);
static void print_stack_usage(Handle stream);
+ static void compute_offsets();
+
// Allocate space for backtrace (created but stack trace not filled in)
static void allocate_backtrace(Handle throwable, TRAPS);
// Fill in current stack trace for throwable with preallocated backtrace (no GC)
@@ -504,8 +502,7 @@
static void fill_in_stack_trace(Handle throwable, const methodHandle& method, TRAPS);
static void fill_in_stack_trace(Handle throwable, const methodHandle& method = methodHandle());
// Programmatic access to stack trace
- static oop get_stack_trace_element(oop throwable, int index, TRAPS);
- static int get_stack_trace_depth(oop throwable, TRAPS);
+ static void get_stack_trace_elements(Handle throwable, objArrayHandle stack_trace, TRAPS);
// Printing
static void print(Handle throwable, outputStream* st);
static void print_stack_trace(Handle throwable, outputStream* st);
@@ -1277,17 +1274,19 @@
static int fileName_offset;
static int lineNumber_offset;
- public:
// Setters
static void set_declaringClass(oop element, oop value);
static void set_methodName(oop element, oop value);
static void set_fileName(oop element, oop value);
static void set_lineNumber(oop element, int value);
+ public:
// Create an instance of StackTraceElement
- static oop create(Handle mirror, int method, int version, int bci, int cpref, TRAPS);
static oop create(const methodHandle& method, int bci, TRAPS);
+ static void fill_in(Handle element, InstanceKlass* holder, const methodHandle& method,
+ int version, int bci, int cpref, TRAPS);
+
// Debugging
friend class JavaClasses;
};
--- a/hotspot/src/share/vm/classfile/verificationType.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/classfile/verificationType.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -61,7 +61,7 @@
Klass* obj = SystemDictionary::resolve_or_fail(
name(), Handle(THREAD, klass->class_loader()),
Handle(THREAD, klass->protection_domain()), true, CHECK_false);
- if (log_is_enabled(Info, classresolve)) {
+ if (log_is_enabled(Debug, classresolve)) {
Verifier::trace_class_resolution(obj, klass());
}
@@ -80,7 +80,7 @@
Klass* from_class = SystemDictionary::resolve_or_fail(
from.name(), Handle(THREAD, klass->class_loader()),
Handle(THREAD, klass->protection_domain()), true, CHECK_false);
- if (log_is_enabled(Info, classresolve)) {
+ if (log_is_enabled(Debug, classresolve)) {
Verifier::trace_class_resolution(from_class, klass());
}
return InstanceKlass::cast(from_class)->is_subclass_of(this_class());
--- a/hotspot/src/share/vm/classfile/verifier.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/classfile/verifier.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -33,6 +33,7 @@
#include "classfile/vmSymbols.hpp"
#include "interpreter/bytecodes.hpp"
#include "interpreter/bytecodeStream.hpp"
+#include "logging/log.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "oops/instanceKlass.hpp"
@@ -106,9 +107,9 @@
const char* resolve = resolve_class->external_name();
// print in a single call to reduce interleaving between threads
if (source_file != NULL) {
- log_info(classresolve)("%s %s %s (verification)", verify, resolve, source_file);
+ log_debug(classresolve)("%s %s %s (verification)", verify, resolve, source_file);
} else {
- log_info(classresolve)("%s %s (verification)", verify, resolve);
+ log_debug(classresolve)("%s %s (verification)", verify, resolve);
}
}
@@ -176,9 +177,7 @@
if (can_failover && !HAS_PENDING_EXCEPTION &&
(exception_name == vmSymbols::java_lang_VerifyError() ||
exception_name == vmSymbols::java_lang_ClassFormatError())) {
- if (VerboseVerification) {
- tty->print_cr("Fail over class verification to old verifier for: %s", klassName);
- }
+ log_info(verboseverification)("Fail over class verification to old verifier for: %s", klassName);
log_info(classinit)("Fail over class verification to old verifier for: %s", klassName);
exception_name = inference_verify(
klass, message_buffer, message_buffer_len, THREAD);
@@ -194,8 +193,8 @@
if (log_is_enabled(Info, classinit)){
log_end_verification(LogHandle(classinit)::info_stream(), klassName, exception_name, THREAD);
}
- if (VerboseVerification){
- log_end_verification(tty, klassName, exception_name, THREAD);
+ if (log_is_enabled(Info, verboseverification)){
+ log_end_verification(LogHandle(verboseverification)::info_stream(), klassName, exception_name, THREAD);
}
if (HAS_PENDING_EXCEPTION) {
@@ -206,7 +205,7 @@
ResourceMark rm(THREAD);
instanceKlassHandle kls =
SystemDictionary::resolve_or_fail(exception_name, true, CHECK_false);
- if (log_is_enabled(Info, classresolve)) {
+ if (log_is_enabled(Debug, classresolve)) {
Verifier::trace_class_resolution(kls(), klass());
}
@@ -269,9 +268,7 @@
}
ResourceMark rm(THREAD);
- if (VerboseVerification) {
- tty->print_cr("Verifying class %s with old format", klass->external_name());
- }
+ log_info(verboseverification)("Verifying class %s with old format", klass->external_name());
jclass cls = (jclass) JNIHandles::make_local(env, klass->java_mirror());
jint result;
@@ -583,10 +580,7 @@
}
void ClassVerifier::verify_class(TRAPS) {
- if (VerboseVerification) {
- tty->print_cr("Verifying class %s with new format",
- _klass->external_name());
- }
+ log_info(verboseverification)("Verifying class %s with new format", _klass->external_name());
Array<Method*>* methods = _klass->methods();
int num_methods = methods->length();
@@ -606,10 +600,7 @@
}
if (was_recursively_verified()){
- if (VerboseVerification){
- tty->print_cr("Recursive verification detected for: %s",
- _klass->external_name());
- }
+ log_info(verboseverification)("Recursive verification detected for: %s", _klass->external_name());
log_info(classinit)("Recursive verification detected for: %s",
_klass->external_name());
}
@@ -618,9 +609,7 @@
void ClassVerifier::verify_method(const methodHandle& m, TRAPS) {
HandleMark hm(THREAD);
_method = m; // initialize _method
- if (VerboseVerification) {
- tty->print_cr("Verifying method %s", m->name_and_sig_as_C_string());
- }
+ log_info(verboseverification)("Verifying method %s", m->name_and_sig_as_C_string());
// For clang, the only good constant format string is a literal constant format string.
#define bad_type_msg "Bad type on operand stack in %s"
@@ -667,8 +656,9 @@
StackMapTable stackmap_table(&reader, ¤t_frame, max_locals, max_stack,
code_data, code_length, CHECK_VERIFY(this));
- if (VerboseVerification) {
- stackmap_table.print_on(tty);
+ if (log_is_enabled(Info, verboseverification)) {
+ ResourceMark rm(THREAD);
+ stackmap_table.print_on(LogHandle(verboseverification)::info_stream());
}
RawBytecodeStream bcs(m);
@@ -708,12 +698,11 @@
VerificationType type, type2;
VerificationType atype;
-#ifndef PRODUCT
- if (VerboseVerification) {
- current_frame.print_on(tty);
- tty->print_cr("offset = %d, opcode = %s", bci, Bytecodes::name(opcode));
+ if (log_is_enabled(Info, verboseverification)) {
+ ResourceMark rm(THREAD);
+ current_frame.print_on(LogHandle(verboseverification)::info_stream());
+ log_info(verboseverification)("offset = %d, opcode = %s", bci, Bytecodes::name(opcode));
}
-#endif
// Make sure wide instruction is in correct format
if (bcs.is_wide()) {
@@ -2005,7 +1994,7 @@
name, Handle(THREAD, loader), Handle(THREAD, protection_domain),
true, THREAD);
- if (log_is_enabled(Info, classresolve)) {
+ if (log_is_enabled(Debug, classresolve)) {
instanceKlassHandle cur_class = current_class();
Verifier::trace_class_resolution(kls, cur_class());
}
@@ -2533,11 +2522,10 @@
verify_error(ErrorContext::bad_code(bci),
"Bad <init> method call from after the start of a try block");
return;
- } else if (VerboseVerification) {
- ResourceMark rm;
- tty->print_cr(
- "Survived call to ends_in_athrow(): %s",
- current_class()->name()->as_C_string());
+ } else if (log_is_enabled(Info, verboseverification)) {
+ ResourceMark rm(THREAD);
+ log_info(verboseverification)("Survived call to ends_in_athrow(): %s",
+ current_class()->name()->as_C_string());
}
}
}
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -376,6 +376,7 @@
template(fillInStackTrace_name, "fillInStackTrace") \
template(getCause_name, "getCause") \
template(initCause_name, "initCause") \
+ template(depth_name, "depth") \
template(setProperty_name, "setProperty") \
template(getProperty_name, "getProperty") \
template(context_name, "context") \
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, 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
@@ -32,6 +32,7 @@
#include "compiler/compileLog.hpp"
#include "compiler/compilerOracle.hpp"
#include "compiler/directivesParser.hpp"
+#include "gc/shared/referencePendingListLocker.hpp"
#include "interpreter/linkResolver.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/methodData.hpp"
@@ -904,7 +905,7 @@
// the pending list lock or a 3-way deadlock may occur
// between the reference handler thread, a GC (instigated
// by a compiler thread), and compiled method registration.
- if (InstanceRefKlass::owns_pending_list_lock(JavaThread::current())) {
+ if (ReferencePendingListLocker::is_locked_by_self()) {
return;
}
@@ -1309,7 +1310,7 @@
* has been fulfilled?
*/
bool CompileBroker::is_compile_blocking() {
- assert(!InstanceRefKlass::owns_pending_list_lock(JavaThread::current()), "possible deadlock");
+ assert(!ReferencePendingListLocker::is_locked_by_self(), "possible deadlock");
return !BackgroundCompilation;
}
--- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1931,11 +1931,6 @@
if (blk->_ptr == NULL) {
refillLinearAllocBlock(blk);
}
- if (PrintMiscellaneous && Verbose) {
- if (blk->_word_size == 0) {
- warning("CompactibleFreeListSpace(prologue):: Linear allocation failure");
- }
- }
}
void
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -502,7 +502,7 @@
{
MutexLockerEx x(_markBitMap.lock(), Mutex::_no_safepoint_check_flag);
if (!_markBitMap.allocate(_span)) {
- warning("Failed to allocate CMS Bit Map");
+ log_warning(gc)("Failed to allocate CMS Bit Map");
return;
}
assert(_markBitMap.covers(_span), "_markBitMap inconsistency?");
@@ -513,7 +513,7 @@
}
if (!_markStack.allocate(MarkStackSize)) {
- warning("Failed to allocate CMS Marking Stack");
+ log_warning(gc)("Failed to allocate CMS Marking Stack");
return;
}
@@ -527,8 +527,7 @@
_conc_workers = new YieldingFlexibleWorkGang("CMS Thread",
ConcGCThreads, true);
if (_conc_workers == NULL) {
- warning("GC/CMS: _conc_workers allocation failure: "
- "forcing -CMSConcurrentMTEnabled");
+ log_warning(gc)("GC/CMS: _conc_workers allocation failure: forcing -CMSConcurrentMTEnabled");
CMSConcurrentMTEnabled = false;
} else {
_conc_workers->initialize_workers();
@@ -559,7 +558,7 @@
&& num_queues > 0) {
_task_queues = new OopTaskQueueSet(num_queues);
if (_task_queues == NULL) {
- warning("task_queues allocation failure.");
+ log_warning(gc)("task_queues allocation failure.");
return;
}
_hash_seed = NEW_C_HEAP_ARRAY(int, num_queues, mtGC);
@@ -567,7 +566,7 @@
for (i = 0; i < num_queues; i++) {
PaddedOopTaskQueue *q = new PaddedOopTaskQueue();
if (q == NULL) {
- warning("work_queue allocation failure.");
+ log_warning(gc)("work_queue allocation failure.");
return;
}
_task_queues->register_queue(i, q);
@@ -1413,7 +1412,7 @@
if (_foregroundGCShouldWait) {
// We are going to be waiting for action for the CMS thread;
// it had better not be gone (for instance at shutdown)!
- assert(ConcurrentMarkSweepThread::cmst() != NULL,
+ assert(ConcurrentMarkSweepThread::cmst() != NULL && !ConcurrentMarkSweepThread::cmst()->has_terminated(),
"CMS thread must be running");
// Wait here until the background collector gives us the go-ahead
ConcurrentMarkSweepThread::clear_CMS_flag(
@@ -1519,7 +1518,7 @@
gch->pre_full_gc_dump(gc_timer);
- GCTraceTime(Trace, gc) t("CMS:MSC");
+ GCTraceTime(Trace, gc, phases) t("CMS:MSC");
// Temporarily widen the span of the weak reference processing to
// the entire heap.
@@ -2235,7 +2234,7 @@
};
bool CMSCollector::verify_after_remark() {
- GCTraceTime(Info, gc, verify) tm("Verifying CMS Marking.");
+ GCTraceTime(Info, gc, phases, verify) tm("Verifying CMS Marking.");
MutexLockerEx ml(verification_mark_bm()->lock(), Mutex::_no_safepoint_check_flag);
static bool init = false;
@@ -2287,17 +2286,16 @@
// all marking, then check if the new marks-vector is
// a subset of the CMS marks-vector.
verify_after_remark_work_1();
- } else if (CMSRemarkVerifyVariant == 2) {
+ } else {
+ guarantee(CMSRemarkVerifyVariant == 2, "Range checking for CMSRemarkVerifyVariant should guarantee 1 or 2");
// In this second variant of verification, we flag an error
// (i.e. an object reachable in the new marks-vector not reachable
// in the CMS marks-vector) immediately, also indicating the
// identify of an object (A) that references the unmarked object (B) --
// presumably, a mutation to A failed to be picked up by preclean/remark?
verify_after_remark_work_2();
- } else {
- warning("Unrecognized value " UINTX_FORMAT " for CMSRemarkVerifyVariant",
- CMSRemarkVerifyVariant);
- }
+ }
+
return true;
}
@@ -2820,7 +2818,7 @@
// CMS collection cycle.
setup_cms_unloading_and_verification_state();
- GCTraceTime(Trace, gc) ts("checkpointRootsInitialWork", _gc_timer_cm);
+ GCTraceTime(Trace, gc, phases) ts("checkpointRootsInitialWork", _gc_timer_cm);
// Reset all the PLAB chunk arrays if necessary.
if (_survivor_plab_array != NULL && !CMSPLABRecordAlways) {
@@ -3650,7 +3648,7 @@
// XXX FIX ME!!! YSR
size_t loops = 0, workdone = 0, cumworkdone = 0, waited = 0;
while (!(should_abort_preclean() ||
- ConcurrentMarkSweepThread::should_terminate())) {
+ ConcurrentMarkSweepThread::cmst()->should_terminate())) {
workdone = preclean_work(CMSPrecleanRefLists2, CMSPrecleanSurvivors2);
cumworkdone += workdone;
loops++;
@@ -4104,8 +4102,6 @@
// expect it to be false and set to true
FlagSetting fl(gch->_is_gc_active, false);
- GCTraceTime(Trace, gc) tm("Pause Scavenge Before Remark", _gc_timer_cm);
-
gch->do_collection(true, // full (i.e. force, see below)
false, // !clear_all_soft_refs
0, // size
@@ -4123,7 +4119,7 @@
}
void CMSCollector::checkpointRootsFinalWork() {
- GCTraceTime(Trace, gc) tm("checkpointRootsFinalWork", _gc_timer_cm);
+ GCTraceTime(Trace, gc, phases) tm("checkpointRootsFinalWork", _gc_timer_cm);
assert(haveFreelistLocks(), "must have free list locks");
assert_lock_strong(bitMapLock());
@@ -4173,10 +4169,10 @@
// the most recent young generation GC, minus those cleaned up by the
// concurrent precleaning.
if (CMSParallelRemarkEnabled) {
- GCTraceTime(Debug, gc) t("Rescan (parallel)", _gc_timer_cm);
+ GCTraceTime(Debug, gc, phases) t("Rescan (parallel)", _gc_timer_cm);
do_remark_parallel();
} else {
- GCTraceTime(Debug, gc) t("Rescan (non-parallel)", _gc_timer_cm);
+ GCTraceTime(Debug, gc, phases) t("Rescan (non-parallel)", _gc_timer_cm);
do_remark_non_parallel();
}
}
@@ -4184,7 +4180,7 @@
verify_overflow_empty();
{
- GCTraceTime(Trace, gc) ts("refProcessingWork", _gc_timer_cm);
+ GCTraceTime(Trace, gc, phases) ts("refProcessingWork", _gc_timer_cm);
refProcessingWork();
}
verify_work_stacks_empty();
@@ -4907,7 +4903,7 @@
NULL, // space is set further below
&_markBitMap, &_markStack, &mrias_cl);
{
- GCTraceTime(Trace, gc) t("Grey Object Rescan", _gc_timer_cm);
+ GCTraceTime(Trace, gc, phases) t("Grey Object Rescan", _gc_timer_cm);
// Iterate over the dirty cards, setting the corresponding bits in the
// mod union table.
{
@@ -4941,7 +4937,7 @@
Universe::verify();
}
{
- GCTraceTime(Trace, gc) t("Root Rescan", _gc_timer_cm);
+ GCTraceTime(Trace, gc, phases) t("Root Rescan", _gc_timer_cm);
verify_work_stacks_empty();
@@ -4963,7 +4959,7 @@
}
{
- GCTraceTime(Trace, gc) t("Visit Unhandled CLDs", _gc_timer_cm);
+ GCTraceTime(Trace, gc, phases) t("Visit Unhandled CLDs", _gc_timer_cm);
verify_work_stacks_empty();
@@ -4982,7 +4978,7 @@
}
{
- GCTraceTime(Trace, gc) t("Dirty Klass Scan", _gc_timer_cm);
+ GCTraceTime(Trace, gc, phases) t("Dirty Klass Scan", _gc_timer_cm);
verify_work_stacks_empty();
@@ -5186,7 +5182,7 @@
_span, &_markBitMap, &_markStack,
&cmsKeepAliveClosure, false /* !preclean */);
{
- GCTraceTime(Debug, gc) t("Weak Refs Processing", _gc_timer_cm);
+ GCTraceTime(Debug, gc, phases) t("Reference Processing", _gc_timer_cm);
ReferenceProcessorStats stats;
if (rp->processing_is_mt()) {
@@ -5228,7 +5224,7 @@
if (should_unload_classes()) {
{
- GCTraceTime(Debug, gc) t("Class Unloading", _gc_timer_cm);
+ GCTraceTime(Debug, gc, phases) t("Class Unloading", _gc_timer_cm);
// Unload classes and purge the SystemDictionary.
bool purged_class = SystemDictionary::do_unloading(&_is_alive_closure);
@@ -5241,13 +5237,13 @@
}
{
- GCTraceTime(Debug, gc) t("Scrub Symbol Table", _gc_timer_cm);
+ GCTraceTime(Debug, gc, phases) t("Scrub Symbol Table", _gc_timer_cm);
// Clean up unreferenced symbols in symbol table.
SymbolTable::unlink();
}
{
- GCTraceTime(Debug, gc) t("Scrub String Table", _gc_timer_cm);
+ GCTraceTime(Debug, gc, phases) t("Scrub String Table", _gc_timer_cm);
// Delete entries for dead interned strings.
StringTable::unlink(&_is_alive_closure);
}
@@ -5657,13 +5653,13 @@
ReservedSpace brs(ReservedSpace::allocation_align_size_up(
(_bmWordSize >> (_shifter + LogBitsPerByte)) + 1));
if (!brs.is_reserved()) {
- warning("CMS bit map allocation failure");
+ log_warning(gc)("CMS bit map allocation failure");
return false;
}
// For now we'll just commit all of the bit map up front.
// Later on we'll try to be more parsimonious with swap.
if (!_virtual_space.initialize(brs, brs.size())) {
- warning("CMS bit map backing store failure");
+ log_warning(gc)("CMS bit map backing store failure");
return false;
}
assert(_virtual_space.committed_size() == brs.size(),
@@ -5749,11 +5745,11 @@
ReservedSpace rs(ReservedSpace::allocation_align_size_up(
size * sizeof(oop)));
if (!rs.is_reserved()) {
- warning("CMSMarkStack allocation failure");
+ log_warning(gc)("CMSMarkStack allocation failure");
return false;
}
if (!_virtual_space.initialize(rs, rs.size())) {
- warning("CMSMarkStack backing store failure");
+ log_warning(gc)("CMSMarkStack backing store failure");
return false;
}
assert(_virtual_space.committed_size() == rs.size(),
@@ -7047,13 +7043,13 @@
}
void SweepClosure::print_on(outputStream* st) const {
- tty->print_cr("_sp = [" PTR_FORMAT "," PTR_FORMAT ")",
- p2i(_sp->bottom()), p2i(_sp->end()));
- tty->print_cr("_limit = " PTR_FORMAT, p2i(_limit));
- tty->print_cr("_freeFinger = " PTR_FORMAT, p2i(_freeFinger));
- NOT_PRODUCT(tty->print_cr("_last_fc = " PTR_FORMAT, p2i(_last_fc));)
- tty->print_cr("_inFreeRange = %d, _freeRangeInFreeLists = %d, _lastFreeRangeCoalesced = %d",
- _inFreeRange, _freeRangeInFreeLists, _lastFreeRangeCoalesced);
+ st->print_cr("_sp = [" PTR_FORMAT "," PTR_FORMAT ")",
+ p2i(_sp->bottom()), p2i(_sp->end()));
+ st->print_cr("_limit = " PTR_FORMAT, p2i(_limit));
+ st->print_cr("_freeFinger = " PTR_FORMAT, p2i(_freeFinger));
+ NOT_PRODUCT(st->print_cr("_last_fc = " PTR_FORMAT, p2i(_last_fc));)
+ st->print_cr("_inFreeRange = %d, _freeRangeInFreeLists = %d, _lastFreeRangeCoalesced = %d",
+ _inFreeRange, _freeRangeInFreeLists, _lastFreeRangeCoalesced);
}
#ifndef PRODUCT
@@ -7066,8 +7062,10 @@
assert(_limit >= _sp->bottom() && _limit <= _sp->end(),
"sweep _limit out of bounds");
if (inFreeRange()) {
- warning("inFreeRange() should have been reset; dumping state of SweepClosure");
- print();
+ LogHandle(gc, sweep) log;
+ log.error("inFreeRange() should have been reset; dumping state of SweepClosure");
+ ResourceMark rm;
+ print_on(log.error_stream());
ShouldNotReachHere();
}
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -28,7 +28,7 @@
#include "gc/cms/concurrentMarkSweepThread.hpp"
#include "gc/shared/gcId.hpp"
#include "gc/shared/genCollectedHeap.hpp"
-#include "oops/instanceRefKlass.hpp"
+#include "gc/shared/referencePendingListLocker.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/interfaceSupport.hpp"
@@ -42,16 +42,10 @@
ConcurrentMarkSweepThread* ConcurrentMarkSweepThread::_cmst = NULL;
CMSCollector* ConcurrentMarkSweepThread::_collector = NULL;
-bool ConcurrentMarkSweepThread::_should_terminate = false;
int ConcurrentMarkSweepThread::_CMS_flag = CMS_nil;
volatile jint ConcurrentMarkSweepThread::_pending_yields = 0;
-SurrogateLockerThread* ConcurrentMarkSweepThread::_slt = NULL;
-SurrogateLockerThread::SLT_msg_type
- ConcurrentMarkSweepThread::_sltBuffer = SurrogateLockerThread::empty;
-Monitor* ConcurrentMarkSweepThread::_sltMonitor = NULL;
-
ConcurrentMarkSweepThread::ConcurrentMarkSweepThread(CMSCollector* collector)
: ConcurrentGCThread() {
assert(UseConcMarkSweepGC, "UseConcMarkSweepGC should be set");
@@ -62,88 +56,58 @@
set_name("CMS Main Thread");
- if (os::create_thread(this, os::cgc_thread)) {
- // An old comment here said: "Priority should be just less
- // than that of VMThread". Since the VMThread runs at
- // NearMaxPriority, the old comment was inaccurate, but
- // changing the default priority to NearMaxPriority-1
- // could change current behavior, so the default of
- // NearMaxPriority stays in place.
- //
- // Note that there's a possibility of the VMThread
- // starving if UseCriticalCMSThreadPriority is on.
- // That won't happen on Solaris for various reasons,
- // but may well happen on non-Solaris platforms.
- int native_prio;
- if (UseCriticalCMSThreadPriority) {
- native_prio = os::java_to_os_priority[CriticalPriority];
- } else {
- native_prio = os::java_to_os_priority[NearMaxPriority];
- }
- os::set_native_priority(this, native_prio);
-
- if (!DisableStartThread) {
- os::start_thread(this);
- }
- }
- _sltMonitor = SLT_lock;
+ // An old comment here said: "Priority should be just less
+ // than that of VMThread". Since the VMThread runs at
+ // NearMaxPriority, the old comment was inaccurate, but
+ // changing the default priority to NearMaxPriority-1
+ // could change current behavior, so the default of
+ // NearMaxPriority stays in place.
+ //
+ // Note that there's a possibility of the VMThread
+ // starving if UseCriticalCMSThreadPriority is on.
+ // That won't happen on Solaris for various reasons,
+ // but may well happen on non-Solaris platforms.
+ create_and_start(UseCriticalCMSThreadPriority ? CriticalPriority : NearMaxPriority);
}
-void ConcurrentMarkSweepThread::run() {
+void ConcurrentMarkSweepThread::run_service() {
assert(this == cmst(), "just checking");
- initialize_in_thread();
- // From this time Thread::current() should be working.
- assert(this == Thread::current(), "just checking");
if (BindCMSThreadToCPU && !os::bind_to_processor(CPUForCMSThread)) {
- warning("Couldn't bind CMS thread to processor " UINTX_FORMAT, CPUForCMSThread);
+ log_warning(gc)("Couldn't bind CMS thread to processor " UINTX_FORMAT, CPUForCMSThread);
}
- // Wait until Universe::is_fully_initialized()
+
{
- CMSLoopCountWarn loopX("CMS::run", "waiting for "
- "Universe::is_fully_initialized()", 2);
MutexLockerEx x(CGC_lock, true);
set_CMS_flag(CMS_cms_wants_token);
- // Wait until Universe is initialized and all initialization is completed.
- while (!is_init_completed() && !Universe::is_fully_initialized() &&
- !_should_terminate) {
- CGC_lock->wait(true, 200);
- loopX.tick();
- }
+ assert(is_init_completed() && Universe::is_fully_initialized(), "ConcurrentGCThread::run() should have waited for this.");
+
// Wait until the surrogate locker thread that will do
// pending list locking on our behalf has been created.
// We cannot start the SLT thread ourselves since we need
// to be a JavaThread to do so.
CMSLoopCountWarn loopY("CMS::run", "waiting for SLT installation", 2);
- while (_slt == NULL && !_should_terminate) {
+ while (!ReferencePendingListLocker::is_initialized() && !should_terminate()) {
CGC_lock->wait(true, 200);
loopY.tick();
}
clear_CMS_flag(CMS_cms_wants_token);
}
- while (!_should_terminate) {
+ while (!should_terminate()) {
sleepBeforeNextCycle();
- if (_should_terminate) break;
+ if (should_terminate()) break;
GCIdMark gc_id_mark;
GCCause::Cause cause = _collector->_full_gc_requested ?
_collector->_full_gc_cause : GCCause::_cms_concurrent_mark;
_collector->collect_in_background(cause);
}
- assert(_should_terminate, "just checking");
+
// Check that the state of any protocol for synchronization
// between background (CMS) and foreground collector is "clean"
// (i.e. will not potentially block the foreground collector,
// requiring action by us).
verify_ok_to_terminate();
- // Signal that it is terminated
- {
- MutexLockerEx mu(Terminator_lock,
- Mutex::_no_safepoint_check_flag);
- assert(_cmst == this, "Weird!");
- _cmst = NULL;
- Terminator_lock->notify();
- }
}
#ifndef PRODUCT
@@ -157,39 +121,24 @@
// create and start a new ConcurrentMarkSweep Thread for given CMS generation
ConcurrentMarkSweepThread* ConcurrentMarkSweepThread::start(CMSCollector* collector) {
- if (!_should_terminate) {
- assert(cmst() == NULL, "start() called twice?");
- ConcurrentMarkSweepThread* th = new ConcurrentMarkSweepThread(collector);
- assert(cmst() == th, "Where did the just-created CMS thread go?");
- return th;
- }
- return NULL;
+ guarantee(_cmst == NULL, "start() called twice!");
+ ConcurrentMarkSweepThread* th = new ConcurrentMarkSweepThread(collector);
+ assert(_cmst == th, "Where did the just-created CMS thread go?");
+ return th;
}
-void ConcurrentMarkSweepThread::stop() {
- // it is ok to take late safepoints here, if needed
- {
- MutexLockerEx x(Terminator_lock);
- _should_terminate = true;
- }
- { // Now post a notify on CGC_lock so as to nudge
- // CMS thread(s) that might be slumbering in
- // sleepBeforeNextCycle.
- MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
- CGC_lock->notify_all();
- }
- { // Now wait until (all) CMS thread(s) have exited
- MutexLockerEx x(Terminator_lock);
- while(cmst() != NULL) {
- Terminator_lock->wait();
- }
- }
+void ConcurrentMarkSweepThread::stop_service() {
+ // Now post a notify on CGC_lock so as to nudge
+ // CMS thread(s) that might be slumbering in
+ // sleepBeforeNextCycle.
+ MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
+ CGC_lock->notify_all();
}
void ConcurrentMarkSweepThread::threads_do(ThreadClosure* tc) {
assert(tc != NULL, "Null ThreadClosure");
- if (_cmst != NULL) {
- tc->do_thread(_cmst);
+ if (cmst() != NULL && !cmst()->has_terminated()) {
+ tc->do_thread(cmst());
}
assert(Universe::is_fully_initialized(),
"Called too early, make sure heap is fully initialized");
@@ -202,8 +151,8 @@
}
void ConcurrentMarkSweepThread::print_all_on(outputStream* st) {
- if (_cmst != NULL) {
- _cmst->print_on(st);
+ if (cmst() != NULL && !cmst()->has_terminated()) {
+ cmst()->print_on(st);
st->cr();
}
if (_collector != NULL) {
@@ -278,7 +227,7 @@
void ConcurrentMarkSweepThread::wait_on_cms_lock(long t_millis) {
MutexLockerEx x(CGC_lock,
Mutex::_no_safepoint_check_flag);
- if (_should_terminate || _collector->_full_gc_requested) {
+ if (should_terminate() || _collector->_full_gc_requested) {
return;
}
set_CMS_flag(CMS_cms_wants_token); // to provoke notifies
@@ -307,7 +256,7 @@
unsigned int loop_count = 0;
- while(!_should_terminate) {
+ while(!should_terminate()) {
double now_time = os::elapsedTime();
long wait_time_millis;
@@ -327,7 +276,7 @@
{
MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
- if (_should_terminate || _collector->_full_gc_requested) {
+ if (should_terminate() || _collector->_full_gc_requested) {
return;
}
set_CMS_flag(CMS_cms_wants_token); // to provoke notifies
@@ -358,13 +307,13 @@
// Too many loops warning
if(++loop_count == 0) {
- warning("wait_on_cms_lock_for_scavenge() has looped %u times", loop_count - 1);
+ log_warning(gc)("wait_on_cms_lock_for_scavenge() has looped %u times", loop_count - 1);
}
}
}
void ConcurrentMarkSweepThread::sleepBeforeNextCycle() {
- while (!_should_terminate) {
+ while (!should_terminate()) {
if(CMSWaitDuration >= 0) {
// Wait until the next synchronous GC, a concurrent full gc
// request or a timeout, whichever is earlier.
@@ -381,15 +330,3 @@
// and wait some more
}
}
-
-// Note: this method, although exported by the ConcurrentMarkSweepThread,
-// which is a non-JavaThread, can only be called by a JavaThread.
-// Currently this is done at vm creation time (post-vm-init) by the
-// main/Primordial (Java)Thread.
-// XXX Consider changing this in the future to allow the CMS thread
-// itself to create this thread?
-void ConcurrentMarkSweepThread::makeSurrogateLockerThread(TRAPS) {
- assert(UseConcMarkSweepGC, "SLT thread needed only for CMS GC");
- assert(_slt == NULL, "SLT already created");
- _slt = SurrogateLockerThread::make(THREAD);
-}
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepThread.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -37,17 +37,10 @@
friend class VMStructs;
friend class ConcurrentMarkSweepGeneration; // XXX should remove friendship
friend class CMSCollector;
- public:
- virtual void run();
private:
- static ConcurrentMarkSweepThread* _cmst;
- static CMSCollector* _collector;
- static SurrogateLockerThread* _slt;
- static SurrogateLockerThread::SLT_msg_type _sltBuffer;
- static Monitor* _sltMonitor;
-
- static bool _should_terminate;
+ static ConcurrentMarkSweepThread* _cmst;
+ static CMSCollector* _collector;
enum CMS_flag_type {
CMS_nil = NoBits,
@@ -72,13 +65,13 @@
// debugging
void verify_ok_to_terminate() const PRODUCT_RETURN;
+ void run_service();
+ void stop_service();
+
public:
// Constructor
ConcurrentMarkSweepThread(CMSCollector* collector);
- static void makeSurrogateLockerThread(TRAPS);
- static SurrogateLockerThread* slt() { return _slt; }
-
static void threads_do(ThreadClosure* tc);
// Printing
@@ -91,8 +84,6 @@
// Create and start the CMS Thread, or stop it on shutdown
static ConcurrentMarkSweepThread* start(CMSCollector* collector);
- static void stop();
- static bool should_terminate() { return _should_terminate; }
// Synchronization using CMS token
static void synchronize(bool is_cms_thread);
@@ -170,7 +161,7 @@
inline void tick() {
_ticks++;
if (CMSLoopWarn && _ticks % _threshold == 0) {
- warning("%s has looped " INTX_FORMAT " times %s", _src, _ticks, _msg);
+ log_warning(gc)("%s has looped " INTX_FORMAT " times %s", _src, _ticks, _msg);
}
}
};
--- a/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -161,15 +161,6 @@
}
}
-
-// If you want a talkative process_chunk_boundaries,
-// then #define NOISY(x) x
-#ifdef NOISY
-#error "Encountered a global preprocessor flag, NOISY, which might clash with local definition to follow"
-#else
-#define NOISY(x)
-#endif
-
void
CardTableModRefBSForCTRS::
process_chunk_boundaries(Space* sp,
@@ -197,10 +188,6 @@
assert(start_chunk_index >= lowest_non_clean_base_chunk_index, "Bounds error.");
uintptr_t cur_chunk_index = start_chunk_index - lowest_non_clean_base_chunk_index;
- NOISY(tty->print_cr("===========================================================================");)
- NOISY(tty->print_cr(" process_chunk_boundary: Called with [" PTR_FORMAT "," PTR_FORMAT ")",
- chunk_mr.start(), chunk_mr.end());)
-
// First, set "our" lowest_non_clean entry, which would be
// used by the thread scanning an adjoining left chunk with
// a non-array object straddling the mutual boundary.
@@ -239,36 +226,18 @@
}
}
if (first_dirty_card != NULL) {
- NOISY(tty->print_cr(" LNC: Found a dirty card at " PTR_FORMAT " in current chunk",
- first_dirty_card);)
assert(cur_chunk_index < lowest_non_clean_chunk_size, "Bounds error.");
assert(lowest_non_clean[cur_chunk_index] == NULL,
"Write exactly once : value should be stable hereafter for this round");
lowest_non_clean[cur_chunk_index] = first_dirty_card;
- } NOISY(else {
- tty->print_cr(" LNC: Found no dirty card in current chunk; leaving LNC entry NULL");
- // In the future, we could have this thread look for a non-NULL value to copy from its
- // right neighbor (up to the end of the first object).
- if (last_card_of_cur_chunk < last_card_of_first_obj) {
- tty->print_cr(" LNC: BEWARE!!! first obj straddles past right end of chunk:\n"
- " might be efficient to get value from right neighbor?");
- }
- })
+ }
} else {
// In this case we can help our neighbor by just asking them
// to stop at our first card (even though it may not be dirty).
- NOISY(tty->print_cr(" LNC: first block is not a non-array object; setting LNC to first card of current chunk");)
assert(lowest_non_clean[cur_chunk_index] == NULL, "Write once : value should be stable hereafter");
jbyte* first_card_of_cur_chunk = byte_for(chunk_mr.start());
lowest_non_clean[cur_chunk_index] = first_card_of_cur_chunk;
}
- NOISY(tty->print_cr(" process_chunk_boundary: lowest_non_clean[" INTPTR_FORMAT "] = " PTR_FORMAT
- " which corresponds to the heap address " PTR_FORMAT,
- cur_chunk_index, lowest_non_clean[cur_chunk_index],
- (lowest_non_clean[cur_chunk_index] != NULL)
- ? addr_for(lowest_non_clean[cur_chunk_index])
- : NULL);)
- NOISY(tty->print_cr("---------------------------------------------------------------------------");)
// Next, set our own max_to_do, which will strictly/exclusively bound
// the highest address that we will scan past the right end of our chunk.
@@ -285,8 +254,6 @@
|| oop(last_block)->is_objArray() // last_block is an array (precisely marked)
|| oop(last_block)->is_typeArray()) {
max_to_do = chunk_mr.end();
- NOISY(tty->print_cr(" process_chunk_boundary: Last block on this card is not a non-array object;\n"
- " max_to_do left at " PTR_FORMAT, max_to_do);)
} else {
assert(last_block < chunk_mr.end(), "Tautology");
// It is a non-array object that straddles the right boundary of this chunk.
@@ -301,9 +268,6 @@
// subsequent cards still in this chunk must have been made
// precisely; we can cap processing at the end of our chunk.
max_to_do = chunk_mr.end();
- NOISY(tty->print_cr(" process_chunk_boundary: Head of last object on this card is not dirty;\n"
- " max_to_do left at " PTR_FORMAT,
- max_to_do);)
} else {
// The last object must be considered dirty, and extends onto the
// following chunk. Look for a dirty card in that chunk that will
@@ -323,8 +287,6 @@
cur <= last_card_of_last_obj; cur++) {
const jbyte val = *cur;
if (card_will_be_scanned(val)) {
- NOISY(tty->print_cr(" Found a non-clean card " PTR_FORMAT " with value 0x%x",
- cur, (int)val);)
limit_card = cur; break;
} else {
assert(!card_may_have_been_dirty(val), "Error: card can't be skipped");
@@ -333,10 +295,6 @@
if (limit_card != NULL) {
max_to_do = addr_for(limit_card);
assert(limit_card != NULL && max_to_do != NULL, "Error");
- NOISY(tty->print_cr(" process_chunk_boundary: Found a dirty card at " PTR_FORMAT
- " max_to_do set at " PTR_FORMAT " which is before end of last block in chunk: "
- PTR_FORMAT " + " PTR_FORMAT " = " PTR_FORMAT,
- limit_card, max_to_do, last_block, last_block_size, (last_block+last_block_size));)
} else {
// The following is a pessimistic value, because it's possible
// that a dirty card on a subsequent chunk has been cleared by
@@ -346,10 +304,6 @@
limit_card = last_card_of_last_obj;
max_to_do = last_block + last_block_size;
assert(limit_card != NULL && max_to_do != NULL, "Error");
- NOISY(tty->print_cr(" process_chunk_boundary: Found no dirty card before end of last block in chunk\n"
- " Setting limit_card to " PTR_FORMAT
- " and max_to_do " PTR_FORMAT " + " PTR_FORMAT " = " PTR_FORMAT,
- limit_card, last_block, last_block_size, max_to_do);)
}
assert(0 < cur_chunk_index+1 && cur_chunk_index+1 < lowest_non_clean_chunk_size,
"Bounds error.");
@@ -382,7 +336,6 @@
"[" PTR_FORMAT "," PTR_FORMAT ") -> [" PTR_FORMAT "," PTR_FORMAT ")",
p2i(sp->used_region().start()), p2i(sp->used_region().end()),
p2i(used.start()), p2i(used.end()));
- NOISY(tty->print_cr(" process_chunk_boundary: heap expanded; explicitly bounding last_chunk");)
last_chunk_index_to_check = last_chunk_index;
}
for (uintptr_t lnc_index = cur_chunk_index + 1;
@@ -392,9 +345,6 @@
if (lnc_card != NULL) {
// we can stop at the first non-NULL entry we find
if (lnc_card <= limit_card) {
- NOISY(tty->print_cr(" process_chunk_boundary: LNC card " PTR_FORMAT " is lower than limit_card " PTR_FORMAT,
- " max_to_do will be lowered to " PTR_FORMAT " from " PTR_FORMAT,
- lnc_card, limit_card, addr_for(lnc_card), max_to_do);)
limit_card = lnc_card;
max_to_do = addr_for(limit_card);
assert(limit_card != NULL && max_to_do != NULL, "Error");
@@ -410,9 +360,6 @@
assert(max_to_do != NULL, "OOPS 2!");
} else {
max_to_do = used.end();
- NOISY(tty->print_cr(" process_chunk_boundary: Last chunk of this space;\n"
- " max_to_do left at " PTR_FORMAT,
- max_to_do);)
}
assert(max_to_do != NULL, "OOPS 3!");
// Now we can set the closure we're using so it doesn't to beyond
@@ -421,11 +368,8 @@
#ifndef PRODUCT
dcto_cl->set_last_bottom(max_to_do);
#endif
- NOISY(tty->print_cr("===========================================================================\n");)
}
-#undef NOISY
-
void
CardTableModRefBSForCTRS::
get_LNC_array_for_space(Space* sp,
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -901,7 +901,7 @@
size_policy->minor_collection_begin();
}
- GCTraceTime(Trace, gc) t1("ParNew", NULL, gch->gc_cause());
+ GCTraceTime(Trace, gc, phases) t1("ParNew", NULL, gch->gc_cause());
age_table()->clear();
to()->clear(SpaceDecorator::Mangle);
--- a/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -82,18 +82,19 @@
if ((HeapWord*)obj < _boundary) {
#ifndef PRODUCT
if (_g->to()->is_in_reserved(obj)) {
- tty->print_cr("Scanning field (" PTR_FORMAT ") twice?", p2i(p));
+ LogHandle(gc) log;
+ log.error("Scanning field (" PTR_FORMAT ") twice?", p2i(p));
GenCollectedHeap* gch = GenCollectedHeap::heap();
Space* sp = gch->space_containing(p);
oop obj = oop(sp->block_start(p));
assert((HeapWord*)obj < (HeapWord*)p, "Error");
- tty->print_cr("Object: " PTR_FORMAT, p2i((void *)obj));
- tty->print_cr("-------");
- obj->print();
- tty->print_cr("-----");
- tty->print_cr("Heap:");
- tty->print_cr("-----");
- gch->print();
+ log.error("Object: " PTR_FORMAT, p2i((void *)obj));
+ log.error("-------");
+ obj->print_on(log.error_stream());
+ log.error("-----");
+ log.error("Heap:");
+ log.error("-----");
+ gch->print_on(log.error_stream());
ShouldNotReachHere();
}
#endif
--- a/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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
@@ -38,27 +38,17 @@
// Methods in abstract class VM_CMS_Operation
//////////////////////////////////////////////////////////
void VM_CMS_Operation::acquire_pending_list_lock() {
- // The caller may block while communicating
- // with the SLT thread in order to acquire/release the PLL.
- SurrogateLockerThread* slt = ConcurrentMarkSweepThread::slt();
- if (slt != NULL) {
- slt->manipulatePLL(SurrogateLockerThread::acquirePLL);
- } else {
- SurrogateLockerThread::report_missing_slt();
- }
+ _pending_list_locker.lock();
}
void VM_CMS_Operation::release_and_notify_pending_list_lock() {
- // The caller may block while communicating
- // with the SLT thread in order to acquire/release the PLL.
- ConcurrentMarkSweepThread::slt()->
- manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL);
+ _pending_list_locker.unlock();
}
void VM_CMS_Operation::verify_before_gc() {
if (VerifyBeforeGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
- GCTraceTime(Info, gc, verify) tm("Verify Before", _collector->_gc_timer_cm);
+ GCTraceTime(Info, gc, phases, verify) tm("Verify Before", _collector->_gc_timer_cm);
HandleMark hm;
FreelistLocker x(_collector);
MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag);
@@ -70,7 +60,7 @@
void VM_CMS_Operation::verify_after_gc() {
if (VerifyAfterGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
- GCTraceTime(Info, gc, verify) tm("Verify After", _collector->_gc_timer_cm);
+ GCTraceTime(Info, gc, phases, verify) tm("Verify After", _collector->_gc_timer_cm);
HandleMark hm;
FreelistLocker x(_collector);
MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag);
@@ -95,7 +85,7 @@
assert(!ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
"Possible deadlock");
- if (needs_pll()) {
+ if (needs_pending_list_lock()) {
acquire_pending_list_lock();
}
// Get the Heap_lock after the pending_list_lock.
@@ -103,7 +93,7 @@
if (lost_race()) {
assert(_prologue_succeeded == false, "Initialized in c'tor");
Heap_lock->unlock();
- if (needs_pll()) {
+ if (needs_pending_list_lock()) {
release_and_notify_pending_list_lock();
}
} else {
@@ -120,7 +110,7 @@
// Release the Heap_lock first.
Heap_lock->unlock();
- if (needs_pll()) {
+ if (needs_pending_list_lock()) {
release_and_notify_pending_list_lock();
}
}
--- a/hotspot/src/share/vm/gc/cms/vmCMSOperations.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/vmCMSOperations.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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
@@ -28,6 +28,7 @@
#include "gc/cms/concurrentMarkSweepGeneration.hpp"
#include "gc/shared/gcCause.hpp"
#include "gc/shared/gcId.hpp"
+#include "gc/shared/referencePendingListLocker.hpp"
#include "gc/shared/vmGCOperations.hpp"
#include "runtime/vm_operations.hpp"
@@ -51,6 +52,9 @@
class CMSCollector;
class VM_CMS_Operation: public VM_Operation {
+ private:
+ ReferencePendingListLocker _pending_list_locker;
+
protected:
CMSCollector* _collector; // associated collector
bool _prologue_succeeded; // whether doit_prologue succeeded
@@ -73,7 +77,7 @@
virtual const CMSCollector::CollectorState legal_state() const = 0;
// Whether the pending list lock needs to be held
- virtual const bool needs_pll() const = 0;
+ virtual const bool needs_pending_list_lock() const = 0;
// Execute operations in the context of the caller,
// prior to execution of the vm operation itself.
@@ -105,7 +109,7 @@
return CMSCollector::InitialMarking;
}
- virtual const bool needs_pll() const {
+ virtual const bool needs_pending_list_lock() const {
return false;
}
};
@@ -122,7 +126,7 @@
return CMSCollector::FinalMarking;
}
- virtual const bool needs_pll() const {
+ virtual const bool needs_pending_list_lock() const {
return true;
}
};
--- a/hotspot/src/share/vm/gc/cms/vmStructs_cms.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/vmStructs_cms.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, 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
@@ -51,14 +51,12 @@
declare_type(ConcurrentMarkSweepGeneration,CardGeneration) \
declare_type(CompactibleFreeListSpace, CompactibleSpace) \
declare_type(ConcurrentMarkSweepThread, NamedThread) \
- declare_type(SurrogateLockerThread, JavaThread) \
declare_toplevel_type(CMSCollector) \
declare_toplevel_type(CMSBitMap) \
declare_toplevel_type(FreeChunk) \
declare_toplevel_type(Metablock) \
declare_toplevel_type(ConcurrentMarkSweepThread*) \
declare_toplevel_type(ConcurrentMarkSweepGeneration*) \
- declare_toplevel_type(SurrogateLockerThread*) \
declare_toplevel_type(CompactibleFreeListSpace*) \
declare_toplevel_type(CMSCollector*) \
declare_toplevel_type(AFLBinaryTreeDictionary) \
--- a/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -145,7 +145,6 @@
verify();
}
-
void CollectionSetChooser::add_region(HeapRegion* hr) {
assert(!hr->is_pinned(),
"Pinned region shouldn't be added to the collection set (index %u)", hr->hrm_index());
@@ -210,4 +209,67 @@
_front = 0;
_end = 0;
_remaining_reclaimable_bytes = 0;
+}
+
+class ParKnownGarbageHRClosure: public HeapRegionClosure {
+ G1CollectedHeap* _g1h;
+ CSetChooserParUpdater _cset_updater;
+
+public:
+ ParKnownGarbageHRClosure(CollectionSetChooser* hrSorted,
+ uint chunk_size) :
+ _g1h(G1CollectedHeap::heap()),
+ _cset_updater(hrSorted, true /* parallel */, chunk_size) { }
+
+ bool doHeapRegion(HeapRegion* r) {
+ // Do we have any marking information for this region?
+ if (r->is_marked()) {
+ // We will skip any region that's currently used as an old GC
+ // alloc region (we should not consider those for collection
+ // before we fill them up).
+ if (_cset_updater.should_add(r) && !_g1h->is_old_gc_alloc_region(r)) {
+ _cset_updater.add_region(r);
+ }
+ }
+ return false;
+ }
};
+
+class ParKnownGarbageTask: public AbstractGangTask {
+ CollectionSetChooser* _hrSorted;
+ uint _chunk_size;
+ G1CollectedHeap* _g1;
+ HeapRegionClaimer _hrclaimer;
+
+public:
+ ParKnownGarbageTask(CollectionSetChooser* hrSorted, uint chunk_size, uint n_workers) :
+ AbstractGangTask("ParKnownGarbageTask"),
+ _hrSorted(hrSorted), _chunk_size(chunk_size),
+ _g1(G1CollectedHeap::heap()), _hrclaimer(n_workers) {}
+
+ void work(uint worker_id) {
+ ParKnownGarbageHRClosure parKnownGarbageCl(_hrSorted, _chunk_size);
+ _g1->heap_region_par_iterate(&parKnownGarbageCl, worker_id, &_hrclaimer);
+ }
+};
+
+uint CollectionSetChooser::calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) const {
+ assert(n_workers > 0, "Active gc workers should be greater than 0");
+ const uint overpartition_factor = 4;
+ const uint min_chunk_size = MAX2(n_regions / n_workers, 1U);
+ return MAX2(n_regions / (n_workers * overpartition_factor), min_chunk_size);
+}
+
+void CollectionSetChooser::rebuild(WorkGang* workers, uint n_regions) {
+ clear();
+
+ uint n_workers = workers->active_workers();
+
+ uint chunk_size = calculate_parallel_work_chunk_size(n_workers, n_regions);
+ prepare_for_par_region_addition(n_workers, n_regions, chunk_size);
+
+ ParKnownGarbageTask par_known_garbage_task(this, chunk_size, n_workers);
+ workers->run_task(&par_known_garbage_task);
+
+ sort_regions();
+}
--- a/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -65,6 +65,9 @@
// The sum of reclaimable bytes over all the regions in the CSet chooser.
size_t _remaining_reclaimable_bytes;
+ // Calculate and return chunk size (in number of regions) for parallel
+ // addition of regions
+ uint calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) const;
public:
// Return the current candidate region to be considered for
@@ -132,6 +135,8 @@
void clear();
+ void rebuild(WorkGang* workers, uint n_regions);
+
// Return the number of candidate regions that remain to be collected.
uint remaining_regions() { return _end - _front; }
--- a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -78,7 +78,7 @@
void ConcurrentG1RefineThread::wait_for_completed_buffers() {
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
- while (!_should_terminate && !is_active()) {
+ while (!should_terminate() && !is_active()) {
_monitor->wait(Mutex::_no_safepoint_check_flag);
}
}
@@ -109,22 +109,13 @@
}
}
-void ConcurrentG1RefineThread::run() {
- initialize_in_thread();
- wait_for_universe_init();
-
- run_service();
-
- terminate();
-}
-
void ConcurrentG1RefineThread::run_service() {
_vtime_start = os::elapsedVTime();
- while (!_should_terminate) {
+ while (!should_terminate()) {
// Wait for work
wait_for_completed_buffers();
- if (_should_terminate) {
+ if (should_terminate()) {
break;
}
@@ -168,23 +159,6 @@
log_debug(gc, refine)("Stopping %d", _worker_id);
}
-void ConcurrentG1RefineThread::stop() {
- // it is ok to take late safepoints here, if needed
- {
- MutexLockerEx mu(Terminator_lock);
- _should_terminate = true;
- }
-
- stop_service();
-
- {
- MutexLockerEx mu(Terminator_lock);
- while (!_has_terminated) {
- Terminator_lock->wait();
- }
- }
-}
-
void ConcurrentG1RefineThread::stop_service() {
MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
_monitor->notify();
--- a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -72,7 +72,6 @@
void stop_service();
public:
- virtual void run();
// Constructor
ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread* next,
CardTableEntryClosure* refine_closure,
@@ -84,9 +83,6 @@
double vtime_accum() { return _vtime_accum; }
ConcurrentG1Refine* cg1r() { return _cg1r; }
-
- // shutdown
- void stop();
};
#endif // SHARE_VM_GC_G1_CONCURRENTG1REFINETHREAD_HPP
--- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/classLoaderData.hpp"
#include "gc/g1/concurrentMarkThread.inline.hpp"
+#include "gc/g1/g1Analytics.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectorPolicy.hpp"
#include "gc/g1/g1MMUTracker.hpp"
@@ -41,9 +42,6 @@
// The CM thread is created when the G1 garbage collector is used
-SurrogateLockerThread*
- ConcurrentMarkThread::_slt = NULL;
-
ConcurrentMarkThread::ConcurrentMarkThread(G1ConcurrentMark* cm) :
ConcurrentGCThread(),
_cm(cm),
@@ -82,60 +80,59 @@
// Marking pauses can be scheduled flexibly, so we might delay marking to meet MMU.
void ConcurrentMarkThread::delay_to_keep_mmu(G1CollectorPolicy* g1_policy, bool remark) {
+ const G1Analytics* analytics = g1_policy->analytics();
if (g1_policy->adaptive_young_list_length()) {
double now = os::elapsedTime();
- double prediction_ms = remark ? g1_policy->predict_remark_time_ms()
- : g1_policy->predict_cleanup_time_ms();
+ double prediction_ms = remark ? analytics->predict_remark_time_ms()
+ : analytics->predict_cleanup_time_ms();
G1MMUTracker *mmu_tracker = g1_policy->mmu_tracker();
jlong sleep_time_ms = mmu_tracker->when_ms(now, prediction_ms);
os::sleep(this, sleep_time_ms, false);
}
}
-class GCConcPhaseTimer : StackObj {
+class G1ConcPhaseTimer : public GCTraceConcTimeImpl<LogLevel::Info, LOG_TAGS(gc, marking)> {
G1ConcurrentMark* _cm;
public:
- GCConcPhaseTimer(G1ConcurrentMark* cm, const char* title) : _cm(cm) {
- _cm->register_concurrent_phase_start(title);
+ G1ConcPhaseTimer(G1ConcurrentMark* cm, const char* title) :
+ GCTraceConcTimeImpl<LogLevel::Info, LogTag::_gc, LogTag::_marking>(title),
+ _cm(cm) {
+ _cm->gc_timer_cm()->register_gc_concurrent_start(title);
}
- ~GCConcPhaseTimer() {
- _cm->register_concurrent_phase_end();
+ ~G1ConcPhaseTimer() {
+ _cm->gc_timer_cm()->register_gc_concurrent_end();
}
};
-void ConcurrentMarkThread::run() {
- initialize_in_thread();
- wait_for_universe_init();
-
- run_service();
-
- terminate();
-}
-
void ConcurrentMarkThread::run_service() {
_vtime_start = os::elapsedVTime();
G1CollectedHeap* g1h = G1CollectedHeap::heap();
G1CollectorPolicy* g1_policy = g1h->g1_policy();
- while (!_should_terminate) {
+ while (!should_terminate()) {
// wait until started is set.
sleepBeforeNextCycle();
- if (_should_terminate) {
- _cm->root_regions()->cancel_scan();
+ if (should_terminate()) {
break;
}
+ GCIdMark gc_id_mark;
+
+ cm()->concurrent_cycle_start();
+
assert(GCId::current() != GCId::undefined(), "GC id should have been set up by the initial mark GC.");
+
+ GCTraceConcTime(Info, gc) tt("Concurrent Cycle");
{
ResourceMark rm;
HandleMark hm;
double cycle_start = os::elapsedVTime();
{
- GCConcPhaseTimer(_cm, "Concurrent Clearing of Claimed Marks");
+ G1ConcPhaseTimer t(_cm, "Concurrent Clear Claimed Marks");
ClassLoaderDataGraph::clear_claimed_marks();
}
@@ -148,22 +145,22 @@
// correctness issue.
{
- GCConcPhaseTimer(_cm, "Concurrent Root Region Scanning");
- _cm->scanRootRegions();
+ G1ConcPhaseTimer t(_cm, "Concurrent Scan Root Regions");
+ _cm->scan_root_regions();
}
// It would be nice to use the GCTraceConcTime class here but
// the "end" logging is inside the loop and not at the end of
// a scope. Mimicking the same log output as GCTraceConcTime instead.
jlong mark_start = os::elapsed_counter();
- log_info(gc)("Concurrent Mark (%.3fs)", TimeHelper::counter_to_seconds(mark_start));
+ log_info(gc, marking)("Concurrent Mark (%.3fs)", TimeHelper::counter_to_seconds(mark_start));
int iter = 0;
do {
iter++;
if (!cm()->has_aborted()) {
- GCConcPhaseTimer(_cm, "Concurrent Mark");
- _cm->markFromRoots();
+ G1ConcPhaseTimer t(_cm, "Concurrent Mark From Roots");
+ _cm->mark_from_roots();
}
double mark_end_time = os::elapsedVTime();
@@ -171,18 +168,18 @@
_vtime_mark_accum += (mark_end_time - cycle_start);
if (!cm()->has_aborted()) {
delay_to_keep_mmu(g1_policy, true /* remark */);
- log_info(gc)("Concurrent Mark (%.3fs, %.3fs) %.3fms",
- TimeHelper::counter_to_seconds(mark_start),
- TimeHelper::counter_to_seconds(mark_end),
- TimeHelper::counter_to_millis(mark_end - mark_start));
+ log_info(gc, marking)("Concurrent Mark (%.3fs, %.3fs) %.3fms",
+ TimeHelper::counter_to_seconds(mark_start),
+ TimeHelper::counter_to_seconds(mark_end),
+ TimeHelper::counter_to_millis(mark_end - mark_start));
CMCheckpointRootsFinalClosure final_cl(_cm);
VM_CGC_Operation op(&final_cl, "Pause Remark", true /* needs_pll */);
VMThread::execute(&op);
}
if (cm()->restart_for_overflow()) {
- log_debug(gc)("Restarting conc marking because of MS overflow in remark (restart #%d).", iter);
- log_info(gc)("Concurrent Mark restart for overflow");
+ log_debug(gc, marking)("Restarting Concurrent Marking because of Mark Stack Overflow in Remark (Iteration #%d).", iter);
+ log_info(gc, marking)("Concurrent Mark Restart due to overflow");
}
} while (cm()->restart_for_overflow());
@@ -216,11 +213,9 @@
// place, it would wait for us to process the regions
// reclaimed by cleanup.
- GCTraceConcTime(Info, gc) tt("Concurrent Cleanup");
- GCConcPhaseTimer(_cm, "Concurrent Cleanup");
-
+ G1ConcPhaseTimer t(_cm, "Concurrent Complete Cleanup");
// Now do the concurrent cleanup operation.
- _cm->completeCleanup();
+ _cm->complete_cleanup();
// Notify anyone who's waiting that there are no more free
// regions coming. We have to do this before we join the STS
@@ -265,7 +260,7 @@
if (!cm()->has_aborted()) {
g1_policy->record_concurrent_mark_cleanup_completed();
} else {
- log_info(gc)("Concurrent Mark abort");
+ log_info(gc, marking)("Concurrent Mark Abort");
}
}
@@ -274,8 +269,8 @@
// We may have aborted just before the remark. Do not bother clearing the
// bitmap then, as it has been done during mark abort.
if (!cm()->has_aborted()) {
- GCConcPhaseTimer(_cm, "Concurrent Bitmap Clearing");
- _cm->clearNextBitmap();
+ G1ConcPhaseTimer t(_cm, "Concurrent Cleanup for Next Mark");
+ _cm->cleanup_for_next_mark();
} else {
assert(!G1VerifyBitmaps || _cm->nextMarkBitmapIsClear(), "Next mark bitmap must be clear");
}
@@ -288,25 +283,11 @@
{
SuspendibleThreadSetJoiner sts_join;
g1h->increment_old_marking_cycles_completed(true /* concurrent */);
- g1h->register_concurrent_cycle_end();
+
+ cm()->concurrent_cycle_end();
}
}
-}
-
-void ConcurrentMarkThread::stop() {
- {
- MutexLockerEx ml(Terminator_lock);
- _should_terminate = true;
- }
-
- stop_service();
-
- {
- MutexLockerEx ml(Terminator_lock);
- while (!_has_terminated) {
- Terminator_lock->wait();
- }
- }
+ _cm->root_regions()->cancel_scan();
}
void ConcurrentMarkThread::stop_service() {
@@ -320,7 +301,7 @@
assert(!in_progress(), "should have been cleared");
MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
- while (!started() && !_should_terminate) {
+ while (!started() && !should_terminate()) {
CGC_lock->wait(Mutex::_no_safepoint_check_flag);
}
@@ -328,16 +309,3 @@
set_in_progress();
}
}
-
-// Note: As is the case with CMS - this method, although exported
-// by the ConcurrentMarkThread, which is a non-JavaThread, can only
-// be called by a JavaThread. Currently this is done at vm creation
-// time (post-vm-init) by the main/Primordial (Java)Thread.
-// XXX Consider changing this in the future to allow the CM thread
-// itself to create this thread?
-void ConcurrentMarkThread::makeSurrogateLockerThread(TRAPS) {
- assert(UseG1GC, "SLT thread needed only for concurrent GC");
- assert(THREAD->is_Java_thread(), "must be a Java thread");
- assert(_slt == NULL, "SLT already created");
- _slt = SurrogateLockerThread::make(THREAD);
-}
--- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -38,13 +38,8 @@
double _vtime_start; // Initial virtual time.
double _vtime_accum; // Accumulated virtual time.
-
double _vtime_mark_accum;
- public:
- virtual void run();
-
- private:
G1ConcurrentMark* _cm;
enum State {
@@ -61,15 +56,10 @@
void run_service();
void stop_service();
- static SurrogateLockerThread* _slt;
-
public:
// Constructor
ConcurrentMarkThread(G1ConcurrentMark* cm);
- static void makeSurrogateLockerThread(TRAPS);
- static SurrogateLockerThread* slt() { return _slt; }
-
// Total virtual time so far for this thread and concurrent marking tasks.
double vtime_accum();
// Marking virtual time so far this thread and concurrent marking tasks.
@@ -93,9 +83,6 @@
// as the CM thread might take some time to wake up before noticing
// that started() is set and set in_progress().
bool during_cycle() { return !idle(); }
-
- // shutdown
- void stop();
};
#endif // SHARE_VM_GC_G1_CONCURRENTMARKTHREAD_HPP
--- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -110,44 +110,6 @@
}
}
-bool DirtyCardQueue::apply_closure(CardTableEntryClosure* cl,
- bool consume,
- uint worker_i) {
- bool res = true;
- if (_buf != NULL) {
- res = apply_closure_to_buffer(cl, _buf, _index, _sz,
- consume,
- worker_i);
- if (res && consume) {
- _index = _sz;
- }
- }
- return res;
-}
-
-bool DirtyCardQueue::apply_closure_to_buffer(CardTableEntryClosure* cl,
- void** buf,
- size_t index, size_t sz,
- bool consume,
- uint worker_i) {
- if (cl == NULL) return true;
- size_t limit = byte_index_to_index(sz);
- for (size_t i = byte_index_to_index(index); i < limit; ++i) {
- jbyte* card_ptr = static_cast<jbyte*>(buf[i]);
- if (card_ptr != NULL) {
- // Set the entry to null, so we don't do it again (via the test
- // above) if we reconsider this buffer.
- if (consume) {
- buf[i] = NULL;
- }
- if (!cl->do_card_ptr(card_ptr, worker_i)) {
- return false;
- }
- }
- }
- return true;
-}
-
DirtyCardQueueSet::DirtyCardQueueSet(bool notify_when_complete) :
PtrQueueSet(notify_when_complete),
_mut_process_closure(NULL),
@@ -188,14 +150,39 @@
t->dirty_card_queue().handle_zero_index();
}
-bool DirtyCardQueueSet::mut_process_buffer(void** buf) {
+bool DirtyCardQueueSet::apply_closure_to_buffer(CardTableEntryClosure* cl,
+ BufferNode* node,
+ bool consume,
+ uint worker_i) {
+ if (cl == NULL) return true;
+ void** buf = BufferNode::make_buffer_from_node(node);
+ size_t limit = DirtyCardQueue::byte_index_to_index(buffer_size());
+ size_t start = DirtyCardQueue::byte_index_to_index(node->index());
+ for (size_t i = start; i < limit; ++i) {
+ jbyte* card_ptr = static_cast<jbyte*>(buf[i]);
+ assert(card_ptr != NULL, "invariant");
+ if (!cl->do_card_ptr(card_ptr, worker_i)) {
+ if (consume) {
+ size_t new_index = DirtyCardQueue::index_to_byte_index(i + 1);
+ assert(new_index <= buffer_size(), "invariant");
+ node->set_index(new_index);
+ }
+ return false;
+ }
+ }
+ if (consume) {
+ node->set_index(buffer_size());
+ }
+ return true;
+}
+
+bool DirtyCardQueueSet::mut_process_buffer(BufferNode* node) {
guarantee(_free_ids != NULL, "must be");
// claim a par id
uint worker_i = _free_ids->claim_par_id();
- bool b = DirtyCardQueue::apply_closure_to_buffer(_mut_process_closure, buf, 0,
- _sz, true, worker_i);
+ bool b = apply_closure_to_buffer(_mut_process_closure, node, true, worker_i);
if (b) {
Atomic::inc(&_processed_buffers_mut);
}
@@ -239,49 +226,30 @@
if (nd == NULL) {
return false;
} else {
- void** buf = BufferNode::make_buffer_from_node(nd);
- size_t index = nd->index();
- if (DirtyCardQueue::apply_closure_to_buffer(cl,
- buf, index, _sz,
- true, worker_i)) {
+ if (apply_closure_to_buffer(cl, nd, true, worker_i)) {
// Done with fully processed buffer.
- deallocate_buffer(buf);
+ deallocate_buffer(nd);
Atomic::inc(&_processed_buffers_rs_thread);
return true;
} else {
// Return partially processed buffer to the queue.
- enqueue_complete_buffer(buf, index);
+ enqueue_complete_buffer(nd);
return false;
}
}
}
-void DirtyCardQueueSet::apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl) {
- BufferNode* nd = _completed_buffers_head;
- while (nd != NULL) {
- bool b =
- DirtyCardQueue::apply_closure_to_buffer(cl,
- BufferNode::make_buffer_from_node(nd),
- 0, _sz, false);
- guarantee(b, "Should not stop early.");
- nd = nd->next();
- }
-}
-
void DirtyCardQueueSet::par_apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl) {
BufferNode* nd = _cur_par_buffer_node;
while (nd != NULL) {
- BufferNode* next = (BufferNode*)nd->next();
- BufferNode* actual = (BufferNode*)Atomic::cmpxchg_ptr((void*)next, (volatile void*)&_cur_par_buffer_node, (void*)nd);
+ BufferNode* next = nd->next();
+ void* actual = Atomic::cmpxchg_ptr(next, &_cur_par_buffer_node, nd);
if (actual == nd) {
- bool b =
- DirtyCardQueue::apply_closure_to_buffer(cl,
- BufferNode::make_buffer_from_node(actual),
- 0, _sz, false);
+ bool b = apply_closure_to_buffer(cl, nd, false);
guarantee(b, "Should not stop early.");
nd = next;
} else {
- nd = actual;
+ nd = static_cast<BufferNode*>(actual);
}
}
}
@@ -304,7 +272,7 @@
while (buffers_to_delete != NULL) {
BufferNode* nd = buffers_to_delete;
buffers_to_delete = nd->next();
- deallocate_buffer(BufferNode::make_buffer_from_node(nd));
+ deallocate_buffer(nd);
}
}
@@ -320,6 +288,13 @@
shared_dirty_card_queue()->reset();
}
+void DirtyCardQueueSet::concatenate_log(DirtyCardQueue& dcq) {
+ if (!dcq.is_empty()) {
+ enqueue_complete_buffer(
+ BufferNode::make_node_from_buffer(dcq.get_buf(), dcq.get_index()));
+ dcq.reinitialize();
+ }
+}
void DirtyCardQueueSet::concatenate_logs() {
// Iterate over all the threads, if we find a partial log add it to
@@ -329,23 +304,9 @@
_max_completed_queue = max_jint;
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
for (JavaThread* t = Threads::first(); t; t = t->next()) {
- DirtyCardQueue& dcq = t->dirty_card_queue();
- if (dcq.size() != 0) {
- void** buf = dcq.get_buf();
- // We must NULL out the unused entries, then enqueue.
- size_t limit = dcq.byte_index_to_index(dcq.get_index());
- for (size_t i = 0; i < limit; ++i) {
- buf[i] = NULL;
- }
- enqueue_complete_buffer(dcq.get_buf(), dcq.get_index());
- dcq.reinitialize();
- }
+ concatenate_log(t->dirty_card_queue());
}
- if (_shared_dirty_card_queue.size() != 0) {
- enqueue_complete_buffer(_shared_dirty_card_queue.get_buf(),
- _shared_dirty_card_queue.get_index());
- _shared_dirty_card_queue.reinitialize();
- }
+ concatenate_log(_shared_dirty_card_queue);
// Restore the completed buffer queue limit.
_max_completed_queue = save_max_completed_queue;
}
--- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -37,7 +37,7 @@
public:
// Process the card whose card table entry is "card_ptr". If returns
// "false", terminate the iteration early.
- virtual bool do_card_ptr(jbyte* card_ptr, uint worker_i = 0) = 0;
+ virtual bool do_card_ptr(jbyte* card_ptr, uint worker_i) = 0;
};
// A ptrQueue whose elements are "oops", pointers to object heads.
@@ -52,23 +52,6 @@
// Process queue entries and release resources.
void flush() { flush_impl(); }
- // Apply the closure to all elements, and reset the index to make the
- // buffer empty. If a closure application returns "false", return
- // "false" immediately, halting the iteration. If "consume" is true,
- // deletes processed entries from logs.
- bool apply_closure(CardTableEntryClosure* cl,
- bool consume = true,
- uint worker_i = 0);
-
- // Apply the closure to all elements of "buf", down to "index"
- // (inclusive.) If returns "false", then a closure application returned
- // "false", and we return immediately. If "consume" is true, entries are
- // set to NULL as they are processed, so they will not be processed again
- // later.
- static bool apply_closure_to_buffer(CardTableEntryClosure* cl,
- void** buf, size_t index, size_t sz,
- bool consume = true,
- uint worker_i = 0);
void **get_buf() { return _buf;}
size_t get_index() { return _index;}
void reinitialize() { _buf = 0; _sz = 0; _index = 0;}
@@ -94,8 +77,18 @@
DirtyCardQueue _shared_dirty_card_queue;
- // Override.
- bool mut_process_buffer(void** buf);
+ // Apply the closure to the elements of "node" from it's index to
+ // buffer_size. If all closure applications return true, then
+ // returns true. Stops processing after the first closure
+ // application that returns false, and returns false from this
+ // function. If "consume" is true, the node's index is updated to
+ // follow the last processed element.
+ bool apply_closure_to_buffer(CardTableEntryClosure* cl,
+ BufferNode* node,
+ bool consume,
+ uint worker_i = 0);
+
+ bool mut_process_buffer(BufferNode* node);
// Protected by the _cbl_mon.
FreeIdSet* _free_ids;
@@ -107,6 +100,9 @@
// Current buffer node used for parallel iteration.
BufferNode* volatile _cur_par_buffer_node;
+
+ void concatenate_log(DirtyCardQueue& dcq);
+
public:
DirtyCardQueueSet(bool notify_when_complete = true);
@@ -126,12 +122,13 @@
static void handle_zero_index_for_thread(JavaThread* t);
// If there exists some completed buffer, pop it, then apply the
- // specified closure to all its elements, nulling out those elements
- // processed. If all elements are processed, returns "true". If no
- // completed buffers exist, returns false. If a completed buffer exists,
- // but is only partially completed before a "yield" happens, the
- // partially completed buffer (with its processed elements set to NULL)
- // is returned to the completed buffer set, and this call returns false.
+ // specified closure to its active elements. If all active elements
+ // are processed, returns "true". If no completed buffers exist,
+ // returns false. If a completed buffer exists, but is only
+ // partially completed before a "yield" happens, the partially
+ // completed buffer (with its index updated to exclude the processed
+ // elements) is returned to the completed buffer set, and this call
+ // returns false.
bool apply_closure_to_completed_buffer(CardTableEntryClosure* cl,
uint worker_i,
size_t stop_at,
@@ -139,13 +136,10 @@
BufferNode* get_completed_buffer(size_t stop_at);
- // Applies the current closure to all completed buffers,
- // non-consumptively.
- void apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl);
-
void reset_for_par_iteration() { _cur_par_buffer_node = _completed_buffers_head; }
// Applies the current closure to all completed buffers, non-consumptively.
- // Parallel version.
+ // Can be used in parallel, all callers using the iteration state initialized
+ // by reset_for_par_iteration.
void par_apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl);
DirtyCardQueue* shared_dirty_card_queue() {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1Analytics.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2016, 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/g1Analytics.hpp"
+#include "gc/g1/g1Predictions.hpp"
+#include "runtime/os.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/numberSeq.hpp"
+
+// Different defaults for different number of GC threads
+// They were chosen by running GCOld and SPECjbb on debris with different
+// numbers of GC threads and choosing them based on the results
+
+// all the same
+static double rs_length_diff_defaults[] = {
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+};
+
+static double cost_per_card_ms_defaults[] = {
+ 0.01, 0.005, 0.005, 0.003, 0.003, 0.002, 0.002, 0.0015
+};
+
+// all the same
+static double young_cards_per_entry_ratio_defaults[] = {
+ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0
+};
+
+static double cost_per_entry_ms_defaults[] = {
+ 0.015, 0.01, 0.01, 0.008, 0.008, 0.0055, 0.0055, 0.005
+};
+
+static double cost_per_byte_ms_defaults[] = {
+ 0.00006, 0.00003, 0.00003, 0.000015, 0.000015, 0.00001, 0.00001, 0.000009
+};
+
+// these should be pretty consistent
+static double constant_other_time_ms_defaults[] = {
+ 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0
+};
+
+
+static double young_other_cost_per_region_ms_defaults[] = {
+ 0.3, 0.2, 0.2, 0.15, 0.15, 0.12, 0.12, 0.1
+};
+
+static double non_young_other_cost_per_region_ms_defaults[] = {
+ 1.0, 0.7, 0.7, 0.5, 0.5, 0.42, 0.42, 0.30
+};
+
+G1Analytics::G1Analytics(const G1Predictions* predictor) :
+ _predictor(predictor),
+ _recent_gc_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)),
+ _concurrent_mark_remark_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)),
+ _concurrent_mark_cleanup_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)),
+ _alloc_rate_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _prev_collection_pause_end_ms(0.0),
+ _rs_length_diff_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _cost_per_card_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _cost_scan_hcc_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _young_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _mixed_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _cost_per_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _mixed_cost_per_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _cost_per_byte_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _cost_per_byte_ms_during_cm_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _constant_other_time_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _young_other_cost_per_region_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _non_young_other_cost_per_region_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _pending_cards_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _rs_lengths_seq(new TruncatedSeq(TruncatedSeqLength)),
+ _recent_prev_end_times_for_all_gcs_sec(new TruncatedSeq(NumPrevPausesForHeuristics)) {
+
+ // Seed sequences with initial values.
+ _recent_prev_end_times_for_all_gcs_sec->add(os::elapsedTime());
+ _prev_collection_pause_end_ms = os::elapsedTime() * 1000.0;
+
+ int index = MIN2(ParallelGCThreads - 1, 7u);
+
+ _rs_length_diff_seq->add(rs_length_diff_defaults[index]);
+ _cost_per_card_ms_seq->add(cost_per_card_ms_defaults[index]);
+ _cost_scan_hcc_seq->add(0.0);
+ _young_cards_per_entry_ratio_seq->add(young_cards_per_entry_ratio_defaults[index]);
+ _cost_per_entry_ms_seq->add(cost_per_entry_ms_defaults[index]);
+ _cost_per_byte_ms_seq->add(cost_per_byte_ms_defaults[index]);
+ _constant_other_time_ms_seq->add(constant_other_time_ms_defaults[index]);
+ _young_other_cost_per_region_ms_seq->add(young_other_cost_per_region_ms_defaults[index]);
+ _non_young_other_cost_per_region_ms_seq->add(non_young_other_cost_per_region_ms_defaults[index]);
+
+ // start conservatively (around 50ms is about right)
+ _concurrent_mark_remark_times_ms->add(0.05);
+ _concurrent_mark_cleanup_times_ms->add(0.20);
+}
+
+double G1Analytics::get_new_prediction(TruncatedSeq const* seq) const {
+ return _predictor->get_new_prediction(seq);
+}
+
+size_t G1Analytics::get_new_size_prediction(TruncatedSeq const* seq) const {
+ return (size_t)get_new_prediction(seq);
+}
+
+int G1Analytics::num_alloc_rate_ms() const {
+ return _alloc_rate_ms_seq->num();
+}
+
+void G1Analytics::report_concurrent_mark_remark_times_ms(double ms) {
+ _concurrent_mark_remark_times_ms->add(ms);
+}
+
+void G1Analytics::report_alloc_rate_ms(double alloc_rate) {
+ _alloc_rate_ms_seq->add(alloc_rate);
+}
+
+void G1Analytics::compute_pause_time_ratio(double interval_ms, double pause_time_ms) {
+ _recent_avg_pause_time_ratio = _recent_gc_times_ms->sum() / interval_ms;
+ if (_recent_avg_pause_time_ratio < 0.0 ||
+ (_recent_avg_pause_time_ratio - 1.0 > 0.0)) {
+ // Clip ratio between 0.0 and 1.0, and continue. This will be fixed in
+ // CR 6902692 by redoing the manner in which the ratio is incrementally computed.
+ if (_recent_avg_pause_time_ratio < 0.0) {
+ _recent_avg_pause_time_ratio = 0.0;
+ } else {
+ assert(_recent_avg_pause_time_ratio - 1.0 > 0.0, "Ctl-point invariant");
+ _recent_avg_pause_time_ratio = 1.0;
+ }
+ }
+
+ // Compute the ratio of just this last pause time to the entire time range stored
+ // in the vectors. Comparing this pause to the entire range, rather than only the
+ // most recent interval, has the effect of smoothing over a possible transient 'burst'
+ // of more frequent pauses that don't really reflect a change in heap occupancy.
+ // This reduces the likelihood of a needless heap expansion being triggered.
+ _last_pause_time_ratio =
+ (pause_time_ms * _recent_prev_end_times_for_all_gcs_sec->num()) / interval_ms;
+}
+
+void G1Analytics::report_cost_per_card_ms(double cost_per_card_ms) {
+ _cost_per_card_ms_seq->add(cost_per_card_ms);
+}
+
+void G1Analytics::report_cost_scan_hcc(double cost_scan_hcc) {
+ _cost_scan_hcc_seq->add(cost_scan_hcc);
+}
+
+void G1Analytics::report_cost_per_entry_ms(double cost_per_entry_ms, bool last_gc_was_young) {
+ if (last_gc_was_young) {
+ _cost_per_entry_ms_seq->add(cost_per_entry_ms);
+ } else {
+ _mixed_cost_per_entry_ms_seq->add(cost_per_entry_ms);
+ }
+}
+
+void G1Analytics::report_cards_per_entry_ratio(double cards_per_entry_ratio, bool last_gc_was_young) {
+ if (last_gc_was_young) {
+ _young_cards_per_entry_ratio_seq->add(cards_per_entry_ratio);
+ } else {
+ _mixed_cards_per_entry_ratio_seq->add(cards_per_entry_ratio);
+ }
+}
+
+void G1Analytics::report_rs_length_diff(double rs_length_diff) {
+ _rs_length_diff_seq->add(rs_length_diff);
+}
+
+void G1Analytics::report_cost_per_byte_ms(double cost_per_byte_ms, bool in_marking_window) {
+ if (in_marking_window) {
+ _cost_per_byte_ms_during_cm_seq->add(cost_per_byte_ms);
+ } else {
+ _cost_per_byte_ms_seq->add(cost_per_byte_ms);
+ }
+}
+
+void G1Analytics::report_young_other_cost_per_region_ms(double other_cost_per_region_ms) {
+ _young_other_cost_per_region_ms_seq->add(other_cost_per_region_ms);
+}
+
+void G1Analytics::report_non_young_other_cost_per_region_ms(double other_cost_per_region_ms) {
+ _non_young_other_cost_per_region_ms_seq->add(other_cost_per_region_ms);
+}
+
+void G1Analytics::report_constant_other_time_ms(double constant_other_time_ms) {
+ _constant_other_time_ms_seq->add(constant_other_time_ms);
+}
+
+void G1Analytics::report_pending_cards(double pending_cards) {
+ _pending_cards_seq->add(pending_cards);
+}
+
+void G1Analytics::report_rs_lengths(double rs_lengths) {
+ _rs_lengths_seq->add(rs_lengths);
+}
+
+size_t G1Analytics::predict_rs_length_diff() const {
+ return get_new_size_prediction(_rs_length_diff_seq);
+}
+
+double G1Analytics::predict_alloc_rate_ms() const {
+ return get_new_prediction(_alloc_rate_ms_seq);
+}
+
+double G1Analytics::predict_cost_per_card_ms() const {
+ return get_new_prediction(_cost_per_card_ms_seq);
+}
+
+double G1Analytics::predict_scan_hcc_ms() const {
+ return get_new_prediction(_cost_scan_hcc_seq);
+}
+
+double G1Analytics::predict_rs_update_time_ms(size_t pending_cards) const {
+ return pending_cards * predict_cost_per_card_ms() + predict_scan_hcc_ms();
+}
+
+double G1Analytics::predict_young_cards_per_entry_ratio() const {
+ return get_new_prediction(_young_cards_per_entry_ratio_seq);
+}
+
+double G1Analytics::predict_mixed_cards_per_entry_ratio() const {
+ if (_mixed_cards_per_entry_ratio_seq->num() < 2) {
+ return predict_young_cards_per_entry_ratio();
+ } else {
+ return get_new_prediction(_mixed_cards_per_entry_ratio_seq);
+ }
+}
+
+size_t G1Analytics::predict_card_num(size_t rs_length, bool gcs_are_young) const {
+ if (gcs_are_young) {
+ return (size_t) (rs_length * predict_young_cards_per_entry_ratio());
+ } else {
+ return (size_t) (rs_length * predict_mixed_cards_per_entry_ratio());
+ }
+}
+
+double G1Analytics::predict_rs_scan_time_ms(size_t card_num, bool gcs_are_young) const {
+ if (gcs_are_young) {
+ return card_num * get_new_prediction(_cost_per_entry_ms_seq);
+ } else {
+ return predict_mixed_rs_scan_time_ms(card_num);
+ }
+}
+
+double G1Analytics::predict_mixed_rs_scan_time_ms(size_t card_num) const {
+ if (_mixed_cost_per_entry_ms_seq->num() < 3) {
+ return card_num * get_new_prediction(_cost_per_entry_ms_seq);
+ } else {
+ return card_num * get_new_prediction(_mixed_cost_per_entry_ms_seq);
+ }
+}
+
+double G1Analytics::predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const {
+ if (_cost_per_byte_ms_during_cm_seq->num() < 3) {
+ return (1.1 * bytes_to_copy) * get_new_prediction(_cost_per_byte_ms_seq);
+ } else {
+ return bytes_to_copy * get_new_prediction(_cost_per_byte_ms_during_cm_seq);
+ }
+}
+
+double G1Analytics::predict_object_copy_time_ms(size_t bytes_to_copy, bool during_concurrent_mark) const {
+ if (during_concurrent_mark) {
+ return predict_object_copy_time_ms_during_cm(bytes_to_copy);
+ } else {
+ return bytes_to_copy * get_new_prediction(_cost_per_byte_ms_seq);
+ }
+}
+
+double G1Analytics::predict_constant_other_time_ms() const {
+ return get_new_prediction(_constant_other_time_ms_seq);
+}
+
+double G1Analytics::predict_young_other_time_ms(size_t young_num) const {
+ return young_num * get_new_prediction(_young_other_cost_per_region_ms_seq);
+}
+
+double G1Analytics::predict_non_young_other_time_ms(size_t non_young_num) const {
+ return non_young_num * get_new_prediction(_non_young_other_cost_per_region_ms_seq);
+}
+
+double G1Analytics::predict_remark_time_ms() const {
+ return get_new_prediction(_concurrent_mark_remark_times_ms);
+}
+
+double G1Analytics::predict_cleanup_time_ms() const {
+ return get_new_prediction(_concurrent_mark_cleanup_times_ms);
+}
+
+size_t G1Analytics::predict_rs_lengths() const {
+ return get_new_size_prediction(_rs_lengths_seq);
+}
+
+size_t G1Analytics::predict_pending_cards() const {
+ return get_new_size_prediction(_pending_cards_seq);
+}
+
+double G1Analytics::last_known_gc_end_time_sec() const {
+ return _recent_prev_end_times_for_all_gcs_sec->oldest();
+}
+
+void G1Analytics::update_recent_gc_times(double end_time_sec,
+ double pause_time_ms) {
+ _recent_gc_times_ms->add(pause_time_ms);
+ _recent_prev_end_times_for_all_gcs_sec->add(end_time_sec);
+ _prev_collection_pause_end_ms = end_time_sec * 1000.0;
+}
+
+void G1Analytics::report_concurrent_mark_cleanup_times_ms(double ms) {
+ _concurrent_mark_cleanup_times_ms->add(ms);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1Analytics.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2016, 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_G1_G1MEASUREMENTS_HPP
+#define SHARE_VM_GC_G1_G1MEASUREMENTS_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class TruncatedSeq;
+class G1Predictions;
+
+class G1Analytics: public CHeapObj<mtGC> {
+ const static int TruncatedSeqLength = 10;
+ const static int NumPrevPausesForHeuristics = 10;
+ const G1Predictions* _predictor;
+
+ // These exclude marking times.
+ TruncatedSeq* _recent_gc_times_ms;
+
+ TruncatedSeq* _concurrent_mark_remark_times_ms;
+ TruncatedSeq* _concurrent_mark_cleanup_times_ms;
+
+ TruncatedSeq* _alloc_rate_ms_seq;
+ double _prev_collection_pause_end_ms;
+
+ TruncatedSeq* _rs_length_diff_seq;
+ TruncatedSeq* _cost_per_card_ms_seq;
+ TruncatedSeq* _cost_scan_hcc_seq;
+ TruncatedSeq* _young_cards_per_entry_ratio_seq;
+ TruncatedSeq* _mixed_cards_per_entry_ratio_seq;
+ TruncatedSeq* _cost_per_entry_ms_seq;
+ TruncatedSeq* _mixed_cost_per_entry_ms_seq;
+ TruncatedSeq* _cost_per_byte_ms_seq;
+ TruncatedSeq* _constant_other_time_ms_seq;
+ TruncatedSeq* _young_other_cost_per_region_ms_seq;
+ TruncatedSeq* _non_young_other_cost_per_region_ms_seq;
+
+ TruncatedSeq* _pending_cards_seq;
+ TruncatedSeq* _rs_lengths_seq;
+
+ TruncatedSeq* _cost_per_byte_ms_during_cm_seq;
+
+ // Statistics kept per GC stoppage, pause or full.
+ TruncatedSeq* _recent_prev_end_times_for_all_gcs_sec;
+
+ // The ratio of gc time to elapsed time, computed over recent pauses,
+ // and the ratio for just the last pause.
+ double _recent_avg_pause_time_ratio;
+ double _last_pause_time_ratio;
+
+ double get_new_prediction(TruncatedSeq const* seq) const;
+ size_t get_new_size_prediction(TruncatedSeq const* seq) const;
+
+public:
+ G1Analytics(const G1Predictions* predictor);
+
+ double prev_collection_pause_end_ms() const {
+ return _prev_collection_pause_end_ms;
+ }
+
+ double recent_avg_pause_time_ratio() const {
+ return _recent_avg_pause_time_ratio;
+ }
+
+ double last_pause_time_ratio() const {
+ return _last_pause_time_ratio;
+ }
+
+ uint number_of_recorded_pause_times() const {
+ return NumPrevPausesForHeuristics;
+ }
+
+ void append_prev_collection_pause_end_ms(double ms) {
+ _prev_collection_pause_end_ms += ms;
+ }
+
+ void report_concurrent_mark_remark_times_ms(double ms);
+ void report_concurrent_mark_cleanup_times_ms(double ms);
+ void report_alloc_rate_ms(double alloc_rate);
+ void report_cost_per_card_ms(double cost_per_card_ms);
+ void report_cost_scan_hcc(double cost_scan_hcc);
+ void report_cost_per_entry_ms(double cost_per_entry_ms, bool last_gc_was_young);
+ void report_cards_per_entry_ratio(double cards_per_entry_ratio, bool last_gc_was_young);
+ void report_rs_length_diff(double rs_length_diff);
+ void report_cost_per_byte_ms(double cost_per_byte_ms, bool in_marking_window);
+ void report_young_other_cost_per_region_ms(double other_cost_per_region_ms);
+ void report_non_young_other_cost_per_region_ms(double other_cost_per_region_ms);
+ void report_constant_other_time_ms(double constant_other_time_ms);
+ void report_pending_cards(double pending_cards);
+ void report_rs_lengths(double rs_lengths);
+
+ size_t predict_rs_length_diff() const;
+
+ double predict_alloc_rate_ms() const;
+ int num_alloc_rate_ms() const;
+
+ double predict_cost_per_card_ms() const;
+
+ double predict_scan_hcc_ms() const;
+
+ double predict_rs_update_time_ms(size_t pending_cards) const;
+
+ double predict_young_cards_per_entry_ratio() const;
+
+ double predict_mixed_cards_per_entry_ratio() const;
+
+ size_t predict_card_num(size_t rs_length, bool gcs_are_young) const;
+
+ double predict_rs_scan_time_ms(size_t card_num, bool gcs_are_young) const;
+
+ double predict_mixed_rs_scan_time_ms(size_t card_num) const;
+
+ double predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const;
+
+ double predict_object_copy_time_ms(size_t bytes_to_copy, bool during_concurrent_mark) const;
+
+ double predict_constant_other_time_ms() const;
+
+ double predict_young_other_time_ms(size_t young_num) const;
+
+ double predict_non_young_other_time_ms(size_t non_young_num) const;
+
+ double predict_remark_time_ms() const;
+
+ double predict_cleanup_time_ms() const;
+
+ size_t predict_rs_lengths() const;
+ size_t predict_pending_cards() const;
+
+ // Add a new GC of the given duration and end time to the record.
+ void update_recent_gc_times(double end_time_sec, double elapsed_ms);
+ void compute_pause_time_ratio(double interval_ms, double pause_time_ms);
+
+ double last_known_gc_end_time_sec() const;
+};
+
+#endif // SHARE_VM_GC_G1_G1MEASUREMENTS_HPP
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -34,10 +34,12 @@
#include "gc/g1/concurrentMarkThread.inline.hpp"
#include "gc/g1/g1Allocator.inline.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1CollectionSet.hpp"
#include "gc/g1/g1CollectorPolicy.hpp"
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1EvacStats.inline.hpp"
#include "gc/g1/g1GCPhaseTimes.hpp"
+#include "gc/g1/g1HeapSizingPolicy.hpp"
#include "gc/g1/g1HeapTransition.hpp"
#include "gc/g1/g1HeapVerifier.hpp"
#include "gc/g1/g1MarkSweep.hpp"
@@ -566,7 +568,7 @@
// Give a warning if we seem to be looping forever.
if ((QueuedAllocationWarningCount > 0) &&
(try_count % QueuedAllocationWarningCount == 0)) {
- warning("G1CollectedHeap::mem_allocate retries %d times", try_count);
+ log_warning(gc)("G1CollectedHeap::mem_allocate retries %d times", try_count);
}
}
@@ -675,8 +677,8 @@
// Give a warning if we seem to be looping forever.
if ((QueuedAllocationWarningCount > 0) &&
(try_count % QueuedAllocationWarningCount == 0)) {
- warning("G1CollectedHeap::attempt_allocation_slow() "
- "retries %d times", try_count);
+ log_warning(gc)("G1CollectedHeap::attempt_allocation_slow() "
+ "retries %d times", try_count);
}
}
@@ -1091,8 +1093,8 @@
if ((QueuedAllocationWarningCount > 0) &&
(try_count % QueuedAllocationWarningCount == 0)) {
- warning("G1CollectedHeap::attempt_allocation_humongous() "
- "retries %d times", try_count);
+ log_warning(gc)("G1CollectedHeap::attempt_allocation_humongous() "
+ "retries %d times", try_count);
}
}
@@ -1228,6 +1230,7 @@
ResourceMark rm;
print_heap_before_gc();
+ print_heap_regions();
trace_heap_before_gc(gc_tracer);
size_t metadata_prev_used = MetaspaceAux::used_bytes();
@@ -1302,9 +1305,9 @@
// set between the last GC or pause and now. We need to clear the
// incremental collection set and then start rebuilding it afresh
// after this full GC.
- abandon_collection_set(g1_policy()->inc_cset_head());
- g1_policy()->clear_incremental_cset();
- g1_policy()->stop_incremental_cset_building();
+ abandon_collection_set(collection_set()->inc_head());
+ collection_set()->clear_incremental();
+ collection_set()->stop_incremental_building();
tear_down_region_sets(false /* free_list_only */);
collector_state()->set_gcs_are_young(true);
@@ -1421,13 +1424,13 @@
// the full GC has compacted objects and updated TAMS but not updated
// the prev bitmap.
if (G1VerifyBitmaps) {
- ((G1CMBitMap*) concurrent_mark()->prevMarkBitMap())->clearAll();
+ _cm->clear_prev_bitmap(workers());
}
_verifier->check_bitmaps("Full GC End");
// Start a new incremental collection set for the next pause
- assert(g1_policy()->collection_set() == NULL, "must be");
- g1_policy()->start_incremental_cset_building();
+ assert(collection_set()->head() == NULL, "must be");
+ collection_set()->start_incremental_building();
clear_cset_fast_test();
@@ -1446,6 +1449,7 @@
heap_transition.print();
print_heap_after_gc();
+ print_heap_regions();
trace_heap_after_gc(gc_tracer);
post_full_gc_dump(gc_timer);
@@ -1741,6 +1745,7 @@
G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) :
CollectedHeap(),
_g1_policy(policy_),
+ _collection_set(this),
_dirty_card_queue_set(false),
_is_alive_closure_cm(this),
_is_alive_closure_stw(this),
@@ -1765,15 +1770,12 @@
_expand_heap_after_alloc_failure(true),
_old_marking_cycles_started(0),
_old_marking_cycles_completed(0),
- _heap_summary_sent(false),
_in_cset_fast_test(),
_dirty_cards_region_list(NULL),
_worker_cset_start_region(NULL),
_worker_cset_start_region_time_stamp(NULL),
_gc_timer_stw(new (ResourceObj::C_HEAP, mtGC) STWGCTimer()),
- _gc_timer_cm(new (ResourceObj::C_HEAP, mtGC) ConcurrentGCTimer()),
- _gc_tracer_stw(new (ResourceObj::C_HEAP, mtGC) G1NewTracer()),
- _gc_tracer_cm(new (ResourceObj::C_HEAP, mtGC) G1OldTracer()) {
+ _gc_tracer_stw(new (ResourceObj::C_HEAP, mtGC) G1NewTracer()) {
_workers = new WorkGang("GC Thread", ParallelGCThreads,
/* are_GC_task_threads */true,
@@ -1782,6 +1784,9 @@
_verifier = new G1HeapVerifier(this);
_allocator = G1Allocator::create_allocator(this);
+
+ _heap_sizing_policy = G1HeapSizingPolicy::create(this, _g1_policy->analytics());
+
_humongous_object_threshold_in_words = humongous_threshold_for(HeapRegion::GrainWords);
// Override the default _filler_array_max_size so that no humongous filler
@@ -2314,52 +2319,6 @@
FullGCCount_lock->notify_all();
}
-void G1CollectedHeap::register_concurrent_cycle_start(const Ticks& start_time) {
- GCIdMarkAndRestore conc_gc_id_mark;
- collector_state()->set_concurrent_cycle_started(true);
- _gc_timer_cm->register_gc_start(start_time);
-
- _gc_tracer_cm->report_gc_start(gc_cause(), _gc_timer_cm->gc_start());
- trace_heap_before_gc(_gc_tracer_cm);
- _cmThread->set_gc_id(GCId::current());
-}
-
-void G1CollectedHeap::register_concurrent_cycle_end() {
- if (collector_state()->concurrent_cycle_started()) {
- GCIdMarkAndRestore conc_gc_id_mark(_cmThread->gc_id());
- if (_cm->has_aborted()) {
- _gc_tracer_cm->report_concurrent_mode_failure();
-
- // ConcurrentGCTimer will be ended as well.
- _cm->register_concurrent_gc_end_and_stop_timer();
- } else {
- _gc_timer_cm->register_gc_end();
- }
-
- _gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions());
-
- // Clear state variables to prepare for the next concurrent cycle.
- collector_state()->set_concurrent_cycle_started(false);
- _heap_summary_sent = false;
- }
-}
-
-void G1CollectedHeap::trace_heap_after_concurrent_cycle() {
- if (collector_state()->concurrent_cycle_started()) {
- // This function can be called when:
- // the cleanup pause is run
- // the concurrent cycle is aborted before the cleanup pause.
- // the concurrent cycle is aborted after the cleanup pause,
- // but before the concurrent cycle end has been registered.
- // Make sure that we only send the heap information once.
- if (!_heap_summary_sent) {
- GCIdMarkAndRestore conc_gc_id_mark(_cmThread->gc_id());
- trace_heap_after_gc(_gc_tracer_cm);
- _heap_summary_sent = true;
- }
- }
-}
-
void G1CollectedHeap::collect(GCCause::Cause cause) {
assert_heap_not_locked();
@@ -2545,8 +2504,8 @@
// p threads
// Then thread t will start at region floor ((t * n) / p)
- result = g1_policy()->collection_set();
- uint cs_size = g1_policy()->cset_region_length();
+ result = collection_set()->head();
+ uint cs_size = collection_set()->region_length();
uint active_workers = workers()->active_workers();
uint end_ind = (cs_size * worker_i) / active_workers;
@@ -2577,7 +2536,7 @@
}
void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) {
- HeapRegion* r = g1_policy()->collection_set();
+ HeapRegion* r = collection_set()->head();
while (r != NULL) {
HeapRegion* next = r->next_in_collection_set();
if (cl->doHeapRegion(r)) {
@@ -2606,7 +2565,7 @@
}
cur = next;
}
- cur = g1_policy()->collection_set();
+ cur = collection_set()->head();
while (cur != r) {
HeapRegion* next = cur->next_in_collection_set();
if (cl->doHeapRegion(cur) && false) {
@@ -2716,6 +2675,14 @@
return false; // keep some compilers happy
}
+void G1CollectedHeap::print_heap_regions() const {
+ LogHandle(gc, heap, region) log;
+ if (log.is_trace()) {
+ ResourceMark rm;
+ print_regions_on(log.trace_stream());
+ }
+}
+
void G1CollectedHeap::print_on(outputStream* st) const {
st->print(" %-20s", "garbage-first heap");
st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K",
@@ -2729,18 +2696,14 @@
uint young_regions = _young_list->length();
st->print("%u young (" SIZE_FORMAT "K), ", young_regions,
(size_t) young_regions * HeapRegion::GrainBytes / K);
- uint survivor_regions = g1_policy()->recorded_survivor_regions();
+ uint survivor_regions = _young_list->survivor_length();
st->print("%u survivors (" SIZE_FORMAT "K)", survivor_regions,
(size_t) survivor_regions * HeapRegion::GrainBytes / K);
st->cr();
MetaspaceAux::print_on(st);
}
-void G1CollectedHeap::print_extended_on(outputStream* st) const {
- print_on(st);
-
- // Print the per-region information.
- st->cr();
+void G1CollectedHeap::print_regions_on(outputStream* st) const {
st->print_cr("Heap Regions: E=young(eden), S=young(survivor), O=old, "
"HS=humongous(starts), HC=humongous(continues), "
"CS=collection set, F=free, A=archive, TS=gc time stamp, "
@@ -2750,6 +2713,13 @@
heap_region_iterate(&blk);
}
+void G1CollectedHeap::print_extended_on(outputStream* st) const {
+ print_on(st);
+
+ // Print the per-region information.
+ print_regions_on(st);
+}
+
void G1CollectedHeap::print_on_error(outputStream* st) const {
this->CollectedHeap::print_on_error(st);
@@ -2839,12 +2809,14 @@
size_t eden_used_bytes = young_list->eden_used_bytes();
size_t survivor_used_bytes = young_list->survivor_used_bytes();
+ size_t heap_used = Heap_lock->owned_by_self() ? used() : used_unlocked();
size_t eden_capacity_bytes =
(g1_policy()->young_list_target_length() * HeapRegion::GrainBytes) - survivor_used_bytes;
VirtualSpaceSummary heap_summary = create_heap_space_summary();
- return G1HeapSummary(heap_summary, used(), eden_used_bytes, eden_capacity_bytes, survivor_used_bytes, num_regions());
+ return G1HeapSummary(heap_summary, heap_used, eden_used_bytes,
+ eden_capacity_bytes, survivor_used_bytes, num_regions());
}
G1EvacSummary G1CollectedHeap::create_g1_evac_summary(G1EvacStats* stats) {
@@ -2862,7 +2834,6 @@
gc_tracer->report_metaspace_summary(when, metaspace_summary);
}
-
G1CollectedHeap* G1CollectedHeap::heap() {
CollectedHeap* heap = Universe::heap();
assert(heap != NULL, "Uninitialized access to G1CollectedHeap::heap()");
@@ -3201,15 +3172,19 @@
wait_for_root_region_scanning();
print_heap_before_gc();
+ print_heap_regions();
trace_heap_before_gc(_gc_tracer_stw);
_verifier->verify_region_sets_optional();
_verifier->verify_dirty_young_regions();
- // This call will decide whether this pause is an initial-mark
- // pause. If it is, during_initial_mark_pause() will return true
- // for the duration of this pause.
- g1_policy()->decide_on_conc_mark_initiation();
+ // We should not be doing initial mark unless the conc mark thread is running
+ if (!_cmThread->should_terminate()) {
+ // This call will decide whether this pause is an initial-mark
+ // pause. If it is, during_initial_mark_pause() will return true
+ // for the duration of this pause.
+ g1_policy()->decide_on_conc_mark_initiation();
+ }
// We do not allow initial-mark to be piggy-backed on a mixed GC.
assert(!collector_state()->during_initial_mark_pause() ||
@@ -3231,7 +3206,7 @@
// We are about to start a marking cycle, so we increment the
// full collection counter.
increment_old_marking_cycles_started();
- register_concurrent_cycle_start(_gc_timer_stw->gc_start());
+ _cm->gc_tracer_cm()->set_gc_cause(gc_cause());
}
_gc_tracer_stw->report_yc_type(collector_state()->yc_type());
@@ -3336,10 +3311,9 @@
concurrent_mark()->checkpointRootsInitialPre();
}
- double time_remaining_ms = g1_policy()->finalize_young_cset_part(target_pause_time_ms);
- g1_policy()->finalize_old_cset_part(time_remaining_ms);
-
- evacuation_info.set_collectionset_regions(g1_policy()->cset_region_length());
+ g1_policy()->finalize_collection_set(target_pause_time_ms);
+
+ evacuation_info.set_collectionset_regions(collection_set()->region_length());
// Make sure the remembered sets are up to date. This needs to be
// done before register_humongous_regions_with_cset(), because the
@@ -3358,7 +3332,7 @@
_cm->verify_no_cset_oops();
if (_hr_printer.is_active()) {
- HeapRegion* hr = g1_policy()->collection_set();
+ HeapRegion* hr = collection_set()->head();
while (hr != NULL) {
_hr_printer.cset(hr);
hr = hr->next_in_collection_set();
@@ -3373,7 +3347,7 @@
// Initialize the GC alloc regions.
_allocator->init_gc_alloc_regions(evacuation_info);
- G1ParScanThreadStateSet per_thread_states(this, workers()->active_workers(), g1_policy()->young_cset_region_length());
+ G1ParScanThreadStateSet per_thread_states(this, workers()->active_workers(), collection_set()->young_region_length());
pre_evacuate_collection_set();
// Actually do the work...
@@ -3382,18 +3356,18 @@
post_evacuate_collection_set(evacuation_info, &per_thread_states);
const size_t* surviving_young_words = per_thread_states.surviving_young_words();
- free_collection_set(g1_policy()->collection_set(), evacuation_info, surviving_young_words);
+ free_collection_set(collection_set()->head(), evacuation_info, surviving_young_words);
eagerly_reclaim_humongous_regions();
- g1_policy()->clear_collection_set();
+ collection_set()->clear_head();
record_obj_copy_mem_stats();
_survivor_evac_stats.adjust_desired_plab_sz();
_old_evac_stats.adjust_desired_plab_sz();
// Start a new incremental collection set for the next pause.
- g1_policy()->start_incremental_cset_building();
+ collection_set()->start_incremental_building();
clear_cset_fast_test();
@@ -3404,10 +3378,6 @@
assert(check_young_list_empty(false /* check_heap */),
"young list should be empty");
- g1_policy()->record_survivor_regions(_young_list->survivor_length(),
- _young_list->first_survivor_region(),
- _young_list->last_survivor_region());
-
_young_list->reset_auxilary_lists();
if (evacuation_failed()) {
@@ -3442,7 +3412,7 @@
_allocator->init_mutator_alloc_region();
{
- size_t expand_bytes = g1_policy()->expansion_amount();
+ size_t expand_bytes = _heap_sizing_policy->expansion_amount();
if (expand_bytes > 0) {
size_t bytes_before = capacity();
// No need for an ergo logging here,
@@ -3468,7 +3438,7 @@
size_t total_cards_scanned = per_thread_states.total_cards_scanned();
g1_policy()->record_collection_pause_end(pause_time_ms, total_cards_scanned, heap_used_bytes_before_gc);
- evacuation_info.set_collectionset_used_before(g1_policy()->collection_set_bytes_used_before());
+ evacuation_info.set_collectionset_used_before(collection_set()->bytes_used_before());
evacuation_info.set_bytes_copied(g1_policy()->bytes_copied_during_gc());
MemoryService::track_memory_usage();
@@ -3538,6 +3508,7 @@
TASKQUEUE_STATS_ONLY(reset_taskqueue_stats());
print_heap_after_gc();
+ print_heap_regions();
trace_heap_after_gc(_gc_tracer_stw);
// We must call G1MonitoringSupport::update_sizes() in the same scoping level
@@ -3776,11 +3747,12 @@
"claim value %d after unlink less than initial symbol table size %d",
SymbolTable::parallel_claimed_index(), _initial_symbol_table_size);
- log_debug(gc, stringdedup)("Cleaned string and symbol table, "
- "strings: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed, "
- "symbols: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed",
- strings_processed(), strings_removed(),
- symbols_processed(), symbols_removed());
+ log_info(gc, stringtable)(
+ "Cleaned string and symbol table, "
+ "strings: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed, "
+ "symbols: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed",
+ strings_processed(), strings_removed(),
+ symbols_processed(), symbols_removed());
}
void work(uint worker_id) {
@@ -4083,14 +4055,10 @@
void G1CollectedHeap::unlink_string_and_symbol_table(BoolObjectClosure* is_alive,
bool process_strings, bool process_symbols) {
- {
+ { // Timing scope
G1StringSymbolTableUnlinkTask g1_unlink_task(is_alive, process_strings, process_symbols);
workers()->run_task(&g1_unlink_task);
}
-
- if (G1StringDedup::is_enabled()) {
- G1StringDedup::unlink(is_alive);
- }
}
class G1RedirtyLoggedCardsTask : public AbstractGangTask {
@@ -4909,7 +4877,7 @@
if (cur->is_young()) {
int index = cur->young_index_in_cset();
assert(index != -1, "invariant");
- assert((uint) index < policy->young_cset_region_length(), "invariant");
+ assert((uint) index < collection_set()->young_region_length(), "invariant");
size_t words_survived = surviving_young_words[index];
cur->record_surv_words_in_group(words_survived);
@@ -5382,7 +5350,7 @@
assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */);
assert(alloc_region->is_eden(), "all mutator alloc regions should be eden");
- g1_policy()->add_region_to_incremental_cset_lhs(alloc_region);
+ collection_set()->add_eden_region(alloc_region);
increase_used(allocated_bytes);
_hr_printer.retire(alloc_region);
// We update the eden sizes here, when the region is retired,
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -28,6 +28,7 @@
#include "gc/g1/evacuationInfo.hpp"
#include "gc/g1/g1AllocationContext.hpp"
#include "gc/g1/g1BiasedArray.hpp"
+#include "gc/g1/g1CollectionSet.hpp"
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1ConcurrentMark.hpp"
#include "gc/g1/g1HRPrinter.hpp"
@@ -65,17 +66,16 @@
class SpaceClosure;
class CompactibleSpaceClosure;
class Space;
+class G1CollectionSet;
class G1CollectorPolicy;
class G1RemSet;
class HeapRegionRemSetIterator;
class G1ConcurrentMark;
class ConcurrentMarkThread;
class ConcurrentG1Refine;
-class ConcurrentGCTimer;
class GenerationCounters;
class STWGCTimer;
class G1NewTracer;
-class G1OldTracer;
class EvacuationFailedInfo;
class nmethod;
class Ticks;
@@ -83,6 +83,7 @@
class G1Allocator;
class G1ArchiveAllocator;
class G1HeapVerifier;
+class G1HeapSizingPolicy;
typedef OverflowTaskQueue<StarTask, mtGC> RefToScanQueue;
typedef GenericTaskQueueSet<RefToScanQueue, mtGC> RefToScanQueueSet;
@@ -268,8 +269,6 @@
// concurrent cycles) we have completed.
volatile uint _old_marking_cycles_completed;
- bool _heap_summary_sent;
-
// This is a non-product method that is helpful for testing. It is
// called at the end of a GC and artificially expands the heap by
// allocating a number of dead regions. This way we can induce very
@@ -362,6 +361,9 @@
// The current policy object for the collector.
G1CollectorPolicy* _g1_policy;
+ G1HeapSizingPolicy* _heap_sizing_policy;
+
+ G1CollectionSet _collection_set;
// This is the second level of trying to allocate a new region. If
// new_region() didn't find a region on the free_list, this call will
@@ -618,10 +620,6 @@
return _old_marking_cycles_completed;
}
- void register_concurrent_cycle_start(const Ticks& start_time);
- void register_concurrent_cycle_end();
- void trace_heap_after_concurrent_cycle();
-
G1HRPrinter* hr_printer() { return &_hr_printer; }
// Allocates a new heap region instance.
@@ -896,9 +894,7 @@
ReferenceProcessor* _ref_processor_stw;
STWGCTimer* _gc_timer_stw;
- ConcurrentGCTimer* _gc_timer_cm;
- G1OldTracer* _gc_tracer_cm;
G1NewTracer* _gc_tracer_stw;
// During reference object discovery, the _is_alive_non_header
@@ -985,6 +981,9 @@
// The current policy object for the collector.
G1CollectorPolicy* g1_policy() const { return _g1_policy; }
+ const G1CollectionSet* collection_set() const { return &_collection_set; }
+ G1CollectionSet* collection_set() { return &_collection_set; }
+
virtual CollectorPolicy* collector_policy() const;
// Adaptive size policy. No such thing for g1.
@@ -1029,9 +1028,6 @@
// The Concurrent Marking reference processor...
ReferenceProcessor* ref_processor_cm() const { return _ref_processor_cm; }
- ConcurrentGCTimer* gc_timer_cm() const { return _gc_timer_cm; }
- G1OldTracer* gc_tracer_cm() const { return _gc_tracer_cm; }
-
virtual size_t capacity() const;
virtual size_t used() const;
// This should be called when we're not holding the heap lock. The
@@ -1285,6 +1281,12 @@
return true;
}
+ // The reference pending list lock is acquired from from the
+ // ConcurrentMarkThread.
+ virtual bool needs_reference_pending_list_locker_thread() const {
+ return true;
+ }
+
inline bool is_in_young(const oop obj);
virtual bool is_scavengable(const void* addr);
@@ -1463,7 +1465,11 @@
G1EvacSummary create_g1_evac_summary(G1EvacStats* stats);
// Printing
+private:
+ void print_heap_regions() const;
+ void print_regions_on(outputStream* st) const;
+public:
virtual void print_on(outputStream* st) const;
virtual void print_extended_on(outputStream* st) const;
virtual void print_on_error(outputStream* st) const;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1CollectionSet.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2016, 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/g1CollectionSet.hpp"
+#include "gc/g1/g1CollectorPolicy.hpp"
+#include "gc/g1/g1CollectorState.hpp"
+#include "gc/g1/heapRegion.inline.hpp"
+#include "gc/g1/heapRegionRemSet.hpp"
+#include "gc/g1/heapRegionSet.hpp"
+#include "utilities/debug.hpp"
+
+G1CollectorState* G1CollectionSet::collector_state() {
+ return _g1->collector_state();
+}
+
+G1GCPhaseTimes* G1CollectionSet::phase_times() {
+ return _policy->phase_times();
+}
+
+CollectionSetChooser* G1CollectionSet::cset_chooser() {
+ return _cset_chooser;
+}
+
+double G1CollectionSet::predict_region_elapsed_time_ms(HeapRegion* hr) {
+ return _policy->predict_region_elapsed_time_ms(hr, collector_state()->gcs_are_young());
+}
+
+
+G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h) :
+ _g1(g1h),
+ _policy(NULL),
+ _cset_chooser(new CollectionSetChooser()),
+ _eden_region_length(0),
+ _survivor_region_length(0),
+ _old_region_length(0),
+
+ _head(NULL),
+ _bytes_used_before(0),
+ _recorded_rs_lengths(0),
+ // Incremental CSet attributes
+ _inc_build_state(Inactive),
+ _inc_head(NULL),
+ _inc_tail(NULL),
+ _inc_bytes_used_before(0),
+ _inc_recorded_rs_lengths(0),
+ _inc_recorded_rs_lengths_diffs(0),
+ _inc_predicted_elapsed_time_ms(0.0),
+ _inc_predicted_elapsed_time_ms_diffs(0.0) {}
+
+G1CollectionSet::~G1CollectionSet() {
+ delete _cset_chooser;
+}
+
+void G1CollectionSet::init_region_lengths(uint eden_cset_region_length,
+ uint survivor_cset_region_length) {
+ _eden_region_length = eden_cset_region_length;
+ _survivor_region_length = survivor_cset_region_length;
+ _old_region_length = 0;
+}
+
+void G1CollectionSet::set_recorded_rs_lengths(size_t rs_lengths) {
+ _recorded_rs_lengths = rs_lengths;
+}
+
+// Add the heap region at the head of the non-incremental collection set
+void G1CollectionSet::add_old_region(HeapRegion* hr) {
+ assert(_inc_build_state == Active, "Precondition");
+ assert(hr->is_old(), "the region should be old");
+
+ assert(!hr->in_collection_set(), "should not already be in the CSet");
+ _g1->register_old_region_with_cset(hr);
+ hr->set_next_in_collection_set(_head);
+ _head = hr;
+ _bytes_used_before += hr->used();
+ size_t rs_length = hr->rem_set()->occupied();
+ _recorded_rs_lengths += rs_length;
+ _old_region_length += 1;
+}
+
+// Initialize the per-collection-set information
+void G1CollectionSet::start_incremental_building() {
+ assert(_inc_build_state == Inactive, "Precondition");
+
+ _inc_head = NULL;
+ _inc_tail = NULL;
+ _inc_bytes_used_before = 0;
+
+ _inc_recorded_rs_lengths = 0;
+ _inc_recorded_rs_lengths_diffs = 0;
+ _inc_predicted_elapsed_time_ms = 0.0;
+ _inc_predicted_elapsed_time_ms_diffs = 0.0;
+ _inc_build_state = Active;
+}
+
+void G1CollectionSet::finalize_incremental_building() {
+ assert(_inc_build_state == Active, "Precondition");
+ assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint");
+
+ // The two "main" fields, _inc_recorded_rs_lengths and
+ // _inc_predicted_elapsed_time_ms, are updated by the thread
+ // that adds a new region to the CSet. Further updates by the
+ // concurrent refinement thread that samples the young RSet lengths
+ // are accumulated in the *_diffs fields. Here we add the diffs to
+ // the "main" fields.
+
+ if (_inc_recorded_rs_lengths_diffs >= 0) {
+ _inc_recorded_rs_lengths += _inc_recorded_rs_lengths_diffs;
+ } else {
+ // This is defensive. The diff should in theory be always positive
+ // as RSets can only grow between GCs. However, given that we
+ // sample their size concurrently with other threads updating them
+ // it's possible that we might get the wrong size back, which
+ // could make the calculations somewhat inaccurate.
+ size_t diffs = (size_t) (-_inc_recorded_rs_lengths_diffs);
+ if (_inc_recorded_rs_lengths >= diffs) {
+ _inc_recorded_rs_lengths -= diffs;
+ } else {
+ _inc_recorded_rs_lengths = 0;
+ }
+ }
+ _inc_predicted_elapsed_time_ms += _inc_predicted_elapsed_time_ms_diffs;
+
+ _inc_recorded_rs_lengths_diffs = 0;
+ _inc_predicted_elapsed_time_ms_diffs = 0.0;
+}
+
+void G1CollectionSet::update_young_region_prediction(HeapRegion* hr,
+ size_t new_rs_length) {
+ // Update the CSet information that is dependent on the new RS length
+ assert(hr->is_young(), "Precondition");
+ assert(!SafepointSynchronize::is_at_safepoint(), "should not be at a safepoint");
+
+ // We could have updated _inc_recorded_rs_lengths and
+ // _inc_predicted_elapsed_time_ms directly but we'd need to do
+ // that atomically, as this code is executed by a concurrent
+ // refinement thread, potentially concurrently with a mutator thread
+ // allocating a new region and also updating the same fields. To
+ // avoid the atomic operations we accumulate these updates on two
+ // separate fields (*_diffs) and we'll just add them to the "main"
+ // fields at the start of a GC.
+
+ ssize_t old_rs_length = (ssize_t) hr->recorded_rs_length();
+ ssize_t rs_lengths_diff = (ssize_t) new_rs_length - old_rs_length;
+ _inc_recorded_rs_lengths_diffs += rs_lengths_diff;
+
+ double old_elapsed_time_ms = hr->predicted_elapsed_time_ms();
+ double new_region_elapsed_time_ms = predict_region_elapsed_time_ms(hr);
+ double elapsed_ms_diff = new_region_elapsed_time_ms - old_elapsed_time_ms;
+ _inc_predicted_elapsed_time_ms_diffs += elapsed_ms_diff;
+
+ hr->set_recorded_rs_length(new_rs_length);
+ hr->set_predicted_elapsed_time_ms(new_region_elapsed_time_ms);
+}
+
+void G1CollectionSet::add_young_region_common(HeapRegion* hr) {
+ assert(hr->is_young(), "invariant");
+ assert(hr->young_index_in_cset() > -1, "should have already been set");
+ assert(_inc_build_state == Active, "Precondition");
+
+ // This routine is used when:
+ // * adding survivor regions to the incremental cset at the end of an
+ // evacuation pause or
+ // * adding the current allocation region to the incremental cset
+ // when it is retired.
+ // Therefore this routine may be called at a safepoint by the
+ // VM thread, or in-between safepoints by mutator threads (when
+ // retiring the current allocation region)
+ // We need to clear and set the cached recorded/cached collection set
+ // information in the heap region here (before the region gets added
+ // to the collection set). An individual heap region's cached values
+ // are calculated, aggregated with the policy collection set info,
+ // and cached in the heap region here (initially) and (subsequently)
+ // by the Young List sampling code.
+
+ size_t rs_length = hr->rem_set()->occupied();
+ double region_elapsed_time_ms = predict_region_elapsed_time_ms(hr);
+
+ // Cache the values we have added to the aggregated information
+ // in the heap region in case we have to remove this region from
+ // the incremental collection set, or it is updated by the
+ // rset sampling code
+ hr->set_recorded_rs_length(rs_length);
+ hr->set_predicted_elapsed_time_ms(region_elapsed_time_ms);
+
+ size_t used_bytes = hr->used();
+ _inc_recorded_rs_lengths += rs_length;
+ _inc_predicted_elapsed_time_ms += region_elapsed_time_ms;
+ _inc_bytes_used_before += used_bytes;
+
+ assert(!hr->in_collection_set(), "invariant");
+ _g1->register_young_region_with_cset(hr);
+ assert(hr->next_in_collection_set() == NULL, "invariant");
+}
+
+// Add the region at the RHS of the incremental cset
+void G1CollectionSet::add_survivor_regions(HeapRegion* hr) {
+ // We should only ever be appending survivors at the end of a pause
+ assert(hr->is_survivor(), "Logic");
+
+ // Do the 'common' stuff
+ add_young_region_common(hr);
+
+ // Now add the region at the right hand side
+ if (_inc_tail == NULL) {
+ assert(_inc_head == NULL, "invariant");
+ _inc_head = hr;
+ } else {
+ _inc_tail->set_next_in_collection_set(hr);
+ }
+ _inc_tail = hr;
+}
+
+// Add the region to the LHS of the incremental cset
+void G1CollectionSet::add_eden_region(HeapRegion* hr) {
+ // Survivors should be added to the RHS at the end of a pause
+ assert(hr->is_eden(), "Logic");
+
+ // Do the 'common' stuff
+ add_young_region_common(hr);
+
+ // Add the region at the left hand side
+ hr->set_next_in_collection_set(_inc_head);
+ if (_inc_head == NULL) {
+ assert(_inc_tail == NULL, "Invariant");
+ _inc_tail = hr;
+ }
+ _inc_head = hr;
+}
+
+#ifndef PRODUCT
+void G1CollectionSet::print(HeapRegion* list_head, outputStream* st) {
+ assert(list_head == inc_head() || list_head == head(), "must be");
+
+ st->print_cr("\nCollection_set:");
+ HeapRegion* csr = list_head;
+ while (csr != NULL) {
+ HeapRegion* next = csr->next_in_collection_set();
+ assert(csr->in_collection_set(), "bad CS");
+ st->print_cr(" " HR_FORMAT ", P: " PTR_FORMAT "N: " PTR_FORMAT ", age: %4d",
+ HR_FORMAT_PARAMS(csr),
+ p2i(csr->prev_top_at_mark_start()), p2i(csr->next_top_at_mark_start()),
+ csr->age_in_surv_rate_group_cond());
+ csr = next;
+ }
+}
+#endif // !PRODUCT
+
+double G1CollectionSet::finalize_young_part(double target_pause_time_ms) {
+ double young_start_time_sec = os::elapsedTime();
+
+ YoungList* young_list = _g1->young_list();
+ finalize_incremental_building();
+
+ guarantee(target_pause_time_ms > 0.0,
+ "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms);
+ guarantee(_head == NULL, "Precondition");
+
+ size_t pending_cards = _policy->pending_cards();
+ double base_time_ms = _policy->predict_base_elapsed_time_ms(pending_cards);
+ double time_remaining_ms = MAX2(target_pause_time_ms - base_time_ms, 0.0);
+
+ log_trace(gc, ergo, cset)("Start choosing CSet. pending cards: " SIZE_FORMAT " predicted base time: %1.2fms remaining time: %1.2fms target pause time: %1.2fms",
+ pending_cards, base_time_ms, time_remaining_ms, target_pause_time_ms);
+
+ collector_state()->set_last_gc_was_young(collector_state()->gcs_are_young());
+
+ // The young list is laid with the survivor regions from the previous
+ // pause are appended to the RHS of the young list, i.e.
+ // [Newly Young Regions ++ Survivors from last pause].
+
+ uint survivor_region_length = young_list->survivor_length();
+ uint eden_region_length = young_list->eden_length();
+ init_region_lengths(eden_region_length, survivor_region_length);
+
+ HeapRegion* hr = young_list->first_survivor_region();
+ while (hr != NULL) {
+ assert(hr->is_survivor(), "badly formed young list");
+ // There is a convention that all the young regions in the CSet
+ // are tagged as "eden", so we do this for the survivors here. We
+ // use the special set_eden_pre_gc() as it doesn't check that the
+ // region is free (which is not the case here).
+ hr->set_eden_pre_gc();
+ hr = hr->get_next_young_region();
+ }
+
+ // Clear the fields that point to the survivor list - they are all young now.
+ young_list->clear_survivors();
+
+ _head = _inc_head;
+ _bytes_used_before = _inc_bytes_used_before;
+ time_remaining_ms = MAX2(time_remaining_ms - _inc_predicted_elapsed_time_ms, 0.0);
+
+ log_trace(gc, ergo, cset)("Add young regions to CSet. eden: %u regions, survivors: %u regions, predicted young region time: %1.2fms, target pause time: %1.2fms",
+ eden_region_length, survivor_region_length, _inc_predicted_elapsed_time_ms, target_pause_time_ms);
+
+ // The number of recorded young regions is the incremental
+ // collection set's current size
+ set_recorded_rs_lengths(_inc_recorded_rs_lengths);
+
+ double young_end_time_sec = os::elapsedTime();
+ phase_times()->record_young_cset_choice_time_ms((young_end_time_sec - young_start_time_sec) * 1000.0);
+
+ return time_remaining_ms;
+}
+
+void G1CollectionSet::finalize_old_part(double time_remaining_ms) {
+ double non_young_start_time_sec = os::elapsedTime();
+ double predicted_old_time_ms = 0.0;
+
+ if (!collector_state()->gcs_are_young()) {
+ cset_chooser()->verify();
+ const uint min_old_cset_length = _policy->calc_min_old_cset_length();
+ const uint max_old_cset_length = _policy->calc_max_old_cset_length();
+
+ uint expensive_region_num = 0;
+ bool check_time_remaining = _policy->adaptive_young_list_length();
+
+ HeapRegion* hr = cset_chooser()->peek();
+ while (hr != NULL) {
+ if (old_region_length() >= max_old_cset_length) {
+ // Added maximum number of old regions to the CSet.
+ log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached max). old %u regions, max %u regions",
+ old_region_length(), max_old_cset_length);
+ break;
+ }
+
+ // Stop adding regions if the remaining reclaimable space is
+ // not above G1HeapWastePercent.
+ size_t reclaimable_bytes = cset_chooser()->remaining_reclaimable_bytes();
+ double reclaimable_perc = _policy->reclaimable_bytes_perc(reclaimable_bytes);
+ double threshold = (double) G1HeapWastePercent;
+ if (reclaimable_perc <= threshold) {
+ // We've added enough old regions that the amount of uncollected
+ // reclaimable space is at or below the waste threshold. Stop
+ // adding old regions to the CSet.
+ log_debug(gc, ergo, cset)("Finish adding old regions to CSet (reclaimable percentage not over threshold). "
+ "old %u regions, max %u regions, reclaimable: " SIZE_FORMAT "B (%1.2f%%) threshold: " UINTX_FORMAT "%%",
+ old_region_length(), max_old_cset_length, reclaimable_bytes, reclaimable_perc, G1HeapWastePercent);
+ break;
+ }
+
+ double predicted_time_ms = predict_region_elapsed_time_ms(hr);
+ if (check_time_remaining) {
+ if (predicted_time_ms > time_remaining_ms) {
+ // Too expensive for the current CSet.
+
+ if (old_region_length() >= min_old_cset_length) {
+ // We have added the minimum number of old regions to the CSet,
+ // we are done with this CSet.
+ log_debug(gc, ergo, cset)("Finish adding old regions to CSet (predicted time is too high). "
+ "predicted time: %1.2fms, remaining time: %1.2fms old %u regions, min %u regions",
+ predicted_time_ms, time_remaining_ms, old_region_length(), min_old_cset_length);
+ break;
+ }
+
+ // We'll add it anyway given that we haven't reached the
+ // minimum number of old regions.
+ expensive_region_num += 1;
+ }
+ } else {
+ if (old_region_length() >= min_old_cset_length) {
+ // In the non-auto-tuning case, we'll finish adding regions
+ // to the CSet if we reach the minimum.
+
+ log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached min). old %u regions, min %u regions",
+ old_region_length(), min_old_cset_length);
+ break;
+ }
+ }
+
+ // We will add this region to the CSet.
+ time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0);
+ predicted_old_time_ms += predicted_time_ms;
+ cset_chooser()->pop(); // already have region via peek()
+ _g1->old_set_remove(hr);
+ add_old_region(hr);
+
+ hr = cset_chooser()->peek();
+ }
+ if (hr == NULL) {
+ log_debug(gc, ergo, cset)("Finish adding old regions to CSet (candidate old regions not available)");
+ }
+
+ if (expensive_region_num > 0) {
+ // We print the information once here at the end, predicated on
+ // whether we added any apparently expensive regions or not, to
+ // avoid generating output per region.
+ log_debug(gc, ergo, cset)("Added expensive regions to CSet (old CSet region num not reached min)."
+ "old: %u regions, expensive: %u regions, min: %u regions, remaining time: %1.2fms",
+ old_region_length(), expensive_region_num, min_old_cset_length, time_remaining_ms);
+ }
+
+ cset_chooser()->verify();
+ }
+
+ stop_incremental_building();
+
+ log_debug(gc, ergo, cset)("Finish choosing CSet. old: %u regions, predicted old region time: %1.2fms, time remaining: %1.2f",
+ old_region_length(), predicted_old_time_ms, time_remaining_ms);
+
+ double non_young_end_time_sec = os::elapsedTime();
+ phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1CollectionSet.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2016, 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_G1_G1COLLECTIONSET_HPP
+#define SHARE_VM_GC_G1_G1COLLECTIONSET_HPP
+
+#include "gc/g1/collectionSetChooser.hpp"
+#include "memory/allocation.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class G1CollectedHeap;
+class G1CollectorPolicy;
+class G1CollectorState;
+class G1GCPhaseTimes;
+class HeapRegion;
+
+class G1CollectionSet VALUE_OBJ_CLASS_SPEC {
+ G1CollectedHeap* _g1;
+ G1CollectorPolicy* _policy;
+
+ CollectionSetChooser* _cset_chooser;
+
+ uint _eden_region_length;
+ uint _survivor_region_length;
+ uint _old_region_length;
+
+ // The head of the list (via "next_in_collection_set()") representing the
+ // current collection set. Set from the incrementally built collection
+ // set at the start of the pause.
+ HeapRegion* _head;
+
+ // The number of bytes in the collection set before the pause. Set from
+ // the incrementally built collection set at the start of an evacuation
+ // pause, and incremented in finalize_old_part() when adding old regions
+ // (if any) to the collection set.
+ size_t _bytes_used_before;
+
+ size_t _recorded_rs_lengths;
+
+ // The associated information that is maintained while the incremental
+ // collection set is being built with young regions. Used to populate
+ // the recorded info for the evacuation pause.
+
+ enum CSetBuildType {
+ Active, // We are actively building the collection set
+ Inactive // We are not actively building the collection set
+ };
+
+ CSetBuildType _inc_build_state;
+
+ // The head of the incrementally built collection set.
+ HeapRegion* _inc_head;
+
+ // The tail of the incrementally built collection set.
+ HeapRegion* _inc_tail;
+
+ // The number of bytes in the incrementally built collection set.
+ // Used to set _collection_set_bytes_used_before at the start of
+ // an evacuation pause.
+ size_t _inc_bytes_used_before;
+
+ // The RSet lengths recorded for regions in the CSet. It is updated
+ // by the thread that adds a new region to the CSet. We assume that
+ // only one thread can be allocating a new CSet region (currently,
+ // it does so after taking the Heap_lock) hence no need to
+ // synchronize updates to this field.
+ size_t _inc_recorded_rs_lengths;
+
+ // A concurrent refinement thread periodically samples the young
+ // region RSets and needs to update _inc_recorded_rs_lengths as
+ // the RSets grow. Instead of having to synchronize updates to that
+ // field we accumulate them in this field and add it to
+ // _inc_recorded_rs_lengths_diffs at the start of a GC.
+ ssize_t _inc_recorded_rs_lengths_diffs;
+
+ // The predicted elapsed time it will take to collect the regions in
+ // the CSet. This is updated by the thread that adds a new region to
+ // the CSet. See the comment for _inc_recorded_rs_lengths about
+ // MT-safety assumptions.
+ double _inc_predicted_elapsed_time_ms;
+
+ // See the comment for _inc_recorded_rs_lengths_diffs.
+ double _inc_predicted_elapsed_time_ms_diffs;
+
+ G1CollectorState* collector_state();
+ G1GCPhaseTimes* phase_times();
+
+ double predict_region_elapsed_time_ms(HeapRegion* hr);
+
+public:
+ G1CollectionSet(G1CollectedHeap* g1h);
+ ~G1CollectionSet();
+
+ void set_policy(G1CollectorPolicy* g1p) {
+ assert(_policy == NULL, "should only initialize once");
+ _policy = g1p;
+ }
+
+ CollectionSetChooser* cset_chooser();
+
+ void init_region_lengths(uint eden_cset_region_length,
+ uint survivor_cset_region_length);
+
+ void set_recorded_rs_lengths(size_t rs_lengths);
+
+ uint region_length() const { return young_region_length() +
+ old_region_length(); }
+ uint young_region_length() const { return eden_region_length() +
+ survivor_region_length(); }
+
+ uint eden_region_length() const { return _eden_region_length; }
+ uint survivor_region_length() const { return _survivor_region_length; }
+ uint old_region_length() const { return _old_region_length; }
+
+ // Incremental CSet Support
+
+ // The head of the incrementally built collection set.
+ HeapRegion* inc_head() { return _inc_head; }
+
+ // The tail of the incrementally built collection set.
+ HeapRegion* inc_tail() { return _inc_tail; }
+
+ // Initialize incremental collection set info.
+ void start_incremental_building();
+
+ // Perform any final calculations on the incremental CSet fields
+ // before we can use them.
+ void finalize_incremental_building();
+
+ void clear_incremental() {
+ _inc_head = NULL;
+ _inc_tail = NULL;
+ }
+
+ // Stop adding regions to the incremental collection set
+ void stop_incremental_building() { _inc_build_state = Inactive; }
+
+ // The head of the list (via "next_in_collection_set()") representing the
+ // current collection set.
+ HeapRegion* head() { return _head; }
+
+ void clear_head() { _head = NULL; }
+
+ size_t recorded_rs_lengths() { return _recorded_rs_lengths; }
+
+ size_t bytes_used_before() const {
+ return _bytes_used_before;
+ }
+
+ void reset_bytes_used_before() {
+ _bytes_used_before = 0;
+ }
+
+ // Choose a new collection set. Marks the chosen regions as being
+ // "in_collection_set", and links them together. The head and number of
+ // the collection set are available via access methods.
+ double finalize_young_part(double target_pause_time_ms);
+ void finalize_old_part(double time_remaining_ms);
+
+ // Add old region "hr" to the CSet.
+ void add_old_region(HeapRegion* hr);
+
+ // Update information about hr in the aggregated information for
+ // the incrementally built collection set.
+ void update_young_region_prediction(HeapRegion* hr, size_t new_rs_length);
+
+ // Add hr to the LHS of the incremental collection set.
+ void add_eden_region(HeapRegion* hr);
+
+ // Add hr to the RHS of the incremental collection set.
+ void add_survivor_regions(HeapRegion* hr);
+
+#ifndef PRODUCT
+ void print(HeapRegion* list_head, outputStream* st);
+#endif // !PRODUCT
+
+private:
+ // Update the incremental cset information when adding a region
+ // (should not be called directly).
+ void add_young_region_common(HeapRegion* hr);
+
+};
+
+#endif // SHARE_VM_GC_G1_G1COLLECTIONSET_HPP
+
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -25,11 +25,14 @@
#include "precompiled.hpp"
#include "gc/g1/concurrentG1Refine.hpp"
#include "gc/g1/concurrentMarkThread.inline.hpp"
+#include "gc/g1/g1Analytics.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1CollectionSet.hpp"
#include "gc/g1/g1CollectorPolicy.hpp"
#include "gc/g1/g1ConcurrentMark.hpp"
#include "gc/g1/g1IHOPControl.hpp"
#include "gc/g1/g1GCPhaseTimes.hpp"
+#include "gc/g1/g1YoungGenSizer.hpp"
#include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
#include "gc/shared/gcPolicyCounters.hpp"
@@ -39,107 +42,14 @@
#include "utilities/debug.hpp"
#include "utilities/pair.hpp"
-// Different defaults for different number of GC threads
-// They were chosen by running GCOld and SPECjbb on debris with different
-// numbers of GC threads and choosing them based on the results
-
-// all the same
-static double rs_length_diff_defaults[] = {
- 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
-};
-
-static double cost_per_card_ms_defaults[] = {
- 0.01, 0.005, 0.005, 0.003, 0.003, 0.002, 0.002, 0.0015
-};
-
-// all the same
-static double young_cards_per_entry_ratio_defaults[] = {
- 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0
-};
-
-static double cost_per_entry_ms_defaults[] = {
- 0.015, 0.01, 0.01, 0.008, 0.008, 0.0055, 0.0055, 0.005
-};
-
-static double cost_per_byte_ms_defaults[] = {
- 0.00006, 0.00003, 0.00003, 0.000015, 0.000015, 0.00001, 0.00001, 0.000009
-};
-
-// these should be pretty consistent
-static double constant_other_time_ms_defaults[] = {
- 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0
-};
-
-
-static double young_other_cost_per_region_ms_defaults[] = {
- 0.3, 0.2, 0.2, 0.15, 0.15, 0.12, 0.12, 0.1
-};
-
-static double non_young_other_cost_per_region_ms_defaults[] = {
- 1.0, 0.7, 0.7, 0.5, 0.5, 0.42, 0.42, 0.30
-};
-
G1CollectorPolicy::G1CollectorPolicy() :
_predictor(G1ConfidencePercent / 100.0),
-
- _recent_gc_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)),
-
- _concurrent_mark_remark_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)),
- _concurrent_mark_cleanup_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)),
-
- _alloc_rate_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
- _prev_collection_pause_end_ms(0.0),
- _rs_length_diff_seq(new TruncatedSeq(TruncatedSeqLength)),
- _cost_per_card_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
- _cost_scan_hcc_seq(new TruncatedSeq(TruncatedSeqLength)),
- _young_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)),
- _mixed_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)),
- _cost_per_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
- _mixed_cost_per_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
- _cost_per_byte_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
- _cost_per_byte_ms_during_cm_seq(new TruncatedSeq(TruncatedSeqLength)),
- _constant_other_time_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
- _young_other_cost_per_region_ms_seq(new TruncatedSeq(TruncatedSeqLength)),
- _non_young_other_cost_per_region_ms_seq(
- new TruncatedSeq(TruncatedSeqLength)),
-
- _pending_cards_seq(new TruncatedSeq(TruncatedSeqLength)),
- _rs_lengths_seq(new TruncatedSeq(TruncatedSeqLength)),
-
+ _analytics(new G1Analytics(&_predictor)),
_pause_time_target_ms((double) MaxGCPauseMillis),
-
- _recent_prev_end_times_for_all_gcs_sec(
- new TruncatedSeq(NumPrevPausesForHeuristics)),
-
- _recent_avg_pause_time_ratio(0.0),
_rs_lengths_prediction(0),
_max_survivor_regions(0),
-
- _eden_cset_region_length(0),
- _survivor_cset_region_length(0),
- _old_cset_region_length(0),
-
- _collection_set(NULL),
- _collection_set_bytes_used_before(0),
-
- // Incremental CSet attributes
- _inc_cset_build_state(Inactive),
- _inc_cset_head(NULL),
- _inc_cset_tail(NULL),
- _inc_cset_bytes_used_before(0),
- _inc_cset_recorded_rs_lengths(0),
- _inc_cset_recorded_rs_lengths_diffs(0),
- _inc_cset_predicted_elapsed_time_ms(0.0),
- _inc_cset_predicted_elapsed_time_ms_diffs(0.0),
-
- // add here any more surv rate groups
- _recorded_survivor_regions(0),
- _recorded_survivor_head(NULL),
- _recorded_survivor_tail(NULL),
_survivors_age_table(true),
- _gc_overhead_perc(0.0),
-
_bytes_allocated_in_old_since_last_gc(0),
_ihop_control(NULL),
_initial_mark_to_mixed() {
@@ -165,27 +75,8 @@
HeapRegion::setup_heap_region_size(InitialHeapSize, MaxHeapSize);
HeapRegionRemSet::setup_remset_size();
- _recent_prev_end_times_for_all_gcs_sec->add(os::elapsedTime());
- _prev_collection_pause_end_ms = os::elapsedTime() * 1000.0;
- clear_ratio_check_data();
-
_phase_times = new G1GCPhaseTimes(ParallelGCThreads);
- int index = MIN2(ParallelGCThreads - 1, 7u);
-
- _rs_length_diff_seq->add(rs_length_diff_defaults[index]);
- _cost_per_card_ms_seq->add(cost_per_card_ms_defaults[index]);
- _cost_scan_hcc_seq->add(0.0);
- _young_cards_per_entry_ratio_seq->add(
- young_cards_per_entry_ratio_defaults[index]);
- _cost_per_entry_ms_seq->add(cost_per_entry_ms_defaults[index]);
- _cost_per_byte_ms_seq->add(cost_per_byte_ms_defaults[index]);
- _constant_other_time_ms_seq->add(constant_other_time_ms_defaults[index]);
- _young_other_cost_per_region_ms_seq->add(
- young_other_cost_per_region_ms_defaults[index]);
- _non_young_other_cost_per_region_ms_seq->add(
- non_young_other_cost_per_region_ms_defaults[index]);
-
// Below, we might need to calculate the pause time target based on
// the pause interval. When we do so we are going to give G1 maximum
// flexibility and allow it to do pauses when it needs to. So, we'll
@@ -198,18 +89,7 @@
// First make sure that, if either parameter is set, its value is
// reasonable.
- if (!FLAG_IS_DEFAULT(MaxGCPauseMillis)) {
- if (MaxGCPauseMillis < 1) {
- vm_exit_during_initialization("MaxGCPauseMillis should be "
- "greater than 0");
- }
- }
- if (!FLAG_IS_DEFAULT(GCPauseIntervalMillis)) {
- if (GCPauseIntervalMillis < 1) {
- vm_exit_during_initialization("GCPauseIntervalMillis should be "
- "greater than 0");
- }
- }
+ guarantee(MaxGCPauseMillis >= 1, "Range checking for MaxGCPauseMillis should guarantee that value is >= 1");
// Then, if the pause time target parameter was not set, set it to
// the default value.
@@ -231,45 +111,22 @@
if (FLAG_IS_DEFAULT(GCPauseIntervalMillis)) {
FLAG_SET_DEFAULT(GCPauseIntervalMillis, MaxGCPauseMillis + 1);
}
-
- // Finally, make sure that the two parameters are consistent.
- if (MaxGCPauseMillis >= GCPauseIntervalMillis) {
- char buffer[256];
- jio_snprintf(buffer, 256,
- "MaxGCPauseMillis (%u) should be less than "
- "GCPauseIntervalMillis (%u)",
- MaxGCPauseMillis, GCPauseIntervalMillis);
- vm_exit_during_initialization(buffer);
- }
+ guarantee(GCPauseIntervalMillis >= 1, "Constraint for GCPauseIntervalMillis should guarantee that value is >= 1");
+ guarantee(GCPauseIntervalMillis > MaxGCPauseMillis, "Constraint for GCPauseIntervalMillis should guarantee that GCPauseIntervalMillis > MaxGCPauseMillis");
double max_gc_time = (double) MaxGCPauseMillis / 1000.0;
double time_slice = (double) GCPauseIntervalMillis / 1000.0;
_mmu_tracker = new G1MMUTrackerQueue(time_slice, max_gc_time);
- // start conservatively (around 50ms is about right)
- _concurrent_mark_remark_times_ms->add(0.05);
- _concurrent_mark_cleanup_times_ms->add(0.20);
_tenuring_threshold = MaxTenuringThreshold;
- assert(GCTimeRatio > 0,
- "we should have set it to a default value set_g1_gc_flags() "
- "if a user set it to 0");
- _gc_overhead_perc = 100.0 * (1.0 / (1.0 + GCTimeRatio));
- uintx reserve_perc = G1ReservePercent;
- // Put an artificial ceiling on this so that it's not set to a silly value.
- if (reserve_perc > 50) {
- reserve_perc = 50;
- warning("G1ReservePercent is set to a value that is too large, "
- "it's been updated to " UINTX_FORMAT, reserve_perc);
- }
- _reserve_factor = (double) reserve_perc / 100.0;
+ guarantee(G1ReservePercent <= 50, "Range checking should not allow values over 50.");
+ _reserve_factor = (double) G1ReservePercent / 100.0;
// This will be set when the heap is expanded
// for the first time during initialization.
_reserve_regions = 0;
- _cset_chooser = new CollectionSetChooser();
-
_ihop_control = create_ihop_control();
}
@@ -277,14 +134,6 @@
delete _ihop_control;
}
-double G1CollectorPolicy::get_new_prediction(TruncatedSeq const* seq) const {
- return _predictor.get_new_prediction(seq);
-}
-
-size_t G1CollectorPolicy::get_new_size_prediction(TruncatedSeq const* seq) const {
- return (size_t)get_new_prediction(seq);
-}
-
void G1CollectorPolicy::initialize_alignments() {
_space_alignment = HeapRegion::GrainBytes;
size_t card_table_alignment = CardTableRS::ct_max_alignment_constraint();
@@ -294,177 +143,6 @@
G1CollectorState* G1CollectorPolicy::collector_state() const { return _g1->collector_state(); }
-// There are three command line options related to the young gen size:
-// NewSize, MaxNewSize and NewRatio (There is also -Xmn, but that is
-// just a short form for NewSize==MaxNewSize). G1 will use its internal
-// heuristics to calculate the actual young gen size, so these options
-// basically only limit the range within which G1 can pick a young gen
-// size. Also, these are general options taking byte sizes. G1 will
-// internally work with a number of regions instead. So, some rounding
-// will occur.
-//
-// If nothing related to the the young gen size is set on the command
-// line we should allow the young gen to be between G1NewSizePercent
-// and G1MaxNewSizePercent of the heap size. This means that every time
-// the heap size changes, the limits for the young gen size will be
-// recalculated.
-//
-// If only -XX:NewSize is set we should use the specified value as the
-// minimum size for young gen. Still using G1MaxNewSizePercent of the
-// heap as maximum.
-//
-// If only -XX:MaxNewSize is set we should use the specified value as the
-// maximum size for young gen. Still using G1NewSizePercent of the heap
-// as minimum.
-//
-// If -XX:NewSize and -XX:MaxNewSize are both specified we use these values.
-// No updates when the heap size changes. There is a special case when
-// NewSize==MaxNewSize. This is interpreted as "fixed" and will use a
-// different heuristic for calculating the collection set when we do mixed
-// collection.
-//
-// If only -XX:NewRatio is set we should use the specified ratio of the heap
-// as both min and max. This will be interpreted as "fixed" just like the
-// NewSize==MaxNewSize case above. But we will update the min and max
-// every time the heap size changes.
-//
-// NewSize and MaxNewSize override NewRatio. So, NewRatio is ignored if it is
-// combined with either NewSize or MaxNewSize. (A warning message is printed.)
-class G1YoungGenSizer : public CHeapObj<mtGC> {
-private:
- enum SizerKind {
- SizerDefaults,
- SizerNewSizeOnly,
- SizerMaxNewSizeOnly,
- SizerMaxAndNewSize,
- SizerNewRatio
- };
- SizerKind _sizer_kind;
- uint _min_desired_young_length;
- uint _max_desired_young_length;
- bool _adaptive_size;
- uint calculate_default_min_length(uint new_number_of_heap_regions);
- uint calculate_default_max_length(uint new_number_of_heap_regions);
-
- // Update the given values for minimum and maximum young gen length in regions
- // given the number of heap regions depending on the kind of sizing algorithm.
- void recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length);
-
-public:
- G1YoungGenSizer();
- // Calculate the maximum length of the young gen given the number of regions
- // depending on the sizing algorithm.
- uint max_young_length(uint number_of_heap_regions);
-
- void heap_size_changed(uint new_number_of_heap_regions);
- uint min_desired_young_length() {
- return _min_desired_young_length;
- }
- uint max_desired_young_length() {
- return _max_desired_young_length;
- }
-
- bool adaptive_young_list_length() const {
- return _adaptive_size;
- }
-};
-
-
-G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true),
- _min_desired_young_length(0), _max_desired_young_length(0) {
- if (FLAG_IS_CMDLINE(NewRatio)) {
- if (FLAG_IS_CMDLINE(NewSize) || FLAG_IS_CMDLINE(MaxNewSize)) {
- warning("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio");
- } else {
- _sizer_kind = SizerNewRatio;
- _adaptive_size = false;
- return;
- }
- }
-
- if (NewSize > MaxNewSize) {
- if (FLAG_IS_CMDLINE(MaxNewSize)) {
- warning("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). "
- "A new max generation size of " SIZE_FORMAT "k will be used.",
- NewSize/K, MaxNewSize/K, NewSize/K);
- }
- MaxNewSize = NewSize;
- }
-
- if (FLAG_IS_CMDLINE(NewSize)) {
- _min_desired_young_length = MAX2((uint) (NewSize / HeapRegion::GrainBytes),
- 1U);
- if (FLAG_IS_CMDLINE(MaxNewSize)) {
- _max_desired_young_length =
- MAX2((uint) (MaxNewSize / HeapRegion::GrainBytes),
- 1U);
- _sizer_kind = SizerMaxAndNewSize;
- _adaptive_size = _min_desired_young_length == _max_desired_young_length;
- } else {
- _sizer_kind = SizerNewSizeOnly;
- }
- } else if (FLAG_IS_CMDLINE(MaxNewSize)) {
- _max_desired_young_length =
- MAX2((uint) (MaxNewSize / HeapRegion::GrainBytes),
- 1U);
- _sizer_kind = SizerMaxNewSizeOnly;
- }
-}
-
-uint G1YoungGenSizer::calculate_default_min_length(uint new_number_of_heap_regions) {
- uint default_value = (new_number_of_heap_regions * G1NewSizePercent) / 100;
- return MAX2(1U, default_value);
-}
-
-uint G1YoungGenSizer::calculate_default_max_length(uint new_number_of_heap_regions) {
- uint default_value = (new_number_of_heap_regions * G1MaxNewSizePercent) / 100;
- return MAX2(1U, default_value);
-}
-
-void G1YoungGenSizer::recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length) {
- assert(number_of_heap_regions > 0, "Heap must be initialized");
-
- switch (_sizer_kind) {
- case SizerDefaults:
- *min_young_length = calculate_default_min_length(number_of_heap_regions);
- *max_young_length = calculate_default_max_length(number_of_heap_regions);
- break;
- case SizerNewSizeOnly:
- *max_young_length = calculate_default_max_length(number_of_heap_regions);
- *max_young_length = MAX2(*min_young_length, *max_young_length);
- break;
- case SizerMaxNewSizeOnly:
- *min_young_length = calculate_default_min_length(number_of_heap_regions);
- *min_young_length = MIN2(*min_young_length, *max_young_length);
- break;
- case SizerMaxAndNewSize:
- // Do nothing. Values set on the command line, don't update them at runtime.
- break;
- case SizerNewRatio:
- *min_young_length = number_of_heap_regions / (NewRatio + 1);
- *max_young_length = *min_young_length;
- break;
- default:
- ShouldNotReachHere();
- }
-
- assert(*min_young_length <= *max_young_length, "Invalid min/max young gen size values");
-}
-
-uint G1YoungGenSizer::max_young_length(uint number_of_heap_regions) {
- // We need to pass the desired values because recalculation may not update these
- // values in some cases.
- uint temp = _min_desired_young_length;
- uint result = _max_desired_young_length;
- recalculate_min_max_young_length(number_of_heap_regions, &temp, &result);
- return result;
-}
-
-void G1YoungGenSizer::heap_size_changed(uint new_number_of_heap_regions) {
- recalculate_min_max_young_length(new_number_of_heap_regions, &_min_desired_young_length,
- &_max_desired_young_length);
-}
-
void G1CollectorPolicy::post_heap_initialize() {
uintx max_regions = G1CollectedHeap::heap()->max_regions();
size_t max_young_size = (size_t)_young_gen_sizer->max_young_length(max_regions) * HeapRegion::GrainBytes;
@@ -478,9 +156,8 @@
FLAG_SET_ERGO(size_t, G1HeapRegionSize, HeapRegion::GrainBytes);
}
- if (SurvivorRatio < 1) {
- vm_exit_during_initialization("Invalid survivor ratio specified");
- }
+ guarantee(SurvivorRatio >= 1, "Range checking for SurvivorRatio should guarantee that value is >= 1");
+
CollectorPolicy::initialize_flags();
_young_gen_sizer = new G1YoungGenSizer(); // Must be after call to initialize_flags
}
@@ -489,6 +166,8 @@
void G1CollectorPolicy::init() {
// Set aside an initial future to_space.
_g1 = G1CollectedHeap::heap();
+ _collection_set = _g1->collection_set();
+ _collection_set->set_policy(this);
assert(Heap_lock->owned_by_self(), "Locking discipline.");
@@ -504,7 +183,7 @@
update_young_list_max_and_target_length();
// We may immediately start allocating regions and placing them on the
// collection set list. Initialize the per-collection set info
- start_incremental_cset_building();
+ _collection_set->start_incremental_building();
}
void G1CollectorPolicy::note_gc_start(uint num_active_workers) {
@@ -528,8 +207,9 @@
double accum_surv_rate = accum_yg_surv_rate_pred((int) young_length - 1);
size_t bytes_to_copy =
(size_t) (accum_surv_rate * (double) HeapRegion::GrainBytes);
- double copy_time_ms = predict_object_copy_time_ms(bytes_to_copy);
- double young_other_time_ms = predict_young_other_time_ms(young_length);
+ double copy_time_ms = _analytics->predict_object_copy_time_ms(bytes_to_copy,
+ collector_state()->during_concurrent_mark());
+ double young_other_time_ms = _analytics->predict_young_other_time_ms(young_length);
double pause_time_ms = base_time_ms + copy_time_ms + young_other_time_ms;
if (pause_time_ms > target_pause_time_ms) {
// end condition 2: prediction is over the target pause time
@@ -573,10 +253,10 @@
uint base_min_length) const {
uint desired_min_length = 0;
if (adaptive_young_list_length()) {
- if (_alloc_rate_ms_seq->num() > 3) {
+ if (_analytics->num_alloc_rate_ms() > 3) {
double now_sec = os::elapsedTime();
double when_ms = _mmu_tracker->when_max_gc_sec(now_sec) * 1000.0;
- double alloc_rate_ms = predict_alloc_rate_ms();
+ double alloc_rate_ms = _analytics->predict_alloc_rate_ms();
desired_min_length = (uint) ceil(alloc_rate_ms * when_ms);
} else {
// otherwise we don't have enough info to make the prediction
@@ -595,7 +275,7 @@
}
uint G1CollectorPolicy::update_young_list_max_and_target_length() {
- return update_young_list_max_and_target_length(get_new_size_prediction(_rs_lengths_seq));
+ return update_young_list_max_and_target_length(_analytics->predict_rs_lengths());
}
uint G1CollectorPolicy::update_young_list_max_and_target_length(size_t rs_lengths) {
@@ -616,7 +296,7 @@
// Calculate the absolute and desired min bounds first.
// This is how many young regions we already have (currently: the survivors).
- uint base_min_length = recorded_survivor_regions();
+ const uint base_min_length = _g1->young_list()->survivor_length();
uint desired_min_length = calculate_young_list_desired_min_length(base_min_length);
// This is the absolute minimum young length. Ensure that we
// will at least have one eden region available for allocation.
@@ -667,7 +347,7 @@
young_list_target_length = desired_min_length;
}
- assert(young_list_target_length > recorded_survivor_regions(),
+ assert(young_list_target_length > base_min_length,
"we should be able to allocate at least one eden region");
assert(young_list_target_length >= absolute_min_length, "post-condition");
@@ -700,9 +380,9 @@
double target_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0;
double survivor_regions_evac_time = predict_survivor_regions_evac_time();
- size_t pending_cards = get_new_size_prediction(_pending_cards_seq);
- size_t adj_rs_lengths = rs_lengths + predict_rs_length_diff();
- size_t scanned_cards = predict_young_card_num(adj_rs_lengths);
+ size_t pending_cards = _analytics->predict_pending_cards();
+ size_t adj_rs_lengths = rs_lengths + _analytics->predict_rs_length_diff();
+ size_t scanned_cards = _analytics->predict_card_num(adj_rs_lengths, /* gcs_are_young */ true);
double base_time_ms =
predict_base_elapsed_time_ms(pending_cards, scanned_cards) +
survivor_regions_evac_time;
@@ -781,8 +461,8 @@
double G1CollectorPolicy::predict_survivor_regions_evac_time() const {
double survivor_regions_evac_time = 0.0;
- for (HeapRegion * r = _recorded_survivor_head;
- r != NULL && r != _recorded_survivor_tail->get_next_young_region();
+ for (HeapRegion * r = _g1->young_list()->first_survivor_region();
+ r != NULL && r != _g1->young_list()->last_survivor_region()->get_next_young_region();
r = r->get_next_young_region()) {
survivor_regions_evac_time += predict_region_elapsed_time_ms(r, collector_state()->gcs_are_young());
}
@@ -802,7 +482,7 @@
}
void G1CollectorPolicy::update_rs_lengths_prediction() {
- update_rs_lengths_prediction(get_new_size_prediction(_rs_lengths_seq));
+ update_rs_lengths_prediction(_analytics->predict_rs_lengths());
}
void G1CollectorPolicy::update_rs_lengths_prediction(size_t prediction) {
@@ -870,7 +550,7 @@
double full_gc_time_sec = end_sec - _full_collection_start_sec;
double full_gc_time_ms = full_gc_time_sec * 1000.0;
- update_recent_gc_times(end_sec, full_gc_time_ms);
+ _analytics->update_recent_gc_times(end_sec, full_gc_time_ms);
collector_state()->set_full_collection(false);
@@ -886,8 +566,6 @@
_short_lived_surv_rate_group->start_adding_regions();
// also call this on any additional surv rate groups
- record_survivor_regions(0, NULL, NULL);
-
_free_regions_at_end_of_collection = _g1->num_free_regions();
// Reset survivors SurvRateGroup.
_survivor_surv_rate_group->reset();
@@ -913,7 +591,7 @@
phase_times()->record_cur_collection_start_sec(start_time_sec);
_pending_cards = _g1->pending_card_num();
- _collection_set_bytes_used_before = 0;
+ _collection_set->reset_bytes_used_before();
_bytes_copied_during_gc = 0;
collector_state()->set_last_gc_was_young(false);
@@ -940,8 +618,8 @@
void G1CollectorPolicy::record_concurrent_mark_remark_end() {
double end_time_sec = os::elapsedTime();
double elapsed_time_ms = (end_time_sec - _mark_remark_start_sec)*1000.0;
- _concurrent_mark_remark_times_ms->add(elapsed_time_ms);
- _prev_collection_pause_end_ms += elapsed_time_ms;
+ _analytics->report_concurrent_mark_remark_times_ms(elapsed_time_ms);
+ _analytics->append_prev_collection_pause_end_ms(elapsed_time_ms);
record_pause(Remark, _mark_remark_start_sec, end_time_sec);
}
@@ -988,6 +666,10 @@
return other_time_ms(pause_time_ms) - young_other_time_ms() - non_young_other_time_ms();
}
+CollectionSetChooser* G1CollectorPolicy::cset_chooser() const {
+ return _collection_set->cset_chooser();
+}
+
bool G1CollectorPolicy::about_to_start_mixed_phase() const {
return _g1->concurrent_mark()->cmThread()->during_cycle() || collector_state()->last_young_gc();
}
@@ -1036,7 +718,7 @@
maybe_start_marking();
}
- double app_time_ms = (phase_times()->cur_collection_start_sec() * 1000.0 - _prev_collection_pause_end_ms);
+ double app_time_ms = (phase_times()->cur_collection_start_sec() * 1000.0 - _analytics->prev_collection_pause_end_ms());
if (app_time_ms < MIN_TIMER_GRANULARITY) {
// This usually happens due to the timer not having the required
// granularity. Some Linuxes are the usual culprits.
@@ -1053,33 +735,14 @@
// given that humongous object allocations do not really affect
// either the pause's duration nor when the next pause will take
// place we can safely ignore them here.
- uint regions_allocated = eden_cset_region_length();
+ uint regions_allocated = _collection_set->eden_region_length();
double alloc_rate_ms = (double) regions_allocated / app_time_ms;
- _alloc_rate_ms_seq->add(alloc_rate_ms);
+ _analytics->report_alloc_rate_ms(alloc_rate_ms);
double interval_ms =
- (end_time_sec - _recent_prev_end_times_for_all_gcs_sec->oldest()) * 1000.0;
- update_recent_gc_times(end_time_sec, pause_time_ms);
- _recent_avg_pause_time_ratio = _recent_gc_times_ms->sum()/interval_ms;
- if (recent_avg_pause_time_ratio() < 0.0 ||
- (recent_avg_pause_time_ratio() - 1.0 > 0.0)) {
- // Clip ratio between 0.0 and 1.0, and continue. This will be fixed in
- // CR 6902692 by redoing the manner in which the ratio is incrementally computed.
- if (_recent_avg_pause_time_ratio < 0.0) {
- _recent_avg_pause_time_ratio = 0.0;
- } else {
- assert(_recent_avg_pause_time_ratio - 1.0 > 0.0, "Ctl-point invariant");
- _recent_avg_pause_time_ratio = 1.0;
- }
- }
-
- // Compute the ratio of just this last pause time to the entire time range stored
- // in the vectors. Comparing this pause to the entire range, rather than only the
- // most recent interval, has the effect of smoothing over a possible transient 'burst'
- // of more frequent pauses that don't really reflect a change in heap occupancy.
- // This reduces the likelihood of a needless heap expansion being triggered.
- _last_pause_time_ratio =
- (pause_time_ms * _recent_prev_end_times_for_all_gcs_sec->num()) / interval_ms;
+ (end_time_sec - _analytics->last_known_gc_end_time_sec()) * 1000.0;
+ _analytics->update_recent_gc_times(end_time_sec, pause_time_ms);
+ _analytics->compute_pause_time_ratio(interval_ms, pause_time_ms);
}
bool new_in_marking_window = collector_state()->in_marking_window();
@@ -1125,28 +788,20 @@
double cost_per_card_ms = 0.0;
if (_pending_cards > 0) {
cost_per_card_ms = (average_time_ms(G1GCPhaseTimes::UpdateRS) - scan_hcc_time_ms) / (double) _pending_cards;
- _cost_per_card_ms_seq->add(cost_per_card_ms);
+ _analytics->report_cost_per_card_ms(cost_per_card_ms);
}
- _cost_scan_hcc_seq->add(scan_hcc_time_ms);
+ _analytics->report_cost_scan_hcc(scan_hcc_time_ms);
double cost_per_entry_ms = 0.0;
if (cards_scanned > 10) {
cost_per_entry_ms = average_time_ms(G1GCPhaseTimes::ScanRS) / (double) cards_scanned;
- if (collector_state()->last_gc_was_young()) {
- _cost_per_entry_ms_seq->add(cost_per_entry_ms);
- } else {
- _mixed_cost_per_entry_ms_seq->add(cost_per_entry_ms);
- }
+ _analytics->report_cost_per_entry_ms(cost_per_entry_ms, collector_state()->last_gc_was_young());
}
if (_max_rs_lengths > 0) {
double cards_per_entry_ratio =
(double) cards_scanned / (double) _max_rs_lengths;
- if (collector_state()->last_gc_was_young()) {
- _young_cards_per_entry_ratio_seq->add(cards_per_entry_ratio);
- } else {
- _mixed_cards_per_entry_ratio_seq->add(cards_per_entry_ratio);
- }
+ _analytics->report_cards_per_entry_ratio(cards_per_entry_ratio, collector_state()->last_gc_was_young());
}
// This is defensive. For a while _max_rs_lengths could get
@@ -1163,38 +818,35 @@
// say, it's in mid-coarsening). So I'll leave in the defensive
// conditional below just in case.
size_t rs_length_diff = 0;
- if (_max_rs_lengths > _recorded_rs_lengths) {
- rs_length_diff = _max_rs_lengths - _recorded_rs_lengths;
+ size_t recorded_rs_lengths = _collection_set->recorded_rs_lengths();
+ if (_max_rs_lengths > recorded_rs_lengths) {
+ rs_length_diff = _max_rs_lengths - recorded_rs_lengths;
}
- _rs_length_diff_seq->add((double) rs_length_diff);
+ _analytics->report_rs_length_diff((double) rs_length_diff);
size_t freed_bytes = heap_used_bytes_before_gc - cur_used_bytes;
- size_t copied_bytes = _collection_set_bytes_used_before - freed_bytes;
+ size_t copied_bytes = _collection_set->bytes_used_before() - freed_bytes;
double cost_per_byte_ms = 0.0;
if (copied_bytes > 0) {
cost_per_byte_ms = average_time_ms(G1GCPhaseTimes::ObjCopy) / (double) copied_bytes;
- if (collector_state()->in_marking_window()) {
- _cost_per_byte_ms_during_cm_seq->add(cost_per_byte_ms);
- } else {
- _cost_per_byte_ms_seq->add(cost_per_byte_ms);
- }
+ _analytics->report_cost_per_byte_ms(cost_per_byte_ms, collector_state()->in_marking_window());
+ }
+
+ if (_collection_set->young_region_length() > 0) {
+ _analytics->report_young_other_cost_per_region_ms(young_other_time_ms() /
+ _collection_set->young_region_length());
}
- if (young_cset_region_length() > 0) {
- _young_other_cost_per_region_ms_seq->add(young_other_time_ms() /
- young_cset_region_length());
+ if (_collection_set->old_region_length() > 0) {
+ _analytics->report_non_young_other_cost_per_region_ms(non_young_other_time_ms() /
+ _collection_set->old_region_length());
}
- if (old_cset_region_length() > 0) {
- _non_young_other_cost_per_region_ms_seq->add(non_young_other_time_ms() /
- old_cset_region_length());
- }
+ _analytics->report_constant_other_time_ms(constant_other_time_ms(pause_time_ms));
- _constant_other_time_ms_seq->add(constant_other_time_ms(pause_time_ms));
-
- _pending_cards_seq->add((double) _pending_cards);
- _rs_lengths_seq->add((double) _max_rs_lengths);
+ _analytics->report_pending_cards((double) _pending_cards);
+ _analytics->report_rs_lengths((double) _max_rs_lengths);
}
collector_state()->set_in_marking_window(new_in_marking_window);
@@ -1331,102 +983,10 @@
dcqs.notify_if_necessary();
}
-size_t G1CollectorPolicy::predict_rs_length_diff() const {
- return get_new_size_prediction(_rs_length_diff_seq);
-}
-
-double G1CollectorPolicy::predict_alloc_rate_ms() const {
- return get_new_prediction(_alloc_rate_ms_seq);
-}
-
-double G1CollectorPolicy::predict_cost_per_card_ms() const {
- return get_new_prediction(_cost_per_card_ms_seq);
-}
-
-double G1CollectorPolicy::predict_scan_hcc_ms() const {
- return get_new_prediction(_cost_scan_hcc_seq);
-}
-
-double G1CollectorPolicy::predict_rs_update_time_ms(size_t pending_cards) const {
- return pending_cards * predict_cost_per_card_ms() + predict_scan_hcc_ms();
-}
-
-double G1CollectorPolicy::predict_young_cards_per_entry_ratio() const {
- return get_new_prediction(_young_cards_per_entry_ratio_seq);
-}
-
-double G1CollectorPolicy::predict_mixed_cards_per_entry_ratio() const {
- if (_mixed_cards_per_entry_ratio_seq->num() < 2) {
- return predict_young_cards_per_entry_ratio();
- } else {
- return get_new_prediction(_mixed_cards_per_entry_ratio_seq);
- }
-}
-
-size_t G1CollectorPolicy::predict_young_card_num(size_t rs_length) const {
- return (size_t) (rs_length * predict_young_cards_per_entry_ratio());
-}
-
-size_t G1CollectorPolicy::predict_non_young_card_num(size_t rs_length) const {
- return (size_t)(rs_length * predict_mixed_cards_per_entry_ratio());
-}
-
-double G1CollectorPolicy::predict_rs_scan_time_ms(size_t card_num) const {
- if (collector_state()->gcs_are_young()) {
- return card_num * get_new_prediction(_cost_per_entry_ms_seq);
- } else {
- return predict_mixed_rs_scan_time_ms(card_num);
- }
-}
-
-double G1CollectorPolicy::predict_mixed_rs_scan_time_ms(size_t card_num) const {
- if (_mixed_cost_per_entry_ms_seq->num() < 3) {
- return card_num * get_new_prediction(_cost_per_entry_ms_seq);
- } else {
- return card_num * get_new_prediction(_mixed_cost_per_entry_ms_seq);
- }
-}
-
-double G1CollectorPolicy::predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const {
- if (_cost_per_byte_ms_during_cm_seq->num() < 3) {
- return (1.1 * bytes_to_copy) * get_new_prediction(_cost_per_byte_ms_seq);
- } else {
- return bytes_to_copy * get_new_prediction(_cost_per_byte_ms_during_cm_seq);
- }
-}
-
-double G1CollectorPolicy::predict_object_copy_time_ms(size_t bytes_to_copy) const {
- if (collector_state()->during_concurrent_mark()) {
- return predict_object_copy_time_ms_during_cm(bytes_to_copy);
- } else {
- return bytes_to_copy * get_new_prediction(_cost_per_byte_ms_seq);
- }
-}
-
-double G1CollectorPolicy::predict_constant_other_time_ms() const {
- return get_new_prediction(_constant_other_time_ms_seq);
-}
-
-double G1CollectorPolicy::predict_young_other_time_ms(size_t young_num) const {
- return young_num * get_new_prediction(_young_other_cost_per_region_ms_seq);
-}
-
-double G1CollectorPolicy::predict_non_young_other_time_ms(size_t non_young_num) const {
- return non_young_num * get_new_prediction(_non_young_other_cost_per_region_ms_seq);
-}
-
-double G1CollectorPolicy::predict_remark_time_ms() const {
- return get_new_prediction(_concurrent_mark_remark_times_ms);
-}
-
-double G1CollectorPolicy::predict_cleanup_time_ms() const {
- return get_new_prediction(_concurrent_mark_cleanup_times_ms);
-}
-
double G1CollectorPolicy::predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) const {
TruncatedSeq* seq = surv_rate_group->get_seq(age);
guarantee(seq->num() > 0, "There should be some young gen survivor samples available. Tried to access with age %d", age);
- double pred = get_new_prediction(seq);
+ double pred = _predictor.get_new_prediction(seq);
if (pred > 1.0) {
pred = 1.0;
}
@@ -1444,19 +1004,14 @@
double G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards,
size_t scanned_cards) const {
return
- predict_rs_update_time_ms(pending_cards) +
- predict_rs_scan_time_ms(scanned_cards) +
- predict_constant_other_time_ms();
+ _analytics->predict_rs_update_time_ms(pending_cards) +
+ _analytics->predict_rs_scan_time_ms(scanned_cards, collector_state()->gcs_are_young()) +
+ _analytics->predict_constant_other_time_ms();
}
double G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards) const {
- size_t rs_length = predict_rs_length_diff();
- size_t card_num;
- if (collector_state()->gcs_are_young()) {
- card_num = predict_young_card_num(rs_length);
- } else {
- card_num = predict_non_young_card_num(rs_length);
- }
+ size_t rs_length = _analytics->predict_rs_lengths() + _analytics->predict_rs_length_diff();
+ size_t card_num = _analytics->predict_card_num(rs_length, collector_state()->gcs_are_young());
return predict_base_elapsed_time_ms(pending_cards, card_num);
}
@@ -1476,160 +1031,25 @@
double G1CollectorPolicy::predict_region_elapsed_time_ms(HeapRegion* hr,
bool for_young_gc) const {
size_t rs_length = hr->rem_set()->occupied();
- size_t card_num;
-
// Predicting the number of cards is based on which type of GC
// we're predicting for.
- if (for_young_gc) {
- card_num = predict_young_card_num(rs_length);
- } else {
- card_num = predict_non_young_card_num(rs_length);
- }
+ size_t card_num = _analytics->predict_card_num(rs_length, for_young_gc);
size_t bytes_to_copy = predict_bytes_to_copy(hr);
double region_elapsed_time_ms =
- predict_rs_scan_time_ms(card_num) +
- predict_object_copy_time_ms(bytes_to_copy);
+ _analytics->predict_rs_scan_time_ms(card_num, collector_state()->gcs_are_young()) +
+ _analytics->predict_object_copy_time_ms(bytes_to_copy, collector_state()->during_concurrent_mark());
// The prediction of the "other" time for this region is based
// upon the region type and NOT the GC type.
if (hr->is_young()) {
- region_elapsed_time_ms += predict_young_other_time_ms(1);
+ region_elapsed_time_ms += _analytics->predict_young_other_time_ms(1);
} else {
- region_elapsed_time_ms += predict_non_young_other_time_ms(1);
+ region_elapsed_time_ms += _analytics->predict_non_young_other_time_ms(1);
}
return region_elapsed_time_ms;
}
-void G1CollectorPolicy::init_cset_region_lengths(uint eden_cset_region_length,
- uint survivor_cset_region_length) {
- _eden_cset_region_length = eden_cset_region_length;
- _survivor_cset_region_length = survivor_cset_region_length;
- _old_cset_region_length = 0;
-}
-
-void G1CollectorPolicy::set_recorded_rs_lengths(size_t rs_lengths) {
- _recorded_rs_lengths = rs_lengths;
-}
-
-void G1CollectorPolicy::update_recent_gc_times(double end_time_sec,
- double elapsed_ms) {
- _recent_gc_times_ms->add(elapsed_ms);
- _recent_prev_end_times_for_all_gcs_sec->add(end_time_sec);
- _prev_collection_pause_end_ms = end_time_sec * 1000.0;
-}
-
-void G1CollectorPolicy::clear_ratio_check_data() {
- _ratio_over_threshold_count = 0;
- _ratio_over_threshold_sum = 0.0;
- _pauses_since_start = 0;
-}
-
-size_t G1CollectorPolicy::expansion_amount() {
- double recent_gc_overhead = recent_avg_pause_time_ratio() * 100.0;
- double last_gc_overhead = _last_pause_time_ratio * 100.0;
- double threshold = _gc_overhead_perc;
- size_t expand_bytes = 0;
-
- // If the heap is at less than half its maximum size, scale the threshold down,
- // to a limit of 1. Thus the smaller the heap is, the more likely it is to expand,
- // though the scaling code will likely keep the increase small.
- if (_g1->capacity() <= _g1->max_capacity() / 2) {
- threshold *= (double)_g1->capacity() / (double)(_g1->max_capacity() / 2);
- threshold = MAX2(threshold, 1.0);
- }
-
- // If the last GC time ratio is over the threshold, increment the count of
- // times it has been exceeded, and add this ratio to the sum of exceeded
- // ratios.
- if (last_gc_overhead > threshold) {
- _ratio_over_threshold_count++;
- _ratio_over_threshold_sum += last_gc_overhead;
- }
-
- // Check if we've had enough GC time ratio checks that were over the
- // threshold to trigger an expansion. We'll also expand if we've
- // reached the end of the history buffer and the average of all entries
- // is still over the threshold. This indicates a smaller number of GCs were
- // long enough to make the average exceed the threshold.
- bool filled_history_buffer = _pauses_since_start == NumPrevPausesForHeuristics;
- if ((_ratio_over_threshold_count == MinOverThresholdForGrowth) ||
- (filled_history_buffer && (recent_gc_overhead > threshold))) {
- size_t min_expand_bytes = HeapRegion::GrainBytes;
- size_t reserved_bytes = _g1->max_capacity();
- size_t committed_bytes = _g1->capacity();
- size_t uncommitted_bytes = reserved_bytes - committed_bytes;
- size_t expand_bytes_via_pct =
- uncommitted_bytes * G1ExpandByPercentOfAvailable / 100;
- double scale_factor = 1.0;
-
- // If the current size is less than 1/4 of the Initial heap size, expand
- // by half of the delta between the current and Initial sizes. IE, grow
- // back quickly.
- //
- // Otherwise, take the current size, or G1ExpandByPercentOfAvailable % of
- // the available expansion space, whichever is smaller, as the base
- // expansion size. Then possibly scale this size according to how much the
- // threshold has (on average) been exceeded by. If the delta is small
- // (less than the StartScaleDownAt value), scale the size down linearly, but
- // not by less than MinScaleDownFactor. If the delta is large (greater than
- // the StartScaleUpAt value), scale up, but adding no more than MaxScaleUpFactor
- // times the base size. The scaling will be linear in the range from
- // StartScaleUpAt to (StartScaleUpAt + ScaleUpRange). In other words,
- // ScaleUpRange sets the rate of scaling up.
- if (committed_bytes < InitialHeapSize / 4) {
- expand_bytes = (InitialHeapSize - committed_bytes) / 2;
- } else {
- double const MinScaleDownFactor = 0.2;
- double const MaxScaleUpFactor = 2;
- double const StartScaleDownAt = _gc_overhead_perc;
- double const StartScaleUpAt = _gc_overhead_perc * 1.5;
- double const ScaleUpRange = _gc_overhead_perc * 2.0;
-
- double ratio_delta;
- if (filled_history_buffer) {
- ratio_delta = recent_gc_overhead - threshold;
- } else {
- ratio_delta = (_ratio_over_threshold_sum/_ratio_over_threshold_count) - threshold;
- }
-
- expand_bytes = MIN2(expand_bytes_via_pct, committed_bytes);
- if (ratio_delta < StartScaleDownAt) {
- scale_factor = ratio_delta / StartScaleDownAt;
- scale_factor = MAX2(scale_factor, MinScaleDownFactor);
- } else if (ratio_delta > StartScaleUpAt) {
- scale_factor = 1 + ((ratio_delta - StartScaleUpAt) / ScaleUpRange);
- scale_factor = MIN2(scale_factor, MaxScaleUpFactor);
- }
- }
-
- log_debug(gc, ergo, heap)("Attempt heap expansion (recent GC overhead higher than threshold after GC) "
- "recent GC overhead: %1.2f %% threshold: %1.2f %% uncommitted: " SIZE_FORMAT "B base expansion amount and scale: " SIZE_FORMAT "B (%1.2f%%)",
- recent_gc_overhead, threshold, uncommitted_bytes, expand_bytes, scale_factor * 100);
-
- expand_bytes = static_cast<size_t>(expand_bytes * scale_factor);
-
- // Ensure the expansion size is at least the minimum growth amount
- // and at most the remaining uncommitted byte size.
- expand_bytes = MAX2(expand_bytes, min_expand_bytes);
- expand_bytes = MIN2(expand_bytes, uncommitted_bytes);
-
- clear_ratio_check_data();
- } else {
- // An expansion was not triggered. If we've started counting, increment
- // the number of checks we've made in the current window. If we've
- // reached the end of the window without resizing, clear the counters to
- // start again the next time we see a ratio above the threshold.
- if (_ratio_over_threshold_count > 0) {
- _pauses_since_start++;
- if (_pauses_since_start > NumPrevPausesForHeuristics) {
- clear_ratio_check_data();
- }
- }
- }
-
- return expand_bytes;
-}
void G1CollectorPolicy::print_yg_surv_rate_info() const {
#ifndef PRODUCT
@@ -1747,269 +1167,17 @@
}
}
-class ParKnownGarbageHRClosure: public HeapRegionClosure {
- G1CollectedHeap* _g1h;
- CSetChooserParUpdater _cset_updater;
-
-public:
- ParKnownGarbageHRClosure(CollectionSetChooser* hrSorted,
- uint chunk_size) :
- _g1h(G1CollectedHeap::heap()),
- _cset_updater(hrSorted, true /* parallel */, chunk_size) { }
-
- bool doHeapRegion(HeapRegion* r) {
- // Do we have any marking information for this region?
- if (r->is_marked()) {
- // We will skip any region that's currently used as an old GC
- // alloc region (we should not consider those for collection
- // before we fill them up).
- if (_cset_updater.should_add(r) && !_g1h->is_old_gc_alloc_region(r)) {
- _cset_updater.add_region(r);
- }
- }
- return false;
- }
-};
-
-class ParKnownGarbageTask: public AbstractGangTask {
- CollectionSetChooser* _hrSorted;
- uint _chunk_size;
- G1CollectedHeap* _g1;
- HeapRegionClaimer _hrclaimer;
-
-public:
- ParKnownGarbageTask(CollectionSetChooser* hrSorted, uint chunk_size, uint n_workers) :
- AbstractGangTask("ParKnownGarbageTask"),
- _hrSorted(hrSorted), _chunk_size(chunk_size),
- _g1(G1CollectedHeap::heap()), _hrclaimer(n_workers) {}
-
- void work(uint worker_id) {
- ParKnownGarbageHRClosure parKnownGarbageCl(_hrSorted, _chunk_size);
- _g1->heap_region_par_iterate(&parKnownGarbageCl, worker_id, &_hrclaimer);
- }
-};
-
-uint G1CollectorPolicy::calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) const {
- assert(n_workers > 0, "Active gc workers should be greater than 0");
- const uint overpartition_factor = 4;
- const uint min_chunk_size = MAX2(n_regions / n_workers, 1U);
- return MAX2(n_regions / (n_workers * overpartition_factor), min_chunk_size);
-}
-
void G1CollectorPolicy::record_concurrent_mark_cleanup_end() {
- cset_chooser()->clear();
-
- WorkGang* workers = _g1->workers();
- uint n_workers = workers->active_workers();
-
- uint n_regions = _g1->num_regions();
- uint chunk_size = calculate_parallel_work_chunk_size(n_workers, n_regions);
- cset_chooser()->prepare_for_par_region_addition(n_workers, n_regions, chunk_size);
- ParKnownGarbageTask par_known_garbage_task(cset_chooser(), chunk_size, n_workers);
- workers->run_task(&par_known_garbage_task);
-
- cset_chooser()->sort_regions();
+ cset_chooser()->rebuild(_g1->workers(), _g1->num_regions());
double end_sec = os::elapsedTime();
double elapsed_time_ms = (end_sec - _mark_cleanup_start_sec) * 1000.0;
- _concurrent_mark_cleanup_times_ms->add(elapsed_time_ms);
- _prev_collection_pause_end_ms += elapsed_time_ms;
+ _analytics->report_concurrent_mark_cleanup_times_ms(elapsed_time_ms);
+ _analytics->append_prev_collection_pause_end_ms(elapsed_time_ms);
record_pause(Cleanup, _mark_cleanup_start_sec, end_sec);
}
-// Add the heap region at the head of the non-incremental collection set
-void G1CollectorPolicy::add_old_region_to_cset(HeapRegion* hr) {
- assert(_inc_cset_build_state == Active, "Precondition");
- assert(hr->is_old(), "the region should be old");
-
- assert(!hr->in_collection_set(), "should not already be in the CSet");
- _g1->register_old_region_with_cset(hr);
- hr->set_next_in_collection_set(_collection_set);
- _collection_set = hr;
- _collection_set_bytes_used_before += hr->used();
- size_t rs_length = hr->rem_set()->occupied();
- _recorded_rs_lengths += rs_length;
- _old_cset_region_length += 1;
-}
-
-// Initialize the per-collection-set information
-void G1CollectorPolicy::start_incremental_cset_building() {
- assert(_inc_cset_build_state == Inactive, "Precondition");
-
- _inc_cset_head = NULL;
- _inc_cset_tail = NULL;
- _inc_cset_bytes_used_before = 0;
-
- _inc_cset_recorded_rs_lengths = 0;
- _inc_cset_recorded_rs_lengths_diffs = 0;
- _inc_cset_predicted_elapsed_time_ms = 0.0;
- _inc_cset_predicted_elapsed_time_ms_diffs = 0.0;
- _inc_cset_build_state = Active;
-}
-
-void G1CollectorPolicy::finalize_incremental_cset_building() {
- assert(_inc_cset_build_state == Active, "Precondition");
- assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint");
-
- // The two "main" fields, _inc_cset_recorded_rs_lengths and
- // _inc_cset_predicted_elapsed_time_ms, are updated by the thread
- // that adds a new region to the CSet. Further updates by the
- // concurrent refinement thread that samples the young RSet lengths
- // are accumulated in the *_diffs fields. Here we add the diffs to
- // the "main" fields.
-
- if (_inc_cset_recorded_rs_lengths_diffs >= 0) {
- _inc_cset_recorded_rs_lengths += _inc_cset_recorded_rs_lengths_diffs;
- } else {
- // This is defensive. The diff should in theory be always positive
- // as RSets can only grow between GCs. However, given that we
- // sample their size concurrently with other threads updating them
- // it's possible that we might get the wrong size back, which
- // could make the calculations somewhat inaccurate.
- size_t diffs = (size_t) (-_inc_cset_recorded_rs_lengths_diffs);
- if (_inc_cset_recorded_rs_lengths >= diffs) {
- _inc_cset_recorded_rs_lengths -= diffs;
- } else {
- _inc_cset_recorded_rs_lengths = 0;
- }
- }
- _inc_cset_predicted_elapsed_time_ms +=
- _inc_cset_predicted_elapsed_time_ms_diffs;
-
- _inc_cset_recorded_rs_lengths_diffs = 0;
- _inc_cset_predicted_elapsed_time_ms_diffs = 0.0;
-}
-
-void G1CollectorPolicy::add_to_incremental_cset_info(HeapRegion* hr, size_t rs_length) {
- // This routine is used when:
- // * adding survivor regions to the incremental cset at the end of an
- // evacuation pause,
- // * adding the current allocation region to the incremental cset
- // when it is retired, and
- // * updating existing policy information for a region in the
- // incremental cset via young list RSet sampling.
- // Therefore this routine may be called at a safepoint by the
- // VM thread, or in-between safepoints by mutator threads (when
- // retiring the current allocation region) or a concurrent
- // refine thread (RSet sampling).
-
- double region_elapsed_time_ms = predict_region_elapsed_time_ms(hr, collector_state()->gcs_are_young());
- size_t used_bytes = hr->used();
- _inc_cset_recorded_rs_lengths += rs_length;
- _inc_cset_predicted_elapsed_time_ms += region_elapsed_time_ms;
- _inc_cset_bytes_used_before += used_bytes;
-
- // Cache the values we have added to the aggregated information
- // in the heap region in case we have to remove this region from
- // the incremental collection set, or it is updated by the
- // rset sampling code
- hr->set_recorded_rs_length(rs_length);
- hr->set_predicted_elapsed_time_ms(region_elapsed_time_ms);
-}
-
-void G1CollectorPolicy::update_incremental_cset_info(HeapRegion* hr,
- size_t new_rs_length) {
- // Update the CSet information that is dependent on the new RS length
- assert(hr->is_young(), "Precondition");
- assert(!SafepointSynchronize::is_at_safepoint(),
- "should not be at a safepoint");
-
- // We could have updated _inc_cset_recorded_rs_lengths and
- // _inc_cset_predicted_elapsed_time_ms directly but we'd need to do
- // that atomically, as this code is executed by a concurrent
- // refinement thread, potentially concurrently with a mutator thread
- // allocating a new region and also updating the same fields. To
- // avoid the atomic operations we accumulate these updates on two
- // separate fields (*_diffs) and we'll just add them to the "main"
- // fields at the start of a GC.
-
- ssize_t old_rs_length = (ssize_t) hr->recorded_rs_length();
- ssize_t rs_lengths_diff = (ssize_t) new_rs_length - old_rs_length;
- _inc_cset_recorded_rs_lengths_diffs += rs_lengths_diff;
-
- double old_elapsed_time_ms = hr->predicted_elapsed_time_ms();
- double new_region_elapsed_time_ms = predict_region_elapsed_time_ms(hr, collector_state()->gcs_are_young());
- double elapsed_ms_diff = new_region_elapsed_time_ms - old_elapsed_time_ms;
- _inc_cset_predicted_elapsed_time_ms_diffs += elapsed_ms_diff;
-
- hr->set_recorded_rs_length(new_rs_length);
- hr->set_predicted_elapsed_time_ms(new_region_elapsed_time_ms);
-}
-
-void G1CollectorPolicy::add_region_to_incremental_cset_common(HeapRegion* hr) {
- assert(hr->is_young(), "invariant");
- assert(hr->young_index_in_cset() > -1, "should have already been set");
- assert(_inc_cset_build_state == Active, "Precondition");
-
- // We need to clear and set the cached recorded/cached collection set
- // information in the heap region here (before the region gets added
- // to the collection set). An individual heap region's cached values
- // are calculated, aggregated with the policy collection set info,
- // and cached in the heap region here (initially) and (subsequently)
- // by the Young List sampling code.
-
- size_t rs_length = hr->rem_set()->occupied();
- add_to_incremental_cset_info(hr, rs_length);
-
- assert(!hr->in_collection_set(), "invariant");
- _g1->register_young_region_with_cset(hr);
- assert(hr->next_in_collection_set() == NULL, "invariant");
-}
-
-// Add the region at the RHS of the incremental cset
-void G1CollectorPolicy::add_region_to_incremental_cset_rhs(HeapRegion* hr) {
- // We should only ever be appending survivors at the end of a pause
- assert(hr->is_survivor(), "Logic");
-
- // Do the 'common' stuff
- add_region_to_incremental_cset_common(hr);
-
- // Now add the region at the right hand side
- if (_inc_cset_tail == NULL) {
- assert(_inc_cset_head == NULL, "invariant");
- _inc_cset_head = hr;
- } else {
- _inc_cset_tail->set_next_in_collection_set(hr);
- }
- _inc_cset_tail = hr;
-}
-
-// Add the region to the LHS of the incremental cset
-void G1CollectorPolicy::add_region_to_incremental_cset_lhs(HeapRegion* hr) {
- // Survivors should be added to the RHS at the end of a pause
- assert(hr->is_eden(), "Logic");
-
- // Do the 'common' stuff
- add_region_to_incremental_cset_common(hr);
-
- // Add the region at the left hand side
- hr->set_next_in_collection_set(_inc_cset_head);
- if (_inc_cset_head == NULL) {
- assert(_inc_cset_tail == NULL, "Invariant");
- _inc_cset_tail = hr;
- }
- _inc_cset_head = hr;
-}
-
-#ifndef PRODUCT
-void G1CollectorPolicy::print_collection_set(HeapRegion* list_head, outputStream* st) {
- assert(list_head == inc_cset_head() || list_head == collection_set(), "must be");
-
- st->print_cr("\nCollection_set:");
- HeapRegion* csr = list_head;
- while (csr != NULL) {
- HeapRegion* next = csr->next_in_collection_set();
- assert(csr->in_collection_set(), "bad CS");
- st->print_cr(" " HR_FORMAT ", P: " PTR_FORMAT "N: " PTR_FORMAT ", age: %4d",
- HR_FORMAT_PARAMS(csr),
- p2i(csr->prev_top_at_mark_start()), p2i(csr->next_top_at_mark_start()),
- csr->age_in_surv_rate_group_cond());
- csr = next;
- }
-}
-#endif // !PRODUCT
-
double G1CollectorPolicy::reclaimable_bytes_perc(size_t reclaimable_bytes) const {
// Returns the given amount of reclaimable bytes (that represents
// the amount of reclaimable space still to be collected) as a
@@ -2139,161 +1307,7 @@
return (uint) result;
}
-
-double G1CollectorPolicy::finalize_young_cset_part(double target_pause_time_ms) {
- double young_start_time_sec = os::elapsedTime();
-
- YoungList* young_list = _g1->young_list();
- finalize_incremental_cset_building();
-
- guarantee(target_pause_time_ms > 0.0,
- "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms);
- guarantee(_collection_set == NULL, "Precondition");
-
- double base_time_ms = predict_base_elapsed_time_ms(_pending_cards);
- double time_remaining_ms = MAX2(target_pause_time_ms - base_time_ms, 0.0);
-
- log_trace(gc, ergo, cset)("Start choosing CSet. pending cards: " SIZE_FORMAT " predicted base time: %1.2fms remaining time: %1.2fms target pause time: %1.2fms",
- _pending_cards, base_time_ms, time_remaining_ms, target_pause_time_ms);
-
- collector_state()->set_last_gc_was_young(collector_state()->gcs_are_young());
-
- // The young list is laid with the survivor regions from the previous
- // pause are appended to the RHS of the young list, i.e.
- // [Newly Young Regions ++ Survivors from last pause].
-
- uint survivor_region_length = young_list->survivor_length();
- uint eden_region_length = young_list->eden_length();
- init_cset_region_lengths(eden_region_length, survivor_region_length);
-
- HeapRegion* hr = young_list->first_survivor_region();
- while (hr != NULL) {
- assert(hr->is_survivor(), "badly formed young list");
- // There is a convention that all the young regions in the CSet
- // are tagged as "eden", so we do this for the survivors here. We
- // use the special set_eden_pre_gc() as it doesn't check that the
- // region is free (which is not the case here).
- hr->set_eden_pre_gc();
- hr = hr->get_next_young_region();
- }
-
- // Clear the fields that point to the survivor list - they are all young now.
- young_list->clear_survivors();
-
- _collection_set = _inc_cset_head;
- _collection_set_bytes_used_before = _inc_cset_bytes_used_before;
- time_remaining_ms = MAX2(time_remaining_ms - _inc_cset_predicted_elapsed_time_ms, 0.0);
-
- log_trace(gc, ergo, cset)("Add young regions to CSet. eden: %u regions, survivors: %u regions, predicted young region time: %1.2fms, target pause time: %1.2fms",
- eden_region_length, survivor_region_length, _inc_cset_predicted_elapsed_time_ms, target_pause_time_ms);
-
- // The number of recorded young regions is the incremental
- // collection set's current size
- set_recorded_rs_lengths(_inc_cset_recorded_rs_lengths);
-
- double young_end_time_sec = os::elapsedTime();
- phase_times()->record_young_cset_choice_time_ms((young_end_time_sec - young_start_time_sec) * 1000.0);
-
- return time_remaining_ms;
+void G1CollectorPolicy::finalize_collection_set(double target_pause_time_ms) {
+ double time_remaining_ms = _collection_set->finalize_young_part(target_pause_time_ms);
+ _collection_set->finalize_old_part(time_remaining_ms);
}
-
-void G1CollectorPolicy::finalize_old_cset_part(double time_remaining_ms) {
- double non_young_start_time_sec = os::elapsedTime();
- double predicted_old_time_ms = 0.0;
-
-
- if (!collector_state()->gcs_are_young()) {
- cset_chooser()->verify();
- const uint min_old_cset_length = calc_min_old_cset_length();
- const uint max_old_cset_length = calc_max_old_cset_length();
-
- uint expensive_region_num = 0;
- bool check_time_remaining = adaptive_young_list_length();
-
- HeapRegion* hr = cset_chooser()->peek();
- while (hr != NULL) {
- if (old_cset_region_length() >= max_old_cset_length) {
- // Added maximum number of old regions to the CSet.
- log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached max). old %u regions, max %u regions",
- old_cset_region_length(), max_old_cset_length);
- break;
- }
-
-
- // Stop adding regions if the remaining reclaimable space is
- // not above G1HeapWastePercent.
- size_t reclaimable_bytes = cset_chooser()->remaining_reclaimable_bytes();
- double reclaimable_perc = reclaimable_bytes_perc(reclaimable_bytes);
- double threshold = (double) G1HeapWastePercent;
- if (reclaimable_perc <= threshold) {
- // We've added enough old regions that the amount of uncollected
- // reclaimable space is at or below the waste threshold. Stop
- // adding old regions to the CSet.
- log_debug(gc, ergo, cset)("Finish adding old regions to CSet (reclaimable percentage not over threshold). "
- "old %u regions, max %u regions, reclaimable: " SIZE_FORMAT "B (%1.2f%%) threshold: " UINTX_FORMAT "%%",
- old_cset_region_length(), max_old_cset_length, reclaimable_bytes, reclaimable_perc, G1HeapWastePercent);
- break;
- }
-
- double predicted_time_ms = predict_region_elapsed_time_ms(hr, collector_state()->gcs_are_young());
- if (check_time_remaining) {
- if (predicted_time_ms > time_remaining_ms) {
- // Too expensive for the current CSet.
-
- if (old_cset_region_length() >= min_old_cset_length) {
- // We have added the minimum number of old regions to the CSet,
- // we are done with this CSet.
- log_debug(gc, ergo, cset)("Finish adding old regions to CSet (predicted time is too high). "
- "predicted time: %1.2fms, remaining time: %1.2fms old %u regions, min %u regions",
- predicted_time_ms, time_remaining_ms, old_cset_region_length(), min_old_cset_length);
- break;
- }
-
- // We'll add it anyway given that we haven't reached the
- // minimum number of old regions.
- expensive_region_num += 1;
- }
- } else {
- if (old_cset_region_length() >= min_old_cset_length) {
- // In the non-auto-tuning case, we'll finish adding regions
- // to the CSet if we reach the minimum.
-
- log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached min). old %u regions, min %u regions",
- old_cset_region_length(), min_old_cset_length);
- break;
- }
- }
-
- // We will add this region to the CSet.
- time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0);
- predicted_old_time_ms += predicted_time_ms;
- cset_chooser()->pop(); // already have region via peek()
- _g1->old_set_remove(hr);
- add_old_region_to_cset(hr);
-
- hr = cset_chooser()->peek();
- }
- if (hr == NULL) {
- log_debug(gc, ergo, cset)("Finish adding old regions to CSet (candidate old regions not available)");
- }
-
- if (expensive_region_num > 0) {
- // We print the information once here at the end, predicated on
- // whether we added any apparently expensive regions or not, to
- // avoid generating output per region.
- log_debug(gc, ergo, cset)("Added expensive regions to CSet (old CSet region num not reached min)."
- "old: %u regions, expensive: %u regions, min: %u regions, remaining time: %1.2fms",
- old_cset_region_length(), expensive_region_num, min_old_cset_length, time_remaining_ms);
- }
-
- cset_chooser()->verify();
- }
-
- stop_incremental_cset_building();
-
- log_debug(gc, ergo, cset)("Finish choosing CSet. old: %u regions, predicted old region time: %1.2fms, time remaining: %1.2f",
- old_cset_region_length(), predicted_old_time_ms, time_remaining_ms);
-
- double non_young_end_time_sec = os::elapsedTime();
- phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0);
-}
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -25,7 +25,6 @@
#ifndef SHARE_VM_GC_G1_G1COLLECTORPOLICY_HPP
#define SHARE_VM_GC_G1_G1COLLECTORPOLICY_HPP
-#include "gc/g1/collectionSetChooser.hpp"
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1GCPhaseTimes.hpp"
#include "gc/g1/g1InCSetState.hpp"
@@ -41,8 +40,10 @@
// * when to collect.
class HeapRegion;
+class G1CollectionSet;
class CollectionSetChooser;
class G1IHOPControl;
+class G1Analytics;
class G1YoungGenSizer;
class G1CollectorPolicy: public CollectorPolicy {
@@ -57,30 +58,14 @@
void report_ihop_statistics();
G1Predictions _predictor;
-
- double get_new_prediction(TruncatedSeq const* seq) const;
- size_t get_new_size_prediction(TruncatedSeq const* seq) const;
-
+ G1Analytics* _analytics;
G1MMUTracker* _mmu_tracker;
void initialize_alignments();
void initialize_flags();
- CollectionSetChooser* _cset_chooser;
-
double _full_collection_start_sec;
- // These exclude marking times.
- TruncatedSeq* _recent_gc_times_ms;
-
- TruncatedSeq* _concurrent_mark_remark_times_ms;
- TruncatedSeq* _concurrent_mark_cleanup_times_ms;
-
- // Ratio check data for determining if heap growth is necessary.
- uint _ratio_over_threshold_count;
- double _ratio_over_threshold_sum;
- uint _pauses_since_start;
-
uint _young_list_target_length;
uint _young_list_fixed_length;
@@ -90,58 +75,14 @@
SurvRateGroup* _short_lived_surv_rate_group;
SurvRateGroup* _survivor_surv_rate_group;
- // add here any more surv rate groups
-
- double _gc_overhead_perc;
double _reserve_factor;
uint _reserve_regions;
- enum PredictionConstants {
- TruncatedSeqLength = 10,
- NumPrevPausesForHeuristics = 10,
- // MinOverThresholdForGrowth must be less than NumPrevPausesForHeuristics,
- // representing the minimum number of pause time ratios that exceed
- // GCTimeRatio before a heap expansion will be triggered.
- MinOverThresholdForGrowth = 4
- };
-
- TruncatedSeq* _alloc_rate_ms_seq;
- double _prev_collection_pause_end_ms;
-
- TruncatedSeq* _rs_length_diff_seq;
- TruncatedSeq* _cost_per_card_ms_seq;
- TruncatedSeq* _cost_scan_hcc_seq;
- TruncatedSeq* _young_cards_per_entry_ratio_seq;
- TruncatedSeq* _mixed_cards_per_entry_ratio_seq;
- TruncatedSeq* _cost_per_entry_ms_seq;
- TruncatedSeq* _mixed_cost_per_entry_ms_seq;
- TruncatedSeq* _cost_per_byte_ms_seq;
- TruncatedSeq* _constant_other_time_ms_seq;
- TruncatedSeq* _young_other_cost_per_region_ms_seq;
- TruncatedSeq* _non_young_other_cost_per_region_ms_seq;
-
- TruncatedSeq* _pending_cards_seq;
- TruncatedSeq* _rs_lengths_seq;
-
- TruncatedSeq* _cost_per_byte_ms_during_cm_seq;
-
G1YoungGenSizer* _young_gen_sizer;
- uint _eden_cset_region_length;
- uint _survivor_cset_region_length;
- uint _old_cset_region_length;
-
- void init_cset_region_lengths(uint eden_cset_region_length,
- uint survivor_cset_region_length);
-
- uint eden_cset_region_length() const { return _eden_cset_region_length; }
- uint survivor_cset_region_length() const { return _survivor_cset_region_length; }
- uint old_cset_region_length() const { return _old_cset_region_length; }
-
uint _free_regions_at_end_of_collection;
- size_t _recorded_rs_lengths;
size_t _max_rs_lengths;
size_t _rs_lengths_prediction;
@@ -165,6 +106,7 @@
G1InitialMarkToMixedTimeTracker _initial_mark_to_mixed;
public:
const G1Predictions& predictor() const { return _predictor; }
+ const G1Analytics* analytics() const { return const_cast<const G1Analytics*>(_analytics); }
// Add the given number of bytes to the total number of allocated bytes in the old gen.
void add_bytes_allocated_in_old_since_last_gc(size_t bytes) { _bytes_allocated_in_old_since_last_gc += bytes; }
@@ -191,37 +133,6 @@
_max_rs_lengths = rs_lengths;
}
- size_t predict_rs_length_diff() const;
-
- double predict_alloc_rate_ms() const;
-
- double predict_cost_per_card_ms() const;
-
- double predict_scan_hcc_ms() const;
-
- double predict_rs_update_time_ms(size_t pending_cards) const;
-
- double predict_young_cards_per_entry_ratio() const;
-
- double predict_mixed_cards_per_entry_ratio() const;
-
- size_t predict_young_card_num(size_t rs_length) const;
-
- size_t predict_non_young_card_num(size_t rs_length) const;
-
- double predict_rs_scan_time_ms(size_t card_num) const;
-
- double predict_mixed_rs_scan_time_ms(size_t card_num) const;
-
- double predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) const;
-
- double predict_object_copy_time_ms(size_t bytes_to_copy) const;
-
- double predict_constant_other_time_ms() const;
-
- double predict_young_other_time_ms(size_t young_num) const;
-
- double predict_non_young_other_time_ms(size_t non_young_num) const;
double predict_base_elapsed_time_ms(size_t pending_cards) const;
double predict_base_elapsed_time_ms(size_t pending_cards,
@@ -229,13 +140,6 @@
size_t predict_bytes_to_copy(HeapRegion* hr) const;
double predict_region_elapsed_time_ms(HeapRegion* hr, bool for_young_gc) const;
- void set_recorded_rs_lengths(size_t rs_lengths);
-
- uint cset_region_length() const { return young_cset_region_length() +
- old_cset_region_length(); }
- uint young_cset_region_length() const { return eden_cset_region_length() +
- survivor_cset_region_length(); }
-
double predict_survivor_regions_evac_time() const;
bool should_update_surv_rate_group_predictors() {
@@ -261,10 +165,6 @@
return _mmu_tracker->max_gc_time() * 1000.0;
}
- double predict_remark_time_ms() const;
-
- double predict_cleanup_time_ms() const;
-
// Returns an estimate of the survival rate of the region at yg-age
// "yg_age".
double predict_yg_surv_rate(int age, SurvRateGroup* surv_rate_group) const;
@@ -274,6 +174,7 @@
double accum_yg_surv_rate_pred(int age) const;
protected:
+ G1CollectionSet* _collection_set;
virtual double average_time_ms(G1GCPhaseTimes::GCParPhases phase) const;
virtual double other_time_ms(double pause_time_ms) const;
@@ -281,90 +182,17 @@
double non_young_other_time_ms() const;
double constant_other_time_ms(double pause_time_ms) const;
- CollectionSetChooser* cset_chooser() const {
- return _cset_chooser;
- }
-
+ CollectionSetChooser* cset_chooser() const;
private:
- // Statistics kept per GC stoppage, pause or full.
- TruncatedSeq* _recent_prev_end_times_for_all_gcs_sec;
-
- // Add a new GC of the given duration and end time to the record.
- void update_recent_gc_times(double end_time_sec, double elapsed_ms);
-
- // The head of the list (via "next_in_collection_set()") representing the
- // current collection set. Set from the incrementally built collection
- // set at the start of the pause.
- HeapRegion* _collection_set;
-
- // The number of bytes in the collection set before the pause. Set from
- // the incrementally built collection set at the start of an evacuation
- // pause, and incremented in finalize_old_cset_part() when adding old regions
- // (if any) to the collection set.
- size_t _collection_set_bytes_used_before;
// The number of bytes copied during the GC.
size_t _bytes_copied_during_gc;
- // The associated information that is maintained while the incremental
- // collection set is being built with young regions. Used to populate
- // the recorded info for the evacuation pause.
-
- enum CSetBuildType {
- Active, // We are actively building the collection set
- Inactive // We are not actively building the collection set
- };
-
- CSetBuildType _inc_cset_build_state;
-
- // The head of the incrementally built collection set.
- HeapRegion* _inc_cset_head;
-
- // The tail of the incrementally built collection set.
- HeapRegion* _inc_cset_tail;
-
- // The number of bytes in the incrementally built collection set.
- // Used to set _collection_set_bytes_used_before at the start of
- // an evacuation pause.
- size_t _inc_cset_bytes_used_before;
-
- // The RSet lengths recorded for regions in the CSet. It is updated
- // by the thread that adds a new region to the CSet. We assume that
- // only one thread can be allocating a new CSet region (currently,
- // it does so after taking the Heap_lock) hence no need to
- // synchronize updates to this field.
- size_t _inc_cset_recorded_rs_lengths;
-
- // A concurrent refinement thread periodically samples the young
- // region RSets and needs to update _inc_cset_recorded_rs_lengths as
- // the RSets grow. Instead of having to synchronize updates to that
- // field we accumulate them in this field and add it to
- // _inc_cset_recorded_rs_lengths_diffs at the start of a GC.
- ssize_t _inc_cset_recorded_rs_lengths_diffs;
-
- // The predicted elapsed time it will take to collect the regions in
- // the CSet. This is updated by the thread that adds a new region to
- // the CSet. See the comment for _inc_cset_recorded_rs_lengths about
- // MT-safety assumptions.
- double _inc_cset_predicted_elapsed_time_ms;
-
- // See the comment for _inc_cset_recorded_rs_lengths_diffs.
- double _inc_cset_predicted_elapsed_time_ms_diffs;
-
// Stash a pointer to the g1 heap.
G1CollectedHeap* _g1;
G1GCPhaseTimes* _phase_times;
- // The ratio of gc time to elapsed time, computed over recent pauses,
- // and the ratio for just the last pause.
- double _recent_avg_pause_time_ratio;
- double _last_pause_time_ratio;
-
- double recent_avg_pause_time_ratio() const {
- return _recent_avg_pause_time_ratio;
- }
-
// This set of variables tracks the collector efficiency, in order to
// determine whether we should initiate a new marking.
double _mark_remark_start_sec;
@@ -412,10 +240,6 @@
void update_rs_lengths_prediction();
void update_rs_lengths_prediction(size_t prediction);
- // Calculate and return chunk size (in number of regions) for parallel
- // concurrent mark cleanup.
- uint calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) const;
-
// Check whether a given young length (young_length) fits into the
// given target pause time and whether the prediction for the amount
// of objects to be copied for the given length will fit into the
@@ -424,6 +248,9 @@
bool predict_will_fit(uint young_length, double base_time_ms,
uint base_free_regions, double target_pause_time_ms) const;
+public:
+ size_t pending_cards() const { return _pending_cards; }
+
// Calculate the minimum number of old regions we'll add to the CSet
// during a mixed GC.
uint calc_min_old_cset_length() const;
@@ -436,6 +263,7 @@
// as a percentage of the current heap capacity.
double reclaimable_bytes_perc(size_t reclaimable_bytes) const;
+private:
// Sets up marking if proper conditions are met.
void maybe_start_marking();
@@ -520,83 +348,20 @@
return _bytes_copied_during_gc;
}
- size_t collection_set_bytes_used_before() const {
- return _collection_set_bytes_used_before;
- }
-
// Determine whether there are candidate regions so that the
// next GC should be mixed. The two action strings are used
// in the ergo output when the method returns true or false.
bool next_gc_should_be_mixed(const char* true_action_str,
const char* false_action_str) const;
- // Choose a new collection set. Marks the chosen regions as being
- // "in_collection_set", and links them together. The head and number of
- // the collection set are available via access methods.
- double finalize_young_cset_part(double target_pause_time_ms);
- virtual void finalize_old_cset_part(double time_remaining_ms);
-
- // The head of the list (via "next_in_collection_set()") representing the
- // current collection set.
- HeapRegion* collection_set() { return _collection_set; }
-
- void clear_collection_set() { _collection_set = NULL; }
-
- // Add old region "hr" to the CSet.
- void add_old_region_to_cset(HeapRegion* hr);
-
- // Incremental CSet Support
-
- // The head of the incrementally built collection set.
- HeapRegion* inc_cset_head() { return _inc_cset_head; }
-
- // The tail of the incrementally built collection set.
- HeapRegion* inc_set_tail() { return _inc_cset_tail; }
-
- // Initialize incremental collection set info.
- void start_incremental_cset_building();
-
- // Perform any final calculations on the incremental CSet fields
- // before we can use them.
- void finalize_incremental_cset_building();
-
- void clear_incremental_cset() {
- _inc_cset_head = NULL;
- _inc_cset_tail = NULL;
- }
-
- // Stop adding regions to the incremental collection set
- void stop_incremental_cset_building() { _inc_cset_build_state = Inactive; }
-
- // Add information about hr to the aggregated information for the
- // incrementally built collection set.
- void add_to_incremental_cset_info(HeapRegion* hr, size_t rs_length);
-
- // Update information about hr in the aggregated information for
- // the incrementally built collection set.
- void update_incremental_cset_info(HeapRegion* hr, size_t new_rs_length);
-
+ virtual void finalize_collection_set(double target_pause_time_ms);
private:
- // Update the incremental cset information when adding a region
- // (should not be called directly).
- void add_region_to_incremental_cset_common(HeapRegion* hr);
-
// Set the state to start a concurrent marking cycle and clear
// _initiate_conc_mark_if_possible because it has now been
// acted on.
void initiate_conc_mark();
public:
- // Add hr to the LHS of the incremental collection set.
- void add_region_to_incremental_cset_lhs(HeapRegion* hr);
-
- // Add hr to the RHS of the incremental collection set.
- void add_region_to_incremental_cset_rhs(HeapRegion* hr);
-
-#ifndef PRODUCT
- void print_collection_set(HeapRegion* list_head, outputStream* st);
-#endif // !PRODUCT
-
// This sets the initiate_conc_mark_if_possible() flag to start a
// new cycle, as long as we are not already in one. It's best if it
// is called during a safepoint when the test whether a cycle is in
@@ -611,13 +376,6 @@
// the initial-mark work and start a marking cycle.
void decide_on_conc_mark_initiation();
- // If an expansion would be appropriate, because recent GC overhead had
- // exceeded the desired limit, return an amount to expand by.
- virtual size_t expansion_amount();
-
- // Clear ratio tracking data used by expansion_amount().
- void clear_ratio_check_data();
-
// Print stats on young survival ratio
void print_yg_surv_rate_info() const;
@@ -627,7 +385,6 @@
} else {
_short_lived_surv_rate_group->finished_recalculating_age_indexes();
}
- // do that for any other surv rate groups
}
size_t young_list_target_length() const { return _young_list_target_length; }
@@ -658,16 +415,6 @@
// The limit on the number of regions allocated for survivors.
uint _max_survivor_regions;
- // For reporting purposes.
- // The value of _heap_bytes_before_gc is also used to calculate
- // the cost of copying.
-
- // The amount of survivor regions after a collection.
- uint _recorded_survivor_regions;
- // List of survivor regions.
- HeapRegion* _recorded_survivor_head;
- HeapRegion* _recorded_survivor_tail;
-
AgeTable _survivors_age_table;
public:
@@ -701,18 +448,6 @@
_survivor_surv_rate_group->stop_adding_regions();
}
- void record_survivor_regions(uint regions,
- HeapRegion* head,
- HeapRegion* tail) {
- _recorded_survivor_regions = regions;
- _recorded_survivor_head = head;
- _recorded_survivor_tail = tail;
- }
-
- uint recorded_survivor_regions() const {
- return _recorded_survivor_regions;
- }
-
void record_age_table(AgeTable* age_table) {
_survivors_age_table.merge(age_table);
}
--- a/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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,9 @@
#ifndef SHARE_VM_GC_G1_G1COLLECTORSTATE_HPP
#define SHARE_VM_GC_G1_G1COLLECTORSTATE_HPP
+#include "gc/g1/g1YCTypes.hpp"
+#include "memory/allocation.hpp"
#include "utilities/globalDefinitions.hpp"
-#include "gc/g1/g1YCTypes.hpp"
// Various state variables that indicate
// the phase of the G1 collection.
@@ -71,7 +72,6 @@
bool _in_marking_window;
bool _in_marking_window_im;
- bool _concurrent_cycle_started;
bool _full_collection;
public:
@@ -87,7 +87,6 @@
_mark_in_progress(false),
_in_marking_window(false),
_in_marking_window_im(false),
- _concurrent_cycle_started(false),
_full_collection(false) {}
// Setters
@@ -100,7 +99,6 @@
void set_mark_in_progress(bool v) { _mark_in_progress = v; }
void set_in_marking_window(bool v) { _in_marking_window = v; }
void set_in_marking_window_im(bool v) { _in_marking_window_im = v; }
- void set_concurrent_cycle_started(bool v) { _concurrent_cycle_started = v; }
void set_full_collection(bool v) { _full_collection = v; }
// Getters
@@ -113,7 +111,6 @@
bool mark_in_progress() const { return _mark_in_progress; }
bool in_marking_window() const { return _in_marking_window; }
bool in_marking_window_im() const { return _in_marking_window_im; }
- bool concurrent_cycle_started() const { return _concurrent_cycle_started; }
bool full_collection() const { return _full_collection; }
// Composite booleans (clients worry about flickering)
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -120,74 +120,10 @@
}
// We need to clear the bitmap on commit, removing any existing information.
MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_region), num_regions * HeapRegion::GrainWords);
- _bm->clearRange(mr);
+ _bm->clear_range(mr);
}
-// Closure used for clearing the given mark bitmap.
-class ClearBitmapHRClosure : public HeapRegionClosure {
- private:
- G1ConcurrentMark* _cm;
- G1CMBitMap* _bitmap;
- bool _may_yield; // The closure may yield during iteration. If yielded, abort the iteration.
- public:
- ClearBitmapHRClosure(G1ConcurrentMark* cm, G1CMBitMap* bitmap, bool may_yield) : HeapRegionClosure(), _cm(cm), _bitmap(bitmap), _may_yield(may_yield) {
- assert(!may_yield || cm != NULL, "CM must be non-NULL if this closure is expected to yield.");
- }
-
- virtual bool doHeapRegion(HeapRegion* r) {
- size_t const chunk_size_in_words = M / HeapWordSize;
-
- HeapWord* cur = r->bottom();
- HeapWord* const end = r->end();
-
- while (cur < end) {
- MemRegion mr(cur, MIN2(cur + chunk_size_in_words, end));
- _bitmap->clearRange(mr);
-
- cur += chunk_size_in_words;
-
- // Abort iteration if after yielding the marking has been aborted.
- if (_may_yield && _cm->do_yield_check() && _cm->has_aborted()) {
- return true;
- }
- // Repeat the asserts from before the start of the closure. We will do them
- // as asserts here to minimize their overhead on the product. However, we
- // will have them as guarantees at the beginning / end of the bitmap
- // clearing to get some checking in the product.
- assert(!_may_yield || _cm->cmThread()->during_cycle(), "invariant");
- assert(!_may_yield || !G1CollectedHeap::heap()->collector_state()->mark_in_progress(), "invariant");
- }
-
- return false;
- }
-};
-
-class ParClearNextMarkBitmapTask : public AbstractGangTask {
- ClearBitmapHRClosure* _cl;
- HeapRegionClaimer _hrclaimer;
- bool _suspendible; // If the task is suspendible, workers must join the STS.
-
-public:
- ParClearNextMarkBitmapTask(ClearBitmapHRClosure *cl, uint n_workers, bool suspendible) :
- _cl(cl), _suspendible(suspendible), AbstractGangTask("Parallel Clear Bitmap Task"), _hrclaimer(n_workers) {}
-
- void work(uint worker_id) {
- SuspendibleThreadSetJoiner sts_join(_suspendible);
- G1CollectedHeap::heap()->heap_region_par_iterate(_cl, worker_id, &_hrclaimer, true);
- }
-};
-
-void G1CMBitMap::clearAll() {
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
- ClearBitmapHRClosure cl(NULL, this, false /* may_yield */);
- uint n_workers = g1h->workers()->active_workers();
- ParClearNextMarkBitmapTask task(&cl, n_workers, false);
- g1h->workers()->run_task(&task);
- guarantee(cl.complete(), "Must have completed iteration.");
- return;
-}
-
-void G1CMBitMap::clearRange(MemRegion mr) {
+void G1CMBitMap::clear_range(MemRegion mr) {
mr.intersection(MemRegion(_bmStartWord, _bmWordSize));
assert(!mr.is_empty(), "unexpected empty region");
// convert address range into offset range
@@ -203,12 +139,12 @@
// allocate a stack of the requisite depth
ReservedSpace rs(ReservedSpace::allocation_align_size_up(capacity * sizeof(oop)));
if (!rs.is_reserved()) {
- warning("ConcurrentMark MarkStack allocation failure");
+ log_warning(gc)("ConcurrentMark MarkStack allocation failure");
return false;
}
MemTracker::record_virtual_memory_type((address)rs.base(), mtGC);
if (!_virtual_space.initialize(rs, rs.size())) {
- warning("ConcurrentMark MarkStack backing store failure");
+ log_warning(gc)("ConcurrentMark MarkStack backing store failure");
// Release the virtual memory reserved for the marking stack
rs.release();
return false;
@@ -441,7 +377,8 @@
_has_aborted(false),
_restart_for_overflow(false),
_concurrent_marking_in_progress(false),
- _concurrent_phase_status(ConcPhaseNotStarted),
+ _gc_timer_cm(new (ResourceObj::C_HEAP, mtGC) ConcurrentGCTimer()),
+ _gc_tracer_cm(new (ResourceObj::C_HEAP, mtGC) G1OldTracer()),
// _verbose_level set below
@@ -478,9 +415,8 @@
_root_regions.init(_g1h, this);
if (ConcGCThreads > ParallelGCThreads) {
- warning("Can't have more ConcGCThreads (%u) "
- "than ParallelGCThreads (%u).",
- ConcGCThreads, ParallelGCThreads);
+ log_warning(gc)("Can't have more ConcGCThreads (%u) than ParallelGCThreads (%u).",
+ ConcGCThreads, ParallelGCThreads);
return;
}
if (!FLAG_IS_DEFAULT(ConcGCThreads) && ConcGCThreads > 0) {
@@ -534,9 +470,9 @@
// Verify that the calculated value for MarkStackSize is in range.
// It would be nice to use the private utility routine from Arguments.
if (!(mark_stack_size >= 1 && mark_stack_size <= MarkStackSizeMax)) {
- warning("Invalid value calculated for MarkStackSize (" SIZE_FORMAT "): "
- "must be between 1 and " SIZE_FORMAT,
- mark_stack_size, MarkStackSizeMax);
+ log_warning(gc)("Invalid value calculated for MarkStackSize (" SIZE_FORMAT "): "
+ "must be between 1 and " SIZE_FORMAT,
+ mark_stack_size, MarkStackSizeMax);
return;
}
FLAG_SET_ERGO(size_t, MarkStackSize, mark_stack_size);
@@ -545,16 +481,16 @@
if (FLAG_IS_CMDLINE(MarkStackSize)) {
if (FLAG_IS_DEFAULT(MarkStackSizeMax)) {
if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) {
- warning("Invalid value specified for MarkStackSize (" SIZE_FORMAT "): "
- "must be between 1 and " SIZE_FORMAT,
- MarkStackSize, MarkStackSizeMax);
+ log_warning(gc)("Invalid value specified for MarkStackSize (" SIZE_FORMAT "): "
+ "must be between 1 and " SIZE_FORMAT,
+ MarkStackSize, MarkStackSizeMax);
return;
}
} else if (FLAG_IS_CMDLINE(MarkStackSizeMax)) {
if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) {
- warning("Invalid value specified for MarkStackSize (" SIZE_FORMAT ")"
- " or for MarkStackSizeMax (" SIZE_FORMAT ")",
- MarkStackSize, MarkStackSizeMax);
+ log_warning(gc)("Invalid value specified for MarkStackSize (" SIZE_FORMAT ")"
+ " or for MarkStackSizeMax (" SIZE_FORMAT ")",
+ MarkStackSize, MarkStackSizeMax);
return;
}
}
@@ -562,7 +498,7 @@
}
if (!_markStack.allocate(MarkStackSize)) {
- warning("Failed to allocate CM marking stack");
+ log_warning(gc)("Failed to allocate CM marking stack");
return;
}
@@ -698,9 +634,76 @@
ShouldNotReachHere();
}
-void G1ConcurrentMark::clearNextBitmap() {
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
-
+class G1ClearBitMapTask : public AbstractGangTask {
+ // Heap region closure used for clearing the given mark bitmap.
+ class G1ClearBitmapHRClosure : public HeapRegionClosure {
+ private:
+ G1CMBitMap* _bitmap;
+ G1ConcurrentMark* _cm;
+ public:
+ G1ClearBitmapHRClosure(G1CMBitMap* bitmap, G1ConcurrentMark* cm) : HeapRegionClosure(), _cm(cm), _bitmap(bitmap) {
+ }
+
+ virtual bool doHeapRegion(HeapRegion* r) {
+ size_t const chunk_size_in_words = M / HeapWordSize;
+
+ HeapWord* cur = r->bottom();
+ HeapWord* const end = r->end();
+
+ while (cur < end) {
+ MemRegion mr(cur, MIN2(cur + chunk_size_in_words, end));
+ _bitmap->clear_range(mr);
+
+ cur += chunk_size_in_words;
+
+ // Abort iteration if after yielding the marking has been aborted.
+ if (_cm != NULL && _cm->do_yield_check() && _cm->has_aborted()) {
+ return true;
+ }
+ // Repeat the asserts from before the start of the closure. We will do them
+ // as asserts here to minimize their overhead on the product. However, we
+ // will have them as guarantees at the beginning / end of the bitmap
+ // clearing to get some checking in the product.
+ assert(_cm == NULL || _cm->cmThread()->during_cycle(), "invariant");
+ assert(_cm == NULL || !G1CollectedHeap::heap()->collector_state()->mark_in_progress(), "invariant");
+ }
+ assert(cur == end, "Must have completed iteration over the bitmap for region %u.", r->hrm_index());
+
+ return false;
+ }
+ };
+
+ G1ClearBitmapHRClosure _cl;
+ HeapRegionClaimer _hr_claimer;
+ bool _suspendible; // If the task is suspendible, workers must join the STS.
+
+public:
+ G1ClearBitMapTask(G1CMBitMap* bitmap, G1ConcurrentMark* cm, uint n_workers, bool suspendible) :
+ AbstractGangTask("Parallel Clear Bitmap Task"),
+ _cl(bitmap, suspendible ? cm : NULL),
+ _hr_claimer(n_workers),
+ _suspendible(suspendible)
+ { }
+
+ void work(uint worker_id) {
+ SuspendibleThreadSetJoiner sts_join(_suspendible);
+ G1CollectedHeap::heap()->heap_region_par_iterate(&_cl, worker_id, &_hr_claimer, true);
+ }
+
+ bool is_complete() {
+ return _cl.complete();
+ }
+};
+
+void G1ConcurrentMark::clear_bitmap(G1CMBitMap* bitmap, WorkGang* workers, bool may_yield) {
+ assert(may_yield || SafepointSynchronize::is_at_safepoint(), "Non-yielding bitmap clear only allowed at safepoint.");
+
+ G1ClearBitMapTask task(bitmap, this, workers->active_workers(), may_yield);
+ workers->run_task(&task);
+ guarantee(!may_yield || task.is_complete(), "Must have completed iteration when not yielding.");
+}
+
+void G1ConcurrentMark::cleanup_for_next_mark() {
// Make sure that the concurrent mark thread looks to still be in
// the current cycle.
guarantee(cmThread()->during_cycle(), "invariant");
@@ -709,21 +712,24 @@
// marking bitmap and getting it ready for the next cycle. During
// this time no other cycle can start. So, let's make sure that this
// is the case.
- guarantee(!g1h->collector_state()->mark_in_progress(), "invariant");
-
- ClearBitmapHRClosure cl(this, _nextMarkBitMap, true /* may_yield */);
- ParClearNextMarkBitmapTask task(&cl, parallel_marking_threads(), true);
- _parallel_workers->run_task(&task);
+ guarantee(!_g1h->collector_state()->mark_in_progress(), "invariant");
+
+ clear_bitmap(_nextMarkBitMap, _parallel_workers, true);
// Clear the liveness counting data. If the marking has been aborted, the abort()
// call already did that.
- if (cl.complete()) {
+ if (!has_aborted()) {
clear_all_count_data();
}
// Repeat the asserts from above.
guarantee(cmThread()->during_cycle(), "invariant");
- guarantee(!g1h->collector_state()->mark_in_progress(), "invariant");
+ guarantee(!_g1h->collector_state()->mark_in_progress(), "invariant");
+}
+
+void G1ConcurrentMark::clear_prev_bitmap(WorkGang* workers) {
+ assert(SafepointSynchronize::is_at_safepoint(), "Should only clear the entire prev bitmap at a safepoint.");
+ clear_bitmap((G1CMBitMap*)_prevMarkBitMap, workers, false);
}
class CheckBitmapClearHRClosure : public HeapRegionClosure {
@@ -848,7 +854,7 @@
// marking.
reset_marking_state(true /* clear_overflow */);
- log_info(gc)("Concurrent Mark reset for overflow");
+ log_info(gc, marking)("Concurrent Mark reset for overflow");
}
}
@@ -983,13 +989,12 @@
}
};
-void G1ConcurrentMark::scanRootRegions() {
+void G1ConcurrentMark::scan_root_regions() {
// scan_in_progress() will have been set to true only if there was
// at least one root region to scan. So, if it's false, we
// should not attempt to do any further work.
if (root_regions()->scan_in_progress()) {
assert(!has_aborted(), "Aborting before root region scanning is finished not supported.");
- GCTraceConcTime(Info, gc) tt("Concurrent Root Region Scan");
_parallel_marking_threads = calc_parallel_marking_threads();
assert(parallel_marking_threads() <= max_parallel_marking_threads(),
@@ -1007,47 +1012,27 @@
}
}
-void G1ConcurrentMark::register_concurrent_phase_start(const char* title) {
- uint old_val = 0;
- do {
- old_val = Atomic::cmpxchg(ConcPhaseStarted, &_concurrent_phase_status, ConcPhaseNotStarted);
- } while (old_val != ConcPhaseNotStarted);
- _g1h->gc_timer_cm()->register_gc_concurrent_start(title);
+void G1ConcurrentMark::concurrent_cycle_start() {
+ _gc_timer_cm->register_gc_start();
+
+ _gc_tracer_cm->report_gc_start(GCCause::_no_gc /* first parameter is not used */, _gc_timer_cm->gc_start());
+
+ _g1h->trace_heap_before_gc(_gc_tracer_cm);
}
-void G1ConcurrentMark::register_concurrent_phase_end_common(bool end_timer) {
- if (_concurrent_phase_status == ConcPhaseNotStarted) {
- return;
+void G1ConcurrentMark::concurrent_cycle_end() {
+ _g1h->trace_heap_after_gc(_gc_tracer_cm);
+
+ if (has_aborted()) {
+ _gc_tracer_cm->report_concurrent_mode_failure();
}
- uint old_val = Atomic::cmpxchg(ConcPhaseStopping, &_concurrent_phase_status, ConcPhaseStarted);
- if (old_val == ConcPhaseStarted) {
- _g1h->gc_timer_cm()->register_gc_concurrent_end();
- // If 'end_timer' is true, we came here to end timer which needs concurrent phase ended.
- // We need to end it before changing the status to 'ConcPhaseNotStarted' to prevent
- // starting a new concurrent phase by 'ConcurrentMarkThread'.
- if (end_timer) {
- _g1h->gc_timer_cm()->register_gc_end();
- }
- old_val = Atomic::cmpxchg(ConcPhaseNotStarted, &_concurrent_phase_status, ConcPhaseStopping);
- assert(old_val == ConcPhaseStopping, "Should not have changed since we entered this scope.");
- } else {
- do {
- // Let other thread finish changing '_concurrent_phase_status' to 'ConcPhaseNotStarted'.
- os::naked_short_sleep(1);
- } while (_concurrent_phase_status != ConcPhaseNotStarted);
- }
+ _gc_timer_cm->register_gc_end();
+
+ _gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions());
}
-void G1ConcurrentMark::register_concurrent_phase_end() {
- register_concurrent_phase_end_common(false);
-}
-
-void G1ConcurrentMark::register_concurrent_gc_end_and_stop_timer() {
- register_concurrent_phase_end_common(true);
-}
-
-void G1ConcurrentMark::markFromRoots() {
+void G1ConcurrentMark::mark_from_roots() {
// we might be tempted to assert that:
// assert(asynch == !SafepointSynchronize::is_at_safepoint(),
// "inconsistent argument?");
@@ -1110,7 +1095,6 @@
if (has_overflown()) {
// Oops. We overflowed. Restart concurrent marking.
_restart_for_overflow = true;
- log_develop_trace(gc)("Remark led to restart for overflow.");
// Verify the heap w.r.t. the previous marking bitmap.
if (VerifyDuringGC) {
@@ -1124,7 +1108,7 @@
reset_marking_state();
} else {
{
- GCTraceTime(Debug, gc) trace("Aggregate Data", g1h->gc_timer_cm());
+ GCTraceTime(Debug, gc, phases) trace("Aggregate Data", _gc_timer_cm);
// Aggregate the per-task counting data that we have accumulated
// while marking.
@@ -1163,7 +1147,7 @@
g1p->record_concurrent_mark_remark_end();
G1CMIsAliveClosure is_alive(g1h);
- g1h->gc_tracer_cm()->report_object_count_after_gc(&is_alive);
+ _gc_tracer_cm->report_object_count_after_gc(&is_alive);
}
// Base class of the closures that finalize and verify the
@@ -1752,11 +1736,9 @@
// sure we update the old gen/space data.
g1h->g1mm()->update_sizes();
g1h->allocation_context_stats().update_after_mark();
-
- g1h->trace_heap_after_concurrent_cycle();
}
-void G1ConcurrentMark::completeCleanup() {
+void G1ConcurrentMark::complete_cleanup() {
if (has_aborted()) return;
G1CollectedHeap* g1h = G1CollectedHeap::heap();
@@ -2045,7 +2027,7 @@
// Inner scope to exclude the cleaning of the string and symbol
// tables from the displayed time.
{
- GCTraceTime(Debug, gc) trace("Reference Processing", g1h->gc_timer_cm());
+ GCTraceTime(Debug, gc, phases) trace("Reference Processing", _gc_timer_cm);
ReferenceProcessor* rp = g1h->ref_processor_cm();
@@ -2102,8 +2084,8 @@
&g1_keep_alive,
&g1_drain_mark_stack,
executor,
- g1h->gc_timer_cm());
- g1h->gc_tracer_cm()->report_gc_reference_stats(stats);
+ _gc_timer_cm);
+ _gc_tracer_cm->report_gc_reference_stats(stats);
// The do_oop work routines of the keep_alive and drain_marking_stack
// oop closures will set the has_overflown flag if we overflow the
@@ -2134,28 +2116,24 @@
assert(_markStack.isEmpty(), "Marking should have completed");
// Unload Klasses, String, Symbols, Code Cache, etc.
- {
- GCTraceTime(Debug, gc) trace("Unloading", g1h->gc_timer_cm());
-
- if (ClassUnloadingWithConcurrentMark) {
- bool purged_classes;
-
- {
- GCTraceTime(Trace, gc) trace("System Dictionary Unloading", g1h->gc_timer_cm());
- purged_classes = SystemDictionary::do_unloading(&g1_is_alive, false /* Defer klass cleaning */);
- }
-
- {
- GCTraceTime(Trace, gc) trace("Parallel Unloading", g1h->gc_timer_cm());
- weakRefsWorkParallelPart(&g1_is_alive, purged_classes);
- }
+ if (ClassUnloadingWithConcurrentMark) {
+ bool purged_classes;
+
+ {
+ GCTraceTime(Debug, gc, phases) trace("System Dictionary Unloading", _gc_timer_cm);
+ purged_classes = SystemDictionary::do_unloading(&g1_is_alive, false /* Defer klass cleaning */);
}
- if (G1StringDedup::is_enabled()) {
- GCTraceTime(Trace, gc) trace("String Deduplication Unlink", g1h->gc_timer_cm());
- G1StringDedup::unlink(&g1_is_alive);
+ {
+ GCTraceTime(Debug, gc, phases) trace("Parallel Unloading", _gc_timer_cm);
+ weakRefsWorkParallelPart(&g1_is_alive, purged_classes);
}
}
+
+ if (G1StringDedup::is_enabled()) {
+ GCTraceTime(Debug, gc, phases) trace("String Deduplication Unlink", _gc_timer_cm);
+ G1StringDedup::unlink(&g1_is_alive);
+ }
}
void G1ConcurrentMark::swapMarkBitMaps() {
@@ -2273,7 +2251,7 @@
HandleMark hm;
G1CollectedHeap* g1h = G1CollectedHeap::heap();
- GCTraceTime(Debug, gc) trace("Finalize Marking", g1h->gc_timer_cm());
+ GCTraceTime(Debug, gc, phases) trace("Finalize Marking", _gc_timer_cm);
g1h->ensure_parsability(false);
@@ -2308,7 +2286,7 @@
void G1ConcurrentMark::clearRangePrevBitmap(MemRegion mr) {
// Note we are overriding the read-only view of the prev map here, via
// the cast.
- ((G1CMBitMap*)_prevMarkBitMap)->clearRange(mr);
+ ((G1CMBitMap*)_prevMarkBitMap)->clear_range(mr);
}
HeapRegion*
@@ -2605,7 +2583,7 @@
// Clear all marks in the next bitmap for the next marking cycle. This will allow us to skip the next
// concurrent bitmap clearing.
- _nextMarkBitMap->clearAll();
+ clear_bitmap(_nextMarkBitMap, _g1h->workers(), false);
// Note we cannot clear the previous marking bitmap here
// since VerifyDuringGC verifies the objects marked during
@@ -2629,10 +2607,6 @@
satb_mq_set.set_active_all_threads(
false, /* new active value */
satb_mq_set.is_active() /* expected_active */);
-
- _g1h->trace_heap_after_concurrent_cycle();
-
- _g1h->register_concurrent_cycle_end();
}
static void print_ms_time_info(const char* prefix, const char* name,
@@ -3554,8 +3528,6 @@
G1PrintRegionLivenessInfoClosure(const char* phase_name)
: _total_used_bytes(0), _total_capacity_bytes(0),
_total_prev_live_bytes(0), _total_next_live_bytes(0),
- _hum_used_bytes(0), _hum_capacity_bytes(0),
- _hum_prev_live_bytes(0), _hum_next_live_bytes(0),
_total_remset_bytes(0), _total_strong_code_roots_bytes(0) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
MemRegion g1_reserved = g1h->g1_reserved();
@@ -3595,36 +3567,6 @@
"(bytes)", "(bytes)");
}
-// It takes as a parameter a reference to one of the _hum_* fields, it
-// deduces the corresponding value for a region in a humongous region
-// series (either the region size, or what's left if the _hum_* field
-// is < the region size), and updates the _hum_* field accordingly.
-size_t G1PrintRegionLivenessInfoClosure::get_hum_bytes(size_t* hum_bytes) {
- size_t bytes = 0;
- // The > 0 check is to deal with the prev and next live bytes which
- // could be 0.
- if (*hum_bytes > 0) {
- bytes = MIN2(HeapRegion::GrainBytes, *hum_bytes);
- *hum_bytes -= bytes;
- }
- return bytes;
-}
-
-// It deduces the values for a region in a humongous region series
-// from the _hum_* fields and updates those accordingly. It assumes
-// that that _hum_* fields have already been set up from the "starts
-// humongous" region and we visit the regions in address order.
-void G1PrintRegionLivenessInfoClosure::get_hum_bytes(size_t* used_bytes,
- size_t* capacity_bytes,
- size_t* prev_live_bytes,
- size_t* next_live_bytes) {
- assert(_hum_used_bytes > 0 && _hum_capacity_bytes > 0, "pre-condition");
- *used_bytes = get_hum_bytes(&_hum_used_bytes);
- *capacity_bytes = get_hum_bytes(&_hum_capacity_bytes);
- *prev_live_bytes = get_hum_bytes(&_hum_prev_live_bytes);
- *next_live_bytes = get_hum_bytes(&_hum_next_live_bytes);
-}
-
bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) {
const char* type = r->get_type_str();
HeapWord* bottom = r->bottom();
@@ -3637,24 +3579,6 @@
size_t remset_bytes = r->rem_set()->mem_size();
size_t strong_code_roots_bytes = r->rem_set()->strong_code_roots_mem_size();
- if (r->is_starts_humongous()) {
- assert(_hum_used_bytes == 0 && _hum_capacity_bytes == 0 &&
- _hum_prev_live_bytes == 0 && _hum_next_live_bytes == 0,
- "they should have been zeroed after the last time we used them");
- // Set up the _hum_* fields.
- _hum_capacity_bytes = capacity_bytes;
- _hum_used_bytes = used_bytes;
- _hum_prev_live_bytes = prev_live_bytes;
- _hum_next_live_bytes = next_live_bytes;
- get_hum_bytes(&used_bytes, &capacity_bytes,
- &prev_live_bytes, &next_live_bytes);
- end = bottom + HeapRegion::GrainWords;
- } else if (r->is_continues_humongous()) {
- get_hum_bytes(&used_bytes, &capacity_bytes,
- &prev_live_bytes, &next_live_bytes);
- assert(end == bottom + HeapRegion::GrainWords, "invariant");
- }
-
_total_used_bytes += used_bytes;
_total_capacity_bytes += capacity_bytes;
_total_prev_live_bytes += prev_live_bytes;
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -34,6 +34,8 @@
class G1CMBitMap;
class G1CMTask;
class G1ConcurrentMark;
+class ConcurrentGCTimer;
+class G1OldTracer;
typedef GenericTaskQueue<oop, mtGC> G1CMTaskQueue;
typedef GenericTaskQueueSet<G1CMTaskQueue, mtGC> G1CMTaskQueueSet;
@@ -139,10 +141,7 @@
inline void clear(HeapWord* addr);
inline bool parMark(HeapWord* addr);
- void clearRange(MemRegion mr);
-
- // Clear the whole mark bitmap.
- void clearAll();
+ void clear_range(MemRegion mr);
};
// Represents a marking stack used by ConcurrentMarking in the G1 collector.
@@ -352,17 +351,9 @@
// time of remark.
volatile bool _concurrent_marking_in_progress;
- // There would be a race between ConcurrentMarkThread and VMThread(ConcurrentMark::abort())
- // to call ConcurrentGCTimer::register_gc_concurrent_end().
- // And this variable is used to keep track of concurrent phase.
- volatile uint _concurrent_phase_status;
- // Concurrent phase is not yet started.
- static const uint ConcPhaseNotStarted = 0;
- // Concurrent phase is started.
- static const uint ConcPhaseStarted = 1;
- // Caller thread of ConcurrentGCTimer::register_gc_concurrent_end() is ending concurrent phase.
- // So other thread should wait until the status to be changed to ConcPhaseNotStarted.
- static const uint ConcPhaseStopping = 2;
+ ConcurrentGCTimer* _gc_timer_cm;
+
+ G1OldTracer* _gc_tracer_cm;
// All of these times are in ms
NumberSeq _init_times;
@@ -497,6 +488,9 @@
// end_timer, true to end gc timer after ending concurrent phase.
void register_concurrent_phase_end_common(bool end_timer);
+ // Clear the given bitmap in parallel using the given WorkGang. If may_yield is
+ // true, periodically insert checks to see if this method should exit prematurely.
+ void clear_bitmap(G1CMBitMap* bitmap, WorkGang* workers, bool may_yield);
public:
// Manipulation of the global mark stack.
// The push and pop operations are used by tasks for transfers
@@ -530,10 +524,8 @@
_concurrent_marking_in_progress = false;
}
- void register_concurrent_phase_start(const char* title);
- void register_concurrent_phase_end();
- // Ends both concurrent phase and timer.
- void register_concurrent_gc_end_and_stop_timer();
+ void concurrent_cycle_start();
+ void concurrent_cycle_end();
void update_accum_task_vtime(int i, double vtime) {
_accum_task_vtime[i] += vtime;
@@ -585,8 +577,13 @@
uint worker_id,
HeapRegion* hr = NULL);
- // Clear the next marking bitmap (will be called concurrently).
- void clearNextBitmap();
+ // Prepare internal data structures for the next mark cycle. This includes clearing
+ // the next mark bitmap and some internal data structures. This method is intended
+ // to be called concurrently to the mutator. It will yield to safepoint requests.
+ void cleanup_for_next_mark();
+
+ // Clear the previous marking bitmap during safepoint.
+ void clear_prev_bitmap(WorkGang* workers);
// Return whether the next mark bitmap has no marks set. To be used for assertions
// only. Will not yield to pause requests.
@@ -603,18 +600,18 @@
// Scan all the root regions and mark everything reachable from
// them.
- void scanRootRegions();
+ void scan_root_regions();
// Scan a single root region and mark everything reachable from it.
void scanRootRegion(HeapRegion* hr, uint worker_id);
// Do concurrent phase of marking, to a tentative transitive closure.
- void markFromRoots();
+ void mark_from_roots();
void checkpointRootsFinal(bool clear_all_soft_refs);
void checkpointRootsFinalWork();
void cleanup();
- void completeCleanup();
+ void complete_cleanup();
// Mark in the previous bitmap. NB: this is usually read-only, so use
// this carefully!
@@ -730,6 +727,9 @@
return _completed_initialization;
}
+ ConcurrentGCTimer* gc_timer_cm() const { return _gc_timer_cm; }
+ G1OldTracer* gc_tracer_cm() const { return _gc_tracer_cm; }
+
protected:
// Clear all the per-task bitmaps and arrays used to store the
// counting data.
@@ -996,18 +996,6 @@
size_t _total_prev_live_bytes;
size_t _total_next_live_bytes;
- // These are set up when we come across a "stars humongous" region
- // (as this is where most of this information is stored, not in the
- // subsequent "continues humongous" regions). After that, for every
- // region in a given humongous region series we deduce the right
- // values for it by simply subtracting the appropriate amount from
- // these fields. All these values should reach 0 after we've visited
- // the last region in the series.
- size_t _hum_used_bytes;
- size_t _hum_capacity_bytes;
- size_t _hum_prev_live_bytes;
- size_t _hum_next_live_bytes;
-
// Accumulator for the remembered set size
size_t _total_remset_bytes;
@@ -1026,11 +1014,6 @@
return (double) val / (double) M;
}
- // See the .cpp file.
- size_t get_hum_bytes(size_t* hum_bytes);
- void get_hum_bytes(size_t* used_bytes, size_t* capacity_bytes,
- size_t* prev_live_bytes, size_t* next_live_bytes);
-
public:
// The header and footer are printed in the constructor and
// destructor respectively.
--- a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -110,15 +110,9 @@
size_t const cur_plab_sz = (size_t)((double)total_waste_allowed / G1LastPLABAverageOccupancy);
// Take historical weighted average
_filter.sample(cur_plab_sz);
- // Clip from above and below, and align to object boundary
- size_t plab_sz;
- plab_sz = MAX2(min_size(), (size_t)_filter.average());
- plab_sz = MIN2(max_size(), plab_sz);
- plab_sz = align_object_size(plab_sz);
- // Latch the result
- _desired_net_plab_sz = plab_sz;
+ _desired_net_plab_sz = MAX2(min_size(), (size_t)_filter.average());
- log_sizing(cur_plab_sz, plab_sz);
+ log_sizing(cur_plab_sz, _desired_net_plab_sz);
// Clear accumulators for next round.
reset();
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1HeapSizingPolicy.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2016, 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/g1HeapSizingPolicy.hpp"
+#include "gc/g1/g1Analytics.hpp"
+#include "logging/log.hpp"
+#include "runtime/globals.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+G1HeapSizingPolicy::G1HeapSizingPolicy(const G1CollectedHeap* g1, const G1Analytics* analytics) :
+ _g1(g1),
+ _analytics(analytics),
+ _num_prev_pauses_for_heuristics(analytics->number_of_recorded_pause_times()) {
+ assert(MinOverThresholdForGrowth < _num_prev_pauses_for_heuristics, "Threshold must be less than %u", _num_prev_pauses_for_heuristics);
+ clear_ratio_check_data();
+ }
+
+void G1HeapSizingPolicy::clear_ratio_check_data() {
+ _ratio_over_threshold_count = 0;
+ _ratio_over_threshold_sum = 0.0;
+ _pauses_since_start = 0;
+}
+
+size_t G1HeapSizingPolicy::expansion_amount() {
+ double recent_gc_overhead = _analytics->recent_avg_pause_time_ratio() * 100.0;
+ double last_gc_overhead = _analytics->last_pause_time_ratio() * 100.0;
+ assert(GCTimeRatio > 0,
+ "we should have set it to a default value set_g1_gc_flags() "
+ "if a user set it to 0");
+ const double gc_overhead_perc = 100.0 * (1.0 / (1.0 + GCTimeRatio));
+
+ double threshold = gc_overhead_perc;
+ size_t expand_bytes = 0;
+
+ // If the heap is at less than half its maximum size, scale the threshold down,
+ // to a limit of 1. Thus the smaller the heap is, the more likely it is to expand,
+ // though the scaling code will likely keep the increase small.
+ if (_g1->capacity() <= _g1->max_capacity() / 2) {
+ threshold *= (double)_g1->capacity() / (double)(_g1->max_capacity() / 2);
+ threshold = MAX2(threshold, 1.0);
+ }
+
+ // If the last GC time ratio is over the threshold, increment the count of
+ // times it has been exceeded, and add this ratio to the sum of exceeded
+ // ratios.
+ if (last_gc_overhead > threshold) {
+ _ratio_over_threshold_count++;
+ _ratio_over_threshold_sum += last_gc_overhead;
+ }
+
+ // Check if we've had enough GC time ratio checks that were over the
+ // threshold to trigger an expansion. We'll also expand if we've
+ // reached the end of the history buffer and the average of all entries
+ // is still over the threshold. This indicates a smaller number of GCs were
+ // long enough to make the average exceed the threshold.
+ bool filled_history_buffer = _pauses_since_start == _num_prev_pauses_for_heuristics;
+ if ((_ratio_over_threshold_count == MinOverThresholdForGrowth) ||
+ (filled_history_buffer && (recent_gc_overhead > threshold))) {
+ size_t min_expand_bytes = HeapRegion::GrainBytes;
+ size_t reserved_bytes = _g1->max_capacity();
+ size_t committed_bytes = _g1->capacity();
+ size_t uncommitted_bytes = reserved_bytes - committed_bytes;
+ size_t expand_bytes_via_pct =
+ uncommitted_bytes * G1ExpandByPercentOfAvailable / 100;
+ double scale_factor = 1.0;
+
+ // If the current size is less than 1/4 of the Initial heap size, expand
+ // by half of the delta between the current and Initial sizes. IE, grow
+ // back quickly.
+ //
+ // Otherwise, take the current size, or G1ExpandByPercentOfAvailable % of
+ // the available expansion space, whichever is smaller, as the base
+ // expansion size. Then possibly scale this size according to how much the
+ // threshold has (on average) been exceeded by. If the delta is small
+ // (less than the StartScaleDownAt value), scale the size down linearly, but
+ // not by less than MinScaleDownFactor. If the delta is large (greater than
+ // the StartScaleUpAt value), scale up, but adding no more than MaxScaleUpFactor
+ // times the base size. The scaling will be linear in the range from
+ // StartScaleUpAt to (StartScaleUpAt + ScaleUpRange). In other words,
+ // ScaleUpRange sets the rate of scaling up.
+ if (committed_bytes < InitialHeapSize / 4) {
+ expand_bytes = (InitialHeapSize - committed_bytes) / 2;
+ } else {
+ double const MinScaleDownFactor = 0.2;
+ double const MaxScaleUpFactor = 2;
+ double const StartScaleDownAt = gc_overhead_perc;
+ double const StartScaleUpAt = gc_overhead_perc * 1.5;
+ double const ScaleUpRange = gc_overhead_perc * 2.0;
+
+ double ratio_delta;
+ if (filled_history_buffer) {
+ ratio_delta = recent_gc_overhead - threshold;
+ } else {
+ ratio_delta = (_ratio_over_threshold_sum/_ratio_over_threshold_count) - threshold;
+ }
+
+ expand_bytes = MIN2(expand_bytes_via_pct, committed_bytes);
+ if (ratio_delta < StartScaleDownAt) {
+ scale_factor = ratio_delta / StartScaleDownAt;
+ scale_factor = MAX2(scale_factor, MinScaleDownFactor);
+ } else if (ratio_delta > StartScaleUpAt) {
+ scale_factor = 1 + ((ratio_delta - StartScaleUpAt) / ScaleUpRange);
+ scale_factor = MIN2(scale_factor, MaxScaleUpFactor);
+ }
+ }
+
+ log_debug(gc, ergo, heap)("Attempt heap expansion (recent GC overhead higher than threshold after GC) "
+ "recent GC overhead: %1.2f %% threshold: %1.2f %% uncommitted: " SIZE_FORMAT "B base expansion amount and scale: " SIZE_FORMAT "B (%1.2f%%)",
+ recent_gc_overhead, threshold, uncommitted_bytes, expand_bytes, scale_factor * 100);
+
+ expand_bytes = static_cast<size_t>(expand_bytes * scale_factor);
+
+ // Ensure the expansion size is at least the minimum growth amount
+ // and at most the remaining uncommitted byte size.
+ expand_bytes = MAX2(expand_bytes, min_expand_bytes);
+ expand_bytes = MIN2(expand_bytes, uncommitted_bytes);
+
+ clear_ratio_check_data();
+ } else {
+ // An expansion was not triggered. If we've started counting, increment
+ // the number of checks we've made in the current window. If we've
+ // reached the end of the window without resizing, clear the counters to
+ // start again the next time we see a ratio above the threshold.
+ if (_ratio_over_threshold_count > 0) {
+ _pauses_since_start++;
+ if (_pauses_since_start > _num_prev_pauses_for_heuristics) {
+ clear_ratio_check_data();
+ }
+ }
+ }
+
+ return expand_bytes;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1HeapSizingPolicy.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, 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_G1_G1HEAPSIZINGPOLICY_HPP
+#define SHARE_VM_GC_G1_G1HEAPSIZINGPOLICY_HPP
+
+#include "memory/allocation.hpp"
+
+class G1Analytics;
+class G1CollectedHeap;
+
+class G1HeapSizingPolicy: public CHeapObj<mtGC> {
+ // MinOverThresholdForGrowth must be less than the number of recorded
+ // pause times in G1Analytics, representing the minimum number of pause
+ // time ratios that exceed GCTimeRatio before a heap expansion will be triggered.
+ const static uint MinOverThresholdForGrowth = 4;
+
+ const G1CollectedHeap* _g1;
+ const G1Analytics* _analytics;
+
+ const uint _num_prev_pauses_for_heuristics;
+ // Ratio check data for determining if heap growth is necessary.
+ uint _ratio_over_threshold_count;
+ double _ratio_over_threshold_sum;
+ uint _pauses_since_start;
+
+
+protected:
+ G1HeapSizingPolicy(const G1CollectedHeap* g1, const G1Analytics* analytics);
+public:
+
+ // If an expansion would be appropriate, because recent GC overhead had
+ // exceeded the desired limit, return an amount to expand by.
+ virtual size_t expansion_amount();
+
+ // Clear ratio tracking data used by expansion_amount().
+ void clear_ratio_check_data();
+
+ static G1HeapSizingPolicy* create(const G1CollectedHeap* g1, const G1Analytics* analytics);
+};
+
+#endif // SRC_SHARE_VM_GC_G1_G1HEAPSIZINGPOLICY_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1HeapSizingPolicy_ext.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016, 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/g1HeapSizingPolicy.hpp"
+
+G1HeapSizingPolicy* G1HeapSizingPolicy::create(const G1CollectedHeap* g1, const G1Analytics* analytics) {
+ return new G1HeapSizingPolicy(g1, analytics);
+}
--- a/hotspot/src/share/vm/gc/g1/g1HeapTransition.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1HeapTransition.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -82,8 +82,8 @@
void G1HeapTransition::print() {
Data after(_g1_heap);
- size_t eden_capacity_bytes_after_gc = _g1_heap->g1_policy()->young_list_target_length() - after._survivor_length;
- size_t survivor_capacity_bytes_after_gc = _g1_heap->g1_policy()->max_survivor_regions();
+ size_t eden_capacity_length_after_gc = _g1_heap->g1_policy()->young_list_target_length() - after._survivor_length;
+ size_t survivor_capacity_length_after_gc = _g1_heap->g1_policy()->max_survivor_regions();
DetailedUsage usage;
if (log_is_enabled(Trace, gc, heap)) {
@@ -100,11 +100,11 @@
}
log_info(gc, heap)("Eden regions: " SIZE_FORMAT "->" SIZE_FORMAT "(" SIZE_FORMAT ")",
- _before._eden_length, after._eden_length, eden_capacity_bytes_after_gc);
+ _before._eden_length, after._eden_length, eden_capacity_length_after_gc);
log_trace(gc, heap)(" Used: 0K, Waste: 0K");
log_info(gc, heap)("Survivor regions: " SIZE_FORMAT "->" SIZE_FORMAT "(" SIZE_FORMAT ")",
- _before._survivor_length, after._survivor_length, survivor_capacity_bytes_after_gc);
+ _before._survivor_length, after._survivor_length, survivor_capacity_length_after_gc);
log_trace(gc, heap)(" Used: " SIZE_FORMAT "K, Waste: " SIZE_FORMAT "K",
usage._survivor_used / K, ((after._survivor_length * HeapRegion::GrainBytes) - usage._survivor_used) / K);
--- a/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -36,7 +36,7 @@
_use_cache = true;
_hot_cache_size = (size_t)1 << G1ConcRSLogCacheSize;
- _hot_cache = _hot_cache_memory.allocate(_hot_cache_size);
+ _hot_cache = ArrayAllocator<jbyte*, mtGC>::allocate(_hot_cache_size);
reset_hot_cache_internal();
@@ -51,7 +51,7 @@
G1HotCardCache::~G1HotCardCache() {
if (default_use_cache()) {
assert(_hot_cache != NULL, "Logic");
- _hot_cache_memory.free();
+ ArrayAllocator<jbyte*, mtGC>::free(_hot_cache, _hot_cache_size);
_hot_cache = NULL;
}
}
--- a/hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1HotCardCache.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -61,7 +61,6 @@
G1CardCounts _card_counts;
- ArrayAllocator<jbyte*, mtGC> _hot_cache_memory;
// The card cache table
jbyte** _hot_cache;
--- a/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -122,7 +122,7 @@
void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading,
bool clear_all_softrefs) {
// Recursively traverse all live objects and mark them
- GCTraceTime(Trace, gc) tm("Phase 1: Mark live objects", gc_timer());
+ GCTraceTime(Info, gc, phases) tm("Phase 1: Mark live objects", gc_timer());
G1CollectedHeap* g1h = G1CollectedHeap::heap();
@@ -137,34 +137,49 @@
&follow_code_closure);
}
- // Process reference objects found during marking
- ReferenceProcessor* rp = GenMarkSweep::ref_processor();
- assert(rp == g1h->ref_processor_stw(), "Sanity");
+ {
+ GCTraceTime(Debug, gc, phases) trace("Reference Processing", gc_timer());
+
+ // Process reference objects found during marking
+ ReferenceProcessor* rp = GenMarkSweep::ref_processor();
+ assert(rp == g1h->ref_processor_stw(), "Sanity");
- rp->setup_policy(clear_all_softrefs);
- const ReferenceProcessorStats& stats =
- rp->process_discovered_references(&GenMarkSweep::is_alive,
- &GenMarkSweep::keep_alive,
- &GenMarkSweep::follow_stack_closure,
- NULL,
- gc_timer());
- gc_tracer()->report_gc_reference_stats(stats);
-
+ rp->setup_policy(clear_all_softrefs);
+ const ReferenceProcessorStats& stats =
+ rp->process_discovered_references(&GenMarkSweep::is_alive,
+ &GenMarkSweep::keep_alive,
+ &GenMarkSweep::follow_stack_closure,
+ NULL,
+ gc_timer());
+ gc_tracer()->report_gc_reference_stats(stats);
+ }
// This is the point where the entire marking should have completed.
assert(GenMarkSweep::_marking_stack.is_empty(), "Marking should have completed");
- // Unload classes and purge the SystemDictionary.
- bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive);
+ {
+ GCTraceTime(Debug, gc, phases) trace("Class Unloading", gc_timer());
- // Unload nmethods.
- CodeCache::do_unloading(&GenMarkSweep::is_alive, purged_class);
+ // Unload classes and purge the SystemDictionary.
+ bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive);
+
+ // Unload nmethods.
+ CodeCache::do_unloading(&GenMarkSweep::is_alive, purged_class);
- // Prune dead klasses from subklass/sibling/implementor lists.
- Klass::clean_weak_klass_links(&GenMarkSweep::is_alive);
+ // Prune dead klasses from subklass/sibling/implementor lists.
+ Klass::clean_weak_klass_links(&GenMarkSweep::is_alive);
+ }
- // Delete entries for dead interned string and clean up unreferenced symbols in symbol table.
- g1h->unlink_string_and_symbol_table(&GenMarkSweep::is_alive);
+ {
+ GCTraceTime(Debug, gc, phases) trace("Scrub String and Symbol Tables", gc_timer());
+ // Delete entries for dead interned string and clean up unreferenced symbols in symbol table.
+ g1h->unlink_string_and_symbol_table(&GenMarkSweep::is_alive);
+ }
+
+ if (G1StringDedup::is_enabled()) {
+ GCTraceTime(Debug, gc, phases) trace("String Deduplication Unlink", gc_timer());
+ G1StringDedup::unlink(&GenMarkSweep::is_alive);
+ }
if (VerifyDuringGC) {
HandleMark hm; // handle scope
@@ -197,7 +212,7 @@
// phase2, phase3 and phase4, but the ValidateMarkSweep live oops
// tracking expects us to do so. See comment under phase4.
- GCTraceTime(Trace, gc) tm("Phase 2: Compute new object addresses", gc_timer());
+ GCTraceTime(Info, gc, phases) tm("Phase 2: Compute new object addresses", gc_timer());
prepare_compaction();
}
@@ -220,17 +235,11 @@
}
};
-class G1AlwaysTrueClosure: public BoolObjectClosure {
-public:
- bool do_object_b(oop p) { return true; }
-};
-static G1AlwaysTrueClosure always_true;
-
void G1MarkSweep::mark_sweep_phase3() {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
// Adjust the pointers to reflect the new locations
- GCTraceTime(Trace, gc) tm("Phase 3: Adjust pointers", gc_timer());
+ GCTraceTime(Info, gc, phases) tm("Phase 3: Adjust pointers", gc_timer());
// Need cleared claim bits for the roots processing
ClassLoaderDataGraph::clear_claimed_marks();
@@ -248,7 +257,7 @@
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)
- JNIHandles::weak_oops_do(&always_true, &GenMarkSweep::adjust_pointer_closure);
+ JNIHandles::weak_oops_do(&GenMarkSweep::adjust_pointer_closure);
if (G1StringDedup::is_enabled()) {
G1StringDedup::oops_do(&GenMarkSweep::adjust_pointer_closure);
@@ -291,7 +300,7 @@
// to use a higher index (saved from phase2) when verifying perm_gen.
G1CollectedHeap* g1h = G1CollectedHeap::heap();
- GCTraceTime(Trace, gc) tm("Phase 4: Move objects", gc_timer());
+ GCTraceTime(Info, gc, phases) tm("Phase 4: Move objects", gc_timer());
G1SpaceCompactClosure blk;
g1h->heap_region_iterate(&blk);
--- a/hotspot/src/share/vm/gc/g1/g1MonitoringSupport.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1MonitoringSupport.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, 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
@@ -178,7 +178,7 @@
// of a GC).
uint young_list_length = g1->young_list()->length();
- uint survivor_list_length = g1->g1_policy()->recorded_survivor_regions();
+ uint survivor_list_length = g1->young_list()->survivor_length();
assert(young_list_length >= survivor_list_length, "invariant");
uint eden_list_length = young_list_length - survivor_list_length;
// Max length includes any potential extensions to the young gen
--- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "gc/g1/g1Allocator.inline.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1CollectionSet.hpp"
#include "gc/g1/g1OopClosures.inline.hpp"
#include "gc/g1/g1ParScanThreadState.inline.hpp"
#include "gc/g1/g1RootClosures.hpp"
@@ -80,7 +81,7 @@
_plab_allocator->flush_and_retire_stats();
_g1h->g1_policy()->record_age_table(&_age_table);
- uint length = _g1h->g1_policy()->young_cset_region_length();
+ uint length = _g1h->collection_set()->young_region_length();
for (uint region_index = 0; region_index < length; region_index++) {
surviving_young_words[region_index] += _surviving_young_words[region_index];
}
--- a/hotspot/src/share/vm/gc/g1/g1StringDedup.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedup.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, 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
@@ -47,7 +47,7 @@
void G1StringDedup::stop() {
assert(is_enabled(), "String deduplication not enabled");
- G1StringDedupThread::stop();
+ G1StringDedupThread::thread()->stop();
}
bool G1StringDedup::is_candidate_from_mark(oop obj) {
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, 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
@@ -81,11 +81,9 @@
StringTable::shared_oops_do(&sharedStringDedup);
}
-void G1StringDedupThread::run() {
+void G1StringDedupThread::run_service() {
G1StringDedupStat total_stat;
- initialize_in_thread();
- wait_for_universe_init();
deduplicate_shared_strings(total_stat);
// Main loop
@@ -96,7 +94,7 @@
// Wait for the queue to become non-empty
G1StringDedupQueue::wait();
- if (_should_terminate) {
+ if (should_terminate()) {
break;
}
@@ -133,23 +131,10 @@
}
}
- terminate();
}
-void G1StringDedupThread::stop() {
- {
- MonitorLockerEx ml(Terminator_lock);
- _thread->_should_terminate = true;
- }
-
+void G1StringDedupThread::stop_service() {
G1StringDedupQueue::cancel_wait();
-
- {
- MonitorLockerEx ml(Terminator_lock);
- while (!_thread->_has_terminated) {
- ml.wait();
- }
- }
}
void G1StringDedupThread::print(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, 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
@@ -45,14 +45,14 @@
void print(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
+ void run_service();
+ void stop_service();
+
public:
static void create();
- static void stop();
static G1StringDedupThread* thread();
- virtual void run();
-
void deduplicate_shared_strings(G1StringDedupStat& stat);
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1YoungGenSizer.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016, 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/g1YoungGenSizer.hpp"
+#include "gc/g1/heapRegion.hpp"
+
+G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true),
+ _min_desired_young_length(0), _max_desired_young_length(0) {
+ if (FLAG_IS_CMDLINE(NewRatio)) {
+ if (FLAG_IS_CMDLINE(NewSize) || FLAG_IS_CMDLINE(MaxNewSize)) {
+ warning("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio");
+ } else {
+ _sizer_kind = SizerNewRatio;
+ _adaptive_size = false;
+ return;
+ }
+ }
+
+ if (NewSize > MaxNewSize) {
+ if (FLAG_IS_CMDLINE(MaxNewSize)) {
+ warning("NewSize (" SIZE_FORMAT "k) is greater than the MaxNewSize (" SIZE_FORMAT "k). "
+ "A new max generation size of " SIZE_FORMAT "k will be used.",
+ NewSize/K, MaxNewSize/K, NewSize/K);
+ }
+ MaxNewSize = NewSize;
+ }
+
+ if (FLAG_IS_CMDLINE(NewSize)) {
+ _min_desired_young_length = MAX2((uint) (NewSize / HeapRegion::GrainBytes),
+ 1U);
+ if (FLAG_IS_CMDLINE(MaxNewSize)) {
+ _max_desired_young_length =
+ MAX2((uint) (MaxNewSize / HeapRegion::GrainBytes),
+ 1U);
+ _sizer_kind = SizerMaxAndNewSize;
+ _adaptive_size = _min_desired_young_length == _max_desired_young_length;
+ } else {
+ _sizer_kind = SizerNewSizeOnly;
+ }
+ } else if (FLAG_IS_CMDLINE(MaxNewSize)) {
+ _max_desired_young_length =
+ MAX2((uint) (MaxNewSize / HeapRegion::GrainBytes),
+ 1U);
+ _sizer_kind = SizerMaxNewSizeOnly;
+ }
+}
+
+uint G1YoungGenSizer::calculate_default_min_length(uint new_number_of_heap_regions) {
+ uint default_value = (new_number_of_heap_regions * G1NewSizePercent) / 100;
+ return MAX2(1U, default_value);
+}
+
+uint G1YoungGenSizer::calculate_default_max_length(uint new_number_of_heap_regions) {
+ uint default_value = (new_number_of_heap_regions * G1MaxNewSizePercent) / 100;
+ return MAX2(1U, default_value);
+}
+
+void G1YoungGenSizer::recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length) {
+ assert(number_of_heap_regions > 0, "Heap must be initialized");
+
+ switch (_sizer_kind) {
+ case SizerDefaults:
+ *min_young_length = calculate_default_min_length(number_of_heap_regions);
+ *max_young_length = calculate_default_max_length(number_of_heap_regions);
+ break;
+ case SizerNewSizeOnly:
+ *max_young_length = calculate_default_max_length(number_of_heap_regions);
+ *max_young_length = MAX2(*min_young_length, *max_young_length);
+ break;
+ case SizerMaxNewSizeOnly:
+ *min_young_length = calculate_default_min_length(number_of_heap_regions);
+ *min_young_length = MIN2(*min_young_length, *max_young_length);
+ break;
+ case SizerMaxAndNewSize:
+ // Do nothing. Values set on the command line, don't update them at runtime.
+ break;
+ case SizerNewRatio:
+ *min_young_length = number_of_heap_regions / (NewRatio + 1);
+ *max_young_length = *min_young_length;
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+
+ assert(*min_young_length <= *max_young_length, "Invalid min/max young gen size values");
+}
+
+uint G1YoungGenSizer::max_young_length(uint number_of_heap_regions) {
+ // We need to pass the desired values because recalculation may not update these
+ // values in some cases.
+ uint temp = _min_desired_young_length;
+ uint result = _max_desired_young_length;
+ recalculate_min_max_young_length(number_of_heap_regions, &temp, &result);
+ return result;
+}
+
+void G1YoungGenSizer::heap_size_changed(uint new_number_of_heap_regions) {
+ recalculate_min_max_young_length(new_number_of_heap_regions, &_min_desired_young_length,
+ &_max_desired_young_length);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1YoungGenSizer.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2016, 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"
+
+// There are three command line options related to the young gen size:
+// NewSize, MaxNewSize and NewRatio (There is also -Xmn, but that is
+// just a short form for NewSize==MaxNewSize). G1 will use its internal
+// heuristics to calculate the actual young gen size, so these options
+// basically only limit the range within which G1 can pick a young gen
+// size. Also, these are general options taking byte sizes. G1 will
+// internally work with a number of regions instead. So, some rounding
+// will occur.
+//
+// If nothing related to the the young gen size is set on the command
+// line we should allow the young gen to be between G1NewSizePercent
+// and G1MaxNewSizePercent of the heap size. This means that every time
+// the heap size changes, the limits for the young gen size will be
+// recalculated.
+//
+// If only -XX:NewSize is set we should use the specified value as the
+// minimum size for young gen. Still using G1MaxNewSizePercent of the
+// heap as maximum.
+//
+// If only -XX:MaxNewSize is set we should use the specified value as the
+// maximum size for young gen. Still using G1NewSizePercent of the heap
+// as minimum.
+//
+// If -XX:NewSize and -XX:MaxNewSize are both specified we use these values.
+// No updates when the heap size changes. There is a special case when
+// NewSize==MaxNewSize. This is interpreted as "fixed" and will use a
+// different heuristic for calculating the collection set when we do mixed
+// collection.
+//
+// If only -XX:NewRatio is set we should use the specified ratio of the heap
+// as both min and max. This will be interpreted as "fixed" just like the
+// NewSize==MaxNewSize case above. But we will update the min and max
+// every time the heap size changes.
+//
+// NewSize and MaxNewSize override NewRatio. So, NewRatio is ignored if it is
+// combined with either NewSize or MaxNewSize. (A warning message is printed.)
+class G1YoungGenSizer : public CHeapObj<mtGC> {
+private:
+ enum SizerKind {
+ SizerDefaults,
+ SizerNewSizeOnly,
+ SizerMaxNewSizeOnly,
+ SizerMaxAndNewSize,
+ SizerNewRatio
+ };
+ SizerKind _sizer_kind;
+ uint _min_desired_young_length;
+ uint _max_desired_young_length;
+ bool _adaptive_size;
+ uint calculate_default_min_length(uint new_number_of_heap_regions);
+ uint calculate_default_max_length(uint new_number_of_heap_regions);
+
+ // Update the given values for minimum and maximum young gen length in regions
+ // given the number of heap regions depending on the kind of sizing algorithm.
+ void recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length);
+
+public:
+ G1YoungGenSizer();
+ // Calculate the maximum length of the young gen given the number of regions
+ // depending on the sizing algorithm.
+ uint max_young_length(uint number_of_heap_regions);
+
+ void heap_size_changed(uint new_number_of_heap_regions);
+ uint min_desired_young_length() {
+ return _min_desired_young_length;
+ }
+ uint max_desired_young_length() {
+ return _max_desired_young_length;
+ }
+
+ bool adaptive_young_list_length() const {
+ return _adaptive_size;
+ }
+};
+
--- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -25,38 +25,13 @@
#include "precompiled.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectorPolicy.hpp"
+#include "gc/g1/g1CollectionSet.hpp"
#include "gc/g1/g1YoungRemSetSamplingThread.hpp"
#include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
#include "gc/g1/suspendibleThreadSet.hpp"
#include "runtime/mutexLocker.hpp"
-void G1YoungRemSetSamplingThread::run() {
- initialize_in_thread();
- wait_for_universe_init();
-
- run_service();
-
- terminate();
-}
-
-void G1YoungRemSetSamplingThread::stop() {
- // it is ok to take late safepoints here, if needed
- {
- MutexLockerEx mu(Terminator_lock);
- _should_terminate = true;
- }
-
- stop_service();
-
- {
- MutexLockerEx mu(Terminator_lock);
- while (!_has_terminated) {
- Terminator_lock->wait();
- }
- }
-}
-
G1YoungRemSetSamplingThread::G1YoungRemSetSamplingThread() :
ConcurrentGCThread(),
_monitor(Mutex::nonleaf,
@@ -69,7 +44,7 @@
void G1YoungRemSetSamplingThread::sleep_before_next_cycle() {
MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag);
- if (!_should_terminate) {
+ if (!should_terminate()) {
uintx waitms = G1ConcRefinementServiceIntervalMillis; // 300, really should be?
_monitor.wait(Mutex::_no_safepoint_check_flag, waitms);
}
@@ -78,7 +53,7 @@
void G1YoungRemSetSamplingThread::run_service() {
double vtime_start = os::elapsedVTime();
- while (!_should_terminate) {
+ while (!should_terminate()) {
sample_young_list_rs_lengths();
if (os::supports_vtime()) {
@@ -114,7 +89,7 @@
// retired as the current allocation region).
if (hr->in_collection_set()) {
// Update the collection set policy information for this region
- g1p->update_incremental_cset_info(hr, rs_length);
+ g1h->collection_set()->update_young_region_prediction(hr, rs_length);
}
++regions_visited;
--- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -55,9 +55,6 @@
public:
G1YoungRemSetSamplingThread();
double vtime_accum() { return _vtime_accum; }
-
- virtual void run();
- void stop();
};
#endif // SHARE_VM_GC_G1_G1YOUNGREMSETSAMPLINGTHREAD_HPP
--- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -233,10 +233,6 @@
"Raise a fatal VM exit out of memory failure in the event " \
" that heap expansion fails due to running out of swap.") \
\
- develop(uintx, G1ConcMarkForceOverflow, 0, \
- "The number of times we'll force an overflow during " \
- "concurrent marking") \
- \
experimental(uintx, G1MaxNewSizePercent, 60, \
"Percentage (0-100) of the heap size to use as default " \
" maximum young gen size.") \
--- a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -43,16 +43,12 @@
void PtrQueue::flush_impl() {
if (!_permanent && _buf != NULL) {
- if (_index == _sz) {
+ BufferNode* node = BufferNode::make_node_from_buffer(_buf, _index);
+ if (is_empty()) {
// No work to do.
- qset()->deallocate_buffer(_buf);
+ qset()->deallocate_buffer(node);
} else {
- // We must NULL out the unused entries, then enqueue.
- size_t limit = byte_index_to_index(_index);
- for (size_t i = 0; i < limit; ++i) {
- _buf[i] = NULL;
- }
- qset()->enqueue_complete_buffer(_buf);
+ qset()->enqueue_complete_buffer(node);
}
_buf = NULL;
_index = 0;
@@ -74,7 +70,7 @@
assert(_index <= _sz, "Invariant.");
}
-void PtrQueue::locking_enqueue_completed_buffer(void** buf) {
+void PtrQueue::locking_enqueue_completed_buffer(BufferNode* node) {
assert(_lock->owned_by_self(), "Required.");
// We have to unlock _lock (which may be Shared_DirtyCardQ_lock) before
@@ -82,7 +78,7 @@
// have the same rank and we may get the "possible deadlock" message
_lock->unlock();
- qset()->enqueue_complete_buffer(buf);
+ qset()->enqueue_complete_buffer(node);
// We must relock only because the caller will unlock, for the normal
// case.
_lock->lock_without_safepoint_check();
@@ -157,10 +153,9 @@
return BufferNode::make_buffer_from_node(node);
}
-void PtrQueueSet::deallocate_buffer(void** buf) {
+void PtrQueueSet::deallocate_buffer(BufferNode* node) {
assert(_sz > 0, "Didn't set a buffer size.");
MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
- BufferNode *node = BufferNode::make_node_from_buffer(buf);
node->set_next(_fl_owner->_buf_free_list);
_fl_owner->_buf_free_list = node;
_fl_owner->_buf_free_list_sz++;
@@ -211,10 +206,10 @@
// preventing the subsequent the multiple enqueue, and
// install a newly allocated buffer below.
- void** buf = _buf; // local pointer to completed buffer
+ BufferNode* node = BufferNode::make_node_from_buffer(_buf, _index);
_buf = NULL; // clear shared _buf field
- locking_enqueue_completed_buffer(buf); // enqueue completed buffer
+ locking_enqueue_completed_buffer(node); // enqueue completed buffer
// While the current thread was enqueueing the buffer another thread
// may have a allocated a new buffer and inserted it into this pointer
@@ -224,9 +219,11 @@
if (_buf != NULL) return;
} else {
- if (qset()->process_or_enqueue_complete_buffer(_buf)) {
+ BufferNode* node = BufferNode::make_node_from_buffer(_buf, _index);
+ if (qset()->process_or_enqueue_complete_buffer(node)) {
// Recycle the buffer. No allocation.
- _sz = qset()->buffer_size();
+ assert(_buf == BufferNode::make_buffer_from_node(node), "invariant");
+ assert(_sz == qset()->buffer_size(), "invariant");
_index = _sz;
return;
}
@@ -238,12 +235,12 @@
_index = _sz;
}
-bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) {
+bool PtrQueueSet::process_or_enqueue_complete_buffer(BufferNode* node) {
if (Thread::current()->is_Java_thread()) {
// We don't lock. It is fine to be epsilon-precise here.
if (_max_completed_queue == 0 || _max_completed_queue > 0 &&
_n_completed_buffers >= _max_completed_queue + _completed_queue_padding) {
- bool b = mut_process_buffer(buf);
+ bool b = mut_process_buffer(node);
if (b) {
// True here means that the buffer hasn't been deallocated and the caller may reuse it.
return true;
@@ -251,14 +248,12 @@
}
}
// The buffer will be enqueued. The caller will have to get a new one.
- enqueue_complete_buffer(buf);
+ enqueue_complete_buffer(node);
return false;
}
-void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) {
+void PtrQueueSet::enqueue_complete_buffer(BufferNode* cbn) {
MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
- BufferNode* cbn = BufferNode::make_node_from_buffer(buf);
- cbn->set_index(index);
cbn->set_next(NULL);
if (_completed_buffers_tail == NULL) {
assert(_completed_buffers_head == NULL, "Well-formedness");
--- a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -33,6 +33,7 @@
// the addresses of modified old-generation objects. This type supports
// this operation.
+class BufferNode;
class PtrQueueSet;
class PtrQueue VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
@@ -104,7 +105,7 @@
// get into an infinite loop).
virtual bool should_enqueue_buffer() { return true; }
void handle_zero_index();
- void locking_enqueue_completed_buffer(void** buf);
+ void locking_enqueue_completed_buffer(BufferNode* node);
void enqueue_known_active(void* ptr);
@@ -136,6 +137,10 @@
return ind / sizeof(void*);
}
+ static size_t index_to_byte_index(size_t ind) {
+ return ind * sizeof(void*);
+ }
+
// To support compiler.
protected:
@@ -186,10 +191,13 @@
// Free a BufferNode.
static void deallocate(BufferNode* node);
- // Return the BufferNode containing the buffer.
- static BufferNode* make_node_from_buffer(void** buffer) {
- return reinterpret_cast<BufferNode*>(
- reinterpret_cast<char*>(buffer) - buffer_offset());
+ // Return the BufferNode containing the buffer, after setting its index.
+ static BufferNode* make_node_from_buffer(void** buffer, size_t index) {
+ BufferNode* node =
+ reinterpret_cast<BufferNode*>(
+ reinterpret_cast<char*>(buffer) - buffer_offset());
+ node->set_index(index);
+ return node;
}
// Return the buffer for node.
@@ -243,7 +251,7 @@
// A mutator thread does the the work of processing a buffer.
// Returns "true" iff the work is complete (and the buffer may be
// deallocated).
- virtual bool mut_process_buffer(void** buf) {
+ virtual bool mut_process_buffer(BufferNode* node) {
ShouldNotReachHere();
return false;
}
@@ -267,13 +275,13 @@
// Return an empty buffer to the free list. The "buf" argument is
// required to be a pointer to the head of an array of length "_sz".
- void deallocate_buffer(void** buf);
+ void deallocate_buffer(BufferNode* node);
// Declares that "buf" is a complete buffer.
- void enqueue_complete_buffer(void** buf, size_t index = 0);
+ void enqueue_complete_buffer(BufferNode* node);
// To be invoked by the mutator.
- bool process_or_enqueue_complete_buffer(void** buf);
+ bool process_or_enqueue_complete_buffer(BufferNode* node);
bool completed_buffers_exist_dirty() {
return _n_completed_buffers > 0;
--- a/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/satbMarkQueue.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -100,6 +100,10 @@
return true;
}
+inline bool retain_entry(const void* entry, G1CollectedHeap* heap) {
+ return requires_marking(entry, heap) && !heap->isMarkedNext((oop)entry);
+}
+
// This method removes entries from a SATB buffer that will not be
// useful to the concurrent marking threads. Entries are retained if
// they require marking and are not already marked. Retained entries
@@ -114,43 +118,28 @@
return;
}
- // Used for sanity checking at the end of the loop.
- DEBUG_ONLY(size_t entries = 0; size_t retained = 0;)
+ assert(_index <= _sz, "invariant");
- assert(_index <= _sz, "invariant");
- void** limit = &buf[byte_index_to_index(_index)];
- void** src = &buf[byte_index_to_index(_sz)];
- void** dst = src;
-
- while (limit < src) {
- DEBUG_ONLY(entries += 1;)
- --src;
+ // Two-fingered compaction toward the end.
+ void** src = &buf[byte_index_to_index(_index)];
+ void** dst = &buf[byte_index_to_index(_sz)];
+ for ( ; src < dst; ++src) {
+ // Search low to high for an entry to keep.
void* entry = *src;
- // NULL the entry so that unused parts of the buffer contain NULLs
- // at the end. If we are going to retain it we will copy it to its
- // final place. If we have retained all entries we have visited so
- // far, we'll just end up copying it to the same place.
- *src = NULL;
-
- if (requires_marking(entry, g1h) && !g1h->isMarkedNext((oop)entry)) {
- --dst;
- assert(*dst == NULL, "filtering destination should be clear");
- *dst = entry;
- DEBUG_ONLY(retained += 1;);
+ if (retain_entry(entry, g1h)) {
+ // Found keeper. Search high to low for an entry to discard.
+ while (src < --dst) {
+ if (!retain_entry(*dst, g1h)) {
+ *dst = entry; // Replace discard with keeper.
+ break;
+ }
+ }
+ // If discard search failed (src == dst), the outer loop will also end.
}
}
- size_t new_index = pointer_delta(dst, buf, 1);
-
-#ifdef ASSERT
- size_t entries_calc = (_sz - _index) / sizeof(void*);
- assert(entries == entries_calc, "the number of entries we counted "
- "should match the number of entries we calculated");
- size_t retained_calc = (_sz - new_index) / sizeof(void*);
- assert(retained == retained_calc, "the number of retained entries we counted "
- "should match the number of retained entries we calculated");
-#endif // ASSERT
-
- _index = new_index;
+ // dst points to the lowest retained entry, or the end of the buffer
+ // if all the entries were filtered out.
+ _index = pointer_delta(dst, buf, 1);
}
// This method will first apply the above filtering to the buffer. If
@@ -286,19 +275,11 @@
}
if (nd != NULL) {
void **buf = BufferNode::make_buffer_from_node(nd);
- // Skip over NULL entries at beginning (e.g. push end) of buffer.
- // Filtering can result in non-full completed buffers; see
- // should_enqueue_buffer.
- assert(_sz % sizeof(void*) == 0, "invariant");
- size_t limit = SATBMarkQueue::byte_index_to_index(_sz);
- for (size_t i = 0; i < limit; ++i) {
- if (buf[i] != NULL) {
- // Found the end of the block of NULLs; process the remainder.
- cl->do_buffer(buf + i, limit - i);
- break;
- }
- }
- deallocate_buffer(buf);
+ size_t index = SATBMarkQueue::byte_index_to_index(nd->index());
+ size_t size = SATBMarkQueue::byte_index_to_index(_sz);
+ assert(index <= size, "invariant");
+ cl->do_buffer(buf + index, size - index);
+ deallocate_buffer(nd);
return true;
} else {
return false;
@@ -355,7 +336,7 @@
while (buffers_to_delete != NULL) {
BufferNode* nd = buffers_to_delete;
buffers_to_delete = nd->next();
- deallocate_buffer(BufferNode::make_buffer_from_node(nd));
+ deallocate_buffer(nd);
}
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
// So we can safely manipulate these queues.
--- a/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/satbMarkQueue.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -115,9 +115,8 @@
// If there exists some completed buffer, pop and process it, and
// return true. Otherwise return false. Processing a buffer
- // consists of applying the closure to the buffer range starting
- // with the first non-NULL entry to the end of the buffer; the
- // leading entries may be NULL due to filtering.
+ // consists of applying the closure to the active range of the
+ // buffer; the leading entries may be excluded due to filtering.
bool apply_closure_to_completed_buffer(SATBBufferClosure* cl);
#ifndef PRODUCT
--- a/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/vm_operations_g1.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -205,30 +205,18 @@
}
void VM_CGC_Operation::acquire_pending_list_lock() {
- assert(_needs_pll, "don't call this otherwise");
- // The caller may block while communicating
- // with the SLT thread in order to acquire/release the PLL.
- SurrogateLockerThread* slt = ConcurrentMarkThread::slt();
- if (slt != NULL) {
- slt->manipulatePLL(SurrogateLockerThread::acquirePLL);
- } else {
- SurrogateLockerThread::report_missing_slt();
- }
+ _pending_list_locker.lock();
}
void VM_CGC_Operation::release_and_notify_pending_list_lock() {
- assert(_needs_pll, "don't call this otherwise");
- // The caller may block while communicating
- // with the SLT thread in order to acquire/release the PLL.
- ConcurrentMarkThread::slt()->
- manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL);
+ _pending_list_locker.unlock();
}
void VM_CGC_Operation::doit() {
GCIdMark gc_id_mark(_gc_id);
GCTraceCPUTime tcpu;
G1CollectedHeap* g1h = G1CollectedHeap::heap();
- GCTraceTime(Info, gc) t(_printGCMessage, g1h->gc_timer_cm(), GCCause::_no_gc, true);
+ GCTraceTime(Info, gc) t(_printGCMessage, g1h->concurrent_mark()->gc_timer_cm(), GCCause::_no_gc, true);
IsGCActiveMark x;
_cl->do_void();
}
@@ -236,10 +224,9 @@
bool VM_CGC_Operation::doit_prologue() {
// Note the relative order of the locks must match that in
// VM_GC_Operation::doit_prologue() or deadlocks can occur
- if (_needs_pll) {
+ if (_needs_pending_list_lock) {
acquire_pending_list_lock();
}
-
Heap_lock->lock();
return true;
}
@@ -248,7 +235,7 @@
// Note the relative order of the unlocks must match that in
// VM_GC_Operation::doit_epilogue()
Heap_lock->unlock();
- if (_needs_pll) {
+ if (_needs_pending_list_lock) {
release_and_notify_pending_list_lock();
}
}
--- a/hotspot/src/share/vm/gc/g1/vm_operations_g1.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/vm_operations_g1.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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,7 @@
#include "gc/g1/g1AllocationContext.hpp"
#include "gc/shared/gcId.hpp"
+#include "gc/shared/referencePendingListLocker.hpp"
#include "gc/shared/vmGCOperations.hpp"
// VM_operations for the G1 collector.
@@ -102,10 +103,11 @@
// Concurrent GC stop-the-world operations such as remark and cleanup;
// consider sharing these with CMS's counterparts.
class VM_CGC_Operation: public VM_Operation {
- VoidClosure* _cl;
- const char* _printGCMessage;
- bool _needs_pll;
- uint _gc_id;
+ VoidClosure* _cl;
+ const char* _printGCMessage;
+ bool _needs_pending_list_lock;
+ ReferencePendingListLocker _pending_list_locker;
+ uint _gc_id;
protected:
// java.lang.ref.Reference support
@@ -113,8 +115,8 @@
void release_and_notify_pending_list_lock();
public:
- VM_CGC_Operation(VoidClosure* cl, const char *printGCMsg, bool needs_pll)
- : _cl(cl), _printGCMessage(printGCMsg), _needs_pll(needs_pll), _gc_id(GCId::current()) { }
+ VM_CGC_Operation(VoidClosure* cl, const char *printGCMsg, bool needs_pending_list_lock)
+ : _cl(cl), _printGCMessage(printGCMsg), _needs_pending_list_lock(needs_pending_list_lock), _gc_id(GCId::current()) {}
virtual VMOp_Type type() const { return VMOp_CGC_Operation; }
virtual void doit();
virtual bool doit_prologue();
--- a/hotspot/src/share/vm/gc/g1/youngList.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/youngList.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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,6 +24,7 @@
#include "precompiled.hpp"
#include "gc/g1/g1CollectedHeap.hpp"
+#include "gc/g1/g1CollectionSet.hpp"
#include "gc/g1/g1CollectorPolicy.hpp"
#include "gc/g1/heapRegion.hpp"
#include "gc/g1/heapRegion.inline.hpp"
@@ -153,7 +154,7 @@
// The region is a non-empty survivor so let's add it to
// the incremental collection set for the next evacuation
// pause.
- _g1h->g1_policy()->add_region_to_incremental_cset_rhs(curr);
+ _g1h->collection_set()->add_survivor_regions(curr);
young_index_in_cset += 1;
}
assert((uint) young_index_in_cset == _survivor_length, "post-condition");
--- a/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, 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
@@ -113,8 +113,8 @@
}
if (!os::bind_to_processor(processor_id())) {
DEBUG_ONLY(
- warning("Couldn't bind GCTaskThread %u to processor %u",
- which(), processor_id());
+ log_warning(gc)("Couldn't bind GCTaskThread %u to processor %u",
+ which(), processor_id());
)
}
}
--- a/hotspot/src/share/vm/gc/parallel/mutableSpace.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/mutableSpace.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -58,7 +58,7 @@
}
void MutableSpace::pretouch_pages(MemRegion mr) {
- os::pretouch_memory((char*)mr.start(), (char*)mr.end());
+ os::pretouch_memory(mr.start(), mr.end());
}
void MutableSpace::initialize(MemRegion mr,
--- a/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -325,8 +325,8 @@
loop_count++;
if ((result == NULL) && (QueuedAllocationWarningCount > 0) &&
(loop_count % QueuedAllocationWarningCount == 0)) {
- warning("ParallelScavengeHeap::mem_allocate retries %d times \n\t"
- " size=" SIZE_FORMAT, loop_count, size);
+ log_warning(gc)("ParallelScavengeHeap::mem_allocate retries %d times", loop_count);
+ log_warning(gc)("\tsize=" SIZE_FORMAT, size);
}
}
--- a/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -493,7 +493,7 @@
void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
// Recursively traverse all live objects and mark them
- GCTraceTime(Trace, gc) tm("Phase 1: Mark live objects", _gc_timer);
+ GCTraceTime(Info, gc, phases) tm("Phase 1: Mark live objects", _gc_timer);
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
@@ -523,6 +523,8 @@
// Process reference objects found during marking
{
+ GCTraceTime(Debug, gc, phases) t("Reference Processing", _gc_timer);
+
ref_processor()->setup_policy(clear_all_softrefs);
const ReferenceProcessorStats& stats =
ref_processor()->process_discovered_references(
@@ -533,26 +535,37 @@
// This is the point where the entire marking should have completed.
assert(_marking_stack.is_empty(), "Marking should have completed");
- // Unload classes and purge the SystemDictionary.
- bool purged_class = SystemDictionary::do_unloading(is_alive_closure());
+ {
+ GCTraceTime(Debug, gc, phases) t("Class Unloading", _gc_timer);
+
+ // Unload classes and purge the SystemDictionary.
+ bool purged_class = SystemDictionary::do_unloading(is_alive_closure());
- // Unload nmethods.
- CodeCache::do_unloading(is_alive_closure(), purged_class);
+ // Unload nmethods.
+ CodeCache::do_unloading(is_alive_closure(), purged_class);
+
+ // Prune dead klasses from subklass/sibling/implementor lists.
+ Klass::clean_weak_klass_links(is_alive_closure());
+ }
- // Prune dead klasses from subklass/sibling/implementor lists.
- Klass::clean_weak_klass_links(is_alive_closure());
+ {
+ GCTraceTime(Debug, gc, phases) t("Scrub String Table", _gc_timer);
+ // Delete entries for dead interned strings.
+ StringTable::unlink(is_alive_closure());
+ }
- // Delete entries for dead interned strings.
- StringTable::unlink(is_alive_closure());
+ {
+ GCTraceTime(Debug, gc, phases) t("Scrub Symbol Table", _gc_timer);
+ // Clean up unreferenced symbols in symbol table.
+ SymbolTable::unlink();
+ }
- // Clean up unreferenced symbols in symbol table.
- SymbolTable::unlink();
_gc_tracer->report_object_count_after_gc(is_alive_closure());
}
void PSMarkSweep::mark_sweep_phase2() {
- GCTraceTime(Trace, gc) tm("Phase 2: Compute new object addresses", _gc_timer);
+ GCTraceTime(Info, gc, phases) tm("Phase 2: Compute new object addresses", _gc_timer);
// Now all live objects are marked, compute the new object addresses.
@@ -570,16 +583,9 @@
old_gen->precompact();
}
-// This should be moved to the shared markSweep code!
-class PSAlwaysTrueClosure: public BoolObjectClosure {
-public:
- bool do_object_b(oop p) { return true; }
-};
-static PSAlwaysTrueClosure always_true;
-
void PSMarkSweep::mark_sweep_phase3() {
// Adjust the pointers to reflect the new locations
- GCTraceTime(Trace, gc) tm("Phase 3: Adjust pointers", _gc_timer);
+ GCTraceTime(Info, gc, phases) tm("Phase 3: Adjust pointers", _gc_timer);
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
PSYoungGen* young_gen = heap->young_gen();
@@ -603,7 +609,7 @@
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)
// Global (weak) JNI handles
- JNIHandles::weak_oops_do(&always_true, adjust_pointer_closure());
+ JNIHandles::weak_oops_do(adjust_pointer_closure());
CodeBlobToOopClosure adjust_from_blobs(adjust_pointer_closure(), CodeBlobToOopClosure::FixRelocations);
CodeCache::blobs_do(&adjust_from_blobs);
@@ -619,7 +625,7 @@
void PSMarkSweep::mark_sweep_phase4() {
EventMark m("4 compact heap");
- GCTraceTime(Trace, gc) tm("Phase 4: Move objects", _gc_timer);
+ GCTraceTime(Info, gc, phases) tm("Phase 4: Move objects", _gc_timer);
// All pointers are now adjusted, move objects accordingly
@@ -638,7 +644,7 @@
jlong ret_val = now - _time_of_last_gc;
// XXX See note in genCollectedHeap::millis_since_last_gc().
if (ret_val < 0) {
- NOT_PRODUCT(warning("time warp: " JLONG_FORMAT, ret_val);)
+ NOT_PRODUCT(log_warning(gc)("time warp: " JLONG_FORMAT, ret_val);)
return 0;
}
return ret_val;
--- a/hotspot/src/share/vm/gc/parallel/psOldGen.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psOldGen.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -309,7 +309,7 @@
const size_t remaining_bytes = virtual_space()->uncommitted_size();
if (remaining_bytes > 0) {
result = expand_by(remaining_bytes);
- DEBUG_ONLY(if (!result) warning("grow to reserve failed"));
+ DEBUG_ONLY(if (!result) log_warning(gc)("grow to reserve failed"));
}
return result;
}
--- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -195,10 +195,10 @@
};
void PSParallelCompact::print_region_ranges() {
- if (!log_develop_is_enabled(Trace, gc, compaction, phases)) {
+ if (!log_develop_is_enabled(Trace, gc, compaction)) {
return;
}
- LogHandle(gc, compaction, phases) log;
+ LogHandle(gc, compaction) log;
ResourceMark rm;
Universe::print_on(log.trace_stream());
log.trace("space bottom top end new_top");
@@ -225,7 +225,7 @@
ParallelCompactData& sd = PSParallelCompact::summary_data();
size_t dci = c->destination() ? sd.addr_to_region_idx(c->destination()) : 0;
- log_develop_trace(gc, compaction, phases)(
+ log_develop_trace(gc, compaction)(
REGION_IDX_FORMAT " " PTR_FORMAT " "
REGION_IDX_FORMAT " " PTR_FORMAT " "
REGION_DATA_FORMAT " " REGION_DATA_FORMAT " "
@@ -258,14 +258,14 @@
++i;
}
- log_develop_trace(gc, compaction, phases)("summary_data_bytes=" SIZE_FORMAT, total_words * HeapWordSize);
+ log_develop_trace(gc, compaction)("summary_data_bytes=" SIZE_FORMAT, total_words * HeapWordSize);
}
void
print_generic_summary_data(ParallelCompactData& summary_data,
SpaceInfo* space_info)
{
- if (!log_develop_is_enabled(Trace, gc, compaction, phases)) {
+ if (!log_develop_is_enabled(Trace, gc, compaction)) {
return;
}
@@ -296,7 +296,7 @@
size_t i = summary_data.addr_to_region_idx(space->bottom());
while (i < end_region && summary_data.region(i)->data_size() == region_size) {
ParallelCompactData::RegionData* c = summary_data.region(i);
- log_develop_trace(gc, compaction, phases)(
+ log_develop_trace(gc, compaction)(
SIZE_FORMAT_W(5) " " PTR_FORMAT " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " %d",
i, p2i(c->destination()),
c->partial_obj_size(), c->live_obj_size(),
@@ -330,7 +330,7 @@
}
ParallelCompactData::RegionData* c = summary_data.region(i);
- log_develop_trace(gc, compaction, phases)(
+ log_develop_trace(gc, compaction)(
SIZE_FORMAT_W(5) " " PTR_FORMAT " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " %d"
"%12.10f " SIZE_FORMAT_W(10) " " SIZE_FORMAT_W(10),
i, p2i(c->destination()),
@@ -346,21 +346,21 @@
// Any remaining regions are empty. Print one more if there is one.
if (i < end_region) {
ParallelCompactData::RegionData* c = summary_data.region(i);
- log_develop_trace(gc, compaction, phases)(
+ log_develop_trace(gc, compaction)(
SIZE_FORMAT_W(5) " " PTR_FORMAT " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " %d",
i, p2i(c->destination()),
c->partial_obj_size(), c->live_obj_size(),
c->data_size(), c->source_region(), c->destination_count());
}
- log_develop_trace(gc, compaction, phases)("max: " SIZE_FORMAT_W(4) " d2r=" SIZE_FORMAT_W(10) " l2r=" SIZE_FORMAT_W(10) " max_ratio=%14.12f",
- max_reclaimed_ratio_region, max_dead_to_right, max_live_to_right, max_reclaimed_ratio);
+ log_develop_trace(gc, compaction)("max: " SIZE_FORMAT_W(4) " d2r=" SIZE_FORMAT_W(10) " l2r=" SIZE_FORMAT_W(10) " max_ratio=%14.12f",
+ max_reclaimed_ratio_region, max_dead_to_right, max_live_to_right, max_reclaimed_ratio);
}
void
print_initial_summary_data(ParallelCompactData& summary_data,
SpaceInfo* space_info) {
- if (!log_develop_is_enabled(Trace, gc, compaction, phases)) {
+ if (!log_develop_is_enabled(Trace, gc, compaction)) {
return;
}
@@ -621,7 +621,7 @@
sr->partial_obj_size()));
const size_t end_idx = addr_to_region_idx(target_end);
- log_develop_trace(gc, compaction, phases)("split: clearing source_region field in [" SIZE_FORMAT ", " SIZE_FORMAT ")", beg_idx, end_idx);
+ log_develop_trace(gc, compaction)("split: clearing source_region field in [" SIZE_FORMAT ", " SIZE_FORMAT ")", beg_idx, end_idx);
for (size_t idx = beg_idx; idx < end_idx; ++idx) {
_region_data[idx].set_source_region(0);
}
@@ -641,22 +641,22 @@
*target_next = split_destination + partial_obj_size;
HeapWord* const source_next = region_to_addr(split_region) + partial_obj_size;
- if (log_develop_is_enabled(Trace, gc, compaction, phases)) {
+ if (log_develop_is_enabled(Trace, gc, compaction)) {
const char * split_type = partial_obj_size == 0 ? "easy" : "hard";
- log_develop_trace(gc, compaction, phases)("%s split: src=" PTR_FORMAT " src_c=" SIZE_FORMAT " pos=" SIZE_FORMAT,
- split_type, p2i(source_next), split_region, partial_obj_size);
- log_develop_trace(gc, compaction, phases)("%s split: dst=" PTR_FORMAT " dst_c=" SIZE_FORMAT " tn=" PTR_FORMAT,
- split_type, p2i(split_destination),
- addr_to_region_idx(split_destination),
- p2i(*target_next));
+ log_develop_trace(gc, compaction)("%s split: src=" PTR_FORMAT " src_c=" SIZE_FORMAT " pos=" SIZE_FORMAT,
+ split_type, p2i(source_next), split_region, partial_obj_size);
+ log_develop_trace(gc, compaction)("%s split: dst=" PTR_FORMAT " dst_c=" SIZE_FORMAT " tn=" PTR_FORMAT,
+ split_type, p2i(split_destination),
+ addr_to_region_idx(split_destination),
+ p2i(*target_next));
if (partial_obj_size != 0) {
HeapWord* const po_beg = split_info.destination();
HeapWord* const po_end = po_beg + split_info.partial_obj_size();
- log_develop_trace(gc, compaction, phases)("%s split: po_beg=" PTR_FORMAT " " SIZE_FORMAT " po_end=" PTR_FORMAT " " SIZE_FORMAT,
- split_type,
- p2i(po_beg), addr_to_region_idx(po_beg),
- p2i(po_end), addr_to_region_idx(po_end));
+ log_develop_trace(gc, compaction)("%s split: po_beg=" PTR_FORMAT " " SIZE_FORMAT " po_end=" PTR_FORMAT " " SIZE_FORMAT,
+ split_type,
+ p2i(po_beg), addr_to_region_idx(po_beg),
+ p2i(po_end), addr_to_region_idx(po_end));
}
}
@@ -670,7 +670,7 @@
HeapWord** target_next)
{
HeapWord* const source_next_val = source_next == NULL ? NULL : *source_next;
- log_develop_trace(gc, compaction, phases)(
+ log_develop_trace(gc, compaction)(
"sb=" PTR_FORMAT " se=" PTR_FORMAT " sn=" PTR_FORMAT
"tb=" PTR_FORMAT " te=" PTR_FORMAT " tn=" PTR_FORMAT,
p2i(source_beg), p2i(source_end), p2i(source_next_val),
@@ -938,7 +938,7 @@
// at each young gen gc. Do the update unconditionally (even though a
// promotion failure does not swap spaces) because an unknown number of young
// collections will have swapped the spaces an unknown number of times.
- GCTraceTime(Trace, gc, phases) tm("Pre Compact", &_gc_timer);
+ GCTraceTime(Debug, gc, phases) tm("Pre Compact", &_gc_timer);
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
_space_info[from_space_id].set_space(heap->young_gen()->from_space());
_space_info[to_space_id].set_space(heap->young_gen()->to_space());
@@ -981,7 +981,7 @@
void PSParallelCompact::post_compact()
{
- GCTraceTime(Trace, gc, phases) tm("Post Compact", &_gc_timer);
+ GCTraceTime(Info, gc, phases) tm("Post Compact", &_gc_timer);
for (unsigned int id = old_space_id; id < last_space_id; ++id) {
// Clear the marking bitmap, summary data and split info.
@@ -1524,7 +1524,7 @@
}
}
- if (log_develop_is_enabled(Trace, gc, compaction, phases)) {
+ if (log_develop_is_enabled(Trace, gc, compaction)) {
const size_t region_size = ParallelCompactData::RegionSize;
HeapWord* const dense_prefix_end = _space_info[id].dense_prefix();
const size_t dp_region = _summary_data.addr_to_region_idx(dense_prefix_end);
@@ -1532,7 +1532,7 @@
HeapWord* const new_top = _space_info[id].new_top();
const HeapWord* nt_aligned_up = _summary_data.region_align_up(new_top);
const size_t cr_words = pointer_delta(nt_aligned_up, dense_prefix_end);
- log_develop_trace(gc, compaction, phases)(
+ log_develop_trace(gc, compaction)(
"id=%d cap=" SIZE_FORMAT " dp=" PTR_FORMAT " "
"dp_region=" SIZE_FORMAT " " "dp_count=" SIZE_FORMAT " "
"cr_count=" SIZE_FORMAT " " "nt=" PTR_FORMAT,
@@ -1548,7 +1548,7 @@
SpaceId src_space_id,
HeapWord* src_beg, HeapWord* src_end)
{
- log_develop_trace(gc, compaction, phases)(
+ log_develop_trace(gc, compaction)(
"Summarizing %d [%s] into %d [%s]: "
"src=" PTR_FORMAT "-" PTR_FORMAT " "
SIZE_FORMAT "-" SIZE_FORMAT " "
@@ -1568,7 +1568,7 @@
void PSParallelCompact::summary_phase(ParCompactionManager* cm,
bool maximum_compaction)
{
- GCTraceTime(Trace, gc, phases) tm("Summary Phase", &_gc_timer);
+ GCTraceTime(Info, gc, phases) tm("Summary Phase", &_gc_timer);
#ifdef ASSERT
if (TraceParallelOldGCMarkingPhase) {
@@ -1584,7 +1584,7 @@
// Quick summarization of each space into itself, to see how much is live.
summarize_spaces_quick();
- log_develop_trace(gc, compaction, phases)("summary phase: after summarizing each space to self");
+ log_develop_trace(gc, compaction)("summary phase: after summarizing each space to self");
NOT_PRODUCT(print_region_ranges());
NOT_PRODUCT(print_initial_summary_data(_summary_data, _space_info));
@@ -1660,7 +1660,7 @@
}
}
- log_develop_trace(gc, compaction, phases)("Summary_phase: after final summarization");
+ log_develop_trace(gc, compaction)("Summary_phase: after final summarization");
NOT_PRODUCT(print_region_ranges());
NOT_PRODUCT(print_initial_summary_data(_summary_data, _space_info));
}
@@ -2042,7 +2042,7 @@
bool maximum_heap_compaction,
ParallelOldTracer *gc_tracer) {
// Recursively traverse all live objects and mark them
- GCTraceTime(Trace, gc, phases) tm("Marking Phase", &_gc_timer);
+ GCTraceTime(Info, gc, phases) tm("Marking Phase", &_gc_timer);
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
uint parallel_gc_threads = heap->gc_task_manager()->workers();
@@ -2057,7 +2057,7 @@
ClassLoaderDataGraph::clear_claimed_marks();
{
- GCTraceTime(Trace, gc, phases) tm("Par Mark", &_gc_timer);
+ GCTraceTime(Debug, gc, phases) tm("Par Mark", &_gc_timer);
ParallelScavengeHeap::ParStrongRootsScope psrs;
@@ -2086,7 +2086,7 @@
// Process reference objects found during marking
{
- GCTraceTime(Trace, gc, phases) tm("Reference Processing", &_gc_timer);
+ GCTraceTime(Debug, gc, phases) tm("Reference Processing", &_gc_timer);
ReferenceProcessorStats stats;
if (ref_processor()->processing_is_mt()) {
@@ -2103,38 +2103,40 @@
gc_tracer->report_gc_reference_stats(stats);
}
- GCTraceTime(Trace, gc) tm_m("Class Unloading", &_gc_timer);
-
// This is the point where the entire marking should have completed.
assert(cm->marking_stacks_empty(), "Marking should have completed");
- // Follow system dictionary roots and unload classes.
- bool purged_class = SystemDictionary::do_unloading(is_alive_closure());
-
- // Unload nmethods.
- CodeCache::do_unloading(is_alive_closure(), purged_class);
-
- // Prune dead klasses from subklass/sibling/implementor lists.
- Klass::clean_weak_klass_links(is_alive_closure());
-
- // Delete entries for dead interned strings.
- StringTable::unlink(is_alive_closure());
-
- // Clean up unreferenced symbols in symbol table.
- SymbolTable::unlink();
+ {
+ GCTraceTime(Debug, gc, phases) tm_m("Class Unloading", &_gc_timer);
+
+ // Follow system dictionary roots and unload classes.
+ bool purged_class = SystemDictionary::do_unloading(is_alive_closure());
+
+ // Unload nmethods.
+ CodeCache::do_unloading(is_alive_closure(), purged_class);
+
+ // Prune dead klasses from subklass/sibling/implementor lists.
+ Klass::clean_weak_klass_links(is_alive_closure());
+ }
+
+ {
+ GCTraceTime(Debug, gc, phases) t("Scrub String Table", &_gc_timer);
+ // Delete entries for dead interned strings.
+ StringTable::unlink(is_alive_closure());
+ }
+
+ {
+ GCTraceTime(Debug, gc, phases) t("Scrub Symbol Table", &_gc_timer);
+ // Clean up unreferenced symbols in symbol table.
+ SymbolTable::unlink();
+ }
+
_gc_tracer.report_object_count_after_gc(is_alive_closure());
}
-// This should be moved to the shared markSweep code!
-class PSAlwaysTrueClosure: public BoolObjectClosure {
-public:
- bool do_object_b(oop p) { return true; }
-};
-static PSAlwaysTrueClosure always_true;
-
void PSParallelCompact::adjust_roots(ParCompactionManager* cm) {
// Adjust the pointers to reflect the new locations
- GCTraceTime(Trace, gc, phases) tm("Adjust Roots", &_gc_timer);
+ GCTraceTime(Info, gc, phases) tm("Adjust Roots", &_gc_timer);
// Need new claim bits when tracing through and adjusting pointers.
ClassLoaderDataGraph::clear_claimed_marks();
@@ -2157,7 +2159,7 @@
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)
// Global (weak) JNI handles
- JNIHandles::weak_oops_do(&always_true, &oop_closure);
+ JNIHandles::weak_oops_do(&oop_closure);
CodeBlobToOopClosure adjust_from_blobs(&oop_closure, CodeBlobToOopClosure::FixRelocations);
CodeCache::blobs_do(&adjust_from_blobs);
@@ -2408,7 +2410,7 @@
#endif // #ifdef ASSERT
void PSParallelCompact::compact() {
- GCTraceTime(Trace, gc, phases) tm("Compaction Phase", &_gc_timer);
+ GCTraceTime(Info, gc, phases) tm("Compaction Phase", &_gc_timer);
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
PSOldGen* old_gen = heap->old_gen();
@@ -2467,9 +2469,8 @@
for (cur_region = beg_region; cur_region < new_top_region; ++cur_region) {
const RegionData* const c = sd.region(cur_region);
if (!c->completed()) {
- warning("region " SIZE_FORMAT " not filled: "
- "destination_count=%u",
- cur_region, c->destination_count());
+ log_warning(gc)("region " SIZE_FORMAT " not filled: destination_count=%u",
+ cur_region, c->destination_count());
issued_a_warning = true;
}
}
@@ -2477,9 +2478,8 @@
for (cur_region = new_top_region; cur_region < old_top_region; ++cur_region) {
const RegionData* const c = sd.region(cur_region);
if (!c->available()) {
- warning("region " SIZE_FORMAT " not empty: "
- "destination_count=%u",
- cur_region, c->destination_count());
+ log_warning(gc)("region " SIZE_FORMAT " not empty: destination_count=%u",
+ cur_region, c->destination_count());
issued_a_warning = true;
}
}
@@ -3013,7 +3013,7 @@
jlong ret_val = now - _time_of_last_gc;
// XXX See note in genCollectedHeap::millis_since_last_gc().
if (ret_val < 0) {
- NOT_PRODUCT(warning("time warp: " JLONG_FORMAT, ret_val);)
+ NOT_PRODUCT(log_warning(gc)("time warp: " JLONG_FORMAT, ret_val);)
return 0;
}
return ret_val;
--- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -29,6 +29,7 @@
#include "gc/parallel/psPromotionManager.inline.hpp"
#include "gc/parallel/psScavenge.inline.hpp"
#include "gc/shared/gcTrace.hpp"
+#include "gc/shared/preservedMarks.inline.hpp"
#include "gc/shared/taskqueue.inline.hpp"
#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
@@ -41,6 +42,7 @@
PaddedEnd<PSPromotionManager>* PSPromotionManager::_manager_array = NULL;
OopStarTaskQueueSet* PSPromotionManager::_stack_array_depth = NULL;
+PreservedMarksSet* PSPromotionManager::_preserved_marks_set = NULL;
PSOldGen* PSPromotionManager::_old_gen = NULL;
MutableSpace* PSPromotionManager::_young_space = NULL;
@@ -50,10 +52,12 @@
_old_gen = heap->old_gen();
_young_space = heap->young_gen()->to_space();
+ const uint promotion_manager_num = ParallelGCThreads + 1;
+
// To prevent false sharing, we pad the PSPromotionManagers
// and make sure that the first instance starts at a cache line.
assert(_manager_array == NULL, "Attempt to initialize twice");
- _manager_array = PaddedArray<PSPromotionManager, mtGC>::create_unfreeable(ParallelGCThreads + 1);
+ _manager_array = PaddedArray<PSPromotionManager, mtGC>::create_unfreeable(promotion_manager_num);
guarantee(_manager_array != NULL, "Could not initialize promotion manager");
_stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads);
@@ -65,6 +69,14 @@
}
// The VMThread gets its own PSPromotionManager, which is not available
// for work stealing.
+
+ assert(_preserved_marks_set == NULL, "Attempt to initialize twice");
+ _preserved_marks_set = new PreservedMarksSet(true /* in_c_heap */);
+ guarantee(_preserved_marks_set != NULL, "Could not initialize preserved marks set");
+ _preserved_marks_set->init(promotion_manager_num);
+ for (uint i = 0; i < promotion_manager_num; i += 1) {
+ _manager_array[i].register_preserved_marks(_preserved_marks_set->get(i));
+ }
}
// Helper functions to get around the circular dependency between
@@ -90,6 +102,7 @@
void PSPromotionManager::pre_scavenge() {
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
+ _preserved_marks_set->assert_empty();
_young_space = heap->young_gen()->to_space();
for(uint i=0; i<ParallelGCThreads+1; i++) {
@@ -110,6 +123,11 @@
}
manager->flush_labs();
}
+ if (!promotion_failure_occurred) {
+ // If there was no promotion failure, the preserved mark stacks
+ // should be empty.
+ _preserved_marks_set->assert_empty();
+ }
return promotion_failure_occurred;
}
@@ -187,6 +205,8 @@
// let's choose 1.5x the chunk size
_min_array_size_for_chunking = 3 * _array_chunk_size / 2;
+ _preserved_marks = NULL;
+
reset();
}
@@ -211,6 +231,10 @@
TASKQUEUE_STATS_ONLY(reset_stats());
}
+void PSPromotionManager::register_preserved_marks(PreservedMarks* preserved_marks) {
+ assert(_preserved_marks == NULL, "do not set it twice");
+ _preserved_marks = preserved_marks;
+}
void PSPromotionManager::drain_stacks_depth(bool totally_drain) {
totally_drain = totally_drain || _totally_drain;
@@ -422,8 +446,7 @@
push_contents(obj);
- // Save the mark if needed
- PSScavenge::oop_promotion_failed(obj, obj_mark);
+ _preserved_marks->push_if_necessary(obj, obj_mark);
} else {
// We lost, someone else "owns" this object
guarantee(obj->is_forwarded(), "Object must be forwarded if the cas failed.");
--- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -28,6 +28,7 @@
#include "gc/parallel/psPromotionLAB.hpp"
#include "gc/shared/copyFailedInfo.hpp"
#include "gc/shared/gcTrace.hpp"
+#include "gc/shared/preservedMarks.hpp"
#include "gc/shared/taskqueue.hpp"
#include "memory/allocation.hpp"
#include "memory/padded.hpp"
@@ -55,6 +56,7 @@
private:
static PaddedEnd<PSPromotionManager>* _manager_array;
static OopStarTaskQueueSet* _stack_array_depth;
+ static PreservedMarksSet* _preserved_marks_set;
static PSOldGen* _old_gen;
static MutableSpace* _young_space;
@@ -84,6 +86,7 @@
uint _array_chunk_size;
uint _min_array_size_for_chunking;
+ PreservedMarks* _preserved_marks;
PromotionFailedInfo _promotion_failed_info;
// Accessors
@@ -176,6 +179,8 @@
oop oop_promotion_failed(oop obj, markOop obj_mark);
void reset();
+ void register_preserved_marks(PreservedMarks* preserved_marks);
+ static void restore_preserved_marks() { _preserved_marks_set->restore(); }
void flush_labs();
void drain_stacks(bool totally_drain) {
--- a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -68,8 +68,6 @@
elapsedTimer PSScavenge::_accumulated_time;
STWGCTimer PSScavenge::_gc_timer;
ParallelScavengeTracer PSScavenge::_gc_tracer;
-Stack<markOop, mtGC> PSScavenge::_preserved_mark_stack;
-Stack<oop, mtGC> PSScavenge::_preserved_oop_stack;
CollectorCounters* PSScavenge::_counters = NULL;
// Define before use
@@ -123,14 +121,6 @@
}
};
-class PSPromotionFailedClosure : public ObjectClosure {
- virtual void do_object(oop obj) {
- if (obj->is_forwarded()) {
- obj->init_mark();
- }
- }
-};
-
class PSRefProcTaskProxy: public GCTask {
typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
ProcessTask & _rp_task;
@@ -257,9 +247,6 @@
assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread");
- assert(_preserved_mark_stack.is_empty(), "should be empty");
- assert(_preserved_oop_stack.is_empty(), "should be empty");
-
_gc_timer.register_gc_start();
TimeStamp scavenge_entry;
@@ -417,7 +404,7 @@
// Process reference objects discovered during scavenge
{
- GCTraceTime(Debug, gc, phases) tm("References", &_gc_timer);
+ GCTraceTime(Debug, gc, phases) tm("Reference Processing", &_gc_timer);
reference_processor()->setup_policy(false); // not always_clear
reference_processor()->set_active_mt_degree(active_workers);
@@ -446,7 +433,7 @@
}
{
- GCTraceTime(Debug, gc, phases) tm("StringTable", &_gc_timer);
+ GCTraceTime(Debug, gc, phases) tm("Scrub String Table", &_gc_timer);
// Unlink any dead interned Strings and process the remaining live ones.
PSScavengeRootsClosure root_closure(promotion_manager);
StringTable::unlink_or_oops_do(&_is_alive_closure, &root_closure);
@@ -656,52 +643,20 @@
}
// This method iterates over all objects in the young generation,
-// unforwarding markOops. It then restores any preserved mark oops,
-// and clears the _preserved_mark_stack.
+// removing all forwarding references. It then restores any preserved marks.
void PSScavenge::clean_up_failed_promotion() {
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
PSYoungGen* young_gen = heap->young_gen();
- {
- ResourceMark rm;
-
- // Unforward all pointers in the young gen.
- PSPromotionFailedClosure unforward_closure;
- young_gen->object_iterate(&unforward_closure);
-
- log_trace(gc, ergo)("Restoring " SIZE_FORMAT " marks", _preserved_oop_stack.size());
+ RemoveForwardedPointerClosure remove_fwd_ptr_closure;
+ young_gen->object_iterate(&remove_fwd_ptr_closure);
- // Restore any saved marks.
- while (!_preserved_oop_stack.is_empty()) {
- oop obj = _preserved_oop_stack.pop();
- markOop mark = _preserved_mark_stack.pop();
- obj->set_mark(mark);
- }
-
- // Clear the preserved mark and oop stack caches.
- _preserved_mark_stack.clear(true);
- _preserved_oop_stack.clear(true);
- }
+ PSPromotionManager::restore_preserved_marks();
// Reset the PromotionFailureALot counters.
NOT_PRODUCT(heap->reset_promotion_should_fail();)
}
-// This method is called whenever an attempt to promote an object
-// fails. Some markOops will need preservation, some will not. Note
-// that the entire eden is traversed after a failed promotion, with
-// all forwarded headers replaced by the default markOop. This means
-// it is not necessary to preserve most markOops.
-void PSScavenge::oop_promotion_failed(oop obj, markOop obj_mark) {
- if (obj_mark->must_be_preserved_for_promotion_failure(obj)) {
- // Should use per-worker private stacks here rather than
- // locking a common pair of stacks.
- ThreadCritical tc;
- _preserved_oop_stack.push(obj);
- _preserved_mark_stack.push(obj_mark);
- }
-}
-
bool PSScavenge::should_attempt_scavenge() {
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
PSGCAdaptivePolicyCounters* counters = heap->gc_policy_counters();
--- a/hotspot/src/share/vm/gc/parallel/psScavenge.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psScavenge.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -79,8 +79,6 @@
static HeapWord* _young_generation_boundary;
// Used to optimize compressed oops young gen boundary checking.
static uintptr_t _young_generation_boundary_compressed;
- static Stack<markOop, mtGC> _preserved_mark_stack; // List of marks to be restored after failed promotion
- static Stack<oop, mtGC> _preserved_oop_stack; // List of oops that need their mark restored.
static CollectorCounters* _counters; // collector performance counters
static void clean_up_failed_promotion();
@@ -127,9 +125,6 @@
// Return true if a collection was done; false otherwise.
static bool invoke_no_policy();
- // If an attempt to promote fails, this method is invoked
- static void oop_promotion_failed(oop obj, markOop obj_mark);
-
template <class T> static inline bool should_scavenge(T* p);
// These call should_scavenge() above and, if it returns true, also check that
--- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -594,7 +594,7 @@
init_assuming_no_promotion_failure();
- GCTraceTime(Trace, gc) tm("DefNew", NULL, gch->gc_cause());
+ GCTraceTime(Trace, gc, phases) tm("DefNew", NULL, gch->gc_cause());
gch->trace_heap_before_gc(&gc_tracer);
--- a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -180,7 +180,7 @@
void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
// Recursively traverse all live objects and mark them
- GCTraceTime(Trace, gc) tm("Phase 1: Mark live objects", _gc_timer);
+ GCTraceTime(Info, gc, phases) tm("Phase 1: Mark live objects", _gc_timer);
GenCollectedHeap* gch = GenCollectedHeap::heap();
@@ -208,6 +208,8 @@
// Process reference objects found during marking
{
+ GCTraceTime(Debug, gc, phases) tm_m("Reference Processing", gc_timer());
+
ref_processor()->setup_policy(clear_all_softrefs);
const ReferenceProcessorStats& stats =
ref_processor()->process_discovered_references(
@@ -218,20 +220,30 @@
// This is the point where the entire marking should have completed.
assert(_marking_stack.is_empty(), "Marking should have completed");
- // Unload classes and purge the SystemDictionary.
- bool purged_class = SystemDictionary::do_unloading(&is_alive);
+ {
+ GCTraceTime(Debug, gc, phases) tm_m("Class Unloading", gc_timer());
- // Unload nmethods.
- CodeCache::do_unloading(&is_alive, purged_class);
+ // Unload classes and purge the SystemDictionary.
+ bool purged_class = SystemDictionary::do_unloading(&is_alive);
+
+ // Unload nmethods.
+ CodeCache::do_unloading(&is_alive, purged_class);
- // Prune dead klasses from subklass/sibling/implementor lists.
- Klass::clean_weak_klass_links(&is_alive);
+ // Prune dead klasses from subklass/sibling/implementor lists.
+ Klass::clean_weak_klass_links(&is_alive);
+ }
- // Delete entries for dead interned strings.
- StringTable::unlink(&is_alive);
+ {
+ GCTraceTime(Debug, gc, phases) t("Scrub String Table", gc_timer());
+ // Delete entries for dead interned strings.
+ StringTable::unlink(&is_alive);
+ }
- // Clean up unreferenced symbols in symbol table.
- SymbolTable::unlink();
+ {
+ GCTraceTime(Debug, gc, phases) t("Scrub Symbol Table", gc_timer());
+ // Clean up unreferenced symbols in symbol table.
+ SymbolTable::unlink();
+ }
gc_tracer()->report_object_count_after_gc(&is_alive);
}
@@ -253,7 +265,7 @@
GenCollectedHeap* gch = GenCollectedHeap::heap();
- GCTraceTime(Trace, gc) tm("Phase 2: Compute new object addresses", _gc_timer);
+ GCTraceTime(Info, gc, phases) tm("Phase 2: Compute new object addresses", _gc_timer);
gch->prepare_for_compaction();
}
@@ -269,7 +281,7 @@
GenCollectedHeap* gch = GenCollectedHeap::heap();
// Adjust the pointers to reflect the new locations
- GCTraceTime(Trace, gc) tm("Phase 3: Adjust pointers", _gc_timer);
+ GCTraceTime(Info, gc, phases) tm("Phase 3: Adjust pointers", gc_timer());
// Need new claim bits for the pointer adjustment tracing.
ClassLoaderDataGraph::clear_claimed_marks();
@@ -321,7 +333,7 @@
// to use a higher index (saved from phase2) when verifying perm_gen.
GenCollectedHeap* gch = GenCollectedHeap::heap();
- GCTraceTime(Trace, gc) tm("Phase 4: Move objects", _gc_timer);
+ GCTraceTime(Info, gc, phases) tm("Phase 4: Move objects", _gc_timer);
GenCompactClosure blk;
gch->generation_iterate(&blk, true);
--- a/hotspot/src/share/vm/gc/shared/barrierSet.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/barrierSet.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -30,10 +30,6 @@
// count is number of array elements being written
void BarrierSet::static_write_ref_array_pre(HeapWord* start, size_t count) {
assert(count <= (size_t)max_intx, "count too large");
-#if 0
- warning("Pre: \t" INTPTR_FORMAT "[" SIZE_FORMAT "]\t",
- start, count);
-#endif
if (UseCompressedOops) {
Universe::heap()->barrier_set()->write_ref_array_pre((narrowOop*)start, (int)count, false);
} else {
--- a/hotspot/src/share/vm/gc/shared/barrierSet.inline.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/barrierSet.inline.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -78,10 +78,6 @@
// If compressed oops were not being used, these should already be aligned
assert(UseCompressedOops || (aligned_start == start && aligned_end == end),
"Expected heap word alignment of start and end");
-#if 0
- warning("Post:\t" INTPTR_FORMAT "[" SIZE_FORMAT "] : [" INTPTR_FORMAT "," INTPTR_FORMAT ")\t",
- start, count, aligned_start, aligned_end);
-#endif
write_ref_array_work(MemRegion(aligned_start, aligned_end));
}
--- a/hotspot/src/share/vm/gc/shared/cardGeneration.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/cardGeneration.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, 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
@@ -144,7 +144,7 @@
const size_t remaining_bytes = _virtual_space.uncommitted_size();
if (remaining_bytes > 0) {
success = grow_by(remaining_bytes);
- DEBUG_ONLY(if (!success) warning("grow to reserved failed");)
+ DEBUG_ONLY(if (!success) log_warning(gc)("grow to reserved failed");)
}
return success;
}
--- a/hotspot/src/share/vm/gc/shared/cardTableRS.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/cardTableRS.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -325,17 +325,17 @@
// In the case of CMS+ParNew, issue a warning
if (!ur.contains(urasm)) {
assert(UseConcMarkSweepGC, "Tautology: see assert above");
- warning("CMS+ParNew: Did you forget to call save_marks()? "
- "[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in "
- "[" PTR_FORMAT ", " PTR_FORMAT ")",
- p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end()));
+ log_warning(gc)("CMS+ParNew: Did you forget to call save_marks()? "
+ "[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in "
+ "[" PTR_FORMAT ", " PTR_FORMAT ")",
+ p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end()));
MemRegion ur2 = sp->used_region();
MemRegion urasm2 = sp->used_region_at_save_marks();
if (!ur.equals(ur2)) {
- warning("CMS+ParNew: Flickering used_region()!!");
+ log_warning(gc)("CMS+ParNew: Flickering used_region()!!");
}
if (!urasm.equals(urasm2)) {
- warning("CMS+ParNew: Flickering used_region_at_save_marks()!!");
+ log_warning(gc)("CMS+ParNew: Flickering used_region_at_save_marks()!!");
}
ShouldNotReachHere();
}
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -213,7 +213,7 @@
do_full_collection(false); // don't clear all soft refs
break;
}
- case GCCause::_last_ditch_collection: {
+ case GCCause::_metadata_GC_clear_soft_refs: {
HandleMark hm;
do_full_collection(true); // do clear all soft refs
break;
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -438,6 +438,12 @@
// remembered set.
virtual void flush_deferred_store_barrier(JavaThread* thread);
+ // Should return true if the reference pending list lock is
+ // acquired from non-Java threads, such as a concurrent GC thread.
+ virtual bool needs_reference_pending_list_locker_thread() const {
+ return false;
+ }
+
// Perform a collection of the heap; intended for use in implementing
// "System.gc". This probably implies as full a collection as the
// "CollectedHeap" supports.
--- a/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -96,6 +96,9 @@
}
// Check heap parameter properties
+ if (MaxHeapSize < 2 * M) {
+ vm_exit_during_initialization("Too small maximum heap");
+ }
if (InitialHeapSize < M) {
vm_exit_during_initialization("Too small initial heap");
}
--- a/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/concurrentGCThread.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -37,12 +37,12 @@
_should_terminate(false), _has_terminated(false) {
};
-void ConcurrentGCThread::create_and_start() {
+void ConcurrentGCThread::create_and_start(ThreadPriority prio) {
if (os::create_thread(this, os::cgc_thread)) {
// XXX: need to set this to low priority
// unless "aggressive mode" set; priority
// should be just less than that of VMThread.
- os::set_priority(this, NearMaxPriority);
+ os::set_priority(this, prio);
if (!_should_terminate && !DisableStartThread) {
os::start_thread(this);
}
@@ -75,130 +75,30 @@
}
}
-static void _sltLoop(JavaThread* thread, TRAPS) {
- SurrogateLockerThread* slt = (SurrogateLockerThread*)thread;
- slt->loop();
-}
-
-SurrogateLockerThread::SurrogateLockerThread() :
- JavaThread(&_sltLoop),
- _monitor(Mutex::nonleaf, "SLTMonitor", false,
- Monitor::_safepoint_check_sometimes),
- _buffer(empty)
-{}
-
-SurrogateLockerThread* SurrogateLockerThread::make(TRAPS) {
- Klass* k =
- SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(),
- true, CHECK_NULL);
- instanceKlassHandle klass (THREAD, k);
- instanceHandle thread_oop = klass->allocate_instance_handle(CHECK_NULL);
-
- const char thread_name[] = "Surrogate Locker Thread (Concurrent GC)";
- Handle string = java_lang_String::create_from_str(thread_name, CHECK_NULL);
+void ConcurrentGCThread::run() {
+ initialize_in_thread();
+ wait_for_universe_init();
- // Initialize thread_oop to put it into the system threadGroup
- Handle thread_group (THREAD, Universe::system_thread_group());
- JavaValue result(T_VOID);
- JavaCalls::call_special(&result, thread_oop,
- klass,
- vmSymbols::object_initializer_name(),
- vmSymbols::threadgroup_string_void_signature(),
- thread_group,
- string,
- CHECK_NULL);
-
- SurrogateLockerThread* res;
- {
- MutexLocker mu(Threads_lock);
- res = new SurrogateLockerThread();
+ run_service();
- // At this point it may be possible that no osthread was created for the
- // JavaThread due to lack of memory. We would have to throw an exception
- // in that case. However, since this must work and we do not allow
- // exceptions anyway, check and abort if this fails.
- if (res == NULL || res->osthread() == NULL) {
- vm_exit_during_initialization("java.lang.OutOfMemoryError",
- os::native_thread_creation_failed_msg());
- }
- java_lang_Thread::set_thread(thread_oop(), res);
- java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
- java_lang_Thread::set_daemon(thread_oop());
-
- res->set_threadObj(thread_oop());
- Threads::add(res);
- Thread::start(res);
- }
- os::naked_yield(); // This seems to help with initial start-up of SLT
- return res;
+ terminate();
}
-void SurrogateLockerThread::report_missing_slt() {
- vm_exit_during_initialization(
- "GC before GC support fully initialized: "
- "SLT is needed but has not yet been created.");
- ShouldNotReachHere();
-}
+void ConcurrentGCThread::stop() {
+ // it is ok to take late safepoints here, if needed
+ {
+ MutexLockerEx mu(Terminator_lock);
+ assert(!_has_terminated, "stop should only be called once");
+ assert(!_should_terminate, "stop should only be called once");
+ _should_terminate = true;
+ }
-void SurrogateLockerThread::manipulatePLL(SLT_msg_type msg) {
- MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag);
- assert(_buffer == empty, "Should be empty");
- assert(msg != empty, "empty message");
- assert(!Heap_lock->owned_by_self(), "Heap_lock owned by requesting thread");
+ stop_service();
- _buffer = msg;
- while (_buffer != empty) {
- _monitor.notify();
- _monitor.wait(Mutex::_no_safepoint_check_flag);
+ {
+ MutexLockerEx mu(Terminator_lock);
+ while (!_has_terminated) {
+ Terminator_lock->wait();
+ }
}
}
-
-// ======= Surrogate Locker Thread =============
-
-void SurrogateLockerThread::loop() {
- BasicLock pll_basic_lock;
- SLT_msg_type msg;
- debug_only(unsigned int owned = 0;)
-
- while (/* !isTerminated() */ 1) {
- {
- MutexLocker x(&_monitor);
- // Since we are a JavaThread, we can't be here at a safepoint.
- assert(!SafepointSynchronize::is_at_safepoint(),
- "SLT is a JavaThread");
- // wait for msg buffer to become non-empty
- while (_buffer == empty) {
- _monitor.notify();
- _monitor.wait();
- }
- msg = _buffer;
- }
- switch(msg) {
- case acquirePLL: {
- InstanceRefKlass::acquire_pending_list_lock(&pll_basic_lock);
- debug_only(owned++;)
- break;
- }
- case releaseAndNotifyPLL: {
- assert(owned > 0, "Don't have PLL");
- InstanceRefKlass::release_and_notify_pending_list_lock(&pll_basic_lock);
- debug_only(owned--;)
- break;
- }
- case empty:
- default: {
- guarantee(false,"Unexpected message in _buffer");
- break;
- }
- }
- {
- MutexLocker x(&_monitor);
- // Since we are a JavaThread, we can't be here at a safepoint.
- assert(!SafepointSynchronize::is_at_safepoint(),
- "SLT is a JavaThread");
- _buffer = empty;
- _monitor.notify();
- }
- }
- assert(!_monitor.owned_by_self(), "Should unlock before exit.");
-}
--- a/hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/concurrentGCThread.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -31,13 +31,9 @@
class ConcurrentGCThread: public NamedThread {
friend class VMStructs;
-protected:
bool volatile _should_terminate;
bool _has_terminated;
- // Create and start the thread (setting it's priority high.)
- void create_and_start();
-
// Do initialization steps in the thread: record stack base and size,
// init thread local storage, set JNI handle block.
void initialize_in_thread();
@@ -49,44 +45,29 @@
// concurrent work.
void terminate();
+protected:
+ // Create and start the thread (setting it's priority.)
+ void create_and_start(ThreadPriority prio = NearMaxPriority);
+
+ // Do the specific GC work. Called by run() after initialization complete.
+ virtual void run_service() = 0;
+
+ // Shut down the specific GC work. Called by stop() as part of termination protocol.
+ virtual void stop_service() = 0;
+
public:
ConcurrentGCThread();
// Tester
bool is_ConcurrentGC_thread() const { return true; }
-};
+
+ virtual void run();
-// The SurrogateLockerThread is used by concurrent GC threads for
-// manipulating Java monitors, in particular, currently for
-// manipulating the pending_list_lock. XXX
-class SurrogateLockerThread: public JavaThread {
- friend class VMStructs;
- public:
- enum SLT_msg_type {
- empty = 0, // no message
- acquirePLL, // acquire pending list lock
- releaseAndNotifyPLL // notify and release pending list lock
- };
- private:
- // the following are shared with the CMSThread
- SLT_msg_type _buffer; // communication buffer
- Monitor _monitor; // monitor controlling buffer
- BasicLock _basicLock; // used for PLL locking
+ // shutdown following termination protocol
+ virtual void stop();
- public:
- static SurrogateLockerThread* make(TRAPS);
-
- // Terminate VM with error message that SLT needed but not yet created.
- static void report_missing_slt();
-
- SurrogateLockerThread();
-
- bool is_hidden_from_external_view() const { return true; }
-
- void loop(); // main method
-
- void manipulatePLL(SLT_msg_type msg);
-
+ bool should_terminate() { return _should_terminate; }
+ bool has_terminated() { return _has_terminated; }
};
#endif // SHARE_VM_GC_SHARED_CONCURRENTGCTHREAD_HPP
--- a/hotspot/src/share/vm/gc/shared/gcCause.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/gcCause.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -57,6 +57,9 @@
case _wb_conc_mark:
return "WhiteBox Initiated Concurrent Mark";
+ case _wb_full_gc:
+ return "WhiteBox Initiated Full GC";
+
case _update_allocation_context_stats_inc:
case _update_allocation_context_stats_full:
return "Update Allocation Context Stats";
@@ -73,6 +76,9 @@
case _metadata_GC_threshold:
return "Metadata GC Threshold";
+ case _metadata_GC_clear_soft_refs:
+ return "Metadata GC Clear Soft References";
+
case _cms_generation_full:
return "CMS Generation Full";
@@ -100,9 +106,6 @@
case _g1_humongous_allocation:
return "G1 Humongous Allocation";
- case _last_ditch_collection:
- return "Last ditch collection";
-
case _dcmd_gc_run:
return "Diagnostic Command";
--- a/hotspot/src/share/vm/gc/shared/gcCause.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/gcCause.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -33,6 +33,9 @@
// use of this class grows, we should split it into public
// and implementation-private "causes".
//
+// The definitions in the SA code should be kept in sync
+// with the definitions here.
+//
class GCCause : public AllStatic {
public:
@@ -48,6 +51,7 @@
_heap_dump,
_wb_young_gc,
_wb_conc_mark,
+ _wb_full_gc,
_update_allocation_context_stats_inc,
_update_allocation_context_stats_full,
@@ -60,6 +64,7 @@
_tenured_generation_full,
_metadata_GC_threshold,
+ _metadata_GC_clear_soft_refs,
_cms_generation_full,
_cms_initial_mark,
@@ -73,8 +78,6 @@
_g1_inc_collection_pause,
_g1_humongous_allocation,
- _last_ditch_collection,
-
_dcmd_gc_run,
_last_gc_cause
@@ -103,22 +106,18 @@
// _allocation_failure is the generic cause a collection which could result
// in the collection of the tenured generation if there is not enough space
// in the tenured generation to support a young GC.
- // _last_ditch_collection is a collection done to include SoftReferences.
return (cause == GCCause::_tenured_generation_full ||
cause == GCCause::_cms_generation_full ||
cause == GCCause::_adaptive_size_policy ||
- cause == GCCause::_allocation_failure ||
- cause == GCCause::_last_ditch_collection);
+ cause == GCCause::_allocation_failure);
}
// Causes for collection of the young generation
inline static bool is_allocation_failure_gc(GCCause::Cause cause) {
// _allocation_failure is the generic cause a collection for allocation failure
// _adaptive_size_policy is for a collecton done before a full GC
- // _last_ditch_collection is a collection done to include SoftReferences.
return (cause == GCCause::_allocation_failure ||
- cause == GCCause::_adaptive_size_policy ||
- cause == GCCause::_last_ditch_collection);
+ cause == GCCause::_adaptive_size_policy);
}
// Return a string describing the GCCause.
--- a/hotspot/src/share/vm/gc/shared/gcTrace.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/gcTrace.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
@@ -242,4 +242,12 @@
prediction_active);
}
+void G1OldTracer::report_gc_start_impl(GCCause::Cause cause, const Ticks& timestamp) {
+ _shared_gc_info.set_start_timestamp(timestamp);
+}
+
+void G1OldTracer::set_gc_cause(GCCause::Cause cause) {
+ _shared_gc_info.set_cause(cause);
+}
+
#endif
--- a/hotspot/src/share/vm/gc/shared/gcTrace.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/gcTrace.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
@@ -126,7 +126,7 @@
protected:
GCTracer(GCName name) : _shared_gc_info(name) {}
- void report_gc_start_impl(GCCause::Cause cause, const Ticks& timestamp);
+ virtual void report_gc_start_impl(GCCause::Cause cause, const Ticks& timestamp);
virtual void report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions);
private:
@@ -297,8 +297,11 @@
};
class G1OldTracer : public OldGCTracer {
+ protected:
+ void report_gc_start_impl(GCCause::Cause cause, const Ticks& timestamp);
public:
G1OldTracer() : OldGCTracer(G1Old) {}
+ void set_gc_cause(GCCause::Cause cause);
};
#endif // SHARE_VM_GC_SHARED_GCTRACE_HPP
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -295,7 +295,8 @@
}
bool GenCollectedHeap::must_clear_all_soft_refs() {
- return _gc_cause == GCCause::_last_ditch_collection;
+ return _gc_cause == GCCause::_metadata_GC_clear_soft_refs ||
+ _gc_cause == GCCause::_wb_full_gc;
}
bool GenCollectedHeap::should_do_concurrent_full_gc(GCCause::Cause cause) {
@@ -315,7 +316,7 @@
bool is_tlab, bool run_verification, bool clear_soft_refs,
bool restore_marks_for_biased_locking) {
FormatBuffer<> title("Collect gen: %s", gen->short_name());
- GCTraceTime(Debug, gc) t1(title);
+ GCTraceTime(Trace, gc, phases) t1(title);
TraceCollectorStats tcs(gen->counters());
TraceMemoryManagerStats tmms(gen->kind(),gc_cause());
@@ -684,15 +685,8 @@
_process_strong_tasks->all_tasks_completed(scope->n_threads());
}
-
-class AlwaysTrueClosure: public BoolObjectClosure {
-public:
- bool do_object_b(oop p) { return true; }
-};
-static AlwaysTrueClosure always_true;
-
void GenCollectedHeap::gen_process_weak_roots(OopClosure* root_closure) {
- JNIHandles::weak_oops_do(&always_true, root_closure);
+ JNIHandles::weak_oops_do(root_closure);
_young_gen->ref_processor()->weak_oops_do(root_closure);
_old_gen->ref_processor()->weak_oops_do(root_closure);
}
@@ -1272,7 +1266,7 @@
// back a time later than 'now'.
jlong retVal = now - tolgc_cl.time();
if (retVal < 0) {
- NOT_PRODUCT(warning("time warp: " JLONG_FORMAT, retVal);)
+ NOT_PRODUCT(log_warning(gc)("time warp: " JLONG_FORMAT, retVal);)
return 0;
}
return retVal;
@@ -1281,7 +1275,7 @@
void GenCollectedHeap::stop() {
#if INCLUDE_ALL_GCS
if (UseConcMarkSweepGC) {
- ConcurrentMarkSweepThread::stop();
+ ConcurrentMarkSweepThread::cmst()->stop();
}
#endif
}
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, 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
@@ -281,6 +281,10 @@
return UseConcMarkSweepGC;
}
+ virtual bool needs_reference_pending_list_locker_thread() const {
+ return UseConcMarkSweepGC;
+ }
+
// We don't need barriers for stores to objects in the
// young gen and, a fortiori, for initializing stores to
// objects therein. This applies to DefNew+Tenured and ParNew+CMS
--- a/hotspot/src/share/vm/gc/shared/generation.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/generation.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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,7 @@
#include "gc/shared/collectorCounters.hpp"
#include "gc/shared/referenceProcessor.hpp"
+#include "logging/log.hpp"
#include "memory/allocation.hpp"
#include "memory/memRegion.hpp"
#include "memory/universe.hpp"
@@ -377,7 +378,7 @@
// have to guard against non-monotonicity.
NOT_PRODUCT(
if (now < _time_of_last_gc) {
- warning("time warp: " JLONG_FORMAT " to " JLONG_FORMAT, _time_of_last_gc, now);
+ log_warning(gc)("time warp: " JLONG_FORMAT " to " JLONG_FORMAT, _time_of_last_gc, now);
}
)
return _time_of_last_gc;
--- a/hotspot/src/share/vm/gc/shared/plab.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/plab.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -136,7 +136,7 @@
// Calculates plab size for current number of gc worker threads.
size_t PLABStats::desired_plab_sz(uint no_of_gc_workers) {
- return MAX2(min_size(), (size_t)align_object_size(_desired_net_plab_sz / no_of_gc_workers));
+ return (size_t)align_object_size(MIN2(MAX2(min_size(), _desired_net_plab_sz / no_of_gc_workers), max_size()));
}
// Compute desired plab size for one gc worker thread and latch result for later
@@ -175,14 +175,9 @@
size_t recent_plab_sz = used / target_refills;
// Take historical weighted average
_filter.sample(recent_plab_sz);
- // Clip from above and below, and align to object boundary
- size_t new_plab_sz = MAX2(min_size(), (size_t)_filter.average());
- new_plab_sz = MIN2(max_size(), new_plab_sz);
- new_plab_sz = align_object_size(new_plab_sz);
- // Latch the result
- _desired_net_plab_sz = new_plab_sz;
+ _desired_net_plab_sz = MAX2(min_size(), (size_t)_filter.average());
- log_sizing(recent_plab_sz, new_plab_sz);
+ log_sizing(recent_plab_sz, _desired_net_plab_sz);
reset();
}
--- a/hotspot/src/share/vm/gc/shared/preservedMarks.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/preservedMarks.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -62,9 +62,14 @@
}
void PreservedMarksSet::restore() {
+ size_t total_size = 0;
for (uint i = 0; i < _num; i += 1) {
+ total_size += get(i)->size();
get(i)->restore();
}
+ assert_empty();
+
+ log_trace(gc)("Restored " SIZE_FORMAT " marks", total_size);
}
void PreservedMarksSet::reclaim() {
--- a/hotspot/src/share/vm/gc/shared/preservedMarks.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/preservedMarks.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -53,6 +53,7 @@
public:
bool is_empty() const { return _stack.is_empty(); }
+ size_t size() const { return _stack.size(); }
inline void push_if_necessary(oop obj, markOop m);
// Iterate over the stack, restore the preserved marks, then reclaim
// the memory taken up by stack chunks.
@@ -65,7 +66,7 @@
virtual void do_object(oop obj);
};
-class PreservedMarksSet VALUE_OBJ_CLASS_SPEC {
+class PreservedMarksSet : public CHeapObj<mtGC> {
private:
// true -> _stacks will be allocated in the C heap
// false -> _stacks will be allocated in the resource arena
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/shared/referencePendingListLocker.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2016, 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/systemDictionary.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/referencePendingListLocker.hpp"
+#include "memory/universe.hpp"
+#include "runtime/javaCalls.hpp"
+#include "utilities/preserveException.hpp"
+
+ReferencePendingListLockerThread::ReferencePendingListLockerThread() :
+ JavaThread(&start),
+ _monitor(Monitor::nonleaf, "ReferencePendingListLocker", false, Monitor::_safepoint_check_sometimes),
+ _message(NONE) {}
+
+ReferencePendingListLockerThread* ReferencePendingListLockerThread::create(TRAPS) {
+ // Create Java thread objects
+ instanceKlassHandle thread_klass = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK_NULL);
+ instanceHandle thread_object = thread_klass->allocate_instance_handle(CHECK_NULL);
+ Handle thread_name = java_lang_String::create_from_str("Reference Pending List Locker", CHECK_NULL);
+ Handle thread_group = Universe::system_thread_group();
+ JavaValue result(T_VOID);
+ JavaCalls::call_special(&result,
+ thread_object,
+ thread_klass,
+ vmSymbols::object_initializer_name(),
+ vmSymbols::threadgroup_string_void_signature(),
+ thread_group,
+ thread_name,
+ CHECK_NULL);
+
+ {
+ MutexLocker ml(Threads_lock);
+
+ // Allocate thread
+ ReferencePendingListLockerThread* thread = new ReferencePendingListLockerThread();
+ if (thread == NULL || thread->osthread() == NULL) {
+ vm_exit_during_initialization("java.lang.OutOfMemoryError",
+ os::native_thread_creation_failed_msg());
+ }
+
+ // Initialize thread
+ java_lang_Thread::set_thread(thread_object(), thread);
+ java_lang_Thread::set_priority(thread_object(), NearMaxPriority);
+ java_lang_Thread::set_daemon(thread_object());
+ thread->set_threadObj(thread_object());
+
+ // Start thread
+ Threads::add(thread);
+ Thread::start(thread);
+
+ return thread;
+ }
+}
+
+void ReferencePendingListLockerThread::start(JavaThread* thread, TRAPS) {
+ ReferencePendingListLockerThread* locker_thread = static_cast<ReferencePendingListLockerThread*>(thread);
+ locker_thread->receive_and_handle_messages();
+}
+
+bool ReferencePendingListLockerThread::is_hidden_from_external_view() const {
+ return true;
+}
+
+void ReferencePendingListLockerThread::send_message(Message message) {
+ assert(message != NONE, "Should not be none");
+ MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag);
+
+ // Wait for completion of current message
+ while (_message != NONE) {
+ ml.wait(Monitor::_no_safepoint_check_flag);
+ }
+
+ // Send new message
+ _message = message;
+ ml.notify_all();
+
+ // Wait for completion of new message
+ while (_message != NONE) {
+ ml.wait(Monitor::_no_safepoint_check_flag);
+ }
+}
+
+void ReferencePendingListLockerThread::receive_and_handle_messages() {
+ ReferencePendingListLocker pending_list_locker;
+ MonitorLockerEx ml(&_monitor);
+
+ // Main loop, never terminates
+ for (;;) {
+ // Wait for message
+ while (_message == NONE) {
+ ml.wait();
+ }
+
+ // Handle message
+ if (_message == LOCK) {
+ pending_list_locker.lock();
+ } else if (_message == UNLOCK) {
+ pending_list_locker.unlock();
+ } else {
+ ShouldNotReachHere();
+ }
+
+ // Clear message
+ _message = NONE;
+ ml.notify_all();
+ }
+}
+
+void ReferencePendingListLockerThread::lock() {
+ send_message(LOCK);
+}
+
+void ReferencePendingListLockerThread::unlock() {
+ send_message(UNLOCK);
+}
+
+bool ReferencePendingListLocker::_is_initialized = false;
+ReferencePendingListLockerThread* ReferencePendingListLocker::_locker_thread = NULL;
+
+void ReferencePendingListLocker::initialize(bool needs_locker_thread, TRAPS) {
+ if (needs_locker_thread) {
+ _locker_thread = ReferencePendingListLockerThread::create(CHECK);
+ }
+
+ _is_initialized = true;
+}
+
+bool ReferencePendingListLocker::is_initialized() {
+ return _is_initialized;
+}
+
+bool ReferencePendingListLocker::is_locked_by_self() {
+ oop pending_list_lock = java_lang_ref_Reference::pending_list_lock();
+ if (pending_list_lock == NULL) {
+ return false;
+ }
+
+ JavaThread* thread = JavaThread::current();
+ Handle handle(thread, pending_list_lock);
+ return ObjectSynchronizer::current_thread_holds_lock(thread, handle);
+}
+
+void ReferencePendingListLocker::lock() {
+ assert(!Heap_lock->owned_by_self(), "Heap_lock must not be owned by requesting thread");
+
+ if (Thread::current()->is_Java_thread()) {
+ assert(java_lang_ref_Reference::pending_list_lock() != NULL, "Not initialized");
+
+ // We may enter this with a pending exception
+ PRESERVE_EXCEPTION_MARK;
+
+ HandleMark hm;
+ Handle handle(THREAD, java_lang_ref_Reference::pending_list_lock());
+
+ // Lock
+ ObjectSynchronizer::fast_enter(handle, &_basic_lock, false, THREAD);
+
+ assert(is_locked_by_self(), "Locking failed");
+
+ if (HAS_PENDING_EXCEPTION) {
+ CLEAR_PENDING_EXCEPTION;
+ }
+ } else {
+ // Delegate operation to locker thread
+ assert(_locker_thread != NULL, "Locker thread not created");
+ _locker_thread->lock();
+ }
+}
+
+void ReferencePendingListLocker::unlock() {
+ if (Thread::current()->is_Java_thread()) {
+ assert(java_lang_ref_Reference::pending_list_lock() != NULL, "Not initialized");
+
+ // We may enter this with a pending exception
+ PRESERVE_EXCEPTION_MARK;
+
+ HandleMark hm;
+ Handle handle(THREAD, java_lang_ref_Reference::pending_list_lock());
+
+ assert(is_locked_by_self(), "Should be locked by self");
+
+ // Notify waiters if the pending list is non-empty
+ if (java_lang_ref_Reference::pending_list() != NULL) {
+ ObjectSynchronizer::notifyall(handle, THREAD);
+ }
+
+ // Unlock
+ ObjectSynchronizer::fast_exit(handle(), &_basic_lock, THREAD);
+
+ if (HAS_PENDING_EXCEPTION) {
+ CLEAR_PENDING_EXCEPTION;
+ }
+ } else {
+ // Delegate operation to locker thread
+ assert(_locker_thread != NULL, "Locker thread not created");
+ _locker_thread->unlock();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/shared/referencePendingListLocker.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016, 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_REFERENCEPENDINGLISTLOCKER_HPP
+#define SHARE_VM_GC_SHARED_REFERENCEPENDINGLISTLOCKER_HPP
+
+#include "memory/allocation.hpp"
+#include "runtime/basicLock.hpp"
+#include "runtime/mutex.hpp"
+#include "runtime/thread.hpp"
+#include "utilities/exceptions.hpp"
+
+//
+// The ReferencePendingListLockerThread locks and unlocks the reference
+// pending list lock on behalf a non-Java thread, typically a concurrent
+// GC thread. This interface should not be directly accessed. All uses
+// should instead go through the ReferencePendingListLocker, which calls
+// this thread if needed.
+//
+class ReferencePendingListLockerThread : public JavaThread {
+private:
+ enum Message {
+ NONE,
+ LOCK,
+ UNLOCK
+ };
+
+ Monitor _monitor;
+ Message _message;
+
+ ReferencePendingListLockerThread();
+
+ static void start(JavaThread* thread, TRAPS);
+
+ void send_message(Message message);
+ void receive_and_handle_messages();
+
+public:
+ static ReferencePendingListLockerThread* create(TRAPS);
+
+ virtual bool is_hidden_from_external_view() const;
+
+ void lock();
+ void unlock();
+};
+
+//
+// The ReferencePendingListLocker is the main interface for locking and
+// unlocking the reference pending list lock, which needs to be held by
+// the GC when adding references to the pending list. Since this is a
+// Java-level monitor it can only be locked/unlocked by a Java thread.
+// For this reason there is an option to spawn a helper thread, the
+// ReferencePendingListLockerThread, during initialization. If a helper
+// thread is spawned all lock operations from non-Java threads will be
+// delegated to the helper thread. The helper thread is typically needed
+// by concurrent GCs.
+//
+class ReferencePendingListLocker VALUE_OBJ_CLASS_SPEC {
+private:
+ static bool _is_initialized;
+ static ReferencePendingListLockerThread* _locker_thread;
+ BasicLock _basic_lock;
+
+public:
+ static void initialize(bool needs_locker_thread, TRAPS);
+ static bool is_initialized();
+
+ static bool is_locked_by_self();
+
+ void lock();
+ void unlock();
+};
+
+#endif // SHARE_VM_GC_SHARED_REFERENCEPENDINGLISTLOCKER_HPP
--- a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -161,8 +161,8 @@
NOT_PRODUCT(
if (now < _soft_ref_timestamp_clock) {
- warning("time warp: " JLONG_FORMAT " to " JLONG_FORMAT,
- _soft_ref_timestamp_clock, now);
+ log_warning(gc)("time warp: " JLONG_FORMAT " to " JLONG_FORMAT,
+ _soft_ref_timestamp_clock, now);
}
)
// The values of now and _soft_ref_timestamp_clock are set using
@@ -266,11 +266,6 @@
#ifndef PRODUCT
// Calculate the number of jni handles.
size_t ReferenceProcessor::count_jni_refs() {
- class AlwaysAliveClosure: public BoolObjectClosure {
- public:
- virtual bool do_object_b(oop obj) { return true; }
- };
-
class CountHandleClosure: public OopClosure {
private:
size_t _count;
@@ -281,8 +276,7 @@
size_t count() { return _count; }
};
CountHandleClosure global_handle_count;
- AlwaysAliveClosure always_alive;
- JNIHandles::weak_oops_do(&always_alive, &global_handle_count);
+ JNIHandles::weak_oops_do(&global_handle_count);
return global_handle_count.count();
}
#endif
@@ -645,9 +639,7 @@
OopClosure& keep_alive,
VoidClosure& complete_gc)
{
- Thread* thr = Thread::current();
- int refs_list_index = ((WorkerThread*)thr)->id();
- _ref_processor.process_phase1(_refs_lists[refs_list_index], _policy,
+ _ref_processor.process_phase1(_refs_lists[i], _policy,
&is_alive, &keep_alive, &complete_gc);
}
private:
@@ -683,11 +675,6 @@
OopClosure& keep_alive,
VoidClosure& complete_gc)
{
- // Don't use "refs_list_index" calculated in this way because
- // balance_queues() has moved the Ref's into the first n queues.
- // Thread* thr = Thread::current();
- // int refs_list_index = ((WorkerThread*)thr)->id();
- // _ref_processor.process_phase3(_refs_lists[refs_list_index], _clear_referent,
_ref_processor.process_phase3(_refs_lists[i], _clear_referent,
&is_alive, &keep_alive, &complete_gc);
}
--- a/hotspot/src/share/vm/gc/shared/spaceDecorator.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/spaceDecorator.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -84,9 +84,7 @@
void SpaceMangler::mangle_region(MemRegion mr) {
assert(ZapUnusedHeapArea, "Mangling should not be in use");
#ifdef ASSERT
- log_develop_trace(gc)("Mangling [" PTR_FORMAT " to " PTR_FORMAT ")", p2i(mr.start()), p2i(mr.end()));
Copy::fill_to_words(mr.start(), mr.word_size(), badHeapWord);
- log_develop_trace(gc)("Mangling done.");
#endif
}
--- a/hotspot/src/share/vm/gc/shared/taskqueue.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/taskqueue.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -248,7 +248,6 @@
template <class E, MEMFLAGS F, unsigned int N = TASKQUEUE_SIZE>
class GenericTaskQueue: public TaskQueueSuper<N, F> {
- ArrayAllocator<E, F> _array_allocator;
protected:
typedef typename TaskQueueSuper<N, F>::Age Age;
typedef typename TaskQueueSuper<N, F>::idx_t idx_t;
--- a/hotspot/src/share/vm/gc/shared/taskqueue.inline.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/taskqueue.inline.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -44,12 +44,13 @@
template<class E, MEMFLAGS F, unsigned int N>
inline void GenericTaskQueue<E, F, N>::initialize() {
- _elems = _array_allocator.allocate(N);
+ _elems = ArrayAllocator<E, F>::allocate(N);
}
template<class E, MEMFLAGS F, unsigned int N>
inline GenericTaskQueue<E, F, N>::~GenericTaskQueue() {
- FREE_C_HEAP_ARRAY(E, _elems);
+ assert(false, "This code is currently never called");
+ ArrayAllocator<E, F>::free(const_cast<E*>(_elems), N);
}
template<class E, MEMFLAGS F, unsigned int N>
--- a/hotspot/src/share/vm/gc/shared/vmGCOperations.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/vmGCOperations.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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
@@ -30,10 +30,8 @@
#include "gc/shared/gcLocker.inline.hpp"
#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/vmGCOperations.hpp"
+#include "logging/log.hpp"
#include "memory/oopFactory.hpp"
-#include "logging/log.hpp"
-#include "oops/instanceKlass.hpp"
-#include "oops/instanceRefKlass.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/interfaceSupport.hpp"
@@ -64,14 +62,11 @@
}
void VM_GC_Operation::acquire_pending_list_lock() {
- // we may enter this with pending exception set
- InstanceRefKlass::acquire_pending_list_lock(&_pending_list_basic_lock);
+ _pending_list_locker.lock();
}
-
void VM_GC_Operation::release_and_notify_pending_list_lock() {
-
- InstanceRefKlass::release_and_notify_pending_list_lock(&_pending_list_basic_lock);
+ _pending_list_locker.unlock();
}
// Allocations may fail in several threads at about the same time,
@@ -160,7 +155,7 @@
// be about to attempt holds value for us only
// if it happens now and not if it happens in the eventual
// future.
- warning("GC locker is held; pre-dump GC was skipped");
+ log_warning(gc)("GC locker is held; pre-dump GC was skipped");
}
}
HeapInspection inspect(_csv_format, _print_help, _print_class_stats,
@@ -276,12 +271,8 @@
return;
}
- // If expansion failed, do a last-ditch collection and try allocating
- // again. A last-ditch collection will clear softrefs. This
- // behavior is similar to the last-ditch collection done for perm
- // gen when it was full and a collection for failed allocation
- // did not free perm gen space.
- heap->collect_as_vm_thread(GCCause::_last_ditch_collection);
+ // If expansion failed, do a collection clearing soft references.
+ heap->collect_as_vm_thread(GCCause::_metadata_GC_clear_soft_refs);
_result = _loader_data->metaspace_non_null()->allocate(_size, _mdtype);
if (_result != NULL) {
return;
--- a/hotspot/src/share/vm/gc/shared/vmGCOperations.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/vmGCOperations.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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,7 @@
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/genCollectedHeap.hpp"
+#include "gc/shared/referencePendingListLocker.hpp"
#include "memory/heapInspection.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/handles.hpp"
@@ -69,8 +70,10 @@
//
class VM_GC_Operation: public VM_Operation {
+ private:
+ ReferencePendingListLocker _pending_list_locker;
+
protected:
- BasicLock _pending_list_basic_lock; // for refs pending list notification (PLL)
uint _gc_count_before; // gc count before acquiring PLL
uint _full_gc_count_before; // full gc count before acquiring PLL
bool _full; // whether a "full" collection
--- a/hotspot/src/share/vm/logging/log.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/logging/log.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -136,4 +136,27 @@
LogConfiguration::parse_log_arguments("stdout", saved_config, NULL, NULL, log.error_stream());
os::free(saved_config);
}
+
+static int Test_logconfiguration_subscribe_triggered = 0;
+
+static void Test_logconfiguration_subscribe_helper() {
+ Test_logconfiguration_subscribe_triggered++;
+}
+
+void Test_logconfiguration_subscribe() {
+ ResourceMark rm;
+ LogHandle(logging) log;
+
+ LogConfiguration::register_update_listener(&Test_logconfiguration_subscribe_helper);
+
+ LogConfiguration::parse_log_arguments("stdout", "logging=trace", NULL, NULL, log.error_stream());
+ assert(Test_logconfiguration_subscribe_triggered == 1, "subscription not triggered (1)");
+
+ LogConfiguration::configure_stdout(LogLevel::Debug, true, LOG_TAGS(gc));
+ assert(Test_logconfiguration_subscribe_triggered == 2, "subscription not triggered (2)");
+
+ LogConfiguration::disable_logging();
+ assert(Test_logconfiguration_subscribe_triggered == 3, "subscription not triggered (3)");
+}
+
#endif // PRODUCT
--- a/hotspot/src/share/vm/logging/logConfiguration.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/logging/logConfiguration.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -40,6 +40,9 @@
LogOutput** LogConfiguration::_outputs = NULL;
size_t LogConfiguration::_n_outputs = 0;
+LogConfiguration::UpdateListenerFunction* LogConfiguration::_listener_callbacks = NULL;
+size_t LogConfiguration::_n_listener_callbacks = 0;
+
// Stack object to take the lock for configuring the logging.
// Should only be held during the critical parts of the configuration
// (when calling configure_output or reading/modifying the outputs array).
@@ -254,6 +257,7 @@
for (size_t i = 0; i < _n_outputs; i++) {
disable_output(i);
}
+ notify_update_listeners();
}
void LogConfiguration::configure_stdout(LogLevelType level, bool exact_match, ...) {
@@ -282,6 +286,7 @@
// Apply configuration to stdout (output #0), with the same decorators as before.
ConfigurationLock cl;
configure_output(0, expr, LogOutput::Stdout->decorators());
+ notify_update_listeners();
}
bool LogConfiguration::parse_command_line_arguments(const char* opts) {
@@ -373,6 +378,7 @@
}
}
configure_output(idx, expr, decorators);
+ notify_update_listeners();
return true;
}
@@ -471,3 +477,20 @@
}
}
+void LogConfiguration::register_update_listener(UpdateListenerFunction cb) {
+ assert(cb != NULL, "Should not register NULL as listener");
+ ConfigurationLock cl;
+ size_t idx = _n_listener_callbacks++;
+ _listener_callbacks = REALLOC_C_HEAP_ARRAY(UpdateListenerFunction,
+ _listener_callbacks,
+ _n_listener_callbacks,
+ mtLogging);
+ _listener_callbacks[idx] = cb;
+}
+
+void LogConfiguration::notify_update_listeners() {
+ assert(ConfigurationLock::current_thread_has_lock(), "notify_update_listeners must be called in ConfigurationLock scope (lock held)");
+ for (size_t i = 0; i < _n_listener_callbacks; i++) {
+ _listener_callbacks[i]();
+ }
+}
--- a/hotspot/src/share/vm/logging/logConfiguration.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/logging/logConfiguration.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -37,10 +37,26 @@
// kept implicitly in the LogTagSets and their LogOutputLists. During configuration the tagsets
// are iterated over and updated accordingly.
class LogConfiguration : public AllStatic {
+ public:
+ // Function for listeners
+ typedef void (*UpdateListenerFunction)(void);
+
+ // Register callback for config change.
+ // The callback is always called with ConfigurationLock held,
+ // hence doing log reconfiguration from the callback will deadlock.
+ // The main Java thread may call this callback if there is an early registration
+ // else the attach listener JavaThread, started via diagnostic command, will be executing thread.
+ // The main purpose of this callback is to see if a loglevel have been changed.
+ // There is no way to unregister.
+ static void register_update_listener(UpdateListenerFunction cb);
+
private:
static LogOutput** _outputs;
static size_t _n_outputs;
+ static UpdateListenerFunction* _listener_callbacks;
+ static size_t _n_listener_callbacks;
+
// Create a new output. Returns NULL if failed.
static LogOutput* new_output(char* name, const char* options, outputStream* errstream);
@@ -60,6 +76,9 @@
// Configure output (add or update existing configuration) to log on tag-level combination using specified decorators.
static void configure_output(size_t idx, const LogTagLevelExpression& tag_level_expression, const LogDecorators& decorators);
+ // This should be called after any configuration change while still holding ConfigurationLock
+ static void notify_update_listeners();
+
public:
// Initialization and finalization of log configuration, to be run at vm startup and shutdown respectively.
static void initialize(jlong vm_start_time);
--- a/hotspot/src/share/vm/logging/logFileOutput.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/logging/logFileOutput.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -64,7 +64,7 @@
}
if (fclose(_stream) != 0) {
jio_fprintf(defaultStream::error_stream(), "Could not close log file '%s' (%s).\n",
- _file_name, strerror(errno));
+ _file_name, os::strerror(errno));
}
}
os::free(_archive_name);
@@ -139,7 +139,7 @@
}
_stream = fopen(_file_name, FileOpenMode);
if (_stream == NULL) {
- log_error(logging)("Could not open log file '%s' (%s).\n", _file_name, strerror(errno));
+ log_error(logging)("Could not open log file '%s' (%s).\n", _file_name, os::strerror(errno));
return false;
}
return true;
@@ -176,7 +176,7 @@
// Rename the file from ex hotspot.log to hotspot.log.2
if (rename(_file_name, _archive_name) == -1) {
jio_fprintf(defaultStream::error_stream(), "Could not rename log file '%s' to '%s' (%s).\n",
- _file_name, _archive_name, strerror(errno));
+ _file_name, _archive_name, os::strerror(errno));
}
}
@@ -194,7 +194,7 @@
if (fclose(_stream)) {
jio_fprintf(defaultStream::error_stream(), "Error closing file '%s' during log rotation (%s).\n",
- _file_name, strerror(errno));
+ _file_name, os::strerror(errno));
}
// Archive the current log file
@@ -204,7 +204,7 @@
_stream = fopen(_file_name, FileOpenMode);
if (_stream == NULL) {
jio_fprintf(defaultStream::error_stream(), "Could not reopen file '%s' during log rotation (%s).\n",
- _file_name, strerror(errno));
+ _file_name, os::strerror(errno));
return;
}
--- a/hotspot/src/share/vm/logging/logPrefix.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/logging/logPrefix.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -45,16 +45,17 @@
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, barrier)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, classhisto)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, compaction)) \
- LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, compaction, phases)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, cpu)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ergo)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ergo, cset)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ergo, heap)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ergo, ihop)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, heap)) \
+ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, heap, region)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, freelist)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ihop)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, liveness)) \
+ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, marking)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, metaspace)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, start)) \
--- a/hotspot/src/share/vm/logging/logTag.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/logging/logTag.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -24,6 +24,7 @@
#ifndef SHARE_VM_LOGGING_LOGTAG_HPP
#define SHARE_VM_LOGGING_LOGTAG_HPP
+#include "logging/logTag_ext.hpp"
#include "memory/allocation.hpp"
#include "utilities/globalDefinitions.hpp"
@@ -67,28 +68,34 @@
LOG_TAG(phases) \
LOG_TAG(plab) \
LOG_TAG(promotion) \
+ LOG_TAG(preorder) /* Trace all classes loaded in order referenced (not loaded) */ \
LOG_TAG(protectiondomain) /* "Trace protection domain verification" */ \
LOG_TAG(ref) \
LOG_TAG(refine) \
LOG_TAG(region) \
LOG_TAG(remset) \
LOG_TAG(safepoint) \
+ LOG_TAG(safepointcleanup) \
LOG_TAG(scavenge) \
LOG_TAG(scrub) \
+ LOG_TAG(stacktrace) \
LOG_TAG(start) \
LOG_TAG(startuptime) \
LOG_TAG(state) \
LOG_TAG(stats) \
LOG_TAG(stringdedup) \
+ LOG_TAG(stringtable) \
LOG_TAG(survivor) \
LOG_TAG(sweep) \
LOG_TAG(task) \
LOG_TAG(thread) \
LOG_TAG(tlab) \
LOG_TAG(time) \
+ LOG_TAG(verboseverification) \
LOG_TAG(verify) \
LOG_TAG(vmoperation) \
- LOG_TAG(vtables)
+ LOG_TAG(vtables) \
+ LOG_TAG_LIST_EXT
#define PREFIX_LOG_TAG(T) (LogTag::_##T)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/logging/logTag_ext.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016, 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_LOGGING_LOGTAG_EXT_HPP
+#define SHARE_VM_LOGGING_LOGTAG_EXT_HPP
+
+#define LOG_TAG_LIST_EXT
+
+#endif // SHARE_VM_LOGGING_LOGTAG_EXT_HPP
--- a/hotspot/src/share/vm/memory/allocation.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/memory/allocation.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -242,7 +242,7 @@
ChunkPool(size_t size) : _size(size) { _first = NULL; _num_chunks = _num_used = 0; }
// Allocate a new chunk from the pool (might expand the pool)
- _NOINLINE_ void* allocate(size_t bytes, AllocFailType alloc_failmode) {
+ NOINLINE void* allocate(size_t bytes, AllocFailType alloc_failmode) {
assert(bytes == _size, "bad size");
void* p = NULL;
// No VM lock can be taken inside ThreadCritical lock, so os::malloc
--- a/hotspot/src/share/vm/memory/allocation.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/memory/allocation.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -41,18 +41,6 @@
#define ARENA_ALIGN_MASK (~((size_t)ARENA_ALIGN_M1))
#define ARENA_ALIGN(x) ((((size_t)(x)) + ARENA_ALIGN_M1) & ARENA_ALIGN_MASK)
-
-// noinline attribute
-#ifdef _WINDOWS
- #define _NOINLINE_ __declspec(noinline)
-#else
- #if __GNUC__ < 3 // gcc 2.x does not support noinline attribute
- #define _NOINLINE_
- #else
- #define _NOINLINE_ __attribute__ ((noinline))
- #endif
-#endif
-
class AllocFailStrategy {
public:
enum AllocFailEnum { EXIT_OOM, RETURN_NULL };
@@ -178,17 +166,17 @@
template <MEMFLAGS F> class CHeapObj ALLOCATION_SUPER_CLASS_SPEC {
public:
- _NOINLINE_ void* operator new(size_t size, const NativeCallStack& stack) throw();
- _NOINLINE_ void* operator new(size_t size) throw();
- _NOINLINE_ void* operator new (size_t size, const std::nothrow_t& nothrow_constant,
+ NOINLINE void* operator new(size_t size, const NativeCallStack& stack) throw();
+ NOINLINE void* operator new(size_t size) throw();
+ NOINLINE void* operator new (size_t size, const std::nothrow_t& nothrow_constant,
const NativeCallStack& stack) throw();
- _NOINLINE_ void* operator new (size_t size, const std::nothrow_t& nothrow_constant)
+ NOINLINE void* operator new (size_t size, const std::nothrow_t& nothrow_constant)
throw();
- _NOINLINE_ void* operator new [](size_t size, const NativeCallStack& stack) throw();
- _NOINLINE_ void* operator new [](size_t size) throw();
- _NOINLINE_ void* operator new [](size_t size, const std::nothrow_t& nothrow_constant,
+ NOINLINE void* operator new [](size_t size, const NativeCallStack& stack) throw();
+ NOINLINE void* operator new [](size_t size) throw();
+ NOINLINE void* operator new [](size_t size, const std::nothrow_t& nothrow_constant,
const NativeCallStack& stack) throw();
- _NOINLINE_ void* operator new [](size_t size, const std::nothrow_t& nothrow_constant)
+ NOINLINE void* operator new [](size_t size, const std::nothrow_t& nothrow_constant)
throw();
void operator delete(void* p);
void operator delete [] (void* p);
@@ -724,30 +712,42 @@
// is set so that we always use malloc except for Solaris where we set the
// limit to get mapped memory.
template <class E, MEMFLAGS F>
-class ArrayAllocator VALUE_OBJ_CLASS_SPEC {
- char* _addr;
- bool _use_malloc;
- size_t _size;
- bool _free_in_destructor;
+class ArrayAllocator : public AllStatic {
+ private:
+ static bool should_use_malloc(size_t length);
- static bool should_use_malloc(size_t size) {
- return size < ArrayAllocatorMallocLimit;
- }
+ static E* allocate_malloc(size_t length);
+ static E* allocate_mmap(size_t length);
- static char* allocate_inner(size_t& size, bool& use_malloc);
+ static void free_malloc(E* addr, size_t length);
+ static void free_mmap(E* addr, size_t length);
+
public:
- ArrayAllocator(bool free_in_destructor = true) :
- _addr(NULL), _use_malloc(false), _size(0), _free_in_destructor(free_in_destructor) { }
+ static E* allocate(size_t length);
+ static E* reallocate(E* old_addr, size_t old_length, size_t new_length);
+ static void free(E* addr, size_t length);
+};
+
+// Uses mmaped memory for all allocations. All allocations are initially
+// zero-filled. No pre-touching.
+template <class E, MEMFLAGS F>
+class MmapArrayAllocator : public AllStatic {
+ private:
+ static size_t size_for(size_t length);
- ~ArrayAllocator() {
- if (_free_in_destructor) {
- free();
- }
- }
+ public:
+ static E* allocate(size_t length);
+ static void free(E* addr, size_t length);
+};
- E* allocate(size_t length);
- E* reallocate(size_t new_length);
- void free();
+// Uses malloc:ed memory for all allocations.
+template <class E, MEMFLAGS F>
+class MallocArrayAllocator : public AllStatic {
+ public:
+ static size_t size_for(size_t length);
+
+ static E* allocate(size_t length);
+ static void free(E* addr, size_t length);
};
#endif // SHARE_VM_MEMORY_ALLOCATION_HPP
--- a/hotspot/src/share/vm/memory/allocation.inline.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/memory/allocation.inline.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -151,66 +151,107 @@
}
template <class E, MEMFLAGS F>
-char* ArrayAllocator<E, F>::allocate_inner(size_t &size, bool &use_malloc) {
- char* addr = NULL;
+size_t MmapArrayAllocator<E, F>::size_for(size_t length) {
+ size_t size = length * sizeof(E);
+ int alignment = os::vm_allocation_granularity();
+ return align_size_up(size, alignment);
+}
- if (use_malloc) {
- addr = AllocateHeap(size, F);
- if (addr == NULL && size >= (size_t)os::vm_allocation_granularity()) {
- // malloc failed let's try with mmap instead
- use_malloc = false;
- } else {
- return addr;
- }
- }
+template <class E, MEMFLAGS F>
+E* MmapArrayAllocator<E, F>::allocate(size_t length) {
+ size_t size = size_for(length);
+ int alignment = os::vm_allocation_granularity();
- int alignment = os::vm_allocation_granularity();
- size = align_size_up(size, alignment);
-
- addr = os::reserve_memory(size, NULL, alignment, F);
+ char* addr = os::reserve_memory(size, NULL, alignment, F);
if (addr == NULL) {
vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "Allocator (reserve)");
}
os::commit_memory_or_exit(addr, size, !ExecMem, "Allocator (commit)");
- return addr;
+
+ return (E*)addr;
+}
+
+template <class E, MEMFLAGS F>
+void MmapArrayAllocator<E, F>::free(E* addr, size_t length) {
+ bool result = os::release_memory((char*)addr, size_for(length));
+ assert(result, "Failed to release memory");
+}
+
+template <class E, MEMFLAGS F>
+size_t MallocArrayAllocator<E, F>::size_for(size_t length) {
+ return length * sizeof(E);
+}
+
+template <class E, MEMFLAGS F>
+E* MallocArrayAllocator<E, F>::allocate(size_t length) {
+ return (E*)AllocateHeap(size_for(length), F);
+}
+
+template<class E, MEMFLAGS F>
+void MallocArrayAllocator<E, F>::free(E* addr, size_t /*length*/) {
+ FreeHeap(addr);
+}
+
+template <class E, MEMFLAGS F>
+bool ArrayAllocator<E, F>::should_use_malloc(size_t length) {
+ return MallocArrayAllocator<E, F>::size_for(length) < ArrayAllocatorMallocLimit;
+}
+
+template <class E, MEMFLAGS F>
+E* ArrayAllocator<E, F>::allocate_malloc(size_t length) {
+ return MallocArrayAllocator<E, F>::allocate(length);
+}
+
+template <class E, MEMFLAGS F>
+E* ArrayAllocator<E, F>::allocate_mmap(size_t length) {
+ return MmapArrayAllocator<E, F>::allocate(length);
}
template <class E, MEMFLAGS F>
E* ArrayAllocator<E, F>::allocate(size_t length) {
- assert(_addr == NULL, "Already in use");
+ if (should_use_malloc(length)) {
+ return allocate_malloc(length);
+ }
- _size = sizeof(E) * length;
- _use_malloc = should_use_malloc(_size);
- _addr = allocate_inner(_size, _use_malloc);
-
- return (E*)_addr;
+ return allocate_mmap(length);
}
template <class E, MEMFLAGS F>
-E* ArrayAllocator<E, F>::reallocate(size_t new_length) {
- size_t new_size = sizeof(E) * new_length;
- bool use_malloc = should_use_malloc(new_size);
- char* new_addr = allocate_inner(new_size, use_malloc);
+E* ArrayAllocator<E, F>::reallocate(E* old_addr, size_t old_length, size_t new_length) {
+ E* new_addr = (new_length > 0)
+ ? allocate(new_length)
+ : NULL;
- memcpy(new_addr, _addr, MIN2(new_size, _size));
+ if (new_addr != NULL && old_addr != NULL) {
+ memcpy(new_addr, old_addr, MIN2(old_length, new_length) * sizeof(E));
+ }
- free();
- _size = new_size;
- _use_malloc = use_malloc;
- _addr = new_addr;
- return (E*)new_addr;
+ if (old_addr != NULL) {
+ free(old_addr, old_length);
+ }
+
+ return new_addr;
}
template<class E, MEMFLAGS F>
-void ArrayAllocator<E, F>::free() {
- if (_addr != NULL) {
- if (_use_malloc) {
- FreeHeap(_addr);
+void ArrayAllocator<E, F>::free_malloc(E* addr, size_t length) {
+ MallocArrayAllocator<E, F>::free(addr, length);
+}
+
+template<class E, MEMFLAGS F>
+void ArrayAllocator<E, F>::free_mmap(E* addr, size_t length) {
+ MmapArrayAllocator<E, F>::free(addr, length);
+}
+
+template<class E, MEMFLAGS F>
+void ArrayAllocator<E, F>::free(E* addr, size_t length) {
+ if (addr != NULL) {
+ if (should_use_malloc(length)) {
+ free_malloc(addr, length);
} else {
- os::release_memory(_addr, _size);
+ free_mmap(addr, length);
}
- _addr = NULL;
}
}
--- a/hotspot/src/share/vm/memory/filemap.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/memory/filemap.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -363,7 +363,7 @@
fail_continue("Specified shared archive not found.");
} else {
fail_continue("Failed to open shared archive file (%s).",
- strerror(errno));
+ os::strerror(errno));
}
return false;
}
@@ -393,7 +393,7 @@
int fd = open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0444);
if (fd < 0) {
fail_stop("Unable to create shared archive file %s: (%s).", _full_path,
- strerror(errno));
+ os::strerror(errno));
}
_fd = fd;
_file_offset = 0;
--- a/hotspot/src/share/vm/memory/iterator.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/memory/iterator.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -213,6 +213,16 @@
virtual bool do_object_b(oop obj) = 0;
};
+class AlwaysTrueClosure: public BoolObjectClosure {
+ public:
+ bool do_object_b(oop p) { return true; }
+};
+
+class AlwaysFalseClosure : public BoolObjectClosure {
+ public:
+ bool do_object_b(oop p) { return false; }
+};
+
// Applies an oop closure to all ref fields in objects iterated over in an
// object iteration.
class ObjectToOopClosure: public ObjectClosure {
--- a/hotspot/src/share/vm/memory/metaspace.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/memory/metaspace.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -759,7 +759,6 @@
void verify();
void verify_chunk_size(Metachunk* chunk);
- NOT_PRODUCT(void mangle_freed_chunks();)
#ifdef ASSERT
void verify_allocated_blocks_words();
#endif
@@ -1574,7 +1573,7 @@
} else {
_shrink_factor = MIN2(current_shrink_factor * 4, (uint) 100);
}
- log_trace(gc, metaspace)(" shrinking: initSize: %.1fK maximum_desired_capacity: %.1fK",
+ log_trace(gc, metaspace)(" shrinking: initThreshold: %.1fK maximum_desired_capacity: %.1fK",
MetaspaceSize / (double) K, maximum_desired_capacity / (double) K);
log_trace(gc, metaspace)(" shrink_bytes: %.1fK current_shrink_factor: %d new shrink factor: %d MinMetaspaceExpansion: %.1fK",
shrink_bytes / (double) K, current_shrink_factor, _shrink_factor, MinMetaspaceExpansion / (double) K);
@@ -2519,20 +2518,6 @@
" waste " SIZE_FORMAT, curr_total, used, free, capacity, waste);
}
-#ifndef PRODUCT
-void SpaceManager::mangle_freed_chunks() {
- for (ChunkIndex index = ZeroIndex;
- index < NumberOfInUseLists;
- index = next_chunk_index(index)) {
- for (Metachunk* curr = chunks_in_use(index);
- curr != NULL;
- curr = curr->next()) {
- curr->mangle();
- }
- }
-}
-#endif // PRODUCT
-
// MetaspaceAux
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -879,7 +879,7 @@
InstanceKlass* ik = InstanceKlass::cast(klass);
- // Should be class load order as per -XX:+TraceClassLoadingPreorder
+ // Should be class load order as per -Xlog:classload+preorder
class_promote_order->append(ik);
// Link the class to cause the bytecodes to be rewritten and the
--- a/hotspot/src/share/vm/memory/universe.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/memory/universe.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -376,8 +376,7 @@
// We can allocate directly in the permanent generation, so we do.
int size;
if (UseConcMarkSweepGC) {
- warning("Using +FullGCALot with concurrent mark sweep gc "
- "will not force all objects to relocate");
+ log_warning(gc)("Using +FullGCALot with concurrent mark sweep gc will not force all objects to relocate");
size = FullGCALotDummies;
} else {
size = FullGCALotDummies * 2;
@@ -1094,19 +1093,19 @@
void Universe::print_heap_before_gc() {
LogHandle(gc, heap) log;
- if (log.is_trace()) {
- log.trace("Heap before GC invocations=%u (full %u):", heap()->total_collections(), heap()->total_full_collections());
+ if (log.is_debug()) {
+ log.debug("Heap before GC invocations=%u (full %u):", heap()->total_collections(), heap()->total_full_collections());
ResourceMark rm;
- heap()->print_on(log.trace_stream());
+ heap()->print_on(log.debug_stream());
}
}
void Universe::print_heap_after_gc() {
LogHandle(gc, heap) log;
- if (log.is_trace()) {
- log.trace("Heap after GC invocations=%u (full %u):", heap()->total_collections(), heap()->total_full_collections());
+ if (log.is_debug()) {
+ log.debug("Heap after GC invocations=%u (full %u):", heap()->total_collections(), heap()->total_full_collections());
ResourceMark rm;
- heap()->print_on(log.trace_stream());
+ heap()->print_on(log.debug_stream());
}
}
--- a/hotspot/src/share/vm/oops/constantPool.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/oops/constantPool.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -208,11 +208,11 @@
if (k() != this_cp->pool_holder()) {
// only print something if the classes are different
if (source_file != NULL) {
- log_info(classresolve)("%s %s %s:%d",
+ log_debug(classresolve)("%s %s %s:%d",
this_cp->pool_holder()->external_name(),
k->external_name(), source_file, line_number);
} else {
- log_info(classresolve)("%s %s",
+ log_debug(classresolve)("%s %s",
this_cp->pool_holder()->external_name(),
k->external_name());
}
@@ -281,15 +281,10 @@
ClassLoaderData* this_key = this_cp->pool_holder()->class_loader_data();
this_key->record_dependency(k(), CHECK_NULL); // Can throw OOM
- if (log_is_enabled(Info, classresolve) && !k->is_array_klass()) {
- // skip resolving the constant pool so that this code gets
- // called the next time some bytecodes refer to this class.
- trace_class_resolution(this_cp, k);
- return k();
- } else {
- this_cp->klass_at_put(which, k());
- }
+ // logging for classresolve tag.
+ trace_class_resolution(this_cp, k);
+ this_cp->klass_at_put(which, k());
entry = this_cp->resolved_klass_at(which);
assert(entry.is_resolved() && entry.get_klass()->is_klass(), "must be resolved at this point");
return entry.get_klass();
--- a/hotspot/src/share/vm/oops/instanceKlass.inline.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/oops/instanceKlass.inline.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -36,16 +36,9 @@
// The iteration over the oops in objects is a hot path in the GC code.
// By force inlining the following functions, we get similar GC performance
// as the previous macro based implementation.
-#ifdef TARGET_COMPILER_visCPP
-#define INLINE __forceinline
-#elif defined(TARGET_COMPILER_sparcWorks)
-#define INLINE __attribute__((always_inline))
-#else
-#define INLINE inline
-#endif
template <bool nv, typename T, class OopClosureType>
-INLINE void InstanceKlass::oop_oop_iterate_oop_map(OopMapBlock* map, oop obj, OopClosureType* closure) {
+ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_map(OopMapBlock* map, oop obj, OopClosureType* closure) {
T* p = (T*)obj->obj_field_addr<T>(map->offset());
T* const end = p + map->count();
@@ -56,7 +49,7 @@
#if INCLUDE_ALL_GCS
template <bool nv, typename T, class OopClosureType>
-INLINE void InstanceKlass::oop_oop_iterate_oop_map_reverse(OopMapBlock* map, oop obj, OopClosureType* closure) {
+ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_map_reverse(OopMapBlock* map, oop obj, OopClosureType* closure) {
T* const start = (T*)obj->obj_field_addr<T>(map->offset());
T* p = start + map->count();
@@ -68,7 +61,7 @@
#endif
template <bool nv, typename T, class OopClosureType>
-INLINE void InstanceKlass::oop_oop_iterate_oop_map_bounded(OopMapBlock* map, oop obj, OopClosureType* closure, MemRegion mr) {
+ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_map_bounded(OopMapBlock* map, oop obj, OopClosureType* closure, MemRegion mr) {
T* p = (T*)obj->obj_field_addr<T>(map->offset());
T* end = p + map->count();
@@ -91,7 +84,7 @@
}
template <bool nv, typename T, class OopClosureType>
-INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized(oop obj, OopClosureType* closure) {
+ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized(oop obj, OopClosureType* closure) {
OopMapBlock* map = start_of_nonstatic_oop_maps();
OopMapBlock* const end_map = map + nonstatic_oop_map_count();
@@ -102,7 +95,7 @@
#if INCLUDE_ALL_GCS
template <bool nv, typename T, class OopClosureType>
-INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized_reverse(oop obj, OopClosureType* closure) {
+ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized_reverse(oop obj, OopClosureType* closure) {
OopMapBlock* const start_map = start_of_nonstatic_oop_maps();
OopMapBlock* map = start_map + nonstatic_oop_map_count();
@@ -114,7 +107,7 @@
#endif
template <bool nv, typename T, class OopClosureType>
-INLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized_bounded(oop obj, OopClosureType* closure, MemRegion mr) {
+ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_maps_specialized_bounded(oop obj, OopClosureType* closure, MemRegion mr) {
OopMapBlock* map = start_of_nonstatic_oop_maps();
OopMapBlock* const end_map = map + nonstatic_oop_map_count();
@@ -124,7 +117,7 @@
}
template <bool nv, class OopClosureType>
-INLINE void InstanceKlass::oop_oop_iterate_oop_maps(oop obj, OopClosureType* closure) {
+ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_maps(oop obj, OopClosureType* closure) {
if (UseCompressedOops) {
oop_oop_iterate_oop_maps_specialized<nv, narrowOop>(obj, closure);
} else {
@@ -134,7 +127,7 @@
#if INCLUDE_ALL_GCS
template <bool nv, class OopClosureType>
-INLINE void InstanceKlass::oop_oop_iterate_oop_maps_reverse(oop obj, OopClosureType* closure) {
+ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_maps_reverse(oop obj, OopClosureType* closure) {
if (UseCompressedOops) {
oop_oop_iterate_oop_maps_specialized_reverse<nv, narrowOop>(obj, closure);
} else {
@@ -144,7 +137,7 @@
#endif
template <bool nv, class OopClosureType>
-INLINE void InstanceKlass::oop_oop_iterate_oop_maps_bounded(oop obj, OopClosureType* closure, MemRegion mr) {
+ALWAYSINLINE void InstanceKlass::oop_oop_iterate_oop_maps_bounded(oop obj, OopClosureType* closure, MemRegion mr) {
if (UseCompressedOops) {
oop_oop_iterate_oop_maps_specialized_bounded<nv, narrowOop>(obj, closure, mr);
} else {
@@ -153,7 +146,7 @@
}
template <bool nv, class OopClosureType>
-INLINE int InstanceKlass::oop_oop_iterate(oop obj, OopClosureType* closure) {
+ALWAYSINLINE int InstanceKlass::oop_oop_iterate(oop obj, OopClosureType* closure) {
if (Devirtualizer<nv>::do_metadata(closure)) {
Devirtualizer<nv>::do_klass(closure, this);
}
@@ -165,7 +158,7 @@
#if INCLUDE_ALL_GCS
template <bool nv, class OopClosureType>
-INLINE int InstanceKlass::oop_oop_iterate_reverse(oop obj, OopClosureType* closure) {
+ALWAYSINLINE int InstanceKlass::oop_oop_iterate_reverse(oop obj, OopClosureType* closure) {
assert(!Devirtualizer<nv>::do_metadata(closure),
"Code to handle metadata is not implemented");
@@ -176,7 +169,7 @@
#endif
template <bool nv, class OopClosureType>
-INLINE int InstanceKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) {
+ALWAYSINLINE int InstanceKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) {
if (Devirtualizer<nv>::do_metadata(closure)) {
if (mr.contains(obj)) {
Devirtualizer<nv>::do_klass(closure, this);
@@ -188,8 +181,6 @@
return size_helper();
}
-#undef INLINE
-
#define ALL_INSTANCE_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \
OOP_OOP_ITERATE_DEFN( InstanceKlass, OopClosureType, nv_suffix) \
OOP_OOP_ITERATE_DEFN_BOUNDED( InstanceKlass, OopClosureType, nv_suffix) \
--- a/hotspot/src/share/vm/oops/instanceRefKlass.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/oops/instanceRefKlass.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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,13 +25,8 @@
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
-#include "gc/shared/collectedHeap.inline.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
-#include "gc/shared/specialized_oop_closures.hpp"
#include "oops/instanceRefKlass.inline.hpp"
#include "oops/oop.inline.hpp"
-#include "utilities/macros.hpp"
-#include "utilities/preserveException.hpp"
void InstanceRefKlass::update_nonstatic_oop_maps(Klass* k) {
// Clear the nonstatic oop-map entries corresponding to referent
@@ -87,48 +82,3 @@
guarantee(InstanceKlass::cast(next->klass())->is_reference_instance_klass(), "next field verify failed");
}
}
-
-bool InstanceRefKlass::owns_pending_list_lock(JavaThread* thread) {
- if (java_lang_ref_Reference::pending_list_lock() == NULL) return false;
- Handle h_lock(thread, java_lang_ref_Reference::pending_list_lock());
- return ObjectSynchronizer::current_thread_holds_lock(thread, h_lock);
-}
-
-void InstanceRefKlass::acquire_pending_list_lock(BasicLock *pending_list_basic_lock) {
- // we may enter this with pending exception set
- PRESERVE_EXCEPTION_MARK; // exceptions are never thrown, needed for TRAPS argument
-
- // Create a HandleMark in case we retry a GC multiple times.
- // Each time we attempt the GC, we allocate the handle below
- // to hold the pending list lock. We want to free this handle.
- HandleMark hm;
-
- Handle h_lock(THREAD, java_lang_ref_Reference::pending_list_lock());
- ObjectSynchronizer::fast_enter(h_lock, pending_list_basic_lock, false, THREAD);
- assert(ObjectSynchronizer::current_thread_holds_lock(
- JavaThread::current(), h_lock),
- "Locking should have succeeded");
- if (HAS_PENDING_EXCEPTION) CLEAR_PENDING_EXCEPTION;
-}
-
-void InstanceRefKlass::release_and_notify_pending_list_lock(
- BasicLock *pending_list_basic_lock) {
- // we may enter this with pending exception set
- PRESERVE_EXCEPTION_MARK; // exceptions are never thrown, needed for TRAPS argument
-
- // Create a HandleMark in case we retry a GC multiple times.
- // Each time we attempt the GC, we allocate the handle below
- // to hold the pending list lock. We want to free this handle.
- HandleMark hm;
-
- Handle h_lock(THREAD, java_lang_ref_Reference::pending_list_lock());
- assert(ObjectSynchronizer::current_thread_holds_lock(
- JavaThread::current(), h_lock),
- "Lock should be held");
- // Notify waiters on pending lists lock if there is any reference.
- if (java_lang_ref_Reference::pending_list() != NULL) {
- ObjectSynchronizer::notifyall(h_lock, THREAD);
- }
- ObjectSynchronizer::fast_exit(h_lock(), pending_list_basic_lock, THREAD);
- if (HAS_PENDING_EXCEPTION) CLEAR_PENDING_EXCEPTION;
-}
--- a/hotspot/src/share/vm/oops/instanceRefKlass.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/oops/instanceRefKlass.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -118,10 +118,6 @@
ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL_BACKWARDS)
#endif // INCLUDE_ALL_GCS
- static void release_and_notify_pending_list_lock(BasicLock *pending_list_basic_lock);
- static void acquire_pending_list_lock(BasicLock *pending_list_basic_lock);
- static bool owns_pending_list_lock(JavaThread* thread);
-
// Update non-static oop maps so 'referent', 'nextPending' and
// 'discovered' will look like non-oops
static void update_nonstatic_oop_maps(Klass* k);
--- a/hotspot/src/share/vm/oops/method.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/oops/method.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -30,6 +30,7 @@
#include "gc/shared/collectedHeap.inline.hpp"
#include "gc/shared/gcLocker.hpp"
#include "gc/shared/generation.hpp"
+#include "gc/shared/referencePendingListLocker.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/bytecodeTracer.hpp"
#include "interpreter/bytecodes.hpp"
@@ -374,7 +375,7 @@
// Do not profile method if current thread holds the pending list lock,
// which avoids deadlock for acquiring the MethodData_lock.
- if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) {
+ if (ReferencePendingListLocker::is_locked_by_self()) {
return;
}
--- a/hotspot/src/share/vm/prims/jni.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/prims/jni.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -347,7 +347,7 @@
&st,
CHECK_NULL);
- if (log_is_enabled(Info, classresolve) && k != NULL) {
+ if (log_is_enabled(Debug, classresolve) && k != NULL) {
trace_class_resolution(k);
}
@@ -417,7 +417,7 @@
result = find_class_from_class_loader(env, sym, true, loader,
protection_domain, true, thread);
- if (log_is_enabled(Info, classresolve) && result != NULL) {
+ if (log_is_enabled(Debug, classresolve) && result != NULL) {
trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result)));
}
@@ -3269,7 +3269,7 @@
TempNewSymbol sym = SymbolTable::new_symbol(name, CHECK_NULL);
jclass result = find_class_from_class_loader(env, sym, true, loader, protection_domain, true, CHECK_NULL);
- if (log_is_enabled(Info, classresolve) && result != NULL) {
+ if (log_is_enabled(Debug, classresolve) && result != NULL) {
trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result)));
}
return result;
--- a/hotspot/src/share/vm/prims/jvm.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/prims/jvm.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -206,9 +206,9 @@
const char * to = to_class->external_name();
// print in a single call to reduce interleaving between threads
if (source_file != NULL) {
- log_info(classresolve)("%s %s %s:%d (%s)", from, to, source_file, line_number, trace);
+ log_debug(classresolve)("%s %s %s:%d (%s)", from, to, source_file, line_number, trace);
} else {
- log_info(classresolve)("%s %s (%s)", from, to, trace);
+ log_debug(classresolve)("%s %s (%s)", from, to, trace);
}
}
}
@@ -514,19 +514,13 @@
JVM_END
-JVM_ENTRY(jint, JVM_GetStackTraceDepth(JNIEnv *env, jobject throwable))
- JVMWrapper("JVM_GetStackTraceDepth");
- oop exception = JNIHandles::resolve(throwable);
- return java_lang_Throwable::get_stack_trace_depth(exception, THREAD);
-JVM_END
-
-
-JVM_ENTRY(jobject, JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint index))
- JVMWrapper("JVM_GetStackTraceElement");
- JvmtiVMObjectAllocEventCollector oam; // This ctor (throughout this module) may trigger a safepoint/GC
- oop exception = JNIHandles::resolve(throwable);
- oop element = java_lang_Throwable::get_stack_trace_element(exception, index, CHECK_NULL);
- return JNIHandles::make_local(env, element);
+JVM_ENTRY(void, JVM_GetStackTraceElements(JNIEnv *env, jobject throwable, jobjectArray stackTrace))
+ JVMWrapper("JVM_GetStackTraceElements");
+ Handle exception(THREAD, JNIHandles::resolve(throwable));
+ objArrayOop st = objArrayOop(JNIHandles::resolve(stackTrace));
+ objArrayHandle stack_trace(THREAD, st);
+ // Fill in the allocated stack trace
+ java_lang_Throwable::get_stack_trace_elements(exception, stack_trace, CHECK);
JVM_END
@@ -835,7 +829,7 @@
return NULL;
}
- if (log_is_enabled(Info, classresolve)) {
+ if (log_is_enabled(Debug, classresolve)) {
trace_class_resolution(k);
}
return (jclass) JNIHandles::make_local(env, k->java_mirror());
@@ -872,7 +866,7 @@
jclass result = find_class_from_class_loader(env, h_name, init, h_loader,
h_prot, false, THREAD);
- if (log_is_enabled(Info, classresolve) && result != NULL) {
+ if (log_is_enabled(Debug, classresolve) && result != NULL) {
trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result)));
}
return result;
@@ -902,7 +896,7 @@
jclass result = find_class_from_class_loader(env, h_name, init, h_loader,
h_prot, true, thread);
- if (log_is_enabled(Info, classresolve) && result != NULL) {
+ if (log_is_enabled(Debug, classresolve) && result != NULL) {
// this function is generally only used for class loading during verification.
ResourceMark rm;
oop from_mirror = JNIHandles::resolve_non_null(from);
@@ -912,7 +906,7 @@
oop mirror = JNIHandles::resolve_non_null(result);
Klass* to_class = java_lang_Class::as_Klass(mirror);
const char * to = to_class->external_name();
- log_info(classresolve)("%s %s (verification)", from_name, to);
+ log_debug(classresolve)("%s %s (verification)", from_name, to);
}
return result;
@@ -980,7 +974,7 @@
&st,
CHECK_NULL);
- if (log_is_enabled(Info, classresolve) && k != NULL) {
+ if (log_is_enabled(Debug, classresolve) && k != NULL) {
trace_class_resolution(k);
}
--- a/hotspot/src/share/vm/prims/jvm.h Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/prims/jvm.h Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -201,11 +201,8 @@
JNIEXPORT void JNICALL
JVM_FillInStackTrace(JNIEnv *env, jobject throwable);
-JNIEXPORT jint JNICALL
-JVM_GetStackTraceDepth(JNIEnv *env, jobject throwable);
-
-JNIEXPORT jobject JNICALL
-JVM_GetStackTraceElement(JNIEnv *env, jobject throwable, jint index);
+JNIEXPORT void JNICALL
+JVM_GetStackTraceElements(JNIEnv *env, jobject throwable, jobjectArray elements);
/*
* java.lang.StackWalker
--- a/hotspot/src/share/vm/prims/whitebox.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/prims/whitebox.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -33,6 +33,7 @@
#include "jvmtifiles/jvmtiEnv.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceShared.hpp"
+#include "memory/iterator.hpp"
#include "memory/universe.hpp"
#include "oops/constantPool.hpp"
#include "oops/oop.inline.hpp"
@@ -711,11 +712,6 @@
return result;
WB_END
-class AlwaysFalseClosure : public BoolObjectClosure {
- public:
- bool do_object_b(oop p) { return false; }
-};
-
static AlwaysFalseClosure always_false;
WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
@@ -991,7 +987,7 @@
WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o))
Universe::heap()->collector_policy()->set_should_clear_all_soft_refs(true);
- Universe::heap()->collect(GCCause::_last_ditch_collection);
+ Universe::heap()->collect(GCCause::_wb_full_gc);
#if INCLUDE_ALL_GCS
if (UseG1GC) {
// Needs to be cleared explicitly for G1
--- a/hotspot/src/share/vm/runtime/arguments.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -405,14 +405,16 @@
};
static AliasedLoggingFlag const aliased_logging_flags[] = {
- { "TraceClassLoading", LogLevel::Info, true, LogTag::_classload },
- { "TraceClassPaths", LogLevel::Info, true, LogTag::_classpath },
- { "TraceClassResolution", LogLevel::Info, true, LogTag::_classresolve },
- { "TraceClassUnloading", LogLevel::Info, true, LogTag::_classunload },
- { "TraceExceptions", LogLevel::Info, true, LogTag::_exceptions },
- { "TraceMonitorInflation", LogLevel::Debug, true, LogTag::_monitorinflation },
- { "TraceBiasedLocking", LogLevel::Info, true, LogTag::_biasedlocking },
- { NULL, LogLevel::Off, false, LogTag::__NO_TAG }
+ { "TraceBiasedLocking", LogLevel::Info, true, LOG_TAGS(biasedlocking) },
+ { "TraceClassLoading", LogLevel::Info, true, LOG_TAGS(classload) },
+ { "TraceClassLoadingPreorder", LogLevel::Debug, true, LOG_TAGS(classload, preorder) },
+ { "TraceClassPaths", LogLevel::Info, true, LOG_TAGS(classpath) },
+ { "TraceClassResolution", LogLevel::Debug, true, LOG_TAGS(classresolve) },
+ { "TraceClassUnloading", LogLevel::Info, true, LOG_TAGS(classunload) },
+ { "TraceExceptions", LogLevel::Info, true, LOG_TAGS(exceptions) },
+ { "TraceMonitorInflation", LogLevel::Debug, true, LOG_TAGS(monitorinflation) },
+ { "TraceSafepointCleanupTime", LogLevel::Info, true, LOG_TAGS(safepointcleanup) },
+ { NULL, LogLevel::Off, false, LOG_TAGS(_NO_TAG) }
};
// Return true if "v" is less than "other", where "other" may be "undefined".
@@ -952,7 +954,7 @@
return alf;
}
}
- AliasedLoggingFlag a = {NULL, LogLevel::Off, false, LogTag::__NO_TAG};
+ AliasedLoggingFlag a = {NULL, LogLevel::Off, false, LOG_TAGS(_NO_TAG)};
return a;
}
@@ -965,12 +967,11 @@
char dummy;
const char* real_name;
bool warn_if_deprecated = true;
- AliasedLoggingFlag alf;
if (sscanf(arg, "-%" XSTR(BUFLEN) NAME_RANGE "%c", name, &dummy) == 1) {
- alf = catch_logging_aliases(name);
+ AliasedLoggingFlag alf = catch_logging_aliases(name);
if (alf.alias_name != NULL){
- LogConfiguration::configure_stdout(LogLevel::Off, alf.exactMatch, alf.tag, LogTag::__NO_TAG);
+ LogConfiguration::configure_stdout(LogLevel::Off, alf.exactMatch, alf.tag0, alf.tag1, alf.tag2, alf.tag3, alf.tag4, alf.tag5);
return true;
}
real_name = handle_aliases_and_deprecation(name, warn_if_deprecated);
@@ -980,9 +981,9 @@
return set_bool_flag(real_name, false, origin);
}
if (sscanf(arg, "+%" XSTR(BUFLEN) NAME_RANGE "%c", name, &dummy) == 1) {
- alf = catch_logging_aliases(name);
+ AliasedLoggingFlag alf = catch_logging_aliases(name);
if (alf.alias_name != NULL){
- LogConfiguration::configure_stdout(alf.level, alf.exactMatch, alf.tag, LogTag::__NO_TAG);
+ LogConfiguration::configure_stdout(alf.level, alf.exactMatch, alf.tag0, alf.tag1, alf.tag2, alf.tag3, alf.tag4, alf.tag5);
return true;
}
real_name = handle_aliases_and_deprecation(name, warn_if_deprecated);
--- a/hotspot/src/share/vm/runtime/arguments.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/arguments.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -230,7 +230,12 @@
const char* alias_name;
LogLevelType level;
bool exactMatch;
- LogTagType tag;
+ LogTagType tag0;
+ LogTagType tag1;
+ LogTagType tag2;
+ LogTagType tag3;
+ LogTagType tag4;
+ LogTagType tag5;
} AliasedLoggingFlag;
class Arguments : AllStatic {
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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,6 +25,7 @@
#include "precompiled.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/collectorPolicy.hpp"
+#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/threadLocalAllocBuffer.hpp"
#include "runtime/arguments.hpp"
#include "runtime/commandLineFlagConstraintsGC.hpp"
@@ -448,6 +449,22 @@
return Flag::SUCCESS;
}
+Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) {
+#if INCLUDE_ALL_GCS
+ if (UseConcMarkSweepGC) {
+ size_t max_capacity = GenCollectedHeap::heap()->young_gen()->max_capacity();
+ if (value > max_uintx - max_capacity) {
+ CommandLineError::print(verbose,
+ "CMSSamplingGrain (" UINTX_FORMAT ") must be "
+ "less than or equal to ergonomic maximum (" SIZE_FORMAT ")\n",
+ value, max_uintx - max_capacity);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ }
+#endif
+ return Flag::SUCCESS;
+}
+
Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) {
#if INCLUDE_ALL_GCS
if (UseConcMarkSweepGC) {
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -61,6 +61,7 @@
Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose);
Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose);
Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose);
+Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose);
Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose);
Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose);
Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose);
--- a/hotspot/src/share/vm/runtime/globals.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/globals.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -990,9 +990,6 @@
develop(bool, PrintVMMessages, true, \
"Print VM messages on console") \
\
- diagnostic(bool, VerboseVerification, false, \
- "Display detailed verification details") \
- \
notproduct(uintx, ErrorHandlerTest, 0, \
"If > 0, provokes an error after VM initialization; the value " \
"determines which error to provoke. See test_error_handler() " \
@@ -1052,9 +1049,6 @@
"directory) of the dump file (defaults to java_pid<pid>.hprof " \
"in the working directory)") \
\
- develop(size_t, HeapDumpSegmentSize, 1*G, \
- "Approximate segment size when generating a segmented heap dump") \
- \
develop(bool, BreakAtWarning, false, \
"Execute breakpoint upon encountering VM warning") \
\
@@ -1472,9 +1466,6 @@
develop(bool, TraceCompiledIC, false, \
"Trace changes of compiled IC") \
\
- develop(bool, TraceClearedExceptions, false, \
- "Print when an exception is forcibly cleared") \
- \
/* gc */ \
\
product(bool, UseSerialGC, false, \
@@ -1904,7 +1895,8 @@
\
product(uintx, CMSSamplingGrain, 16*K, \
"The minimum distance between eden samples for CMS (see above)") \
- range(1, max_uintx) \
+ range(ObjectAlignmentInBytes, max_uintx) \
+ constraint(CMSSamplingGrainConstraintFunc,AfterMemoryInit) \
\
product(bool, CMSScavengeBeforeRemark, false, \
"Attempt scavenge before the CMS remark step") \
@@ -2067,9 +2059,6 @@
develop(uintx, MetadataAllocationFailALotInterval, 1000, \
"Metadata allocation failure a lot interval") \
\
- develop(bool, TraceMetadataChunkAllocation, false, \
- "Trace chunk metadata allocations") \
- \
notproduct(bool, ExecuteInternalVMTests, false, \
"Enable execution of internal VM tests") \
\
@@ -2223,10 +2212,10 @@
"Decay factor to TenuredGenerationSizeIncrement") \
range(1, max_uintx) \
\
- product(uintx, MaxGCPauseMillis, max_uintx, \
+ product(uintx, MaxGCPauseMillis, max_uintx - 1, \
"Adaptive size policy maximum GC pause time goal in millisecond, "\
"or (G1 Only) the maximum GC time per MMU time slice") \
- range(1, max_uintx) \
+ range(1, max_uintx - 1) \
constraint(MaxGCPauseMillisConstraintFunc,AfterMemoryInit) \
\
product(uintx, GCPauseIntervalMillis, 0, \
@@ -2390,9 +2379,6 @@
product(bool, IgnoreEmptyClassPaths, false, \
"Ignore empty path elements in -classpath") \
\
- product(bool, TraceClassLoadingPreorder, false, \
- "Trace all classes loaded in order referenced (not loaded)") \
- \
product_rw(bool, TraceLoaderConstraints, false, \
"Trace loader constraints") \
\
@@ -2545,10 +2531,6 @@
LP64_ONLY(range(-1, max_intx/MICROUNITS)) \
NOT_LP64(range(-1, max_intx)) \
\
- product(bool, TraceSafepointCleanupTime, false, \
- "Print the break down of clean up tasks performed during " \
- "safepoint") \
- \
product(bool, Inline, true, \
"Enable inlining") \
\
@@ -2780,10 +2762,6 @@
"Produce histogram of IC misses") \
\
/* interpreter */ \
- develop(bool, ClearInterpreterLocals, false, \
- "Always clear local variables of interpreter activations upon " \
- "entry") \
- \
product_pd(bool, RewriteBytecodes, \
"Allow rewriting of bytecodes (bytecodes are not immutable)") \
\
@@ -3267,7 +3245,8 @@
range(0, max_uintx) \
\
product_pd(size_t, MetaspaceSize, \
- "Initial size of Metaspaces (in bytes)") \
+ "Initial threshold (in bytes) at which a garbage collection " \
+ "is done to reduce Metaspace usage") \
constraint(MetaspaceSizeConstraintFunc,AfterErgo) \
\
product(size_t, MaxMetaspaceSize, max_uintx, \
--- a/hotspot/src/share/vm/runtime/jniHandles.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/jniHandles.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "logging/log.hpp"
+#include "memory/iterator.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/jniHandles.hpp"
@@ -128,6 +129,12 @@
}
+void JNIHandles::weak_oops_do(OopClosure* f) {
+ AlwaysTrueClosure always_true;
+ weak_oops_do(&always_true, f);
+}
+
+
void JNIHandles::initialize() {
_global_handles = JNIHandleBlock::allocate_block();
_weak_global_handles = JNIHandleBlock::allocate_block();
@@ -185,11 +192,6 @@
}
-class AlwaysAliveClosure: public BoolObjectClosure {
-public:
- bool do_object_b(oop obj) { return true; }
-};
-
class CountHandleClosure: public OopClosure {
private:
int _count;
@@ -211,9 +213,8 @@
"JNIHandles not initialized");
CountHandleClosure global_handle_count;
- AlwaysAliveClosure always_alive;
oops_do(&global_handle_count);
- weak_oops_do(&always_alive, &global_handle_count);
+ weak_oops_do(&global_handle_count);
st->print_cr("JNI global references: %d", global_handle_count.count());
st->cr();
@@ -230,10 +231,9 @@
void JNIHandles::verify() {
VerifyHandleClosure verify_handle;
- AlwaysAliveClosure always_alive;
oops_do(&verify_handle);
- weak_oops_do(&always_alive, &verify_handle);
+ weak_oops_do(&verify_handle);
}
--- a/hotspot/src/share/vm/runtime/jniHandles.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/jniHandles.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -86,6 +86,8 @@
static void oops_do(OopClosure* f);
// Traversal of weak global handles. Unreachable oops are cleared.
static void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f);
+ // Traversal of weak global handles.
+ static void weak_oops_do(OopClosure* f);
};
--- a/hotspot/src/share/vm/runtime/logTimer.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/logTimer.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -28,7 +28,7 @@
#include "logging/log.hpp"
#include "runtime/timer.hpp"
-// TraceStartupTime is used for tracing the execution time of a block with logging
+// These classes are used for tracing the execution time of a block with logging
// Usage:
// { TraceStartupTime t("block time")
// some_code();
@@ -40,4 +40,9 @@
TraceStartupTime(const char* s) : TraceTime(s, log_is_enabled(Info, startuptime), LogTag::_startuptime) {}
};
+class TraceSafepointTime : public TraceTime {
+ public:
+ TraceSafepointTime(const char* s) : TraceTime(s, log_is_enabled(Info, safepointcleanup), LogTag::_safepointcleanup) {}
+};
+
#endif // SHARE_VM_RUNTIME_LOG_TIMER_HPP
--- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -70,7 +70,6 @@
Monitor* Threads_lock = NULL;
Monitor* CGC_lock = NULL;
Monitor* STS_lock = NULL;
-Monitor* SLT_lock = NULL;
Monitor* FullGCCount_lock = NULL;
Mutex* SATB_Q_FL_lock = NULL;
Monitor* SATB_Q_CBL_mon = NULL;
@@ -242,9 +241,6 @@
def(JNIGlobalHandle_lock , Mutex , nonleaf, true, Monitor::_safepoint_check_always); // locks JNIHandleBlockFreeList_lock
def(JNICritical_lock , Monitor, nonleaf, true, Monitor::_safepoint_check_always); // used for JNI critical regions
def(AdapterHandlerLibrary_lock , Mutex , nonleaf, true, Monitor::_safepoint_check_always);
- if (UseConcMarkSweepGC) {
- def(SLT_lock , Monitor, nonleaf, false, Monitor::_safepoint_check_never); // used in CMS GC for locking PLL lock
- }
def(Heap_lock , Monitor, nonleaf+1, false, Monitor::_safepoint_check_sometimes);
def(JfieldIdCreation_lock , Mutex , nonleaf+1, true, Monitor::_safepoint_check_always); // jfieldID, Used in VM_Operation
--- a/hotspot/src/share/vm/runtime/mutexLocker.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -65,7 +65,6 @@
extern Monitor* CGC_lock; // used for coordination between
// fore- & background GC threads.
extern Monitor* STS_lock; // used for joining/leaving SuspendibleThreadSet.
-extern Monitor* SLT_lock; // used in CMS GC for acquiring PLL
extern Monitor* FullGCCount_lock; // in support of "concurrent" full gc
extern Mutex* SATB_Q_FL_lock; // Protects SATB Q
// buffer free list.
--- a/hotspot/src/share/vm/runtime/objectMonitor.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -44,14 +44,6 @@
#include "utilities/macros.hpp"
#include "utilities/preserveException.hpp"
-#if defined(__GNUC__) && !defined(IA64) && !defined(PPC64)
-// Need to inhibit inlining for older versions of GCC to avoid build-time failures
- #define NOINLINE __attribute__((noinline))
-#else
- #define NOINLINE
-#endif
-
-
#ifdef DTRACE_ENABLED
// Only bother with this argument setup if dtrace is available
@@ -254,7 +246,7 @@
// -----------------------------------------------------------------------------
// Enter support
-void NOINLINE ObjectMonitor::enter(TRAPS) {
+void ObjectMonitor::enter(TRAPS) {
// The following code is ordered to check the most common cases first
// and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors.
Thread * const Self = THREAD;
@@ -431,7 +423,7 @@
#define MAX_RECHECK_INTERVAL 1000
-void NOINLINE ObjectMonitor::EnterI(TRAPS) {
+void ObjectMonitor::EnterI(TRAPS) {
Thread * const Self = THREAD;
assert(Self->is_Java_thread(), "invariant");
assert(((JavaThread *) Self)->thread_state() == _thread_blocked, "invariant");
@@ -681,7 +673,7 @@
// Knob_Reset and Knob_SpinAfterFutile support and restructuring the
// loop accordingly.
-void NOINLINE ObjectMonitor::ReenterI(Thread * Self, ObjectWaiter * SelfNode) {
+void ObjectMonitor::ReenterI(Thread * Self, ObjectWaiter * SelfNode) {
assert(Self != NULL, "invariant");
assert(SelfNode != NULL, "invariant");
assert(SelfNode->_thread == Self, "invariant");
@@ -894,7 +886,7 @@
// structured the code so the windows are short and the frequency
// of such futile wakups is low.
-void NOINLINE ObjectMonitor::exit(bool not_suspended, TRAPS) {
+void ObjectMonitor::exit(bool not_suspended, TRAPS) {
Thread * const Self = THREAD;
if (THREAD != _owner) {
if (THREAD->is_lock_owned((address) _owner)) {
--- a/hotspot/src/share/vm/runtime/os.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/os.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -61,6 +61,7 @@
#include "utilities/events.hpp"
# include <signal.h>
+# include <errno.h>
OSThread* os::_starting_thread = NULL;
address os::_polling_page = NULL;
@@ -1427,6 +1428,131 @@
return page_size_for_region(region_size, min_pages, false);
}
+static const char* errno_to_string (int e, bool short_text) {
+ #define ALL_SHARED_ENUMS(X) \
+ X(E2BIG, "Argument list too long") \
+ X(EACCES, "Permission denied") \
+ X(EADDRINUSE, "Address in use") \
+ X(EADDRNOTAVAIL, "Address not available") \
+ X(EAFNOSUPPORT, "Address family not supported") \
+ X(EAGAIN, "Resource unavailable, try again") \
+ X(EALREADY, "Connection already in progress") \
+ X(EBADF, "Bad file descriptor") \
+ X(EBADMSG, "Bad message") \
+ X(EBUSY, "Device or resource busy") \
+ X(ECANCELED, "Operation canceled") \
+ X(ECHILD, "No child processes") \
+ X(ECONNABORTED, "Connection aborted") \
+ X(ECONNREFUSED, "Connection refused") \
+ X(ECONNRESET, "Connection reset") \
+ X(EDEADLK, "Resource deadlock would occur") \
+ X(EDESTADDRREQ, "Destination address required") \
+ X(EDOM, "Mathematics argument out of domain of function") \
+ X(EEXIST, "File exists") \
+ X(EFAULT, "Bad address") \
+ X(EFBIG, "File too large") \
+ X(EHOSTUNREACH, "Host is unreachable") \
+ X(EIDRM, "Identifier removed") \
+ X(EILSEQ, "Illegal byte sequence") \
+ X(EINPROGRESS, "Operation in progress") \
+ X(EINTR, "Interrupted function") \
+ X(EINVAL, "Invalid argument") \
+ X(EIO, "I/O error") \
+ X(EISCONN, "Socket is connected") \
+ X(EISDIR, "Is a directory") \
+ X(ELOOP, "Too many levels of symbolic links") \
+ X(EMFILE, "Too many open files") \
+ X(EMLINK, "Too many links") \
+ X(EMSGSIZE, "Message too large") \
+ X(ENAMETOOLONG, "Filename too long") \
+ X(ENETDOWN, "Network is down") \
+ X(ENETRESET, "Connection aborted by network") \
+ X(ENETUNREACH, "Network unreachable") \
+ X(ENFILE, "Too many files open in system") \
+ X(ENOBUFS, "No buffer space available") \
+ X(ENODATA, "No message is available on the STREAM head read queue") \
+ X(ENODEV, "No such device") \
+ X(ENOENT, "No such file or directory") \
+ X(ENOEXEC, "Executable file format error") \
+ X(ENOLCK, "No locks available") \
+ X(ENOLINK, "Reserved") \
+ X(ENOMEM, "Not enough space") \
+ X(ENOMSG, "No message of the desired type") \
+ X(ENOPROTOOPT, "Protocol not available") \
+ X(ENOSPC, "No space left on device") \
+ X(ENOSR, "No STREAM resources") \
+ X(ENOSTR, "Not a STREAM") \
+ X(ENOSYS, "Function not supported") \
+ X(ENOTCONN, "The socket is not connected") \
+ X(ENOTDIR, "Not a directory") \
+ X(ENOTEMPTY, "Directory not empty") \
+ X(ENOTSOCK, "Not a socket") \
+ X(ENOTSUP, "Not supported") \
+ X(ENOTTY, "Inappropriate I/O control operation") \
+ X(ENXIO, "No such device or address") \
+ X(EOPNOTSUPP, "Operation not supported on socket") \
+ X(EOVERFLOW, "Value too large to be stored in data type") \
+ X(EPERM, "Operation not permitted") \
+ X(EPIPE, "Broken pipe") \
+ X(EPROTO, "Protocol error") \
+ X(EPROTONOSUPPORT, "Protocol not supported") \
+ X(EPROTOTYPE, "Protocol wrong type for socket") \
+ X(ERANGE, "Result too large") \
+ X(EROFS, "Read-only file system") \
+ X(ESPIPE, "Invalid seek") \
+ X(ESRCH, "No such process") \
+ X(ETIME, "Stream ioctl() timeout") \
+ X(ETIMEDOUT, "Connection timed out") \
+ X(ETXTBSY, "Text file busy") \
+ X(EWOULDBLOCK, "Operation would block") \
+ X(EXDEV, "Cross-device link")
+
+ #define DEFINE_ENTRY(e, text) { e, #e, text },
+
+ static const struct {
+ int v;
+ const char* short_text;
+ const char* long_text;
+ } table [] = {
+
+ ALL_SHARED_ENUMS(DEFINE_ENTRY)
+
+ // The following enums are not defined on all platforms.
+ #ifdef ESTALE
+ DEFINE_ENTRY(ESTALE, "Reserved")
+ #endif
+ #ifdef EDQUOT
+ DEFINE_ENTRY(EDQUOT, "Reserved")
+ #endif
+ #ifdef EMULTIHOP
+ DEFINE_ENTRY(EMULTIHOP, "Reserved")
+ #endif
+
+ // End marker.
+ { -1, "Unknown errno", "Unknown error" }
+
+ };
+
+ #undef DEFINE_ENTRY
+ #undef ALL_FLAGS
+
+ int i = 0;
+ while (table[i].v != -1 && table[i].v != e) {
+ i ++;
+ }
+
+ return short_text ? table[i].short_text : table[i].long_text;
+
+}
+
+const char* os::strerror(int e) {
+ return errno_to_string(e, false);
+}
+
+const char* os::errno_name(int e) {
+ return errno_to_string(e, true);
+}
+
#ifndef PRODUCT
void os::trace_page_sizes(const char* str, const size_t* page_sizes, int count)
{
@@ -1600,8 +1726,8 @@
return res;
}
-void os::pretouch_memory(char* start, char* end) {
- for (volatile char *p = start; p < end; p += os::vm_page_size()) {
+void os::pretouch_memory(void* start, void* end) {
+ for (volatile char *p = (char*)start; p < (char*)end; p += os::vm_page_size()) {
*p = 0;
}
}
--- a/hotspot/src/share/vm/runtime/os.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/os.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -325,7 +325,7 @@
// to make the OS back the memory range with actual memory.
// Current implementation may not touch the last page if unaligned addresses
// are passed.
- static void pretouch_memory(char* start, char* end);
+ static void pretouch_memory(void* start, void* end);
enum ProtType { MEM_PROT_NONE, MEM_PROT_READ, MEM_PROT_RW, MEM_PROT_RWX };
static bool protect_memory(char* addr, size_t bytes, ProtType prot,
@@ -617,6 +617,22 @@
static size_t lasterror(char *buf, size_t len);
static int get_last_error();
+ // Replacement for strerror().
+ // Will return the english description of the error (e.g. "File not found", as
+ // suggested in the POSIX standard.
+ // Will return "Unknown error" for an unknown errno value.
+ // Will not attempt to localize the returned string.
+ // Will always return a valid string which is a static constant.
+ // Will not change the value of errno.
+ static const char* strerror(int e);
+
+ // Will return the literalized version of the given errno (e.g. "EINVAL"
+ // for EINVAL).
+ // Will return "Unknown error" for an unknown errno value.
+ // Will always return a valid string which is a static constant.
+ // Will not change the value of errno.
+ static const char* errno_name(int e);
+
// Determines whether the calling process is being debugged by a user-mode debugger.
static bool is_debugger_attached();
--- a/hotspot/src/share/vm/runtime/reflection.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/reflection.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -74,9 +74,9 @@
const char * to = to_class->external_name();
// print in a single call to reduce interleaving between threads
if (source_file != NULL) {
- log_info(classresolve)("%s %s %s:%d (reflection)", from, to, source_file, line_number);
+ log_debug(classresolve)("%s %s %s:%d (reflection)", from, to, source_file, line_number);
} else {
- log_info(classresolve)("%s %s (reflection)", from, to);
+ log_debug(classresolve)("%s %s (reflection)", from, to);
}
}
}
@@ -599,7 +599,7 @@
Handle(THREAD, protection_domain),
true,
CHECK_NULL);
- if (log_is_enabled(Info, classresolve)) {
+ if (log_is_enabled(Debug, classresolve)) {
trace_class_resolution(k);
}
return k->java_mirror();
@@ -654,7 +654,7 @@
Handle(THREAD, k->protection_domain()),
true, CHECK_(Handle()));
- if (log_is_enabled(Info, classresolve)) {
+ if (log_is_enabled(Debug, classresolve)) {
trace_class_resolution(result);
}
--- a/hotspot/src/share/vm/runtime/safepoint.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/safepoint.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -44,6 +44,7 @@
#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/interfaceSupport.hpp"
+#include "runtime/logTimer.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/orderAccess.inline.hpp"
#include "runtime/osThread.hpp"
@@ -221,7 +222,7 @@
}
if (log_is_enabled(Trace, safepoint)) {
ResourceMark rm;
- cur_state->print_on(LogHandle(safepoint)::debug_stream());
+ cur_state->print_on(LogHandle(safepoint)::trace_stream());
}
}
}
@@ -487,38 +488,38 @@
// Various cleaning tasks that should be done periodically at safepoints
void SafepointSynchronize::do_cleanup_tasks() {
{
- TraceTime t1("deflating idle monitors", TraceSafepointCleanupTime);
+ TraceSafepointTime t1("deflating idle monitors");
ObjectSynchronizer::deflate_idle_monitors();
}
{
- TraceTime t2("updating inline caches", TraceSafepointCleanupTime);
+ TraceSafepointTime t2("updating inline caches");
InlineCacheBuffer::update_inline_caches();
}
{
- TraceTime t3("compilation policy safepoint handler", TraceSafepointCleanupTime);
+ TraceSafepointTime t3("compilation policy safepoint handler");
CompilationPolicy::policy()->do_safepoint_work();
}
{
- TraceTime t4("mark nmethods", TraceSafepointCleanupTime);
+ TraceSafepointTime t4("mark nmethods");
NMethodSweeper::mark_active_nmethods();
}
if (SymbolTable::needs_rehashing()) {
- TraceTime t5("rehashing symbol table", TraceSafepointCleanupTime);
+ TraceSafepointTime t5("rehashing symbol table");
SymbolTable::rehash_table();
}
if (StringTable::needs_rehashing()) {
- TraceTime t6("rehashing string table", TraceSafepointCleanupTime);
+ TraceSafepointTime t6("rehashing string table");
StringTable::rehash_table();
}
{
// CMS delays purging the CLDG until the beginning of the next safepoint and to
// make sure concurrent sweep is done
- TraceTime t7("purging class loader data graph", TraceSafepointCleanupTime);
+ TraceSafepointTime t7("purging class loader data graph");
ClassLoaderDataGraph::purge_if_needed();
}
}
--- a/hotspot/src/share/vm/runtime/synchronizer.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/synchronizer.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, 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
@@ -48,13 +48,6 @@
#include "utilities/events.hpp"
#include "utilities/preserveException.hpp"
-#if defined(__GNUC__) && !defined(PPC64)
-// Need to inhibit inlining for older versions of GCC to avoid build-time failures
- #define NOINLINE __attribute__((noinline))
-#else
- #define NOINLINE
-#endif
-
// The "core" versions of monitor enter and exit reside in this file.
// The interpreter and compilers contain specialized transliterated
// variants of the enter-exit fast-path operations. See i486.ad fast_lock(),
@@ -1038,7 +1031,7 @@
assert(free_tally == Self->omFreeCount, "free count off");
}
-ObjectMonitor * NOINLINE ObjectSynchronizer::omAlloc(Thread * Self) {
+ObjectMonitor* ObjectSynchronizer::omAlloc(Thread * Self) {
// A large MAXPRIVATE value reduces both list lock contention
// and list coherency traffic, but also tends to increase the
// number of objectMonitors in circulation as well as the STW
@@ -1313,7 +1306,7 @@
inflate_cause_vm_internal);
}
-ObjectMonitor * NOINLINE ObjectSynchronizer::inflate(Thread * Self,
+ObjectMonitor* ObjectSynchronizer::inflate(Thread * Self,
oop object,
const InflateCause cause) {
--- a/hotspot/src/share/vm/runtime/thread.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/thread.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -34,6 +34,7 @@
#include "compiler/compileTask.hpp"
#include "gc/shared/gcId.hpp"
#include "gc/shared/gcLocker.inline.hpp"
+#include "gc/shared/referencePendingListLocker.hpp"
#include "gc/shared/workgroup.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/linkResolver.hpp"
@@ -3650,18 +3651,9 @@
// anymore. We call vm_exit_during_initialization directly instead.
SystemDictionary::compute_java_system_loader(CHECK_(JNI_ERR));
-#if INCLUDE_ALL_GCS
- // Support for ConcurrentMarkSweep. This should be cleaned up
- // and better encapsulated. The ugly nested if test would go away
- // once things are properly refactored. XXX YSR
- if (UseConcMarkSweepGC || UseG1GC) {
- if (UseConcMarkSweepGC) {
- ConcurrentMarkSweepThread::makeSurrogateLockerThread(CHECK_JNI_ERR);
- } else {
- ConcurrentMarkThread::makeSurrogateLockerThread(CHECK_JNI_ERR);
- }
- }
-#endif // INCLUDE_ALL_GCS
+ // Initialize reference pending list locker
+ bool needs_locker_thread = Universe::heap()->needs_reference_pending_list_locker_thread();
+ ReferencePendingListLocker::initialize(needs_locker_thread, CHECK_JNI_ERR);
// Always call even when there are not JVMTI environments yet, since environments
// may be attached late and JVMTI must track phases of VM execution
--- a/hotspot/src/share/vm/runtime/timer.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/timer.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -153,6 +153,9 @@
case LogTag::_startuptime :
log_info(startuptime)("%s, %3.7f secs", _title, _t.seconds());
break;
+ case LogTag::_safepointcleanup :
+ log_info(safepointcleanup)("%s, %3.7f secs", _title, _t.seconds());
+ break;
case LogTag::__NO_TAG :
default :
tty->print_cr("[%s, %3.7f secs]", _title, _t.seconds());
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -54,6 +54,7 @@
#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/generation.hpp"
#include "gc/shared/generationSpec.hpp"
+#include "gc/shared/referencePendingListLocker.hpp"
#include "gc/shared/space.hpp"
#include "interpreter/bytecodeInterpreter.hpp"
#include "interpreter/bytecodes.hpp"
@@ -1692,6 +1693,7 @@
declare_type(JavaThread, Thread) \
declare_type(JvmtiAgentThread, JavaThread) \
declare_type(ServiceThread, JavaThread) \
+ declare_type(ReferencePendingListLockerThread, JavaThread) \
declare_type(CompilerThread, JavaThread) \
declare_type(CodeCacheSweeperThread, JavaThread) \
declare_toplevel_type(OSThread) \
--- a/hotspot/src/share/vm/services/heapDumper.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/services/heapDumper.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -459,7 +459,7 @@
// if the open failed we record the error
if (_fd < 0) {
- _error = (char*)os::strdup(strerror(errno));
+ _error = (char*)os::strdup(os::strerror(errno));
}
}
@@ -509,7 +509,7 @@
if (n < 0) {
// EINTR cannot happen here, os::write will take care of that
- set_error(strerror(errno));
+ set_error(os::strerror(errno));
os::close(file_descriptor());
set_file_descriptor(-1);
return;
--- a/hotspot/src/share/vm/trace/trace.dtd Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/trace/trace.dtd Sat Mar 19 01:23:46 2016 +0100
@@ -23,7 +23,7 @@
-->
-<!ELEMENT trace (xi:include, relation_decls, events*, xi:include, xi:include)>
+<!ELEMENT trace (xi:include*)>
<!ELEMENT types (content_types, primary_types)>
<!ELEMENT content_types (content_type|struct_type)*>
<!ELEMENT content_type (value|structvalue|structarray|array)*>
--- a/hotspot/src/share/vm/trace/trace.xml Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/trace/trace.xml Sat Mar 19 01:23:46 2016 +0100
@@ -30,573 +30,10 @@
]>
<trace>
- <xi:include href="tracetypes.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
-
- <relation_decls>
- <relation_decl id="GC_ID" uri="vm/gc/id"/>
- <relation_decl id="COMP_ID" uri="vm/compiler/id"/>
- <relation_decl id="SWEEP_ID" uri="vm/code_sweeper/id"/>
- <relation_decl id="JAVA_MONITOR_ADDRESS" uri="java/monitor/address"/>
- </relation_decls>
-
-<!--
-
-Events in the JVM are by default timed (it's more common)
-Perhaps a little strange. Might change.
-
-EVENTS
-
-Declard with the 'event' tag.
-
-<value fields> can be one or more of
- value - a simple primitive or constant type value
- structvalue - value is a sub-struct. This type must be previously defined
- with 'struct'
-All these require you to declare type, field and label of the field. They also accept
-an optional description of the field. If the meaning of the field is not obvious
-from the label you should provide a description. If an event however is not actually
-meant for end-users, you should probably _not_ write descriptions at all, since you
-might just add more concepts the user has no notion of/interest in.
-
-Events should be modeled after what conceptual process you are expressing, _NOT_
-from whatever data structures you might use inside the JVM for expressing a process.
-
-
-STRUCT
-
-Declared with the 'struct' tag.
-
-Declares a structure type that can be used in other events.
-
--->
-
- <events>
- <event id="ThreadStart" path="java/thread_start" label="Java Thread Start"
- has_thread="true" is_instant="true">
- <value type="THREAD" field="thread" label="Java Thread"/>
- </event>
-
- <event id="ThreadEnd" path="java/thread_end" label="Java Thread End"
- has_thread="true" is_instant="true">
- <value type="THREAD" field="thread" label="Java Thread"/>
- </event>
-
- <event id="ThreadSleep" path="java/thread_sleep" label="Java Thread Sleep"
- has_thread="true" has_stacktrace="true" is_instant="false">
- <value type="MILLIS" field="time" label="Sleep Time"/>
- </event>
-
- <event id="ThreadPark" path="java/thread_park" label="Java Thread Park"
- has_thread="true" has_stacktrace="true" is_instant="false">
- <value type="CLASS" field="klass" label="Class Parked On"/>
- <value type="MILLIS" field="timeout" label="Park Timeout"/>
- <value type="ADDRESS" field="address" label="Address of Object Parked" relation="JAVA_MONITOR_ADDRESS"/>
- </event>
-
- <event id="JavaMonitorEnter" path="java/monitor_enter" label="Java Monitor Blocked"
- has_thread="true" has_stacktrace="true" is_instant="false">
- <value type="CLASS" field="klass" label="Monitor Class"/>
- <value type="THREAD" field="previousOwner" label="Previous Monitor Owner"/>
- <value type="ADDRESS" field="address" label="Monitor Address" relation="JAVA_MONITOR_ADDRESS"/>
- </event>
-
- <event id="JavaMonitorWait" path="java/monitor_wait" label="Java Monitor Wait" description="Waiting on a Java monitor"
- has_thread="true" has_stacktrace="true" is_instant="false">
- <value type="CLASS" field="klass" label="Monitor Class" description="Class of object waited on"/>
- <value type="THREAD" field="notifier" label="Notifier Thread" description="Notifying Thread"/>
- <value type="MILLIS" field="timeout" label="Timeout" description="Maximum wait time"/>
- <value type="BOOLEAN" field="timedOut" label="Timed Out" description="Wait has been timed out"/>
- <value type="ADDRESS" field="address" label="Monitor Address" description="Address of object waited on" relation="JAVA_MONITOR_ADDRESS"/>
- </event>
-
- <event id="JavaMonitorInflate" path="java/monitor_inflate" label="Java Monitor Inflated"
- has_thread="true" has_stacktrace="true" is_instant="false">
- <value type="CLASS" field="klass" label="Monitor Class"/>
- <value type="ADDRESS" field="address" label="Monitor Address" relation="JAVA_MONITOR_ADDRESS"/>
- <value type="INFLATECAUSE" field="cause" label="Cause" description="Cause of inflation"/>
- </event>
-
- <event id="ReservedStackActivation" path="java/reserved_stack_activation" label="Reserved Stack Activation" description="Activation of Reserved Stack Area caused by stack overflow with ReservedStackAccess annotated method in call stack"
- has_thread="true" has_stacktrace="true" is_instant="true">
- <value type="METHOD" field="method" label="Java Method"/>
- </event>
-
- <event id="ClassLoad" path="vm/class/load" label="Class Load"
- has_thread="true" has_stacktrace="true" is_instant="false">
- <value type="CLASS" field="loadedClass" label="Loaded Class"/>
- <value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
- <value type="CLASS" field="initiatingClassLoader" label="Initiating Class Loader"/>
- </event>
-
- <event id="ClassUnload" path="vm/class/unload" label="Class Unload"
- has_thread="true" is_instant="true">
- <value type="CLASS" field="unloadedClass" label="Unloaded Class"/>
- <value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
- </event>
-
- <event id="IntFlagChanged" path="vm/flag/int_changed" label="Int Flag Changed"
- is_instant="true">
- <value type="UTF8" field="name" label="Name" />
- <value type="INTEGER" field="old_value" label="Old Value" />
- <value type="INTEGER" field="new_value" label="New Value" />
- <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
- </event>
-
- <event id="UnsignedIntFlagChanged" path="vm/flag/uint_changed" label="Unsigned Int Flag Changed"
- is_instant="true">
- <value type="UTF8" field="name" label="Name" />
- <value type="UINT" field="old_value" label="Old Value" />
- <value type="UINT" field="new_value" label="New Value" />
- <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
- </event>
-
- <event id="LongFlagChanged" path="vm/flag/long_changed" label="Long Flag Changed"
- is_instant="true">
- <value type="UTF8" field="name" label="Name" />
- <value type="LONG" field="old_value" label="Old Value" />
- <value type="LONG" field="new_value" label="New Value" />
- <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
- </event>
-
- <event id="UnsignedLongFlagChanged" path="vm/flag/ulong_changed" label="Unsigned Long Flag Changed"
- is_instant="true">
- <value type="UTF8" field="name" label="Name" />
- <value type="ULONG" field="old_value" label="Old Value" />
- <value type="ULONG" field="new_value" label="New Value" />
- <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
- </event>
-
- <event id="DoubleFlagChanged" path="vm/flag/double_changed" label="Double Flag Changed"
- is_instant="true">
- <value type="UTF8" field="name" label="Name" />
- <value type="DOUBLE" field="old_value" label="Old Value" />
- <value type="DOUBLE" field="new_value" label="New Value" />
- <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
- </event>
-
- <event id="BooleanFlagChanged" path="vm/flag/boolean_changed" label="Boolean Flag Changed"
- is_instant="true">
- <value type="UTF8" field="name" label="Name" />
- <value type="BOOLEAN" field="old_value" label="Old Value" />
- <value type="BOOLEAN" field="new_value" label="New Value" />
- <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
- </event>
-
- <event id="StringFlagChanged" path="vm/flag/string_changed" label="String Flag Changed"
- is_instant="true">
- <value type="UTF8" field="name" label="Name" />
- <value type="UTF8" field="old_value" label="Old Value" />
- <value type="UTF8" field="new_value" label="New Value" />
- <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
- </event>
-
- <struct id="VirtualSpace">
- <value type="ADDRESS" field="start" label="Start Address" description="Start address of the virtual space" />
- <value type="ADDRESS" field="committedEnd" label="Committed End Address" description="End address of the committed memory for the virtual space" />
- <value type="BYTES64" field="committedSize" label="Committed Size" description="Size of the committed memory for the virtual space" />
- <value type="ADDRESS" field="reservedEnd" label="Reserved End Address" description="End address of the reserved memory for the virtual space" />
- <value type="BYTES64" field="reservedSize" label="Reserved Size" description="Size of the reserved memory for the virtual space" />
- </struct>
-
- <struct id="ObjectSpace">
- <value type="ADDRESS" field="start" label="Start Address" description="Start address of the space" />
- <value type="ADDRESS" field="end" label="End Address" description="End address of the space" />
- <value type="BYTES64" field="used" label="Used" description="Bytes allocated by objects in the space" />
- <value type="BYTES64" field="size" label="Size" description="Size of the space" />
- </struct>
-
- <event id="GCHeapSummary" path="vm/gc/heap/summary" label="Heap Summary" is_instant="true">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="GCWHEN" field="when" label="When" />
- <structvalue type="VirtualSpace" field="heapSpace" label="Heap Space"/>
- <value type="BYTES64" field="heapUsed" label="Heap Used" description="Bytes allocated by objects in the heap"/>
- </event>
-
- <struct id="MetaspaceSizes">
- <value type="BYTES64" field="committed" label="Committed" description="Committed memory for this space" />
- <value type="BYTES64" field="used" label="Used" description="Bytes allocated by objects in the space" />
- <value type="BYTES64" field="reserved" label="Reserved" description="Reserved memory for this space" />
- </struct>
-
- <event id="MetaspaceSummary" path="vm/gc/heap/metaspace_summary" label="Metaspace Summary" is_instant="true">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="GCWHEN" field="when" label="When" />
- <value type="BYTES64" field="gcThreshold" label="GC Threshold" />
- <structvalue type="MetaspaceSizes" field="metaspace" label="Total"/>
- <structvalue type="MetaspaceSizes" field="dataSpace" label="Data"/>
- <structvalue type="MetaspaceSizes" field="classSpace" label="Class"/>
- </event>
-
- <event id="MetaspaceGCThreshold" path="vm/gc/metaspace/gc_threshold" label="Metaspace GC Threshold" is_instant="true">
- <value type="BYTES64" field="oldValue" label="Old Value" />
- <value type="BYTES64" field="newValue" label="New Value" />
- <value type="GCTHRESHOLDUPDATER" field="updater" label="Updater" />
- </event>
-
- <event id="MetaspaceAllocationFailure" path="vm/gc/metaspace/allocation_failure" label="Metaspace Allocation Failure" is_instant="true" has_stacktrace="true">
- <value type="CLASS" field="classLoader" label="Class Loader" />
- <value type="BOOLEAN" field="anonymousClassLoader" label="Anonymous Class Loader" />
- <value type="BYTES64" field="size" label="Size" />
- <value type="METADATATYPE" field="metadataType" label="Metadata Type" />
- <value type="METASPACEOBJTYPE" field="metaspaceObjectType" label="Metaspace Object Type" />
- </event>
-
- <event id="MetaspaceOOM" path="vm/gc/metaspace/out_of_memory" label="Metaspace Out of Memory" is_instant="true" has_stacktrace="true">
- <value type="CLASS" field="classLoader" label="Class Loader" />
- <value type="BOOLEAN" field="anonymousClassLoader" label="Anonymous Class Loader" />
- <value type="BYTES64" field="size" label="Size" />
- <value type="METADATATYPE" field="metadataType" label="Metadata Type" />
- <value type="METASPACEOBJTYPE" field="metaspaceObjectType" label="Metaspace Object Type" />
- </event>
-
- <event id="MetaspaceChunkFreeListSummary" path="vm/gc/metaspace/chunk_free_list_summary" label="Metaspace Chunk Free List Summary" is_instant="true">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="GCWHEN" field="when" label="When" />
- <value type="METADATATYPE" field="metadataType" label="Metadata Type" />
- <value type="ULONG" field="specializedChunks" label="Specialized Chunks" />
- <value type="BYTES64" field="specializedChunksTotalSize" label="Specialized Chunks Total Size" />
- <value type="ULONG" field="smallChunks" label="Small Chunks" />
- <value type="BYTES64" field="smallChunksTotalSize" label="Small Chunks Total Size" />
- <value type="ULONG" field="mediumChunks" label="Medium Chunks" />
- <value type="BYTES64" field="mediumChunksTotalSize" label="Medium Chunks Total Size" />
- <value type="ULONG" field="humongousChunks" label="Humongous Chunks" />
- <value type="BYTES64" field="humongousChunksTotalSize" label="Humongous Chunks Total Size" />
- </event>
-
- <event id="PSHeapSummary" path="vm/gc/heap/ps_summary" label="Parallel Scavenge Heap Summary" is_instant="true">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="GCWHEN" field="when" label="When" />
-
- <structvalue type="VirtualSpace" field="oldSpace" label="Old Space"/>
- <structvalue type="ObjectSpace" field="oldObjectSpace" label="Old Object Space"/>
-
- <structvalue type="VirtualSpace" field="youngSpace" label="Young Space"/>
- <structvalue type="ObjectSpace" field="edenSpace" label="Eden Space"/>
- <structvalue type="ObjectSpace" field="fromSpace" label="From Space"/>
- <structvalue type="ObjectSpace" field="toSpace" label="To Space"/>
- </event>
-
- <event id="G1HeapSummary" path="vm/gc/heap/g1_summary" label="G1 Heap Summary" is_instant="true">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="GCWHEN" field="when" label="When" />
-
- <value type="BYTES64" field="edenUsedSize" label="Eden Used Size" />
- <value type="BYTES64" field="edenTotalSize" label="Eden Total Size" />
- <value type="BYTES64" field="survivorUsedSize" label="Survivor Used Size" />
- <value type="UINT" field="numberOfRegions" label="Number of Regions" />
- </event>
-
- <event id="GCGarbageCollection" path="vm/gc/collector/garbage_collection" label="Garbage Collection"
- description="Garbage collection performed by the JVM">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" />
- <value type="GCNAME" field="name" label="Name" description="The name of the Garbage Collector" />
- <value type="GCCAUSE" field="cause" label="Cause" description="The reason for triggering this Garbage Collection" />
- <value type="TICKSPAN" field="sumOfPauses" label="Sum of Pauses" description="Sum of all the times in which Java execution was paused during the garbage collection" />
- <value type="TICKSPAN" field="longestPause" label="Longest Pause" description="Longest individual pause during the garbage collection" />
- </event>
-
- <event id="GCParallelOld" path="vm/gc/collector/parold_garbage_collection" label="Parallel Old Garbage Collection"
- description="Extra information specific to Parallel Old Garbage Collections">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" />
- <value type="ADDRESS" field="densePrefix" label="Dense Prefix" description="The address of the dense prefix, used when compacting" />
- </event>
-
- <event id="GCYoungGarbageCollection" path="vm/gc/collector/young_garbage_collection" label="Young Garbage Collection"
- description="Extra information specific to Young Garbage Collections">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" />
- <value type="UINT" field="tenuringThreshold" label="Tenuring Threshold" />
- </event>
-
- <event id="GCOldGarbageCollection" path="vm/gc/collector/old_garbage_collection" label="Old Garbage Collection"
- description="Extra information specific to Old Garbage Collections">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- </event>
-
- <event id="GCG1GarbageCollection" path="vm/gc/collector/g1_garbage_collection" label="G1 Garbage Collection"
- description="Extra information specific to G1 Garbage Collections">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="G1YCTYPE" field="type" label="Type" />
- </event>
-
- <event id="GCG1MMU" path="vm/gc/detailed/g1_mmu_info" label="G1 MMU Information" is_instant="true">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="DOUBLE" field="timeSlice" label="Time slice used to calculate MMU"/>
- <value type="DOUBLE" field="gcTime" label="Time spent on GC during last time slice"/>
- <value type="DOUBLE" field="maxGcTime" label="Max time allowed to be spent on GC during last time slice"/>
- </event>
-
- <event id="EvacuationInfo" path="vm/gc/detailed/evacuation_info" label="Evacuation Information" is_instant="true">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="UINT" field="cSetRegions" label="Collection Set Regions"/>
- <value type="BYTES64" field="cSetUsedBefore" label="Collection Set Before" description="Memory usage before GC in the collection set regions"/>
- <value type="BYTES64" field="cSetUsedAfter" label="Collection Set After" description="Memory usage after GC in the collection set regions"/>
- <value type="UINT" field="allocationRegions" label="Allocation Regions" description="Regions chosen as allocation regions during evacuation (includes survivors and old space regions)"/>
- <value type="BYTES64" field="allocRegionsUsedBefore" label="Alloc Regions Before" description="Memory usage before GC in allocation regions"/>
- <value type="BYTES64" field="allocRegionsUsedAfter" label="Alloc Regions After" description="Memory usage after GC in allocation regions"/>
- <value type="BYTES64" field="bytesCopied" label="Bytes Copied"/>
- <value type="UINT" field="regionsFreed" label="Regions Freed"/>
- </event>
-
- <event id="GCReferenceStatistics" path="vm/gc/reference/statistics"
- label="GC Reference Statistics" is_instant="true"
- description="Total count of processed references during GC">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="REFERENCETYPE" field="type" label="Type" />
- <value type="ULONG" field="count" label="Total Count" />
- </event>
-
- <struct id="CopyFailed">
- <value type="ULONG" field="objectCount" label="Object Count"/>
- <value type="BYTES64" field="firstSize" label="First Failed Object Size"/>
- <value type="BYTES64" field="smallestSize" label="Smallest Failed Object Size"/>
- <value type="BYTES64" field="totalSize" label="Total Object Size"/>
- </struct>
-
- <event id="ObjectCountAfterGC" path="vm/gc/detailed/object_count_after_gc" is_instant="true" label="Object Count after GC">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" />
- <value type="CLASS" field="class" label="Class" />
- <value type="LONG" field="count" label="Count" />
- <value type="BYTES64" field="totalSize" label="Total Size" />
- </event>
-
- <struct id="G1EvacStats">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="BYTES64" field="allocated" label="Allocated" description="Total memory allocated by PLABs"/>
- <value type="BYTES64" field="wasted" label="Wasted" description="Total memory wasted within PLABs due to alignment or refill"/>
- <value type="BYTES64" field="used" label="Used" description="Total memory occupied by objects within PLABs"/>
- <value type="BYTES64" field="undoWaste" label="Undo Wasted" description="Total memory wasted due to allocation undo within PLABs"/>
- <value type="BYTES64" field="regionEndWaste" label="Region End Wasted" description="Total memory wasted at the end of regions due to refill"/>
- <value type="UINT" field="regionsRefilled" label="Region Refills" description="Total memory wasted at the end of regions due to refill"/>
- <value type="BYTES64" field="directAllocated" label="Allocated (direct)" description="Total memory allocated using direct allocation outside of PLABs"/>
- <value type="BYTES64" field="failureUsed" label="Used (failure)" description="Total memory occupied by objects in regions where evacuation failed"/>
- <value type="BYTES64" field="failureWaste" label="Wasted (failure)" description="Total memory left unused in regions where evacuation failed"/>
- </struct>
-
- <event id="GCG1EvacuationYoungStatistics" path="vm/gc/detailed/g1_evac_young_stats" label="G1 Evacuation Statistics for Young" is_instant="true"
- description="Memory related evacuation statistics during GC for the young generation">
- <structvalue type="G1EvacStats" field="stats" label="Evacuation statistics"/>
- </event>
-
- <event id="GCG1EvacuationOldStatistics" path="vm/gc/detailed/g1_evac_old_stats" label="G1 Evacuation Memory Statistics for Old" is_instant="true"
- description="Memory related evacuation statistics during GC for the old generation">
- <structvalue type="G1EvacStats" field="stats" label="Evacuation statistics"/>
- </event>
-
- <event id="GCG1BasicIHOP" path="vm/gc/detailed/g1_basic_ihop_status" label="G1 Basic IHOP statistics" is_instant="true"
- description="Basic statistics related to current IHOP calculation">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="BYTES64" field="threshold" label="Current IHOP threshold" description="Current IHOP threshold in bytes"/>
- <value type="BYTES64" field="thresholdPercentage" label="Current IHOP threshold in percent" description="Current IHOP threshold in percent of old gen"/>
- <value type="BYTES64" field="targetOccupancy" label="Target occupancy" description="Target old gen occupancy to reach at the start of mixed GC in bytes"/>
- <value type="BYTES64" field="currentOccupancy" label="Current occupancy" description="Current old gen occupancy in bytes"/>
- <value type="BYTES64" field="lastAllocationSize" label="Last mutator allocation size" description="Mutator allocation during mutator operation since last GC in bytes"/>
- <value type="DOUBLE" field="lastAllocationDuration" label="Last mutator operation duration" description="Time the mutator ran since last GC in seconds"/>
- <value type="DOUBLE" field="lastAllocationRate" label="Last mutator allocation rate" description="Allocation rate of the mutator since last GC in bytes/second"/>
- <value type="DOUBLE" field="lastMarkingLength" label="Last mutator time from initial mark to first mixed GC" description="Last time from the end of the last initial mark to the first mixed GC in seconds"/>
- </event>
-
- <event id="GCG1AdaptiveIHOP" path="vm/gc/detailed/g1_adaptive_ihop_status" label="G1 Adaptive IHOP statistics" is_instant="true"
- description="Statistics related to current adaptive IHOP calculation">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="BYTES64" field="threshold" label="Current IHOP threshold" description="Current IHOP threshold in bytes"/>
- <value type="BYTES64" field="thresholdPercentage" label="Current IHOP threshold in percent" description="Current IHOP threshold in percent of the internal target occupancy"/>
- <value type="BYTES64" field="internalTargetOccupancy" label="Target occupancy" description="Internal target old gen occupancy to reach at the start of mixed GC in bytes"/>
- <value type="BYTES64" field="currentOccupancy" label="Current occupancy" description="Current old gen occupancy in bytes"/>
- <value type="BYTES64" field="additionalBufferSize" label="Additional buffer size" description="Additional buffer size in bytes"/>
- <value type="DOUBLE" field="predictedAllocationRate" label="Predicted mutator allocation rate" description="Current predicted allocation rate for the mutator in bytes/second"/>
- <value type="DOUBLE" field="predictedMarkingLength" label="Predicted time from initial mark to first mixed GC" description="Current predicted time from the end of the last initial mark to the first mixed GC in seconds"/>
- <value type="BOOLEAN" field="predictionActive" label="Prediction active" description="Indicates whether the adaptive IHOP prediction is active"/>
- </event>
-
- <!-- Promotion events, Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. -->
- <event id="PromoteObjectInNewPLAB" path="vm/gc/detailed/object_promotion_in_new_PLAB" label="Promotion in new PLAB"
- description="Object survived scavenge and was copied to a new Promotion Local Allocation Buffer (PLAB). Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. Due to promotion being done in parallel an object might be reported multiple times as the GC threads race to copy all objects."
- has_thread="true" has_stacktrace="false" is_instant="true">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" description="ID of GC during which the object was promoted"/>
- <value type="CLASS" field="class" label="Class" description="Class of promoted object"/>
- <value type="BYTES64" field="objectSize" label="Object Size" description="Size of promoted object"/>
- <value type="UINT" field="tenuringAge" label="Object Tenuring Age" description="Tenuring age of a surviving object before being copied. The tenuring age of an object is a value between 0-15 and is incremented each scavange the object survives. Newly allocated objects have tenuring age 0."/>
- <value type="BOOLEAN" field="tenured" label="Tenured" description="True if object was promoted to Old space, otherwise the object was aged and copied to a Survivor space"/>
- <value type="BYTES64" field="plabSize" label="PLAB Size" description="Size of the allocated PLAB to which the object was copied"/>
- </event>
-
- <event id="PromoteObjectOutsidePLAB" path="vm/gc/detailed/object_promotion_outside_PLAB" label="Promotion outside PLAB"
- description="Object survived scavenge and was copied directly to the heap. Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. Due to promotion being done in parallel an object might be reported multiple times as the GC threads race to copy all objects."
- has_thread="true" has_stacktrace="false" is_instant="true">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" description="ID of GC during which the object was promoted"/>
- <value type="CLASS" field="class" label="Class" description="Class of promoted object"/>
- <value type="BYTES64" field="objectSize" label="Object Size" description="Size of promoted object"/>
- <value type="UINT" field="tenuringAge" label="Object Tenuring Age" description="Tenuring age of a surviving object before being copied. The tenuring age of an object is a value between 0-15 and is incremented each scavange the object survives. Newly allocated objects have tenuring age 0."/>
- <value type="BOOLEAN" field="tenured" label="Tenured" description="True if object was promoted to Old space, otherwise the object was aged and copied to a Survivor space"/>
- </event>
-
- <event id="PromotionFailed" path="vm/gc/detailed/promotion_failed" label="Promotion Failed" is_instant="true"
- description="Promotion of an object failed">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <structvalue type="CopyFailed" field="data" label="Data"/>
- <value type="THREAD" field="thread" label="Running thread"/>
- </event>
-
- <event id="EvacuationFailed" path="vm/gc/detailed/evacuation_failed" label="Evacuation Failed" is_instant="true"
- description="Evacuation of an object failed">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <structvalue type="CopyFailed" field="data" label="Data"/>
- </event>
-
- <event id="ConcurrentModeFailure" path="vm/gc/detailed/concurrent_mode_failure" label="Concurrent Mode Failure"
- is_instant="true" description="Concurrent Mode failed">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- </event>
-
- <event id="GCPhasePause" path="vm/gc/phases/pause" label="GC Phase Pause">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="UTF8" field="name" label="Name" />
- </event>
-
- <event id="GCPhasePauseLevel1" path="vm/gc/phases/pause_level_1" label="GC Phase Pause Level 1">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="UTF8" field="name" label="Name" />
- </event>
-
- <event id="GCPhasePauseLevel2" path="vm/gc/phases/pause_level_2" label="GC Phase Pause Level 2">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="UTF8" field="name" label="Name" />
- </event>
-
- <event id="GCPhasePauseLevel3" path="vm/gc/phases/pause_level_3" label="GC Phase Pause Level 3">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="UTF8" field="name" label="Name" />
- </event>
-
- <event id="GCPhaseConcurrent" path="vm/gc/phases/concurrent" label="GC Phase Concurrent">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="UTF8" field="name" label="Name" />
- </event>
-
- <event id="AllocationRequiringGC" path="vm/gc/detailed/allocation_requiring_gc" label="Allocation Requiring GC"
- has_thread="true" has_stacktrace="true" is_instant="true">
- <value type="UINT" field="gcId" label="Pending GC ID" relation="GC_ID" />
- <value type="BYTES64" field="size" label="Allocation Size" />
- </event>
-
- <event id="TenuringDistribution" path="vm/gc/detailed/tenuring_distribution" label="Tenuring Distribution"
- is_instant="true">
- <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
- <value type="UINT" field="age" label="Age" />
- <value type="BYTES64" field="size" label="Size" />
- </event>
-
- <event id="G1HeapRegionTypeChange" path="vm/gc/detailed/g1_heap_region_type_change" label="G1 Heap Region Type Change"
- description="Information about a G1 heap region type change." is_instant="true">
- <value type="UINT" field="index" label="Index" />
- <value type="G1HEAPREGIONTYPE" field="from" label="From Type" />
- <value type="G1HEAPREGIONTYPE" field="to" label="To Type" />
- <value type="ADDRESS" field="start" label="Start" />
- <value type="BYTES64" field="used" label="Used" />
- <value type="UINT" field="allocContext" label="Allocation Context" />
- </event>
-
- <event id="VMError" path="vm/runtime/vm_error" label="VM Error"
- description="VM shutdown due to an error" has_stacktrace="true" has_thread="true">
- <value type="BOOLEAN" field="out_of_java_memory" label="Java Out Of Memory"/>
- </event>
-
- <!-- Compiler events -->
-
- <event id="Compilation" path="vm/compiler/compilation" label="Compilation"
- has_thread="true" is_requestable="false" is_constant="false">
- <value type="METHOD" field="method" label="Java Method"/>
- <value type="UINT" field="compileID" label="Compilation ID" relation="COMP_ID"/>
- <value type="USHORT" field="compileLevel" label="Compilation Level"/>
- <value type="BOOLEAN" field="succeded" label="Succeeded"/>
- <value type="BOOLEAN" field="isOsr" label="On Stack Replacement"/>
- <value type="BYTES" field="codeSize" label="Compiled Code Size"/>
- <value type="BYTES" field="inlinedBytes" label="Inlined Code Size"/>
- </event>
-
- <event id="CompilerPhase" path="vm/compiler/phase" label="Compiler Phase"
- has_thread="true" is_requestable="false" is_constant="false">
- <value type="COMPILERPHASETYPE" field="phase" label="Compile Phase"/>
- <value type="UINT" field="compileID" label="Compilation ID" relation="COMP_ID"/>
- <value type="USHORT" field="phaseLevel" label="Phase Level"/>
- </event>
-
- <event id="CompilerFailure" path="vm/compiler/failure" label="Compilation Failure"
- has_thread="true" is_requestable="false" is_constant="false" is_instant="true">
- <value type="UTF8" field="failure" label="Message"/>
- <value type="UINT" field="compileID" label="Compilation ID" relation="COMP_ID"/>
- </event>
-
- <struct id="CiMethod">
- <value type="UTF8" field="class" label="Class name"/>
- <value type="UTF8" field="name" label="Method name"/>
- <value type="UTF8" field="signature" label="Method signature"/>
- </struct>
-
- <event id="CompilerInlining" path="vm/compiler/optimization/inlining" label="Method Inlining"
- has_thread="true" is_instant="true">
- <value type="UINT" field="compileID" label="Compilation ID" relation="COMP_ID"/>
- <value type="METHOD" field="caller" label="Caller Method"/>
- <structvalue type="CiMethod" field="callee" label="Callee Method"/>
- <value type="BOOLEAN" field="succeeded" label="Succeeded"/>
- <value type="UTF8" field="message" label="Message"/>
- <value type="INTEGER" field="bci" label="Byte Code Index"/>
- </event>
-
- <!-- Code sweeper events -->
-
- <event id="SweepCodeCache" path="vm/code_sweeper/sweep" label="Sweep Code Cache"
- has_thread="true" is_requestable="false" is_constant="false">
- <value type="INTEGER" field="sweepIndex" label="Sweep Index" relation="SWEEP_ID"/>
- <value type="UINT" field="sweptCount" label="Methods Swept"/>
- <value type="UINT" field="flushedCount" label="Methods Flushed"/>
- <value type="UINT" field="markedCount" label="Methods Reclaimed"/>
- <value type="UINT" field="zombifiedCount" label="Methods Zombified"/>
- </event>
-
- <!-- Code cache events -->
-
- <event id="CodeCacheFull" path="vm/code_cache/full" label="Code Cache Full"
- has_thread="true" is_requestable="false" is_constant="false" is_instant="true">
- <value type="CODEBLOBTYPE" field="codeBlobType" label="Code Heap"/>
- <value type="ADDRESS" field="startAddress" label="Start Address"/>
- <value type="ADDRESS" field="commitedTopAddress" label="Commited Top"/>
- <value type="ADDRESS" field="reservedTopAddress" label="Reserved Top"/>
- <value type="INTEGER" field="entryCount" label="Entries"/>
- <value type="INTEGER" field="methodCount" label="Methods"/>
- <value type="INTEGER" field="adaptorCount" label="Adaptors"/>
- <value type="BYTES64" field="unallocatedCapacity" label="Unallocated"/>
- <value type="INTEGER" field="fullCount" label="Full Count"/>
- </event>
-
- <event id="ExecuteVMOperation" path="vm/runtime/execute_vm_operation" label="VM Operation"
- description="Execution of a VM Operation" has_thread="true">
- <value type="VMOPERATIONTYPE" field="operation" label="Operation" />
- <value type="BOOLEAN" field="safepoint" label="At Safepoint" description="If the operation occured at a safepoint."/>
- <value type="BOOLEAN" field="blocking" label="Caller Blocked" description="If the calling thread was blocked until the operation was complete."/>
- <value type="THREAD" field="caller" label="Caller" transition="FROM" description="Thread requesting operation. If non-blocking, will be set to 0 indicating thread is unknown."/>
- </event>
-
- <!-- Allocation events -->
- <event id="AllocObjectInNewTLAB" path="java/object_alloc_in_new_TLAB" label="Allocation in new TLAB"
- description="Allocation in new Thread Local Allocation Buffer" has_thread="true" has_stacktrace="true" is_instant="true">
- <value type="CLASS" field="class" label="Class" description="Class of allocated object"/>
- <value type="BYTES64" field="allocationSize" label="Allocation Size"/>
- <value type="BYTES64" field="tlabSize" label="TLAB Size"/>
- </event>
-
- <event id="AllocObjectOutsideTLAB" path="java/object_alloc_outside_TLAB" label="Allocation outside TLAB"
- description="Allocation outside Thread Local Allocation Buffers" has_thread="true" has_stacktrace="true" is_instant="true">
- <value type="CLASS" field="class" label="Class" description="Class of allocated object"/>
- <value type="BYTES64" field="allocationSize" label="Allocation Size"/>
- </event>
- </events>
-
- <xi:include href="../../../closed/share/vm/trace/traceeventtypes.xml" xmlns:xi="http://www.w3.org/2001/XInclude">
- <xi:fallback/>
- </xi:include>
-
- <xi:include href="../../../closed/share/vm/trace/traceevents.xml" xmlns:xi="http://www.w3.org/2001/XInclude">
- <xi:fallback/>
- </xi:include>
+ <xi:include href="tracetypes.xml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"/>
+ <xi:include href="tracerelationdecls.xml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"/>
+ <xi:include href="traceevents.xml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"/>
</trace>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/trace/traceevents.xml Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,581 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2012, 2016, 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.
+
+-->
+
+
+<!DOCTYPE events SYSTEM "trace.dtd">
+
+<events>
+
+<!--
+
+Events in the JVM are by default timed (it's more common)
+Perhaps a little strange. Might change.
+
+EVENTS
+
+Declard with the 'event' tag.
+
+<value fields> can be one or more of
+ value - a simple primitive or constant type value
+ structvalue - value is a sub-struct. This type must be previously defined
+ with 'struct'
+All these require you to declare type, field and label of the field. They also accept
+an optional description of the field. If the meaning of the field is not obvious
+from the label you should provide a description. If an event however is not actually
+meant for end-users, you should probably _not_ write descriptions at all, since you
+might just add more concepts the user has no notion of/interest in.
+
+Events should be modeled after what conceptual process you are expressing, _NOT_
+from whatever data structures you might use inside the JVM for expressing a process.
+
+
+STRUCT
+
+Declared with the 'struct' tag.
+
+Declares a structure type that can be used in other events.
+
+-->
+
+ <event id="ThreadStart" path="java/thread_start" label="Java Thread Start"
+ has_thread="true" is_instant="true">
+ <value type="THREAD" field="thread" label="Java Thread"/>
+ </event>
+
+ <event id="ThreadEnd" path="java/thread_end" label="Java Thread End"
+ has_thread="true" is_instant="true">
+ <value type="THREAD" field="thread" label="Java Thread"/>
+ </event>
+
+ <event id="ThreadSleep" path="java/thread_sleep" label="Java Thread Sleep"
+ has_thread="true" has_stacktrace="true" is_instant="false">
+ <value type="MILLIS" field="time" label="Sleep Time"/>
+ </event>
+
+ <event id="ThreadPark" path="java/thread_park" label="Java Thread Park"
+ has_thread="true" has_stacktrace="true" is_instant="false">
+ <value type="CLASS" field="klass" label="Class Parked On"/>
+ <value type="MILLIS" field="timeout" label="Park Timeout"/>
+ <value type="ADDRESS" field="address" label="Address of Object Parked" relation="JAVA_MONITOR_ADDRESS"/>
+ </event>
+
+ <event id="JavaMonitorEnter" path="java/monitor_enter" label="Java Monitor Blocked"
+ has_thread="true" has_stacktrace="true" is_instant="false">
+ <value type="CLASS" field="klass" label="Monitor Class"/>
+ <value type="THREAD" field="previousOwner" label="Previous Monitor Owner"/>
+ <value type="ADDRESS" field="address" label="Monitor Address" relation="JAVA_MONITOR_ADDRESS"/>
+ </event>
+
+ <event id="JavaMonitorWait" path="java/monitor_wait" label="Java Monitor Wait" description="Waiting on a Java monitor"
+ has_thread="true" has_stacktrace="true" is_instant="false">
+ <value type="CLASS" field="klass" label="Monitor Class" description="Class of object waited on"/>
+ <value type="THREAD" field="notifier" label="Notifier Thread" description="Notifying Thread"/>
+ <value type="MILLIS" field="timeout" label="Timeout" description="Maximum wait time"/>
+ <value type="BOOLEAN" field="timedOut" label="Timed Out" description="Wait has been timed out"/>
+ <value type="ADDRESS" field="address" label="Monitor Address" description="Address of object waited on" relation="JAVA_MONITOR_ADDRESS"/>
+ </event>
+
+ <event id="JavaMonitorInflate" path="java/monitor_inflate" label="Java Monitor Inflated"
+ has_thread="true" has_stacktrace="true" is_instant="false">
+ <value type="CLASS" field="klass" label="Monitor Class"/>
+ <value type="ADDRESS" field="address" label="Monitor Address" relation="JAVA_MONITOR_ADDRESS"/>
+ <value type="INFLATECAUSE" field="cause" label="Cause" description="Cause of inflation"/>
+ </event>
+
+ <event id="ReservedStackActivation" path="java/reserved_stack_activation" label="Reserved Stack Activation" description="Activation of Reserved Stack Area caused by stack overflow with ReservedStackAccess annotated method in call stack"
+ has_thread="true" has_stacktrace="true" is_instant="true">
+ <value type="METHOD" field="method" label="Java Method"/>
+ </event>
+
+ <event id="ClassLoad" path="vm/class/load" label="Class Load"
+ has_thread="true" has_stacktrace="true" is_instant="false">
+ <value type="CLASS" field="loadedClass" label="Loaded Class"/>
+ <value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
+ <value type="CLASS" field="initiatingClassLoader" label="Initiating Class Loader"/>
+ </event>
+
+ <event id="ClassUnload" path="vm/class/unload" label="Class Unload"
+ has_thread="true" is_instant="true">
+ <value type="CLASS" field="unloadedClass" label="Unloaded Class"/>
+ <value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
+ </event>
+
+ <event id="IntFlagChanged" path="vm/flag/int_changed" label="Int Flag Changed"
+ is_instant="true">
+ <value type="UTF8" field="name" label="Name" />
+ <value type="INTEGER" field="old_value" label="Old Value" />
+ <value type="INTEGER" field="new_value" label="New Value" />
+ <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
+ </event>
+
+ <event id="UnsignedIntFlagChanged" path="vm/flag/uint_changed" label="Unsigned Int Flag Changed"
+ is_instant="true">
+ <value type="UTF8" field="name" label="Name" />
+ <value type="UINT" field="old_value" label="Old Value" />
+ <value type="UINT" field="new_value" label="New Value" />
+ <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
+ </event>
+
+ <event id="LongFlagChanged" path="vm/flag/long_changed" label="Long Flag Changed"
+ is_instant="true">
+ <value type="UTF8" field="name" label="Name" />
+ <value type="LONG" field="old_value" label="Old Value" />
+ <value type="LONG" field="new_value" label="New Value" />
+ <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
+ </event>
+
+ <event id="UnsignedLongFlagChanged" path="vm/flag/ulong_changed" label="Unsigned Long Flag Changed"
+ is_instant="true">
+ <value type="UTF8" field="name" label="Name" />
+ <value type="ULONG" field="old_value" label="Old Value" />
+ <value type="ULONG" field="new_value" label="New Value" />
+ <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
+ </event>
+
+ <event id="DoubleFlagChanged" path="vm/flag/double_changed" label="Double Flag Changed"
+ is_instant="true">
+ <value type="UTF8" field="name" label="Name" />
+ <value type="DOUBLE" field="old_value" label="Old Value" />
+ <value type="DOUBLE" field="new_value" label="New Value" />
+ <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
+ </event>
+
+ <event id="BooleanFlagChanged" path="vm/flag/boolean_changed" label="Boolean Flag Changed"
+ is_instant="true">
+ <value type="UTF8" field="name" label="Name" />
+ <value type="BOOLEAN" field="old_value" label="Old Value" />
+ <value type="BOOLEAN" field="new_value" label="New Value" />
+ <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
+ </event>
+
+ <event id="StringFlagChanged" path="vm/flag/string_changed" label="String Flag Changed"
+ is_instant="true">
+ <value type="UTF8" field="name" label="Name" />
+ <value type="UTF8" field="old_value" label="Old Value" />
+ <value type="UTF8" field="new_value" label="New Value" />
+ <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
+ </event>
+
+ <struct id="VirtualSpace">
+ <value type="ADDRESS" field="start" label="Start Address" description="Start address of the virtual space" />
+ <value type="ADDRESS" field="committedEnd" label="Committed End Address" description="End address of the committed memory for the virtual space" />
+ <value type="BYTES64" field="committedSize" label="Committed Size" description="Size of the committed memory for the virtual space" />
+ <value type="ADDRESS" field="reservedEnd" label="Reserved End Address" description="End address of the reserved memory for the virtual space" />
+ <value type="BYTES64" field="reservedSize" label="Reserved Size" description="Size of the reserved memory for the virtual space" />
+ </struct>
+
+ <struct id="ObjectSpace">
+ <value type="ADDRESS" field="start" label="Start Address" description="Start address of the space" />
+ <value type="ADDRESS" field="end" label="End Address" description="End address of the space" />
+ <value type="BYTES64" field="used" label="Used" description="Bytes allocated by objects in the space" />
+ <value type="BYTES64" field="size" label="Size" description="Size of the space" />
+ </struct>
+
+ <event id="GCHeapSummary" path="vm/gc/heap/summary" label="Heap Summary" is_instant="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="GCWHEN" field="when" label="When" />
+ <structvalue type="VirtualSpace" field="heapSpace" label="Heap Space"/>
+ <value type="BYTES64" field="heapUsed" label="Heap Used" description="Bytes allocated by objects in the heap"/>
+ </event>
+
+ <struct id="MetaspaceSizes">
+ <value type="BYTES64" field="committed" label="Committed" description="Committed memory for this space" />
+ <value type="BYTES64" field="used" label="Used" description="Bytes allocated by objects in the space" />
+ <value type="BYTES64" field="reserved" label="Reserved" description="Reserved memory for this space" />
+ </struct>
+
+ <event id="MetaspaceSummary" path="vm/gc/heap/metaspace_summary" label="Metaspace Summary" is_instant="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="GCWHEN" field="when" label="When" />
+ <value type="BYTES64" field="gcThreshold" label="GC Threshold" />
+ <structvalue type="MetaspaceSizes" field="metaspace" label="Total"/>
+ <structvalue type="MetaspaceSizes" field="dataSpace" label="Data"/>
+ <structvalue type="MetaspaceSizes" field="classSpace" label="Class"/>
+ </event>
+
+ <event id="MetaspaceGCThreshold" path="vm/gc/metaspace/gc_threshold" label="Metaspace GC Threshold" is_instant="true">
+ <value type="BYTES64" field="oldValue" label="Old Value" />
+ <value type="BYTES64" field="newValue" label="New Value" />
+ <value type="GCTHRESHOLDUPDATER" field="updater" label="Updater" />
+ </event>
+
+ <event id="MetaspaceAllocationFailure" path="vm/gc/metaspace/allocation_failure" label="Metaspace Allocation Failure" is_instant="true" has_stacktrace="true">
+ <value type="CLASS" field="classLoader" label="Class Loader" />
+ <value type="BOOLEAN" field="anonymousClassLoader" label="Anonymous Class Loader" />
+ <value type="BYTES64" field="size" label="Size" />
+ <value type="METADATATYPE" field="metadataType" label="Metadata Type" />
+ <value type="METASPACEOBJTYPE" field="metaspaceObjectType" label="Metaspace Object Type" />
+ </event>
+
+ <event id="MetaspaceOOM" path="vm/gc/metaspace/out_of_memory" label="Metaspace Out of Memory" is_instant="true" has_stacktrace="true">
+ <value type="CLASS" field="classLoader" label="Class Loader" />
+ <value type="BOOLEAN" field="anonymousClassLoader" label="Anonymous Class Loader" />
+ <value type="BYTES64" field="size" label="Size" />
+ <value type="METADATATYPE" field="metadataType" label="Metadata Type" />
+ <value type="METASPACEOBJTYPE" field="metaspaceObjectType" label="Metaspace Object Type" />
+ </event>
+
+ <event id="MetaspaceChunkFreeListSummary" path="vm/gc/metaspace/chunk_free_list_summary" label="Metaspace Chunk Free List Summary" is_instant="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="GCWHEN" field="when" label="When" />
+ <value type="METADATATYPE" field="metadataType" label="Metadata Type" />
+ <value type="ULONG" field="specializedChunks" label="Specialized Chunks" />
+ <value type="BYTES64" field="specializedChunksTotalSize" label="Specialized Chunks Total Size" />
+ <value type="ULONG" field="smallChunks" label="Small Chunks" />
+ <value type="BYTES64" field="smallChunksTotalSize" label="Small Chunks Total Size" />
+ <value type="ULONG" field="mediumChunks" label="Medium Chunks" />
+ <value type="BYTES64" field="mediumChunksTotalSize" label="Medium Chunks Total Size" />
+ <value type="ULONG" field="humongousChunks" label="Humongous Chunks" />
+ <value type="BYTES64" field="humongousChunksTotalSize" label="Humongous Chunks Total Size" />
+ </event>
+
+ <event id="PSHeapSummary" path="vm/gc/heap/ps_summary" label="Parallel Scavenge Heap Summary" is_instant="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="GCWHEN" field="when" label="When" />
+
+ <structvalue type="VirtualSpace" field="oldSpace" label="Old Space"/>
+ <structvalue type="ObjectSpace" field="oldObjectSpace" label="Old Object Space"/>
+
+ <structvalue type="VirtualSpace" field="youngSpace" label="Young Space"/>
+ <structvalue type="ObjectSpace" field="edenSpace" label="Eden Space"/>
+ <structvalue type="ObjectSpace" field="fromSpace" label="From Space"/>
+ <structvalue type="ObjectSpace" field="toSpace" label="To Space"/>
+ </event>
+
+ <event id="G1HeapSummary" path="vm/gc/heap/g1_summary" label="G1 Heap Summary" is_instant="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="GCWHEN" field="when" label="When" />
+
+ <value type="BYTES64" field="edenUsedSize" label="Eden Used Size" />
+ <value type="BYTES64" field="edenTotalSize" label="Eden Total Size" />
+ <value type="BYTES64" field="survivorUsedSize" label="Survivor Used Size" />
+ <value type="UINT" field="numberOfRegions" label="Number of Regions" />
+ </event>
+
+ <event id="GCGarbageCollection" path="vm/gc/collector/garbage_collection" label="Garbage Collection"
+ description="Garbage collection performed by the JVM">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" />
+ <value type="GCNAME" field="name" label="Name" description="The name of the Garbage Collector" />
+ <value type="GCCAUSE" field="cause" label="Cause" description="The reason for triggering this Garbage Collection" />
+ <value type="TICKSPAN" field="sumOfPauses" label="Sum of Pauses" description="Sum of all the times in which Java execution was paused during the garbage collection" />
+ <value type="TICKSPAN" field="longestPause" label="Longest Pause" description="Longest individual pause during the garbage collection" />
+ </event>
+
+ <event id="GCParallelOld" path="vm/gc/collector/parold_garbage_collection" label="Parallel Old Garbage Collection"
+ description="Extra information specific to Parallel Old Garbage Collections">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" />
+ <value type="ADDRESS" field="densePrefix" label="Dense Prefix" description="The address of the dense prefix, used when compacting" />
+ </event>
+
+ <event id="GCYoungGarbageCollection" path="vm/gc/collector/young_garbage_collection" label="Young Garbage Collection"
+ description="Extra information specific to Young Garbage Collections">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" />
+ <value type="UINT" field="tenuringThreshold" label="Tenuring Threshold" />
+ </event>
+
+ <event id="GCOldGarbageCollection" path="vm/gc/collector/old_garbage_collection" label="Old Garbage Collection"
+ description="Extra information specific to Old Garbage Collections">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ </event>
+
+ <event id="GCG1GarbageCollection" path="vm/gc/collector/g1_garbage_collection" label="G1 Garbage Collection"
+ description="Extra information specific to G1 Garbage Collections">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="G1YCTYPE" field="type" label="Type" />
+ </event>
+
+ <event id="GCG1MMU" path="vm/gc/detailed/g1_mmu_info" label="G1 MMU Information" is_instant="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="DOUBLE" field="timeSlice" label="Time slice used to calculate MMU"/>
+ <value type="DOUBLE" field="gcTime" label="Time spent on GC during last time slice"/>
+ <value type="DOUBLE" field="maxGcTime" label="Max time allowed to be spent on GC during last time slice"/>
+ </event>
+
+ <event id="EvacuationInfo" path="vm/gc/detailed/evacuation_info" label="Evacuation Information" is_instant="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="UINT" field="cSetRegions" label="Collection Set Regions"/>
+ <value type="BYTES64" field="cSetUsedBefore" label="Collection Set Before" description="Memory usage before GC in the collection set regions"/>
+ <value type="BYTES64" field="cSetUsedAfter" label="Collection Set After" description="Memory usage after GC in the collection set regions"/>
+ <value type="UINT" field="allocationRegions" label="Allocation Regions" description="Regions chosen as allocation regions during evacuation (includes survivors and old space regions)"/>
+ <value type="BYTES64" field="allocRegionsUsedBefore" label="Alloc Regions Before" description="Memory usage before GC in allocation regions"/>
+ <value type="BYTES64" field="allocRegionsUsedAfter" label="Alloc Regions After" description="Memory usage after GC in allocation regions"/>
+ <value type="BYTES64" field="bytesCopied" label="Bytes Copied"/>
+ <value type="UINT" field="regionsFreed" label="Regions Freed"/>
+ </event>
+
+ <event id="GCReferenceStatistics" path="vm/gc/reference/statistics"
+ label="GC Reference Statistics" is_instant="true"
+ description="Total count of processed references during GC">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="REFERENCETYPE" field="type" label="Type" />
+ <value type="ULONG" field="count" label="Total Count" />
+ </event>
+
+ <struct id="CopyFailed">
+ <value type="ULONG" field="objectCount" label="Object Count"/>
+ <value type="BYTES64" field="firstSize" label="First Failed Object Size"/>
+ <value type="BYTES64" field="smallestSize" label="Smallest Failed Object Size"/>
+ <value type="BYTES64" field="totalSize" label="Total Object Size"/>
+ </struct>
+
+ <event id="ObjectCountAfterGC" path="vm/gc/detailed/object_count_after_gc" is_instant="true" label="Object Count after GC">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" />
+ <value type="CLASS" field="class" label="Class" />
+ <value type="LONG" field="count" label="Count" />
+ <value type="BYTES64" field="totalSize" label="Total Size" />
+ </event>
+
+ <struct id="G1EvacStats">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="BYTES64" field="allocated" label="Allocated" description="Total memory allocated by PLABs"/>
+ <value type="BYTES64" field="wasted" label="Wasted" description="Total memory wasted within PLABs due to alignment or refill"/>
+ <value type="BYTES64" field="used" label="Used" description="Total memory occupied by objects within PLABs"/>
+ <value type="BYTES64" field="undoWaste" label="Undo Wasted" description="Total memory wasted due to allocation undo within PLABs"/>
+ <value type="BYTES64" field="regionEndWaste" label="Region End Wasted" description="Total memory wasted at the end of regions due to refill"/>
+ <value type="UINT" field="regionsRefilled" label="Region Refills" description="Total memory wasted at the end of regions due to refill"/>
+ <value type="BYTES64" field="directAllocated" label="Allocated (direct)" description="Total memory allocated using direct allocation outside of PLABs"/>
+ <value type="BYTES64" field="failureUsed" label="Used (failure)" description="Total memory occupied by objects in regions where evacuation failed"/>
+ <value type="BYTES64" field="failureWaste" label="Wasted (failure)" description="Total memory left unused in regions where evacuation failed"/>
+ </struct>
+
+ <event id="GCG1EvacuationYoungStatistics" path="vm/gc/detailed/g1_evac_young_stats" label="G1 Evacuation Statistics for Young" is_instant="true"
+ description="Memory related evacuation statistics during GC for the young generation">
+ <structvalue type="G1EvacStats" field="stats" label="Evacuation statistics"/>
+ </event>
+
+ <event id="GCG1EvacuationOldStatistics" path="vm/gc/detailed/g1_evac_old_stats" label="G1 Evacuation Memory Statistics for Old" is_instant="true"
+ description="Memory related evacuation statistics during GC for the old generation">
+ <structvalue type="G1EvacStats" field="stats" label="Evacuation statistics"/>
+ </event>
+
+ <event id="GCG1BasicIHOP" path="vm/gc/detailed/g1_basic_ihop_status" label="G1 Basic IHOP statistics" is_instant="true"
+ description="Basic statistics related to current IHOP calculation">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="BYTES64" field="threshold" label="Current IHOP threshold" description="Current IHOP threshold in bytes"/>
+ <value type="BYTES64" field="thresholdPercentage" label="Current IHOP threshold in percent" description="Current IHOP threshold in percent of old gen"/>
+ <value type="BYTES64" field="targetOccupancy" label="Target occupancy" description="Target old gen occupancy to reach at the start of mixed GC in bytes"/>
+ <value type="BYTES64" field="currentOccupancy" label="Current occupancy" description="Current old gen occupancy in bytes"/>
+ <value type="BYTES64" field="lastAllocationSize" label="Last mutator allocation size" description="Mutator allocation during mutator operation since last GC in bytes"/>
+ <value type="DOUBLE" field="lastAllocationDuration" label="Last mutator operation duration" description="Time the mutator ran since last GC in seconds"/>
+ <value type="DOUBLE" field="lastAllocationRate" label="Last mutator allocation rate" description="Allocation rate of the mutator since last GC in bytes/second"/>
+ <value type="DOUBLE" field="lastMarkingLength" label="Last mutator time from initial mark to first mixed GC" description="Last time from the end of the last initial mark to the first mixed GC in seconds"/>
+ </event>
+
+ <event id="GCG1AdaptiveIHOP" path="vm/gc/detailed/g1_adaptive_ihop_status" label="G1 Adaptive IHOP statistics" is_instant="true"
+ description="Statistics related to current adaptive IHOP calculation">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="BYTES64" field="threshold" label="Current IHOP threshold" description="Current IHOP threshold in bytes"/>
+ <value type="BYTES64" field="thresholdPercentage" label="Current IHOP threshold in percent" description="Current IHOP threshold in percent of the internal target occupancy"/>
+ <value type="BYTES64" field="internalTargetOccupancy" label="Target occupancy" description="Internal target old gen occupancy to reach at the start of mixed GC in bytes"/>
+ <value type="BYTES64" field="currentOccupancy" label="Current occupancy" description="Current old gen occupancy in bytes"/>
+ <value type="BYTES64" field="additionalBufferSize" label="Additional buffer size" description="Additional buffer size in bytes"/>
+ <value type="DOUBLE" field="predictedAllocationRate" label="Predicted mutator allocation rate" description="Current predicted allocation rate for the mutator in bytes/second"/>
+ <value type="DOUBLE" field="predictedMarkingLength" label="Predicted time from initial mark to first mixed GC" description="Current predicted time from the end of the last initial mark to the first mixed GC in seconds"/>
+ <value type="BOOLEAN" field="predictionActive" label="Prediction active" description="Indicates whether the adaptive IHOP prediction is active"/>
+ </event>
+
+ <!-- Promotion events, Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. -->
+ <event id="PromoteObjectInNewPLAB" path="vm/gc/detailed/object_promotion_in_new_PLAB" label="Promotion in new PLAB"
+ description="Object survived scavenge and was copied to a new Promotion Local Allocation Buffer (PLAB). Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. Due to promotion being done in parallel an object might be reported multiple times as the GC threads race to copy all objects."
+ has_thread="true" has_stacktrace="false" is_instant="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" description="ID of GC during which the object was promoted"/>
+ <value type="CLASS" field="class" label="Class" description="Class of promoted object"/>
+ <value type="BYTES64" field="objectSize" label="Object Size" description="Size of promoted object"/>
+ <value type="UINT" field="tenuringAge" label="Object Tenuring Age" description="Tenuring age of a surviving object before being copied. The tenuring age of an object is a value between 0-15 and is incremented each scavange the object survives. Newly allocated objects have tenuring age 0."/>
+ <value type="BOOLEAN" field="tenured" label="Tenured" description="True if object was promoted to Old space, otherwise the object was aged and copied to a Survivor space"/>
+ <value type="BYTES64" field="plabSize" label="PLAB Size" description="Size of the allocated PLAB to which the object was copied"/>
+ </event>
+
+ <event id="PromoteObjectOutsidePLAB" path="vm/gc/detailed/object_promotion_outside_PLAB" label="Promotion outside PLAB"
+ description="Object survived scavenge and was copied directly to the heap. Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. Due to promotion being done in parallel an object might be reported multiple times as the GC threads race to copy all objects."
+ has_thread="true" has_stacktrace="false" is_instant="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" description="ID of GC during which the object was promoted"/>
+ <value type="CLASS" field="class" label="Class" description="Class of promoted object"/>
+ <value type="BYTES64" field="objectSize" label="Object Size" description="Size of promoted object"/>
+ <value type="UINT" field="tenuringAge" label="Object Tenuring Age" description="Tenuring age of a surviving object before being copied. The tenuring age of an object is a value between 0-15 and is incremented each scavange the object survives. Newly allocated objects have tenuring age 0."/>
+ <value type="BOOLEAN" field="tenured" label="Tenured" description="True if object was promoted to Old space, otherwise the object was aged and copied to a Survivor space"/>
+ </event>
+
+ <event id="PromotionFailed" path="vm/gc/detailed/promotion_failed" label="Promotion Failed" is_instant="true"
+ description="Promotion of an object failed">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <structvalue type="CopyFailed" field="data" label="Data"/>
+ <value type="THREAD" field="thread" label="Running thread"/>
+ </event>
+
+ <event id="EvacuationFailed" path="vm/gc/detailed/evacuation_failed" label="Evacuation Failed" is_instant="true"
+ description="Evacuation of an object failed">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <structvalue type="CopyFailed" field="data" label="Data"/>
+ </event>
+
+ <event id="ConcurrentModeFailure" path="vm/gc/detailed/concurrent_mode_failure" label="Concurrent Mode Failure"
+ is_instant="true" description="Concurrent Mode failed">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ </event>
+
+ <event id="GCPhasePause" path="vm/gc/phases/pause" label="GC Phase Pause" has_thread="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="UTF8" field="name" label="Name" />
+ </event>
+
+ <event id="GCPhasePauseLevel1" path="vm/gc/phases/pause_level_1" label="GC Phase Pause Level 1" has_thread="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="UTF8" field="name" label="Name" />
+ </event>
+
+ <event id="GCPhasePauseLevel2" path="vm/gc/phases/pause_level_2" label="GC Phase Pause Level 2" has_thread="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="UTF8" field="name" label="Name" />
+ </event>
+
+ <event id="GCPhasePauseLevel3" path="vm/gc/phases/pause_level_3" label="GC Phase Pause Level 3" has_thread="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="UTF8" field="name" label="Name" />
+ </event>
+
+ <event id="GCPhaseConcurrent" path="vm/gc/phases/concurrent" label="GC Phase Concurrent" has_thread="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="UTF8" field="name" label="Name" />
+ </event>
+
+ <event id="AllocationRequiringGC" path="vm/gc/detailed/allocation_requiring_gc" label="Allocation Requiring GC"
+ has_thread="true" has_stacktrace="true" is_instant="true">
+ <value type="UINT" field="gcId" label="Pending GC ID" relation="GC_ID" />
+ <value type="BYTES64" field="size" label="Allocation Size" />
+ </event>
+
+ <event id="TenuringDistribution" path="vm/gc/detailed/tenuring_distribution" label="Tenuring Distribution"
+ is_instant="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="UINT" field="age" label="Age" />
+ <value type="BYTES64" field="size" label="Size" />
+ </event>
+
+ <event id="G1HeapRegionTypeChange" path="vm/gc/detailed/g1_heap_region_type_change" label="G1 Heap Region Type Change"
+ description="Information about a G1 heap region type change." is_instant="true">
+ <value type="UINT" field="index" label="Index" />
+ <value type="G1HEAPREGIONTYPE" field="from" label="From Type" />
+ <value type="G1HEAPREGIONTYPE" field="to" label="To Type" />
+ <value type="ADDRESS" field="start" label="Start" />
+ <value type="BYTES64" field="used" label="Used" />
+ <value type="UINT" field="allocContext" label="Allocation Context" />
+ </event>
+
+ <event id="VMError" path="vm/runtime/vm_error" label="VM Error"
+ description="VM shutdown due to an error" has_stacktrace="true" has_thread="true">
+ <value type="BOOLEAN" field="out_of_java_memory" label="Java Out Of Memory"/>
+ </event>
+
+ <!-- Compiler events -->
+
+ <event id="Compilation" path="vm/compiler/compilation" label="Compilation"
+ has_thread="true" is_requestable="false" is_constant="false">
+ <value type="METHOD" field="method" label="Java Method"/>
+ <value type="UINT" field="compileID" label="Compilation ID" relation="COMP_ID"/>
+ <value type="USHORT" field="compileLevel" label="Compilation Level"/>
+ <value type="BOOLEAN" field="succeded" label="Succeeded"/>
+ <value type="BOOLEAN" field="isOsr" label="On Stack Replacement"/>
+ <value type="BYTES" field="codeSize" label="Compiled Code Size"/>
+ <value type="BYTES" field="inlinedBytes" label="Inlined Code Size"/>
+ </event>
+
+ <event id="CompilerPhase" path="vm/compiler/phase" label="Compiler Phase"
+ has_thread="true" is_requestable="false" is_constant="false">
+ <value type="COMPILERPHASETYPE" field="phase" label="Compile Phase"/>
+ <value type="UINT" field="compileID" label="Compilation ID" relation="COMP_ID"/>
+ <value type="USHORT" field="phaseLevel" label="Phase Level"/>
+ </event>
+
+ <event id="CompilerFailure" path="vm/compiler/failure" label="Compilation Failure"
+ has_thread="true" is_requestable="false" is_constant="false" is_instant="true">
+ <value type="UTF8" field="failure" label="Message"/>
+ <value type="UINT" field="compileID" label="Compilation ID" relation="COMP_ID"/>
+ </event>
+
+ <struct id="CiMethod">
+ <value type="UTF8" field="class" label="Class name"/>
+ <value type="UTF8" field="name" label="Method name"/>
+ <value type="UTF8" field="signature" label="Method signature"/>
+ </struct>
+
+ <event id="CompilerInlining" path="vm/compiler/optimization/inlining" label="Method Inlining"
+ has_thread="true" is_instant="true">
+ <value type="UINT" field="compileID" label="Compilation ID" relation="COMP_ID"/>
+ <value type="METHOD" field="caller" label="Caller Method"/>
+ <structvalue type="CiMethod" field="callee" label="Callee Method"/>
+ <value type="BOOLEAN" field="succeeded" label="Succeeded"/>
+ <value type="UTF8" field="message" label="Message"/>
+ <value type="INTEGER" field="bci" label="Byte Code Index"/>
+ </event>
+
+ <!-- Code sweeper events -->
+
+ <event id="SweepCodeCache" path="vm/code_sweeper/sweep" label="Sweep Code Cache"
+ has_thread="true" is_requestable="false" is_constant="false">
+ <value type="INTEGER" field="sweepIndex" label="Sweep Index" relation="SWEEP_ID"/>
+ <value type="UINT" field="sweptCount" label="Methods Swept"/>
+ <value type="UINT" field="flushedCount" label="Methods Flushed"/>
+ <value type="UINT" field="markedCount" label="Methods Reclaimed"/>
+ <value type="UINT" field="zombifiedCount" label="Methods Zombified"/>
+ </event>
+
+ <!-- Code cache events -->
+
+ <event id="CodeCacheFull" path="vm/code_cache/full" label="Code Cache Full"
+ has_thread="true" is_requestable="false" is_constant="false" is_instant="true">
+ <value type="CODEBLOBTYPE" field="codeBlobType" label="Code Heap"/>
+ <value type="ADDRESS" field="startAddress" label="Start Address"/>
+ <value type="ADDRESS" field="commitedTopAddress" label="Commited Top"/>
+ <value type="ADDRESS" field="reservedTopAddress" label="Reserved Top"/>
+ <value type="INTEGER" field="entryCount" label="Entries"/>
+ <value type="INTEGER" field="methodCount" label="Methods"/>
+ <value type="INTEGER" field="adaptorCount" label="Adaptors"/>
+ <value type="BYTES64" field="unallocatedCapacity" label="Unallocated"/>
+ <value type="INTEGER" field="fullCount" label="Full Count"/>
+ </event>
+
+ <event id="ExecuteVMOperation" path="vm/runtime/execute_vm_operation" label="VM Operation"
+ description="Execution of a VM Operation" has_thread="true">
+ <value type="VMOPERATIONTYPE" field="operation" label="Operation" />
+ <value type="BOOLEAN" field="safepoint" label="At Safepoint" description="If the operation occured at a safepoint."/>
+ <value type="BOOLEAN" field="blocking" label="Caller Blocked" description="If the calling thread was blocked until the operation was complete."/>
+ <value type="THREAD" field="caller" label="Caller" transition="FROM" description="Thread requesting operation. If non-blocking, will be set to 0 indicating thread is unknown."/>
+ </event>
+
+ <!-- Allocation events -->
+ <event id="AllocObjectInNewTLAB" path="java/object_alloc_in_new_TLAB" label="Allocation in new TLAB"
+ description="Allocation in new Thread Local Allocation Buffer" has_thread="true" has_stacktrace="true" is_instant="true">
+ <value type="CLASS" field="class" label="Class" description="Class of allocated object"/>
+ <value type="BYTES64" field="allocationSize" label="Allocation Size"/>
+ <value type="BYTES64" field="tlabSize" label="TLAB Size"/>
+ </event>
+
+ <event id="AllocObjectOutsideTLAB" path="java/object_alloc_outside_TLAB" label="Allocation outside TLAB"
+ description="Allocation outside Thread Local Allocation Buffers" has_thread="true" has_stacktrace="true" is_instant="true">
+ <value type="CLASS" field="class" label="Class" description="Class of allocated object"/>
+ <value type="BYTES64" field="allocationSize" label="Allocation Size"/>
+ </event>
+</events>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/trace/tracerelationdecls.xml Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2012, 2016, 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.
+
+-->
+
+
+<!DOCTYPE relation_decls SYSTEM "trace.dtd">
+
+<relation_decls>
+ <relation_decl id="GC_ID" uri="vm/gc/id"/>
+ <relation_decl id="COMP_ID" uri="vm/compiler/id"/>
+ <relation_decl id="SWEEP_ID" uri="vm/code_sweeper/id"/>
+ <relation_decl id="JAVA_MONITOR_ADDRESS" uri="java/monitor/address"/>
+</relation_decls>
--- a/hotspot/src/share/vm/utilities/bitMap.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/bitMap.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -29,19 +29,25 @@
#include "utilities/bitMap.inline.hpp"
#include "utilities/copy.hpp"
-BitMap::BitMap(bm_word_t* map, idx_t size_in_bits) :
- _map(map), _size(size_in_bits), _map_allocator(false)
+STATIC_ASSERT(sizeof(BitMap::bm_word_t) == BytesPerWord); // "Implementation assumption."
+
+BitMap::BitMap(idx_t size_in_bits, bool in_resource_area) :
+ _map(NULL), _size(0)
{
- assert(sizeof(bm_word_t) == BytesPerWord, "Implementation assumption.");
+ resize(size_in_bits, in_resource_area);
}
+#ifdef ASSERT
+void BitMap::verify_index(idx_t index) const {
+ assert(index < _size, "BitMap index out of bounds");
+}
-BitMap::BitMap(idx_t size_in_bits, bool in_resource_area) :
- _map(NULL), _size(0), _map_allocator(false)
-{
- assert(sizeof(bm_word_t) == BytesPerWord, "Implementation assumption.");
- resize(size_in_bits, in_resource_area);
+void BitMap::verify_range(idx_t beg_index, idx_t end_index) const {
+ assert(beg_index <= end_index, "BitMap range error");
+ // Note that [0,0) and [size,size) are both valid ranges.
+ if (end_index != _size) verify_index(end_index);
}
+#endif // #ifdef ASSERT
void BitMap::resize(idx_t size_in_bits, bool in_resource_area) {
idx_t old_size_in_words = size_in_words();
@@ -54,7 +60,7 @@
Copy::disjoint_words((HeapWord*)old_map, (HeapWord*) _map,
MIN2(old_size_in_words, new_size_in_words));
} else {
- _map = _map_allocator.reallocate(new_size_in_words);
+ _map = ArrayAllocator<bm_word_t, mtInternal>::reallocate(old_map, old_size_in_words, new_size_in_words);
}
if (new_size_in_words > old_size_in_words) {
--- a/hotspot/src/share/vm/utilities/bitMap.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/bitMap.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -48,7 +48,6 @@
} RangeSizeHint;
private:
- ArrayAllocator<bm_word_t, mtInternal> _map_allocator;
bm_word_t* _map; // First word in bitmap
idx_t _size; // Size of bitmap (in bits)
@@ -101,9 +100,8 @@
idx_t word_index_round_up(idx_t bit) const;
// Verification.
- inline void verify_index(idx_t index) const NOT_DEBUG_RETURN;
- inline void verify_range(idx_t beg_index, idx_t end_index) const
- NOT_DEBUG_RETURN;
+ void verify_index(idx_t index) const NOT_DEBUG_RETURN;
+ void verify_range(idx_t beg_index, idx_t end_index) const NOT_DEBUG_RETURN;
// Statistics.
static idx_t* _pop_count_table;
@@ -114,10 +112,10 @@
public:
// Constructs a bitmap with no map, and size 0.
- BitMap() : _map(NULL), _size(0), _map_allocator(false) {}
+ BitMap() : _map(NULL), _size(0) {}
// Constructs a bitmap with the given map and size.
- BitMap(bm_word_t* map, idx_t size_in_bits);
+ BitMap(bm_word_t* map, idx_t size_in_bits) :_map(map), _size(size_in_bits) {}
// Constructs an empty bitmap of the given size (that is, this clears the
// new bitmap). Allocates the map array in resource area if
@@ -307,36 +305,12 @@
return _map.size() / _bits_per_slot;
}
- bool is_valid_index(idx_t slot_index, idx_t bit_within_slot_index) {
- verify_bit_within_slot_index(bit_within_slot_index);
- return (bit_index(slot_index, bit_within_slot_index) < size_in_bits());
- }
-
- bool at(idx_t slot_index, idx_t bit_within_slot_index) const {
- verify_bit_within_slot_index(bit_within_slot_index);
- return _map.at(bit_index(slot_index, bit_within_slot_index));
- }
-
- void set_bit(idx_t slot_index, idx_t bit_within_slot_index) {
- verify_bit_within_slot_index(bit_within_slot_index);
- _map.set_bit(bit_index(slot_index, bit_within_slot_index));
- }
-
- void clear_bit(idx_t slot_index, idx_t bit_within_slot_index) {
- verify_bit_within_slot_index(bit_within_slot_index);
- _map.clear_bit(bit_index(slot_index, bit_within_slot_index));
- }
-
- void at_put(idx_t slot_index, idx_t bit_within_slot_index, bool value) {
- verify_bit_within_slot_index(bit_within_slot_index);
- _map.at_put(bit_index(slot_index, bit_within_slot_index), value);
- }
-
- void at_put_grow(idx_t slot_index, idx_t bit_within_slot_index, bool value) {
- verify_bit_within_slot_index(bit_within_slot_index);
- _map.at_put_grow(bit_index(slot_index, bit_within_slot_index), value);
- }
-
+ bool is_valid_index(idx_t slot_index, idx_t bit_within_slot_index);
+ bool at(idx_t slot_index, idx_t bit_within_slot_index) const;
+ void set_bit(idx_t slot_index, idx_t bit_within_slot_index);
+ void clear_bit(idx_t slot_index, idx_t bit_within_slot_index);
+ void at_put(idx_t slot_index, idx_t bit_within_slot_index, bool value);
+ void at_put_grow(idx_t slot_index, idx_t bit_within_slot_index, bool value);
void clear();
};
--- a/hotspot/src/share/vm/utilities/bitMap.inline.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/bitMap.inline.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -28,18 +28,6 @@
#include "runtime/atomic.inline.hpp"
#include "utilities/bitMap.hpp"
-#ifdef ASSERT
-inline void BitMap::verify_index(idx_t index) const {
- assert(index < _size, "BitMap index out of bounds");
-}
-
-inline void BitMap::verify_range(idx_t beg_index, idx_t end_index) const {
- assert(beg_index <= end_index, "BitMap range error");
- // Note that [0,0) and [size,size) are both valid ranges.
- if (end_index != _size) verify_index(end_index);
-}
-#endif // #ifdef ASSERT
-
inline void BitMap::set_bit(idx_t bit) {
verify_index(bit);
*word_addr(bit) |= bit_mask(bit);
@@ -344,6 +332,36 @@
return get_next_zero_offset_inline(l_offset, r_offset);
}
+inline bool BitMap2D::is_valid_index(idx_t slot_index, idx_t bit_within_slot_index) {
+ verify_bit_within_slot_index(bit_within_slot_index);
+ return (bit_index(slot_index, bit_within_slot_index) < size_in_bits());
+}
+
+inline bool BitMap2D::at(idx_t slot_index, idx_t bit_within_slot_index) const {
+ verify_bit_within_slot_index(bit_within_slot_index);
+ return _map.at(bit_index(slot_index, bit_within_slot_index));
+}
+
+inline void BitMap2D::set_bit(idx_t slot_index, idx_t bit_within_slot_index) {
+ verify_bit_within_slot_index(bit_within_slot_index);
+ _map.set_bit(bit_index(slot_index, bit_within_slot_index));
+}
+
+inline void BitMap2D::clear_bit(idx_t slot_index, idx_t bit_within_slot_index) {
+ verify_bit_within_slot_index(bit_within_slot_index);
+ _map.clear_bit(bit_index(slot_index, bit_within_slot_index));
+}
+
+inline void BitMap2D::at_put(idx_t slot_index, idx_t bit_within_slot_index, bool value) {
+ verify_bit_within_slot_index(bit_within_slot_index);
+ _map.at_put(bit_index(slot_index, bit_within_slot_index), value);
+}
+
+inline void BitMap2D::at_put_grow(idx_t slot_index, idx_t bit_within_slot_index, bool value) {
+ verify_bit_within_slot_index(bit_within_slot_index);
+ _map.at_put_grow(bit_index(slot_index, bit_within_slot_index), value);
+}
+
inline void BitMap2D::clear() {
_map.clear();
}
--- a/hotspot/src/share/vm/utilities/debug.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/debug.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -224,6 +224,11 @@
va_end(detail_args);
}
+void report_vm_status_error(const char* file, int line, const char* error_msg,
+ int status, const char* detail) {
+ report_vm_error(file, line, error_msg, "error %s(%d), %s", os::errno_name(status), status, detail);
+}
+
void report_fatal(const char* file, int line, const char* detail_fmt, ...)
{
if (Debugging || error_is_suppressed(file, line)) return;
--- a/hotspot/src/share/vm/utilities/debug.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/debug.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -137,7 +137,13 @@
// an extra arg and use strerror to convert it to a meaningful string
// like "Invalid argument", "out of memory" etc
#define vmassert_status(p, status, msg) \
- vmassert(p, "error %s(%d), %s", strerror(status), status, msg)
+do { \
+ if (!(p)) { \
+ report_vm_status_error(__FILE__, __LINE__, "assert(" #p ") failed", \
+ status, msg); \
+ BREAKPOINT; \
+ } \
+} while (0)
// For backward compatibility.
#define assert_status(p, status, msg) vmassert_status(p, status, msg)
@@ -209,6 +215,8 @@
void report_vm_error(const char* file, int line, const char* error_msg,
const char* detail_fmt, ...);
#endif
+void report_vm_status_error(const char* file, int line, const char* error_msg,
+ int status, const char* detail);
void report_fatal(const char* file, int line, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(3, 4);
void report_vm_out_of_memory(const char* file, int line, size_t size, VMErrorType vm_err_type,
const char* detail_fmt, ...) ATTRIBUTE_PRINTF(5, 6);
--- a/hotspot/src/share/vm/utilities/exceptions.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/exceptions.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -52,11 +52,11 @@
}
void ThreadShadow::clear_pending_exception() {
- if (TraceClearedExceptions) {
- if (_pending_exception != NULL) {
- tty->print_cr("Thread::clear_pending_exception: cleared exception:");
- _pending_exception->print();
- }
+ if (_pending_exception != NULL && log_is_enabled(Debug, exceptions)) {
+ ResourceMark rm;
+ outputStream* logst = LogHandle(exceptions)::debug_stream();
+ logst->print("Thread::clear_pending_exception: cleared exception:");
+ _pending_exception->print_on(logst);
}
_pending_exception = NULL;
_exception_file = NULL;
--- a/hotspot/src/share/vm/utilities/globalDefinitions.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -358,6 +358,20 @@
return size_t(result);
}
+
+// Test that nth_bit macro and friends behave as
+// expected, even with low-precedence operators.
+
+STATIC_ASSERT(nth_bit(3) == 0x8);
+STATIC_ASSERT(nth_bit(1|2) == 0x8);
+
+STATIC_ASSERT(right_n_bits(3) == 0x7);
+STATIC_ASSERT(right_n_bits(1|2) == 0x7);
+
+STATIC_ASSERT(left_n_bits(3) == (intptr_t) LP64_ONLY(0xE000000000000000) NOT_LP64(0xE0000000));
+STATIC_ASSERT(left_n_bits(1|2) == (intptr_t) LP64_ONLY(0xE000000000000000) NOT_LP64(0xE0000000));
+
+
#ifndef PRODUCT
// For unit testing only
class GlobalDefinitions {
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -42,6 +42,12 @@
# include "utilities/globalDefinitions_xlc.hpp"
#endif
+#ifndef NOINLINE
+#define NOINLINE
+#endif
+#ifndef ALWAYSINLINE
+#define ALWAYSINLINE inline
+#endif
#ifndef PRAGMA_DIAG_PUSH
#define PRAGMA_DIAG_PUSH
#endif
@@ -1083,9 +1089,9 @@
// get a word with the n.th or the right-most or left-most n bits set
// (note: #define used only so that they can be used in enum constant definitions)
-#define nth_bit(n) (n >= BitsPerWord ? 0 : OneBit << (n))
+#define nth_bit(n) (((n) >= BitsPerWord) ? 0 : (OneBit << (n)))
#define right_n_bits(n) (nth_bit(n) - 1)
-#define left_n_bits(n) (right_n_bits(n) << (n >= BitsPerWord ? 0 : (BitsPerWord - n)))
+#define left_n_bits(n) (right_n_bits(n) << (((n) >= BitsPerWord) ? 0 : (BitsPerWord - (n))))
// bit-operations using a mask m
inline void set_bits (intptr_t& x, intptr_t m) { x |= m; }
--- a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -322,4 +322,8 @@
#define THREAD_LOCAL_DECL __thread
#endif
+// Inlining support
+#define NOINLINE __attribute__ ((noinline))
+#define ALWAYSINLINE __attribute__ ((always_inline))
+
#endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_GCC_HPP
--- a/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -277,4 +277,8 @@
#define THREAD_LOCAL_DECL __thread
#endif
+// Inlining support
+#define NOINLINE
+#define ALWAYSINLINE __attribute__((always_inline))
+
#endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_SPARCWORKS_HPP
--- a/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_visCPP.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -240,4 +240,11 @@
#define THREAD_LOCAL_DECL __declspec( thread )
#endif
+// Inlining support
+// MSVC has '__declspec(noinline)' but according to the official documentation
+// it only applies to member functions. There are reports though which pretend
+// that it also works for freestanding functions.
+#define NOINLINE __declspec(noinline)
+#define ALWAYSINLINE __forceinline
+
#endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_VISCPP_HPP
--- a/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2013 SAP SE. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016 SAP SE. 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
@@ -184,4 +184,8 @@
#define THREAD_LOCAL_DECL __thread
#endif
+// Inlining support
+#define NOINLINE
+#define ALWAYSINLINE __attribute__((always_inline))
+
#endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_XLC_HPP
--- a/hotspot/src/share/vm/utilities/internalVMTests.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/internalVMTests.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -69,6 +69,7 @@
run_unit_test(JSON_test);
run_unit_test(Test_log_length);
run_unit_test(Test_configure_stdout);
+ run_unit_test(Test_logconfiguration_subscribe);
run_unit_test(DirectivesParser_test);
run_unit_test(Test_TempNewSymbol);
#if INCLUDE_VM_STRUCTS
--- a/hotspot/src/share/vm/utilities/ostream.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/ostream.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -504,7 +504,7 @@
if (_file != NULL) {
_need_close = true;
} else {
- warning("Cannot open file %s due to %s\n", file_name, strerror(errno));
+ warning("Cannot open file %s due to %s\n", file_name, os::strerror(errno));
_need_close = false;
}
}
@@ -514,7 +514,7 @@
if (_file != NULL) {
_need_close = true;
} else {
- warning("Cannot open file %s due to %s\n", file_name, strerror(errno));
+ warning("Cannot open file %s due to %s\n", file_name, os::strerror(errno));
_need_close = false;
}
}
--- a/hotspot/src/share/vm/utilities/stack.inline.hpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/stack.inline.hpp Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, 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,17 +27,6 @@
#include "utilities/stack.hpp"
-// Stack is used by the GC code and in some hot paths a lot of the Stack
-// code gets inlined. This is generally good, but when too much code has
-// been inlined, no further inlining is allowed by GCC. Therefore we need
-// to prevent parts of the slow path in Stack to be inlined to allow other
-// code to be.
-#if defined(TARGET_COMPILER_gcc)
-#define NOINLINE __attribute__((noinline))
-#else
-#define NOINLINE
-#endif
-
template <MEMFLAGS F> StackBase<F>::StackBase(size_t segment_size, size_t max_cache_size,
size_t max_size):
_seg_size(segment_size),
@@ -151,6 +140,11 @@
FREE_C_HEAP_ARRAY(char, (char*) addr);
}
+// Stack is used by the GC code and in some hot paths a lot of the Stack
+// code gets inlined. This is generally good, but when too much code has
+// been inlined, no further inlining is allowed by GCC. Therefore we need
+// to prevent parts of the slow path in Stack to be inlined to allow other
+// code to be.
template <class E, MEMFLAGS F>
NOINLINE void Stack<E, F>::push_segment()
{
@@ -280,6 +274,4 @@
return _cur_seg + --_cur_seg_size;
}
-#undef NOINLINE
-
#endif // SHARE_VM_UTILITIES_STACK_INLINE_HPP
--- a/hotspot/src/share/vm/utilities/vmError.cpp Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/src/share/vm/utilities/vmError.cpp Sat Mar 19 01:23:46 2016 +0100
@@ -1260,8 +1260,9 @@
out.print_raw("#\n# Compiler replay data is saved as:\n# ");
out.print_raw_cr(buffer);
} else {
+ int e = errno;
out.print_raw("#\n# Can't open file to dump replay data. Error: ");
- out.print_raw_cr(strerror(os::get_last_error()));
+ out.print_raw_cr(os::strerror(e));
}
}
}
@@ -1301,7 +1302,8 @@
out.print_raw_cr("\" ...");
if (os::fork_and_exec(cmd) < 0) {
- out.print_cr("os::fork_and_exec failed: %s (%d)", strerror(errno), errno);
+ out.print_cr("os::fork_and_exec failed: %s (%s=%d)",
+ os::strerror(errno), os::errno_name(errno), errno);
}
}
@@ -1359,7 +1361,8 @@
tty->print_cr("\"%s\"...", cmd);
if (os::fork_and_exec(cmd) < 0) {
- tty->print_cr("os::fork_and_exec failed: %s (%d)", strerror(errno), errno);
+ tty->print_cr("os::fork_and_exec failed: %s (%s=%d)",
+ os::strerror(errno), os::errno_name(errno), errno);
}
}
}
--- a/hotspot/test/gc/arguments/TestMaxHeapSizeTools.java Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/test/gc/arguments/TestMaxHeapSizeTools.java Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+* Copyright (c) 2013, 2016, 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
@@ -112,10 +112,12 @@
}
private static void checkInvalidMinInitialHeapCombinations(String gcflag) throws Exception {
+ expectError(new String[] { gcflag, "-XX:InitialHeapSize=1023K", "-version" });
expectError(new String[] { gcflag, "-Xms64M", "-XX:InitialHeapSize=32M", "-version" });
}
private static void checkValidMinInitialHeapCombinations(String gcflag) throws Exception {
+ expectValid(new String[] { gcflag, "-XX:InitialHeapSize=1024K", "-version" });
expectValid(new String[] { gcflag, "-XX:InitialHeapSize=8M", "-Xms4M", "-version" });
expectValid(new String[] { gcflag, "-Xms4M", "-XX:InitialHeapSize=8M", "-version" });
expectValid(new String[] { gcflag, "-XX:InitialHeapSize=8M", "-Xms8M", "-version" });
@@ -124,11 +126,13 @@
}
private static void checkInvalidInitialMaxHeapCombinations(String gcflag) throws Exception {
+ expectError(new String[] { gcflag, "-XX:MaxHeapSize=2047K", "-version" });
expectError(new String[] { gcflag, "-XX:MaxHeapSize=4M", "-XX:InitialHeapSize=8M", "-version" });
expectError(new String[] { gcflag, "-XX:InitialHeapSize=8M", "-XX:MaxHeapSize=4M", "-version" });
}
private static void checkValidInitialMaxHeapCombinations(String gcflag) throws Exception {
+ expectValid(new String[] { gcflag, "-XX:MaxHeapSize=2048K", "-version" });
expectValid(new String[] { gcflag, "-XX:InitialHeapSize=4M", "-XX:MaxHeapSize=8M", "-version" });
expectValid(new String[] { gcflag, "-XX:MaxHeapSize=8M", "-XX:InitialHeapSize=4M", "-version" });
expectValid(new String[] { gcflag, "-XX:MaxHeapSize=4M", "-XX:InitialHeapSize=4M", "-version" });
--- a/hotspot/test/gc/arguments/TestSelectDefaultGC.java Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/test/gc/arguments/TestSelectDefaultGC.java Sat Mar 19 01:23:46 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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,9 +27,9 @@
* @bug 8068582
* @key gc
* @library /testlibrary
+ * @requires vm.gc=="null"
* @modules java.base/sun.misc
* java.management
- * @ignore 8148239
* @run driver TestSelectDefaultGC
*/
@@ -41,24 +41,40 @@
output.shouldMatch(" " + option + " .*=.* " + value + " ");
}
- public static void main(String[] args) throws Exception {
+ public static void testDefaultGC(boolean actAsServer) throws Exception {
+ String[] args = new String[] {
+ "-XX:" + (actAsServer ? "+" : "-") + "AlwaysActAsServerClassMachine",
+ "-XX:" + (actAsServer ? "-" : "+") + "NeverActAsServerClassMachine",
+ "-XX:+PrintFlagsFinal",
+ "-version"
+ };
+
// Start VM without specifying GC
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+PrintFlagsFinal", "-version");
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args);
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
- boolean isServerVM = Platform.isServer();
- boolean isEmbeddedVM = Platform.isEmbedded();
+ final boolean isServer = actAsServer;
+ final boolean isEmbedded = Platform.isEmbedded();
// Verify GC selection
- // G1 is default for non-embedded server VMs
- assertVMOption(output, "UseG1GC", isServerVM && !isEmbeddedVM);
- // Parallel is default for embedded server VMs
- assertVMOption(output, "UseParallelGC", isServerVM && isEmbeddedVM);
- assertVMOption(output, "UseParallelOldGC", isServerVM && isEmbeddedVM);
- // Serial is default for non-server VMs
- assertVMOption(output, "UseSerialGC", !isServerVM);
+ // G1 is default for non-embedded server class machines
+ assertVMOption(output, "UseG1GC", isServer && !isEmbedded);
+ // Parallel is default for embedded server class machines
+ assertVMOption(output, "UseParallelGC", isServer && isEmbedded);
+ assertVMOption(output, "UseParallelOldGC", isServer && isEmbedded);
+ // Serial is default for non-server class machines
+ assertVMOption(output, "UseSerialGC", !isServer);
+ // CMS is never default
assertVMOption(output, "UseConcMarkSweepGC", false);
assertVMOption(output, "UseParNewGC", false);
}
+
+ public static void main(String[] args) throws Exception {
+ // Test server class machine
+ testDefaultGC(false);
+
+ // Test non-server class machine
+ testDefaultGC(true);
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/TestRegionLivenessPrint.java Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+/*
+ * @test TestRegionLivenessPrint.java
+ * @bug 8151920
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @summary Make sure that G1 does not assert when printing region liveness data on a humongous continues region.
+ * @key gc
+ * @library /testlibrary /test/lib
+ * @modules java.base/sun.misc
+ * @build TestRegionLivenessPrint
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+WhiteBoxAPI -XX:+UseG1GC -Xmx128M -XX:G1HeapRegionSize=1m -Xlog:gc+liveness=trace TestRegionLivenessPrint
+ */
+
+import sun.hotspot.WhiteBox;
+
+public class TestRegionLivenessPrint {
+
+ static byte[] bigobj = new byte[1024* 1024 * 2];
+
+ public static void main(String[] args) throws InterruptedException {
+ WhiteBox wb = WhiteBox.getWhiteBox();
+ // Run a concurrent mark cycle to trigger the liveness accounting log messages.
+ wb.g1StartConcMarkCycle();
+ while (wb.g1InConcurrentMark()) {
+ Thread.sleep(100);
+ }
+ }
+
+}
--- a/hotspot/test/gc/g1/TestStringSymbolTableStats.java Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/test/gc/g1/TestStringSymbolTableStats.java Sat Mar 19 01:23:46 2016 +0100
@@ -39,7 +39,7 @@
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
"-XX:+UnlockExperimentalVMOptions",
- "-Xlog:gc+stringdedup=trace",
+ "-Xlog:gc+stringtable=trace",
SystemGCTest.class.getName());
OutputAnalyzer output = new OutputAnalyzer(pb.start());
--- a/hotspot/test/gc/g1/plab/TestPLABPromotion.java Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/test/gc/g1/plab/TestPLABPromotion.java Sat Mar 19 01:23:46 2016 +0100
@@ -27,7 +27,7 @@
* @summary Test PLAB promotion
* @requires vm.gc=="G1" | vm.gc=="null"
* @requires vm.opt.FlightRecorder != true
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @modules java.management
* @build ClassFileInstaller
* sun.hotspot.WhiteBox
--- a/hotspot/test/gc/g1/plab/TestPLABResize.java Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/test/gc/g1/plab/TestPLABResize.java Sat Mar 19 01:23:46 2016 +0100
@@ -27,7 +27,7 @@
* @summary Test for PLAB resizing
* @requires vm.gc=="G1" | vm.gc=="null"
* @requires vm.opt.FlightRecorder != true
- * @library /testlibrary /../../test/lib /
+ * @library /testlibrary /test/lib /
* @modules java.management
* @build ClassFileInstaller
* sun.hotspot.WhiteBox
@@ -122,29 +122,23 @@
.collect(Collectors.toCollection(ArrayList::new));
// Check that desired plab size was changed during iterations.
- // It should decrease during first half of iterations
- // and increase after.
- List<Long> decreasedPlabs = plabSizes.subList(testCase.getIterations(), testCase.getIterations() * 2);
- List<Long> increasedPlabs = plabSizes.subList(testCase.getIterations() * 2, testCase.getIterations() * 3);
+ // The test case does 3 rounds of allocations. The second round of N allocations and GC's
+ // has a decreasing size of allocations so that iterations N to 2*N -1 will be of decreasing size.
+ // The third round with iterations 2*N to 3*N -1 has increasing sizes of allocation.
+ long startDesiredPLABSize = plabSizes.get(testCase.getIterations());
+ long endDesiredPLABSize = plabSizes.get(testCase.getIterations() * 2 - 1);
- Long prev = decreasedPlabs.get(0);
- for (int index = 1; index < decreasedPlabs.size(); ++index) {
- Long current = decreasedPlabs.get(index);
- if (prev < current) {
- System.out.println(output);
- throw new RuntimeException("Test failed! Expect that previous PLAB size should be greater than current. Prev.size: " + prev + " Current size:" + current);
- }
- prev = current;
+ if (startDesiredPLABSize < endDesiredPLABSize) {
+ System.out.println(output);
+ throw new RuntimeException("Test failed! Expect that initial PLAB size should be greater than checked. Initial size: " + startDesiredPLABSize + " Checked size:" + endDesiredPLABSize);
}
- prev = increasedPlabs.get(0);
- for (int index = 1; index < increasedPlabs.size(); ++index) {
- Long current = increasedPlabs.get(index);
- if (prev > current) {
- System.out.println(output);
- throw new RuntimeException("Test failed! Expect that previous PLAB size should be less than current. Prev.size: " + prev + " Current size:" + current);
- }
- prev = current;
+ startDesiredPLABSize = plabSizes.get(testCase.getIterations() * 2);
+ endDesiredPLABSize = plabSizes.get(testCase.getIterations() * 3 - 1);
+
+ if (startDesiredPLABSize > endDesiredPLABSize) {
+ System.out.println(output);
+ throw new RuntimeException("Test failed! Expect that initial PLAB size should be less than checked. Initial size: " + startDesiredPLABSize + " Checked size:" + endDesiredPLABSize);
}
System.out.println("Test passed!");
@@ -195,7 +189,6 @@
return Arrays.asList("-XX:ParallelGCThreads=" + parGCThreads,
"-XX:ParallelGCBufferWastePct=" + wastePct,
"-XX:+ResizePLAB",
- "-Dthreads=" + parGCThreads,
"-Dchunk.size=" + chunkSize,
"-Diterations=" + iterations,
"-XX:NewSize=16m",
--- a/hotspot/test/gc/g1/plab/lib/AppPLABResize.java Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/test/gc/g1/plab/lib/AppPLABResize.java Sat Mar 19 01:23:46 2016 +0100
@@ -38,7 +38,6 @@
* Expects the following properties to be set:
* - iterations - amount of iteration per cycle.
* - chunk.size - size of objects to be allocated
- * - threads - number of gc threads (-XX:ParallelGCThreads) to calculate PLAB sizes.
*/
final public class AppPLABResize {
@@ -47,7 +46,6 @@
// Defined by properties.
private static final int ITERATIONS = Integer.getInteger("iterations");
private static final long CHUNK = Long.getLong("chunk.size");
- private static final int GC_THREADS = Integer.getInteger("threads");
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
@@ -59,13 +57,13 @@
*/
public static void main(String[] args) {
- if (ITERATIONS == 0 || CHUNK == 0 || GC_THREADS == 0) {
+ if (ITERATIONS == 0 || CHUNK == 0) {
throw new IllegalArgumentException("Properties should be set");
}
long wordSize = Platform.is32bit() ? 4l : 8l;
// PLAB size is shared between threads.
- long initialMemorySize = wordSize * GC_THREADS * MEM_ALLOC_WORDS;
+ long initialMemorySize = wordSize * MEM_ALLOC_WORDS;
// Expect changing memory to half during all iterations.
long memChangeStep = initialMemorySize / 2 / ITERATIONS;
--- a/hotspot/test/gc/g1/plab/lib/LogParser.java Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/test/gc/g1/plab/lib/LogParser.java Sat Mar 19 01:23:46 2016 +0100
@@ -57,7 +57,8 @@
private final String log;
- private final Map<Long, Map<ReportType, Map<String,Long>>> reportHolder;
+ // Contains Map of PLAB statistics for given log.
+ private final Map<Long, Map<ReportType, Map<String, Long>>> report;
// GC ID
private static final Pattern GC_ID_PATTERN = Pattern.compile("\\[gc,plab\\s*\\] GC\\((\\d+)\\)");
@@ -65,7 +66,7 @@
private static final Pattern PAIRS_PATTERN = Pattern.compile("\\w* \\w+:\\s+\\d+");
/**
- * Construct LogParser Object
+ * Construct LogParser object, parse log file with PLAB statistics and store it into report.
*
* @param log - VM Output
*/
@@ -74,43 +75,44 @@
throw new IllegalArgumentException("Parameter log should not be null.");
}
this.log = log;
- reportHolder = parseLines();
+ report = parseLines();
}
/**
- * @return log which is being processed
+ * @return log which was processed
*/
public String getLog() {
return log;
}
/**
- * Returns list of log entries.
+ * Returns the GC log entries for Survivor and Old stats.
+ * The entries are represented as a map of gcID to the StatMap.
*
- * @return list of Pair with ReportType and Map of parameters/values.
+ * @return The log entries for the Survivor and Old stats.
*/
- public Map<Long,Map<ReportType, Map<String,Long>>> getEntries() {
- return reportHolder;
+ public Map<Long, Map<ReportType, Map<String, Long>>> getEntries() {
+ return report;
}
- private Map<Long,Map<ReportType, Map<String,Long>>> parseLines() throws NumberFormatException {
+ private Map<Long, Map<ReportType, Map<String, Long>>> parseLines() throws NumberFormatException {
Scanner lineScanner = new Scanner(log);
- Map<Long,Map<ReportType, Map<String,Long>>> allocationStatistics = new HashMap<>();
+ Map<Long, Map<ReportType, Map<String, Long>>> allocationStatistics = new HashMap<>();
Optional<Long> gc_id;
while (lineScanner.hasNextLine()) {
String line = lineScanner.nextLine();
gc_id = getGcId(line);
- if ( gc_id.isPresent() ) {
+ if (gc_id.isPresent()) {
Matcher matcher = PAIRS_PATTERN.matcher(line);
if (matcher.find()) {
- Map<ReportType,Map<String, Long>> oneReportItem;
+ Map<ReportType, Map<String, Long>> oneReportItem;
ReportType reportType;
if (!allocationStatistics.containsKey(gc_id.get())) {
- allocationStatistics.put(gc_id.get(), new EnumMap<>(ReportType.class));
+ allocationStatistics.put(gc_id.get(), new EnumMap<>(ReportType.class));
}
- if ( line.contains("Young") ) {
+ if (line.contains("Young")) {
reportType = ReportType.SURVIVOR_STATS;
} else {
reportType = ReportType.OLD_STATS;
@@ -118,7 +120,7 @@
oneReportItem = allocationStatistics.get(gc_id.get());
if (!oneReportItem.containsKey(reportType)) {
- oneReportItem.put(reportType,new HashMap<String, Long>());
+ oneReportItem.put(reportType, new HashMap<>());
}
// Extract all pairs from log.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/Throwable/StackTraceLogging.java Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+/*
+ * @test
+ * @bug 8150778
+ * @summary check stacktrace logging
+ * @library /testlibrary
+ * @modules java.base/sun.misc
+ * java.management
+ * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools
+ * @compile TestThrowable.java
+ * @run driver StackTraceLogging
+ */
+
+import java.io.File;
+import java.util.Map;
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+
+public class StackTraceLogging {
+ static void updateEnvironment(ProcessBuilder pb, String environmentVariable, String value) {
+ Map<String, String> env = pb.environment();
+ env.put(environmentVariable, value);
+ }
+
+ static void analyzeOutputOn(ProcessBuilder pb) throws Exception {
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ // These depths match the ones in TestThrowable.java
+ int[] depths = {10, 34, 100, 1024};
+ for (int d : depths) {
+ output.shouldContain("java.lang.RuntimeException, " + d);
+ }
+ output.shouldHaveExitValue(0);
+ }
+
+
+ public static void main(String[] args) throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:stacktrace=info",
+ "-XX:MaxJavaStackTraceDepth=1024",
+ "TestThrowable");
+ analyzeOutputOn(pb);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/Throwable/TestThrowable.java Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+/*
+ * @test
+ * @bug 8150778
+ * @summary Test exception depths, and code to get stack traces
+ * @library /testlibrary
+ * @run main/othervm -XX:MaxJavaStackTraceDepth=1024 TestThrowable
+ */
+
+import java.lang.reflect.Field;
+import jdk.test.lib.Asserts;
+
+public class TestThrowable {
+
+ // Inner class that throws a lot of exceptions
+ static class Thrower {
+ static int MaxJavaStackTraceDepth = 1024; // as above
+ int[] depths = {10, 34, 100, 1024, 2042};
+ int count = 0;
+
+ int getDepth(Throwable t) throws Exception {
+ Field f = Throwable.class.getDeclaredField("depth");
+ f.setAccessible(true); // it's private
+ return f.getInt(t);
+ }
+
+ void callThrow(int depth) {
+ if (++count < depth) {
+ callThrow(depth);
+ } else {
+ throw new RuntimeException("depth tested " + depth);
+ }
+ }
+ void testThrow() throws Exception {
+ for (int d : depths) {
+ try {
+ count = getDepth(new Throwable());
+ callThrow(d);
+ } catch(Exception e) {
+ e.getStackTrace();
+ System.out.println(e.getMessage());
+ int throwableDepth = getDepth(e);
+ Asserts.assertTrue(throwableDepth == d ||
+ (d > MaxJavaStackTraceDepth && throwableDepth == MaxJavaStackTraceDepth),
+ "depth should return the correct value: depth tested=" +
+ d + " throwableDepth=" + throwableDepth);
+ }
+ }
+ }
+ }
+
+ public static void main(String... unused) throws Exception {
+ Thrower t = new Thrower();
+ t.testThrow();
+ }
+}
--- a/hotspot/test/runtime/logging/ClassInitializationTest.java Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/test/runtime/logging/ClassInitializationTest.java Sat Mar 19 01:23:46 2016 +0100
@@ -62,16 +62,6 @@
out.shouldContain("[Initialized").shouldContain("without side effects]");
out.shouldHaveExitValue(0);
}
- // (3) Ensure that VerboseVerification still triggers appropriate messages.
- pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockDiagnosticVMOptions",
- "-XX:+VerboseVerification",
- "-Xverify:all",
- "-Xmx64m",
- "BadMap50");
- out = new OutputAnalyzer(pb.start());
- out.shouldContain("End class verification for:");
- out.shouldContain("Verification for BadMap50 failed");
- out.shouldContain("Fail over class verification to old verifier for: BadMap50");
}
public static class InnerClass {
public static void main(String[] args) throws Exception {
--- a/hotspot/test/runtime/logging/ClassResolutionTest.java Wed Mar 16 14:31:33 2016 +0100
+++ b/hotspot/test/runtime/logging/ClassResolutionTest.java Sat Mar 19 01:23:46 2016 +0100
@@ -58,13 +58,13 @@
public static void main(String... args) throws Exception {
// (1) classresolve should turn on.
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:classresolve=info",
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:classresolve=debug",
ClassResolutionTestMain.class.getName());
OutputAnalyzer o = new OutputAnalyzer(pb.start());
o.shouldContain("[classresolve] ClassResolutionTest$ClassResolutionTestMain$Thing1Handler ClassResolutionTest$ClassResolutionTestMain$Thing1");
// (2) classresolve should turn off.
- pb = ProcessTools.createJavaProcessBuilder("-Xlog",
+ pb = ProcessTools.createJavaProcessBuilder("-Xlog:classresolve=debug",
"-Xlog:classresolve=off",
ClassResolutionTestMain.class.getName());
o = new OutputAnalyzer(pb.start());
@@ -77,12 +77,12 @@
o.shouldContain("[classresolve] ClassResolutionTest$ClassResolutionTestMain$Thing1Handler ClassResolutionTest$ClassResolutionTestMain$Thing1");
// (4) TraceClassResolution should turn off.
- pb = ProcessTools.createJavaProcessBuilder("-Xlog",
+ pb = ProcessTools.createJavaProcessBuilder("-Xlog:classresolve=debug",
"-XX:-TraceClassResolution",
ClassResolutionTestMain.class.getName());
o = new OutputAnalyzer(pb.start());
o.shouldNotContain("[classresolve]");
+ };
- };
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/logging/SafepointCleanupTest.java Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+/*
+ * @test
+ * @bug 8149991
+ * @summary safepointcleanup=info should have output from the code
+ * @library /testlibrary
+ * @modules java.base/sun.misc
+ * java.management
+ * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools
+ * @run driver SafepointCleanupTest
+ */
+
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+
+public class SafepointCleanupTest {
+ static void analyzeOutputOn(ProcessBuilder pb) throws Exception {
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldContain("[safepointcleanup]");
+ output.shouldContain("deflating idle monitors");
+ output.shouldContain("updating inline caches");
+ output.shouldContain("compilation policy safepoint handler");
+ output.shouldContain("mark nmethods");
+ output.shouldContain("purging class loader data graph");
+ output.shouldHaveExitValue(0);
+ }
+
+ static void analyzeOutputOff(ProcessBuilder pb) throws Exception {
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldNotContain("[safepointcleanup]");
+ output.shouldHaveExitValue(0);
+ }
+
+ public static void main(String[] args) throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:safepointcleanup=info",
+ InnerClass.class.getName());
+ analyzeOutputOn(pb);
+
+ pb = ProcessTools.createJavaProcessBuilder("-XX:+TraceSafepointCleanupTime",
+ InnerClass.class.getName());
+ analyzeOutputOn(pb);
+
+ pb = ProcessTools.createJavaProcessBuilder("-Xlog:safepointcleanup=off",
+ InnerClass.class.getName());
+ analyzeOutputOff(pb);
+
+ pb = ProcessTools.createJavaProcessBuilder("-XX:-TraceSafepointCleanupTime",
+ InnerClass.class.getName());
+ analyzeOutputOff(pb);
+ }
+
+ public static class InnerClass {
+ public static void main(String[] args) throws Exception {
+ System.out.println("Safepoint Cleanup test");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/logging/VerboseVerificationTest.java Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+/*
+ * @test
+ * @bug 8150083
+ * @summary verboseverification=info output should have output from the code
+ * @library /testlibrary
+ * @modules java.base/sun.misc
+ * java.management
+ * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools
+ * @run driver VerboseVerificationTest
+ */
+
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+
+public class VerboseVerificationTest {
+ static void analyzeOutputOn(ProcessBuilder pb) throws Exception {
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldContain("[verboseverification]");
+ output.shouldContain("Verifying class VerboseVerificationTest$InternalClass with new format");
+ output.shouldContain("Verifying method VerboseVerificationTest$InternalClass.<init>()V");
+ output.shouldContain("End class verification for: VerboseVerificationTest$InternalClass");
+ output.shouldHaveExitValue(0);
+ }
+
+ static void analyzeOutputOff(ProcessBuilder pb) throws Exception {
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldNotContain("[verboseverification]");
+ output.shouldHaveExitValue(0);
+ }
+
+ public static void main(String[] args) throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:verboseverification=info",
+ InternalClass.class.getName());
+ analyzeOutputOn(pb);
+
+ pb = ProcessTools.createJavaProcessBuilder("-Xlog:verboseverification=off",
+ InternalClass.class.getName());
+ analyzeOutputOff(pb);
+ }
+
+ public static class InternalClass {
+ public static void main(String[] args) throws Exception {
+ System.out.println("VerboseVerificationTest");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/stress/gc/TestMultiThreadStressRSet.java Sat Mar 19 01:23:46 2016 +0100
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import sun.hotspot.WhiteBox;
+
+/*
+ * @test TestMultiThreadStressRSet.java
+ * @key stress
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @requires os.maxMemory > 2G
+ *
+ * @summary Stress G1 Remembered Set using multiple threads
+ * @library /test/lib /testlibrary
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=1 -Xlog:gc
+ * -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 10 4
+ *
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc
+ * -Xmx1G -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 60 16
+ *
+ * @run main/othervm/timeout=700 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * -XX:+UseG1GC -XX:G1SummarizeRSetStatsPeriod=100 -Xlog:gc
+ * -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestMultiThreadStressRSet 600 32
+ */
+public class TestMultiThreadStressRSet {
+
+ private static final Random RND = new Random(2015 * 2016);
+ private static final WhiteBox WB = WhiteBox.getWhiteBox();
+ private static final int REF_SIZE = WB.getHeapOopSize();
+ private static final int REGION_SIZE = WB.g1RegionSize();
+
+ // How many regions to use for the storage
+ private static final int STORAGE_REGIONS = 20;
+
+ // Size a single obj in the storage
+ private static final int OBJ_SIZE = 1024;
+
+ // How many regions of young/old gen to use in the BUFFER
+ private static final int BUFFER_YOUNG_REGIONS = 60;
+ private static final int BUFFER_OLD_REGIONS = 40;
+
+ // Total number of objects in the storage.
+ private final int N;
+
+ // The storage of byte[]
+ private final List<Object> STORAGE;
+
+ // Where references to the Storage will be stored
+ private final List<Object[]> BUFFER;
+
+ // The length of a buffer element.
+ // RSet deals with "cards" (areas of 512 bytes), not with single refs
+ // So, to affect the RSet the BUFFER refs should be allocated in different
+ // memory cards.
+ private final int BUF_ARR_LEN = 100 * (512 / REF_SIZE);
+
+ // Total number of objects in the young/old buffers
+ private final int YOUNG;
+ private final int OLD;
+
+ // To cause Remembered Sets change their coarse level the test uses a window
+ // within STORAGE. All the BUFFER elements refer to only STORAGE objects
+ // from the current window. The window is defined by a range.
+ // The first element has got the index: 'windowStart',
+ // the last one: 'windowStart + windowSize - 1'
+ // The window is shifting periodically.
+ private int windowStart;
+ private final int windowSize;
+
+ // Counter of created worker threads
+ private int counter = 0;
+
+ private volatile String errorMessage = null;
+ private volatile boolean isEnough = false;
+
+ public static void main(String args[]) {
+ if (args.length != 2) {
+ throw new IllegalArgumentException("TEST BUG: wrong arg count " + args.length);
+ }
+ long time = Long.parseLong(args[0]);
+ int threads = Integer.parseInt(args[1]);
+ new TestMultiThreadStressRSet().test(time * 1000, threads);
+ }
+
+ /**
+ * Initiates test parameters, fills out the STORAGE and BUFFER.
+ */
+ public TestMultiThreadStressRSet() {
+
+ N = (REGION_SIZE - 1) * STORAGE_REGIONS / OBJ_SIZE + 1;
+ STORAGE = new ArrayList<>(N);
+ int bytes = OBJ_SIZE - 20;
+ for (int i = 0; i < N - 1; i++) {
+ STORAGE.add(new byte[bytes]);
+ }
+ STORAGE.add(new byte[REGION_SIZE / 2 + 100]); // humongous
+ windowStart = 0;
+ windowSize = REGION_SIZE / OBJ_SIZE;
+
+ BUFFER = new ArrayList<>();
+ int sizeOfBufferObject = 20 + REF_SIZE * BUF_ARR_LEN;
+ OLD = REGION_SIZE * BUFFER_OLD_REGIONS / sizeOfBufferObject;
+ YOUNG = REGION_SIZE * BUFFER_YOUNG_REGIONS / sizeOfBufferObject;
+ for (int i = 0; i < OLD + YOUNG; i++) {
+ BUFFER.add(new Object[BUF_ARR_LEN]);
+ }
+ }
+
+ /**
+ * Does the testing. Steps:
+ * <ul>
+ * <li> starts the Shifter thread
+ * <li> during the given time starts new Worker threads, keeping the number
+ * of live thread under limit.
+ * <li> stops the Shifter thread
+ * </ul>
+ *
+ * @param timeInMillis how long to stress
+ * @param maxThreads the maximum number of Worker thread working together.
+ */
+ public void test(long timeInMillis, int maxThreads) {
+ if (timeInMillis <= 0 || maxThreads <= 0) {
+ throw new IllegalArgumentException("TEST BUG: be positive!");
+ }
+ System.out.println("%% Time to work: " + timeInMillis / 1000 + "s");
+ System.out.println("%% Number of threads: " + maxThreads);
+ long finish = System.currentTimeMillis() + timeInMillis;
+ Shifter shift = new Shifter(this, 1000, (int) (windowSize * 0.9));
+ shift.start();
+ for (int i = 0; i < maxThreads; i++) {
+ new Worker(this, 100).start();
+ }
+ try {
+ while (System.currentTimeMillis() < finish && errorMessage == null) {
+ Thread.sleep(100);
+ }
+ } catch (Throwable t) {
+ printAllStackTraces(System.err);
+ t.printStackTrace(System.err);
+ this.errorMessage = t.getMessage();
+ } finally {
+ isEnough = true;
+ }
+ System.out.println("%% Total work cycles: " + counter);
+ if (errorMessage != null) {
+ throw new RuntimeException(errorMessage);
+ }
+ }
+
+ /**
+ * Returns an element from from the BUFFER (an object array) to keep
+ * references to the storage.
+ *
+ * @return an Object[] from buffer.
+ */
+ private Object[] getFromBuffer() {
+ int index = counter % (OLD + YOUNG);
+ synchronized (BUFFER) {
+ if (index < OLD) {
+ if (counter % 100 == (counter / 100) % 100) {
+ // need to generate garbage in the old gen to provoke mixed GC
+ return replaceInBuffer(index);
+ } else {
+ return BUFFER.get(index);
+ }
+ } else {
+ return replaceInBuffer(index);
+ }
+ }
+ }
+
+ private Object[] replaceInBuffer(int index) {
+ Object[] objs = new Object[BUF_ARR_LEN];
+ BUFFER.set(index, objs);
+ return objs;
+ }
+
+ /**
+ * Returns a random object from the current window within the storage.
+ * A storage element with index from windowStart to windowStart+windowSize.
+ *
+ * @return a random element from the current window within the storage.
+ */
+ private Object getRandomObject() {
+ int index = (windowStart + RND.nextInt(windowSize)) % N;
+ return STORAGE.get(index);
+ }
+
+ private static void printAllStackTraces(PrintStream ps) {
+ Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
+ for (Thread t : traces.keySet()) {
+ ps.println(t.toString() + " " + t.getState());
+ for (StackTraceElement traceElement : traces.get(t)) {
+ ps.println("\tat " + traceElement);
+ }
+ }
+ }
+
+ /**
+ * Thread to create a number of references from BUFFER to STORAGE.
+ */
+ private static class Worker extends Thread {
+
+ final TestMultiThreadStressRSet boss;
+ final int refs; // number of refs to OldGen
+
+ /**
+ * @param boss the tests
+ * @param refsToOldGen how many references to the OldGen to create
+ */
+ Worker(TestMultiThreadStressRSet boss, int refsToOldGen) {
+ this.boss = boss;
+ this.refs = refsToOldGen;
+ }
+
+ @Override
+ public void run() {
+ try {
+ while (!boss.isEnough) {
+ Object[] objs = boss.getFromBuffer();
+ int step = objs.length / refs;
+ for (int i = 0; i < refs; i += step) {
+ objs[i] = boss.getRandomObject();
+ }
+ boss.counter++;
+ }
+ } catch (Throwable t) {
+ t.printStackTrace(System.out);
+ boss.errorMessage = t.getMessage();
+ }
+ }
+ }
+
+ /**
+ * Periodically shifts the current STORAGE window, removing references
+ * in BUFFER that refer to objects outside the window.
+ */
+ private static class Shifter extends Thread {
+
+ final TestMultiThreadStressRSet boss;
+ final int sleepTime;
+ final int shift;
+
+ Shifter(TestMultiThreadStressRSet boss, int sleepTime, int shift) {
+ this.boss = boss;
+ this.sleepTime = sleepTime;
+ this.shift = shift;
+ }
+
+ @Override
+ public void run() {
+ try {
+ while (!boss.isEnough) {
+ Thread.sleep(sleepTime);
+ boss.windowStart += shift;
+ for (int i = 0; i < boss.OLD; i++) {
+ Object[] objs = boss.BUFFER.get(i);
+ for (int j = 0; j < objs.length; j++) {
+ objs[j] = null;
+ }
+ }
+ if (!WB.g1InConcurrentMark()) {
+ System.out.println("%% start CMC");
+ WB.g1StartConcMarkCycle();
+ } else {
+ System.out.println("%% CMC is already in progress");
+ }
+ }
+ } catch (Throwable t) {
+ t.printStackTrace(System.out);
+ boss.errorMessage = t.getMessage();
+ }
+ }
+ }
+}
+