aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoramurillo <none@none>2013-06-13 23:28:20 -0700
committeramurillo <none@none>2013-06-13 23:28:20 -0700
commit8fba2a7da12410200d778e74a6e030b61534ce6c (patch)
tree5eb702749e3c1c59bf024a43b5059e8a32222320
parent6facf90d65eb8d77537adb3c18291948a9ce7d8f (diff)
parente01d4cd81c26df1ff01ecf7f78539166aaae6bbf (diff)
-rw-r--r--make/Makefile2
-rw-r--r--make/bsd/makefiles/buildtree.make14
-rw-r--r--make/bsd/makefiles/minimal1.make3
-rw-r--r--make/bsd/makefiles/top.make8
-rw-r--r--make/bsd/makefiles/trace.make121
-rw-r--r--make/bsd/makefiles/vm.make24
-rw-r--r--make/defs.make13
-rw-r--r--make/excludeSrc.make6
-rw-r--r--make/hotspot_version2
-rw-r--r--make/linux/makefiles/buildtree.make18
-rw-r--r--make/linux/makefiles/minimal1.make3
-rw-r--r--make/linux/makefiles/top.make8
-rw-r--r--make/linux/makefiles/trace.make120
-rw-r--r--make/linux/makefiles/vm.make30
-rw-r--r--make/solaris/makefiles/buildtree.make16
-rw-r--r--make/solaris/makefiles/top.make10
-rw-r--r--make/solaris/makefiles/trace.make116
-rw-r--r--make/solaris/makefiles/vm.make24
-rw-r--r--make/windows/build.make7
-rw-r--r--make/windows/create_obj_files.sh8
-rw-r--r--make/windows/makefiles/generated.make10
-rw-r--r--make/windows/makefiles/projectcreator.make18
-rw-r--r--make/windows/makefiles/trace.make121
-rw-r--r--make/windows/makefiles/vm.make18
-rw-r--r--make/windows/projectfiles/common/Makefile14
-rw-r--r--src/cpu/sparc/vm/frame_sparc.cpp14
-rw-r--r--src/cpu/x86/vm/frame_x86.cpp70
-rw-r--r--src/os/bsd/vm/osThread_bsd.hpp4
-rw-r--r--src/os/bsd/vm/os_bsd.cpp309
-rw-r--r--src/os/bsd/vm/os_bsd.hpp34
-rw-r--r--src/os/bsd/vm/os_bsd.inline.hpp16
-rw-r--r--src/os/linux/vm/osThread_linux.hpp4
-rw-r--r--src/os/linux/vm/os_linux.cpp250
-rw-r--r--src/os/linux/vm/os_linux.hpp31
-rw-r--r--src/os/linux/vm/os_linux.inline.hpp16
-rw-r--r--src/os/solaris/vm/osThread_solaris.cpp176
-rw-r--r--src/os/solaris/vm/osThread_solaris.hpp58
-rw-r--r--src/os/solaris/vm/os_share_solaris.hpp24
-rw-r--r--src/os/solaris/vm/os_solaris.cpp243
-rw-r--r--src/os/solaris/vm/os_solaris.hpp6
-rw-r--r--src/os/windows/vm/os_windows.cpp65
-rw-r--r--src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp12
-rw-r--r--src/os_cpu/bsd_x86/vm/thread_bsd_x86.hpp9
-rw-r--r--src/os_cpu/linux_x86/vm/thread_linux_x86.cpp11
-rw-r--r--src/os_cpu/linux_x86/vm/thread_linux_x86.hpp7
-rw-r--r--src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp32
-rw-r--r--src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp14
-rw-r--r--src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.hpp7
-rw-r--r--src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp32
-rw-r--r--src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp13
-rw-r--r--src/os_cpu/solaris_x86/vm/thread_solaris_x86.hpp8
-rw-r--r--src/os_cpu/windows_x86/vm/thread_windows_x86.cpp12
-rw-r--r--src/os_cpu/windows_x86/vm/thread_windows_x86.hpp8
-rw-r--r--src/share/tools/ProjectCreator/BuildConfig.java4
-rw-r--r--src/share/vm/classfile/classFileParser.cpp1
-rw-r--r--src/share/vm/classfile/classLoaderData.cpp61
-rw-r--r--src/share/vm/classfile/classLoaderData.hpp16
-rw-r--r--src/share/vm/classfile/javaClasses.cpp2
-rw-r--r--src/share/vm/classfile/systemDictionary.cpp54
-rw-r--r--src/share/vm/classfile/systemDictionary.hpp5
-rw-r--r--src/share/vm/code/codeCache.cpp21
-rw-r--r--src/share/vm/code/codeCache.hpp9
-rw-r--r--src/share/vm/compiler/compileBroker.cpp31
-rw-r--r--src/share/vm/compiler/compileBroker.hpp19
-rw-r--r--src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp170
-rw-r--r--src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp34
-rw-r--r--src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp4
-rw-r--r--src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp20
-rw-r--r--src/share/vm/gc_implementation/g1/concurrentMark.cpp23
-rw-r--r--src/share/vm/gc_implementation/g1/concurrentMark.hpp4
-rw-r--r--src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp8
-rw-r--r--src/share/vm/gc_implementation/g1/evacuationInfo.hpp81
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp208
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp57
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp8
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp5
-rw-r--r--src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp2
-rw-r--r--src/share/vm/gc_implementation/g1/g1MarkSweep.cpp27
-rw-r--r--src/share/vm/gc_implementation/g1/g1MarkSweep.hpp5
-rw-r--r--src/share/vm/gc_implementation/g1/g1MonitoringSupport.hpp3
-rw-r--r--src/share/vm/gc_implementation/g1/g1YCTypes.hpp51
-rw-r--r--src/share/vm/gc_implementation/g1/vm_operations_g1.cpp6
-rw-r--r--src/share/vm/gc_implementation/parNew/parNewGeneration.cpp122
-rw-r--r--src/share/vm/gc_implementation/parNew/parNewGeneration.hpp21
-rw-r--r--src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp33
-rw-r--r--src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp11
-rw-r--r--src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp30
-rw-r--r--src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp37
-rw-r--r--src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp74
-rw-r--r--src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp9
-rw-r--r--src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp18
-rw-r--r--src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp10
-rw-r--r--src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp4
-rw-r--r--src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp73
-rw-r--r--src/share/vm/gc_implementation/parallelScavenge/psScavenge.hpp9
-rw-r--r--src/share/vm/gc_implementation/shared/copyFailedInfo.hpp90
-rw-r--r--src/share/vm/gc_implementation/shared/gcHeapSummary.hpp142
-rw-r--r--src/share/vm/gc_implementation/shared/gcTimer.cpp374
-rw-r--r--src/share/vm/gc_implementation/shared/gcTimer.hpp195
-rw-r--r--src/share/vm/gc_implementation/shared/gcTrace.cpp207
-rw-r--r--src/share/vm/gc_implementation/shared/gcTrace.hpp255
-rw-r--r--src/share/vm/gc_implementation/shared/gcTraceSend.cpp318
-rw-r--r--src/share/vm/gc_implementation/shared/gcTraceTime.cpp79
-rw-r--r--src/share/vm/gc_implementation/shared/gcTraceTime.hpp44
-rw-r--r--src/share/vm/gc_implementation/shared/gcWhen.hpp48
-rw-r--r--src/share/vm/gc_implementation/shared/markSweep.cpp9
-rw-r--r--src/share/vm/gc_implementation/shared/markSweep.hpp10
-rw-r--r--src/share/vm/gc_implementation/shared/vmGCOperations.cpp41
-rw-r--r--src/share/vm/gc_implementation/shared/vmGCOperations.hpp7
-rw-r--r--src/share/vm/gc_interface/allocTracer.cpp48
-rw-r--r--src/share/vm/gc_interface/allocTracer.hpp37
-rw-r--r--src/share/vm/gc_interface/collectedHeap.cpp93
-rw-r--r--src/share/vm/gc_interface/collectedHeap.hpp61
-rw-r--r--src/share/vm/gc_interface/collectedHeap.inline.hpp22
-rw-r--r--src/share/vm/gc_interface/gcCause.cpp3
-rw-r--r--src/share/vm/gc_interface/gcCause.hpp1
-rw-r--r--src/share/vm/gc_interface/gcName.hpp61
-rw-r--r--src/share/vm/memory/allocation.hpp3
-rw-r--r--src/share/vm/memory/defNewGeneration.cpp45
-rw-r--r--src/share/vm/memory/defNewGeneration.hpp12
-rw-r--r--src/share/vm/memory/genCollectedHeap.cpp13
-rw-r--r--src/share/vm/memory/genMarkSweep.cpp28
-rw-r--r--src/share/vm/memory/generation.cpp20
-rw-r--r--src/share/vm/memory/heapInspection.cpp74
-rw-r--r--src/share/vm/memory/heapInspection.hpp33
-rw-r--r--src/share/vm/memory/klassInfoClosure.hpp36
-rw-r--r--src/share/vm/memory/metaspace.hpp7
-rw-r--r--src/share/vm/memory/oopFactory.hpp3
-rw-r--r--src/share/vm/memory/referenceProcessor.cpp86
-rw-r--r--src/share/vm/memory/referenceProcessor.hpp38
-rw-r--r--src/share/vm/memory/referenceProcessorStats.hpp73
-rw-r--r--src/share/vm/memory/referenceType.hpp41
-rw-r--r--src/share/vm/memory/universe.cpp35
-rw-r--r--src/share/vm/memory/universe.hpp28
-rw-r--r--src/share/vm/oops/instanceKlass.hpp2
-rw-r--r--src/share/vm/oops/klass.cpp3
-rw-r--r--src/share/vm/opto/compile.cpp51
-rw-r--r--src/share/vm/opto/compile.hpp37
-rw-r--r--src/share/vm/opto/escape.cpp4
-rw-r--r--src/share/vm/opto/library_call.cpp3
-rw-r--r--src/share/vm/opto/loopnode.cpp10
-rw-r--r--src/share/vm/opto/matcher.cpp6
-rw-r--r--src/share/vm/opto/phasetype.hpp98
-rw-r--r--src/share/vm/precompiled/precompiled.hpp1
-rw-r--r--src/share/vm/prims/jni.cpp19
-rw-r--r--src/share/vm/prims/jvm.cpp11
-rw-r--r--src/share/vm/prims/jvmtiGen.java4
-rw-r--r--src/share/vm/prims/jvmtiImpl.cpp28
-rw-r--r--src/share/vm/prims/jvmtiImpl.hpp77
-rw-r--r--src/share/vm/prims/unsafe.cpp11
-rw-r--r--src/share/vm/runtime/frame.hpp3
-rw-r--r--src/share/vm/runtime/frame.inline.hpp6
-rw-r--r--src/share/vm/runtime/globals.hpp12
-rw-r--r--src/share/vm/runtime/java.cpp12
-rw-r--r--src/share/vm/runtime/mutexLocker.cpp11
-rw-r--r--src/share/vm/runtime/objectMonitor.cpp58
-rw-r--r--src/share/vm/runtime/objectMonitor.hpp15
-rw-r--r--src/share/vm/runtime/os.cpp26
-rw-r--r--src/share/vm/runtime/os.hpp98
-rw-r--r--src/share/vm/runtime/perfData.cpp4
-rw-r--r--src/share/vm/runtime/perfData.hpp3
-rw-r--r--src/share/vm/runtime/stubRoutines.hpp4
-rw-r--r--src/share/vm/runtime/sweeper.cpp81
-rw-r--r--src/share/vm/runtime/sweeper.hpp30
-rw-r--r--src/share/vm/runtime/synchronizer.cpp4
-rw-r--r--src/share/vm/runtime/task.cpp10
-rw-r--r--src/share/vm/runtime/thread.cpp24
-rw-r--r--src/share/vm/runtime/thread.hpp8
-rw-r--r--src/share/vm/runtime/timer.cpp46
-rw-r--r--src/share/vm/runtime/timer.hpp18
-rw-r--r--src/share/vm/runtime/vmStructs.cpp1
-rw-r--r--src/share/vm/runtime/vmThread.cpp19
-rw-r--r--src/share/vm/runtime/vm_operations.cpp21
-rw-r--r--src/share/vm/runtime/vm_operations.hpp4
-rw-r--r--src/share/vm/services/attachListener.cpp2
-rw-r--r--src/share/vm/services/diagnosticArgument.cpp29
-rw-r--r--src/share/vm/services/diagnosticCommand.cpp6
-rw-r--r--src/share/vm/services/memBaseline.cpp1
-rw-r--r--src/share/vm/trace/noTraceBackend.hpp48
-rw-r--r--src/share/vm/trace/trace.dtd86
-rw-r--r--src/share/vm/trace/trace.xml367
-rw-r--r--src/share/vm/trace/traceBackend.hpp70
-rw-r--r--src/share/vm/trace/traceDataTypes.hpp67
-rw-r--r--src/share/vm/trace/traceEvent.hpp150
-rw-r--r--src/share/vm/trace/traceEventClasses.xsl246
-rw-r--r--src/share/vm/trace/traceEventIds.xsl74
-rw-r--r--src/share/vm/trace/traceMacros.hpp16
-rw-r--r--src/share/vm/trace/traceStream.hpp121
-rw-r--r--src/share/vm/trace/traceTime.hpp (renamed from src/share/vm/trace/traceEventTypes.hpp)11
-rw-r--r--src/share/vm/trace/traceTypes.xsl72
-rw-r--r--src/share/vm/trace/tracetypes.xml368
-rw-r--r--src/share/vm/trace/tracing.hpp5
-rw-r--r--src/share/vm/trace/xinclude.mod61
-rw-r--r--src/share/vm/trace/xsl_util.xsl78
-rw-r--r--src/share/vm/utilities/globalDefinitions.hpp12
-rw-r--r--src/share/vm/utilities/macros.hpp4
196 files changed, 7625 insertions, 1481 deletions
diff --git a/make/Makefile b/make/Makefile
index 526ed2393..2975088cb 100644
--- a/make/Makefile
+++ b/make/Makefile
@@ -486,7 +486,7 @@ $(EXPORT_INCLUDE_DIR)/%: $(HS_SRC_DIR)/share/vm/services/%
JFR_EXISTS=$(shell if [ -d $(HS_ALT_SRC) ]; then echo 1; else echo 0; fi)
# export jfr.h
ifeq ($JFR_EXISTS,1)
-$(EXPORT_INCLUDE_DIR)/%: $(HS_ALT_SRC)/share/vm/jfr/agent/%
+$(EXPORT_INCLUDE_DIR)/%: $(HS_ALT_SRC)/share/vm/jfr/%
$(install-file)
else
$(EXPORT_INCLUDE_DIR)/jfr.h:
diff --git a/make/bsd/makefiles/buildtree.make b/make/bsd/makefiles/buildtree.make
index 16a0f9a64..ca9d19e0d 100644
--- a/make/bsd/makefiles/buildtree.make
+++ b/make/bsd/makefiles/buildtree.make
@@ -47,6 +47,7 @@
# flags.make - with macro settings
# vm.make - to support making "$(MAKE) -v vm.make" in makefiles
# adlc.make -
+# trace.make - generate tracing event and type definitions
# jvmti.make - generate JVMTI bindings from the spec (JSR-163)
# sa.make - generate SA jar file and natives
#
@@ -119,6 +120,7 @@ SIMPLE_DIRS = \
$(PLATFORM_DIR)/generated/dependencies \
$(PLATFORM_DIR)/generated/adfiles \
$(PLATFORM_DIR)/generated/jvmtifiles \
+ $(PLATFORM_DIR)/generated/tracefiles \
$(PLATFORM_DIR)/generated/dtracefiles
TARGETS = debug fastdebug optimized product
@@ -128,7 +130,7 @@ SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS))
BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make
# dtrace.make is used on BSD versions that implement Dtrace (like MacOS X)
-BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make sa.make dtrace.make
+BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make trace.make sa.make dtrace.make
BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \
SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT)
@@ -331,6 +333,16 @@ jvmti.make: $(BUILDTREE_MAKE)
echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \
) > $@
+trace.make: $(BUILDTREE_MAKE)
+ @echo Creating $@ ...
+ $(QUIETLY) ( \
+ $(BUILDTREE_COMMENT); \
+ echo; \
+ echo include flags.make; \
+ echo; \
+ echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \
+ ) > $@
+
sa.make: $(BUILDTREE_MAKE)
@echo Creating $@ ...
$(QUIETLY) ( \
diff --git a/make/bsd/makefiles/minimal1.make b/make/bsd/makefiles/minimal1.make
index abfbc4c94..42d794ab7 100644
--- a/make/bsd/makefiles/minimal1.make
+++ b/make/bsd/makefiles/minimal1.make
@@ -19,7 +19,7 @@
# 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.
-#
+#
#
TYPE=MINIMAL1
@@ -32,6 +32,7 @@ INCLUDE_SERVICES ?= false
INCLUDE_MANAGEMENT ?= false
INCLUDE_ALL_GCS ?= false
INCLUDE_NMT ?= false
+INCLUDE_TRACE ?= false
INCLUDE_CDS ?= false
CXXFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\"
diff --git a/make/bsd/makefiles/top.make b/make/bsd/makefiles/top.make
index 647e132b0..aebadebe3 100644
--- a/make/bsd/makefiles/top.make
+++ b/make/bsd/makefiles/top.make
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1999, 2013, 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
@@ -80,7 +80,7 @@ default: vm_build_preliminaries the_vm
@echo All done.
# This is an explicit dependency for the sake of parallel makes.
-vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) jvmti_stuff sa_stuff dtrace_stuff
+vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) jvmti_stuff trace_stuff sa_stuff dtrace_stuff
@# We need a null action here, so implicit rules don't get consulted.
$(Cached_plat): $(Plat_File)
@@ -94,6 +94,10 @@ ad_stuff: $(Cached_plat) $(adjust-mflags)
jvmti_stuff: $(Cached_plat) $(adjust-mflags)
@$(MAKE) -f jvmti.make $(MFLAGS-adjusted)
+# generate trace files
+trace_stuff: jvmti_stuff $(Cached_plat) $(adjust-mflags)
+ @$(MAKE) -f trace.make $(MFLAGS-adjusted)
+
ifeq ($(OS_VENDOR), Darwin)
# generate dtrace header files
dtrace_stuff: $(Cached_plat) $(adjust-mflags)
diff --git a/make/bsd/makefiles/trace.make b/make/bsd/makefiles/trace.make
new file mode 100644
index 000000000..ceb40c878
--- /dev/null
+++ b/make/bsd/makefiles/trace.make
@@ -0,0 +1,121 @@
+#
+# Copyright (c) 2003, 2013, 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.
+#
+#
+
+# This makefile (trace.make) is included from the trace.make in the
+# build directories.
+#
+# It knows how to build and run the tools to generate trace files.
+
+include $(GAMMADIR)/make/bsd/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)
+
+TOPDIR = $(shell echo `pwd`)
+GENERATED = $(TOPDIR)/../generated
+JvmtiOutDir = $(GENERATED)/jvmtifiles
+TraceOutDir = $(GENERATED)/tracefiles
+
+TraceAltSrcDir = $(HS_ALT_SRC)/share/vm/trace
+TraceSrcDir = $(HS_COMMON_SRC)/share/vm/trace
+
+# set VPATH so make knows where to look for source files
+Src_Dirs_V += $(TraceSrcDir) $(TraceAltSrcDir)
+VPATH += $(Src_Dirs_V:%=%:)
+
+TraceGeneratedNames = \
+ traceEventClasses.hpp \
+ traceEventIds.hpp \
+ traceTypes.hpp
+
+ifeq ($(HAS_ALT_SRC), true)
+TraceGeneratedNames += \
+ traceRequestables.hpp \
+ traceEventControl.hpp
+
+ifneq ($(INCLUDE_TRACE), false)
+TraceGeneratedNames += traceProducer.cpp
+endif
+
+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
+ifeq ($(HAS_ALT_SRC), true)
+ XML_DEPS += $(TraceAltSrcDir)/traceevents.xml
+endif
+
+.PHONY: all clean cleanall
+
+# #########################################################################
+
+all: $(TraceGeneratedFiles)
+
+GENERATE_CODE= \
+ $(QUIETLY) echo Generating $@; \
+ $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@; \
+ test -f $@
+
+$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+ifeq ($(HAS_ALT_SRC), false)
+
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+else
+
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+endif
+
+# #########################################################################
+
+
+clean cleanall:
+ rm $(TraceGeneratedFiles)
+
diff --git a/make/bsd/makefiles/vm.make b/make/bsd/makefiles/vm.make
index 7342ca3a1..ba2eb0756 100644
--- a/make/bsd/makefiles/vm.make
+++ b/make/bsd/makefiles/vm.make
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1999, 2013, 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
@@ -19,7 +19,7 @@
# 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.
-#
+#
#
# Rules to build JVM and related libraries, included from vm.make in the build
@@ -52,7 +52,7 @@ endif
# Src_Dirs_V is everything in src/share/vm/*, plus the right os/*/vm and cpu/*/vm
# The adfiles directory contains ad_<arch>.[ch]pp.
# The jvmtifiles directory contains jvmti*.[ch]pp
-Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles
+Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles $(GENERATED)/tracefiles
VPATH += $(Src_Dirs_V:%=%:)
# set INCLUDES for C preprocessor.
@@ -66,7 +66,7 @@ else
SYMFLAG =
endif
-# HOTSPOT_RELEASE_VERSION and HOTSPOT_BUILD_VERSION are defined
+# HOTSPOT_RELEASE_VERSION and HOTSPOT_BUILD_VERSION are defined
# in $(GAMMADIR)/make/defs.make
ifeq ($(HOTSPOT_BUILD_VERSION),)
BUILD_VERSION = -DHOTSPOT_RELEASE_VERSION="\"$(HOTSPOT_RELEASE_VERSION)\""
@@ -93,7 +93,7 @@ CXXFLAGS = \
# This is VERY important! The version define must only be supplied to vm_version.o
# If not, ccache will not re-use the cache at all, since the version string might contain
-# a time and date.
+# a time and date.
CXXFLAGS/vm_version.o += ${JRE_VERSION}
CXXFLAGS/BYFILE = $(CXXFLAGS/$@)
@@ -105,10 +105,6 @@ ifdef DEFAULT_LIBPATH
CXXFLAGS += -DDEFAULT_LIBPATH="\"$(DEFAULT_LIBPATH)\""
endif
-ifndef JAVASE_EMBEDDED
-CFLAGS += -DINCLUDE_TRACE
-endif
-
# CFLAGS_WARN holds compiler options to suppress/enable warnings.
CFLAGS += $(CFLAGS_WARN/BYFILE)
@@ -165,15 +161,15 @@ SOURCE_PATHS+=$(HS_COMMON_SRC)/os/posix/vm
SOURCE_PATHS+=$(HS_COMMON_SRC)/cpu/$(Platform_arch)/vm
SOURCE_PATHS+=$(HS_COMMON_SRC)/os_cpu/$(Platform_os_arch)/vm
-ifndef JAVASE_EMBEDDED
-SOURCE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \
+CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path))
+CORE_PATHS+=$(GENERATED)/jvmtifiles $(GENERATED)/tracefiles
+
+ifneq ($(INCLUDE_TRACE), false)
+CORE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \
find $(HS_ALT_SRC)/share/vm/jfr -type d; \
fi)
endif
-CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path))
-CORE_PATHS+=$(GENERATED)/jvmtifiles
-
COMPILER1_PATHS := $(call altsrc,$(HS_COMMON_SRC)/share/vm/c1)
COMPILER1_PATHS += $(HS_COMMON_SRC)/share/vm/c1
diff --git a/make/defs.make b/make/defs.make
index 4e4c2cb01..5ebf167e2 100644
--- a/make/defs.make
+++ b/make/defs.make
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2013, 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
@@ -19,7 +19,7 @@
# 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.
-#
+#
#
# The common definitions for hotspot builds.
@@ -236,7 +236,7 @@ ifneq ($(ALT_JDK_IMAGE_DIR),)
JDK_IMAGE_DIR=$(ALT_JDK_IMAGE_DIR)
endif
-# The platform dependent defs.make defines platform specific variable such
+# The platform dependent defs.make defines platform specific variable such
# as ARCH, EXPORT_LIST etc. We must place the include here after BOOTDIR is defined.
include $(GAMMADIR)/make/$(OSNAME)/makefiles/defs.make
@@ -258,7 +258,7 @@ ifneq ($(OSNAME),windows)
# LIBARCH - directory name in JDK/JRE
# Use uname output for SRCARCH, but deal with platform differences. If ARCH
- # is not explicitly listed below, it is treated as x86.
+ # is not explicitly listed below, it is treated as x86.
SRCARCH = $(ARCH/$(filter sparc sparc64 ia64 amd64 x86_64 arm ppc zero,$(ARCH)))
ARCH/ = x86
ARCH/sparc = sparc
@@ -337,8 +337,5 @@ EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jni.h
EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/$(JDK_INCLUDE_SUBDIR)/jni_md.h
EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jmm.h
-ifndef JAVASE_EMBEDDED
-EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jfr.h
-endif
-
.PHONY: $(HS_ALT_MAKE)/defs.make
+
diff --git a/make/excludeSrc.make b/make/excludeSrc.make
index 2ce60e0a6..88bab5c39 100644
--- a/make/excludeSrc.make
+++ b/make/excludeSrc.make
@@ -19,7 +19,7 @@
# 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.
-#
+#
#
ifeq ($(INCLUDE_JVMTI), false)
CXXFLAGS += -DINCLUDE_JVMTI=0
@@ -100,7 +100,7 @@ ifeq ($(INCLUDE_ALL_GCS), false)
parCardTableModRefBS.cpp parGCAllocBuffer.cpp parNewGeneration.cpp mutableSpace.cpp \
gSpaceCounters.cpp allocationStats.cpp spaceCounters.cpp gcAdaptivePolicyCounters.cpp \
mutableNUMASpace.cpp immutableSpace.cpp yieldingWorkGroup.cpp
-endif
+endif
ifeq ($(INCLUDE_NMT), false)
CXXFLAGS += -DINCLUDE_NMT=0
@@ -110,3 +110,5 @@ ifeq ($(INCLUDE_NMT), false)
memBaseline.cpp memPtr.cpp memRecorder.cpp memReporter.cpp memSnapshot.cpp memTrackWorker.cpp \
memTracker.cpp nmtDCmd.cpp
endif
+
+-include $(HS_ALT_MAKE)/excludeSrc.make
diff --git a/make/hotspot_version b/make/hotspot_version
index c88d72866..e16392a92 100644
--- a/make/hotspot_version
+++ b/make/hotspot_version
@@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2013
HS_MAJOR_VER=25
HS_MINOR_VER=0
-HS_BUILD_NUMBER=36
+HS_BUILD_NUMBER=37
JDK_MAJOR_VER=1
JDK_MINOR_VER=8
diff --git a/make/linux/makefiles/buildtree.make b/make/linux/makefiles/buildtree.make
index 3b7157735..fd6c52513 100644
--- a/make/linux/makefiles/buildtree.make
+++ b/make/linux/makefiles/buildtree.make
@@ -47,6 +47,7 @@
# flags.make - with macro settings
# vm.make - to support making "$(MAKE) -v vm.make" in makefiles
# adlc.make -
+# trace.make - generate tracing event and type definitions
# jvmti.make - generate JVMTI bindings from the spec (JSR-163)
# sa.make - generate SA jar file and natives
#
@@ -114,7 +115,8 @@ COMPILER = $(shell sed -n 's/^compiler[ ]*=[ ]*//p' $(PLATFORM_FILE))
SIMPLE_DIRS = \
$(PLATFORM_DIR)/generated/dependencies \
$(PLATFORM_DIR)/generated/adfiles \
- $(PLATFORM_DIR)/generated/jvmtifiles
+ $(PLATFORM_DIR)/generated/jvmtifiles \
+ $(PLATFORM_DIR)/generated/tracefiles
TARGETS = debug fastdebug optimized product
SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS))
@@ -122,7 +124,7 @@ SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS))
# For dependencies and recursive makes.
BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make
-BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make sa.make
+BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make trace.make sa.make
BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \
SRCARCH=$(SRCARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT)
@@ -269,6 +271,8 @@ flags.make: $(BUILDTREE_MAKE) ../shared_dirs.lst
echo && \
echo "HOTSPOT_EXTRA_SYSDEFS\$$(HOTSPOT_EXTRA_SYSDEFS) = $(HOTSPOT_EXTRA_SYSDEFS)" && \
echo "SYSDEFS += \$$(HOTSPOT_EXTRA_SYSDEFS)"; \
+ [ -n "$(INCLUDE_TRACE)" ] && \
+ echo && echo "INCLUDE_TRACE = $(INCLUDE_TRACE)"; \
echo; \
[ -n "$(SPEC)" ] && \
echo "include $(SPEC)"; \
@@ -337,6 +341,16 @@ jvmti.make: $(BUILDTREE_MAKE)
echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \
) > $@
+trace.make: $(BUILDTREE_MAKE)
+ @echo Creating $@ ...
+ $(QUIETLY) ( \
+ $(BUILDTREE_COMMENT); \
+ echo; \
+ echo include flags.make; \
+ echo; \
+ echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \
+ ) > $@
+
sa.make: $(BUILDTREE_MAKE)
@echo Creating $@ ...
$(QUIETLY) ( \
diff --git a/make/linux/makefiles/minimal1.make b/make/linux/makefiles/minimal1.make
index abfbc4c94..42d794ab7 100644
--- a/make/linux/makefiles/minimal1.make
+++ b/make/linux/makefiles/minimal1.make
@@ -19,7 +19,7 @@
# 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.
-#
+#
#
TYPE=MINIMAL1
@@ -32,6 +32,7 @@ INCLUDE_SERVICES ?= false
INCLUDE_MANAGEMENT ?= false
INCLUDE_ALL_GCS ?= false
INCLUDE_NMT ?= false
+INCLUDE_TRACE ?= false
INCLUDE_CDS ?= false
CXXFLAGS += -DMINIMAL_JVM -DCOMPILER1 -DVMTYPE=\"Minimal\"
diff --git a/make/linux/makefiles/top.make b/make/linux/makefiles/top.make
index 011d46a05..95e6e6856 100644
--- a/make/linux/makefiles/top.make
+++ b/make/linux/makefiles/top.make
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1999, 2013, 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
@@ -80,7 +80,7 @@ default: vm_build_preliminaries the_vm
@echo All done.
# This is an explicit dependency for the sake of parallel makes.
-vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) jvmti_stuff sa_stuff
+vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) trace_stuff jvmti_stuff sa_stuff
@# We need a null action here, so implicit rules don't get consulted.
$(Cached_plat): $(Plat_File)
@@ -94,6 +94,10 @@ ad_stuff: $(Cached_plat) $(adjust-mflags)
jvmti_stuff: $(Cached_plat) $(adjust-mflags)
@$(MAKE) -f jvmti.make $(MFLAGS-adjusted)
+# generate trace files
+trace_stuff: jvmti_stuff $(Cached_plat) $(adjust-mflags)
+ @$(MAKE) -f trace.make $(MFLAGS-adjusted)
+
# generate SA jar files and native header
sa_stuff:
@$(MAKE) -f sa.make $(MFLAGS-adjusted)
diff --git a/make/linux/makefiles/trace.make b/make/linux/makefiles/trace.make
new file mode 100644
index 000000000..f173e0ad3
--- /dev/null
+++ b/make/linux/makefiles/trace.make
@@ -0,0 +1,120 @@
+#
+# Copyright (c) 2003, 2013, 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.
+#
+#
+
+# This makefile (trace.make) is included from the trace.make in the
+# build directories.
+#
+# It knows how to build and run the tools to generate trace files.
+
+include $(GAMMADIR)/make/linux/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)
+
+TOPDIR = $(shell echo `pwd`)
+GENERATED = $(TOPDIR)/../generated
+JvmtiOutDir = $(GENERATED)/jvmtifiles
+TraceOutDir = $(GENERATED)/tracefiles
+
+TraceAltSrcDir = $(HS_ALT_SRC)/share/vm/trace
+TraceSrcDir = $(HS_COMMON_SRC)/share/vm/trace
+
+# set VPATH so make knows where to look for source files
+Src_Dirs_V += $(TraceSrcDir) $(TraceAltSrcDir)
+VPATH += $(Src_Dirs_V:%=%:)
+
+TraceGeneratedNames = \
+ traceEventClasses.hpp \
+ traceEventIds.hpp \
+ traceTypes.hpp
+
+ifeq ($(HAS_ALT_SRC), true)
+TraceGeneratedNames += \
+ traceRequestables.hpp \
+ traceEventControl.hpp
+
+ifneq ($(INCLUDE_TRACE), false)
+TraceGeneratedNames += traceProducer.cpp
+endif
+
+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
+ifeq ($(HAS_ALT_SRC), true)
+ XML_DEPS += $(TraceAltSrcDir)/traceevents.xml
+endif
+
+.PHONY: all clean cleanall
+
+# #########################################################################
+
+all: $(TraceGeneratedFiles)
+
+GENERATE_CODE= \
+ $(QUIETLY) echo Generating $@; \
+ $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@; \
+ test -f $@
+
+$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+ifeq ($(HAS_ALT_SRC), false)
+
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+else
+
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+endif
+
+# #########################################################################
+
+clean cleanall:
+ rm $(TraceGeneratedFiles)
+
+
diff --git a/make/linux/makefiles/vm.make b/make/linux/makefiles/vm.make
index 79a926a8c..d9db77744 100644
--- a/make/linux/makefiles/vm.make
+++ b/make/linux/makefiles/vm.make
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1999, 2013, 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
@@ -19,7 +19,7 @@
# 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.
-#
+#
#
# Rules to build JVM and related libraries, included from vm.make in the build
@@ -52,7 +52,7 @@ endif
# Src_Dirs_V is everything in src/share/vm/*, plus the right os/*/vm and cpu/*/vm
# The adfiles directory contains ad_<arch>.[ch]pp.
# The jvmtifiles directory contains jvmti*.[ch]pp
-Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles
+Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles $(GENERATED)/tracefiles
VPATH += $(Src_Dirs_V:%=%:)
# set INCLUDES for C preprocessor.
@@ -72,7 +72,7 @@ else
endif
endif
-# HOTSPOT_RELEASE_VERSION and HOTSPOT_BUILD_VERSION are defined
+# HOTSPOT_RELEASE_VERSION and HOTSPOT_BUILD_VERSION are defined
# in $(GAMMADIR)/make/defs.make
ifeq ($(HOTSPOT_BUILD_VERSION),)
BUILD_VERSION = -DHOTSPOT_RELEASE_VERSION="\"$(HOTSPOT_RELEASE_VERSION)\""
@@ -99,7 +99,7 @@ CXXFLAGS = \
# This is VERY important! The version define must only be supplied to vm_version.o
# If not, ccache will not re-use the cache at all, since the version string might contain
-# a time and date.
+# a time and date.
CXXFLAGS/vm_version.o += ${JRE_VERSION}
CXXFLAGS/BYFILE = $(CXXFLAGS/$@)
@@ -108,12 +108,6 @@ CXXFLAGS/BYFILE = $(CXXFLAGS/$@)
CXXFLAGS += $(CXXFLAGS/BYFILE)
-ifndef JAVASE_EMBEDDED
-ifneq (${ARCH},arm)
-CFLAGS += -DINCLUDE_TRACE
-endif
-endif
-
# CFLAGS_WARN holds compiler options to suppress/enable warnings.
CFLAGS += $(CFLAGS_WARN/BYFILE)
@@ -158,16 +152,14 @@ SOURCE_PATHS+=$(HS_COMMON_SRC)/os/posix/vm
SOURCE_PATHS+=$(HS_COMMON_SRC)/cpu/$(Platform_arch)/vm
SOURCE_PATHS+=$(HS_COMMON_SRC)/os_cpu/$(Platform_os_arch)/vm
-ifndef JAVASE_EMBEDDED
-ifneq (${ARCH},arm)
-SOURCE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \
+CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path))
+CORE_PATHS+=$(GENERATED)/jvmtifiles $(GENERATED)/tracefiles
+
+ifneq ($(INCLUDE_TRACE), false)
+CORE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \
find $(HS_ALT_SRC)/share/vm/jfr -type d; \
fi)
endif
-endif
-
-CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path))
-CORE_PATHS+=$(GENERATED)/jvmtifiles
COMPILER1_PATHS := $(call altsrc,$(HS_COMMON_SRC)/share/vm/c1)
COMPILER1_PATHS += $(HS_COMMON_SRC)/share/vm/c1
@@ -316,7 +308,7 @@ endif
# With more recent Redhat releases (or the cutting edge version Fedora), if
# SELinux is configured to be enabled, the runtime linker will fail to apply
# the text relocation to libjvm.so considering that it is built as a non-PIC
-# DSO. To workaround that, we run chcon to libjvm.so after it is built. See
+# DSO. To workaround that, we run chcon to libjvm.so after it is built. See
# details in bug 6538311.
$(LIBJVM): $(LIBJVM.o) $(LIBJVM_MAPFILE) $(LD_SCRIPT)
$(QUIETLY) { \
diff --git a/make/solaris/makefiles/buildtree.make b/make/solaris/makefiles/buildtree.make
index 5827c4ff7..ca602a81e 100644
--- a/make/solaris/makefiles/buildtree.make
+++ b/make/solaris/makefiles/buildtree.make
@@ -47,6 +47,7 @@
# flags.make - with macro settings
# vm.make - to support making "$(MAKE) -v vm.make" in makefiles
# adlc.make -
+# trace.make - generate tracing event and type definitions
# jvmti.make - generate JVMTI bindings from the spec (JSR-163)
# sa.make - generate SA jar file and natives
#
@@ -107,7 +108,8 @@ COMPILER = $(shell sed -n 's/^compiler[ ]*=[ ]*//p' $(PLATFORM_FILE))
SIMPLE_DIRS = \
$(PLATFORM_DIR)/generated/dependencies \
$(PLATFORM_DIR)/generated/adfiles \
- $(PLATFORM_DIR)/generated/jvmtifiles
+ $(PLATFORM_DIR)/generated/jvmtifiles \
+ $(PLATFORM_DIR)/generated/tracefiles
TARGETS = debug fastdebug optimized product
SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS))
@@ -115,7 +117,7 @@ SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS))
# For dependencies and recursive makes.
BUILDTREE_MAKE = $(GAMMADIR)/make/$(OS_FAMILY)/makefiles/buildtree.make
-BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make sa.make
+BUILDTREE_TARGETS = Makefile flags.make flags_vm.make vm.make adlc.make jvmti.make trace.make sa.make
BUILDTREE_VARS = GAMMADIR=$(GAMMADIR) OS_FAMILY=$(OS_FAMILY) \
ARCH=$(ARCH) BUILDARCH=$(BUILDARCH) LIBARCH=$(LIBARCH) VARIANT=$(VARIANT)
@@ -327,6 +329,16 @@ jvmti.make: $(BUILDTREE_MAKE)
echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \
) > $@
+trace.make: $(BUILDTREE_MAKE)
+ @echo Creating $@ ...
+ $(QUIETLY) ( \
+ $(BUILDTREE_COMMENT); \
+ echo; \
+ echo include flags.make; \
+ echo; \
+ echo "include \$$(GAMMADIR)/make/$(OS_FAMILY)/makefiles/$(@F)"; \
+ ) > $@
+
sa.make: $(BUILDTREE_MAKE)
@echo Creating $@ ...
$(QUIETLY) ( \
diff --git a/make/solaris/makefiles/top.make b/make/solaris/makefiles/top.make
index 1d31f1e8d..81e34afde 100644
--- a/make/solaris/makefiles/top.make
+++ b/make/solaris/makefiles/top.make
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1998, 2013, 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
@@ -73,7 +73,7 @@ default: vm_build_preliminaries the_vm
@echo All done.
# This is an explicit dependency for the sake of parallel makes.
-vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) jvmti_stuff sa_stuff
+vm_build_preliminaries: checks $(Cached_plat) $(AD_Files_If_Required) jvmti_stuff trace_stuff sa_stuff
@# We need a null action here, so implicit rules don't get consulted.
$(Cached_plat): $(Plat_File)
@@ -87,6 +87,10 @@ ad_stuff: $(Cached_plat) $(adjust-mflags)
jvmti_stuff: $(Cached_plat) $(adjust-mflags)
@$(MAKE) -f jvmti.make $(MFLAGS-adjusted)
+# generate trace files
+trace_stuff: jvmti_stuff $(Cached_plat) $(adjust-mflags)
+ @$(MAKE) -f trace.make $(MFLAGS-adjusted)
+
# generate SA jar files and native header
sa_stuff:
@$(MAKE) -f sa.make $(MFLAGS-adjusted)
@@ -127,5 +131,5 @@ realclean:
rm -fr $(GENERATED)
.PHONY: default vm_build_preliminaries
-.PHONY: lists ad_stuff jvmti_stuff sa_stuff the_vm clean realclean
+.PHONY: lists ad_stuff jvmti_stuff trace_stuff sa_stuff the_vm clean realclean
.PHONY: checks check_os_version install
diff --git a/make/solaris/makefiles/trace.make b/make/solaris/makefiles/trace.make
new file mode 100644
index 000000000..16c82cd78
--- /dev/null
+++ b/make/solaris/makefiles/trace.make
@@ -0,0 +1,116 @@
+#
+# Copyright (c) 2003, 2013, 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.
+#
+#
+
+# This makefile (trace.make) is included from the trace.make in the
+# build directories.
+#
+# It knows how to build and run the tools to generate trace files.
+
+include $(GAMMADIR)/make/solaris/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)
+
+TOPDIR = $(shell echo `pwd`)
+GENERATED = $(TOPDIR)/../generated
+JvmtiOutDir = $(GENERATED)/jvmtifiles
+TraceOutDir = $(GENERATED)/tracefiles
+
+TraceAltSrcDir = $(HS_ALT_SRC)/share/vm/trace
+TraceSrcDir = $(HS_COMMON_SRC)/share/vm/trace
+
+# set VPATH so make knows where to look for source files
+Src_Dirs_V += $(TraceSrcDir) $(TraceAltSrcDir)
+VPATH += $(Src_Dirs_V:%=%:)
+
+TraceGeneratedNames = \
+ traceEventClasses.hpp \
+ traceEventIds.hpp \
+ traceTypes.hpp
+
+ifeq ($(HAS_ALT_SRC), true)
+TraceGeneratedNames += \
+ traceRequestables.hpp \
+ traceEventControl.hpp \
+ traceProducer.cpp
+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
+ifeq ($(HAS_ALT_SRC), true)
+ XML_DEPS += $(TraceAltSrcDir)/traceevents.xml
+endif
+
+.PHONY: all clean cleanall
+
+# #########################################################################
+
+all: $(TraceGeneratedFiles)
+
+GENERATE_CODE= \
+ $(QUIETLY) echo Generating $@; \
+ $(XSLT) -IN $(word 1,$^) -XSL $(word 2,$^) -OUT $@; \
+ test -f $@
+
+$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+ifeq ($(HAS_ALT_SRC), false)
+
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+else
+
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS)
+ $(GENERATE_CODE)
+
+endif
+
+# #########################################################################
+
+clean cleanall:
+ rm $(TraceGeneratedFiles)
+
+
diff --git a/make/solaris/makefiles/vm.make b/make/solaris/makefiles/vm.make
index 855f7f188..d57716c7a 100644
--- a/make/solaris/makefiles/vm.make
+++ b/make/solaris/makefiles/vm.make
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1998, 2013, 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
@@ -19,7 +19,7 @@
# 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.
-#
+#
#
# Rules to build JVM and related libraries, included from vm.make in the build
@@ -48,7 +48,7 @@ include $(MAKEFILES_DIR)/$(BUILDARCH).make
# Src_Dirs_V is everything in src/share/vm/*, plus the right os/*/vm and cpu/*/vm
# The adfiles directory contains ad_<arch>.[ch]pp.
# The jvmtifiles directory contains jvmti*.[ch]pp
-Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles
+Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles $(GENERATED)/tracefiles
VPATH += $(Src_Dirs_V:%=%:)
# set INCLUDES for C preprocessor
@@ -87,7 +87,7 @@ CXXFLAGS = \
# This is VERY important! The version define must only be supplied to vm_version.o
# If not, ccache will not re-use the cache at all, since the version string might contain
-# a time and date.
+# a time and date.
CXXFLAGS/vm_version.o += ${JRE_VERSION}
CXXFLAGS/BYFILE = $(CXXFLAGS/$@)
@@ -103,7 +103,7 @@ CFLAGS += $(CFLAGS_WARN)
CFLAGS += $(CFLAGS/NOEX)
# Extra flags from gnumake's invocation or environment
-CFLAGS += $(EXTRA_CFLAGS) -DINCLUDE_TRACE
+CFLAGS += $(EXTRA_CFLAGS)
# Math Library (libm.so), do not use -lm.
# There might be two versions of libm.so on the build system:
@@ -137,9 +137,7 @@ else
LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle
endif # sparcWorks
-ifeq ("${Platform_arch}", "sparc")
LIBS += -lkstat
-endif
# By default, link the *.o into the library, not the executable.
LINK_INTO$(LINK_INTO) = LIBJVM
@@ -177,12 +175,14 @@ SOURCE_PATHS+=$(HS_COMMON_SRC)/os/posix/vm
SOURCE_PATHS+=$(HS_COMMON_SRC)/cpu/$(Platform_arch)/vm
SOURCE_PATHS+=$(HS_COMMON_SRC)/os_cpu/$(Platform_os_arch)/vm
-SOURCE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \
+CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path))
+CORE_PATHS+=$(GENERATED)/jvmtifiles $(GENERATED)/tracefiles
+
+ifneq ($(INCLUDE_TRACE), false)
+CORE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \
find $(HS_ALT_SRC)/share/vm/jfr -type d; \
fi)
-
-CORE_PATHS=$(foreach path,$(SOURCE_PATHS),$(call altsrc,$(path)) $(path))
-CORE_PATHS+=$(GENERATED)/jvmtifiles
+endif
COMPILER1_PATHS := $(call altsrc,$(HS_COMMON_SRC)/share/vm/c1)
COMPILER1_PATHS += $(HS_COMMON_SRC)/share/vm/c1
@@ -287,7 +287,7 @@ else
LINK_VM = $(LINK_LIB.CXX)
endif
# making the library:
-$(LIBJVM): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(LIBJVM.o) $(LIBJVM_MAPFILE)
+$(LIBJVM): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(LIBJVM.o) $(LIBJVM_MAPFILE)
ifeq ($(filter -sbfast -xsbfast, $(CFLAGS_BROWSE)),)
@echo Linking vm...
$(QUIETLY) $(LINK_LIB.CXX/PRE_HOOK)
diff --git a/make/windows/build.make b/make/windows/build.make
index c072a1701..7c66b206c 100644
--- a/make/windows/build.make
+++ b/make/windows/build.make
@@ -196,6 +196,12 @@ HS_BUILD_VER=$(HOTSPOT_RELEASE_VERSION)-$(HOTSPOT_BUILD_VERSION)
# End VERSIONINFO parameters
+# if hotspot-only build and/or OPENJDK isn't passed down, need to set OPENJDK
+!ifndef OPENJDK
+!if !exists($(WorkSpace)\src\closed)
+OPENJDK=true
+!endif
+!endif
# We don't support SA on ia64, and we can't
# build it if we are using a version of Vis Studio
@@ -273,6 +279,7 @@ $(variantDir)\local.make: checks
@ echo HS_COMPANY=$(COMPANY_NAME) >> $@
@ echo HS_FILEDESC=$(HS_FILEDESC) >> $@
@ echo HOTSPOT_VM_DISTRO=$(HOTSPOT_VM_DISTRO) >> $@
+ @ if "$(OPENJDK)" NEQ "" echo OPENJDK=$(OPENJDK) >> $@
@ echo HS_COPYRIGHT=$(HOTSPOT_VM_COPYRIGHT) >> $@
@ echo HS_NAME=$(PRODUCT_NAME) $(JDK_MKTG_VERSION) >> $@
@ echo HS_BUILD_VER=$(HS_BUILD_VER) >> $@
diff --git a/make/windows/create_obj_files.sh b/make/windows/create_obj_files.sh
index 257b3f140..b162bd07b 100644
--- a/make/windows/create_obj_files.sh
+++ b/make/windows/create_obj_files.sh
@@ -71,13 +71,11 @@ for sd in \
BASE_PATHS="${BASE_PATHS} ${COMMONSRC}/${sd}"
done
-BASE_PATHS="${BASE_PATHS} ${GENERATED}/jvmtifiles"
+BASE_PATHS="${BASE_PATHS} ${GENERATED}/jvmtifiles ${GENERATED}/tracefiles"
if [ -d "${ALTSRC}/share/vm/jfr" ]; then
- BASE_PATHS="${BASE_PATHS} ${ALTSRC}/share/vm/jfr/agent"
- BASE_PATHS="${BASE_PATHS} ${ALTSRC}/share/vm/jfr/agent/isolated_deps/util"
- BASE_PATHS="${BASE_PATHS} ${ALTSRC}/share/vm/jfr/jvm"
- BASE_PATHS="${BASE_PATHS} ${ALTSRC}/share/vm/jfr"
+ BASE_PATHS="${BASE_PATHS} ${ALTSRC}/share/vm/jfr"
+ BASE_PATHS="${BASE_PATHS} ${ALTSRC}/share/vm/jfr/buffers"
fi
BASE_PATHS="${BASE_PATHS} ${COMMONSRC}/share/vm/prims/wbtestmethods"
diff --git a/make/windows/makefiles/generated.make b/make/windows/makefiles/generated.make
index d5add4b03..aaaa8e7c2 100644
--- a/make/windows/makefiles/generated.make
+++ b/make/windows/makefiles/generated.make
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2013, 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,15 +30,19 @@
JvmtiOutDir=jvmtifiles
!include $(WorkSpace)/make/windows/makefiles/jvmti.make
+# Pick up rules for building trace
+TraceOutDir=tracefiles
+!include $(WorkSpace)/make/windows/makefiles/trace.make
+
# Pick up rules for building SA
!include $(WorkSpace)/make/windows/makefiles/sa.make
AdlcOutDir=adfiles
!if ("$(Variant)" == "compiler2") || ("$(Variant)" == "tiered")
-default:: $(AdlcOutDir)/ad_$(Platform_arch_model).cpp $(AdlcOutDir)/dfa_$(Platform_arch_model).cpp $(JvmtiGeneratedFiles) buildobjfiles
+default:: $(AdlcOutDir)/ad_$(Platform_arch_model).cpp $(AdlcOutDir)/dfa_$(Platform_arch_model).cpp $(JvmtiGeneratedFiles) $(TraceGeneratedFiles) buildobjfiles
!else
-default:: $(JvmtiGeneratedFiles) buildobjfiles
+default:: $(JvmtiGeneratedFiles) $(TraceGeneratedFiles) buildobjfiles
!endif
buildobjfiles:
diff --git a/make/windows/makefiles/projectcreator.make b/make/windows/makefiles/projectcreator.make
index f142852ed..7aa3ef65c 100644
--- a/make/windows/makefiles/projectcreator.make
+++ b/make/windows/makefiles/projectcreator.make
@@ -19,7 +19,7 @@
# 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 $(WorkSpace)/make/windows/makefiles/rules.make
@@ -72,7 +72,7 @@ ProjectCreatorIncludesPRIVATE=\
-ignorePath ppc \
-ignorePath zero \
-hidePath .hg
-
+
# This is referenced externally by both the IDE and batch builds
ProjectCreatorOptions=
@@ -89,7 +89,7 @@ ProjectCreatorIDEOptions = \
-disablePch bytecodeInterpreter.cpp \
-disablePch bytecodeInterpreterWithChecks.cpp \
-disablePch getThread_windows_$(Platform_arch).cpp \
- -disablePch_compiler2 opcodes.cpp
+ -disablePch_compiler2 opcodes.cpp
# Common options for the IDE builds for core, c1, and c2
ProjectCreatorIDEOptions=\
@@ -115,7 +115,7 @@ ProjectCreatorIDEOptions=\
-define TARGET_OS_ARCH_windows_x86 \
-define TARGET_OS_FAMILY_windows \
-define TARGET_COMPILER_visCPP \
- -define INCLUDE_TRACE \
+ -define INCLUDE_TRACE=1 \
$(ProjectCreatorIncludesPRIVATE)
# Add in build-specific options
@@ -203,4 +203,12 @@ ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \
-additionalFile jvmtiEnter.cpp \
-additionalFile jvmtiEnterTrace.cpp \
-additionalFile jvmti.h \
- -additionalFile bytecodeInterpreterWithChecks.cpp
+ -additionalFile bytecodeInterpreterWithChecks.cpp \
+ -additionalFile traceEventClasses.hpp \
+ -additionalFile traceEventIds.hpp \
+!if "$(OPENJDK)" != "true"
+ -additionalFile traceRequestables.hpp \
+ -additionalFile traceEventControl.hpp \
+ -additionalFile traceProducer.cpp \
+!endif
+ -additionalFile traceTypes.hpp
diff --git a/make/windows/makefiles/trace.make b/make/windows/makefiles/trace.make
new file mode 100644
index 000000000..82422b173
--- /dev/null
+++ b/make/windows/makefiles/trace.make
@@ -0,0 +1,121 @@
+#
+# Copyright (c) 2003, 2013, 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.
+#
+#
+
+# This makefile (trace.make) is included from the trace.make in the
+# build directories.
+#
+# It knows how to build and run the tools to generate trace files.
+
+!include $(WorkSpace)/make/windows/makefiles/rules.make
+
+# #########################################################################
+
+
+TraceAltSrcDir = $(WorkSpace)/src/closed/share/vm/trace
+TraceSrcDir = $(WorkSpace)/src/share/vm/trace
+
+TraceGeneratedNames = \
+ traceEventClasses.hpp \
+ traceEventIds.hpp \
+ traceTypes.hpp
+
+
+!if "$(OPENJDK)" != "true"
+TraceGeneratedNames = $(TraceGeneratedNames) \
+ traceRequestables.hpp \
+ traceEventControl.hpp \
+ traceProducer.cpp
+!endif
+
+
+#Note: TraceGeneratedFiles must be kept in sync with TraceGeneratedNames by hand.
+#Should be equivalent to "TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%)"
+TraceGeneratedFiles = \
+ $(TraceOutDir)/traceEventClasses.hpp \
+ $(TraceOutDir)/traceEventIds.hpp \
+ $(TraceOutDir)/traceTypes.hpp
+
+!if "$(OPENJDK)" != "true"
+TraceGeneratedFiles = $(TraceGeneratedFiles) \
+ $(TraceOutDir)/traceRequestables.hpp \
+ $(TraceOutDir)/traceEventControl.hpp \
+ $(TraceOutDir)/traceProducer.cpp
+!endif
+
+XSLT = $(QUIETLY) $(REMOTE) $(RUN_JAVA) -classpath $(JvmtiOutDir) jvmtiGen
+
+XML_DEPS = $(TraceSrcDir)/trace.xml $(TraceSrcDir)/tracetypes.xml \
+ $(TraceSrcDir)/trace.dtd $(TraceSrcDir)/xinclude.mod
+
+!if "$(OPENJDK)" != "true"
+XML_DEPS = $(XML_DEPS) $(TraceAltSrcDir)/traceevents.xml
+!endif
+
+.PHONY: all clean cleanall
+
+# #########################################################################
+
+default::
+ @if not exist $(TraceOutDir) mkdir $(TraceOutDir)
+
+$(TraceOutDir)/traceEventIds.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventIds.xsl $(XML_DEPS)
+ @echo Generating $@
+ @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceSrcDir)/traceEventIds.xsl -OUT $(TraceOutDir)/traceEventIds.hpp
+
+$(TraceOutDir)/traceTypes.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceTypes.xsl $(XML_DEPS)
+ @echo Generating $@
+ @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceSrcDir)/traceTypes.xsl -OUT $(TraceOutDir)/traceTypes.hpp
+
+!if "$(OPENJDK)" == "true"
+
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+ @echo Generating $@
+ @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceSrcDir)/traceEventClasses.xsl -OUT $(TraceOutDir)/traceEventClasses.hpp
+
+!else
+
+$(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS)
+ @echo Generating $@
+ @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceEventClasses.xsl -OUT $(TraceOutDir)/traceEventClasses.hpp
+
+$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS)
+ @echo Generating $@
+ @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceProducer.xsl -OUT $(TraceOutDir)/traceProducer.cpp
+
+$(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS)
+ @echo Generating $@
+ @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceRequestables.xsl -OUT $(TraceOutDir)/traceRequestables.hpp
+
+$(TraceOutDir)/traceEventControl.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventControl.xsl $(XML_DEPS)
+ @echo Generating $@
+ @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceEventControl.xsl -OUT $(TraceOutDir)/traceEventControl.hpp
+
+!endif
+
+# #########################################################################
+
+cleanall :
+ rm $(TraceGeneratedFiles)
+
+
diff --git a/make/windows/makefiles/vm.make b/make/windows/makefiles/vm.make
index 9e7c64b8f..54ba1eef5 100644
--- a/make/windows/makefiles/vm.make
+++ b/make/windows/makefiles/vm.make
@@ -66,10 +66,6 @@ CXX_FLAGS=$(CXX_FLAGS) /D "HOTSPOT_BUILD_TARGET=\"$(BUILD_FLAVOR)\""
CXX_FLAGS=$(CXX_FLAGS) /D "HOTSPOT_BUILD_USER=\"$(BuildUser)\""
CXX_FLAGS=$(CXX_FLAGS) /D "HOTSPOT_VM_DISTRO=\"$(HOTSPOT_VM_DISTRO)\""
-!ifndef JAVASE_EMBEDDED
-CXX_FLAGS=$(CXX_FLAGS) /D "INCLUDE_TRACE"
-!endif
-
CXX_FLAGS=$(CXX_FLAGS) $(CXX_INCLUDE_DIRS)
# Define that so jni.h is on correct side
@@ -144,6 +140,7 @@ CXX_USE_PCH=$(CXX_DONT_USE_PCH)
VM_PATH=../generated
VM_PATH=$(VM_PATH);../generated/adfiles
VM_PATH=$(VM_PATH);../generated/jvmtifiles
+VM_PATH=$(VM_PATH);../generated/tracefiles
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/c1
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/compiler
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/code
@@ -172,10 +169,8 @@ VM_PATH=$(VM_PATH);$(WorkSpace)/src/cpu/$(Platform_arch)/vm
VM_PATH=$(VM_PATH);$(WorkSpace)/src/share/vm/opto
!if exists($(ALTSRC)\share\vm\jfr)
-VM_PATH=$(VM_PATH);$(ALTSRC)/share/vm/jfr/agent
-VM_PATH=$(VM_PATH);$(ALTSRC)/share/vm/jfr/agent/isolated_deps/util
-VM_PATH=$(VM_PATH);$(ALTSRC)/share/vm/jfr/jvm
VM_PATH=$(VM_PATH);$(ALTSRC)/share/vm/jfr
+VM_PATH=$(VM_PATH);$(ALTSRC)/share/vm/jfr/buffers
!endif
VM_PATH={$(VM_PATH)}
@@ -384,16 +379,13 @@ bytecodeInterpreterWithChecks.obj: ..\generated\jvmtifiles\bytecodeInterpreterWi
{..\generated\jvmtifiles}.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\agent}.cpp.obj::
+{..\generated\tracefiles}.cpp.obj::
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
-{$(ALTSRC)\share\vm\jfr\agent\isolated_deps\util}.cpp.obj::
+{$(ALTSRC)\share\vm\jfr}.cpp.obj::
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
-{$(ALTSRC)\share\vm\jfr\jvm}.cpp.obj::
+{$(ALTSRC)\share\vm\jfr\buffers}.cpp.obj::
$(CXX) $(CXX_FLAGS) $(CXX_USE_PCH) /c $<
default::
diff --git a/make/windows/projectfiles/common/Makefile b/make/windows/projectfiles/common/Makefile
index 5556aae51..8ae363be7 100644
--- a/make/windows/projectfiles/common/Makefile
+++ b/make/windows/projectfiles/common/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1999, 2013, 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,6 +45,12 @@ BootStrapDir=$(HOTSPOTJDKDIST)
!endif
!endif
+# if hotspot-only build and/or OPENJDK isn't passed down, need to set OPENJDK
+!ifndef OPENJDK
+!if !exists($(WorkSpace)\src\closed)
+OPENJDK=true
+!endif
+!endif
!include $(HOTSPOTWORKSPACE)/make/windows/makefiles/projectcreator.make
@@ -54,6 +60,10 @@ BootStrapDir=$(HOTSPOTJDKDIST)
JvmtiOutDir=$(HOTSPOTBUILDSPACE)\$(Variant)\generated\jvmtifiles
!include $(HOTSPOTWORKSPACE)/make/windows/makefiles/jvmti.make
+# Pick up rules for building trace
+TraceOutDir=$(HOTSPOTBUILDSPACE)\$(Variant)\generated\tracefiles
+!include $(HOTSPOTWORKSPACE)/make/windows/makefiles/trace.make
+
!if "$(Variant)" == "compiler2"
# Pick up rules for building adlc
!include $(HOTSPOTWORKSPACE)/make/windows/makefiles/adlc.make
@@ -66,7 +76,7 @@ JvmtiOutDir=$(HOTSPOTBUILDSPACE)\$(Variant)\generated\jvmtifiles
HS_INTERNAL_NAME=jvm
-default:: $(AdditionalTargets) $(JvmtiGeneratedFiles)
+default:: $(AdditionalTargets) $(JvmtiGeneratedFiles) $(TraceGeneratedFiles)
!include $(HOTSPOTWORKSPACE)/make/hotspot_version
diff --git a/src/cpu/sparc/vm/frame_sparc.cpp b/src/cpu/sparc/vm/frame_sparc.cpp
index 94cef1a9a..b550d77a8 100644
--- a/src/cpu/sparc/vm/frame_sparc.cpp
+++ b/src/cpu/sparc/vm/frame_sparc.cpp
@@ -252,6 +252,16 @@ bool frame::safe_for_sender(JavaThread *thread) {
return false;
}
+ // Could be a zombie method
+ if (sender_blob->is_zombie() || sender_blob->is_unloaded()) {
+ return false;
+ }
+
+ // Could be a zombie method
+ if (sender_blob->is_zombie() || sender_blob->is_unloaded()) {
+ return false;
+ }
+
// It should be safe to construct the sender though it might not be valid
frame sender(_SENDER_SP, younger_sp, adjusted_stack);
@@ -294,10 +304,10 @@ bool frame::safe_for_sender(JavaThread *thread) {
return jcw_safe;
}
- // If the frame size is 0 something is bad because every nmethod has a non-zero frame size
+ // If the frame size is 0 something (or less) is bad because every nmethod has a non-zero frame size
// because you must allocate window space
- if (sender_blob->frame_size() == 0) {
+ if (sender_blob->frame_size() <= 0) {
assert(!sender_blob->is_nmethod(), "should count return address at least");
return false;
}
diff --git a/src/cpu/x86/vm/frame_x86.cpp b/src/cpu/x86/vm/frame_x86.cpp
index 93180c8e3..92587985d 100644
--- a/src/cpu/x86/vm/frame_x86.cpp
+++ b/src/cpu/x86/vm/frame_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
#include "runtime/handles.inline.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/monitorChunk.hpp"
+#include "runtime/os.hpp"
#include "runtime/signature.hpp"
#include "runtime/stubCodeGenerator.hpp"
#include "runtime/stubRoutines.hpp"
@@ -54,16 +55,22 @@ bool frame::safe_for_sender(JavaThread *thread) {
address sp = (address)_sp;
address fp = (address)_fp;
address unextended_sp = (address)_unextended_sp;
- // sp must be within the stack
- bool sp_safe = (sp <= thread->stack_base()) &&
- (sp >= thread->stack_base() - thread->stack_size());
+
+ // consider stack guards when trying to determine "safe" stack pointers
+ static size_t stack_guard_size = os::uses_stack_guard_pages() ? (StackYellowPages + StackRedPages) * os::vm_page_size() : 0;
+ size_t usable_stack_size = thread->stack_size() - stack_guard_size;
+
+ // sp must be within the usable part of the stack (not in guards)
+ bool sp_safe = (sp < thread->stack_base()) &&
+ (sp >= thread->stack_base() - usable_stack_size);
+
if (!sp_safe) {
return false;
}
// unextended sp must be within the stack and above or equal sp
- bool unextended_sp_safe = (unextended_sp <= thread->stack_base()) &&
+ bool unextended_sp_safe = (unextended_sp < thread->stack_base()) &&
(unextended_sp >= sp);
if (!unextended_sp_safe) {
@@ -71,7 +78,8 @@ bool frame::safe_for_sender(JavaThread *thread) {
}
// an fp must be within the stack and above (but not equal) sp
- bool fp_safe = (fp <= thread->stack_base()) && (fp > sp);
+ // second evaluation on fp+ is added to handle situation where fp is -1
+ bool fp_safe = (fp < thread->stack_base() && (fp > sp) && (((fp + (return_addr_offset * sizeof(void*))) < thread->stack_base())));
// We know sp/unextended_sp are safe only fp is questionable here
@@ -86,6 +94,13 @@ bool frame::safe_for_sender(JavaThread *thread) {
// other generic buffer blobs are more problematic so we just assume they are
// ok. adapter blobs never have a frame complete and are never ok.
+ // check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc
+
+ if (!Interpreter::contains(_pc) && _cb->frame_size() <= 0) {
+ //assert(0, "Invalid frame_size");
+ return false;
+ }
+
if (!_cb->is_frame_complete_at(_pc)) {
if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) {
return false;
@@ -107,7 +122,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
address jcw = (address)entry_frame_call_wrapper();
- bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > fp);
+ bool jcw_safe = (jcw < thread->stack_base()) && ( jcw > fp);
return jcw_safe;
@@ -134,12 +149,6 @@ bool frame::safe_for_sender(JavaThread *thread) {
sender_pc = (address) *(sender_sp-1);
}
- // We must always be able to find a recognizable pc
- CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc);
- if (sender_pc == NULL || sender_blob == NULL) {
- return false;
- }
-
// If the potential sender is the interpreter then we can do some more checking
if (Interpreter::contains(sender_pc)) {
@@ -149,7 +158,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
// is really a frame pointer.
intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset);
- bool saved_fp_safe = ((address)saved_fp <= thread->stack_base()) && (saved_fp > sender_sp);
+ bool saved_fp_safe = ((address)saved_fp < thread->stack_base()) && (saved_fp > sender_sp);
if (!saved_fp_safe) {
return false;
@@ -163,6 +172,17 @@ bool frame::safe_for_sender(JavaThread *thread) {
}
+ // We must always be able to find a recognizable pc
+ CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc);
+ if (sender_pc == NULL || sender_blob == NULL) {
+ return false;
+ }
+
+ // Could be a zombie method
+ if (sender_blob->is_zombie() || sender_blob->is_unloaded()) {
+ return false;
+ }
+
// Could just be some random pointer within the codeBlob
if (!sender_blob->code_contains(sender_pc)) {
return false;
@@ -174,10 +194,9 @@ bool frame::safe_for_sender(JavaThread *thread) {
}
// Could be the call_stub
-
if (StubRoutines::returns_to_call_stub(sender_pc)) {
intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset);
- bool saved_fp_safe = ((address)saved_fp <= thread->stack_base()) && (saved_fp > sender_sp);
+ bool saved_fp_safe = ((address)saved_fp < thread->stack_base()) && (saved_fp > sender_sp);
if (!saved_fp_safe) {
return false;
@@ -190,15 +209,24 @@ bool frame::safe_for_sender(JavaThread *thread) {
// Validate the JavaCallWrapper an entry frame must have
address jcw = (address)sender.entry_frame_call_wrapper();
- bool jcw_safe = (jcw <= thread->stack_base()) && ( jcw > (address)sender.fp());
+ bool jcw_safe = (jcw < thread->stack_base()) && ( jcw > (address)sender.fp());
return jcw_safe;
}
- // If the frame size is 0 something is bad because every nmethod has a non-zero frame size
+ if (sender_blob->is_nmethod()) {
+ nmethod* nm = sender_blob->as_nmethod_or_null();
+ if (nm != NULL) {
+ if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc)) {
+ return false;
+ }
+ }
+ }
+
+ // If the frame size is 0 something (or less) is bad because every nmethod has a non-zero frame size
// because the return address counts against the callee's frame.
- if (sender_blob->frame_size() == 0) {
+ if (sender_blob->frame_size() <= 0) {
assert(!sender_blob->is_nmethod(), "should count return address at least");
return false;
}
@@ -208,7 +236,9 @@ bool frame::safe_for_sender(JavaThread *thread) {
// should not be anything but the call stub (already covered), the interpreter (already covered)
// or an nmethod.
- assert(sender_blob->is_nmethod(), "Impossible call chain");
+ if (!sender_blob->is_nmethod()) {
+ return false;
+ }
// Could put some more validation for the potential non-interpreted sender
// frame we'd create by calling sender if I could think of any. Wait for next crash in forte...
diff --git a/src/os/bsd/vm/osThread_bsd.hpp b/src/os/bsd/vm/osThread_bsd.hpp
index b49c3caec..fe903eb58 100644
--- a/src/os/bsd/vm/osThread_bsd.hpp
+++ b/src/os/bsd/vm/osThread_bsd.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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
@@ -94,7 +94,7 @@ public:
// flags that support signal based suspend/resume on Bsd are in a
// separate class to avoid confusion with many flags in OSThread that
// are used by VM level suspend/resume.
- os::Bsd::SuspendResume sr;
+ os::SuspendResume sr;
// _ucontext and _siginfo are used by SR_handler() to save thread context,
// and they will later be used to walk the stack or reposition thread PC.
diff --git a/src/os/bsd/vm/os_bsd.cpp b/src/os/bsd/vm/os_bsd.cpp
index 0eea30991..e1864effb 100644
--- a/src/os/bsd/vm/os_bsd.cpp
+++ b/src/os/bsd/vm/os_bsd.cpp
@@ -1852,17 +1852,118 @@ static volatile jint pending_signals[NSIG+1] = { 0 };
// Bsd(POSIX) specific hand shaking semaphore.
#ifdef __APPLE__
-static semaphore_t sig_sem;
+typedef semaphore_t os_semaphore_t;
#define SEM_INIT(sem, value) semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, value)
-#define SEM_WAIT(sem) semaphore_wait(sem);
-#define SEM_POST(sem) semaphore_signal(sem);
+#define SEM_WAIT(sem) semaphore_wait(sem)
+#define SEM_POST(sem) semaphore_signal(sem)
+#define SEM_DESTROY(sem) semaphore_destroy(mach_task_self(), sem)
#else
-static sem_t sig_sem;
+typedef sem_t os_semaphore_t;
#define SEM_INIT(sem, value) sem_init(&sem, 0, value)
-#define SEM_WAIT(sem) sem_wait(&sem);
-#define SEM_POST(sem) sem_post(&sem);
+#define SEM_WAIT(sem) sem_wait(&sem)
+#define SEM_POST(sem) sem_post(&sem)
+#define SEM_DESTROY(sem) sem_destroy(&sem)
#endif
+class Semaphore : public StackObj {
+ public:
+ Semaphore();
+ ~Semaphore();
+ void signal();
+ void wait();
+ bool trywait();
+ bool timedwait(unsigned int sec, int nsec);
+ private:
+ jlong currenttime() const;
+ semaphore_t _semaphore;
+};
+
+Semaphore::Semaphore() : _semaphore(0) {
+ SEM_INIT(_semaphore, 0);
+}
+
+Semaphore::~Semaphore() {
+ SEM_DESTROY(_semaphore);
+}
+
+void Semaphore::signal() {
+ SEM_POST(_semaphore);
+}
+
+void Semaphore::wait() {
+ SEM_WAIT(_semaphore);
+}
+
+jlong Semaphore::currenttime() const {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (tv.tv_sec * NANOSECS_PER_SEC) + (tv.tv_usec * 1000);
+}
+
+#ifdef __APPLE__
+bool Semaphore::trywait() {
+ return timedwait(0, 0);
+}
+
+bool Semaphore::timedwait(unsigned int sec, int nsec) {
+ kern_return_t kr = KERN_ABORTED;
+ mach_timespec_t waitspec;
+ waitspec.tv_sec = sec;
+ waitspec.tv_nsec = nsec;
+
+ jlong starttime = currenttime();
+
+ kr = semaphore_timedwait(_semaphore, waitspec);
+ while (kr == KERN_ABORTED) {
+ jlong totalwait = (sec * NANOSECS_PER_SEC) + nsec;
+
+ jlong current = currenttime();
+ jlong passedtime = current - starttime;
+
+ if (passedtime >= totalwait) {
+ waitspec.tv_sec = 0;
+ waitspec.tv_nsec = 0;
+ } else {
+ jlong waittime = totalwait - (current - starttime);
+ waitspec.tv_sec = waittime / NANOSECS_PER_SEC;
+ waitspec.tv_nsec = waittime % NANOSECS_PER_SEC;
+ }
+
+ kr = semaphore_timedwait(_semaphore, waitspec);
+ }
+
+ return kr == KERN_SUCCESS;
+}
+
+#else
+
+bool Semaphore::trywait() {
+ return sem_trywait(&_semaphore) == 0;
+}
+
+bool Semaphore::timedwait(unsigned int sec, int nsec) {
+ struct timespec ts;
+ jlong endtime = unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec);
+
+ while (1) {
+ int result = sem_timedwait(&_semaphore, &ts);
+ if (result == 0) {
+ return true;
+ } else if (errno == EINTR) {
+ continue;
+ } else if (errno == ETIMEDOUT) {
+ return false;
+ } else {
+ return false;
+ }
+ }
+}
+
+#endif // __APPLE__
+
+static os_semaphore_t sig_sem;
+static Semaphore sr_semaphore;
+
void os::signal_init_pd() {
// Initialize signal structures
::memset((void*)pending_signals, 0, sizeof(pending_signals));
@@ -2616,9 +2717,6 @@ void os::hint_no_preempt() {}
static void resume_clear_context(OSThread *osthread) {
osthread->set_ucontext(NULL);
osthread->set_siginfo(NULL);
-
- // notify the suspend action is completed, we have now resumed
- osthread->sr.clear_suspended();
}
static void suspend_save_context(OSThread *osthread, siginfo_t* siginfo, ucontext_t* context) {
@@ -2638,7 +2736,7 @@ static void suspend_save_context(OSThread *osthread, siginfo_t* siginfo, ucontex
// its signal handlers run and prevents sigwait()'s use with the
// mutex granting granting signal.
//
-// Currently only ever called on the VMThread
+// Currently only ever called on the VMThread or JavaThread
//
static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) {
// Save and restore errno to avoid confusing native code with EINTR
@@ -2647,38 +2745,48 @@ static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) {
Thread* thread = Thread::current();
OSThread* osthread = thread->osthread();
- assert(thread->is_VM_thread(), "Must be VMThread");
- // read current suspend action
- int action = osthread->sr.suspend_action();
- if (action == os::Bsd::SuspendResume::SR_SUSPEND) {
+ assert(thread->is_VM_thread() || thread->is_Java_thread(), "Must be VMThread or JavaThread");
+
+ os::SuspendResume::State current = osthread->sr.state();
+ if (current == os::SuspendResume::SR_SUSPEND_REQUEST) {
suspend_save_context(osthread, siginfo, context);
- // Notify the suspend action is about to be completed. do_suspend()
- // waits until SR_SUSPENDED is set and then returns. We will wait
- // here for a resume signal and that completes the suspend-other
- // action. do_suspend/do_resume is always called as a pair from
- // the same thread - so there are no races
+ // attempt to switch the state, we assume we had a SUSPEND_REQUEST
+ os::SuspendResume::State state = osthread->sr.suspended();
+ if (state == os::SuspendResume::SR_SUSPENDED) {
+ sigset_t suspend_set; // signals for sigsuspend()
- // notify the caller
- osthread->sr.set_suspended();
+ // get current set of blocked signals and unblock resume signal
+ pthread_sigmask(SIG_BLOCK, NULL, &suspend_set);
+ sigdelset(&suspend_set, SR_signum);
- sigset_t suspend_set; // signals for sigsuspend()
+ sr_semaphore.signal();
+ // wait here until we are resumed
+ while (1) {
+ sigsuspend(&suspend_set);
- // get current set of blocked signals and unblock resume signal
- pthread_sigmask(SIG_BLOCK, NULL, &suspend_set);
- sigdelset(&suspend_set, SR_signum);
+ os::SuspendResume::State result = osthread->sr.running();
+ if (result == os::SuspendResume::SR_RUNNING) {
+ sr_semaphore.signal();
+ break;
+ } else if (result != os::SuspendResume::SR_SUSPENDED) {
+ ShouldNotReachHere();
+ }
+ }
- // wait here until we are resumed
- do {
- sigsuspend(&suspend_set);
- // ignore all returns until we get a resume signal
- } while (osthread->sr.suspend_action() != os::Bsd::SuspendResume::SR_CONTINUE);
+ } else if (state == os::SuspendResume::SR_RUNNING) {
+ // request was cancelled, continue
+ } else {
+ ShouldNotReachHere();
+ }
resume_clear_context(osthread);
-
+ } else if (current == os::SuspendResume::SR_RUNNING) {
+ // request was cancelled, continue
+ } else if (current == os::SuspendResume::SR_WAKEUP_REQUEST) {
+ // ignore
} else {
- assert(action == os::Bsd::SuspendResume::SR_CONTINUE, "unexpected sr action");
- // nothing special to do - just leave the handler
+ // ignore
}
errno = old_errno;
@@ -2722,42 +2830,82 @@ static int SR_initialize() {
return 0;
}
+static int sr_notify(OSThread* osthread) {
+ int status = pthread_kill(osthread->pthread_id(), SR_signum);
+ assert_status(status == 0, status, "pthread_kill");
+ return status;
+}
+
+// "Randomly" selected value for how long we want to spin
+// before bailing out on suspending a thread, also how often
+// we send a signal to a thread we want to resume
+static const int RANDOMLY_LARGE_INTEGER = 1000000;
+static const int RANDOMLY_LARGE_INTEGER2 = 100;
// returns true on success and false on error - really an error is fatal
// but this seems the normal response to library errors
static bool do_suspend(OSThread* osthread) {
+ assert(osthread->sr.is_running(), "thread should be running");
+ assert(!sr_semaphore.trywait(), "semaphore has invalid state");
+
// mark as suspended and send signal
- osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_SUSPEND);
- int status = pthread_kill(osthread->pthread_id(), SR_signum);
- assert_status(status == 0, status, "pthread_kill");
+ if (osthread->sr.request_suspend() != os::SuspendResume::SR_SUSPEND_REQUEST) {
+ // failed to switch, state wasn't running?
+ ShouldNotReachHere();
+ return false;
+ }
- // check status and wait until notified of suspension
- if (status == 0) {
- for (int i = 0; !osthread->sr.is_suspended(); i++) {
- os::yield_all(i);
- }
- osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_NONE);
- return true;
+ if (sr_notify(osthread) != 0) {
+ ShouldNotReachHere();
}
- else {
- osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_NONE);
- return false;
+
+ // managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED
+ while (true) {
+ if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) {
+ break;
+ } else {
+ // timeout
+ os::SuspendResume::State cancelled = osthread->sr.cancel_suspend();
+ if (cancelled == os::SuspendResume::SR_RUNNING) {
+ return false;
+ } else if (cancelled == os::SuspendResume::SR_SUSPENDED) {
+ // make sure that we consume the signal on the semaphore as well
+ sr_semaphore.wait();
+ break;
+ } else {
+ ShouldNotReachHere();
+ return false;
+ }
+ }
}
+
+ guarantee(osthread->sr.is_suspended(), "Must be suspended");
+ return true;
}
static void do_resume(OSThread* osthread) {
assert(osthread->sr.is_suspended(), "thread should be suspended");
- osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_CONTINUE);
+ assert(!sr_semaphore.trywait(), "invalid semaphore state");
- int status = pthread_kill(osthread->pthread_id(), SR_signum);
- assert_status(status == 0, status, "pthread_kill");
- // check status and wait unit notified of resumption
- if (status == 0) {
- for (int i = 0; osthread->sr.is_suspended(); i++) {
- os::yield_all(i);
+ if (osthread->sr.request_wakeup() != os::SuspendResume::SR_WAKEUP_REQUEST) {
+ // failed to switch to WAKEUP_REQUEST
+ ShouldNotReachHere();
+ return;
+ }
+
+ while (true) {
+ if (sr_notify(osthread) == 0) {
+ if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) {
+ if (osthread->sr.is_running()) {
+ return;
+ }
+ }
+ } else {
+ ShouldNotReachHere();
}
}
- osthread->sr.set_suspend_action(os::Bsd::SuspendResume::SR_NONE);
+
+ guarantee(osthread->sr.is_running(), "Must be running!");
}
////////////////////////////////////////////////////////////////////////////////
@@ -3508,7 +3656,40 @@ bool os::bind_to_processor(uint processor_id) {
return false;
}
+void os::SuspendedThreadTask::internal_do_task() {
+ if (do_suspend(_thread->osthread())) {
+ SuspendedThreadTaskContext context(_thread, _thread->osthread()->ucontext());
+ do_task(context);
+ do_resume(_thread->osthread());
+ }
+}
+
///
+class PcFetcher : public os::SuspendedThreadTask {
+public:
+ PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
+ ExtendedPC result();
+protected:
+ void do_task(const os::SuspendedThreadTaskContext& context);
+private:
+ ExtendedPC _epc;
+};
+
+ExtendedPC PcFetcher::result() {
+ guarantee(is_done(), "task is not done yet.");
+ return _epc;
+}
+
+void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
+ Thread* thread = context.thread();
+ OSThread* osthread = thread->osthread();
+ if (osthread->ucontext() != NULL) {
+ _epc = os::Bsd::ucontext_get_pc((ucontext_t *) context.ucontext());
+ } else {
+ // NULL context is unexpected, double-check this is the VMThread
+ guarantee(thread->is_VM_thread(), "can only be called for VMThread");
+ }
+}
// Suspends the target using the signal mechanism and then grabs the PC before
// resuming the target. Used by the flat-profiler only
@@ -3517,22 +3698,9 @@ ExtendedPC os::get_thread_pc(Thread* thread) {
assert(Thread::current()->is_Watcher_thread(), "Must be watcher");
assert(thread->is_VM_thread(), "Can only be called for VMThread");
- ExtendedPC epc;
-
- OSThread* osthread = thread->osthread();
- if (do_suspend(osthread)) {
- if (osthread->ucontext() != NULL) {
- epc = os::Bsd::ucontext_get_pc(osthread->ucontext());
- } else {
- // NULL context is unexpected, double-check this is the VMThread
- guarantee(thread->is_VM_thread(), "can only be called for VMThread");
- }
- do_resume(osthread);
- }
- // failure means pthread_kill failed for some reason - arguably this is
- // a fatal problem, but such problems are ignored elsewhere
-
- return epc;
+ PcFetcher fetcher(thread);
+ fetcher.run();
+ return fetcher.result();
}
int os::Bsd::safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime)
@@ -4517,3 +4685,4 @@ int os::get_core_path(char* buffer, size_t bufferSize) {
return n;
}
+
diff --git a/src/os/bsd/vm/os_bsd.hpp b/src/os/bsd/vm/os_bsd.hpp
index 81562b4f8..f18bb8863 100644
--- a/src/os/bsd/vm/os_bsd.hpp
+++ b/src/os/bsd/vm/os_bsd.hpp
@@ -145,36 +145,6 @@ class Bsd {
// BsdThreads work-around for 6292965
static int safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime);
-
- // Bsd suspend/resume support - this helper is a shadow of its former
- // self now that low-level suspension is barely used, and old workarounds
- // for BsdThreads are no longer needed.
- class SuspendResume {
- private:
- volatile int _suspend_action;
- volatile jint _state;
- public:
- // values for suspend_action:
- enum {
- SR_NONE = 0x00,
- SR_SUSPEND = 0x01, // suspend request
- SR_CONTINUE = 0x02, // resume request
- SR_SUSPENDED = 0x20 // values for _state: + SR_NONE
- };
-
- SuspendResume() { _suspend_action = SR_NONE; _state = SR_NONE; }
-
- int suspend_action() const { return _suspend_action; }
- void set_suspend_action(int x) { _suspend_action = x; }
-
- // atomic updates for _state
- inline void set_suspended();
- inline void clear_suspended();
- bool is_suspended() { return _state & SR_SUSPENDED; }
-
- #undef SR_SUSPENDED
- };
-
private:
typedef int (*sched_getcpu_func_t)(void);
typedef int (*numa_node_to_cpus_func_t)(int node, unsigned long *buffer, int bufferlen);
@@ -250,7 +220,7 @@ class PlatformEvent : public CHeapObj<mtInternal> {
int TryPark () ;
int park (jlong millis) ;
void SetAssociation (Thread * a) { _Assoc = a ; }
-} ;
+};
class PlatformParker : public CHeapObj<mtInternal> {
protected:
@@ -268,6 +238,6 @@ class PlatformParker : public CHeapObj<mtInternal> {
status = pthread_mutex_init (_mutex, NULL);
assert_status(status == 0, status, "mutex_init");
}
-} ;
+};
#endif // OS_BSD_VM_OS_BSD_HPP
diff --git a/src/os/bsd/vm/os_bsd.inline.hpp b/src/os/bsd/vm/os_bsd.inline.hpp
index 723543efe..33ebec9ff 100644
--- a/src/os/bsd/vm/os_bsd.inline.hpp
+++ b/src/os/bsd/vm/os_bsd.inline.hpp
@@ -286,20 +286,4 @@ inline int os::set_sock_opt(int fd, int level, int optname,
return ::setsockopt(fd, level, optname, optval, optlen);
}
-inline void os::Bsd::SuspendResume::set_suspended() {
- jint temp, temp2;
- do {
- temp = _state;
- temp2 = Atomic::cmpxchg(temp | SR_SUSPENDED, &_state, temp);
- } while (temp2 != temp);
-}
-
-inline void os::Bsd::SuspendResume::clear_suspended() {
- jint temp, temp2;
- do {
- temp = _state;
- temp2 = Atomic::cmpxchg(temp & ~SR_SUSPENDED, &_state, temp);
- } while (temp2 != temp);
-}
-
#endif // OS_BSD_VM_OS_BSD_INLINE_HPP
diff --git a/src/os/linux/vm/osThread_linux.hpp b/src/os/linux/vm/osThread_linux.hpp
index 904ab52e6..c9e53c249 100644
--- a/src/os/linux/vm/osThread_linux.hpp
+++ b/src/os/linux/vm/osThread_linux.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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
@@ -77,7 +77,7 @@ public:
// flags that support signal based suspend/resume on Linux are in a
// separate class to avoid confusion with many flags in OSThread that
// are used by VM level suspend/resume.
- os::Linux::SuspendResume sr;
+ os::SuspendResume sr;
// _ucontext and _siginfo are used by SR_handler() to save thread context,
// and they will later be used to walk the stack or reposition thread PC.
diff --git a/src/os/linux/vm/os_linux.cpp b/src/os/linux/vm/os_linux.cpp
index dbf30c481..4b975461e 100644
--- a/src/os/linux/vm/os_linux.cpp
+++ b/src/os/linux/vm/os_linux.cpp
@@ -151,6 +151,9 @@ sigset_t SR_sigset;
/* Used to protect dlsym() calls */
static pthread_mutex_t dl_mutex;
+// Declarations
+static void unpackTime(timespec* absTime, bool isAbsolute, jlong time);
+
#ifdef JAVASE_EMBEDDED
class MemNotifyThread: public Thread {
friend class VMStructs;
@@ -2407,6 +2410,57 @@ void* os::user_handler() {
return CAST_FROM_FN_PTR(void*, UserHandler);
}
+class Semaphore : public StackObj {
+ public:
+ Semaphore();
+ ~Semaphore();
+ void signal();
+ void wait();
+ bool trywait();
+ bool timedwait(unsigned int sec, int nsec);
+ private:
+ sem_t _semaphore;
+};
+
+
+Semaphore::Semaphore() {
+ sem_init(&_semaphore, 0, 0);
+}
+
+Semaphore::~Semaphore() {
+ sem_destroy(&_semaphore);
+}
+
+void Semaphore::signal() {
+ sem_post(&_semaphore);
+}
+
+void Semaphore::wait() {
+ sem_wait(&_semaphore);
+}
+
+bool Semaphore::trywait() {
+ return sem_trywait(&_semaphore) == 0;
+}
+
+bool Semaphore::timedwait(unsigned int sec, int nsec) {
+ struct timespec ts;
+ unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec);
+
+ while (1) {
+ int result = sem_timedwait(&_semaphore, &ts);
+ if (result == 0) {
+ return true;
+ } else if (errno == EINTR) {
+ continue;
+ } else if (errno == ETIMEDOUT) {
+ return false;
+ } else {
+ return false;
+ }
+ }
+}
+
extern "C" {
typedef void (*sa_handler_t)(int);
typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
@@ -2446,6 +2500,7 @@ static volatile jint pending_signals[NSIG+1] = { 0 };
// Linux(POSIX) specific hand shaking semaphore.
static sem_t sig_sem;
+static Semaphore sr_semaphore;
void os::signal_init_pd() {
// Initialize signal structures
@@ -3559,9 +3614,6 @@ void os::hint_no_preempt() {}
static void resume_clear_context(OSThread *osthread) {
osthread->set_ucontext(NULL);
osthread->set_siginfo(NULL);
-
- // notify the suspend action is completed, we have now resumed
- osthread->sr.clear_suspended();
}
static void suspend_save_context(OSThread *osthread, siginfo_t* siginfo, ucontext_t* context) {
@@ -3581,7 +3633,7 @@ static void suspend_save_context(OSThread *osthread, siginfo_t* siginfo, ucontex
// its signal handlers run and prevents sigwait()'s use with the
// mutex granting granting signal.
//
-// Currently only ever called on the VMThread
+// Currently only ever called on the VMThread and JavaThreads (PC sampling)
//
static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) {
// Save and restore errno to avoid confusing native code with EINTR
@@ -3590,38 +3642,46 @@ static void SR_handler(int sig, siginfo_t* siginfo, ucontext_t* context) {
Thread* thread = Thread::current();
OSThread* osthread = thread->osthread();
- assert(thread->is_VM_thread(), "Must be VMThread");
- // read current suspend action
- int action = osthread->sr.suspend_action();
- if (action == os::Linux::SuspendResume::SR_SUSPEND) {
+ assert(thread->is_VM_thread() || thread->is_Java_thread(), "Must be VMThread or JavaThread");
+
+ os::SuspendResume::State current = osthread->sr.state();
+ if (current == os::SuspendResume::SR_SUSPEND_REQUEST) {
suspend_save_context(osthread, siginfo, context);
- // Notify the suspend action is about to be completed. do_suspend()
- // waits until SR_SUSPENDED is set and then returns. We will wait
- // here for a resume signal and that completes the suspend-other
- // action. do_suspend/do_resume is always called as a pair from
- // the same thread - so there are no races
+ // attempt to switch the state, we assume we had a SUSPEND_REQUEST
+ os::SuspendResume::State state = osthread->sr.suspended();
+ if (state == os::SuspendResume::SR_SUSPENDED) {
+ sigset_t suspend_set; // signals for sigsuspend()
- // notify the caller
- osthread->sr.set_suspended();
+ // get current set of blocked signals and unblock resume signal
+ pthread_sigmask(SIG_BLOCK, NULL, &suspend_set);
+ sigdelset(&suspend_set, SR_signum);
- sigset_t suspend_set; // signals for sigsuspend()
+ sr_semaphore.signal();
+ // wait here until we are resumed
+ while (1) {
+ sigsuspend(&suspend_set);
- // get current set of blocked signals and unblock resume signal
- pthread_sigmask(SIG_BLOCK, NULL, &suspend_set);
- sigdelset(&suspend_set, SR_signum);
+ os::SuspendResume::State result = osthread->sr.running();
+ if (result == os::SuspendResume::SR_RUNNING) {
+ sr_semaphore.signal();
+ break;
+ }
+ }
- // wait here until we are resumed
- do {
- sigsuspend(&suspend_set);
- // ignore all returns until we get a resume signal
- } while (osthread->sr.suspend_action() != os::Linux::SuspendResume::SR_CONTINUE);
+ } else if (state == os::SuspendResume::SR_RUNNING) {
+ // request was cancelled, continue
+ } else {
+ ShouldNotReachHere();
+ }
resume_clear_context(osthread);
-
+ } else if (current == os::SuspendResume::SR_RUNNING) {
+ // request was cancelled, continue
+ } else if (current == os::SuspendResume::SR_WAKEUP_REQUEST) {
+ // ignore
} else {
- assert(action == os::Linux::SuspendResume::SR_CONTINUE, "unexpected sr action");
- // nothing special to do - just leave the handler
+ // ignore
}
errno = old_errno;
@@ -3665,42 +3725,82 @@ static int SR_initialize() {
return 0;
}
+static int sr_notify(OSThread* osthread) {
+ int status = pthread_kill(osthread->pthread_id(), SR_signum);
+ assert_status(status == 0, status, "pthread_kill");
+ return status;
+}
+
+// "Randomly" selected value for how long we want to spin
+// before bailing out on suspending a thread, also how often
+// we send a signal to a thread we want to resume
+static const int RANDOMLY_LARGE_INTEGER = 1000000;
+static const int RANDOMLY_LARGE_INTEGER2 = 100;
// returns true on success and false on error - really an error is fatal
// but this seems the normal response to library errors
static bool do_suspend(OSThread* osthread) {
+ assert(osthread->sr.is_running(), "thread should be running");
+ assert(!sr_semaphore.trywait(), "semaphore has invalid state");
+
// mark as suspended and send signal
- osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_SUSPEND);
- int status = pthread_kill(osthread->pthread_id(), SR_signum);
- assert_status(status == 0, status, "pthread_kill");
+ if (osthread->sr.request_suspend() != os::SuspendResume::SR_SUSPEND_REQUEST) {
+ // failed to switch, state wasn't running?
+ ShouldNotReachHere();
+ return false;
+ }
- // check status and wait until notified of suspension
- if (status == 0) {
- for (int i = 0; !osthread->sr.is_suspended(); i++) {
- os::yield_all(i);
- }
- osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_NONE);
- return true;
+ if (sr_notify(osthread) != 0) {
+ ShouldNotReachHere();
}
- else {
- osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_NONE);
- return false;
+
+ // managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED
+ while (true) {
+ if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) {
+ break;
+ } else {
+ // timeout
+ os::SuspendResume::State cancelled = osthread->sr.cancel_suspend();
+ if (cancelled == os::SuspendResume::SR_RUNNING) {
+ return false;
+ } else if (cancelled == os::SuspendResume::SR_SUSPENDED) {
+ // make sure that we consume the signal on the semaphore as well
+ sr_semaphore.wait();
+ break;
+ } else {
+ ShouldNotReachHere();
+ return false;
+ }
+ }
}
+
+ guarantee(osthread->sr.is_suspended(), "Must be suspended");
+ return true;
}
static void do_resume(OSThread* osthread) {
assert(osthread->sr.is_suspended(), "thread should be suspended");
- osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_CONTINUE);
+ assert(!sr_semaphore.trywait(), "invalid semaphore state");
- int status = pthread_kill(osthread->pthread_id(), SR_signum);
- assert_status(status == 0, status, "pthread_kill");
- // check status and wait unit notified of resumption
- if (status == 0) {
- for (int i = 0; osthread->sr.is_suspended(); i++) {
- os::yield_all(i);
+ if (osthread->sr.request_wakeup() != os::SuspendResume::SR_WAKEUP_REQUEST) {
+ // failed to switch to WAKEUP_REQUEST
+ ShouldNotReachHere();
+ return;
+ }
+
+ while (true) {
+ if (sr_notify(osthread) == 0) {
+ if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) {
+ if (osthread->sr.is_running()) {
+ return;
+ }
+ }
+ } else {
+ ShouldNotReachHere();
}
}
- osthread->sr.set_suspend_action(os::Linux::SuspendResume::SR_NONE);
+
+ guarantee(osthread->sr.is_running(), "Must be running!");
}
////////////////////////////////////////////////////////////////////////////////
@@ -4472,6 +4572,40 @@ bool os::bind_to_processor(uint processor_id) {
///
+void os::SuspendedThreadTask::internal_do_task() {
+ if (do_suspend(_thread->osthread())) {
+ SuspendedThreadTaskContext context(_thread, _thread->osthread()->ucontext());
+ do_task(context);
+ do_resume(_thread->osthread());
+ }
+}
+
+class PcFetcher : public os::SuspendedThreadTask {
+public:
+ PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
+ ExtendedPC result();
+protected:
+ void do_task(const os::SuspendedThreadTaskContext& context);
+private:
+ ExtendedPC _epc;
+};
+
+ExtendedPC PcFetcher::result() {
+ guarantee(is_done(), "task is not done yet.");
+ return _epc;
+}
+
+void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
+ Thread* thread = context.thread();
+ OSThread* osthread = thread->osthread();
+ if (osthread->ucontext() != NULL) {
+ _epc = os::Linux::ucontext_get_pc((ucontext_t *) context.ucontext());
+ } else {
+ // NULL context is unexpected, double-check this is the VMThread
+ guarantee(thread->is_VM_thread(), "can only be called for VMThread");
+ }
+}
+
// Suspends the target using the signal mechanism and then grabs the PC before
// resuming the target. Used by the flat-profiler only
ExtendedPC os::get_thread_pc(Thread* thread) {
@@ -4479,22 +4613,9 @@ ExtendedPC os::get_thread_pc(Thread* thread) {
assert(Thread::current()->is_Watcher_thread(), "Must be watcher");
assert(thread->is_VM_thread(), "Can only be called for VMThread");
- ExtendedPC epc;
-
- OSThread* osthread = thread->osthread();
- if (do_suspend(osthread)) {
- if (osthread->ucontext() != NULL) {
- epc = os::Linux::ucontext_get_pc(osthread->ucontext());
- } else {
- // NULL context is unexpected, double-check this is the VMThread
- guarantee(thread->is_VM_thread(), "can only be called for VMThread");
- }
- do_resume(osthread);
- }
- // failure means pthread_kill failed for some reason - arguably this is
- // a fatal problem, but such problems are ignored elsewhere
-
- return epc;
+ PcFetcher fetcher(thread);
+ fetcher.run();
+ return fetcher.result();
}
int os::Linux::safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime)
@@ -5616,4 +5737,5 @@ void MemNotifyThread::start() {
new MemNotifyThread(fd);
}
}
+
#endif // JAVASE_EMBEDDED
diff --git a/src/os/linux/vm/os_linux.hpp b/src/os/linux/vm/os_linux.hpp
index c2ce765bc..41c29f680 100644
--- a/src/os/linux/vm/os_linux.hpp
+++ b/src/os/linux/vm/os_linux.hpp
@@ -210,35 +210,6 @@ class Linux {
// LinuxThreads work-around for 6292965
static int safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime);
-
- // Linux suspend/resume support - this helper is a shadow of its former
- // self now that low-level suspension is barely used, and old workarounds
- // for LinuxThreads are no longer needed.
- class SuspendResume {
- private:
- volatile int _suspend_action;
- volatile jint _state;
- public:
- // values for suspend_action:
- enum {
- SR_NONE = 0x00,
- SR_SUSPEND = 0x01, // suspend request
- SR_CONTINUE = 0x02, // resume request
- SR_SUSPENDED = 0x20 // values for _state: + SR_NONE
- };
-
- SuspendResume() { _suspend_action = SR_NONE; _state = SR_NONE; }
-
- int suspend_action() const { return _suspend_action; }
- void set_suspend_action(int x) { _suspend_action = x; }
-
- // atomic updates for _state
- inline void set_suspended();
- inline void clear_suspended();
- bool is_suspended() { return _state & SR_SUSPENDED; }
-
- };
-
private:
typedef int (*sched_getcpu_func_t)(void);
typedef int (*numa_node_to_cpus_func_t)(int node, unsigned long *buffer, int bufferlen);
@@ -333,6 +304,6 @@ class PlatformParker : public CHeapObj<mtInternal> {
status = pthread_mutex_init (_mutex, NULL);
assert_status(status == 0, status, "mutex_init");
}
-} ;
+};
#endif // OS_LINUX_VM_OS_LINUX_HPP
diff --git a/src/os/linux/vm/os_linux.inline.hpp b/src/os/linux/vm/os_linux.inline.hpp
index 87494dfd9..1afae5cc4 100644
--- a/src/os/linux/vm/os_linux.inline.hpp
+++ b/src/os/linux/vm/os_linux.inline.hpp
@@ -288,20 +288,4 @@ inline int os::set_sock_opt(int fd, int level, int optname,
return ::setsockopt(fd, level, optname, optval, optlen);
}
-inline void os::Linux::SuspendResume::set_suspended() {
- jint temp, temp2;
- do {
- temp = _state;
- temp2 = Atomic::cmpxchg(temp | SR_SUSPENDED, &_state, temp);
- } while (temp2 != temp);
-}
-
-inline void os::Linux::SuspendResume::clear_suspended() {
- jint temp, temp2;
- do {
- temp = _state;
- temp2 = Atomic::cmpxchg(temp & ~SR_SUSPENDED, &_state, temp);
- } while (temp2 != temp);
-}
-
#endif // OS_LINUX_VM_OS_LINUX_INLINE_HPP
diff --git a/src/os/solaris/vm/osThread_solaris.cpp b/src/os/solaris/vm/osThread_solaris.cpp
index 6310471f5..9cbd632e5 100644
--- a/src/os/solaris/vm/osThread_solaris.cpp
+++ b/src/os/solaris/vm/osThread_solaris.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, 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
@@ -41,10 +41,6 @@ void OSThread::pd_initialize() {
_thread_id = 0;
sigemptyset(&_caller_sigmask);
- _current_callback = NULL;
- _current_callback_lock = VM_Version::supports_compare_and_exchange() ? NULL
- : new Mutex(Mutex::suspend_resume, "Callback_lock", true);
-
_saved_interrupt_thread_state = _thread_new;
_vm_created_thread = false;
}
@@ -52,172 +48,6 @@ void OSThread::pd_initialize() {
void OSThread::pd_destroy() {
}
-// Synchronous interrupt support
-//
-// _current_callback == NULL no pending callback
-// == 1 callback_in_progress
-// == other value pointer to the pending callback
-//
-
-// CAS on v8 is implemented by using a global atomic_memory_operation_lock,
-// which is shared by other atomic functions. It is OK for normal uses, but
-// dangerous if used after some thread is suspended or if used in signal
-// handlers. Instead here we use a special per-thread lock to synchronize
-// updating _current_callback if we are running on v8. Note in general trying
-// to grab locks after a thread is suspended is not safe, but it is safe for
-// updating _current_callback, because synchronous interrupt callbacks are
-// currently only used in:
-// 1. GetThreadPC_Callback - used by WatcherThread to profile VM thread
-// There is no overlap between the callbacks, which means we won't try to
-// grab a thread's sync lock after the thread has been suspended while holding
-// the same lock.
-
-// used after a thread is suspended
-static intptr_t compare_and_exchange_current_callback (
- intptr_t callback, intptr_t *addr, intptr_t compare_value, Mutex *sync) {
- if (VM_Version::supports_compare_and_exchange()) {
- return Atomic::cmpxchg_ptr(callback, addr, compare_value);
- } else {
- MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
- if (*addr == compare_value) {
- *addr = callback;
- return compare_value;
- } else {
- return callback;
- }
- }
-}
-
-// used in signal handler
-static intptr_t exchange_current_callback(intptr_t callback, intptr_t *addr, Mutex *sync) {
- if (VM_Version::supports_compare_and_exchange()) {
- return Atomic::xchg_ptr(callback, addr);
- } else {
- MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
- intptr_t cb = *addr;
- *addr = callback;
- return cb;
- }
-}
-
-// one interrupt at a time. spin if _current_callback != NULL
-int OSThread::set_interrupt_callback(Sync_Interrupt_Callback * cb) {
- int count = 0;
- while (compare_and_exchange_current_callback(
- (intptr_t)cb, (intptr_t *)&_current_callback, (intptr_t)NULL, _current_callback_lock) != NULL) {
- while (_current_callback != NULL) {
- count++;
-#ifdef ASSERT
- if ((WarnOnStalledSpinLock > 0) &&
- (count % WarnOnStalledSpinLock == 0)) {
- warning("_current_callback seems to be stalled: %p", _current_callback);
- }
-#endif
- os::yield_all(count);
- }
- }
- return 0;
-}
-
-// reset _current_callback, spin if _current_callback is callback_in_progress
-void OSThread::remove_interrupt_callback(Sync_Interrupt_Callback * cb) {
- int count = 0;
- while (compare_and_exchange_current_callback(
- (intptr_t)NULL, (intptr_t *)&_current_callback, (intptr_t)cb, _current_callback_lock) != (intptr_t)cb) {
-#ifdef ASSERT
- intptr_t p = (intptr_t)_current_callback;
- assert(p == (intptr_t)callback_in_progress ||
- p == (intptr_t)cb, "wrong _current_callback value");
-#endif
- while (_current_callback != cb) {
- count++;
-#ifdef ASSERT
- if ((WarnOnStalledSpinLock > 0) &&
- (count % WarnOnStalledSpinLock == 0)) {
- warning("_current_callback seems to be stalled: %p", _current_callback);
- }
-#endif
- os::yield_all(count);
- }
- }
-}
-
-void OSThread::do_interrupt_callbacks_at_interrupt(InterruptArguments *args) {
- Sync_Interrupt_Callback * cb;
- cb = (Sync_Interrupt_Callback *)exchange_current_callback(
- (intptr_t)callback_in_progress, (intptr_t *)&_current_callback, _current_callback_lock);
-
- if (cb == NULL) {
- // signal is delivered too late (thread is masking interrupt signal??).
- // there is nothing we need to do because requesting thread has given up.
- } else if ((intptr_t)cb == (intptr_t)callback_in_progress) {
- fatal("invalid _current_callback state");
- } else {
- assert(cb->target()->osthread() == this, "wrong target");
- cb->execute(args);
- cb->leave_callback(); // notify the requester
- }
-
- // restore original _current_callback value
- intptr_t p;
- p = exchange_current_callback((intptr_t)cb, (intptr_t *)&_current_callback, _current_callback_lock);
- assert(p == (intptr_t)callback_in_progress, "just checking");
-}
-
-// Called by the requesting thread to send a signal to target thread and
-// execute "this" callback from the signal handler.
-int OSThread::Sync_Interrupt_Callback::interrupt(Thread * target, int timeout) {
- // Let signals to the vm_thread go even if the Threads_lock is not acquired
- assert(Threads_lock->owned_by_self() || (target == VMThread::vm_thread()),
- "must have threads lock to call this");
-
- OSThread * osthread = target->osthread();
-
- // may block if target thread already has a pending callback
- osthread->set_interrupt_callback(this);
-
- _target = target;
-
- int rslt = thr_kill(osthread->thread_id(), os::Solaris::SIGasync());
- assert(rslt == 0, "thr_kill != 0");
-
- bool status = false;
- jlong t1 = os::javaTimeMillis();
- { // don't use safepoint check because we might be the watcher thread.
- MutexLockerEx ml(_sync, Mutex::_no_safepoint_check_flag);
- while (!is_done()) {
- status = _sync->wait(Mutex::_no_safepoint_check_flag, timeout);
-
- // status == true if timed out
- if (status) break;
-
- // update timeout
- jlong t2 = os::javaTimeMillis();
- timeout -= t2 - t1;
- t1 = t2;
- }
- }
-
- // reset current_callback
- osthread->remove_interrupt_callback(this);
-
- return status;
-}
-
-void OSThread::Sync_Interrupt_Callback::leave_callback() {
- if (!_sync->owned_by_self()) {
- // notify requesting thread
- MutexLockerEx ml(_sync, Mutex::_no_safepoint_check_flag);
- _is_done = true;
- _sync->notify_all();
- } else {
- // Current thread is interrupted while it is holding the _sync lock, trying
- // to grab it again will deadlock. The requester will timeout anyway,
- // so just return.
- _is_done = true;
- }
-}
-
// copied from synchronizer.cpp
void OSThread::handle_spinlock_contention(int tries) {
@@ -229,3 +59,7 @@ void OSThread::handle_spinlock_contention(int tries) {
os::yield(); // Yield to threads of same or higher priority
}
}
+
+void OSThread::SR_handler(Thread* thread, ucontext_t* uc) {
+ os::Solaris::SR_handler(thread, uc);
+}
diff --git a/src/os/solaris/vm/osThread_solaris.hpp b/src/os/solaris/vm/osThread_solaris.hpp
index 2a7a2470a..c3f966994 100644
--- a/src/os/solaris/vm/osThread_solaris.hpp
+++ b/src/os/solaris/vm/osThread_solaris.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -72,61 +72,15 @@
// ***************************************************************
public:
-
- class InterruptArguments : StackObj {
- private:
- Thread* _thread; // the thread to signal was dispatched to
- ucontext_t* _ucontext; // the machine context at the time of the signal
-
- public:
- InterruptArguments(Thread* thread, ucontext_t* ucontext) {
- _thread = thread;
- _ucontext = ucontext;
- }
-
- Thread* thread() const { return _thread; }
- ucontext_t* ucontext() const { return _ucontext; }
- };
-
- // There are currently no asynchronous callbacks - and we'd better not
- // support them in the future either, as they need to be deallocated from
- // the interrupt handler, which is not safe; they also require locks to
- // protect the callback queue.
-
- class Sync_Interrupt_Callback : private StackObj {
- protected:
- volatile bool _is_done;
- Monitor* _sync;
- Thread* _target;
- public:
- Sync_Interrupt_Callback(Monitor * sync) {
- _is_done = false; _target = NULL; _sync = sync;
- }
-
- bool is_done() const { return _is_done; }
- Thread* target() const { return _target; }
-
- int interrupt(Thread * target, int timeout);
-
- // override to implement the callback.
- virtual void execute(InterruptArguments *args) = 0;
-
- void leave_callback();
- };
+ os::SuspendResume sr;
private:
-
- Sync_Interrupt_Callback * volatile _current_callback;
- enum {
- callback_in_progress = 1
- };
- Mutex * _current_callback_lock; // only used on v8
+ ucontext_t* _ucontext;
public:
-
- int set_interrupt_callback (Sync_Interrupt_Callback * cb);
- void remove_interrupt_callback(Sync_Interrupt_Callback * cb);
- void do_interrupt_callbacks_at_interrupt(InterruptArguments *args);
+ ucontext_t* ucontext() const { return _ucontext; }
+ void set_ucontext(ucontext_t* ptr) { _ucontext = ptr; }
+ static void SR_handler(Thread* thread, ucontext_t* uc);
// ***************************************************************
// java.lang.Thread.interrupt state.
diff --git a/src/os/solaris/vm/os_share_solaris.hpp b/src/os/solaris/vm/os_share_solaris.hpp
index a7c1ce8c0..40143c6c6 100644
--- a/src/os/solaris/vm/os_share_solaris.hpp
+++ b/src/os/solaris/vm/os_share_solaris.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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,28 +27,6 @@
// Defines the interfaces to Solaris operating systems that vary across platforms
-
-// This is a simple callback that just fetches a PC for an interrupted thread.
-// The thread need not be suspended and the fetched PC is just a hint.
-// Returned PC and nPC are not necessarily consecutive.
-// This one is currently used for profiling the VMThread ONLY!
-
-// Must be synchronous
-class GetThreadPC_Callback : public OSThread::Sync_Interrupt_Callback {
- private:
- ExtendedPC _addr;
-
- public:
-
- GetThreadPC_Callback(Monitor *sync) :
- OSThread::Sync_Interrupt_Callback(sync) { }
- ExtendedPC addr() const { return _addr; }
-
- void set_addr(ExtendedPC addr) { _addr = addr; }
-
- void execute(OSThread::InterruptArguments *args);
-};
-
// misc
extern "C" {
void signalHandler(int, siginfo_t*, void*);
diff --git a/src/os/solaris/vm/os_solaris.cpp b/src/os/solaris/vm/os_solaris.cpp
index 09204157d..5df7a8b40 100644
--- a/src/os/solaris/vm/os_solaris.cpp
+++ b/src/os/solaris/vm/os_solaris.cpp
@@ -240,6 +240,8 @@ extern "C" {
static int pthread_cond_default_init(cond_t *cv, int scope, void *arg){ memset(cv, 0, sizeof(cond_t)); return 0; }
}
+static void unpackTime(timespec* absTime, bool isAbsolute, jlong time);
+
// Thread Local Storage
// This is common to all Solaris platforms so it is defined here,
// in this common file.
@@ -2580,6 +2582,57 @@ void* os::user_handler() {
return CAST_FROM_FN_PTR(void*, UserHandler);
}
+class Semaphore : public StackObj {
+ public:
+ Semaphore();
+ ~Semaphore();
+ void signal();
+ void wait();
+ bool trywait();
+ bool timedwait(unsigned int sec, int nsec);
+ private:
+ sema_t _semaphore;
+};
+
+
+Semaphore::Semaphore() {
+ sema_init(&_semaphore, 0, NULL, NULL);
+}
+
+Semaphore::~Semaphore() {
+ sema_destroy(&_semaphore);
+}
+
+void Semaphore::signal() {
+ sema_post(&_semaphore);
+}
+
+void Semaphore::wait() {
+ sema_wait(&_semaphore);
+}
+
+bool Semaphore::trywait() {
+ return sema_trywait(&_semaphore) == 0;
+}
+
+bool Semaphore::timedwait(unsigned int sec, int nsec) {
+ struct timespec ts;
+ unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec);
+
+ while (1) {
+ int result = sema_timedwait(&_semaphore, &ts);
+ if (result == 0) {
+ return true;
+ } else if (errno == EINTR) {
+ continue;
+ } else if (errno == ETIME) {
+ return false;
+ } else {
+ return false;
+ }
+ }
+}
+
extern "C" {
typedef void (*sa_handler_t)(int);
typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
@@ -4164,6 +4217,68 @@ void os::hint_no_preempt() {
schedctl_start(schedctl_init());
}
+static void resume_clear_context(OSThread *osthread) {
+ osthread->set_ucontext(NULL);
+}
+
+static void suspend_save_context(OSThread *osthread, ucontext_t* context) {
+ osthread->set_ucontext(context);
+}
+
+static Semaphore sr_semaphore;
+
+void os::Solaris::SR_handler(Thread* thread, ucontext_t* uc) {
+ // Save and restore errno to avoid confusing native code with EINTR
+ // after sigsuspend.
+ int old_errno = errno;
+
+ OSThread* osthread = thread->osthread();
+ assert(thread->is_VM_thread() || thread->is_Java_thread(), "Must be VMThread or JavaThread");
+
+ os::SuspendResume::State current = osthread->sr.state();
+ if (current == os::SuspendResume::SR_SUSPEND_REQUEST) {
+ suspend_save_context(osthread, uc);
+
+ // attempt to switch the state, we assume we had a SUSPEND_REQUEST
+ os::SuspendResume::State state = osthread->sr.suspended();
+ if (state == os::SuspendResume::SR_SUSPENDED) {
+ sigset_t suspend_set; // signals for sigsuspend()
+
+ // get current set of blocked signals and unblock resume signal
+ thr_sigsetmask(SIG_BLOCK, NULL, &suspend_set);
+ sigdelset(&suspend_set, os::Solaris::SIGasync());
+
+ sr_semaphore.signal();
+ // wait here until we are resumed
+ while (1) {
+ sigsuspend(&suspend_set);
+
+ os::SuspendResume::State result = osthread->sr.running();
+ if (result == os::SuspendResume::SR_RUNNING) {
+ sr_semaphore.signal();
+ break;
+ }
+ }
+
+ } else if (state == os::SuspendResume::SR_RUNNING) {
+ // request was cancelled, continue
+ } else {
+ ShouldNotReachHere();
+ }
+
+ resume_clear_context(osthread);
+ } else if (current == os::SuspendResume::SR_RUNNING) {
+ // request was cancelled, continue
+ } else if (current == os::SuspendResume::SR_WAKEUP_REQUEST) {
+ // ignore
+ } else {
+ // ignore
+ }
+
+ errno = old_errno;
+}
+
+
void os::interrupt(Thread* thread) {
assert(Thread::current() == thread || Threads_lock->owned_by_self(), "possibility of dangling Thread pointer");
@@ -4247,6 +4362,116 @@ int os::message_box(const char* title, const char* message) {
return buf[0] == 'y' || buf[0] == 'Y';
}
+static int sr_notify(OSThread* osthread) {
+ int status = thr_kill(osthread->thread_id(), os::Solaris::SIGasync());
+ assert_status(status == 0, status, "thr_kill");
+ return status;
+}
+
+// "Randomly" selected value for how long we want to spin
+// before bailing out on suspending a thread, also how often
+// we send a signal to a thread we want to resume
+static const int RANDOMLY_LARGE_INTEGER = 1000000;
+static const int RANDOMLY_LARGE_INTEGER2 = 100;
+
+static bool do_suspend(OSThread* osthread) {
+ assert(osthread->sr.is_running(), "thread should be running");
+ assert(!sr_semaphore.trywait(), "semaphore has invalid state");
+
+ // mark as suspended and send signal
+ if (osthread->sr.request_suspend() != os::SuspendResume::SR_SUSPEND_REQUEST) {
+ // failed to switch, state wasn't running?
+ ShouldNotReachHere();
+ return false;
+ }
+
+ if (sr_notify(osthread) != 0) {
+ ShouldNotReachHere();
+ }
+
+ // managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED
+ while (true) {
+ if (sr_semaphore.timedwait(0, 2000 * NANOSECS_PER_MILLISEC)) {
+ break;
+ } else {
+ // timeout
+ os::SuspendResume::State cancelled = osthread->sr.cancel_suspend();
+ if (cancelled == os::SuspendResume::SR_RUNNING) {
+ return false;
+ } else if (cancelled == os::SuspendResume::SR_SUSPENDED) {
+ // make sure that we consume the signal on the semaphore as well
+ sr_semaphore.wait();
+ break;
+ } else {
+ ShouldNotReachHere();
+ return false;
+ }
+ }
+ }
+
+ guarantee(osthread->sr.is_suspended(), "Must be suspended");
+ return true;
+}
+
+static void do_resume(OSThread* osthread) {
+ assert(osthread->sr.is_suspended(), "thread should be suspended");
+ assert(!sr_semaphore.trywait(), "invalid semaphore state");
+
+ if (osthread->sr.request_wakeup() != os::SuspendResume::SR_WAKEUP_REQUEST) {
+ // failed to switch to WAKEUP_REQUEST
+ ShouldNotReachHere();
+ return;
+ }
+
+ while (true) {
+ if (sr_notify(osthread) == 0) {
+ if (sr_semaphore.timedwait(0, 2 * NANOSECS_PER_MILLISEC)) {
+ if (osthread->sr.is_running()) {
+ return;
+ }
+ }
+ } else {
+ ShouldNotReachHere();
+ }
+ }
+
+ guarantee(osthread->sr.is_running(), "Must be running!");
+}
+
+void os::SuspendedThreadTask::internal_do_task() {
+ if (do_suspend(_thread->osthread())) {
+ SuspendedThreadTaskContext context(_thread, _thread->osthread()->ucontext());
+ do_task(context);
+ do_resume(_thread->osthread());
+ }
+}
+
+class PcFetcher : public os::SuspendedThreadTask {
+public:
+ PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
+ ExtendedPC result();
+protected:
+ void do_task(const os::SuspendedThreadTaskContext& context);
+private:
+ ExtendedPC _epc;
+};
+
+ExtendedPC PcFetcher::result() {
+ guarantee(is_done(), "task is not done yet.");
+ return _epc;
+}
+
+void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
+ Thread* thread = context.thread();
+ OSThread* osthread = thread->osthread();
+ if (osthread->ucontext() != NULL) {
+ _epc = os::Solaris::ucontext_get_pc((ucontext_t *) context.ucontext());
+ } else {
+ // NULL context is unexpected, double-check this is the VMThread
+ guarantee(thread->is_VM_thread(), "can only be called for VMThread");
+ }
+}
+
// A lightweight implementation that does not suspend the target thread and
// thus returns only a hint. Used for profiling only!
ExtendedPC os::get_thread_pc(Thread* thread) {
@@ -4254,21 +4479,9 @@ ExtendedPC os::get_thread_pc(Thread* thread) {
assert(Thread::current()->is_Watcher_thread(), "Must be watcher and own Threads_lock");
// For now, is only used to profile the VM Thread
assert(thread->is_VM_thread(), "Can only be called for VMThread");
- ExtendedPC epc;
-
- GetThreadPC_Callback cb(ProfileVM_lock);
- OSThread *osthread = thread->osthread();
- const int time_to_wait = 400; // 400ms wait for initial response
- int status = cb.interrupt(thread, time_to_wait);
-
- if (cb.is_done() ) {
- epc = cb.addr();
- } else {
- DEBUG_ONLY(tty->print_cr("Failed to get pc for thread: %d got %d status",
- osthread->thread_id(), status););
- // epc is already NULL
- }
- return epc;
+ PcFetcher fetcher(thread);
+ fetcher.run();
+ return fetcher.result();
}
diff --git a/src/os/solaris/vm/os_solaris.hpp b/src/os/solaris/vm/os_solaris.hpp
index c1dff0cf1..99b757cd6 100644
--- a/src/os/solaris/vm/os_solaris.hpp
+++ b/src/os/solaris/vm/os_solaris.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -127,7 +127,6 @@ class Solaris {
static void set_SIGinterrupt(int newsig) { _SIGinterrupt = newsig; }
static void set_SIGasync(int newsig) { _SIGasync = newsig; }
-
public:
// Large Page Support--ISM.
static bool largepage_range(char* addr, size_t size);
@@ -145,6 +144,7 @@ class Solaris {
static intptr_t* ucontext_get_sp(ucontext_t* uc);
// ucontext_get_fp() is only used by Solaris X86 (see note below)
static intptr_t* ucontext_get_fp(ucontext_t* uc);
+ static address ucontext_get_pc(ucontext_t* uc);
// For Analyzer Forte AsyncGetCallTrace profiling support:
// Parameter ret_fp is only used by Solaris X86.
@@ -157,6 +157,8 @@ class Solaris {
static void hotspot_sigmask(Thread* thread);
+ // SR_handler
+ static void SR_handler(Thread* thread, ucontext_t* uc);
protected:
// Solaris-specific interface goes here
static julong available_memory();
diff --git a/src/os/windows/vm/os_windows.cpp b/src/os/windows/vm/os_windows.cpp
index 33ebe5987..baa177682 100644
--- a/src/os/windows/vm/os_windows.cpp
+++ b/src/os/windows/vm/os_windows.cpp
@@ -5048,6 +5048,71 @@ int os::set_sock_opt(int fd, int level, int optname,
return ::setsockopt(fd, level, optname, optval, optlen);
}
+// WINDOWS CONTEXT Flags for THREAD_SAMPLING
+#if defined(IA32)
+# define sampling_context_flags (CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS)
+#elif defined (AMD64)
+# define sampling_context_flags (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
+#endif
+
+// returns true if thread could be suspended,
+// false otherwise
+static bool do_suspend(HANDLE* h) {
+ if (h != NULL) {
+ if (SuspendThread(*h) != ~0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// resume the thread
+// calling resume on an active thread is a no-op
+static void do_resume(HANDLE* h) {
+ if (h != NULL) {
+ ResumeThread(*h);
+ }
+}
+
+// retrieve a suspend/resume context capable handle
+// from the tid. Caller validates handle return value.
+void get_thread_handle_for_extended_context(HANDLE* h, OSThread::thread_id_t tid) {
+ if (h != NULL) {
+ *h = OpenThread(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, tid);
+ }
+}
+
+//
+// Thread sampling implementation
+//
+void os::SuspendedThreadTask::internal_do_task() {
+ CONTEXT ctxt;
+ HANDLE h = NULL;
+
+ // get context capable handle for thread
+ get_thread_handle_for_extended_context(&h, _thread->osthread()->thread_id());
+
+ // sanity
+ if (h == NULL || h == INVALID_HANDLE_VALUE) {
+ return;
+ }
+
+ // suspend the thread
+ if (do_suspend(&h)) {
+ ctxt.ContextFlags = sampling_context_flags;
+ // get thread context
+ GetThreadContext(h, &ctxt);
+ SuspendedThreadTaskContext context(_thread, &ctxt);
+ // pass context to Thread Sampling impl
+ do_task(context);
+ // resume thread
+ do_resume(&h);
+ }
+
+ // close handle
+ CloseHandle(h);
+}
+
// Kernel32 API
typedef SIZE_T (WINAPI* GetLargePageMinimum_Fn)(void);
diff --git a/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp b/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp
index f508ab9ec..8d167adaf 100644
--- a/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp
+++ b/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, 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,16 @@
// currently interrupted by SIGPROF
bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr,
void* ucontext, bool isInJava) {
-
assert(Thread::current() == this, "caller must be current thread");
- assert(this->is_Java_thread(), "must be JavaThread");
+ return pd_get_top_frame(fr_addr, ucontext, isInJava);
+}
+bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) {
+ return pd_get_top_frame(fr_addr, ucontext, isInJava);
+}
+
+bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) {
+ assert(this->is_Java_thread(), "must be JavaThread");
JavaThread* jt = (JavaThread *)this;
// If we have a last_Java_frame, then we should use it even if
diff --git a/src/os_cpu/bsd_x86/vm/thread_bsd_x86.hpp b/src/os_cpu/bsd_x86/vm/thread_bsd_x86.hpp
index 69dba9b3a..1d7921c71 100644
--- a/src/os_cpu/bsd_x86/vm/thread_bsd_x86.hpp
+++ b/src/os_cpu/bsd_x86/vm/thread_bsd_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, 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,13 @@
bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext,
bool isInJava);
+ bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext,
+ bool isInJava);
+
+private:
+ bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava);
+public:
+
// These routines are only used on cpu architectures that
// have separate register stacks (Itanium).
static bool register_stack_overflow() { return false; }
diff --git a/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp b/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp
index 69414cf7f..77affdd52 100644
--- a/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp
+++ b/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, 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,8 +32,15 @@ bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr,
void* ucontext, bool isInJava) {
assert(Thread::current() == this, "caller must be current thread");
- assert(this->is_Java_thread(), "must be JavaThread");
+ return pd_get_top_frame(fr_addr, ucontext, isInJava);
+}
+bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) {
+ return pd_get_top_frame(fr_addr, ucontext, isInJava);
+}
+
+bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) {
+ assert(this->is_Java_thread(), "must be JavaThread");
JavaThread* jt = (JavaThread *)this;
// If we have a last_Java_frame, then we should use it even if
diff --git a/src/os_cpu/linux_x86/vm/thread_linux_x86.hpp b/src/os_cpu/linux_x86/vm/thread_linux_x86.hpp
index 7a7d22252..75fb7df57 100644
--- a/src/os_cpu/linux_x86/vm/thread_linux_x86.hpp
+++ b/src/os_cpu/linux_x86/vm/thread_linux_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, 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,11 @@
bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext,
bool isInJava);
+ bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava);
+private:
+ bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava);
+public:
+
// These routines are only used on cpu architectures that
// have separate register stacks (Itanium).
static bool register_stack_overflow() { return false; }
diff --git a/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp b/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp
index 78902e1b4..939def32f 100644
--- a/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp
+++ b/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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
@@ -194,6 +194,11 @@ intptr_t* os::Solaris::ucontext_get_fp(ucontext_t *uc) {
return NULL;
}
+address os::Solaris::ucontext_get_pc(ucontext_t *uc) {
+ return (address) uc->uc_mcontext.gregs[REG_PC];
+}
+
+
// For Forte Analyzer AsyncGetCallTrace profiling support - thread
// is currently interrupted by SIGPROF.
//
@@ -265,22 +270,6 @@ frame os::current_frame() {
}
}
-
-void GetThreadPC_Callback::execute(OSThread::InterruptArguments *args) {
- Thread* thread = args->thread();
- ucontext_t* uc = args->ucontext();
- intptr_t* sp;
-
- assert(ProfileVM && thread->is_VM_thread(), "just checking");
-
- // Skip the mcontext corruption verification. If if occasionally
- // things get corrupt, it is ok for profiling - we will just get an unresolved
- // function name
- ExtendedPC new_addr((address)uc->uc_mcontext.gregs[REG_PC]);
- _addr = new_addr;
-}
-
-
static int threadgetstate(thread_t tid, int *flags, lwpid_t *lwp, stack_t *ss, gregset_t rs, lwpstatus_t *lwpstatus) {
char lwpstatusfile[PROCFILE_LENGTH];
int lwpfd, err;
@@ -358,13 +347,8 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
guarantee(sig != os::Solaris::SIGinterrupt(), "Can not chain VM interrupt signal, try -XX:+UseAltSigs");
if (sig == os::Solaris::SIGasync()) {
- if (thread) {
- OSThread::InterruptArguments args(thread, uc);
- thread->osthread()->do_interrupt_callbacks_at_interrupt(&args);
- return true;
- } else if (vmthread) {
- OSThread::InterruptArguments args(vmthread, uc);
- vmthread->osthread()->do_interrupt_callbacks_at_interrupt(&args);
+ if (thread || vmthread) {
+ OSThread::SR_handler(t, uc);
return true;
} else if (os::Solaris::chained_handler(sig, info, ucVoid)) {
return true;
diff --git a/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp b/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp
index f0fbc6699..9964114a7 100644
--- a/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp
+++ b/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, 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,11 +36,21 @@ bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr,
void* ucontext, bool isInJava) {
assert(Thread::current() == this, "caller must be current thread");
+ return pd_get_top_frame(fr_addr, ucontext, isInJava, true);
+}
+
+bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) {
+ // get ucontext somehow
+ return pd_get_top_frame(fr_addr, ucontext, isInJava, false);
+}
+
+bool JavaThread::pd_get_top_frame(frame* fr_addr,
+ void* ucontext, bool isInJava, bool makeWalkable) {
assert(this->is_Java_thread(), "must be JavaThread");
JavaThread* jt = (JavaThread *)this;
- if (!isInJava) {
+ if (!isInJava && makeWalkable) {
// make_walkable flushes register windows and grabs last_Java_pc
// which can not be done if the ucontext sp matches last_Java_sp
// stack walking utilities assume last_Java_pc set if marked flushed
diff --git a/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.hpp b/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.hpp
index 1cd0709b6..84b317361 100644
--- a/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.hpp
+++ b/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, 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
@@ -93,6 +93,11 @@ public:
bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext,
bool isInJava);
+ bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava);
+private:
+ bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava, bool makeWalkable);
+public:
+
// These routines are only used on cpu architectures that
// have separate register stacks (Itanium).
static bool register_stack_overflow() { return false; }
diff --git a/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp b/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp
index 51846441e..4ed094db7 100644
--- a/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp
+++ b/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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
@@ -183,6 +183,10 @@ intptr_t* os::Solaris::ucontext_get_fp(ucontext_t *uc) {
return (intptr_t*)uc->uc_mcontext.gregs[REG_FP];
}
+address os::Solaris::ucontext_get_pc(ucontext_t *uc) {
+ return (address) uc->uc_mcontext.gregs[REG_PC];
+}
+
// For Forte Analyzer AsyncGetCallTrace profiling support - thread
// is currently interrupted by SIGPROF.
//
@@ -252,22 +256,6 @@ frame os::current_frame() {
}
}
-// This is a simple callback that just fetches a PC for an interrupted thread.
-// The thread need not be suspended and the fetched PC is just a hint.
-// This one is currently used for profiling the VMThread ONLY!
-
-// Must be synchronous
-void GetThreadPC_Callback::execute(OSThread::InterruptArguments *args) {
- Thread* thread = args->thread();
- ucontext_t* uc = args->ucontext();
- intptr_t* sp;
-
- assert(ProfileVM && thread->is_VM_thread(), "just checking");
-
- ExtendedPC new_addr((address)uc->uc_mcontext.gregs[REG_PC]);
- _addr = new_addr;
-}
-
static int threadgetstate(thread_t tid, int *flags, lwpid_t *lwp, stack_t *ss, gregset_t rs, lwpstatus_t *lwpstatus) {
char lwpstatusfile[PROCFILE_LENGTH];
int lwpfd, err;
@@ -419,14 +407,8 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
guarantee(sig != os::Solaris::SIGinterrupt(), "Can not chain VM interrupt signal, try -XX:+UseAltSigs");
if (sig == os::Solaris::SIGasync()) {
- if(thread){
- OSThread::InterruptArguments args(thread, uc);
- thread->osthread()->do_interrupt_callbacks_at_interrupt(&args);
- return true;
- }
- else if(vmthread){
- OSThread::InterruptArguments args(vmthread, uc);
- vmthread->osthread()->do_interrupt_callbacks_at_interrupt(&args);
+ if(thread || vmthread){
+ OSThread::SR_handler(t, uc);
return true;
} else if (os::Solaris::chained_handler(sig, info, ucVoid)) {
return true;
diff --git a/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp b/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp
index 7c04d0272..3007c6bee 100644
--- a/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp
+++ b/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, 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,8 +30,17 @@
// currently interrupted by SIGPROF
bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr,
void* ucontext, bool isInJava) {
-
assert(Thread::current() == this, "caller must be current thread");
+ return pd_get_top_frame(fr_addr, ucontext, isInJava);
+}
+
+bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr,
+ void* ucontext, bool isInJava) {
+ return pd_get_top_frame(fr_addr, ucontext, isInJava);
+}
+
+bool JavaThread::pd_get_top_frame(frame* fr_addr,
+ void* ucontext, bool isInJava) {
assert(this->is_Java_thread(), "must be JavaThread");
JavaThread* jt = (JavaThread *)this;
diff --git a/src/os_cpu/solaris_x86/vm/thread_solaris_x86.hpp b/src/os_cpu/solaris_x86/vm/thread_solaris_x86.hpp
index d9665d392..7589a81a8 100644
--- a/src/os_cpu/solaris_x86/vm/thread_solaris_x86.hpp
+++ b/src/os_cpu/solaris_x86/vm/thread_solaris_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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
@@ -54,6 +54,12 @@
bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext,
bool isInJava);
+ bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext,
+ bool isInJava);
+private:
+ bool pd_get_top_frame(frame* fr_addr, void* ucontext,
+ bool isInJava);
+public:
// These routines are only used on cpu architectures that
// have separate register stacks (Itanium).
diff --git a/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp b/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp
index 308bd9476..7180fe1d9 100644
--- a/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp
+++ b/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, 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,15 @@ bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr,
void* ucontext, bool isInJava) {
assert(Thread::current() == this, "caller must be current thread");
+ return pd_get_top_frame(fr_addr, ucontext, isInJava);
+}
+
+bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) {
+ return pd_get_top_frame(fr_addr, ucontext, isInJava);
+}
+
+bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) {
+
assert(this->is_Java_thread(), "must be JavaThread");
JavaThread* jt = (JavaThread *)this;
@@ -87,4 +96,3 @@ bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr,
}
void JavaThread::cache_global_variables() { }
-
diff --git a/src/os_cpu/windows_x86/vm/thread_windows_x86.hpp b/src/os_cpu/windows_x86/vm/thread_windows_x86.hpp
index 1199a3c5b..65aac3510 100644
--- a/src/os_cpu/windows_x86/vm/thread_windows_x86.hpp
+++ b/src/os_cpu/windows_x86/vm/thread_windows_x86.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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
@@ -58,6 +58,12 @@
bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext,
bool isInJava);
+ bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava);
+
+private:
+ bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava);
+
+ public:
// These routines are only used on cpu architectures that
// have separate register stacks (Itanium).
static bool register_stack_overflow() { return false; }
diff --git a/src/share/tools/ProjectCreator/BuildConfig.java b/src/share/tools/ProjectCreator/BuildConfig.java
index f9283886a..a9b07e03e 100644
--- a/src/share/tools/ProjectCreator/BuildConfig.java
+++ b/src/share/tools/ProjectCreator/BuildConfig.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, 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
@@ -152,7 +152,7 @@ class BuildConfig {
sysDefines.add("_WINDOWS");
sysDefines.add("HOTSPOT_BUILD_USER=\\\""+System.getProperty("user.name")+"\\\"");
sysDefines.add("HOTSPOT_BUILD_TARGET=\\\""+get("Build")+"\\\"");
- sysDefines.add("INCLUDE_TRACE");
+ sysDefines.add("INCLUDE_TRACE=1");
sysDefines.add("_JNI_IMPLEMENTATION_");
if (vars.get("PlatformName").equals("Win32")) {
sysDefines.add("HOTSPOT_LIB_ARCH=\\\"i386\\\"");
diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp
index 263409f15..65cd2333a 100644
--- a/src/share/vm/classfile/classFileParser.cpp
+++ b/src/share/vm/classfile/classFileParser.cpp
@@ -39,6 +39,7 @@
#include "memory/gcLocker.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/oopFactory.hpp"
+#include "memory/referenceType.hpp"
#include "memory/universe.inline.hpp"
#include "oops/constantPool.hpp"
#include "oops/fieldStreams.hpp"
diff --git a/src/share/vm/classfile/classLoaderData.cpp b/src/share/vm/classfile/classLoaderData.cpp
index c030645f6..1d39afd7f 100644
--- a/src/share/vm/classfile/classLoaderData.cpp
+++ b/src/share/vm/classfile/classLoaderData.cpp
@@ -64,6 +64,11 @@
#include "utilities/growableArray.hpp"
#include "utilities/ostream.hpp"
+#if INCLUDE_TRACE
+ #include "trace/tracing.hpp"
+#endif
+
+
ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL;
ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) :
@@ -120,6 +125,12 @@ void ClassLoaderData::classes_do(KlassClosure* klass_closure) {
}
}
+void ClassLoaderData::classes_do(void f(Klass * const)) {
+ for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
+ f(k);
+ }
+}
+
void ClassLoaderData::classes_do(void f(InstanceKlass*)) {
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
if (k->oop_is_instance()) {
@@ -583,6 +594,19 @@ void ClassLoaderDataGraph::classes_do(KlassClosure* klass_closure) {
}
}
+void ClassLoaderDataGraph::classes_do(void f(Klass* const)) {
+ for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
+ cld->classes_do(f);
+ }
+}
+
+void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) {
+ assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
+ for (ClassLoaderData* cld = _unloading; cld != NULL; cld = cld->next()) {
+ cld->classes_do(f);
+ }
+}
+
GrowableArray<ClassLoaderData*>* ClassLoaderDataGraph::new_clds() {
assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?");
@@ -687,6 +711,11 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure) {
dead->set_next(_unloading);
_unloading = dead;
}
+
+ if (seen_dead_loader) {
+ post_class_unload_events();
+ }
+
return seen_dead_loader;
}
@@ -702,6 +731,20 @@ void ClassLoaderDataGraph::purge() {
Metaspace::purge();
}
+void ClassLoaderDataGraph::post_class_unload_events(void) {
+#if INCLUDE_TRACE
+ assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
+ if (Tracing::enabled()) {
+ if (Tracing::is_event_enabled(TraceClassUnloadEvent)) {
+ assert(_unloading != NULL, "need class loader data unload list!");
+ _class_unload_time = Tracing::time();
+ classes_unloading_do(&class_unload_event);
+ }
+ Tracing::on_unloading_classes();
+ }
+#endif
+}
+
// CDS support
// Global metaspaces for writing information to the shared archive. When
@@ -769,3 +812,21 @@ void ClassLoaderData::print_value_on(outputStream* out) const {
class_loader()->print_value_on(out);
}
}
+
+#if INCLUDE_TRACE
+
+TracingTime ClassLoaderDataGraph::_class_unload_time;
+
+void ClassLoaderDataGraph::class_unload_event(Klass* const k) {
+
+ // post class unload event
+ EventClassUnload event(UNTIMED);
+ event.set_endtime(_class_unload_time);
+ event.set_unloadedClass(k);
+ oop defining_class_loader = k->class_loader();
+ event.set_definingClassLoader(defining_class_loader != NULL ?
+ defining_class_loader->klass() : (Klass*)NULL);
+ event.commit();
+}
+
+#endif /* INCLUDE_TRACE */
diff --git a/src/share/vm/classfile/classLoaderData.hpp b/src/share/vm/classfile/classLoaderData.hpp
index 2a7e43082..6d5747483 100644
--- a/src/share/vm/classfile/classLoaderData.hpp
+++ b/src/share/vm/classfile/classLoaderData.hpp
@@ -32,6 +32,10 @@
#include "runtime/mutex.hpp"
#include "utilities/growableArray.hpp"
+#if INCLUDE_TRACE
+# include "trace/traceTime.hpp"
+#endif
+
//
// A class loader represents a linkset. Conceptually, a linkset identifies
// the complete transitive closure of resolved links that a dynamic linker can
@@ -49,6 +53,7 @@ class ClassLoaderData;
class JNIMethodBlock;
class JNIHandleBlock;
class Metadebug;
+
// GC root for walking class loader data created
class ClassLoaderDataGraph : public AllStatic {
@@ -63,6 +68,7 @@ class ClassLoaderDataGraph : public AllStatic {
static ClassLoaderData* _saved_head;
static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS);
+ static void post_class_unload_events(void);
public:
static ClassLoaderData* find_or_create(Handle class_loader, TRAPS);
static void purge();
@@ -71,6 +77,8 @@ class ClassLoaderDataGraph : public AllStatic {
static void always_strong_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
static void keep_alive_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
static void classes_do(KlassClosure* klass_closure);
+ static void classes_do(void f(Klass* const));
+ static void classes_unloading_do(void f(Klass* const));
static bool do_unloading(BoolObjectClosure* is_alive);
// CMS support.
@@ -86,6 +94,12 @@ class ClassLoaderDataGraph : public AllStatic {
static bool contains(address x);
static bool contains_loader_data(ClassLoaderData* loader_data);
#endif
+
+#if INCLUDE_TRACE
+ private:
+ static TracingTime _class_unload_time;
+ static void class_unload_event(Klass* const k);
+#endif
};
// ClassLoaderData class
@@ -171,7 +185,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
void unload();
bool keep_alive() const { return _keep_alive; }
bool is_alive(BoolObjectClosure* is_alive_closure) const;
-
+ void classes_do(void f(Klass*));
void classes_do(void f(InstanceKlass*));
// Deallocate free list during class unloading.
diff --git a/src/share/vm/classfile/javaClasses.cpp b/src/share/vm/classfile/javaClasses.cpp
index cbe3581ff..65dfa4500 100644
--- a/src/share/vm/classfile/javaClasses.cpp
+++ b/src/share/vm/classfile/javaClasses.cpp
@@ -961,7 +961,7 @@ void java_lang_Thread::set_thread_status(oop java_thread,
// Read thread status value from threadStatus field in java.lang.Thread java class.
java_lang_Thread::ThreadStatus java_lang_Thread::get_thread_status(oop java_thread) {
- assert(Thread::current()->is_VM_thread() ||
+ assert(Thread::current()->is_Watcher_thread() || Thread::current()->is_VM_thread() ||
JavaThread::current()->thread_state() == _thread_in_vm,
"Java Thread is not running in vm");
// The threadStatus is only present starting in 1.5
diff --git a/src/share/vm/classfile/systemDictionary.cpp b/src/share/vm/classfile/systemDictionary.cpp
index 682309035..c0d50ca9a 100644
--- a/src/share/vm/classfile/systemDictionary.cpp
+++ b/src/share/vm/classfile/systemDictionary.cpp
@@ -56,6 +56,11 @@
#include "services/classLoadingService.hpp"
#include "services/threadService.hpp"
+#if INCLUDE_TRACE
+ #include "trace/tracing.hpp"
+ #include "trace/traceMacros.hpp"
+#endif
+
Dictionary* SystemDictionary::_dictionary = NULL;
PlaceholderTable* SystemDictionary::_placeholders = NULL;
@@ -586,10 +591,15 @@ instanceKlassHandle SystemDictionary::handle_parallel_super_load(
}
-Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle class_loader, Handle protection_domain, TRAPS) {
+Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
+ Handle class_loader,
+ Handle protection_domain,
+ TRAPS) {
assert(name != NULL && !FieldType::is_array(name) &&
!FieldType::is_obj(name), "invalid class name");
+ TracingTime class_load_start_time = Tracing::time();
+
// UseNewReflection
// Fix for 4474172; see evaluation for more details
class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
@@ -804,8 +814,9 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla
// during compilations.
MutexLocker mu(Compile_lock, THREAD);
update_dictionary(d_index, d_hash, p_index, p_hash,
- k, class_loader, THREAD);
+ k, class_loader, THREAD);
}
+
if (JvmtiExport::should_post_class_load()) {
Thread *thread = THREAD;
assert(thread->is_Java_thread(), "thread->is_Java_thread()");
@@ -861,8 +872,8 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla
// This brackets the SystemDictionary updates for both defining
// and initiating loaders
MutexLocker mu(SystemDictionary_lock, THREAD);
- placeholders()->find_and_remove(p_index, p_hash, name, loader_data, PlaceholderTable::LOAD_INSTANCE, THREAD);
- SystemDictionary_lock->notify_all();
+ placeholders()->find_and_remove(p_index, p_hash, name, loader_data, PlaceholderTable::LOAD_INSTANCE, THREAD);
+ SystemDictionary_lock->notify_all();
}
}
@@ -870,6 +881,8 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla
return NULL;
}
+ post_class_load_event(class_load_start_time, k, class_loader);
+
#ifdef ASSERT
{
ClassLoaderData* loader_data = k->class_loader_data();
@@ -993,6 +1006,8 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
TRAPS) {
TempNewSymbol parsed_name = NULL;
+ TracingTime class_load_start_time = Tracing::time();
+
ClassLoaderData* loader_data;
if (host_klass.not_null()) {
// Create a new CLD for anonymous class, that uses the same class loader
@@ -1048,6 +1063,8 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
assert(THREAD->is_Java_thread(), "thread->is_Java_thread()");
JvmtiExport::post_class_load((JavaThread *) THREAD, k());
}
+
+ post_class_load_event(class_load_start_time, k, class_loader);
}
assert(host_klass.not_null() || cp_patches == NULL,
"cp_patches only found with host_klass");
@@ -1435,6 +1452,7 @@ void SystemDictionary::define_instance_class(instanceKlassHandle k, TRAPS) {
JvmtiExport::post_class_load((JavaThread *) THREAD, k());
}
+
}
// Support parallel classloading
@@ -1678,6 +1696,7 @@ int SystemDictionary::calculate_systemdictionary_size(int classcount) {
}
return newsize;
}
+
// Assumes classes in the SystemDictionary are only unloaded at a safepoint
// Note: anonymous classes are not in the SD.
bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive) {
@@ -2024,12 +2043,6 @@ void SystemDictionary::update_dictionary(int d_index, unsigned int d_hash,
}
}
- // Assign a classid if one has not already been assigned. The
- // counter does not need to be atomically incremented since this
- // is only done while holding the SystemDictionary_lock.
- // All loaded classes get a unique ID.
- TRACE_INIT_ID(k);
-
// Make a new system dictionary entry.
Klass* sd_check = find_class(d_index, d_hash, name, loader_data);
if (sd_check == NULL) {
@@ -2612,6 +2625,27 @@ void SystemDictionary::verify_obj_klass_present(Symbol* class_name,
"Loaded klasses should be in SystemDictionary");
}
+// utility function for class load event
+void SystemDictionary::post_class_load_event(TracingTime start_time,
+ instanceKlassHandle k,
+ Handle initiating_loader) {
+#if INCLUDE_TRACE
+ EventClassLoad event(UNTIMED);
+ if (event.should_commit()) {
+ event.set_endtime(Tracing::time());
+ event.set_starttime(start_time);
+ event.set_loadedClass(k());
+ oop defining_class_loader = k->class_loader();
+ event.set_definingClassLoader(defining_class_loader != NULL ?
+ defining_class_loader->klass() : (Klass*)NULL);
+ oop class_loader = initiating_loader.is_null() ? (oop)NULL : initiating_loader();
+ event.set_initiatingClassLoader(class_loader != NULL ?
+ class_loader->klass() : (Klass*)NULL);
+ event.commit();
+ }
+#endif /* INCLUDE_TRACE */
+}
+
#ifndef PRODUCT
// statistics code
diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfile/systemDictionary.hpp
index 98e8f433e..a2a1a8575 100644
--- a/src/share/vm/classfile/systemDictionary.hpp
+++ b/src/share/vm/classfile/systemDictionary.hpp
@@ -31,9 +31,11 @@
#include "oops/symbol.hpp"
#include "runtime/java.hpp"
#include "runtime/reflectionUtils.hpp"
+#include "trace/traceTime.hpp"
#include "utilities/hashtable.hpp"
#include "utilities/hashtable.inline.hpp"
+
// The system dictionary stores all loaded classes and maps:
//
// [class name,class loader] -> class i.e. [Symbol*,oop] -> Klass*
@@ -636,6 +638,9 @@ private:
// Setup link to hierarchy
static void add_to_hierarchy(instanceKlassHandle k, TRAPS);
+ // event based tracing
+ static void post_class_load_event(TracingTime start_time, instanceKlassHandle k,
+ Handle initiating_loader);
// We pass in the hashtable index so we can calculate it outside of
// the SystemDictionary_lock.
diff --git a/src/share/vm/code/codeCache.cpp b/src/share/vm/code/codeCache.cpp
index 44d65e233..65c1e5f2e 100644
--- a/src/share/vm/code/codeCache.cpp
+++ b/src/share/vm/code/codeCache.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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,6 +45,7 @@
#include "runtime/java.hpp"
#include "runtime/mutexLocker.hpp"
#include "services/memoryService.hpp"
+#include "trace/tracing.hpp"
#include "utilities/xmlstream.hpp"
// Helper class for printing in CodeCache
@@ -114,7 +115,6 @@ class CodeBlob_sizes {
}
};
-
// CodeCache implementation
CodeHeap * CodeCache::_heap = new CodeHeap();
@@ -126,6 +126,7 @@ bool CodeCache::_needs_cache_clean = false;
nmethod* CodeCache::_scavenge_root_nmethods = NULL;
nmethod* CodeCache::_saved_nmethods = NULL;
+int CodeCache::_codemem_full_count = 0;
CodeBlob* CodeCache::first() {
assert_locked_or_safepoint(CodeCache_lock);
@@ -829,6 +830,22 @@ void CodeCache::verify() {
}
}
+void CodeCache::report_codemem_full() {
+ _codemem_full_count++;
+ EventCodeCacheFull event;
+ if (event.should_commit()) {
+ event.set_startAddress((u8)low_bound());
+ event.set_commitedTopAddress((u8)high());
+ event.set_reservedTopAddress((u8)high_bound());
+ event.set_entryCount(nof_blobs());
+ event.set_methodCount(nof_nmethods());
+ event.set_adaptorCount(nof_adapters());
+ event.set_unallocatedCapacity(unallocated_capacity()/K);
+ event.set_fullCount(_codemem_full_count);
+ event.commit();
+ }
+}
+
//------------------------------------------------------------------------------------------------
// Non-product version
diff --git a/src/share/vm/code/codeCache.hpp b/src/share/vm/code/codeCache.hpp
index 3dde92702..3e8eda6e2 100644
--- a/src/share/vm/code/codeCache.hpp
+++ b/src/share/vm/code/codeCache.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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,11 +64,15 @@ class CodeCache : AllStatic {
static void mark_scavenge_root_nmethods() PRODUCT_RETURN;
static void verify_perm_nmethods(CodeBlobClosure* f_or_null) PRODUCT_RETURN;
+ static int _codemem_full_count;
+
public:
// Initialization
static void initialize();
+ static void report_codemem_full();
+
// Allocation/administration
static CodeBlob* allocate(int size, bool is_critical = false); // allocates a new CodeBlob
static void commit(CodeBlob* cb); // called when the allocated CodeBlob has been filled
@@ -155,6 +159,7 @@ class CodeCache : AllStatic {
// The full limits of the codeCache
static address low_bound() { return (address) _heap->low_boundary(); }
static address high_bound() { return (address) _heap->high_boundary(); }
+ static address high() { return (address) _heap->high(); }
// Profiling
static address first_address(); // first address used for CodeBlobs
@@ -186,6 +191,8 @@ class CodeCache : AllStatic {
// tells how many nmethods have dependencies
static int number_of_nmethods_with_dependencies();
+
+ static int get_codemem_full_count() { return _codemem_full_count; }
};
#endif // SHARE_VM_CODE_CODECACHE_HPP
diff --git a/src/share/vm/compiler/compileBroker.cpp b/src/share/vm/compiler/compileBroker.cpp
index 73c00bf11..685cd74c7 100644
--- a/src/share/vm/compiler/compileBroker.cpp
+++ b/src/share/vm/compiler/compileBroker.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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
@@ -43,6 +43,7 @@
#include "runtime/os.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/sweeper.hpp"
+#include "trace/tracing.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
#ifdef COMPILER1
@@ -179,9 +180,11 @@ int CompileBroker::_sum_standard_bytes_compiled = 0;
int CompileBroker::_sum_nmethod_size = 0;
int CompileBroker::_sum_nmethod_code_size = 0;
-CompileQueue* CompileBroker::_c2_method_queue = NULL;
-CompileQueue* CompileBroker::_c1_method_queue = NULL;
-CompileTask* CompileBroker::_task_free_list = NULL;
+long CompileBroker::_peak_compilation_time = 0;
+
+CompileQueue* CompileBroker::_c2_method_queue = NULL;
+CompileQueue* CompileBroker::_c1_method_queue = NULL;
+CompileTask* CompileBroker::_task_free_list = NULL;
GrowableArray<CompilerThread*>* CompileBroker::_method_threads = NULL;
@@ -1795,6 +1798,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
ciMethod* target = ci_env.get_method_from_handle(target_handle);
TraceTime t1("compilation", &time);
+ EventCompilation event;
AbstractCompiler *comp = compiler(task_level);
if (comp == NULL) {
@@ -1836,6 +1840,16 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
}
// simulate crash during compilation
assert(task->compile_id() != CICrashAt, "just as planned");
+ if (event.should_commit()) {
+ event.set_method(target->get_Method());
+ event.set_compileID(compile_id);
+ event.set_compileLevel(task->comp_level());
+ event.set_succeded(task->is_success());
+ event.set_isOsr(is_osr);
+ event.set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
+ event.set_inlinedBytes(task->num_inlined_bytecodes());
+ event.commit();
+ }
}
pop_jni_handle_block();
@@ -1916,6 +1930,10 @@ void CompileBroker::handle_full_code_cache() {
}
warning("CodeCache is full. Compiler has been disabled.");
warning("Try increasing the code cache size using -XX:ReservedCodeCacheSize=");
+
+ CodeCache::report_codemem_full();
+
+
#ifndef PRODUCT
if (CompileTheWorld || ExitOnFullCodeCache) {
codecache_print(/* detailed= */ true);
@@ -2073,8 +2091,10 @@ void CompileBroker::collect_statistics(CompilerThread* thread, elapsedTimer time
// java.lang.management.CompilationMBean
_perf_total_compilation->inc(time.ticks());
+ _t_total_compilation.add(time);
+ _peak_compilation_time = time.milliseconds() > _peak_compilation_time ? time.milliseconds() : _peak_compilation_time;
+
if (CITime) {
- _t_total_compilation.add(time);
if (is_osr) {
_t_osr_compilation.add(time);
_sum_osr_bytes_compiled += method->code_size() + task->num_inlined_bytecodes();
@@ -2172,7 +2192,6 @@ void CompileBroker::print_times() {
tty->print_cr(" nmethod total size : %6d bytes", CompileBroker::_sum_nmethod_size);
}
-
// Debugging output for failure
void CompileBroker::print_last_compile() {
if ( _last_compile_level != CompLevel_none &&
diff --git a/src/share/vm/compiler/compileBroker.hpp b/src/share/vm/compiler/compileBroker.hpp
index 27fe52851..f336497a3 100644
--- a/src/share/vm/compiler/compileBroker.hpp
+++ b/src/share/vm/compiler/compileBroker.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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
@@ -299,17 +299,17 @@ class CompileBroker: AllStatic {
static elapsedTimer _t_osr_compilation;
static elapsedTimer _t_standard_compilation;
+ static int _total_compile_count;
static int _total_bailout_count;
static int _total_invalidated_count;
- static int _total_compile_count;
static int _total_native_compile_count;
static int _total_osr_compile_count;
static int _total_standard_compile_count;
-
static int _sum_osr_bytes_compiled;
static int _sum_standard_bytes_compiled;
static int _sum_nmethod_size;
static int _sum_nmethod_code_size;
+ static long _peak_compilation_time;
static CompilerThread* make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, TRAPS);
static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count);
@@ -421,6 +421,19 @@ class CompileBroker: AllStatic {
// compiler name for debugging
static const char* compiler_name(int comp_level);
+
+ static int get_total_compile_count() { return _total_compile_count; }
+ static int get_total_bailout_count() { return _total_bailout_count; }
+ static int get_total_invalidated_count() { return _total_invalidated_count; }
+ static int get_total_native_compile_count() { return _total_native_compile_count; }
+ static int get_total_osr_compile_count() { return _total_osr_compile_count; }
+ static int get_total_standard_compile_count() { return _total_standard_compile_count; }
+ static int get_sum_osr_bytes_compiled() { return _sum_osr_bytes_compiled; }
+ static int get_sum_standard_bytes_compiled() { return _sum_standard_bytes_compiled; }
+ static int get_sum_nmethod_size() { return _sum_nmethod_size;}
+ static int get_sum_nmethod_code_size() { return _sum_nmethod_code_size; }
+ static long get_peak_compilation_time() { return _peak_compilation_time; }
+ static long get_total_compilation_time() { return _t_total_compilation.milliseconds(); }
};
#endif // SHARE_VM_COMPILER_COMPILEBROKER_HPP
diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
index 2cc054e91..85c7b7317 100644
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
@@ -37,8 +37,12 @@
#include "gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp"
#include "gc_implementation/parNew/parNewGeneration.hpp"
#include "gc_implementation/shared/collectorCounters.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
#include "gc_implementation/shared/isGCActiveMark.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
+#include "memory/allocation.hpp"
#include "memory/cardTableRS.hpp"
#include "memory/collectorPolicy.hpp"
#include "memory/gcLocker.inline.hpp"
@@ -60,7 +64,8 @@
// statics
CMSCollector* ConcurrentMarkSweepGeneration::_collector = NULL;
-bool CMSCollector::_full_gc_requested = false;
+bool CMSCollector::_full_gc_requested = false;
+GCCause::Cause CMSCollector::_full_gc_cause = GCCause::_no_gc;
//////////////////////////////////////////////////////////////////
// In support of CMS/VM thread synchronization
@@ -591,7 +596,10 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
_concurrent_cycles_since_last_unload(0),
_roots_scanning_options(0),
_inter_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding),
- _intra_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding)
+ _intra_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding),
+ _gc_tracer_cm(new (ResourceObj::C_HEAP, mtGC) CMSTracer()),
+ _gc_timer_cm(new (ResourceObj::C_HEAP, mtGC) ConcurrentGCTimer()),
+ _cms_start_registered(false)
{
if (ExplicitGCInvokesConcurrentAndUnloadsClasses) {
ExplicitGCInvokesConcurrent = true;
@@ -1676,18 +1684,38 @@ void CMSCollector::collect(bool full,
_full_gcs_since_conc_gc++;
}
-void CMSCollector::request_full_gc(unsigned int full_gc_count) {
+void CMSCollector::request_full_gc(unsigned int full_gc_count, GCCause::Cause cause) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
unsigned int gc_count = gch->total_full_collections();
if (gc_count == full_gc_count) {
MutexLockerEx y(CGC_lock, Mutex::_no_safepoint_check_flag);
_full_gc_requested = true;
+ _full_gc_cause = cause;
CGC_lock->notify(); // nudge CMS thread
} else {
assert(gc_count > full_gc_count, "Error: causal loop");
}
}
+bool CMSCollector::is_external_interruption() {
+ GCCause::Cause cause = GenCollectedHeap::heap()->gc_cause();
+ return GCCause::is_user_requested_gc(cause) ||
+ GCCause::is_serviceability_requested_gc(cause);
+}
+
+void CMSCollector::report_concurrent_mode_interruption() {
+ if (is_external_interruption()) {
+ if (PrintGCDetails) {
+ gclog_or_tty->print(" (concurrent mode interrupted)");
+ }
+ } else {
+ if (PrintGCDetails) {
+ gclog_or_tty->print(" (concurrent mode failure)");
+ }
+ _gc_tracer_cm->report_concurrent_mode_failure();
+ }
+}
+
// The foreground and background collectors need to coordinate in order
// to make sure that they do not mutually interfere with CMS collections.
@@ -1845,14 +1873,8 @@ NOT_PRODUCT(
}
)
- if (PrintGCDetails && first_state > Idling) {
- GCCause::Cause cause = GenCollectedHeap::heap()->gc_cause();
- if (GCCause::is_user_requested_gc(cause) ||
- GCCause::is_serviceability_requested_gc(cause)) {
- gclog_or_tty->print(" (concurrent mode interrupted)");
- } else {
- gclog_or_tty->print(" (concurrent mode failure)");
- }
+ if (first_state > Idling) {
+ report_concurrent_mode_interruption();
}
set_did_compact(should_compact);
@@ -1868,6 +1890,10 @@ NOT_PRODUCT(
// Reference objects are active.
ref_processor()->clean_up_discovered_references();
+ if (first_state > Idling) {
+ save_heap_summary();
+ }
+
do_compaction_work(clear_all_soft_refs);
// Has the GC time limit been exceeded?
@@ -1971,7 +1997,14 @@ void CMSCollector::decide_foreground_collection_type(
// a mark-sweep-compact.
void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
- TraceTime t("CMS:MSC ", PrintGCDetails && Verbose, true, gclog_or_tty);
+
+ STWGCTimer* gc_timer = GenMarkSweep::gc_timer();
+ gc_timer->register_gc_start(os::elapsed_counter());
+
+ SerialOldTracer* gc_tracer = GenMarkSweep::gc_tracer();
+ gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start());
+
+ GCTraceTime t("CMS:MSC ", PrintGCDetails && Verbose, true, NULL);
if (PrintGC && Verbose && !(GCCause::is_user_requested_gc(gch->gc_cause()))) {
gclog_or_tty->print_cr("Compact ConcurrentMarkSweepGeneration after %d "
"collections passed to foreground collector", _full_gcs_since_conc_gc);
@@ -2062,6 +2095,10 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
size_policy()->msc_collection_end(gch->gc_cause());
}
+ gc_timer->register_gc_end(os::elapsed_counter());
+
+ gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions());
+
// For a mark-sweep-compact, compute_new_size() will be called
// in the heap's do_collection() method.
}
@@ -2093,7 +2130,7 @@ void CMSCollector::do_mark_sweep_work(bool clear_all_soft_refs,
// required.
_collectorState = FinalMarking;
}
- collect_in_foreground(clear_all_soft_refs);
+ collect_in_foreground(clear_all_soft_refs, GenCollectedHeap::heap()->gc_cause());
// For a mark-sweep, compute_new_size() will be called
// in the heap's do_collection() method.
@@ -2153,7 +2190,7 @@ class ReleaseForegroundGC: public StackObj {
// one "collect" method between the background collector and the foreground
// collector but the if-then-else required made it cleaner to have
// separate methods.
-void CMSCollector::collect_in_background(bool clear_all_soft_refs) {
+void CMSCollector::collect_in_background(bool clear_all_soft_refs, GCCause::Cause cause) {
assert(Thread::current()->is_ConcurrentGC_thread(),
"A CMS asynchronous collection is only allowed on a CMS thread.");
@@ -2172,6 +2209,7 @@ void CMSCollector::collect_in_background(bool clear_all_soft_refs) {
} else {
assert(_collectorState == Idling, "Should be idling before start.");
_collectorState = InitialMarking;
+ register_gc_start(cause);
// Reset the expansion cause, now that we are about to begin
// a new cycle.
clear_expansion_cause();
@@ -2184,6 +2222,7 @@ void CMSCollector::collect_in_background(bool clear_all_soft_refs) {
// ensuing concurrent GC cycle.
update_should_unload_classes();
_full_gc_requested = false; // acks all outstanding full gc requests
+ _full_gc_cause = GCCause::_no_gc;
// Signal that we are about to start a collection
gch->increment_total_full_collections(); // ... starting a collection cycle
_collection_count_start = gch->total_full_collections();
@@ -2263,7 +2302,6 @@ void CMSCollector::collect_in_background(bool clear_all_soft_refs) {
{
ReleaseForegroundGC x(this);
stats().record_cms_begin();
-
VM_CMS_Initial_Mark initial_mark_op(this);
VMThread::execute(&initial_mark_op);
}
@@ -2343,6 +2381,7 @@ void CMSCollector::collect_in_background(bool clear_all_soft_refs) {
CMSTokenSync z(true); // not strictly needed.
if (_collectorState == Resizing) {
compute_new_size();
+ save_heap_summary();
_collectorState = Resetting;
} else {
assert(_collectorState == Idling, "The state should only change"
@@ -2401,7 +2440,39 @@ void CMSCollector::collect_in_background(bool clear_all_soft_refs) {
}
}
-void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) {
+void CMSCollector::register_foreground_gc_start(GCCause::Cause cause) {
+ if (!_cms_start_registered) {
+ register_gc_start(cause);
+ }
+}
+
+void CMSCollector::register_gc_start(GCCause::Cause cause) {
+ _cms_start_registered = true;
+ _gc_timer_cm->register_gc_start(os::elapsed_counter());
+ _gc_tracer_cm->report_gc_start(cause, _gc_timer_cm->gc_start());
+}
+
+void CMSCollector::register_gc_end() {
+ if (_cms_start_registered) {
+ report_heap_summary(GCWhen::AfterGC);
+
+ _gc_timer_cm->register_gc_end(os::elapsed_counter());
+ _gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions());
+ _cms_start_registered = false;
+ }
+}
+
+void CMSCollector::save_heap_summary() {
+ GenCollectedHeap* gch = GenCollectedHeap::heap();
+ _last_heap_summary = gch->create_heap_summary();
+ _last_metaspace_summary = gch->create_metaspace_summary();
+}
+
+void CMSCollector::report_heap_summary(GCWhen::Type when) {
+ _gc_tracer_cm->report_gc_heap_summary(when, _last_heap_summary, _last_metaspace_summary);
+}
+
+void CMSCollector::collect_in_foreground(bool clear_all_soft_refs, GCCause::Cause cause) {
assert(_foregroundGCIsActive && !_foregroundGCShouldWait,
"Foreground collector should be waiting, not executing");
assert(Thread::current()->is_VM_thread(), "A foreground collection"
@@ -2409,8 +2480,8 @@ void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) {
assert(ConcurrentMarkSweepThread::vm_thread_has_cms_token(),
"VM thread should have CMS token");
- NOT_PRODUCT(TraceTime t("CMS:MS (foreground) ", PrintGCDetails && Verbose,
- true, gclog_or_tty);)
+ NOT_PRODUCT(GCTraceTime t("CMS:MS (foreground) ", PrintGCDetails && Verbose,
+ true, NULL);)
if (UseAdaptiveSizePolicy) {
size_policy()->ms_collection_begin();
}
@@ -2434,6 +2505,7 @@ void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) {
}
switch (_collectorState) {
case InitialMarking:
+ register_foreground_gc_start(cause);
init_mark_was_synchronous = true; // fact to be exploited in re-mark
checkpointRootsInitial(false);
assert(_collectorState == Marking, "Collector state should have changed"
@@ -2482,6 +2554,7 @@ void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) {
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
Universe::verify("Verify before reset: ");
}
+ save_heap_summary();
reset(false);
assert(_collectorState == Idling, "Collector state should "
"have changed");
@@ -3504,6 +3577,9 @@ void CMSCollector::checkpointRootsInitial(bool asynch) {
check_correct_thread_executing();
TraceCMSMemoryManagerStats tms(_collectorState,GenCollectedHeap::heap()->gc_cause());
+ save_heap_summary();
+ report_heap_summary(GCWhen::BeforeGC);
+
ReferenceProcessor* rp = ref_processor();
SpecializationStats::clear();
assert(_restart_addr == NULL, "Control point invariant");
@@ -3549,8 +3625,8 @@ void CMSCollector::checkpointRootsInitialWork(bool asynch) {
// CMS collection cycle.
setup_cms_unloading_and_verification_state();
- NOT_PRODUCT(TraceTime t("\ncheckpointRootsInitialWork",
- PrintGCDetails && Verbose, true, gclog_or_tty);)
+ NOT_PRODUCT(GCTraceTime t("\ncheckpointRootsInitialWork",
+ PrintGCDetails && Verbose, true, _gc_timer_cm);)
if (UseAdaptiveSizePolicy) {
size_policy()->checkpoint_roots_initial_begin();
}
@@ -4542,8 +4618,10 @@ size_t CMSCollector::preclean_work(bool clean_refs, bool clean_survivor) {
// The code in this method may need further
// tweaking for better performance and some restructuring
// for cleaner interfaces.
+ GCTimer *gc_timer = NULL; // Currently not tracing concurrent phases
rp->preclean_discovered_references(
- rp->is_alive_non_header(), &keep_alive, &complete_trace, &yield_cl);
+ rp->is_alive_non_header(), &keep_alive, &complete_trace, &yield_cl,
+ gc_timer);
}
if (clean_survivor) { // preclean the active survivor space(s)
@@ -4885,8 +4963,8 @@ void CMSCollector::checkpointRootsFinal(bool asynch,
// Temporarily set flag to false, GCH->do_collection will
// expect it to be false and set to true
FlagSetting fl(gch->_is_gc_active, false);
- NOT_PRODUCT(TraceTime t("Scavenge-Before-Remark",
- PrintGCDetails && Verbose, true, gclog_or_tty);)
+ NOT_PRODUCT(GCTraceTime t("Scavenge-Before-Remark",
+ PrintGCDetails && Verbose, true, _gc_timer_cm);)
int level = _cmsGen->level() - 1;
if (level >= 0) {
gch->do_collection(true, // full (i.e. force, see below)
@@ -4915,7 +4993,7 @@ void CMSCollector::checkpointRootsFinal(bool asynch,
void CMSCollector::checkpointRootsFinalWork(bool asynch,
bool clear_all_soft_refs, bool init_mark_was_synchronous) {
- NOT_PRODUCT(TraceTime tr("checkpointRootsFinalWork", PrintGCDetails, false, gclog_or_tty);)
+ NOT_PRODUCT(GCTraceTime tr("checkpointRootsFinalWork", PrintGCDetails, false, _gc_timer_cm);)
assert(haveFreelistLocks(), "must have free list locks");
assert_lock_strong(bitMapLock());
@@ -4966,11 +5044,11 @@ void CMSCollector::checkpointRootsFinalWork(bool asynch,
// the most recent young generation GC, minus those cleaned up by the
// concurrent precleaning.
if (CMSParallelRemarkEnabled && CollectedHeap::use_parallel_gc_threads()) {
- TraceTime t("Rescan (parallel) ", PrintGCDetails, false, gclog_or_tty);
+ GCTraceTime t("Rescan (parallel) ", PrintGCDetails, false, _gc_timer_cm);
do_remark_parallel();
} else {
- TraceTime t("Rescan (non-parallel) ", PrintGCDetails, false,
- gclog_or_tty);
+ GCTraceTime t("Rescan (non-parallel) ", PrintGCDetails, false,
+ _gc_timer_cm);
do_remark_non_parallel();
}
}
@@ -4983,7 +5061,7 @@ void CMSCollector::checkpointRootsFinalWork(bool asynch,
verify_overflow_empty();
{
- NOT_PRODUCT(TraceTime ts("refProcessingWork", PrintGCDetails, false, gclog_or_tty);)
+ NOT_PRODUCT(GCTraceTime ts("refProcessingWork", PrintGCDetails, false, _gc_timer_cm);)
refProcessingWork(asynch, clear_all_soft_refs);
}
verify_work_stacks_empty();
@@ -5044,6 +5122,8 @@ void CMSCollector::checkpointRootsFinalWork(bool asynch,
verify_after_remark();
}
+ _gc_tracer_cm->report_object_count_after_gc(&_is_alive_closure);
+
// Change under the freelistLocks.
_collectorState = Sweeping;
// Call isAllClear() under bitMapLock
@@ -5697,7 +5777,7 @@ void CMSCollector::do_remark_non_parallel() {
NULL, // space is set further below
&_markBitMap, &_markStack, &mrias_cl);
{
- TraceTime t("grey object rescan", PrintGCDetails, false, gclog_or_tty);
+ GCTraceTime t("grey object rescan", PrintGCDetails, false, _gc_timer_cm);
// Iterate over the dirty cards, setting the corresponding bits in the
// mod union table.
{
@@ -5734,7 +5814,7 @@ void CMSCollector::do_remark_non_parallel() {
Universe::verify();
}
{
- TraceTime t("root rescan", PrintGCDetails, false, gclog_or_tty);
+ GCTraceTime t("root rescan", PrintGCDetails, false, _gc_timer_cm);
verify_work_stacks_empty();
@@ -5756,7 +5836,7 @@ void CMSCollector::do_remark_non_parallel() {
}
{
- TraceTime t("visit unhandled CLDs", PrintGCDetails, false, gclog_or_tty);
+ GCTraceTime t("visit unhandled CLDs", PrintGCDetails, false, _gc_timer_cm);
verify_work_stacks_empty();
@@ -5775,7 +5855,7 @@ void CMSCollector::do_remark_non_parallel() {
}
{
- TraceTime t("dirty klass scan", PrintGCDetails, false, gclog_or_tty);
+ GCTraceTime t("dirty klass scan", PrintGCDetails, false, _gc_timer_cm);
verify_work_stacks_empty();
@@ -5977,7 +6057,9 @@ void CMSCollector::refProcessingWork(bool asynch, bool clear_all_soft_refs) {
_span, &_markBitMap, &_markStack,
&cmsKeepAliveClosure, false /* !preclean */);
{
- TraceTime t("weak refs processing", PrintGCDetails, false, gclog_or_tty);
+ GCTraceTime t("weak refs processing", PrintGCDetails, false, _gc_timer_cm);
+
+ ReferenceProcessorStats stats;
if (rp->processing_is_mt()) {
// Set the degree of MT here. If the discovery is done MT, there
// may have been a different number of threads doing the discovery
@@ -5996,16 +6078,20 @@ void CMSCollector::refProcessingWork(bool asynch, bool clear_all_soft_refs) {
}
rp->set_active_mt_degree(active_workers);
CMSRefProcTaskExecutor task_executor(*this);
- rp->process_discovered_references(&_is_alive_closure,
+ stats = rp->process_discovered_references(&_is_alive_closure,
&cmsKeepAliveClosure,
&cmsDrainMarkingStackClosure,
- &task_executor);
+ &task_executor,
+ _gc_timer_cm);
} else {
- rp->process_discovered_references(&_is_alive_closure,
+ stats = rp->process_discovered_references(&_is_alive_closure,
&cmsKeepAliveClosure,
&cmsDrainMarkingStackClosure,
- NULL);
+ NULL,
+ _gc_timer_cm);
}
+ _gc_tracer_cm->report_gc_reference_stats(stats);
+
}
// This is the point where the entire marking should have completed.
@@ -6013,7 +6099,7 @@ void CMSCollector::refProcessingWork(bool asynch, bool clear_all_soft_refs) {
if (should_unload_classes()) {
{
- TraceTime t("class unloading", PrintGCDetails, false, gclog_or_tty);
+ GCTraceTime t("class unloading", PrintGCDetails, false, _gc_timer_cm);
// Unload classes and purge the SystemDictionary.
bool purged_class = SystemDictionary::do_unloading(&_is_alive_closure);
@@ -6026,7 +6112,7 @@ void CMSCollector::refProcessingWork(bool asynch, bool clear_all_soft_refs) {
}
{
- TraceTime t("scrub symbol table", PrintGCDetails, false, gclog_or_tty);
+ GCTraceTime t("scrub symbol table", PrintGCDetails, false, _gc_timer_cm);
// Clean up unreferenced symbols in symbol table.
SymbolTable::unlink();
}
@@ -6035,7 +6121,7 @@ void CMSCollector::refProcessingWork(bool asynch, bool clear_all_soft_refs) {
// CMS doesn't use the StringTable as hard roots when class unloading is turned off.
// Need to check if we really scanned the StringTable.
if ((roots_scanning_options() & SharedHeap::SO_Strings) == 0) {
- TraceTime t("scrub string table", PrintGCDetails, false, gclog_or_tty);
+ GCTraceTime t("scrub string table", PrintGCDetails, false, _gc_timer_cm);
// Delete entries for dead interned strings.
StringTable::unlink(&_is_alive_closure);
}
@@ -6380,12 +6466,14 @@ void CMSCollector::reset(bool asynch) {
_cmsGen->rotate_debug_collection_type();
}
)
+
+ register_gc_end();
}
void CMSCollector::do_CMS_operation(CMS_op_type op, GCCause::Cause gc_cause) {
gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps);
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
- TraceTime t(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, gclog_or_tty);
+ GCTraceTime t(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL);
TraceCollectorStats tcs(counters());
switch (op) {
diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp
index 8d627c757..bb485f4a8 100644
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp
@@ -25,8 +25,10 @@
#ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_CONCURRENTMARKSWEEPGENERATION_HPP
#define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_CONCURRENTMARKSWEEPGENERATION_HPP
+#include "gc_implementation/shared/gcHeapSummary.hpp"
#include "gc_implementation/shared/gSpaceCounters.hpp"
#include "gc_implementation/shared/gcStats.hpp"
+#include "gc_implementation/shared/gcWhen.hpp"
#include "gc_implementation/shared/generationCounters.hpp"
#include "memory/freeBlockDictionary.hpp"
#include "memory/generation.hpp"
@@ -53,6 +55,8 @@
class CMSAdaptiveSizePolicy;
class CMSConcMarkingTask;
class CMSGCAdaptivePolicyCounters;
+class CMSTracer;
+class ConcurrentGCTimer;
class ConcurrentMarkSweepGeneration;
class ConcurrentMarkSweepPolicy;
class ConcurrentMarkSweepThread;
@@ -61,6 +65,7 @@ class FreeChunk;
class PromotionInfo;
class ScanMarkedObjectsAgainCarefullyClosure;
class TenuredGeneration;
+class SerialOldTracer;
// A generic CMS bit map. It's the basis for both the CMS marking bit map
// as well as for the mod union table (in each case only a subset of the
@@ -567,8 +572,9 @@ class CMSCollector: public CHeapObj<mtGC> {
bool _completed_initialization;
// In support of ExplicitGCInvokesConcurrent
- static bool _full_gc_requested;
- unsigned int _collection_count_start;
+ static bool _full_gc_requested;
+ static GCCause::Cause _full_gc_cause;
+ unsigned int _collection_count_start;
// Should we unload classes this concurrent cycle?
bool _should_unload_classes;
@@ -609,6 +615,20 @@ class CMSCollector: public CHeapObj<mtGC> {
AdaptivePaddedAverage _inter_sweep_estimate;
AdaptivePaddedAverage _intra_sweep_estimate;
+ CMSTracer* _gc_tracer_cm;
+ ConcurrentGCTimer* _gc_timer_cm;
+
+ bool _cms_start_registered;
+
+ GCHeapSummary _last_heap_summary;
+ MetaspaceSummary _last_metaspace_summary;
+
+ void register_foreground_gc_start(GCCause::Cause cause);
+ void register_gc_start(GCCause::Cause cause);
+ void register_gc_end();
+ void save_heap_summary();
+ void report_heap_summary(GCWhen::Type when);
+
protected:
ConcurrentMarkSweepGeneration* _cmsGen; // old gen (CMS)
MemRegion _span; // span covering above two
@@ -827,6 +847,10 @@ class CMSCollector: public CHeapObj<mtGC> {
void do_mark_sweep_work(bool clear_all_soft_refs,
CollectorState first_state, bool should_start_over);
+ // Work methods for reporting concurrent mode interruption or failure
+ bool is_external_interruption();
+ void report_concurrent_mode_interruption();
+
// If the backgrould GC is active, acquire control from the background
// GC and do the collection.
void acquire_control_and_collect(bool full, bool clear_all_soft_refs);
@@ -876,11 +900,11 @@ class CMSCollector: public CHeapObj<mtGC> {
bool clear_all_soft_refs,
size_t size,
bool tlab);
- void collect_in_background(bool clear_all_soft_refs);
- void collect_in_foreground(bool clear_all_soft_refs);
+ void collect_in_background(bool clear_all_soft_refs, GCCause::Cause cause);
+ void collect_in_foreground(bool clear_all_soft_refs, GCCause::Cause cause);
// In support of ExplicitGCInvokesConcurrent
- static void request_full_gc(unsigned int full_gc_count);
+ static void request_full_gc(unsigned int full_gc_count, GCCause::Cause cause);
// Should we unload classes in a particular concurrent cycle?
bool should_unload_classes() const {
return _should_unload_classes;
diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp
index 7bc1c1ea9..f8b0ccb90 100644
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp
@@ -140,7 +140,9 @@ void ConcurrentMarkSweepThread::run() {
while (!_should_terminate) {
sleepBeforeNextCycle();
if (_should_terminate) break;
- _collector->collect_in_background(false); // !clear_all_soft_refs
+ GCCause::Cause cause = _collector->_full_gc_requested ?
+ _collector->_full_gc_cause : GCCause::_cms_concurrent_mark;
+ _collector->collect_in_background(false, cause);
}
assert(_should_terminate, "just checking");
// Check that the state of any protocol for synchronization
diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp
index eacd2a9f6..3e24c2419 100644
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,9 +26,12 @@
#include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp"
#include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp"
#include "gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
#include "gc_implementation/shared/isGCActiveMark.hpp"
#include "memory/gcLocker.inline.hpp"
#include "runtime/interfaceSupport.hpp"
+#include "runtime/os.hpp"
#include "utilities/dtrace.hpp"
@@ -60,6 +63,7 @@ void VM_CMS_Operation::release_and_notify_pending_list_lock() {
void VM_CMS_Operation::verify_before_gc() {
if (VerifyBeforeGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
+ GCTraceTime tm("Verify Before", false, false, _collector->_gc_timer_cm);
HandleMark hm;
FreelistLocker x(_collector);
MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag);
@@ -71,6 +75,7 @@ void VM_CMS_Operation::verify_before_gc() {
void VM_CMS_Operation::verify_after_gc() {
if (VerifyAfterGC &&
GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) {
+ GCTraceTime tm("Verify After", false, false, _collector->_gc_timer_cm);
HandleMark hm;
FreelistLocker x(_collector);
MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag);
@@ -140,6 +145,8 @@ void VM_CMS_Initial_Mark::doit() {
);
#endif /* USDT2 */
+ _collector->_gc_timer_cm->register_gc_pause_start("Initial Mark", os::elapsed_counter());
+
GenCollectedHeap* gch = GenCollectedHeap::heap();
GCCauseSetter gccs(gch, GCCause::_cms_initial_mark);
@@ -149,6 +156,9 @@ void VM_CMS_Initial_Mark::doit() {
_collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsInitial, gch->gc_cause());
VM_CMS_Operation::verify_after_gc();
+
+ _collector->_gc_timer_cm->register_gc_pause_end(os::elapsed_counter());
+
#ifndef USDT2
HS_DTRACE_PROBE(hs_private, cms__initmark__end);
#else /* USDT2 */
@@ -172,6 +182,8 @@ void VM_CMS_Final_Remark::doit() {
);
#endif /* USDT2 */
+ _collector->_gc_timer_cm->register_gc_pause_start("Final Mark", os::elapsed_counter());
+
GenCollectedHeap* gch = GenCollectedHeap::heap();
GCCauseSetter gccs(gch, GCCause::_cms_final_remark);
@@ -181,6 +193,10 @@ void VM_CMS_Final_Remark::doit() {
_collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsFinal, gch->gc_cause());
VM_CMS_Operation::verify_after_gc();
+
+ _collector->save_heap_summary();
+ _collector->_gc_timer_cm->register_gc_pause_end(os::elapsed_counter());
+
#ifndef USDT2
HS_DTRACE_PROBE(hs_private, cms__remark__end);
#else /* USDT2 */
@@ -225,7 +241,7 @@ void VM_GenCollectFullConcurrent::doit() {
// In case CMS thread was in icms_wait(), wake it up.
CMSCollector::start_icms();
// Nudge the CMS thread to start a concurrent collection.
- CMSCollector::request_full_gc(_full_gc_count_before);
+ CMSCollector::request_full_gc(_full_gc_count_before, _gc_cause);
} else {
assert(_full_gc_count_before < gch->total_full_collections(), "Error");
FullGCCount_lock->notify_all(); // Inform the Java thread its work is done
diff --git a/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/src/share/vm/gc_implementation/g1/concurrentMark.cpp
index 137f76c09..13a34a451 100644
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp
@@ -36,6 +36,9 @@
#include "gc_implementation/g1/heapRegionRemSet.hpp"
#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
#include "memory/genOopClosures.inline.hpp"
#include "memory/referencePolicy.hpp"
#include "memory/resourceArea.hpp"
@@ -1342,6 +1345,9 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) {
_remark_times.add((now - start) * 1000.0);
g1p->record_concurrent_mark_remark_end();
+
+ G1CMIsAliveClosure is_alive(g1h);
+ g1h->gc_tracer_cm()->report_object_count_after_gc(&is_alive);
}
// Base class of the closures that finalize and verify the
@@ -2129,6 +2135,7 @@ void ConcurrentMark::cleanup() {
}
g1h->verify_region_sets_optional();
+ g1h->trace_heap_after_concurrent_cycle();
}
void ConcurrentMark::completeCleanup() {
@@ -2439,7 +2446,7 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
if (G1Log::finer()) {
gclog_or_tty->put(' ');
}
- TraceTime t("GC ref-proc", G1Log::finer(), false, gclog_or_tty);
+ GCTraceTime t("GC ref-proc", G1Log::finer(), false, g1h->gc_timer_cm());
ReferenceProcessor* rp = g1h->ref_processor_cm();
@@ -2491,10 +2498,13 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
rp->set_active_mt_degree(active_workers);
// Process the weak references.
- rp->process_discovered_references(&g1_is_alive,
- &g1_keep_alive,
- &g1_drain_mark_stack,
- executor);
+ const ReferenceProcessorStats& stats =
+ rp->process_discovered_references(&g1_is_alive,
+ &g1_keep_alive,
+ &g1_drain_mark_stack,
+ executor,
+ g1h->gc_timer_cm());
+ g1h->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
@@ -3227,6 +3237,9 @@ void ConcurrentMark::abort() {
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,
diff --git a/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/src/share/vm/gc_implementation/g1/concurrentMark.hpp
index 0e576488d..794224b66 100644
--- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp
@@ -569,8 +569,6 @@ protected:
void clear_has_overflown() { _has_overflown = false; }
bool restart_for_overflow() { return _restart_for_overflow; }
- bool has_aborted() { return _has_aborted; }
-
// Methods to enter the two overflow sync barriers
void enter_first_sync_barrier(uint worker_id);
void enter_second_sync_barrier(uint worker_id);
@@ -821,6 +819,8 @@ public:
// Called to abort the marking cycle after a Full GC takes palce.
void abort();
+ bool has_aborted() { return _has_aborted; }
+
// This prints the global/local fingers. It is used for debugging.
NOT_PRODUCT(void print_finger();)
diff --git a/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp b/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp
index a961fda8f..ee53c3ba6 100644
--- a/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp
+++ b/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp
@@ -93,7 +93,6 @@ void ConcurrentMarkThread::run() {
ResourceMark rm;
HandleMark hm;
double cycle_start = os::elapsedVTime();
- char verbose_str[128];
// We have to ensure that we finish scanning the root regions
// before the next GC takes place. To ensure this we have to
@@ -155,8 +154,7 @@ void ConcurrentMarkThread::run() {
}
CMCheckpointRootsFinalClosure final_cl(_cm);
- sprintf(verbose_str, "GC remark");
- VM_CGC_Operation op(&final_cl, verbose_str, true /* needs_pll */);
+ VM_CGC_Operation op(&final_cl, "GC remark", true /* needs_pll */);
VMThread::execute(&op);
}
if (cm()->restart_for_overflow()) {
@@ -187,8 +185,7 @@ void ConcurrentMarkThread::run() {
}
CMCleanUp cl_cl(_cm);
- sprintf(verbose_str, "GC cleanup");
- VM_CGC_Operation op(&cl_cl, verbose_str, false /* needs_pll */);
+ VM_CGC_Operation op(&cl_cl, "GC cleanup", false /* needs_pll */);
VMThread::execute(&op);
} else {
// We don't want to update the marking status if a GC pause
@@ -292,6 +289,7 @@ void ConcurrentMarkThread::run() {
// called System.gc() with +ExplicitGCInvokesConcurrent).
_sts.join();
g1h->increment_old_marking_cycles_completed(true /* concurrent */);
+ g1h->register_concurrent_cycle_end();
_sts.leave();
}
assert(_should_terminate, "just checking");
diff --git a/src/share/vm/gc_implementation/g1/evacuationInfo.hpp b/src/share/vm/gc_implementation/g1/evacuationInfo.hpp
new file mode 100644
index 000000000..97e0ab2f7
--- /dev/null
+++ b/src/share/vm/gc_implementation/g1/evacuationInfo.hpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013, 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_IMPLEMENTATION_SHARED_EVACUATIONINFO_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_SHARED_EVACUATIONINFO_HPP
+
+#include "memory/allocation.hpp"
+
+class EvacuationInfo : public StackObj {
+ uint _collectionset_regions;
+ uint _allocation_regions;
+ size_t _collectionset_used_before;
+ size_t _collectionset_used_after;
+ size_t _alloc_regions_used_before;
+ size_t _bytes_copied;
+ uint _regions_freed;
+
+public:
+ EvacuationInfo() : _collectionset_regions(0), _allocation_regions(0), _collectionset_used_before(0),
+ _collectionset_used_after(0), _alloc_regions_used_before(0),
+ _bytes_copied(0), _regions_freed(0) { }
+
+ void set_collectionset_regions(uint collectionset_regions) {
+ _collectionset_regions = collectionset_regions;
+ }
+
+ void set_allocation_regions(uint allocation_regions) {
+ _allocation_regions = allocation_regions;
+ }
+
+ void set_collectionset_used_before(size_t used) {
+ _collectionset_used_before = used;
+ }
+
+ void increment_collectionset_used_after(size_t used) {
+ _collectionset_used_after += used;
+ }
+
+ void set_alloc_regions_used_before(size_t used) {
+ _alloc_regions_used_before = used;
+ }
+
+ void set_bytes_copied(size_t copied) {
+ _bytes_copied = copied;
+ }
+
+ void set_regions_freed(uint freed) {
+ _regions_freed += freed;
+ }
+
+ uint collectionset_regions() { return _collectionset_regions; }
+ uint allocation_regions() { return _allocation_regions; }
+ size_t collectionset_used_before() { return _collectionset_used_before; }
+ size_t collectionset_used_after() { return _collectionset_used_after; }
+ size_t alloc_regions_used_before() { return _alloc_regions_used_before; }
+ size_t bytes_copied() { return _bytes_copied; }
+ uint regions_freed() { return _regions_freed; }
+};
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_EVACUATIONINFO_HPP
diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
index 0505822e8..db8f863ad 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
@@ -38,10 +38,15 @@
#include "gc_implementation/g1/g1MarkSweep.hpp"
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
#include "gc_implementation/g1/g1RemSet.inline.hpp"
+#include "gc_implementation/g1/g1YCTypes.hpp"
#include "gc_implementation/g1/heapRegion.inline.hpp"
#include "gc_implementation/g1/heapRegionRemSet.hpp"
#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
#include "gc_implementation/g1/vm_operations_g1.hpp"
+#include "gc_implementation/shared/gcHeapSummary.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
#include "gc_implementation/shared/isGCActiveMark.hpp"
#include "memory/gcLocker.inline.hpp"
#include "memory/genOopClosures.inline.hpp"
@@ -76,7 +81,7 @@ size_t G1CollectedHeap::_humongous_object_threshold_in_words = 0;
// The number of GC workers is passed to heap_region_par_iterate_chunked().
// It does use run_task() which sets _n_workers in the task.
// G1ParTask executes g1_process_strong_roots() ->
-// SharedHeap::process_strong_roots() which calls eventuall to
+// SharedHeap::process_strong_roots() which calls eventually to
// CardTableModRefBS::par_non_clean_card_iterate_work() which uses
// SequentialSubTasksDone. SharedHeap::process_strong_roots() also
// directly uses SubTasksDone (_process_strong_tasks field in SharedHeap).
@@ -457,7 +462,7 @@ bool G1CollectedHeap::is_in_partial_collection(const void* p) {
#endif
// Returns true if the reference points to an object that
-// can move in an incremental collecction.
+// can move in an incremental collection.
bool G1CollectedHeap::is_scavengable(const void* p) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
G1CollectorPolicy* g1p = g1h->g1_policy();
@@ -548,7 +553,7 @@ G1CollectedHeap::new_region_try_secondary_free_list() {
return res;
}
- // Wait here until we get notifed either when (a) there are no
+ // Wait here until we get notified either when (a) there are no
// more free regions coming or (b) some regions have been moved on
// the secondary_free_list.
SecondaryFreeList_lock->wait(Mutex::_no_safepoint_check_flag);
@@ -623,7 +628,7 @@ uint G1CollectedHeap::humongous_obj_allocate_find_first(uint num_regions,
uint first = G1_NULL_HRS_INDEX;
if (num_regions == 1) {
// Only one region to allocate, no need to go through the slower
- // path. The caller will attempt the expasion if this fails, so
+ // path. The caller will attempt the expansion if this fails, so
// let's not try to expand here too.
HeapRegion* hr = new_region(word_size, false /* do_expand */);
if (hr != NULL) {
@@ -688,7 +693,7 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first,
// the first region.
HeapWord* new_obj = first_hr->bottom();
// This will be the new end of the first region in the series that
- // should also match the end of the last region in the seriers.
+ // should also match the end of the last region in the series.
HeapWord* new_end = new_obj + word_size_sum;
// This will be the new top of the first region that will reflect
// this allocation.
@@ -863,7 +868,7 @@ G1CollectedHeap::mem_allocate(size_t word_size,
bool* gc_overhead_limit_was_exceeded) {
assert_heap_not_locked_and_not_at_safepoint();
- // Loop until the allocation is satisified, or unsatisfied after GC.
+ // Loop until the allocation is satisfied, or unsatisfied after GC.
for (int try_count = 1, gclocker_retry_count = 0; /* we'll return */; try_count += 1) {
unsigned int gc_count_before;
@@ -1003,7 +1008,7 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size,
(*gclocker_retry_count_ret) += 1;
}
- // We can reach here if we were unsuccessul in scheduling a
+ // We can reach here if we were unsuccessful in scheduling a
// collection (because another thread beat us to it) or if we were
// stalled due to the GC locker. In either can we should retry the
// allocation attempt in case another thread successfully
@@ -1128,7 +1133,7 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size,
(*gclocker_retry_count_ret) += 1;
}
- // We can reach here if we were unsuccessul in scheduling a
+ // We can reach here if we were unsuccessful in scheduling a
// collection (because another thread beat us to it) or if we were
// stalled due to the GC locker. In either can we should retry the
// allocation attempt in case another thread successfully
@@ -1298,10 +1303,17 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
return false;
}
+ STWGCTimer* gc_timer = G1MarkSweep::gc_timer();
+ gc_timer->register_gc_start(os::elapsed_counter());
+
+ SerialOldTracer* gc_tracer = G1MarkSweep::gc_tracer();
+ gc_tracer->report_gc_start(gc_cause(), gc_timer->gc_start());
+
SvcGCMarker sgcm(SvcGCMarker::FULL);
ResourceMark rm;
print_heap_before_gc();
+ trace_heap_before_gc(gc_tracer);
size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes();
@@ -1322,7 +1334,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty);
{
- TraceTime t(GCCauseString("Full GC", gc_cause()), G1Log::fine(), true, gclog_or_tty);
+ GCTraceTime t(GCCauseString("Full GC", gc_cause()), G1Log::fine(), true, NULL);
TraceCollectorStats tcs(g1mm()->full_collection_counters());
TraceMemoryManagerStats tms(true /* fullGC */, gc_cause());
@@ -1351,7 +1363,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
verify_before_gc();
- pre_full_gc_dump();
+ pre_full_gc_dump(gc_timer);
COMPILER2_PRESENT(DerivedPointerTable::clear());
@@ -1433,7 +1445,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
reset_gc_time_stamp();
// Since everything potentially moved, we will clear all remembered
- // sets, and clear all cards. Later we will rebuild remebered
+ // sets, and clear all cards. Later we will rebuild remembered
// sets. We will also reset the GC time stamps of the regions.
clear_rsets_post_compaction();
check_gc_time_stamps();
@@ -1553,8 +1565,12 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
}
print_heap_after_gc();
+ trace_heap_after_gc(gc_tracer);
+
+ post_full_gc_dump(gc_timer);
- post_full_gc_dump();
+ gc_timer->register_gc_end(os::elapsed_counter());
+ gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions());
}
return true;
@@ -1919,7 +1935,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) :
_ref_processor_stw(NULL),
_process_strong_tasks(new SubTasksDone(G1H_PS_NumElements)),
_bot_shared(NULL),
- _evac_failure_scan_stack(NULL) ,
+ _evac_failure_scan_stack(NULL),
_mark_in_progress(false),
_cg1r(NULL), _summary_bytes_used(0),
_g1mm(NULL),
@@ -1939,12 +1955,18 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) :
_surviving_young_words(NULL),
_old_marking_cycles_started(0),
_old_marking_cycles_completed(0),
+ _concurrent_cycle_started(false),
_in_cset_fast_test(NULL),
_in_cset_fast_test_base(NULL),
_dirty_cards_region_list(NULL),
_worker_cset_start_region(NULL),
- _worker_cset_start_region_time_stamp(NULL) {
- _g1h = this; // To catch bugs.
+ _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()) {
+
+ _g1h = this;
if (_process_strong_tasks == NULL || !_process_strong_tasks->valid()) {
vm_exit_during_initialization("Failed necessary allocation.");
}
@@ -1959,13 +1981,14 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) :
_worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues, mtGC);
_worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(unsigned int, n_queues, mtGC);
+ _evacuation_failed_info_array = NEW_C_HEAP_ARRAY(EvacuationFailedInfo, n_queues, mtGC);
for (int i = 0; i < n_queues; i++) {
RefToScanQueue* q = new RefToScanQueue();
q->initialize();
_task_queues->register_queue(i, q);
+ ::new (&_evacuation_failed_info_array[i]) EvacuationFailedInfo();
}
-
clear_cset_start_regions();
// Initialize the G1EvacuationFailureALot counters and flags.
@@ -2025,7 +2048,7 @@ jint G1CollectedHeap::initialize() {
HeapRegion::GrainBytes);
// It is important to do this in a way such that concurrent readers can't
- // temporarily think somethings in the heap. (I've actually seen this
+ // temporarily think something is in the heap. (I've actually seen this
// happen in asserts: DLD.)
_reserved.set_word_size(0);
_reserved.set_start((HeapWord*)heap_rs.base());
@@ -2462,7 +2485,7 @@ void G1CollectedHeap::increment_old_marking_cycles_completed(bool concurrent) {
// We need to clear the "in_progress" flag in the CM thread before
// we wake up any waiters (especially when ExplicitInvokesConcurrent
// is set) so that if a waiter requests another System.gc() it doesn't
- // incorrectly see that a marking cyle is still in progress.
+ // incorrectly see that a marking cycle is still in progress.
if (concurrent) {
_cmThread->clear_in_progress();
}
@@ -2474,6 +2497,49 @@ void G1CollectedHeap::increment_old_marking_cycles_completed(bool concurrent) {
FullGCCount_lock->notify_all();
}
+void G1CollectedHeap::register_concurrent_cycle_start(jlong start_time) {
+ _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);
+}
+
+void G1CollectedHeap::register_concurrent_cycle_end() {
+ if (_concurrent_cycle_started) {
+ _gc_timer_cm->register_gc_end(os::elapsed_counter());
+
+ if (_cm->has_aborted()) {
+ _gc_tracer_cm->report_concurrent_mode_failure();
+ }
+ _gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions());
+
+ _concurrent_cycle_started = false;
+ }
+}
+
+void G1CollectedHeap::trace_heap_after_concurrent_cycle() {
+ if (_concurrent_cycle_started) {
+ trace_heap_after_gc(_gc_tracer_cm);
+ }
+}
+
+G1YCType G1CollectedHeap::yc_type() {
+ bool is_young = g1_policy()->gcs_are_young();
+ bool is_initial_mark = g1_policy()->during_initial_mark_pause();
+ bool is_during_mark = mark_in_progress();
+
+ if (is_initial_mark) {
+ return InitialMark;
+ } else if (is_during_mark) {
+ return DuringMark;
+ } else if (is_young) {
+ return Normal;
+ } else {
+ return Mixed;
+ }
+}
+
void G1CollectedHeap::collect(GCCause::Cause cause) {
assert_heap_not_locked();
@@ -2676,13 +2742,13 @@ G1CollectedHeap::heap_region_par_iterate_chunked(HeapRegionClosure* cl,
break;
}
- // Noone should have claimed it directly. We can given
+ // No one should have claimed it directly. We can given
// that we claimed its "starts humongous" region.
assert(chr->claim_value() != claim_value, "sanity");
assert(chr->humongous_start_region() == r, "sanity");
if (chr->claimHeapRegion(claim_value)) {
- // we should always be able to claim it; noone else should
+ // we should always be able to claim it; no one else should
// be trying to claim this region
bool res2 = cl->doHeapRegion(chr);
@@ -2976,7 +3042,7 @@ size_t G1CollectedHeap::unsafe_max_tlab_alloc(Thread* ignored) const {
// the min TLAB size.
// Also, this value can be at most the humongous object threshold,
- // since we can't allow tlabs to grow big enough to accomodate
+ // since we can't allow tlabs to grow big enough to accommodate
// humongous objects.
HeapRegion* hr = _mutator_alloc_region.get();
@@ -3743,10 +3809,15 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
return false;
}
+ _gc_timer_stw->register_gc_start(os::elapsed_counter());
+
+ _gc_tracer_stw->report_gc_start(gc_cause(), _gc_timer_stw->gc_start());
+
SvcGCMarker sgcm(SvcGCMarker::MINOR);
ResourceMark rm;
print_heap_before_gc();
+ trace_heap_before_gc(_gc_tracer_stw);
HRSPhaseSetter x(HRSPhaseEvacuation);
verify_region_sets_optional();
@@ -3771,11 +3842,17 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
// Inner scope for scope based logging, timers, and stats collection
{
+ EvacuationInfo evacuation_info;
+
if (g1_policy()->during_initial_mark_pause()) {
// 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());
}
+
+ _gc_tracer_stw->report_yc_type(yc_type());
+
TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty);
int active_workers = (G1CollectedHeap::use_parallel_gc_threads() ?
@@ -3885,7 +3962,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
g1_policy()->print_collection_set(g1_policy()->inc_cset_head(), gclog_or_tty);
#endif // YOUNG_LIST_VERBOSE
- g1_policy()->finalize_cset(target_pause_time_ms);
+ g1_policy()->finalize_cset(target_pause_time_ms, evacuation_info);
_cm->note_start_of_gc();
// We should not verify the per-thread SATB buffers given that
@@ -3921,10 +3998,10 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
setup_surviving_young_words();
// Initialize the GC alloc regions.
- init_gc_alloc_regions();
+ init_gc_alloc_regions(evacuation_info);
// Actually do the work...
- evacuate_collection_set();
+ evacuate_collection_set(evacuation_info);
// We do this to mainly verify the per-thread SATB buffers
// (which have been filtered by now) since we didn't verify
@@ -3936,7 +4013,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
true /* verify_thread_buffers */,
true /* verify_fingers */);
- free_collection_set(g1_policy()->collection_set());
+ free_collection_set(g1_policy()->collection_set(), evacuation_info);
g1_policy()->clear_collection_set();
cleanup_surviving_young_words();
@@ -3964,13 +4041,19 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
#endif // YOUNG_LIST_VERBOSE
g1_policy()->record_survivor_regions(_young_list->survivor_length(),
- _young_list->first_survivor_region(),
- _young_list->last_survivor_region());
+ _young_list->first_survivor_region(),
+ _young_list->last_survivor_region());
_young_list->reset_auxilary_lists();
if (evacuation_failed()) {
_summary_bytes_used = recalculate_used();
+ uint n_queues = MAX2((int)ParallelGCThreads, 1);
+ for (uint i = 0; i < n_queues; i++) {
+ if (_evacuation_failed_info_array[i].has_failed()) {
+ _gc_tracer_stw->report_evacuation_failed(_evacuation_failed_info_array[i]);
+ }
+ }
} else {
// The "used" of the the collection set have already been subtracted
// when they were freed. Add in the bytes evacuated.
@@ -4013,7 +4096,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
}
}
- // We redo the verificaiton but now wrt to the new CSet which
+ // We redo the verification but now wrt to the new CSet which
// has just got initialized after the previous CSet was freed.
_cm->verify_no_cset_oops(true /* verify_stacks */,
true /* verify_enqueued_buffers */,
@@ -4026,7 +4109,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
// investigate this in CR 7178365.
double sample_end_time_sec = os::elapsedTime();
double pause_time_ms = (sample_end_time_sec - sample_start_time_sec) * MILLIUNITS;
- g1_policy()->record_collection_pause_end(pause_time_ms);
+ g1_policy()->record_collection_pause_end(pause_time_ms, evacuation_info);
MemoryService::track_memory_usage();
@@ -4093,14 +4176,19 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
TASKQUEUE_STATS_ONLY(reset_taskqueue_stats());
print_heap_after_gc();
+ trace_heap_after_gc(_gc_tracer_stw);
// We must call G1MonitoringSupport::update_sizes() in the same scoping level
// as an active TraceMemoryManagerStats object (i.e. before the destructor for the
// TraceMemoryManagerStats is called) so that the G1 memory pools are updated
// before any GC notifications are raised.
g1mm()->update_sizes();
- }
+ _gc_tracer_stw->report_evacuation_info(&evacuation_info);
+ _gc_tracer_stw->report_tenuring_threshold(_g1_policy->tenuring_threshold());
+ _gc_timer_stw->register_gc_end(os::elapsed_counter());
+ _gc_tracer_stw->report_gc_end(_gc_timer_stw->gc_end(), _gc_timer_stw->time_partitions());
+ }
// It should now be safe to tell the concurrent mark thread to start
// without its logging output interfering with the logging output
// that came from the pause.
@@ -4152,7 +4240,7 @@ void G1CollectedHeap::release_mutator_alloc_region() {
assert(_mutator_alloc_region.get() == NULL, "post-condition");
}
-void G1CollectedHeap::init_gc_alloc_regions() {
+void G1CollectedHeap::init_gc_alloc_regions(EvacuationInfo& evacuation_info) {
assert_at_safepoint(true /* should_be_vm_thread */);
_survivor_gc_alloc_region.init();
@@ -4167,7 +4255,7 @@ void G1CollectedHeap::init_gc_alloc_regions() {
// a cleanup and it should be on the free list now), or
// d) it's humongous (this means that it was emptied
// during a cleanup and was added to the free list, but
- // has been subseqently used to allocate a humongous
+ // has been subsequently used to allocate a humongous
// object that may be less than the region size).
if (retained_region != NULL &&
!retained_region->in_collection_set() &&
@@ -4184,10 +4272,13 @@ void G1CollectedHeap::init_gc_alloc_regions() {
retained_region->note_start_of_copying(during_im);
_old_gc_alloc_region.set(retained_region);
_hr_printer.reuse(retained_region);
+ evacuation_info.set_alloc_regions_used_before(retained_region->used());
}
}
-void G1CollectedHeap::release_gc_alloc_regions(uint no_of_gc_workers) {
+void G1CollectedHeap::release_gc_alloc_regions(uint no_of_gc_workers, EvacuationInfo& evacuation_info) {
+ evacuation_info.set_allocation_regions(_survivor_gc_alloc_region.count() +
+ _old_gc_alloc_region.count());
_survivor_gc_alloc_region.release();
// If we have an old GC alloc region to release, we'll save it in
// _retained_old_gc_alloc_region. If we don't
@@ -4270,7 +4361,7 @@ void G1CollectedHeap::drain_evac_failure_scan_stack() {
}
oop
-G1CollectedHeap::handle_evacuation_failure_par(OopsInHeapRegionClosure* cl,
+G1CollectedHeap::handle_evacuation_failure_par(G1ParScanThreadState* _par_scan_state,
oop old) {
assert(obj_in_cs(old),
err_msg("obj: "PTR_FORMAT" should still be in the CSet",
@@ -4279,7 +4370,12 @@ G1CollectedHeap::handle_evacuation_failure_par(OopsInHeapRegionClosure* cl,
oop forward_ptr = old->forward_to_atomic(old);
if (forward_ptr == NULL) {
// Forward-to-self succeeded.
+ assert(_par_scan_state != NULL, "par scan state");
+ OopsInHeapRegionClosure* cl = _par_scan_state->evac_failure_closure();
+ uint queue_num = _par_scan_state->queue_num();
+ _evacuation_failed = true;
+ _evacuation_failed_info_array[queue_num].register_copy_failure(old->size());
if (_evac_failure_closure != cl) {
MutexLockerEx x(EvacFailureStack_lock, Mutex::_no_safepoint_check_flag);
assert(!_drain_in_progress,
@@ -4310,8 +4406,6 @@ G1CollectedHeap::handle_evacuation_failure_par(OopsInHeapRegionClosure* cl,
}
void G1CollectedHeap::handle_evacuation_failure_common(oop old, markOop m) {
- set_evacuation_failed(true);
-
preserve_mark_if_necessary(old, m);
HeapRegion* r = heap_region_containing(old);
@@ -4561,8 +4655,7 @@ oop G1ParCopyClosure<do_gen_barrier, barrier, do_mark_object>
if (obj_ptr == NULL) {
// This will either forward-to-self, or detect that someone else has
// installed a forwarding pointer.
- OopsInHeapRegionClosure* cl = _par_scan_state->evac_failure_closure();
- return _g1->handle_evacuation_failure_par(cl, old);
+ return _g1->handle_evacuation_failure_par(_par_scan_state, old);
}
oop obj = oop(obj_ptr);
@@ -5166,7 +5259,7 @@ public:
// will be copied, the reference field set to point to the
// new location, and the RSet updated. Otherwise we need to
// use the the non-heap or metadata closures directly to copy
- // the refernt object and update the pointer, while avoiding
+ // the referent object and update the pointer, while avoiding
// updating the RSet.
if (_g1h->is_in_g1_reserved(p)) {
@@ -5334,7 +5427,7 @@ public:
}
};
-// Driver routine for parallel reference enqueing.
+// Driver routine for parallel reference enqueueing.
// Creates an instance of the ref enqueueing gang
// task and has the worker threads execute it.
@@ -5463,7 +5556,7 @@ void G1CollectedHeap::process_discovered_references(uint no_of_gc_workers) {
// processor would have seen that the reference object had already
// been 'discovered' and would have skipped discovering the reference,
// but would not have treated the reference object as a regular oop.
- // As a reult the copy closure would not have been applied to the
+ // As a result the copy closure would not have been applied to the
// referent object.
//
// We need to explicitly copy these referent objects - the references
@@ -5539,21 +5632,28 @@ void G1CollectedHeap::process_discovered_references(uint no_of_gc_workers) {
// Setup the soft refs policy...
rp->setup_policy(false);
+ ReferenceProcessorStats stats;
if (!rp->processing_is_mt()) {
// Serial reference processing...
- rp->process_discovered_references(&is_alive,
- &keep_alive,
- &drain_queue,
- NULL);
+ stats = rp->process_discovered_references(&is_alive,
+ &keep_alive,
+ &drain_queue,
+ NULL,
+ _gc_timer_stw);
} else {
// Parallel reference processing
assert(rp->num_q() == no_of_gc_workers, "sanity");
assert(no_of_gc_workers <= rp->max_num_q(), "sanity");
G1STWRefProcTaskExecutor par_task_executor(this, workers(), _task_queues, no_of_gc_workers);
- rp->process_discovered_references(&is_alive, &keep_alive, &drain_queue, &par_task_executor);
+ stats = rp->process_discovered_references(&is_alive,
+ &keep_alive,
+ &drain_queue,
+ &par_task_executor,
+ _gc_timer_stw);
}
+ _gc_tracer_stw->report_gc_reference_stats(stats);
// We have completed copying any necessary live referent objects
// (that were not copied during the actual pause) so we can
// retire any active alloc buffers
@@ -5577,7 +5677,7 @@ void G1CollectedHeap::enqueue_discovered_references(uint no_of_gc_workers) {
// Serial reference processing...
rp->enqueue_discovered_references();
} else {
- // Parallel reference enqueuing
+ // Parallel reference enqueueing
assert(no_of_gc_workers == workers()->active_workers(),
"Need to reset active workers");
@@ -5594,15 +5694,15 @@ void G1CollectedHeap::enqueue_discovered_references(uint no_of_gc_workers) {
// FIXME
// CM's reference processing also cleans up the string and symbol tables.
// Should we do that here also? We could, but it is a serial operation
- // and could signicantly increase the pause time.
+ // and could significantly increase the pause time.
double ref_enq_time = os::elapsedTime() - ref_enq_start;
g1_policy()->phase_times()->record_ref_enq_time(ref_enq_time * 1000.0);
}
-void G1CollectedHeap::evacuate_collection_set() {
+void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
_expand_heap_after_alloc_failure = true;
- set_evacuation_failed(false);
+ _evacuation_failed = false;
// Should G1EvacuationFailureALot be in effect for this GC?
NOT_PRODUCT(set_evacuation_failure_alot_for_current_gc();)
@@ -5691,7 +5791,7 @@ void G1CollectedHeap::evacuate_collection_set() {
JNIHandles::weak_oops_do(&is_alive, &keep_alive);
}
- release_gc_alloc_regions(n_workers);
+ release_gc_alloc_regions(n_workers, evacuation_info);
g1_rem_set()->cleanup_after_oops_into_collection_set_do();
// Reset and re-enable the hot card cache.
@@ -5714,7 +5814,7 @@ void G1CollectedHeap::evacuate_collection_set() {
// Enqueue any remaining references remaining on the STW
// reference processor's discovered lists. We need to do
// this after the card table is cleaned (and verified) as
- // the act of enqueuing entries on to the pending list
+ // the act of enqueueing entries on to the pending list
// will log these updates (and dirty their associated
// cards). We need these updates logged to update any
// RSets.
@@ -5942,7 +6042,7 @@ void G1CollectedHeap::cleanUpCardTable() {
g1_policy()->phase_times()->record_clear_ct_time(elapsed * 1000.0);
}
-void G1CollectedHeap::free_collection_set(HeapRegion* cs_head) {
+void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& evacuation_info) {
size_t pre_used = 0;
FreeRegionList local_free_list("Local List for CSet Freeing");
@@ -6028,10 +6128,12 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head) {
cur->set_evacuation_failed(false);
// The region is now considered to be old.
_old_set.add(cur);
+ evacuation_info.increment_collectionset_used_after(cur->used());
}
cur = next;
}
+ evacuation_info.set_regions_freed(local_free_list.length());
policy->record_max_rs_lengths(rs_lengths);
policy->cset_regions_freed();
diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
index 3f22247e8..6843d13f7 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,10 +26,12 @@
#define SHARE_VM_GC_IMPLEMENTATION_G1_G1COLLECTEDHEAP_HPP
#include "gc_implementation/g1/concurrentMark.hpp"
+#include "gc_implementation/g1/evacuationInfo.hpp"
#include "gc_implementation/g1/g1AllocRegion.hpp"
#include "gc_implementation/g1/g1HRPrinter.hpp"
-#include "gc_implementation/g1/g1RemSet.hpp"
#include "gc_implementation/g1/g1MonitoringSupport.hpp"
+#include "gc_implementation/g1/g1RemSet.hpp"
+#include "gc_implementation/g1/g1YCTypes.hpp"
#include "gc_implementation/g1/heapRegionSeq.hpp"
#include "gc_implementation/g1/heapRegionSets.hpp"
#include "gc_implementation/shared/hSpaceCounters.hpp"
@@ -61,7 +63,12 @@ class HeapRegionRemSetIterator;
class ConcurrentMark;
class ConcurrentMarkThread;
class ConcurrentG1Refine;
+class ConcurrentGCTimer;
class GenerationCounters;
+class STWGCTimer;
+class G1NewTracer;
+class G1OldTracer;
+class EvacuationFailedInfo;
typedef OverflowTaskQueue<StarTask, mtGC> RefToScanQueue;
typedef GenericTaskQueueSet<RefToScanQueue, mtGC> RefToScanQueueSet;
@@ -160,7 +167,7 @@ public:
// An instance is embedded into the G1CH and used as the
// (optional) _is_alive_non_header closure in the STW
// reference processor. It is also extensively used during
-// refence processing during STW evacuation pauses.
+// reference processing during STW evacuation pauses.
class G1STWIsAliveClosure: public BoolObjectClosure {
G1CollectedHeap* _g1;
public:
@@ -323,10 +330,10 @@ private:
void release_mutator_alloc_region();
// It initializes the GC alloc regions at the start of a GC.
- void init_gc_alloc_regions();
+ void init_gc_alloc_regions(EvacuationInfo& evacuation_info);
// It releases the GC alloc regions at the end of a GC.
- void release_gc_alloc_regions(uint no_of_gc_workers);
+ void release_gc_alloc_regions(uint no_of_gc_workers, EvacuationInfo& evacuation_info);
// It does any cleanup that needs to be done on the GC alloc regions
// before a Full GC.
@@ -389,6 +396,8 @@ private:
// concurrent cycles) we have completed.
volatile unsigned int _old_marking_cycles_completed;
+ bool _concurrent_cycle_started;
+
// 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
@@ -734,6 +743,12 @@ public:
return _old_marking_cycles_completed;
}
+ void register_concurrent_cycle_start(jlong start_time);
+ void register_concurrent_cycle_end();
+ void trace_heap_after_concurrent_cycle();
+
+ G1YCType yc_type();
+
G1HRPrinter* hr_printer() { return &_hr_printer; }
protected:
@@ -769,7 +784,7 @@ protected:
bool do_collection_pause_at_safepoint(double target_pause_time_ms);
// Actually do the work of evacuating the collection set.
- void evacuate_collection_set();
+ void evacuate_collection_set(EvacuationInfo& evacuation_info);
// The g1 remembered set of the heap.
G1RemSet* _g1_rem_set;
@@ -794,7 +809,7 @@ protected:
// After a collection pause, make the regions in the CS into free
// regions.
- void free_collection_set(HeapRegion* cs_head);
+ void free_collection_set(HeapRegion* cs_head, EvacuationInfo& evacuation_info);
// Abandon the current collection set without recording policy
// statistics or updating free lists.
@@ -863,9 +878,7 @@ protected:
// True iff a evacuation has failed in the current collection.
bool _evacuation_failed;
- // Set the attribute indicating whether evacuation has failed in the
- // current collection.
- void set_evacuation_failed(bool b) { _evacuation_failed = b; }
+ EvacuationFailedInfo* _evacuation_failed_info_array;
// Failed evacuations cause some logical from-space objects to have
// forwarding pointers to themselves. Reset them.
@@ -907,7 +920,7 @@ protected:
void finalize_for_evac_failure();
// An attempt to evacuate "obj" has failed; take necessary steps.
- oop handle_evacuation_failure_par(OopsInHeapRegionClosure* cl, oop obj);
+ oop handle_evacuation_failure_par(G1ParScanThreadState* _par_scan_state, oop obj);
void handle_evacuation_failure_common(oop obj, markOop m);
#ifndef PRODUCT
@@ -939,13 +952,13 @@ protected:
inline bool evacuation_should_fail();
// Reset the G1EvacuationFailureALot counters. Should be called at
- // the end of an evacuation pause in which an evacuation failure ocurred.
+ // the end of an evacuation pause in which an evacuation failure occurred.
inline void reset_evacuation_should_fail();
#endif // !PRODUCT
// ("Weak") Reference processing support.
//
- // G1 has 2 instances of the referece processor class. One
+ // G1 has 2 instances of the reference processor class. One
// (_ref_processor_cm) handles reference object discovery
// and subsequent processing during concurrent marking cycles.
//
@@ -995,6 +1008,12 @@ protected:
// The (stw) reference processor...
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
// closure (if non-null) is applied to the referent object to
// determine whether the referent is live. If so then the
@@ -1140,9 +1159,12 @@ public:
// The STW reference processor....
ReferenceProcessor* ref_processor_stw() const { return _ref_processor_stw; }
- // The Concurent Marking reference processor...
+ // 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
@@ -1200,7 +1222,7 @@ public:
// verify_region_sets_optional() is planted in the code for
// list verification in non-product builds (and it can be enabled in
- // product builds by definning HEAP_REGION_SET_FORCE_VERIFY to be 1).
+ // product builds by defining HEAP_REGION_SET_FORCE_VERIFY to be 1).
#if HEAP_REGION_SET_FORCE_VERIFY
void verify_region_sets_optional() {
verify_region_sets();
@@ -1266,7 +1288,7 @@ public:
// The same as above but assume that the caller holds the Heap_lock.
void collect_locked(GCCause::Cause cause);
- // True iff a evacuation has failed in the most-recent collection.
+ // True iff an evacuation has failed in the most-recent collection.
bool evacuation_failed() { return _evacuation_failed; }
// It will free a region if it has allocated objects in it that are
@@ -1554,6 +1576,7 @@ public:
// Override; it uses the "prev" marking information
virtual void verify(bool silent);
+
virtual void print_on(outputStream* st) const;
virtual void print_extended_on(outputStream* st) const;
virtual void print_on_error(outputStream* st) const;
@@ -1839,7 +1862,7 @@ protected:
G1ParScanHeapEvacClosure* _evac_cl;
G1ParScanPartialArrayClosure* _partial_scan_cl;
- int _hash_seed;
+ int _hash_seed;
uint _queue_num;
size_t _term_attempts;
diff --git a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp
index 741c6b713..3bd042819 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp
@@ -909,7 +909,7 @@ bool G1CollectorPolicy::need_to_start_conc_mark(const char* source, size_t alloc
// Anything below that is considered to be zero
#define MIN_TIMER_GRANULARITY 0.0000001
-void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms) {
+void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, EvacuationInfo& evacuation_info) {
double end_time_sec = os::elapsedTime();
assert(_cur_collection_pause_used_regions_at_start >= cset_region_length(),
"otherwise, the subtraction below does not make sense");
@@ -941,6 +941,9 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms) {
_mmu_tracker->add_pause(end_time_sec - pause_time_ms/1000.0,
end_time_sec, false);
+ evacuation_info.set_collectionset_used_before(_collection_set_bytes_used_before);
+ evacuation_info.set_bytes_copied(_bytes_copied_during_gc);
+
if (update_stats) {
_trace_gen0_time_data.record_end_collection(pause_time_ms, phase_times());
// this is where we update the allocation rate of the application
@@ -1896,7 +1899,7 @@ uint G1CollectorPolicy::calc_max_old_cset_length() {
}
-void G1CollectorPolicy::finalize_cset(double target_pause_time_ms) {
+void G1CollectorPolicy::finalize_cset(double target_pause_time_ms, EvacuationInfo& evacuation_info) {
double young_start_time_sec = os::elapsedTime();
YoungList* young_list = _g1->young_list();
@@ -2102,6 +2105,7 @@ void G1CollectorPolicy::finalize_cset(double target_pause_time_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);
+ evacuation_info.set_collectionset_regions(cset_region_length());
}
void TraceGen0TimeData::record_start_collection(double time_to_stop_the_world_ms) {
diff --git a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp
index 90106c00a..a497f2fa3 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp
@@ -671,7 +671,7 @@ public:
// Record the start and end of an evacuation pause.
void record_collection_pause_start(double start_time_sec);
- void record_collection_pause_end(double pause_time_ms);
+ void record_collection_pause_end(double pause_time_ms, EvacuationInfo& evacuation_info);
// Record the start and end of a full collection.
void record_full_collection_start();
@@ -720,7 +720,7 @@ public:
// 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.
- void finalize_cset(double target_pause_time_ms);
+ void finalize_cset(double target_pause_time_ms, EvacuationInfo& evacuation_info);
// The head of the list (via "next_in_collection_set()") representing the
// current collection set.
@@ -879,6 +879,7 @@ private:
ageTable _survivors_age_table;
public:
+ uint tenuring_threshold() const { return _tenuring_threshold; }
inline GCAllocPurpose
evacuation_destination(HeapRegion* src_region, uint age, size_t word_sz) {
diff --git a/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp b/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp
index 2fa5300b1..a1c5739f1 100644
--- a/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp
+++ b/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp
@@ -38,7 +38,7 @@ class WorkerDataArray : public CHeapObj<mtGC> {
NOT_PRODUCT(static const T _uninitialized;)
// We are caching the sum and average to only have to calculate them once.
- // This is not done in an MT-safe way. It is intetened to allow single
+ // This is not done in an MT-safe way. It is intended to allow single
// threaded code to call sum() and average() multiple times in any order
// without having to worry about the cost.
bool _has_new_data;
diff --git a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp
index d87a6cca1..adde08f21 100644
--- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp
+++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, 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
@@ -31,6 +31,10 @@
#include "code/icBuffer.hpp"
#include "gc_implementation/g1/g1Log.hpp"
#include "gc_implementation/g1/g1MarkSweep.hpp"
+#include "gc_implementation/shared/gcHeapSummary.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
#include "memory/gcLocker.hpp"
#include "memory/genCollectedHeap.hpp"
#include "memory/modRefBarrierSet.hpp"
@@ -119,7 +123,7 @@ void G1MarkSweep::allocate_stacks() {
void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading,
bool clear_all_softrefs) {
// Recursively traverse all live objects and mark them
- TraceTime tm("phase 1", G1Log::fine() && Verbose, true, gclog_or_tty);
+ GCTraceTime tm("phase 1", G1Log::fine() && Verbose, true, gc_timer());
GenMarkSweep::trace(" 1");
SharedHeap* sh = SharedHeap::heap();
@@ -139,10 +143,13 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading,
assert(rp == G1CollectedHeap::heap()->ref_processor_stw(), "Sanity");
rp->setup_policy(clear_all_softrefs);
- rp->process_discovered_references(&GenMarkSweep::is_alive,
- &GenMarkSweep::keep_alive,
- &GenMarkSweep::follow_stack_closure,
- NULL);
+ 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.
@@ -185,6 +192,8 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading,
gclog_or_tty->print_cr("]");
}
}
+
+ gc_tracer()->report_object_count_after_gc(&GenMarkSweep::is_alive);
}
class G1PrepareCompactClosure: public HeapRegionClosure {
@@ -257,7 +266,7 @@ void G1MarkSweep::mark_sweep_phase2() {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
- TraceTime tm("phase 2", G1Log::fine() && Verbose, true, gclog_or_tty);
+ GCTraceTime tm("phase 2", G1Log::fine() && Verbose, true, gc_timer());
GenMarkSweep::trace("2");
// find the first region
@@ -294,7 +303,7 @@ void G1MarkSweep::mark_sweep_phase3() {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
// Adjust the pointers to reflect the new locations
- TraceTime tm("phase 3", G1Log::fine() && Verbose, true, gclog_or_tty);
+ GCTraceTime tm("phase 3", G1Log::fine() && Verbose, true, gc_timer());
GenMarkSweep::trace("3");
SharedHeap* sh = SharedHeap::heap();
@@ -353,7 +362,7 @@ void G1MarkSweep::mark_sweep_phase4() {
// to use a higher index (saved from phase2) when verifying perm_gen.
G1CollectedHeap* g1h = G1CollectedHeap::heap();
- TraceTime tm("phase 4", G1Log::fine() && Verbose, true, gclog_or_tty);
+ GCTraceTime tm("phase 4", G1Log::fine() && Verbose, true, gc_timer());
GenMarkSweep::trace("4");
G1SpaceCompactClosure blk;
diff --git a/src/share/vm/gc_implementation/g1/g1MarkSweep.hpp b/src/share/vm/gc_implementation/g1/g1MarkSweep.hpp
index c49bc1939..f1b9d8356 100644
--- a/src/share/vm/gc_implementation/g1/g1MarkSweep.hpp
+++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, 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
@@ -54,6 +54,9 @@ class G1MarkSweep : AllStatic {
static void invoke_at_safepoint(ReferenceProcessor* rp,
bool clear_all_softrefs);
+ static STWGCTimer* gc_timer() { return GenMarkSweep::_gc_timer; }
+ static SerialOldTracer* gc_tracer() { return GenMarkSweep::_gc_tracer; }
+
private:
// Mark live objects
diff --git a/src/share/vm/gc_implementation/g1/g1MonitoringSupport.hpp b/src/share/vm/gc_implementation/g1/g1MonitoringSupport.hpp
index 4e1761e26..03b7300ae 100644
--- a/src/share/vm/gc_implementation/g1/g1MonitoringSupport.hpp
+++ b/src/share/vm/gc_implementation/g1/g1MonitoringSupport.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, 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
@@ -224,6 +224,7 @@ class G1MonitoringSupport : public CHeapObj<mtGC> {
// Monitoring support used by
// MemoryService
// jstat counters
+ // Tracing
size_t overall_reserved() { return _overall_reserved; }
size_t overall_committed() { return _overall_committed; }
diff --git a/src/share/vm/gc_implementation/g1/g1YCTypes.hpp b/src/share/vm/gc_implementation/g1/g1YCTypes.hpp
new file mode 100644
index 000000000..7d2216059
--- /dev/null
+++ b/src/share/vm/gc_implementation/g1/g1YCTypes.hpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012, 2013, 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_IMPLEMENTATION_G1_G1YCTYPES_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_G1_G1YCTYPES_HPP
+
+#include "utilities/debug.hpp"
+
+enum G1YCType {
+ Normal,
+ InitialMark,
+ DuringMark,
+ Mixed,
+ G1YCTypeEndSentinel
+};
+
+class G1YCTypeHelper {
+ public:
+ static const char* to_string(G1YCType type) {
+ switch(type) {
+ case Normal: return "Normal";
+ case InitialMark: return "Initial Mark";
+ case DuringMark: return "During Mark";
+ case Mixed: return "Mixed";
+ default: ShouldNotReachHere(); return NULL;
+ }
+ }
+};
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1YCTYPES_HPP
diff --git a/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp b/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp
index cf7488ffe..3be06e6ae 100644
--- a/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp
+++ b/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, 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,8 @@
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
#include "gc_implementation/g1/g1Log.hpp"
#include "gc_implementation/g1/vm_operations_g1.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
#include "gc_implementation/shared/isGCActiveMark.hpp"
#include "gc_implementation/g1/vm_operations_g1.hpp"
#include "runtime/interfaceSupport.hpp"
@@ -227,7 +229,7 @@ void VM_CGC_Operation::release_and_notify_pending_list_lock() {
void VM_CGC_Operation::doit() {
gclog_or_tty->date_stamp(G1Log::fine() && PrintGCDateStamps);
TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty);
- TraceTime t(_printGCMessage, G1Log::fine(), true, gclog_or_tty);
+ GCTraceTime t(_printGCMessage, G1Log::fine(), true, G1CollectedHeap::heap()->gc_timer_cm());
SharedHeap* sh = SharedHeap::heap();
// This could go away if CollectedHeap gave access to _gc_is_active...
if (sh != NULL) {
diff --git a/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp
index e868d8709..c104533a4 100644
--- a/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp
+++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, 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,11 @@
#include "gc_implementation/shared/adaptiveSizePolicy.hpp"
#include "gc_implementation/shared/ageTable.hpp"
#include "gc_implementation/shared/parGCAllocBuffer.hpp"
+#include "gc_implementation/shared/gcHeapSummary.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
+#include "gc_implementation/shared/copyFailedInfo.hpp"
#include "gc_implementation/shared/spaceDecorator.hpp"
#include "memory/defNewGeneration.inline.hpp"
#include "memory/genCollectedHeap.hpp"
@@ -75,7 +80,6 @@ ParScanThreadState::ParScanThreadState(Space* to_space_,
work_queue_set_, &term_),
_is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this),
_keep_alive_closure(&_scan_weak_ref_closure),
- _promotion_failure_size(0),
_strong_roots_time(0.0), _term_time(0.0)
{
#if TASKQUEUE_STATS
@@ -279,13 +283,10 @@ void ParScanThreadState::undo_alloc_in_to_space(HeapWord* obj,
}
}
-void ParScanThreadState::print_and_clear_promotion_failure_size() {
- if (_promotion_failure_size != 0) {
- if (PrintPromotionFailure) {
- gclog_or_tty->print(" (%d: promotion failure size = " SIZE_FORMAT ") ",
- _thread_num, _promotion_failure_size);
- }
- _promotion_failure_size = 0;
+void ParScanThreadState::print_promotion_failure_size() {
+ if (_promotion_failed_info.has_failed() && PrintPromotionFailure) {
+ gclog_or_tty->print(" (%d: promotion failure size = " SIZE_FORMAT ") ",
+ _thread_num, _promotion_failed_info.first_size());
}
}
@@ -305,6 +306,7 @@ public:
inline ParScanThreadState& thread_state(int i);
+ void trace_promotion_failed(YoungGCTracer& gc_tracer);
void reset(int active_workers, bool promotion_failed);
void flush();
@@ -353,13 +355,21 @@ inline ParScanThreadState& ParScanThreadStateSet::thread_state(int i)
return ((ParScanThreadState*)_data)[i];
}
+void ParScanThreadStateSet::trace_promotion_failed(YoungGCTracer& gc_tracer) {
+ for (int i = 0; i < length(); ++i) {
+ if (thread_state(i).promotion_failed()) {
+ gc_tracer.report_promotion_failed(thread_state(i).promotion_failed_info());
+ thread_state(i).promotion_failed_info().reset();
+ }
+ }
+}
void ParScanThreadStateSet::reset(int active_threads, bool promotion_failed)
{
_term.reset_for_reuse(active_threads);
if (promotion_failed) {
for (int i = 0; i < length(); ++i) {
- thread_state(i).print_and_clear_promotion_failure_size();
+ thread_state(i).print_promotion_failure_size();
}
}
}
@@ -583,14 +593,6 @@ void ParNewGenTask::set_for_termination(int active_workers) {
gch->set_n_termination(active_workers);
}
-// The "i" passed to this method is the part of the work for
-// this thread. It is not the worker ID. The "i" is derived
-// from _started_workers which is incremented in internal_note_start()
-// called in GangWorker loop() and which is called under the
-// which is called under the protection of the gang monitor and is
-// called after a task is started. So "i" is based on
-// first-come-first-served.
-
void ParNewGenTask::work(uint worker_id) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
// Since this is being done in a separate thread, need new resource
@@ -876,16 +878,45 @@ void EvacuateFollowersClosureGeneral::do_void() {
}
+// A Generation that does parallel young-gen collection.
+
bool ParNewGeneration::_avoid_promotion_undo = false;
-// A Generation that does parallel young-gen collection.
+void ParNewGeneration::handle_promotion_failed(GenCollectedHeap* gch, ParScanThreadStateSet& thread_state_set, ParNewTracer& gc_tracer) {
+ assert(_promo_failure_scan_stack.is_empty(), "post condition");
+ _promo_failure_scan_stack.clear(true); // Clear cached segments.
+
+ remove_forwarding_pointers();
+ if (PrintGCDetails) {
+ gclog_or_tty->print(" (promotion failed)");
+ }
+ // All the spaces are in play for mark-sweep.
+ swap_spaces(); // Make life simpler for CMS || rescan; see 6483690.
+ from()->set_next_compaction_space(to());
+ gch->set_incremental_collection_failed();
+ // Inform the next generation that a promotion failure occurred.
+ _next_gen->promotion_failure_occurred();
+
+ // Trace promotion failure in the parallel GC threads
+ thread_state_set.trace_promotion_failed(gc_tracer);
+ // Single threaded code may have reported promotion failure to the global state
+ if (_promotion_failed_info.has_failed()) {
+ gc_tracer.report_promotion_failed(_promotion_failed_info);
+ }
+ // Reset the PromotionFailureALot counters.
+ NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();)
+}
void ParNewGeneration::collect(bool full,
bool clear_all_soft_refs,
size_t size,
bool is_tlab) {
assert(full || size > 0, "otherwise we don't want to collect");
+
GenCollectedHeap* gch = GenCollectedHeap::heap();
+
+ _gc_timer->register_gc_start(os::elapsed_counter());
+
assert(gch->kind() == CollectedHeap::GenCollectedHeap,
"not a CMS generational heap");
AdaptiveSizePolicy* size_policy = gch->gen_policy()->size_policy();
@@ -906,7 +937,7 @@ void ParNewGeneration::collect(bool full,
set_avoid_promotion_undo(true);
}
- // If the next generation is too full to accomodate worst-case promotion
+ // If the next generation is too full to accommodate worst-case promotion
// from this generation, pass on collection; let the next generation
// do it.
if (!collection_attempt_is_safe()) {
@@ -915,6 +946,10 @@ void ParNewGeneration::collect(bool full,
}
assert(to()->is_empty(), "Else not collection_attempt_is_safe");
+ ParNewTracer gc_tracer;
+ gc_tracer.report_gc_start(gch->gc_cause(), _gc_timer->gc_start());
+ gch->trace_heap_before_gc(&gc_tracer);
+
init_assuming_no_promotion_failure();
if (UseAdaptiveSizePolicy) {
@@ -922,7 +957,7 @@ void ParNewGeneration::collect(bool full,
size_policy->minor_collection_begin();
}
- TraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, gclog_or_tty);
+ GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL);
// Capture heap used before collection (for printing).
size_t gch_prev_used = gch->used();
@@ -975,17 +1010,21 @@ void ParNewGeneration::collect(bool full,
rp->setup_policy(clear_all_soft_refs);
// Can the mt_degree be set later (at run_task() time would be best)?
rp->set_active_mt_degree(active_workers);
+ ReferenceProcessorStats stats;
if (rp->processing_is_mt()) {
ParNewRefProcTaskExecutor task_executor(*this, thread_state_set);
- rp->process_discovered_references(&is_alive, &keep_alive,
- &evacuate_followers, &task_executor);
+ stats = rp->process_discovered_references(&is_alive, &keep_alive,
+ &evacuate_followers, &task_executor,
+ _gc_timer);
} else {
thread_state_set.flush();
gch->set_par_threads(0); // 0 ==> non-parallel.
gch->save_marks();
- rp->process_discovered_references(&is_alive, &keep_alive,
- &evacuate_followers, NULL);
+ stats = rp->process_discovered_references(&is_alive, &keep_alive,
+ &evacuate_followers, NULL,
+ _gc_timer);
}
+ gc_tracer.report_gc_reference_stats(stats);
if (!promotion_failed()) {
// Swap the survivor spaces.
eden()->clear(SpaceDecorator::Mangle);
@@ -1010,22 +1049,7 @@ void ParNewGeneration::collect(bool full,
adjust_desired_tenuring_threshold();
} else {
- assert(_promo_failure_scan_stack.is_empty(), "post condition");
- _promo_failure_scan_stack.clear(true); // Clear cached segments.
-
- remove_forwarding_pointers();
- if (PrintGCDetails) {
- gclog_or_tty->print(" (promotion failed)");
- }
- // All the spaces are in play for mark-sweep.
- swap_spaces(); // Make life simpler for CMS || rescan; see 6483690.
- from()->set_next_compaction_space(to());
- gch->set_incremental_collection_failed();
- // Inform the next generation that a promotion failure occurred.
- _next_gen->promotion_failure_occurred();
-
- // Reset the PromotionFailureALot counters.
- NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();)
+ handle_promotion_failed(gch, thread_state_set, gc_tracer);
}
// set new iteration safe limit for the survivor spaces
from()->set_concurrent_iteration_safe_limit(from()->top());
@@ -1065,6 +1089,13 @@ void ParNewGeneration::collect(bool full,
rp->enqueue_discovered_references(NULL);
}
rp->verify_no_references_recorded();
+
+ gch->trace_heap_after_gc(&gc_tracer);
+ gc_tracer.report_tenuring_threshold(tenuring_threshold());
+
+ _gc_timer->register_gc_end(os::elapsed_counter());
+
+ gc_tracer.report_gc_end(_gc_timer->gc_end(), _gc_timer->time_partitions());
}
static int sum;
@@ -1174,8 +1205,7 @@ oop ParNewGeneration::copy_to_survivor_space_avoiding_promotion_undo(
new_obj = old;
preserve_mark_if_necessary(old, m);
- // Log the size of the maiden promotion failure
- par_scan_state->log_promotion_failure(sz);
+ par_scan_state->register_promotion_failure(sz);
}
old->forward_to(new_obj);
@@ -1300,8 +1330,7 @@ oop ParNewGeneration::copy_to_survivor_space_with_undo(
failed_to_promote = true;
preserve_mark_if_necessary(old, m);
- // Log the size of the maiden promotion failure
- par_scan_state->log_promotion_failure(sz);
+ par_scan_state->register_promotion_failure(sz);
}
} else {
// Is in to-space; do copying ourselves.
@@ -1599,8 +1628,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan
}
#undef BUSY
-void ParNewGeneration::ref_processor_init()
-{
+void ParNewGeneration::ref_processor_init() {
if (_ref_processor == NULL) {
// Allocate and initialize a reference processor
_ref_processor =
diff --git a/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp b/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp
index 487552bfb..987767b16 100644
--- a/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp
+++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp
@@ -25,7 +25,9 @@
#ifndef SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARNEWGENERATION_HPP
#define SHARE_VM_GC_IMPLEMENTATION_PARNEW_PARNEWGENERATION_HPP
+#include "gc_implementation/shared/gcTrace.hpp"
#include "gc_implementation/shared/parGCAllocBuffer.hpp"
+#include "gc_implementation/shared/copyFailedInfo.hpp"
#include "memory/defNewGeneration.hpp"
#include "utilities/taskqueue.hpp"
@@ -105,7 +107,7 @@ class ParScanThreadState {
#endif // TASKQUEUE_STATS
// Stats for promotion failure
- size_t _promotion_failure_size;
+ PromotionFailedInfo _promotion_failed_info;
// Timing numbers.
double _start;
@@ -180,13 +182,16 @@ class ParScanThreadState {
void undo_alloc_in_to_space(HeapWord* obj, size_t word_sz);
// Promotion failure stats
- size_t promotion_failure_size() { return promotion_failure_size(); }
- void log_promotion_failure(size_t sz) {
- if (_promotion_failure_size == 0) {
- _promotion_failure_size = sz;
- }
+ void register_promotion_failure(size_t sz) {
+ _promotion_failed_info.register_copy_failure(sz);
+ }
+ PromotionFailedInfo& promotion_failed_info() {
+ return _promotion_failed_info;
}
- void print_and_clear_promotion_failure_size();
+ bool promotion_failed() {
+ return _promotion_failed_info.has_failed();
+ }
+ void print_promotion_failure_size();
#if TASKQUEUE_STATS
TaskQueueStats & taskqueue_stats() const { return _work_queue->stats; }
@@ -337,6 +342,8 @@ class ParNewGeneration: public DefNewGeneration {
// word being overwritten with a self-forwarding-pointer.
void preserve_mark_if_necessary(oop obj, markOop m);
+ void handle_promotion_failed(GenCollectedHeap* gch, ParScanThreadStateSet& thread_state_set, ParNewTracer& gc_tracer);
+
protected:
bool _survivor_overflow;
diff --git a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp
index 9ea2fa856..d5b6c0540 100644
--- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp
+++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,8 @@
#include "gc_implementation/parallelScavenge/psPromotionManager.hpp"
#include "gc_implementation/parallelScavenge/psScavenge.hpp"
#include "gc_implementation/parallelScavenge/vmPSOperations.hpp"
+#include "gc_implementation/shared/gcHeapSummary.hpp"
+#include "gc_implementation/shared/gcWhen.hpp"
#include "memory/gcLocker.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/handles.inline.hpp"
@@ -642,6 +644,29 @@ void ParallelScavengeHeap::prepare_for_verify() {
ensure_parsability(false); // no need to retire TLABs for verification
}
+PSHeapSummary ParallelScavengeHeap::create_ps_heap_summary() {
+ PSOldGen* old = old_gen();
+ HeapWord* old_committed_end = (HeapWord*)old->virtual_space()->committed_high_addr();
+ VirtualSpaceSummary old_summary(old->reserved().start(), old_committed_end, old->reserved().end());
+ SpaceSummary old_space(old->reserved().start(), old_committed_end, old->used_in_bytes());
+
+ PSYoungGen* young = young_gen();
+ VirtualSpaceSummary young_summary(young->reserved().start(),
+ (HeapWord*)young->virtual_space()->committed_high_addr(), young->reserved().end());
+
+ MutableSpace* eden = young_gen()->eden_space();
+ SpaceSummary eden_space(eden->bottom(), eden->end(), eden->used_in_bytes());
+
+ MutableSpace* from = young_gen()->from_space();
+ SpaceSummary from_space(from->bottom(), from->end(), from->used_in_bytes());
+
+ MutableSpace* to = young_gen()->to_space();
+ SpaceSummary to_space(to->bottom(), to->end(), to->used_in_bytes());
+
+ VirtualSpaceSummary heap_summary = create_heap_space_summary();
+ return PSHeapSummary(heap_summary, used(), old_summary, old_space, young_summary, eden_space, from_space, to_space);
+}
+
void ParallelScavengeHeap::print_on(outputStream* st) const {
young_gen()->print_on(st);
old_gen()->print_on(st);
@@ -706,6 +731,12 @@ void ParallelScavengeHeap::print_heap_change(size_t prev_used) {
}
}
+void ParallelScavengeHeap::trace_heap(GCWhen::Type when, GCTracer* gc_tracer) {
+ const PSHeapSummary& heap_summary = create_ps_heap_summary();
+ const MetaspaceSummary& metaspace_summary = create_metaspace_summary();
+ gc_tracer->report_gc_heap_summary(when, heap_summary, metaspace_summary);
+}
+
ParallelScavengeHeap* ParallelScavengeHeap::heap() {
assert(_psh != NULL, "Uninitialized access to ParallelScavengeHeap::heap()");
assert(_psh->kind() == CollectedHeap::ParallelScavengeHeap, "not a parallel scavenge heap");
diff --git a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp
index 98e9c0435..11ef53251 100644
--- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp
+++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, 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,14 +30,18 @@
#include "gc_implementation/parallelScavenge/psOldGen.hpp"
#include "gc_implementation/parallelScavenge/psYoungGen.hpp"
#include "gc_implementation/shared/gcPolicyCounters.hpp"
+#include "gc_implementation/shared/gcWhen.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "utilities/ostream.hpp"
class AdjoiningGenerations;
+class CollectorPolicy;
+class GCHeapSummary;
class GCTaskManager;
-class PSAdaptiveSizePolicy;
class GenerationSizer;
class CollectorPolicy;
+class PSAdaptiveSizePolicy;
+class PSHeapSummary;
class ParallelScavengeHeap : public CollectedHeap {
friend class VMStructs;
@@ -65,6 +69,8 @@ class ParallelScavengeHeap : public CollectedHeap {
static GCTaskManager* _gc_task_manager; // The task manager.
+ void trace_heap(GCWhen::Type when, GCTracer* tracer);
+
protected:
static inline size_t total_invocations();
HeapWord* allocate_new_tlab(size_t size);
@@ -219,6 +225,7 @@ class ParallelScavengeHeap : public CollectedHeap {
jlong millis_since_last_gc();
void prepare_for_verify();
+ PSHeapSummary create_ps_heap_summary();
virtual void print_on(outputStream* st) const;
virtual void print_on_error(outputStream* st) const;
virtual void print_gc_threads_on(outputStream* st) const;
diff --git a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp
index fa3cf7bcc..14be13a26 100644
--- a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp
+++ b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp
@@ -27,6 +27,8 @@
#include "code/codeCache.hpp"
#include "gc_implementation/parallelScavenge/pcTasks.hpp"
#include "gc_implementation/parallelScavenge/psParallelCompact.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
#include "gc_interface/collectedHeap.hpp"
#include "memory/universe.hpp"
#include "oops/objArrayKlass.inline.hpp"
@@ -48,8 +50,8 @@ void ThreadRootsMarkingTask::do_it(GCTaskManager* manager, uint which) {
ResourceMark rm;
- NOT_PRODUCT(TraceTime tm("ThreadRootsMarkingTask",
- PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty));
+ NOT_PRODUCT(GCTraceTime tm("ThreadRootsMarkingTask",
+ PrintGCDetails && TraceParallelOldGCTasks, true, NULL));
ParCompactionManager* cm =
ParCompactionManager::gc_thread_compaction_manager(which);
@@ -77,8 +79,8 @@ void ThreadRootsMarkingTask::do_it(GCTaskManager* manager, uint which) {
void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) {
assert(Universe::heap()->is_gc_active(), "called outside gc");
- NOT_PRODUCT(TraceTime tm("MarkFromRootsTask",
- PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty));
+ NOT_PRODUCT(GCTraceTime tm("MarkFromRootsTask",
+ PrintGCDetails && TraceParallelOldGCTasks, true, NULL));
ParCompactionManager* cm =
ParCompactionManager::gc_thread_compaction_manager(which);
PSParallelCompact::MarkAndPushClosure mark_and_push_closure(cm);
@@ -148,8 +150,8 @@ void RefProcTaskProxy::do_it(GCTaskManager* manager, uint which)
{
assert(Universe::heap()->is_gc_active(), "called outside gc");
- NOT_PRODUCT(TraceTime tm("RefProcTask",
- PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty));
+ NOT_PRODUCT(GCTraceTime tm("RefProcTask",
+ PrintGCDetails && TraceParallelOldGCTasks, true, NULL));
ParCompactionManager* cm =
ParCompactionManager::gc_thread_compaction_manager(which);
PSParallelCompact::MarkAndPushClosure mark_and_push_closure(cm);
@@ -204,8 +206,8 @@ StealMarkingTask::StealMarkingTask(ParallelTaskTerminator* t) :
void StealMarkingTask::do_it(GCTaskManager* manager, uint which) {
assert(Universe::heap()->is_gc_active(), "called outside gc");
- NOT_PRODUCT(TraceTime tm("StealMarkingTask",
- PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty));
+ NOT_PRODUCT(GCTraceTime tm("StealMarkingTask",
+ PrintGCDetails && TraceParallelOldGCTasks, true, NULL));
ParCompactionManager* cm =
ParCompactionManager::gc_thread_compaction_manager(which);
@@ -237,8 +239,8 @@ StealRegionCompactionTask::StealRegionCompactionTask(ParallelTaskTerminator* t):
void StealRegionCompactionTask::do_it(GCTaskManager* manager, uint which) {
assert(Universe::heap()->is_gc_active(), "called outside gc");
- NOT_PRODUCT(TraceTime tm("StealRegionCompactionTask",
- PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty));
+ NOT_PRODUCT(GCTraceTime tm("StealRegionCompactionTask",
+ PrintGCDetails && TraceParallelOldGCTasks, true, NULL));
ParCompactionManager* cm =
ParCompactionManager::gc_thread_compaction_manager(which);
@@ -304,8 +306,8 @@ UpdateDensePrefixTask::UpdateDensePrefixTask(
void UpdateDensePrefixTask::do_it(GCTaskManager* manager, uint which) {
- NOT_PRODUCT(TraceTime tm("UpdateDensePrefixTask",
- PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty));
+ NOT_PRODUCT(GCTraceTime tm("UpdateDensePrefixTask",
+ PrintGCDetails && TraceParallelOldGCTasks, true, NULL));
ParCompactionManager* cm =
ParCompactionManager::gc_thread_compaction_manager(which);
@@ -319,8 +321,8 @@ void UpdateDensePrefixTask::do_it(GCTaskManager* manager, uint which) {
void DrainStacksCompactionTask::do_it(GCTaskManager* manager, uint which) {
assert(Universe::heap()->is_gc_active(), "called outside gc");
- NOT_PRODUCT(TraceTime tm("DrainStacksCompactionTask",
- PrintGCDetails && TraceParallelOldGCTasks, true, gclog_or_tty));
+ NOT_PRODUCT(GCTraceTime tm("DrainStacksCompactionTask",
+ PrintGCDetails && TraceParallelOldGCTasks, true, NULL));
ParCompactionManager* cm =
ParCompactionManager::gc_thread_compaction_manager(which);
diff --git a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp
index 01b3a5b6d..dcdc21806 100644
--- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp
+++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp
@@ -34,6 +34,10 @@
#include "gc_implementation/parallelScavenge/psOldGen.hpp"
#include "gc_implementation/parallelScavenge/psScavenge.hpp"
#include "gc_implementation/parallelScavenge/psYoungGen.hpp"
+#include "gc_implementation/shared/gcHeapSummary.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
#include "gc_implementation/shared/isGCActiveMark.hpp"
#include "gc_implementation/shared/markSweep.hpp"
#include "gc_implementation/shared/spaceDecorator.hpp"
@@ -108,8 +112,12 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
}
ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
- GCCause::Cause gc_cause = heap->gc_cause();
assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
+ GCCause::Cause gc_cause = heap->gc_cause();
+
+ _gc_timer->register_gc_start(os::elapsed_counter());
+ _gc_tracer->report_gc_start(gc_cause, _gc_timer->gc_start());
+
PSAdaptiveSizePolicy* size_policy = heap->size_policy();
// The scope of casr should end after code that can change
@@ -131,6 +139,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
AdaptiveSizePolicyOutput(size_policy, heap->total_collections());
heap->print_heap_before_gc();
+ heap->trace_heap_before_gc(_gc_tracer);
// Fill in TLABs
heap->accumulate_statistics_all_tlabs();
@@ -147,7 +156,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
old_gen->verify_object_start_array();
}
- heap->pre_full_gc_dump();
+ heap->pre_full_gc_dump(_gc_timer);
// Filled in below to track the state of the young gen after the collection.
bool eden_empty;
@@ -159,7 +168,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps);
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
- TraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, gclog_or_tty);
+ GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL);
TraceCollectorStats tcs(counters());
TraceMemoryManagerStats tms(true /* Full GC */,gc_cause);
@@ -374,13 +383,18 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
NOT_PRODUCT(ref_processor()->verify_no_references_recorded());
heap->print_heap_after_gc();
+ heap->trace_heap_after_gc(_gc_tracer);
- heap->post_full_gc_dump();
+ heap->post_full_gc_dump(_gc_timer);
#ifdef TRACESPINNING
ParallelTaskTerminator::print_termination_counts();
#endif
+ _gc_timer->register_gc_end(os::elapsed_counter());
+
+ _gc_tracer->report_gc_end(_gc_timer->gc_end(), _gc_timer->time_partitions());
+
return true;
}
@@ -498,7 +512,7 @@ void PSMarkSweep::deallocate_stacks() {
void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
// Recursively traverse all live objects and mark them
- TraceTime tm("phase 1", PrintGCDetails && Verbose, true, gclog_or_tty);
+ GCTraceTime tm("phase 1", PrintGCDetails && Verbose, true, _gc_timer);
trace(" 1");
ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
@@ -531,8 +545,10 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
// Process reference objects found during marking
{
ref_processor()->setup_policy(clear_all_softrefs);
- ref_processor()->process_discovered_references(
- is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL);
+ const ReferenceProcessorStats& stats =
+ ref_processor()->process_discovered_references(
+ is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL, _gc_timer);
+ gc_tracer()->report_gc_reference_stats(stats);
}
// This is the point where the entire marking should have completed.
@@ -552,11 +568,12 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
// Clean up unreferenced symbols in symbol table.
SymbolTable::unlink();
+ _gc_tracer->report_object_count_after_gc(is_alive_closure());
}
void PSMarkSweep::mark_sweep_phase2() {
- TraceTime tm("phase 2", PrintGCDetails && Verbose, true, gclog_or_tty);
+ GCTraceTime tm("phase 2", PrintGCDetails && Verbose, true, _gc_timer);
trace("2");
// Now all live objects are marked, compute the new object addresses.
@@ -586,7 +603,7 @@ static PSAlwaysTrueClosure always_true;
void PSMarkSweep::mark_sweep_phase3() {
// Adjust the pointers to reflect the new locations
- TraceTime tm("phase 3", PrintGCDetails && Verbose, true, gclog_or_tty);
+ GCTraceTime tm("phase 3", PrintGCDetails && Verbose, true, _gc_timer);
trace("3");
ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
@@ -629,7 +646,7 @@ void PSMarkSweep::mark_sweep_phase3() {
void PSMarkSweep::mark_sweep_phase4() {
EventMark m("4 compact heap");
- TraceTime tm("phase 4", PrintGCDetails && Verbose, true, gclog_or_tty);
+ GCTraceTime tm("phase 4", PrintGCDetails && Verbose, true, _gc_timer);
trace("4");
// All pointers are now adjusted, move objects accordingly
diff --git a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
index be437f327..27a42de95 100644
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
+++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
@@ -39,6 +39,10 @@
#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"
#include "gc_implementation/parallelScavenge/psScavenge.hpp"
#include "gc_implementation/parallelScavenge/psYoungGen.hpp"
+#include "gc_implementation/shared/gcHeapSummary.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
#include "gc_implementation/shared/isGCActiveMark.hpp"
#include "gc_interface/gcCause.hpp"
#include "memory/gcLocker.inline.hpp"
@@ -799,6 +803,8 @@ void ParallelCompactData::verify_clear()
}
#endif // #ifdef ASSERT
+STWGCTimer PSParallelCompact::_gc_timer;
+ParallelOldTracer PSParallelCompact::_gc_tracer;
elapsedTimer PSParallelCompact::_accumulated_time;
unsigned int PSParallelCompact::_total_invocations = 0;
unsigned int PSParallelCompact::_maximum_compaction_gc_num = 0;
@@ -972,7 +978,7 @@ void PSParallelCompact::pre_compact(PreGCValues* pre_gc_values)
// at each young gen gc. Do the update unconditionally (even though a
// promotion failure does not swap spaces) because an unknown number of minor
// collections will have swapped the spaces an unknown number of times.
- TraceTime tm("pre compact", print_phases(), true, gclog_or_tty);
+ GCTraceTime tm("pre compact", print_phases(), true, &_gc_timer);
ParallelScavengeHeap* heap = gc_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());
@@ -989,6 +995,7 @@ void PSParallelCompact::pre_compact(PreGCValues* pre_gc_values)
_total_invocations++;
heap->print_heap_before_gc();
+ heap->trace_heap_before_gc(&_gc_tracer);
// Fill in TLABs
heap->accumulate_statistics_all_tlabs();
@@ -1014,7 +1021,7 @@ void PSParallelCompact::pre_compact(PreGCValues* pre_gc_values)
void PSParallelCompact::post_compact()
{
- TraceTime tm("post compact", print_phases(), true, gclog_or_tty);
+ GCTraceTime tm("post compact", print_phases(), true, &_gc_timer);
for (unsigned int id = old_space_id; id < last_space_id; ++id) {
// Clear the marking bitmap, summary data and split info.
@@ -1840,7 +1847,7 @@ void PSParallelCompact::summary_phase_msg(SpaceId dst_space_id,
void PSParallelCompact::summary_phase(ParCompactionManager* cm,
bool maximum_compaction)
{
- TraceTime tm("summary phase", print_phases(), true, gclog_or_tty);
+ GCTraceTime tm("summary phase", print_phases(), true, &_gc_timer);
// trace("2");
#ifdef ASSERT
@@ -1998,11 +2005,15 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
return false;
}
+ ParallelScavengeHeap* heap = gc_heap();
+
+ _gc_timer.register_gc_start(os::elapsed_counter());
+ _gc_tracer.report_gc_start(heap->gc_cause(), _gc_timer.gc_start());
+
TimeStamp marking_start;
TimeStamp compaction_start;
TimeStamp collection_exit;
- ParallelScavengeHeap* heap = gc_heap();
GCCause::Cause gc_cause = heap->gc_cause();
PSYoungGen* young_gen = heap->young_gen();
PSOldGen* old_gen = heap->old_gen();
@@ -2018,7 +2029,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
heap->record_gen_tops_before_GC();
}
- heap->pre_full_gc_dump();
+ heap->pre_full_gc_dump(&_gc_timer);
_print_phases = PrintGCDetails && PrintParallelOldGCPhaseTimes;
@@ -2045,7 +2056,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps);
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
- TraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, gclog_or_tty);
+ GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL);
TraceCollectorStats tcs(counters());
TraceMemoryManagerStats tms(true /* Full GC */,gc_cause);
@@ -2065,7 +2076,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
bool marked_for_unloading = false;
marking_start.update();
- marking_phase(vmthread_cm, maximum_heap_compaction);
+ marking_phase(vmthread_cm, maximum_heap_compaction, &_gc_tracer);
bool max_on_system_gc = UseMaximumCompactionOnSystemGC
&& gc_cause == GCCause::_java_lang_system_gc;
@@ -2218,6 +2229,8 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
collection_exit.update();
heap->print_heap_after_gc();
+ heap->trace_heap_after_gc(&_gc_tracer);
+
if (PrintGCTaskTimeStamps) {
gclog_or_tty->print_cr("VM-Thread " INT64_FORMAT " " INT64_FORMAT " "
INT64_FORMAT,
@@ -2226,12 +2239,17 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
gc_task_manager()->print_task_time_stamps();
}
- heap->post_full_gc_dump();
+ heap->post_full_gc_dump(&_gc_timer);
#ifdef TRACESPINNING
ParallelTaskTerminator::print_termination_counts();
#endif
+ _gc_timer.register_gc_end(os::elapsed_counter());
+
+ _gc_tracer.report_dense_prefix(dense_prefix(old_space_id));
+ _gc_tracer.report_gc_end(_gc_timer.gc_end(), _gc_timer.time_partitions());
+
return true;
}
@@ -2330,9 +2348,10 @@ GCTaskManager* const PSParallelCompact::gc_task_manager() {
}
void PSParallelCompact::marking_phase(ParCompactionManager* cm,
- bool maximum_heap_compaction) {
+ bool maximum_heap_compaction,
+ ParallelOldTracer *gc_tracer) {
// Recursively traverse all live objects and mark them
- TraceTime tm("marking phase", print_phases(), true, gclog_or_tty);
+ GCTraceTime tm("marking phase", print_phases(), true, &_gc_timer);
ParallelScavengeHeap* heap = gc_heap();
uint parallel_gc_threads = heap->gc_task_manager()->workers();
@@ -2347,7 +2366,8 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm,
ClassLoaderDataGraph::clear_claimed_marks();
{
- TraceTime tm_m("par mark", print_phases(), true, gclog_or_tty);
+ GCTraceTime tm_m("par mark", print_phases(), true, &_gc_timer);
+
ParallelScavengeHeap::ParStrongRootsScope psrs;
GCTaskQueue* q = GCTaskQueue::create();
@@ -2375,19 +2395,24 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm,
// Process reference objects found during marking
{
- TraceTime tm_r("reference processing", print_phases(), true, gclog_or_tty);
+ GCTraceTime tm_r("reference processing", print_phases(), true, &_gc_timer);
+
+ ReferenceProcessorStats stats;
if (ref_processor()->processing_is_mt()) {
RefProcTaskExecutor task_executor;
- ref_processor()->process_discovered_references(
+ stats = ref_processor()->process_discovered_references(
is_alive_closure(), &mark_and_push_closure, &follow_stack_closure,
- &task_executor);
+ &task_executor, &_gc_timer);
} else {
- ref_processor()->process_discovered_references(
- is_alive_closure(), &mark_and_push_closure, &follow_stack_closure, NULL);
+ stats = ref_processor()->process_discovered_references(
+ is_alive_closure(), &mark_and_push_closure, &follow_stack_closure, NULL,
+ &_gc_timer);
}
+
+ gc_tracer->report_gc_reference_stats(stats);
}
- TraceTime tm_c("class unloading", print_phases(), true, gclog_or_tty);
+ GCTraceTime tm_c("class unloading", print_phases(), true, &_gc_timer);
// This is the point where the entire marking should have completed.
assert(cm->marking_stacks_empty(), "Marking should have completed");
@@ -2406,6 +2431,7 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm,
// Clean up unreferenced symbols in symbol table.
SymbolTable::unlink();
+ _gc_tracer.report_object_count_after_gc(is_alive_closure());
}
void PSParallelCompact::follow_klass(ParCompactionManager* cm, Klass* klass) {
@@ -2446,7 +2472,7 @@ static PSAlwaysTrueClosure always_true;
void PSParallelCompact::adjust_roots() {
// Adjust the pointers to reflect the new locations
- TraceTime tm("adjust roots", print_phases(), true, gclog_or_tty);
+ GCTraceTime tm("adjust roots", print_phases(), true, &_gc_timer);
// Need new claim bits when tracing through and adjusting pointers.
ClassLoaderDataGraph::clear_claimed_marks();
@@ -2482,7 +2508,7 @@ void PSParallelCompact::adjust_roots() {
void PSParallelCompact::enqueue_region_draining_tasks(GCTaskQueue* q,
uint parallel_gc_threads)
{
- TraceTime tm("drain task setup", print_phases(), true, gclog_or_tty);
+ GCTraceTime tm("drain task setup", print_phases(), true, &_gc_timer);
// Find the threads that are active
unsigned int which = 0;
@@ -2556,7 +2582,7 @@ void PSParallelCompact::enqueue_region_draining_tasks(GCTaskQueue* q,
void PSParallelCompact::enqueue_dense_prefix_tasks(GCTaskQueue* q,
uint parallel_gc_threads) {
- TraceTime tm("dense prefix task setup", print_phases(), true, gclog_or_tty);
+ GCTraceTime tm("dense prefix task setup", print_phases(), true, &_gc_timer);
ParallelCompactData& sd = PSParallelCompact::summary_data();
@@ -2638,7 +2664,7 @@ void PSParallelCompact::enqueue_region_stealing_tasks(
GCTaskQueue* q,
ParallelTaskTerminator* terminator_ptr,
uint parallel_gc_threads) {
- TraceTime tm("steal task setup", print_phases(), true, gclog_or_tty);
+ GCTraceTime tm("steal task setup", print_phases(), true, &_gc_timer);
// Once a thread has drained it's stack, it should try to steal regions from
// other threads.
@@ -2686,7 +2712,7 @@ void PSParallelCompact::write_block_fill_histogram(outputStream* const out)
void PSParallelCompact::compact() {
// trace("5");
- TraceTime tm("compaction phase", print_phases(), true, gclog_or_tty);
+ GCTraceTime tm("compaction phase", print_phases(), true, &_gc_timer);
ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
@@ -2703,7 +2729,7 @@ void PSParallelCompact::compact() {
enqueue_region_stealing_tasks(q, &terminator, active_gc_threads);
{
- TraceTime tm_pc("par compact", print_phases(), true, gclog_or_tty);
+ GCTraceTime tm_pc("par compact", print_phases(), true, &_gc_timer);
gc_task_manager()->execute_and_wait(q);
@@ -2717,7 +2743,7 @@ void PSParallelCompact::compact() {
{
// Update the deferred objects, if any. Any compaction manager can be used.
- TraceTime tm_du("deferred updates", print_phases(), true, gclog_or_tty);
+ GCTraceTime tm_du("deferred updates", print_phases(), true, &_gc_timer);
ParCompactionManager* cm = ParCompactionManager::manager_array(0);
for (unsigned int id = old_space_id; id < last_space_id; ++id) {
update_deferred_objects(cm, SpaceId(id));
diff --git a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp
index c3a00c7e2..2ba4eb45f 100644
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp
+++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp
@@ -46,6 +46,8 @@ class GCTaskQueue;
class PreGCValues;
class MoveAndUpdateClosure;
class RefProcTaskExecutor;
+class ParallelOldTracer;
+class STWGCTimer;
// The SplitInfo class holds the information needed to 'split' a source region
// so that the live data can be copied to two destination *spaces*. Normally,
@@ -972,6 +974,8 @@ class PSParallelCompact : AllStatic {
friend class RefProcTaskProxy;
private:
+ static STWGCTimer _gc_timer;
+ static ParallelOldTracer _gc_tracer;
static elapsedTimer _accumulated_time;
static unsigned int _total_invocations;
static unsigned int _maximum_compaction_gc_num;
@@ -1015,7 +1019,8 @@ class PSParallelCompact : AllStatic {
// Mark live objects
static void marking_phase(ParCompactionManager* cm,
- bool maximum_heap_compaction);
+ bool maximum_heap_compaction,
+ ParallelOldTracer *gc_tracer);
template <class T>
static inline void follow_root(ParCompactionManager* cm, T* p);
@@ -1284,6 +1289,8 @@ class PSParallelCompact : AllStatic {
// Reference Processing
static ReferenceProcessor* const ref_processor() { return _ref_processor; }
+ static STWGCTimer* gc_timer() { return &_gc_timer; }
+
// Return the SpaceId for the given address.
static SpaceId space_id(HeapWord* addr);
diff --git a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp
index ee54e55bf..32929e7a5 100644
--- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp
+++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, 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_implementation/parallelScavenge/psOldGen.hpp"
#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp"
#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
#include "gc_implementation/shared/mutableSpace.hpp"
#include "memory/memRegion.hpp"
#include "oops/oop.inline.hpp"
@@ -49,7 +50,7 @@ void PSPromotionManager::initialize() {
guarantee(_manager_array != NULL, "Could not initialize promotion manager");
_stack_array_depth = new OopStarTaskQueueSet(ParallelGCThreads);
- guarantee(_stack_array_depth != NULL, "Cound not initialize promotion manager");
+ guarantee(_stack_array_depth != NULL, "Could not initialize promotion manager");
// Create and register the PSPromotionManager(s) for the worker threads.
for(uint i=0; i<ParallelGCThreads; i++) {
@@ -86,13 +87,20 @@ void PSPromotionManager::pre_scavenge() {
}
}
-void PSPromotionManager::post_scavenge() {
+bool PSPromotionManager::post_scavenge(YoungGCTracer& gc_tracer) {
+ bool promotion_failure_occurred = false;
+
TASKQUEUE_STATS_ONLY(if (PrintGCDetails && ParallelGCVerbose) print_stats());
for (uint i = 0; i < ParallelGCThreads + 1; i++) {
PSPromotionManager* manager = manager_array(i);
assert(manager->claimed_stack_depth()->is_empty(), "should be empty");
+ if (manager->_promotion_failed_info.has_failed()) {
+ gc_tracer.report_promotion_failed(manager->_promotion_failed_info);
+ promotion_failure_occurred = true;
+ }
manager->flush_labs();
}
+ return promotion_failure_occurred;
}
#if TASKQUEUE_STATS
@@ -187,6 +195,8 @@ void PSPromotionManager::reset() {
_old_lab.initialize(MemRegion(lab_base, (size_t)0));
_old_gen_is_full = false;
+ _promotion_failed_info.reset();
+
TASKQUEUE_STATS_ONLY(reset_stats());
}
@@ -305,6 +315,8 @@ oop PSPromotionManager::oop_promotion_failed(oop obj, markOop obj_mark) {
// We won any races, we "own" this object.
assert(obj == obj->forwardee(), "Sanity");
+ _promotion_failed_info.register_copy_failure(obj->size());
+
obj->push_contents(this);
// Save the mark if needed
diff --git a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp
index 0e429edc6..8f4731428 100644
--- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp
+++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,8 @@
#define SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSPROMOTIONMANAGER_HPP
#include "gc_implementation/parallelScavenge/psPromotionLAB.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
+#include "gc_implementation/shared/copyFailedInfo.hpp"
#include "memory/allocation.hpp"
#include "utilities/taskqueue.hpp"
@@ -33,7 +35,7 @@
// psPromotionManager is used by a single thread to manage object survival
// during a scavenge. The promotion manager contains thread local data only.
//
-// NOTE! Be carefull when allocating the stacks on cheap. If you are going
+// NOTE! Be careful when allocating the stacks on cheap. If you are going
// to use a promotion manager in more than one thread, the stacks MUST be
// on cheap. This can lead to memory leaks, though, as they are not auto
// deallocated.
@@ -85,6 +87,8 @@ class PSPromotionManager : public CHeapObj<mtGC> {
uint _array_chunk_size;
uint _min_array_size_for_chunking;
+ PromotionFailedInfo _promotion_failed_info;
+
// Accessors
static PSOldGen* old_gen() { return _old_gen; }
static MutableSpace* young_space() { return _young_space; }
@@ -149,7 +153,7 @@ class PSPromotionManager : public CHeapObj<mtGC> {
static void initialize();
static void pre_scavenge();
- static void post_scavenge();
+ static bool post_scavenge(YoungGCTracer& gc_tracer);
static PSPromotionManager* gc_thread_promotion_manager(int index);
static PSPromotionManager* vm_thread_promotion_manager();
diff --git a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp
index 96cd4cec7..841ef64f2 100644
--- a/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp
+++ b/src/share/vm/gc_implementation/parallelScavenge/psPromotionManager.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, 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
@@ -152,7 +152,7 @@ oop PSPromotionManager::copy_to_survivor_space(oop o) {
// This is the promotion failed test, and code handling.
// The code belongs here for two reasons. It is slightly
- // different thatn the code below, and cannot share the
+ // different than the code below, and cannot share the
// CAS testing code. Keeping the code here also minimizes
// the impact on the common case fast path code.
diff --git a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp
index 96a679a66..60c0267bb 100644
--- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp
+++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp
@@ -34,6 +34,10 @@
#include "gc_implementation/parallelScavenge/psParallelCompact.hpp"
#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp"
#include "gc_implementation/parallelScavenge/psTasks.hpp"
+#include "gc_implementation/shared/gcHeapSummary.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
#include "gc_implementation/shared/isGCActiveMark.hpp"
#include "gc_implementation/shared/spaceDecorator.hpp"
#include "gc_interface/gcCause.hpp"
@@ -63,10 +67,11 @@ uint PSScavenge::_tenuring_threshold = 0;
HeapWord* PSScavenge::_young_generation_boundary = NULL;
uintptr_t PSScavenge::_young_generation_boundary_compressed = 0;
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;
-bool PSScavenge::_promotion_failed = false;
// Define before use
class PSIsAliveClosure: public BoolObjectClosure {
@@ -259,6 +264,8 @@ bool PSScavenge::invoke_no_policy() {
assert(_preserved_mark_stack.is_empty(), "should be empty");
assert(_preserved_oop_stack.is_empty(), "should be empty");
+ _gc_timer.register_gc_start(os::elapsed_counter());
+
TimeStamp scavenge_entry;
TimeStamp scavenge_midpoint;
TimeStamp scavenge_exit;
@@ -278,11 +285,14 @@ bool PSScavenge::invoke_no_policy() {
return false;
}
+ _gc_tracer.report_gc_start(heap->gc_cause(), _gc_timer.gc_start());
+
bool promotion_failure_occurred = false;
PSYoungGen* young_gen = heap->young_gen();
PSOldGen* old_gen = heap->old_gen();
PSAdaptiveSizePolicy* size_policy = heap->size_policy();
+
heap->increment_total_collections();
AdaptiveSizePolicyOutput(size_policy, heap->total_collections());
@@ -299,12 +309,12 @@ bool PSScavenge::invoke_no_policy() {
}
heap->print_heap_before_gc();
+ heap->trace_heap_before_gc(&_gc_tracer);
assert(!NeverTenure || _tenuring_threshold == markOopDesc::max_age + 1, "Sanity");
assert(!AlwaysTenure || _tenuring_threshold == 0, "Sanity");
size_t prev_used = heap->used();
- assert(promotion_failed() == false, "Sanity");
// Fill in TLABs
heap->accumulate_statistics_all_tlabs();
@@ -321,7 +331,7 @@ bool PSScavenge::invoke_no_policy() {
gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps);
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
- TraceTime t1(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, gclog_or_tty);
+ GCTraceTime t1(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL);
TraceCollectorStats tcs(counters());
TraceMemoryManagerStats tms(false /* not full GC */,gc_cause);
@@ -387,7 +397,7 @@ bool PSScavenge::invoke_no_policy() {
// We'll use the promotion manager again later.
PSPromotionManager* promotion_manager = PSPromotionManager::vm_thread_promotion_manager();
{
- // TraceTime("Roots");
+ GCTraceTime tm("Scavenge", false, false, &_gc_timer);
ParallelScavengeHeap::ParStrongRootsScope psrs;
GCTaskQueue* q = GCTaskQueue::create();
@@ -429,36 +439,41 @@ bool PSScavenge::invoke_no_policy() {
// Process reference objects discovered during scavenge
{
+ GCTraceTime tm("References", false, false, &_gc_timer);
+
reference_processor()->setup_policy(false); // not always_clear
reference_processor()->set_active_mt_degree(active_workers);
PSKeepAliveClosure keep_alive(promotion_manager);
PSEvacuateFollowersClosure evac_followers(promotion_manager);
+ ReferenceProcessorStats stats;
if (reference_processor()->processing_is_mt()) {
PSRefProcTaskExecutor task_executor;
- reference_processor()->process_discovered_references(
- &_is_alive_closure, &keep_alive, &evac_followers, &task_executor);
+ stats = reference_processor()->process_discovered_references(
+ &_is_alive_closure, &keep_alive, &evac_followers, &task_executor,
+ &_gc_timer);
} else {
- reference_processor()->process_discovered_references(
- &_is_alive_closure, &keep_alive, &evac_followers, NULL);
+ stats = reference_processor()->process_discovered_references(
+ &_is_alive_closure, &keep_alive, &evac_followers, NULL, &_gc_timer);
}
- }
- // Enqueue reference objects discovered during scavenge.
- if (reference_processor()->processing_is_mt()) {
- PSRefProcTaskExecutor task_executor;
- reference_processor()->enqueue_discovered_references(&task_executor);
- } else {
- reference_processor()->enqueue_discovered_references(NULL);
+ _gc_tracer.report_gc_reference_stats(stats);
+
+ // Enqueue reference objects discovered during scavenge.
+ if (reference_processor()->processing_is_mt()) {
+ PSRefProcTaskExecutor task_executor;
+ reference_processor()->enqueue_discovered_references(&task_executor);
+ } else {
+ reference_processor()->enqueue_discovered_references(NULL);
+ }
}
+ GCTraceTime tm("StringTable", false, false, &_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);
// Finally, flush the promotion_manager's labs, and deallocate its stacks.
- PSPromotionManager::post_scavenge();
-
- promotion_failure_occurred = promotion_failed();
+ promotion_failure_occurred = PSPromotionManager::post_scavenge(_gc_tracer);
if (promotion_failure_occurred) {
clean_up_failed_promotion();
if (PrintGC) {
@@ -473,8 +488,6 @@ bool PSScavenge::invoke_no_policy() {
if (!promotion_failure_occurred) {
// Swap the survivor spaces.
-
-
young_gen->eden_space()->clear(SpaceDecorator::Mangle);
young_gen->from_space()->clear(SpaceDecorator::Mangle);
young_gen->swap_spaces();
@@ -612,7 +625,11 @@ bool PSScavenge::invoke_no_policy() {
NOT_PRODUCT(reference_processor()->verify_no_references_recorded());
- CodeCache::prune_scavenge_root_nmethods();
+ {
+ GCTraceTime tm("Prune Scavenge Root Methods", false, false, &_gc_timer);
+
+ CodeCache::prune_scavenge_root_nmethods();
+ }
// Re-verify object start arrays
if (VerifyObjectStartArray &&
@@ -652,6 +669,8 @@ bool PSScavenge::invoke_no_policy() {
}
heap->print_heap_after_gc();
+ heap->trace_heap_after_gc(&_gc_tracer);
+ _gc_tracer.report_tenuring_threshold(tenuring_threshold());
if (ZapUnusedHeapArea) {
young_gen->eden_space()->check_mangled_unused_area_complete();
@@ -672,6 +691,11 @@ bool PSScavenge::invoke_no_policy() {
ParallelTaskTerminator::print_termination_counts();
#endif
+
+ _gc_timer.register_gc_end(os::elapsed_counter());
+
+ _gc_tracer.report_gc_end(_gc_timer.gc_end(), _gc_timer.time_partitions());
+
return !promotion_failure_occurred;
}
@@ -681,7 +705,6 @@ bool PSScavenge::invoke_no_policy() {
void PSScavenge::clean_up_failed_promotion() {
ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity");
- assert(promotion_failed(), "Sanity");
PSYoungGen* young_gen = heap->young_gen();
@@ -706,7 +729,6 @@ void PSScavenge::clean_up_failed_promotion() {
// Clear the preserved mark and oop stack caches.
_preserved_mark_stack.clear(true);
_preserved_oop_stack.clear(true);
- _promotion_failed = false;
}
// Reset the PromotionFailureALot counters.
@@ -717,11 +739,10 @@ void PSScavenge::clean_up_failed_promotion() {
// 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 neccessary to preserve most markOops.
+// it is not necessary to preserve most markOops.
void PSScavenge::oop_promotion_failed(oop obj, markOop obj_mark) {
- _promotion_failed = true;
if (obj_mark->must_be_preserved_for_promotion_failure(obj)) {
- // Should use per-worker private stakcs hetre rather than
+ // Should use per-worker private stacks here rather than
// locking a common pair of stacks.
ThreadCritical tc;
_preserved_oop_stack.push(obj);
diff --git a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.hpp b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.hpp
index 7523f5bf6..896b705c2 100644
--- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.hpp
+++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, 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_implementation/parallelScavenge/cardTableExtension.hpp"
#include "gc_implementation/parallelScavenge/psVirtualspace.hpp"
#include "gc_implementation/shared/collectorCounters.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
#include "memory/allocation.hpp"
#include "oops/oop.hpp"
#include "utilities/stack.hpp"
@@ -37,8 +38,10 @@ class GCTaskQueue;
class OopStack;
class ReferenceProcessor;
class ParallelScavengeHeap;
+class ParallelScavengeTracer;
class PSIsAliveClosure;
class PSRefProcTaskExecutor;
+class STWGCTimer;
class PSScavenge: AllStatic {
friend class PSIsAliveClosure;
@@ -68,6 +71,8 @@ class PSScavenge: AllStatic {
static bool _survivor_overflow; // Overflow this collection
static uint _tenuring_threshold; // tenuring threshold for next scavenge
static elapsedTimer _accumulated_time; // total time spent on scavenge
+ static STWGCTimer _gc_timer; // GC time book keeper
+ static ParallelScavengeTracer _gc_tracer; // GC tracing
// The lowest address possible for the young_gen.
// This is used to decide if an oop should be scavenged,
// cards should be marked, etc.
@@ -77,7 +82,6 @@ class PSScavenge: AllStatic {
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 bool _promotion_failed;
static void clean_up_failed_promotion();
@@ -93,7 +97,6 @@ class PSScavenge: AllStatic {
// Accessors
static uint tenuring_threshold() { return _tenuring_threshold; }
static elapsedTimer* accumulated_time() { return &_accumulated_time; }
- static bool promotion_failed() { return _promotion_failed; }
static int consecutive_skipped_scavenges()
{ return _consecutive_skipped_scavenges; }
diff --git a/src/share/vm/gc_implementation/shared/copyFailedInfo.hpp b/src/share/vm/gc_implementation/shared/copyFailedInfo.hpp
new file mode 100644
index 000000000..2f30f5e8f
--- /dev/null
+++ b/src/share/vm/gc_implementation/shared/copyFailedInfo.hpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, 2013, 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_IMPLEMENTATION_SHARED_COPYFAILEDINFO_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_SHARED_COPYFAILEDINFO_HPP
+
+#include "runtime/thread.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class CopyFailedInfo : public CHeapObj<mtGC> {
+ size_t _first_size;
+ size_t _smallest_size;
+ size_t _total_size;
+ uint _count;
+
+ public:
+ CopyFailedInfo() : _first_size(0), _smallest_size(0), _total_size(0), _count(0) {}
+
+ virtual void register_copy_failure(size_t size) {
+ if (_first_size == 0) {
+ _first_size = size;
+ _smallest_size = size;
+ } else if (size < _smallest_size) {
+ _smallest_size = size;
+ }
+ _total_size += size;
+ _count++;
+ }
+
+ virtual void reset() {
+ _first_size = 0;
+ _smallest_size = 0;
+ _total_size = 0;
+ _count = 0;
+ }
+
+ bool has_failed() const { return _count != 0; }
+ size_t first_size() const { return _first_size; }
+ size_t smallest_size() const { return _smallest_size; }
+ size_t total_size() const { return _total_size; }
+ uint failed_count() const { return _count; }
+};
+
+class PromotionFailedInfo : public CopyFailedInfo {
+ OSThread* _thread;
+
+ public:
+ PromotionFailedInfo() : CopyFailedInfo(), _thread(NULL) {}
+
+ void register_copy_failure(size_t size) {
+ CopyFailedInfo::register_copy_failure(size);
+ if (_thread == NULL) {
+ _thread = Thread::current()->osthread();
+ } else {
+ assert(_thread == Thread::current()->osthread(), "The PromotionFailedInfo should be thread local.");
+ }
+ }
+
+ void reset() {
+ CopyFailedInfo::reset();
+ _thread = NULL;
+ }
+
+ OSThread* thread() const { return _thread; }
+};
+
+class EvacuationFailedInfo : public CopyFailedInfo {};
+
+#endif /* SHARE_VM_GC_IMPLEMENTATION_SHARED_COPYFAILEDINFO_HPP */
diff --git a/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp b/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp
new file mode 100644
index 000000000..4e79b8f93
--- /dev/null
+++ b/src/share/vm/gc_implementation/shared/gcHeapSummary.hpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2012, 2013, 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_IMPLEMENTATION_SHARED_GCHEAPSUMMARY_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_SHARED_GCHEAPSUMMARY_HPP
+
+#include "memory/allocation.hpp"
+
+class VirtualSpaceSummary : public StackObj {
+ HeapWord* _start;
+ HeapWord* _committed_end;
+ HeapWord* _reserved_end;
+public:
+ VirtualSpaceSummary() :
+ _start(NULL), _committed_end(NULL), _reserved_end(NULL) { }
+ VirtualSpaceSummary(HeapWord* start, HeapWord* committed_end, HeapWord* reserved_end) :
+ _start(start), _committed_end(committed_end), _reserved_end(reserved_end) { }
+
+ HeapWord* start() const { return _start; }
+ HeapWord* committed_end() const { return _committed_end; }
+ HeapWord* reserved_end() const { return _reserved_end; }
+ size_t committed_size() const { return (uintptr_t)_committed_end - (uintptr_t)_start; }
+ size_t reserved_size() const { return (uintptr_t)_reserved_end - (uintptr_t)_start; }
+};
+
+class SpaceSummary : public StackObj {
+ HeapWord* _start;
+ HeapWord* _end;
+ size_t _used;
+public:
+ SpaceSummary() :
+ _start(NULL), _end(NULL), _used(0) { }
+ SpaceSummary(HeapWord* start, HeapWord* end, size_t used) :
+ _start(start), _end(end), _used(used) { }
+
+ HeapWord* start() const { return _start; }
+ HeapWord* end() const { return _end; }
+ size_t used() const { return _used; }
+ size_t size() const { return (uintptr_t)_end - (uintptr_t)_start; }
+};
+
+class MetaspaceSizes : public StackObj {
+ size_t _capacity;
+ size_t _used;
+ size_t _reserved;
+
+ public:
+ MetaspaceSizes() : _capacity(0), _used(0), _reserved(0) {}
+ MetaspaceSizes(size_t capacity, size_t used, size_t reserved) :
+ _capacity(capacity), _used(used), _reserved(reserved) {}
+
+ size_t capacity() const { return _capacity; }
+ size_t used() const { return _used; }
+ size_t reserved() const { return _reserved; }
+};
+
+class GCHeapSummary;
+class PSHeapSummary;
+
+class GCHeapSummaryVisitor {
+ public:
+ virtual void visit(const GCHeapSummary* heap_summary) const = 0;
+ virtual void visit(const PSHeapSummary* heap_summary) const {}
+};
+
+class GCHeapSummary : public StackObj {
+ VirtualSpaceSummary _heap;
+ size_t _used;
+
+ public:
+ GCHeapSummary() :
+ _heap(), _used(0) { }
+ GCHeapSummary(VirtualSpaceSummary& heap_space, size_t used) :
+ _heap(heap_space), _used(used) { }
+
+ const VirtualSpaceSummary& heap() const { return _heap; }
+ size_t used() const { return _used; }
+
+ virtual void accept(GCHeapSummaryVisitor* visitor) const {
+ visitor->visit(this);
+ }
+};
+
+class PSHeapSummary : public GCHeapSummary {
+ VirtualSpaceSummary _old;
+ SpaceSummary _old_space;
+ VirtualSpaceSummary _young;
+ SpaceSummary _eden;
+ SpaceSummary _from;
+ SpaceSummary _to;
+ public:
+ PSHeapSummary(VirtualSpaceSummary& heap_space, size_t heap_used, VirtualSpaceSummary old, SpaceSummary old_space, VirtualSpaceSummary young, SpaceSummary eden, SpaceSummary from, SpaceSummary to) :
+ GCHeapSummary(heap_space, heap_used), _old(old), _old_space(old_space), _young(young), _eden(eden), _from(from), _to(to) { }
+ const VirtualSpaceSummary& old() const { return _old; }
+ const SpaceSummary& old_space() const { return _old_space; }
+ const VirtualSpaceSummary& young() const { return _young; }
+ const SpaceSummary& eden() const { return _eden; }
+ const SpaceSummary& from() const { return _from; }
+ const SpaceSummary& to() const { return _to; }
+
+ virtual void accept(GCHeapSummaryVisitor* visitor) const {
+ visitor->visit(this);
+ }
+};
+
+class MetaspaceSummary : public StackObj {
+ MetaspaceSizes _meta_space;
+ MetaspaceSizes _data_space;
+ MetaspaceSizes _class_space;
+
+ public:
+ MetaspaceSummary() : _meta_space(), _data_space(), _class_space() {}
+ MetaspaceSummary(const MetaspaceSizes& meta_space, const MetaspaceSizes& data_space, const MetaspaceSizes& class_space) :
+ _meta_space(meta_space), _data_space(data_space), _class_space(class_space) { }
+
+ const MetaspaceSizes& meta_space() const { return _meta_space; }
+ const MetaspaceSizes& data_space() const { return _data_space; }
+ const MetaspaceSizes& class_space() const { return _class_space; }
+};
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_GCHEAPSUMMARY_HPP
diff --git a/src/share/vm/gc_implementation/shared/gcTimer.cpp b/src/share/vm/gc_implementation/shared/gcTimer.cpp
new file mode 100644
index 000000000..6d011700c
--- /dev/null
+++ b/src/share/vm/gc_implementation/shared/gcTimer.cpp
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2012, 2013, 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_implementation/shared/gcTimer.hpp"
+#include "utilities/growableArray.hpp"
+
+void GCTimer::register_gc_start(jlong time) {
+ _time_partitions.clear();
+ _gc_start = time;
+}
+
+void GCTimer::register_gc_end(jlong time) {
+ assert(!_time_partitions.has_active_phases(),
+ "We should have ended all started phases, before ending the GC");
+
+ _gc_end = time;
+}
+
+void GCTimer::register_gc_pause_start(const char* name, jlong time) {
+ _time_partitions.report_gc_phase_start(name, time);
+}
+
+void GCTimer::register_gc_pause_end(jlong time) {
+ _time_partitions.report_gc_phase_end(time);
+}
+
+void GCTimer::register_gc_phase_start(const char* name, jlong time) {
+ _time_partitions.report_gc_phase_start(name, time);
+}
+
+void GCTimer::register_gc_phase_end(jlong time) {
+ _time_partitions.report_gc_phase_end(time);
+}
+
+
+void STWGCTimer::register_gc_start(jlong time) {
+ GCTimer::register_gc_start(time);
+ register_gc_pause_start("GC Pause", time);
+}
+
+void STWGCTimer::register_gc_end(jlong time) {
+ register_gc_pause_end(time);
+ GCTimer::register_gc_end(time);
+}
+
+void ConcurrentGCTimer::register_gc_pause_start(const char* name, jlong time) {
+ GCTimer::register_gc_pause_start(name, time);
+}
+
+void ConcurrentGCTimer::register_gc_pause_end(jlong time) {
+ GCTimer::register_gc_pause_end(time);
+}
+
+void PhasesStack::clear() {
+ _next_phase_level = 0;
+}
+
+void PhasesStack::push(int phase_index) {
+ assert(_next_phase_level < PHASE_LEVELS, "Overflow");
+
+ _phase_indices[_next_phase_level] = phase_index;
+
+ _next_phase_level++;
+}
+
+int PhasesStack::pop() {
+ assert(_next_phase_level > 0, "Underflow");
+
+ _next_phase_level--;
+
+ return _phase_indices[_next_phase_level];
+}
+
+int PhasesStack::count() const {
+ return _next_phase_level;
+}
+
+
+TimePartitions::TimePartitions() {
+ _phases = new (ResourceObj::C_HEAP, mtGC) GrowableArray<PausePhase>(INITIAL_CAPACITY, true, mtGC);
+ clear();
+}
+
+TimePartitions::~TimePartitions() {
+ delete _phases;
+ _phases = NULL;
+}
+
+void TimePartitions::clear() {
+ _phases->clear();
+ _active_phases.clear();
+ _sum_of_pauses = 0;
+ _longest_pause = 0;
+}
+
+void TimePartitions::report_gc_phase_start(const char* name, jlong time) {
+ assert(_phases->length() <= 1000, "Too many recored phases?");
+
+ int level = _active_phases.count();
+
+ PausePhase phase;
+ phase.set_level(level);
+ phase.set_name(name);
+ phase.set_start(time);
+
+ int index = _phases->append(phase);
+
+ _active_phases.push(index);
+}
+
+void TimePartitions::update_statistics(GCPhase* phase) {
+ // FIXME: This should only be done for pause phases
+ if (phase->level() == 0) {
+ jlong pause = phase->end() - phase->start();
+ _sum_of_pauses += pause;
+ _longest_pause = MAX2(pause, _longest_pause);
+ }
+}
+
+void TimePartitions::report_gc_phase_end(jlong time) {
+ int phase_index = _active_phases.pop();
+ GCPhase* phase = _phases->adr_at(phase_index);
+ phase->set_end(time);
+ update_statistics(phase);
+}
+
+int TimePartitions::num_phases() const {
+ return _phases->length();
+}
+
+GCPhase* TimePartitions::phase_at(int index) const {
+ assert(index >= 0, "Out of bounds");
+ assert(index < _phases->length(), "Out of bounds");
+
+ return _phases->adr_at(index);
+}
+
+jlong TimePartitions::sum_of_pauses() {
+ return _sum_of_pauses;
+}
+
+jlong TimePartitions::longest_pause() {
+ return _longest_pause;
+}
+
+bool TimePartitions::has_active_phases() {
+ return _active_phases.count() > 0;
+}
+
+bool TimePartitionPhasesIterator::has_next() {
+ return _next < _time_partitions->num_phases();
+}
+
+GCPhase* TimePartitionPhasesIterator::next() {
+ assert(has_next(), "Must have phases left");
+ return _time_partitions->phase_at(_next++);
+}
+
+
+/////////////// Unit tests ///////////////
+
+#ifndef PRODUCT
+
+class TimePartitionPhasesIteratorTest {
+ public:
+ static void all() {
+ one_pause();
+ two_pauses();
+ one_sub_pause_phase();
+ many_sub_pause_phases();
+ many_sub_pause_phases2();
+ max_nested_pause_phases();
+ }
+
+ static void validate_pause_phase(GCPhase* phase, int level, const char* name, jlong start, jlong end) {
+ assert(phase->level() == level, "Incorrect level");
+ assert(strcmp(phase->name(), name) == 0, "Incorrect name");
+ assert(phase->start() == start, "Incorrect start");
+ assert(phase->end() == end, "Incorrect end");
+ }
+
+ static void one_pause() {
+ TimePartitions time_partitions;
+ time_partitions.report_gc_phase_start("PausePhase", 2);
+ time_partitions.report_gc_phase_end(8);
+
+ TimePartitionPhasesIterator iter(&time_partitions);
+
+ validate_pause_phase(iter.next(), 0, "PausePhase", 2, 8);
+ assert(time_partitions.sum_of_pauses() == 8-2, "Incorrect");
+ assert(time_partitions.longest_pause() == 8-2, "Incorrect");
+
+ assert(!iter.has_next(), "Too many elements");
+ }
+
+ static void two_pauses() {
+ TimePartitions time_partitions;
+ time_partitions.report_gc_phase_start("PausePhase1", 2);
+ time_partitions.report_gc_phase_end(3);
+ time_partitions.report_gc_phase_start("PausePhase2", 4);
+ time_partitions.report_gc_phase_end(6);
+
+ TimePartitionPhasesIterator iter(&time_partitions);
+
+ validate_pause_phase(iter.next(), 0, "PausePhase1", 2, 3);
+ validate_pause_phase(iter.next(), 0, "PausePhase2", 4, 6);
+
+ assert(time_partitions.sum_of_pauses() == 3, "Incorrect");
+ assert(time_partitions.longest_pause() == 2, "Incorrect");
+
+ assert(!iter.has_next(), "Too many elements");
+ }
+
+ static void one_sub_pause_phase() {
+ TimePartitions time_partitions;
+ time_partitions.report_gc_phase_start("PausePhase", 2);
+ time_partitions.report_gc_phase_start("SubPhase", 3);
+ time_partitions.report_gc_phase_end(4);
+ time_partitions.report_gc_phase_end(5);
+
+ TimePartitionPhasesIterator iter(&time_partitions);
+
+ validate_pause_phase(iter.next(), 0, "PausePhase", 2, 5);
+ validate_pause_phase(iter.next(), 1, "SubPhase", 3, 4);
+
+ assert(time_partitions.sum_of_pauses() == 3, "Incorrect");
+ assert(time_partitions.longest_pause() == 3, "Incorrect");
+
+ assert(!iter.has_next(), "Too many elements");
+ }
+
+ static void max_nested_pause_phases() {
+ TimePartitions time_partitions;
+ time_partitions.report_gc_phase_start("PausePhase", 2);
+ time_partitions.report_gc_phase_start("SubPhase1", 3);
+ time_partitions.report_gc_phase_start("SubPhase2", 4);
+ time_partitions.report_gc_phase_start("SubPhase3", 5);
+ time_partitions.report_gc_phase_end(6);
+ time_partitions.report_gc_phase_end(7);
+ time_partitions.report_gc_phase_end(8);
+ time_partitions.report_gc_phase_end(9);
+
+ TimePartitionPhasesIterator iter(&time_partitions);
+
+ validate_pause_phase(iter.next(), 0, "PausePhase", 2, 9);
+ validate_pause_phase(iter.next(), 1, "SubPhase1", 3, 8);
+ validate_pause_phase(iter.next(), 2, "SubPhase2", 4, 7);
+ validate_pause_phase(iter.next(), 3, "SubPhase3", 5, 6);
+
+ assert(time_partitions.sum_of_pauses() == 7, "Incorrect");
+ assert(time_partitions.longest_pause() == 7, "Incorrect");
+
+ assert(!iter.has_next(), "Too many elements");
+ }
+
+ static void many_sub_pause_phases() {
+ TimePartitions time_partitions;
+ time_partitions.report_gc_phase_start("PausePhase", 2);
+
+ time_partitions.report_gc_phase_start("SubPhase1", 3);
+ time_partitions.report_gc_phase_end(4);
+ time_partitions.report_gc_phase_start("SubPhase2", 5);
+ time_partitions.report_gc_phase_end(6);
+ time_partitions.report_gc_phase_start("SubPhase3", 7);
+ time_partitions.report_gc_phase_end(8);
+ time_partitions.report_gc_phase_start("SubPhase4", 9);
+ time_partitions.report_gc_phase_end(10);
+
+ time_partitions.report_gc_phase_end(11);
+
+ TimePartitionPhasesIterator iter(&time_partitions);
+
+ validate_pause_phase(iter.next(), 0, "PausePhase", 2, 11);
+ validate_pause_phase(iter.next(), 1, "SubPhase1", 3, 4);
+ validate_pause_phase(iter.next(), 1, "SubPhase2", 5, 6);
+ validate_pause_phase(iter.next(), 1, "SubPhase3", 7, 8);
+ validate_pause_phase(iter.next(), 1, "SubPhase4", 9, 10);
+
+ assert(time_partitions.sum_of_pauses() == 9, "Incorrect");
+ assert(time_partitions.longest_pause() == 9, "Incorrect");
+
+ assert(!iter.has_next(), "Too many elements");
+ }
+
+ static void many_sub_pause_phases2() {
+ TimePartitions time_partitions;
+ time_partitions.report_gc_phase_start("PausePhase", 2);
+
+ time_partitions.report_gc_phase_start("SubPhase1", 3);
+ time_partitions.report_gc_phase_start("SubPhase11", 4);
+ time_partitions.report_gc_phase_end(5);
+ time_partitions.report_gc_phase_start("SubPhase12", 6);
+ time_partitions.report_gc_phase_end(7);
+ time_partitions.report_gc_phase_end(8);
+ time_partitions.report_gc_phase_start("SubPhase2", 9);
+ time_partitions.report_gc_phase_start("SubPhase21", 10);
+ time_partitions.report_gc_phase_end(11);
+ time_partitions.report_gc_phase_start("SubPhase22", 12);
+ time_partitions.report_gc_phase_end(13);
+ time_partitions.report_gc_phase_end(14);
+ time_partitions.report_gc_phase_start("SubPhase3", 15);
+ time_partitions.report_gc_phase_end(16);
+
+ time_partitions.report_gc_phase_end(17);
+
+ TimePartitionPhasesIterator iter(&time_partitions);
+
+ validate_pause_phase(iter.next(), 0, "PausePhase", 2, 17);
+ validate_pause_phase(iter.next(), 1, "SubPhase1", 3, 8);
+ validate_pause_phase(iter.next(), 2, "SubPhase11", 4, 5);
+ validate_pause_phase(iter.next(), 2, "SubPhase12", 6, 7);
+ validate_pause_phase(iter.next(), 1, "SubPhase2", 9, 14);
+ validate_pause_phase(iter.next(), 2, "SubPhase21", 10, 11);
+ validate_pause_phase(iter.next(), 2, "SubPhase22", 12, 13);
+ validate_pause_phase(iter.next(), 1, "SubPhase3", 15, 16);
+
+ assert(time_partitions.sum_of_pauses() == 15, "Incorrect");
+ assert(time_partitions.longest_pause() == 15, "Incorrect");
+
+ assert(!iter.has_next(), "Too many elements");
+ }
+};
+
+class GCTimerTest {
+public:
+ static void all() {
+ gc_start();
+ gc_end();
+ }
+
+ static void gc_start() {
+ GCTimer gc_timer;
+ gc_timer.register_gc_start(1);
+
+ assert(gc_timer.gc_start() == 1, "Incorrect");
+ }
+
+ static void gc_end() {
+ GCTimer gc_timer;
+ gc_timer.register_gc_start(1);
+ gc_timer.register_gc_end(2);
+
+ assert(gc_timer.gc_end() == 2, "Incorrect");
+ }
+};
+
+void GCTimerAllTest::all() {
+ GCTimerTest::all();
+ TimePartitionPhasesIteratorTest::all();
+}
+
+#endif
diff --git a/src/share/vm/gc_implementation/shared/gcTimer.hpp b/src/share/vm/gc_implementation/shared/gcTimer.hpp
new file mode 100644
index 000000000..b29e7c544
--- /dev/null
+++ b/src/share/vm/gc_implementation/shared/gcTimer.hpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2012, 2013, 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_IMPLEMENTATION_SHARED_GCTIMER_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_SHARED_GCTIMER_HPP
+
+#include "memory/allocation.hpp"
+#include "prims/jni_md.h"
+#include "utilities/macros.hpp"
+
+class ConcurrentPhase;
+class GCPhase;
+class PausePhase;
+
+template <class E> class GrowableArray;
+
+class PhaseVisitor {
+ public:
+ virtual void visit(GCPhase* phase) = 0;
+ virtual void visit(PausePhase* phase) { visit((GCPhase*)phase); }
+ virtual void visit(ConcurrentPhase* phase) { visit((GCPhase*)phase); }
+};
+
+class GCPhase {
+ const char* _name;
+ int _level;
+ jlong _start;
+ jlong _end;
+
+ public:
+ void set_name(const char* name) { _name = name; }
+ const char* name() { return _name; }
+
+ int level() { return _level; }
+ void set_level(int level) { _level = level; }
+
+ jlong start() { return _start; }
+ void set_start(jlong time) { _start = time; }
+
+ jlong end() { return _end; }
+ void set_end(jlong time) { _end = time; }
+
+ virtual void accept(PhaseVisitor* visitor) = 0;
+};
+
+class PausePhase : public GCPhase {
+ public:
+ void accept(PhaseVisitor* visitor) {
+ visitor->visit(this);
+ }
+};
+
+class ConcurrentPhase : public GCPhase {
+ void accept(PhaseVisitor* visitor) {
+ visitor->visit(this);
+ }
+};
+
+class PhasesStack {
+ public:
+ // FIXME: Temporary set to 5 (used to be 4), since Reference processing needs it.
+ static const int PHASE_LEVELS = 5;
+
+ private:
+ int _phase_indices[PHASE_LEVELS];
+ int _next_phase_level;
+
+ public:
+ PhasesStack() { clear(); }
+ void clear();
+
+ void push(int phase_index);
+ int pop();
+ int count() const;
+};
+
+class TimePartitions {
+ static const int INITIAL_CAPACITY = 10;
+
+ // Currently we only support pause phases.
+ GrowableArray<PausePhase>* _phases;
+ PhasesStack _active_phases;
+
+ jlong _sum_of_pauses;
+ jlong _longest_pause;
+
+ public:
+ TimePartitions();
+ ~TimePartitions();
+ void clear();
+
+ void report_gc_phase_start(const char* name, jlong time);
+ void report_gc_phase_end(jlong time);
+
+ int num_phases() const;
+ GCPhase* phase_at(int index) const;
+
+ jlong sum_of_pauses();
+ jlong longest_pause();
+
+ bool has_active_phases();
+ private:
+ void update_statistics(GCPhase* phase);
+};
+
+class PhasesIterator {
+ public:
+ virtual bool has_next() = 0;
+ virtual GCPhase* next() = 0;
+};
+
+class GCTimer : public ResourceObj {
+ NOT_PRODUCT(friend class GCTimerTest;)
+ protected:
+ jlong _gc_start;
+ jlong _gc_end;
+ TimePartitions _time_partitions;
+
+ public:
+ virtual void register_gc_start(jlong time);
+ virtual void register_gc_end(jlong time);
+
+ void register_gc_phase_start(const char* name, jlong time);
+ void register_gc_phase_end(jlong time);
+
+ jlong gc_start() { return _gc_start; }
+ jlong gc_end() { return _gc_end; }
+
+ TimePartitions* time_partitions() { return &_time_partitions; }
+
+ long longest_pause();
+ long sum_of_pauses();
+
+ protected:
+ void register_gc_pause_start(const char* name, jlong time);
+ void register_gc_pause_end(jlong time);
+};
+
+class STWGCTimer : public GCTimer {
+ public:
+ virtual void register_gc_start(jlong time);
+ virtual void register_gc_end(jlong time);
+};
+
+class ConcurrentGCTimer : public GCTimer {
+ public:
+ void register_gc_pause_start(const char* name, jlong time);
+ void register_gc_pause_end(jlong time);
+};
+
+class TimePartitionPhasesIterator {
+ TimePartitions* _time_partitions;
+ int _next;
+
+ public:
+ TimePartitionPhasesIterator(TimePartitions* time_partitions) : _time_partitions(time_partitions), _next(0) { }
+
+ virtual bool has_next();
+ virtual GCPhase* next();
+};
+
+
+/////////////// Unit tests ///////////////
+
+#ifndef PRODUCT
+
+class GCTimerAllTest {
+ public:
+ static void all();
+};
+
+#endif
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_GCTIMER_HPP
diff --git a/src/share/vm/gc_implementation/shared/gcTrace.cpp b/src/share/vm/gc_implementation/shared/gcTrace.cpp
new file mode 100644
index 000000000..6c5367042
--- /dev/null
+++ b/src/share/vm/gc_implementation/shared/gcTrace.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2012, 2013, 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_implementation/shared/gcHeapSummary.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
+#include "gc_implementation/shared/copyFailedInfo.hpp"
+#include "memory/heapInspection.hpp"
+#include "memory/referenceProcessorStats.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+#if INCLUDE_ALL_GCS
+#include "gc_implementation/g1/evacuationInfo.hpp"
+#endif
+
+#define assert_unset_gc_id() assert(_shared_gc_info.id() == SharedGCInfo::UNSET_GCID, "GC already started?")
+#define assert_set_gc_id() assert(_shared_gc_info.id() != SharedGCInfo::UNSET_GCID, "GC not started?")
+
+static jlong GCTracer_next_gc_id = 0;
+static GCId create_new_gc_id() {
+ return GCTracer_next_gc_id++;
+}
+
+void GCTracer::report_gc_start_impl(GCCause::Cause cause, jlong timestamp) {
+ assert_unset_gc_id();
+
+ GCId gc_id = create_new_gc_id();
+ _shared_gc_info.set_id(gc_id);
+ _shared_gc_info.set_cause(cause);
+ _shared_gc_info.set_start_timestamp(timestamp);
+}
+
+void GCTracer::report_gc_start(GCCause::Cause cause, jlong timestamp) {
+ assert_unset_gc_id();
+
+ report_gc_start_impl(cause, timestamp);
+}
+
+bool GCTracer::has_reported_gc_start() const {
+ return _shared_gc_info.id() != SharedGCInfo::UNSET_GCID;
+}
+
+void GCTracer::report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions) {
+ assert_set_gc_id();
+
+ _shared_gc_info.set_sum_of_pauses(time_partitions->sum_of_pauses());
+ _shared_gc_info.set_longest_pause(time_partitions->longest_pause());
+ _shared_gc_info.set_end_timestamp(timestamp);
+
+ send_phase_events(time_partitions);
+ send_garbage_collection_event();
+}
+
+void GCTracer::report_gc_end(jlong timestamp, TimePartitions* time_partitions) {
+ assert_set_gc_id();
+
+ report_gc_end_impl(timestamp, time_partitions);
+
+ _shared_gc_info.set_id(SharedGCInfo::UNSET_GCID);
+}
+
+void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) const {
+ assert_set_gc_id();
+
+ send_reference_stats_event(REF_SOFT, rps.soft_count());
+ send_reference_stats_event(REF_WEAK, rps.weak_count());
+ send_reference_stats_event(REF_FINAL, rps.final_count());
+ send_reference_stats_event(REF_PHANTOM, rps.phantom_count());
+}
+
+#if INCLUDE_SERVICES
+void ObjectCountEventSenderClosure::do_cinfo(KlassInfoEntry* entry) {
+ if (should_send_event(entry)) {
+ send_event(entry);
+ }
+}
+
+void ObjectCountEventSenderClosure::send_event(KlassInfoEntry* entry) {
+ _gc_tracer->send_object_count_after_gc_event(entry->klass(), entry->count(),
+ entry->words() * BytesPerWord);
+}
+
+bool ObjectCountEventSenderClosure::should_send_event(KlassInfoEntry* entry) const {
+ double percentage_of_heap = ((double) entry->words()) / _total_size_in_words;
+ return percentage_of_heap > _size_threshold_percentage;
+}
+
+void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl) {
+ assert_set_gc_id();
+
+ if (should_send_object_count_after_gc_event()) {
+ ResourceMark rm;
+
+ KlassInfoTable cit(false);
+ if (!cit.allocation_failed()) {
+ HeapInspection hi(false, false, false, NULL);
+ hi.populate_table(&cit, is_alive_cl);
+
+ ObjectCountEventSenderClosure event_sender(this, cit.size_of_instances_in_words());
+ cit.iterate(&event_sender);
+ }
+ }
+}
+#endif
+
+void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary, const MetaspaceSummary& meta_space_summary) const {
+ assert_set_gc_id();
+
+ send_gc_heap_summary_event(when, heap_summary);
+ send_meta_space_summary_event(when, meta_space_summary);
+}
+
+void YoungGCTracer::report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions) {
+ assert_set_gc_id();
+ assert(_tenuring_threshold != UNSET_TENURING_THRESHOLD, "Tenuring threshold has not been reported");
+
+ GCTracer::report_gc_end_impl(timestamp, time_partitions);
+ send_young_gc_event();
+
+ _tenuring_threshold = UNSET_TENURING_THRESHOLD;
+}
+
+void YoungGCTracer::report_promotion_failed(const PromotionFailedInfo& pf_info) {
+ assert_set_gc_id();
+
+ send_promotion_failed_event(pf_info);
+}
+
+void YoungGCTracer::report_tenuring_threshold(const uint tenuring_threshold) {
+ _tenuring_threshold = tenuring_threshold;
+}
+
+void OldGCTracer::report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions) {
+ assert_set_gc_id();
+
+ GCTracer::report_gc_end_impl(timestamp, time_partitions);
+ send_old_gc_event();
+}
+
+void ParallelOldTracer::report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions) {
+ assert_set_gc_id();
+
+ OldGCTracer::report_gc_end_impl(timestamp, time_partitions);
+ send_parallel_old_event();
+}
+
+void ParallelOldTracer::report_dense_prefix(void* dense_prefix) {
+ assert_set_gc_id();
+
+ _parallel_old_gc_info.report_dense_prefix(dense_prefix);
+}
+
+void OldGCTracer::report_concurrent_mode_failure() {
+ assert_set_gc_id();
+
+ send_concurrent_mode_failure_event();
+}
+
+#if INCLUDE_ALL_GCS
+void G1NewTracer::report_yc_type(G1YCType type) {
+ assert_set_gc_id();
+
+ _g1_young_gc_info.set_type(type);
+}
+
+void G1NewTracer::report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions) {
+ assert_set_gc_id();
+
+ YoungGCTracer::report_gc_end_impl(timestamp, time_partitions);
+ send_g1_young_gc_event();
+}
+
+void G1NewTracer::report_evacuation_info(EvacuationInfo* info) {
+ assert_set_gc_id();
+
+ send_evacuation_info_event(info);
+}
+
+void G1NewTracer::report_evacuation_failed(EvacuationFailedInfo& ef_info) {
+ assert_set_gc_id();
+
+ send_evacuation_failed_event(ef_info);
+ ef_info.reset();
+}
+#endif
diff --git a/src/share/vm/gc_implementation/shared/gcTrace.hpp b/src/share/vm/gc_implementation/shared/gcTrace.hpp
new file mode 100644
index 000000000..29ee55b68
--- /dev/null
+++ b/src/share/vm/gc_implementation/shared/gcTrace.hpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2012, 2013, 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_IMPLEMENTATION_SHARED_GCTRACE_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_SHARED_GCTRACE_HPP
+
+#include "gc_interface/gcCause.hpp"
+#include "gc_interface/gcName.hpp"
+#include "gc_implementation/shared/gcWhen.hpp"
+#include "gc_implementation/shared/copyFailedInfo.hpp"
+#include "memory/allocation.hpp"
+#include "memory/klassInfoClosure.hpp"
+#include "memory/referenceType.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc_implementation/g1/g1YCTypes.hpp"
+#endif
+#include "utilities/macros.hpp"
+
+typedef uint GCId;
+
+class EvacuationInfo;
+class GCHeapSummary;
+class MetaspaceSummary;
+class PSHeapSummary;
+class ReferenceProcessorStats;
+class TimePartitions;
+class BoolObjectClosure;
+
+class SharedGCInfo VALUE_OBJ_CLASS_SPEC {
+ static const jlong UNSET_TIMESTAMP = -1;
+
+ public:
+ static const GCId UNSET_GCID = (GCId)-1;
+
+ private:
+ GCId _id;
+ GCName _name;
+ GCCause::Cause _cause;
+ jlong _start_timestamp;
+ jlong _end_timestamp;
+ jlong _sum_of_pauses;
+ jlong _longest_pause;
+
+ public:
+ SharedGCInfo(GCName name) : _id(UNSET_GCID), _name(name), _cause(GCCause::_last_gc_cause),
+ _start_timestamp(UNSET_TIMESTAMP), _end_timestamp(UNSET_TIMESTAMP), _sum_of_pauses(0), _longest_pause(0) {}
+
+ void set_id(GCId id) { _id = id; }
+ GCId id() const { return _id; }
+
+ void set_start_timestamp(jlong timestamp) { _start_timestamp = timestamp; }
+ jlong start_timestamp() const { return _start_timestamp; }
+
+ void set_end_timestamp(jlong timestamp) { _end_timestamp = timestamp; }
+ jlong end_timestamp() const { return _end_timestamp; }
+
+ void set_name(GCName name) { _name = name; }
+ GCName name() const { return _name; }
+
+ void set_cause(GCCause::Cause cause) { _cause = cause; }
+ GCCause::Cause cause() const { return _cause; }
+
+ void set_sum_of_pauses(jlong duration) { _sum_of_pauses = duration; }
+ jlong sum_of_pauses() const { return _sum_of_pauses; }
+
+ void set_longest_pause(jlong duration) { _longest_pause = duration; }
+ jlong longest_pause() const { return _longest_pause; }
+};
+
+class ParallelOldGCInfo VALUE_OBJ_CLASS_SPEC {
+ void* _dense_prefix;
+ public:
+ ParallelOldGCInfo() : _dense_prefix(NULL) {}
+ void report_dense_prefix(void* addr) {
+ _dense_prefix = addr;
+ }
+ void* dense_prefix() const { return _dense_prefix; }
+};
+
+#if INCLUDE_ALL_GCS
+
+class G1YoungGCInfo VALUE_OBJ_CLASS_SPEC {
+ G1YCType _type;
+ public:
+ G1YoungGCInfo() : _type(G1YCTypeEndSentinel) {}
+ void set_type(G1YCType type) {
+ _type = type;
+ }
+ G1YCType type() const { return _type; }
+};
+
+#endif // INCLUDE_ALL_GCS
+
+class GCTracer : public ResourceObj {
+ friend class ObjectCountEventSenderClosure;
+ protected:
+ SharedGCInfo _shared_gc_info;
+
+ public:
+ void report_gc_start(GCCause::Cause cause, jlong timestamp);
+ void report_gc_end(jlong timestamp, TimePartitions* time_partitions);
+ void report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary, const MetaspaceSummary& meta_space_summary) const;
+ void report_gc_reference_stats(const ReferenceProcessorStats& rp) const;
+ void report_object_count_after_gc(BoolObjectClosure* object_filter) NOT_SERVICES_RETURN;
+
+ bool has_reported_gc_start() const;
+
+ protected:
+ GCTracer(GCName name) : _shared_gc_info(name) {}
+ virtual void report_gc_start_impl(GCCause::Cause cause, jlong timestamp);
+ virtual void report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions);
+
+ private:
+ void send_garbage_collection_event() const;
+ void send_gc_heap_summary_event(GCWhen::Type when, const GCHeapSummary& heap_summary) const;
+ void send_meta_space_summary_event(GCWhen::Type when, const MetaspaceSummary& meta_space_summary) const;
+ void send_reference_stats_event(ReferenceType type, size_t count) const;
+ void send_phase_events(TimePartitions* time_partitions) const;
+ void send_object_count_after_gc_event(Klass* klass, jlong count, julong total_size) const NOT_SERVICES_RETURN;
+ bool should_send_object_count_after_gc_event() const;
+};
+
+class ObjectCountEventSenderClosure : public KlassInfoClosure {
+ GCTracer* _gc_tracer;
+ const double _size_threshold_percentage;
+ const size_t _total_size_in_words;
+ public:
+ ObjectCountEventSenderClosure(GCTracer* gc_tracer, size_t total_size_in_words) :
+ _gc_tracer(gc_tracer),
+ _size_threshold_percentage(ObjectCountCutOffPercent / 100),
+ _total_size_in_words(total_size_in_words)
+ {}
+ virtual void do_cinfo(KlassInfoEntry* entry);
+ protected:
+ virtual void send_event(KlassInfoEntry* entry);
+ private:
+ bool should_send_event(KlassInfoEntry* entry) const;
+};
+
+class YoungGCTracer : public GCTracer {
+ static const uint UNSET_TENURING_THRESHOLD = (uint) -1;
+
+ uint _tenuring_threshold;
+
+ protected:
+ YoungGCTracer(GCName name) : GCTracer(name), _tenuring_threshold(UNSET_TENURING_THRESHOLD) {}
+ virtual void report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions);
+
+ public:
+ void report_promotion_failed(const PromotionFailedInfo& pf_info);
+ void report_tenuring_threshold(const uint tenuring_threshold);
+
+ private:
+ void send_young_gc_event() const;
+ void send_promotion_failed_event(const PromotionFailedInfo& pf_info) const;
+};
+
+class OldGCTracer : public GCTracer {
+ protected:
+ OldGCTracer(GCName name) : GCTracer(name) {}
+ virtual void report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions);
+
+ public:
+ void report_concurrent_mode_failure();
+
+ private:
+ void send_old_gc_event() const;
+ void send_concurrent_mode_failure_event();
+};
+
+class ParallelOldTracer : public OldGCTracer {
+ ParallelOldGCInfo _parallel_old_gc_info;
+
+ public:
+ ParallelOldTracer() : OldGCTracer(ParallelOld) {}
+ void report_dense_prefix(void* dense_prefix);
+
+ protected:
+ void report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions);
+
+ private:
+ void send_parallel_old_event() const;
+};
+
+class SerialOldTracer : public OldGCTracer {
+ public:
+ SerialOldTracer() : OldGCTracer(SerialOld) {}
+};
+
+class ParallelScavengeTracer : public YoungGCTracer {
+ public:
+ ParallelScavengeTracer() : YoungGCTracer(ParallelScavenge) {}
+};
+
+class DefNewTracer : public YoungGCTracer {
+ public:
+ DefNewTracer() : YoungGCTracer(DefNew) {}
+};
+
+class ParNewTracer : public YoungGCTracer {
+ public:
+ ParNewTracer() : YoungGCTracer(ParNew) {}
+};
+
+#if INCLUDE_ALL_GCS
+class G1NewTracer : public YoungGCTracer {
+ G1YoungGCInfo _g1_young_gc_info;
+
+ public:
+ G1NewTracer() : YoungGCTracer(G1New) {}
+
+ void report_yc_type(G1YCType type);
+ void report_gc_end_impl(jlong timestamp, TimePartitions* time_partitions);
+ void report_evacuation_info(EvacuationInfo* info);
+ void report_evacuation_failed(EvacuationFailedInfo& ef_info);
+
+ private:
+ void send_g1_young_gc_event();
+ void send_evacuation_info_event(EvacuationInfo* info);
+ void send_evacuation_failed_event(const EvacuationFailedInfo& ef_info) const;
+};
+#endif
+
+class CMSTracer : public OldGCTracer {
+ public:
+ CMSTracer() : OldGCTracer(ConcurrentMarkSweep) {}
+};
+
+class G1OldTracer : public OldGCTracer {
+ public:
+ G1OldTracer() : OldGCTracer(G1Old) {}
+};
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_GCTRACE_HPP
diff --git a/src/share/vm/gc_implementation/shared/gcTraceSend.cpp b/src/share/vm/gc_implementation/shared/gcTraceSend.cpp
new file mode 100644
index 000000000..4af7e3c2f
--- /dev/null
+++ b/src/share/vm/gc_implementation/shared/gcTraceSend.cpp
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2012, 2013, 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_implementation/shared/gcHeapSummary.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
+#include "gc_implementation/shared/gcWhen.hpp"
+#include "gc_implementation/shared/copyFailedInfo.hpp"
+#include "trace/tracing.hpp"
+#include "trace/traceBackend.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc_implementation/g1/evacuationInfo.hpp"
+#include "gc_implementation/g1/g1YCTypes.hpp"
+#endif
+
+// All GC dependencies against the trace framework is contained within this file.
+
+typedef uintptr_t TraceAddress;
+
+void GCTracer::send_garbage_collection_event() const {
+ EventGCGarbageCollection event(UNTIMED);
+ if (event.should_commit()) {
+ event.set_gcId(_shared_gc_info.id());
+ event.set_name(_shared_gc_info.name());
+ event.set_cause((u2) _shared_gc_info.cause());
+ event.set_sumOfPauses(_shared_gc_info.sum_of_pauses());
+ event.set_longestPause(_shared_gc_info.longest_pause());
+ event.set_starttime(_shared_gc_info.start_timestamp());
+ event.set_endtime(_shared_gc_info.end_timestamp());
+ event.commit();
+ }
+}
+
+void GCTracer::send_reference_stats_event(ReferenceType type, size_t count) const {
+ EventGCReferenceStatistics e;
+ if (e.should_commit()) {
+ e.set_gcId(_shared_gc_info.id());
+ e.set_type((u1)type);
+ e.set_count(count);
+ e.commit();
+ }
+}
+
+void ParallelOldTracer::send_parallel_old_event() const {
+ EventGCParallelOld e(UNTIMED);
+ if (e.should_commit()) {
+ e.set_gcId(_shared_gc_info.id());
+ e.set_densePrefix((TraceAddress)_parallel_old_gc_info.dense_prefix());
+ e.set_starttime(_shared_gc_info.start_timestamp());
+ e.set_endtime(_shared_gc_info.end_timestamp());
+ e.commit();
+ }
+}
+
+void YoungGCTracer::send_young_gc_event() const {
+ EventGCYoungGarbageCollection e(UNTIMED);
+ if (e.should_commit()) {
+ e.set_gcId(_shared_gc_info.id());
+ e.set_tenuringThreshold(_tenuring_threshold);
+ e.set_starttime(_shared_gc_info.start_timestamp());
+ e.set_endtime(_shared_gc_info.end_timestamp());
+ e.commit();
+ }
+}
+
+void OldGCTracer::send_old_gc_event() const {
+ EventGCOldGarbageCollection e(UNTIMED);
+ if (e.should_commit()) {
+ e.set_gcId(_shared_gc_info.id());
+ e.set_starttime(_shared_gc_info.start_timestamp());
+ e.set_endtime(_shared_gc_info.end_timestamp());
+ e.commit();
+ }
+}
+
+static TraceStructCopyFailed to_trace_struct(const CopyFailedInfo& cf_info) {
+ TraceStructCopyFailed failed_info;
+ failed_info.set_objectCount(cf_info.failed_count());
+ failed_info.set_firstSize(cf_info.first_size());
+ failed_info.set_smallestSize(cf_info.smallest_size());
+ failed_info.set_totalSize(cf_info.total_size());
+ return failed_info;
+}
+
+void YoungGCTracer::send_promotion_failed_event(const PromotionFailedInfo& pf_info) const {
+ EventPromotionFailed e;
+ if (e.should_commit()) {
+ e.set_gcId(_shared_gc_info.id());
+ e.set_data(to_trace_struct(pf_info));
+ e.set_thread(pf_info.thread()->thread_id());
+ e.commit();
+ }
+}
+
+// Common to CMS and G1
+void OldGCTracer::send_concurrent_mode_failure_event() {
+ EventConcurrentModeFailure e;
+ if (e.should_commit()) {
+ e.set_gcId(_shared_gc_info.id());
+ e.commit();
+ }
+}
+
+#if INCLUDE_SERVICES
+void GCTracer::send_object_count_after_gc_event(Klass* klass, jlong count, julong total_size) const {
+ EventObjectCountAfterGC e;
+ if (e.should_commit()) {
+ e.set_gcId(_shared_gc_info.id());
+ e.set_class(klass);
+ e.set_count(count);
+ e.set_totalSize(total_size);
+ e.commit();
+ }
+}
+#endif
+
+bool GCTracer::should_send_object_count_after_gc_event() const {
+#if INCLUDE_TRACE
+ return Tracing::is_event_enabled(EventObjectCountAfterGC::eventId);
+#else
+ return false;
+#endif
+}
+
+#if INCLUDE_ALL_GCS
+void G1NewTracer::send_g1_young_gc_event() {
+ EventGCG1GarbageCollection e(UNTIMED);
+ if (e.should_commit()) {
+ e.set_gcId(_shared_gc_info.id());
+ e.set_type(_g1_young_gc_info.type());
+ e.set_starttime(_shared_gc_info.start_timestamp());
+ e.set_endtime(_shared_gc_info.end_timestamp());
+ e.commit();
+ }
+}
+
+void G1NewTracer::send_evacuation_info_event(EvacuationInfo* info) {
+ EventEvacuationInfo e;
+ if (e.should_commit()) {
+ e.set_gcId(_shared_gc_info.id());
+ e.set_cSetRegions(info->collectionset_regions());
+ e.set_cSetUsedBefore(info->collectionset_used_before());
+ e.set_cSetUsedAfter(info->collectionset_used_after());
+ e.set_allocationRegions(info->allocation_regions());
+ e.set_allocRegionsUsedBefore(info->alloc_regions_used_before());
+ e.set_allocRegionsUsedAfter(info->alloc_regions_used_before() + info->bytes_copied());
+ e.set_bytesCopied(info->bytes_copied());
+ e.set_regionsFreed(info->regions_freed());
+ e.commit();
+ }
+}
+
+void G1NewTracer::send_evacuation_failed_event(const EvacuationFailedInfo& ef_info) const {
+ EventEvacuationFailed e;
+ if (e.should_commit()) {
+ e.set_gcId(_shared_gc_info.id());
+ e.set_data(to_trace_struct(ef_info));
+ e.commit();
+ }
+}
+#endif
+
+static TraceStructVirtualSpace to_trace_struct(const VirtualSpaceSummary& summary) {
+ TraceStructVirtualSpace space;
+ space.set_start((TraceAddress)summary.start());
+ space.set_committedEnd((TraceAddress)summary.committed_end());
+ space.set_committedSize(summary.committed_size());
+ space.set_reservedEnd((TraceAddress)summary.reserved_end());
+ space.set_reservedSize(summary.reserved_size());
+ return space;
+}
+
+static TraceStructObjectSpace to_trace_struct(const SpaceSummary& summary) {
+ TraceStructObjectSpace space;
+ space.set_start((TraceAddress)summary.start());
+ space.set_end((TraceAddress)summary.end());
+ space.set_used(summary.used());
+ space.set_size(summary.size());
+ return space;
+}
+
+class GCHeapSummaryEventSender : public GCHeapSummaryVisitor {
+ GCId _id;
+ GCWhen::Type _when;
+ public:
+ GCHeapSummaryEventSender(GCId id, GCWhen::Type when) : _id(id), _when(when) {}
+
+ void visit(const GCHeapSummary* heap_summary) const {
+ const VirtualSpaceSummary& heap_space = heap_summary->heap();
+
+ EventGCHeapSummary e;
+ if (e.should_commit()) {
+ e.set_gcId(_id);
+ e.set_when((u1)_when);
+ e.set_heapSpace(to_trace_struct(heap_space));
+ e.set_heapUsed(heap_summary->used());
+ e.commit();
+ }
+ }
+
+ void visit(const PSHeapSummary* ps_heap_summary) const {
+ visit((GCHeapSummary*)ps_heap_summary);
+
+ const VirtualSpaceSummary& old_summary = ps_heap_summary->old();
+ const SpaceSummary& old_space = ps_heap_summary->old_space();
+ const VirtualSpaceSummary& young_summary = ps_heap_summary->young();
+ const SpaceSummary& eden_space = ps_heap_summary->eden();
+ const SpaceSummary& from_space = ps_heap_summary->from();
+ const SpaceSummary& to_space = ps_heap_summary->to();
+
+ EventPSHeapSummary e;
+ if (e.should_commit()) {
+ e.set_gcId(_id);
+ e.set_when((u1)_when);
+
+ e.set_oldSpace(to_trace_struct(ps_heap_summary->old()));
+ e.set_oldObjectSpace(to_trace_struct(ps_heap_summary->old_space()));
+ e.set_youngSpace(to_trace_struct(ps_heap_summary->young()));
+ e.set_edenSpace(to_trace_struct(ps_heap_summary->eden()));
+ e.set_fromSpace(to_trace_struct(ps_heap_summary->from()));
+ e.set_toSpace(to_trace_struct(ps_heap_summary->to()));
+ e.commit();
+ }
+ }
+};
+
+void GCTracer::send_gc_heap_summary_event(GCWhen::Type when, const GCHeapSummary& heap_summary) const {
+ GCHeapSummaryEventSender visitor(_shared_gc_info.id(), when);
+ heap_summary.accept(&visitor);
+}
+
+static TraceStructMetaspaceSizes to_trace_struct(const MetaspaceSizes& sizes) {
+ TraceStructMetaspaceSizes meta_sizes;
+
+ meta_sizes.set_capacity(sizes.capacity());
+ meta_sizes.set_used(sizes.used());
+ meta_sizes.set_reserved(sizes.reserved());
+
+ return meta_sizes;
+}
+
+void GCTracer::send_meta_space_summary_event(GCWhen::Type when, const MetaspaceSummary& meta_space_summary) const {
+ EventMetaspaceSummary e;
+ if (e.should_commit()) {
+ e.set_gcId(_shared_gc_info.id());
+ e.set_when((u1) when);
+ e.set_metaspace(to_trace_struct(meta_space_summary.meta_space()));
+ e.set_dataSpace(to_trace_struct(meta_space_summary.data_space()));
+ e.set_classSpace(to_trace_struct(meta_space_summary.class_space()));
+ e.commit();
+ }
+}
+
+class PhaseSender : public PhaseVisitor {
+ GCId _gc_id;
+ public:
+ PhaseSender(GCId gc_id) : _gc_id(gc_id) {}
+
+ template<typename T>
+ void send_phase(PausePhase* pause) {
+ T event(UNTIMED);
+ if (event.should_commit()) {
+ event.set_gcId(_gc_id);
+ event.set_name(pause->name());
+ event.set_starttime(pause->start());
+ event.set_endtime(pause->end());
+ event.commit();
+ }
+ }
+
+ void visit(GCPhase* pause) { ShouldNotReachHere(); }
+ void visit(ConcurrentPhase* pause) { Unimplemented(); }
+ void visit(PausePhase* pause) {
+ assert(PhasesStack::PHASE_LEVELS == 5, "Need more event types");
+
+ switch (pause->level()) {
+ case 0: send_phase<EventGCPhasePause>(pause); break;
+ case 1: send_phase<EventGCPhasePauseLevel1>(pause); break;
+ case 2: send_phase<EventGCPhasePauseLevel2>(pause); break;
+ case 3: send_phase<EventGCPhasePauseLevel3>(pause); break;
+ default: /* Ignore sending this phase */ break;
+ }
+ }
+
+#undef send_phase
+};
+
+void GCTracer::send_phase_events(TimePartitions* time_partitions) const {
+ PhaseSender phase_reporter(_shared_gc_info.id());
+
+ TimePartitionPhasesIterator iter(time_partitions);
+ while (iter.has_next()) {
+ GCPhase* phase = iter.next();
+ phase->accept(&phase_reporter);
+ }
+}
diff --git a/src/share/vm/gc_implementation/shared/gcTraceTime.cpp b/src/share/vm/gc_implementation/shared/gcTraceTime.cpp
new file mode 100644
index 000000000..1c137047c
--- /dev/null
+++ b/src/share/vm/gc_implementation/shared/gcTraceTime.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2012, 2013, 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_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/os.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/thread.inline.hpp"
+#include "runtime/timer.hpp"
+#include "utilities/ostream.hpp"
+
+
+GCTraceTime::GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer) :
+ _title(title), _doit(doit), _print_cr(print_cr), _timer(timer) {
+ if (_doit || _timer != NULL) {
+ _start_counter = os::elapsed_counter();
+ }
+
+ if (_timer != NULL) {
+ assert(SafepointSynchronize::is_at_safepoint(), "Tracing currently only supported at safepoints");
+ assert(Thread::current()->is_VM_thread(), "Tracing currently only supported from the VM thread");
+
+ _timer->register_gc_phase_start(title, _start_counter);
+ }
+
+ if (_doit) {
+ if (PrintGCTimeStamps) {
+ gclog_or_tty->stamp();
+ gclog_or_tty->print(": ");
+ }
+ gclog_or_tty->print("[%s", title);
+ gclog_or_tty->flush();
+ }
+}
+
+GCTraceTime::~GCTraceTime() {
+ jlong stop_counter = 0;
+
+ if (_doit || _timer != NULL) {
+ stop_counter = os::elapsed_counter();
+ }
+
+ if (_timer != NULL) {
+ _timer->register_gc_phase_end(stop_counter);
+ }
+
+ if (_doit) {
+ double seconds = TimeHelper::counter_to_seconds(stop_counter - _start_counter);
+ if (_print_cr) {
+ gclog_or_tty->print_cr(", %3.7f secs]", seconds);
+ } else {
+ gclog_or_tty->print(", %3.7f secs]", seconds);
+ }
+ gclog_or_tty->flush();
+ }
+}
diff --git a/src/share/vm/gc_implementation/shared/gcTraceTime.hpp b/src/share/vm/gc_implementation/shared/gcTraceTime.hpp
new file mode 100644
index 000000000..5d92b4d33
--- /dev/null
+++ b/src/share/vm/gc_implementation/shared/gcTraceTime.hpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012, 2013, 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_IMPLEMENTATION_SHARED_GCTRACETIME_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_SHARED_GCTRACETIME_HPP
+
+#include "prims/jni_md.h"
+
+class GCTimer;
+
+class GCTraceTime {
+ const char* _title;
+ bool _doit;
+ bool _print_cr;
+ GCTimer* _timer;
+ jlong _start_counter;
+
+ public:
+ GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer);
+ ~GCTraceTime();
+};
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_GCTRACETIME_HPP
diff --git a/src/share/vm/gc_implementation/shared/gcWhen.hpp b/src/share/vm/gc_implementation/shared/gcWhen.hpp
new file mode 100644
index 000000000..5713ba4e8
--- /dev/null
+++ b/src/share/vm/gc_implementation/shared/gcWhen.hpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, 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_IMPLEMENTATION_SHARED_GCWHEN_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_SHARED_GCWHEN_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/debug.hpp"
+
+class GCWhen : AllStatic {
+ public:
+ enum Type {
+ BeforeGC,
+ AfterGC,
+ GCWhenEndSentinel
+ };
+
+ static const char* to_string(GCWhen::Type when) {
+ switch (when) {
+ case BeforeGC: return "Before GC";
+ case AfterGC: return "After GC";
+ default: ShouldNotReachHere(); return NULL;
+ }
+ }
+};
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_SHARED_GCWHEN_HPP
diff --git a/src/share/vm/gc_implementation/shared/markSweep.cpp b/src/share/vm/gc_implementation/shared/markSweep.cpp
index 1a977bbce..7bdcd55f5 100644
--- a/src/share/vm/gc_implementation/shared/markSweep.cpp
+++ b/src/share/vm/gc_implementation/shared/markSweep.cpp
@@ -24,6 +24,8 @@
#include "precompiled.hpp"
#include "compiler/compileBroker.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
#include "gc_implementation/shared/markSweep.inline.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "oops/methodData.hpp"
@@ -41,6 +43,8 @@ size_t MarkSweep::_preserved_count = 0;
size_t MarkSweep::_preserved_count_max = 0;
PreservedMark* MarkSweep::_preserved_marks = NULL;
ReferenceProcessor* MarkSweep::_ref_processor = NULL;
+STWGCTimer* MarkSweep::_gc_timer = NULL;
+SerialOldTracer* MarkSweep::_gc_tracer = NULL;
MarkSweep::FollowRootClosure MarkSweep::follow_root_closure;
CodeBlobToOopClosure MarkSweep::follow_code_root_closure(&MarkSweep::follow_root_closure, /*do_marking=*/ true);
@@ -173,7 +177,10 @@ MarkSweep::KeepAliveClosure MarkSweep::keep_alive;
void MarkSweep::KeepAliveClosure::do_oop(oop* p) { MarkSweep::KeepAliveClosure::do_oop_work(p); }
void MarkSweep::KeepAliveClosure::do_oop(narrowOop* p) { MarkSweep::KeepAliveClosure::do_oop_work(p); }
-void marksweep_init() { /* empty */ }
+void marksweep_init() {
+ MarkSweep::_gc_timer = new (ResourceObj::C_HEAP, mtGC) STWGCTimer();
+ MarkSweep::_gc_tracer = new (ResourceObj::C_HEAP, mtGC) SerialOldTracer();
+}
#ifndef PRODUCT
diff --git a/src/share/vm/gc_implementation/shared/markSweep.hpp b/src/share/vm/gc_implementation/shared/markSweep.hpp
index ab5e6ef32..2c08a6897 100644
--- a/src/share/vm/gc_implementation/shared/markSweep.hpp
+++ b/src/share/vm/gc_implementation/shared/markSweep.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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,6 +36,8 @@
class ReferenceProcessor;
class DataLayout;
+class SerialOldTracer;
+class STWGCTimer;
// MarkSweep takes care of global mark-compact garbage collection for a
// GenCollectedHeap using a four-phase pointer forwarding algorithm. All
@@ -128,6 +130,9 @@ class MarkSweep : AllStatic {
// Reference processing (used in ...follow_contents)
static ReferenceProcessor* _ref_processor;
+ static STWGCTimer* _gc_timer;
+ static SerialOldTracer* _gc_tracer;
+
// Non public closures
static KeepAliveClosure keep_alive;
@@ -151,6 +156,9 @@ class MarkSweep : AllStatic {
// Reference Processing
static ReferenceProcessor* const ref_processor() { return _ref_processor; }
+ static STWGCTimer* gc_timer() { return _gc_timer; }
+ static SerialOldTracer* gc_tracer() { return _gc_tracer; }
+
// Call backs for marking
static void mark_object(oop obj);
// Mark pointer and follow contents. Empty marking stack afterwards.
diff --git a/src/share/vm/gc_implementation/shared/vmGCOperations.cpp b/src/share/vm/gc_implementation/shared/vmGCOperations.cpp
index 211a084ab..31e6bddf4 100644
--- a/src/share/vm/gc_implementation/shared/vmGCOperations.cpp
+++ b/src/share/vm/gc_implementation/shared/vmGCOperations.cpp
@@ -145,32 +145,37 @@ bool VM_GC_HeapInspection::skip_operation() const {
return false;
}
+bool VM_GC_HeapInspection::collect() {
+ if (GC_locker::is_active()) {
+ return false;
+ }
+ Universe::heap()->collect_as_vm_thread(GCCause::_heap_inspection);
+ return true;
+}
+
void VM_GC_HeapInspection::doit() {
HandleMark hm;
- CollectedHeap* ch = Universe::heap();
- ch->ensure_parsability(false); // must happen, even if collection does
- // not happen (e.g. due to GC_locker)
+ Universe::heap()->ensure_parsability(false); // must happen, even if collection does
+ // not happen (e.g. due to GC_locker)
+ // or _full_gc being false
if (_full_gc) {
- // The collection attempt below would be skipped anyway if
- // the gc locker is held. The following dump may then be a tad
- // misleading to someone expecting only live objects to show
- // up in the dump (see CR 6944195). Just issue a suitable warning
- // in that case and do not attempt to do a collection.
- // The latter is a subtle point, because even a failed attempt
- // to GC will, in fact, induce one in the future, which we
- // probably want to avoid in this case because the GC that we may
- // be about to attempt holds value for us only
- // if it happens now and not if it happens in the eventual
- // future.
- if (GC_locker::is_active()) {
+ if (!collect()) {
+ // The collection attempt was skipped because the gc locker is held.
+ // The following dump may then be a tad misleading to someone expecting
+ // only live objects to show up in the dump (see CR 6944195). Just issue
+ // a suitable warning in that case and do not attempt to do a collection.
+ // The latter is a subtle point, because even a failed attempt
+ // to GC will, in fact, induce one in the future, which we
+ // probably want to avoid in this case because the GC that we may
+ // 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");
- } else {
- ch->collect_as_vm_thread(GCCause::_heap_inspection);
}
}
HeapInspection inspect(_csv_format, _print_help, _print_class_stats,
_columns);
- inspect.heap_inspection(_out, _need_prologue /* need_prologue */);
+ inspect.heap_inspection(_out);
}
diff --git a/src/share/vm/gc_implementation/shared/vmGCOperations.hpp b/src/share/vm/gc_implementation/shared/vmGCOperations.hpp
index 2a416f228..60b3a9679 100644
--- a/src/share/vm/gc_implementation/shared/vmGCOperations.hpp
+++ b/src/share/vm/gc_implementation/shared/vmGCOperations.hpp
@@ -129,21 +129,18 @@ class VM_GC_HeapInspection: public VM_GC_Operation {
private:
outputStream* _out;
bool _full_gc;
- bool _need_prologue;
bool _csv_format; // "comma separated values" format for spreadsheet.
bool _print_help;
bool _print_class_stats;
const char* _columns;
public:
- VM_GC_HeapInspection(outputStream* out, bool request_full_gc,
- bool need_prologue) :
+ VM_GC_HeapInspection(outputStream* out, bool request_full_gc) :
VM_GC_Operation(0 /* total collections, dummy, ignored */,
GCCause::_heap_inspection /* GC Cause */,
0 /* total full collections, dummy, ignored */,
request_full_gc) {
_out = out;
_full_gc = request_full_gc;
- _need_prologue = need_prologue;
_csv_format = false;
_print_help = false;
_print_class_stats = false;
@@ -159,6 +156,8 @@ class VM_GC_HeapInspection: public VM_GC_Operation {
void set_print_help(bool value) {_print_help = value;}
void set_print_class_stats(bool value) {_print_class_stats = value;}
void set_columns(const char* value) {_columns = value;}
+ protected:
+ bool collect();
};
diff --git a/src/share/vm/gc_interface/allocTracer.cpp b/src/share/vm/gc_interface/allocTracer.cpp
new file mode 100644
index 000000000..d3440cd85
--- /dev/null
+++ b/src/share/vm/gc_interface/allocTracer.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, 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_interface/allocTracer.hpp"
+#include "trace/tracing.hpp"
+#include "runtime/handles.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+void AllocTracer::send_allocation_outside_tlab_event(KlassHandle klass, size_t alloc_size) {
+ EventAllocObjectOutsideTLAB event;
+ if (event.should_commit()) {
+ event.set_class(klass());
+ event.set_allocationSize(alloc_size);
+ event.commit();
+ }
+}
+
+void AllocTracer::send_allocation_in_new_tlab_event(KlassHandle klass, size_t tlab_size, size_t alloc_size) {
+ EventAllocObjectInNewTLAB event;
+ if (event.should_commit()) {
+ event.set_class(klass());
+ event.set_allocationSize(alloc_size);
+ event.set_tlabSize(tlab_size);
+ event.commit();
+ }
+}
diff --git a/src/share/vm/gc_interface/allocTracer.hpp b/src/share/vm/gc_interface/allocTracer.hpp
new file mode 100644
index 000000000..33e6f19f3
--- /dev/null
+++ b/src/share/vm/gc_interface/allocTracer.hpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013, 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_INTERFACE_ALLOCTRACER_HPP
+#define SHARE_VM_GC_INTERFACE_ALLOCTRACER_HPP
+
+#include "memory/allocation.hpp"
+#include "runtime/handles.hpp"
+
+class AllocTracer : AllStatic {
+ public:
+ static void send_allocation_outside_tlab_event(KlassHandle klass, size_t alloc_size);
+ static void send_allocation_in_new_tlab_event(KlassHandle klass, size_t tlab_size, size_t alloc_size);
+};
+
+#endif /* SHARE_VM_GC_INTERFACE_ALLOCTRACER_HPP */
diff --git a/src/share/vm/gc_interface/collectedHeap.cpp b/src/share/vm/gc_interface/collectedHeap.cpp
index f6555979d..4c6c026e7 100644
--- a/src/share/vm/gc_interface/collectedHeap.cpp
+++ b/src/share/vm/gc_interface/collectedHeap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, 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,9 +24,15 @@
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
+#include "gc_implementation/shared/gcHeapSummary.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
+#include "gc_implementation/shared/gcWhen.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
+#include "gc_interface/allocTracer.hpp"
#include "gc_interface/collectedHeap.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
+#include "memory/metaspace.hpp"
#include "oops/oop.inline.hpp"
#include "oops/instanceMirrorKlass.hpp"
#include "runtime/init.hpp"
@@ -65,11 +71,71 @@ void GCHeapLog::log_heap(bool before) {
}
}
+VirtualSpaceSummary CollectedHeap::create_heap_space_summary() {
+ size_t capacity_in_words = capacity() / HeapWordSize;
+
+ return VirtualSpaceSummary(
+ reserved_region().start(), reserved_region().start() + capacity_in_words, reserved_region().end());
+}
+
+GCHeapSummary CollectedHeap::create_heap_summary() {
+ VirtualSpaceSummary heap_space = create_heap_space_summary();
+ return GCHeapSummary(heap_space, used());
+}
+
+MetaspaceSummary CollectedHeap::create_metaspace_summary() {
+ const MetaspaceSizes meta_space(
+ 0, /*MetaspaceAux::capacity_in_bytes(),*/
+ 0, /*MetaspaceAux::used_in_bytes(),*/
+ MetaspaceAux::reserved_in_bytes());
+ const MetaspaceSizes data_space(
+ 0, /*MetaspaceAux::capacity_in_bytes(Metaspace::NonClassType),*/
+ 0, /*MetaspaceAux::used_in_bytes(Metaspace::NonClassType),*/
+ MetaspaceAux::reserved_in_bytes(Metaspace::NonClassType));
+ const MetaspaceSizes class_space(
+ 0, /*MetaspaceAux::capacity_in_bytes(Metaspace::ClassType),*/
+ 0, /*MetaspaceAux::used_in_bytes(Metaspace::ClassType),*/
+ MetaspaceAux::reserved_in_bytes(Metaspace::ClassType));
+
+ return MetaspaceSummary(meta_space, data_space, class_space);
+}
+
+void CollectedHeap::print_heap_before_gc() {
+ if (PrintHeapAtGC) {
+ Universe::print_heap_before_gc();
+ }
+ if (_gc_heap_log != NULL) {
+ _gc_heap_log->log_heap_before();
+ }
+}
+
+void CollectedHeap::print_heap_after_gc() {
+ if (PrintHeapAtGC) {
+ Universe::print_heap_after_gc();
+ }
+ if (_gc_heap_log != NULL) {
+ _gc_heap_log->log_heap_after();
+ }
+}
+
+void CollectedHeap::trace_heap(GCWhen::Type when, GCTracer* gc_tracer) {
+ const GCHeapSummary& heap_summary = create_heap_summary();
+ const MetaspaceSummary& metaspace_summary = create_metaspace_summary();
+ gc_tracer->report_gc_heap_summary(when, heap_summary, metaspace_summary);
+}
+
+void CollectedHeap::trace_heap_before_gc(GCTracer* gc_tracer) {
+ trace_heap(GCWhen::BeforeGC, gc_tracer);
+}
+
+void CollectedHeap::trace_heap_after_gc(GCTracer* gc_tracer) {
+ trace_heap(GCWhen::AfterGC, gc_tracer);
+}
+
// Memory state functions.
CollectedHeap::CollectedHeap() : _n_par_threads(0)
-
{
const size_t max_len = size_t(arrayOopDesc::max_array_length(T_INT));
const size_t elements_per_word = HeapWordSize / sizeof(jint);
@@ -185,7 +251,7 @@ void CollectedHeap::check_for_valid_allocation_state() {
}
#endif
-HeapWord* CollectedHeap::allocate_from_tlab_slow(Thread* thread, size_t size) {
+HeapWord* CollectedHeap::allocate_from_tlab_slow(KlassHandle klass, Thread* thread, size_t size) {
// Retain tlab and allocate object in shared space if
// the amount free in the tlab is too large to discard.
@@ -209,6 +275,9 @@ HeapWord* CollectedHeap::allocate_from_tlab_slow(Thread* thread, size_t size) {
if (obj == NULL) {
return NULL;
}
+
+ AllocTracer::send_allocation_in_new_tlab_event(klass, new_tlab_size * HeapWordSize, size * HeapWordSize);
+
if (ZeroTLAB) {
// ..and clear it.
Copy::zero_to_words(obj, new_tlab_size);
@@ -458,28 +527,28 @@ void CollectedHeap::resize_all_tlabs() {
}
}
-void CollectedHeap::pre_full_gc_dump() {
+void CollectedHeap::pre_full_gc_dump(GCTimer* timer) {
if (HeapDumpBeforeFullGC) {
- TraceTime tt("Heap Dump (before full gc): ", PrintGCDetails, false, gclog_or_tty);
+ GCTraceTime tt("Heap Dump (before full gc): ", PrintGCDetails, false, timer);
// We are doing a "major" collection and a heap dump before
// major collection has been requested.
HeapDumper::dump_heap();
}
if (PrintClassHistogramBeforeFullGC) {
- TraceTime tt("Class Histogram (before full gc): ", PrintGCDetails, true, gclog_or_tty);
- VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */, false /* ! prologue */);
+ GCTraceTime tt("Class Histogram (before full gc): ", PrintGCDetails, true, timer);
+ VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */);
inspector.doit();
}
}
-void CollectedHeap::post_full_gc_dump() {
+void CollectedHeap::post_full_gc_dump(GCTimer* timer) {
if (HeapDumpAfterFullGC) {
- TraceTime tt("Heap Dump (after full gc): ", PrintGCDetails, false, gclog_or_tty);
+ GCTraceTime tt("Heap Dump (after full gc): ", PrintGCDetails, false, timer);
HeapDumper::dump_heap();
}
if (PrintClassHistogramAfterFullGC) {
- TraceTime tt("Class Histogram (after full gc): ", PrintGCDetails, true, gclog_or_tty);
- VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */, false /* ! prologue */);
+ GCTraceTime tt("Class Histogram (after full gc): ", PrintGCDetails, true, timer);
+ VM_GC_HeapInspection inspector(gclog_or_tty, false /* ! full gc */);
inspector.doit();
}
}
@@ -490,7 +559,7 @@ oop CollectedHeap::Class_obj_allocate(KlassHandle klass, int size, KlassHandle r
assert(size >= 0, "int won't convert to size_t");
HeapWord* obj;
assert(ScavengeRootsInCode > 0, "must be");
- obj = common_mem_allocate_init(size, CHECK_NULL);
+ obj = common_mem_allocate_init(real_klass, size, CHECK_NULL);
post_allocation_setup_common(klass, obj);
assert(Universe::is_bootstrapping() ||
!((oop)obj)->is_array(), "must not be an array");
diff --git a/src/share/vm/gc_interface/collectedHeap.hpp b/src/share/vm/gc_interface/collectedHeap.hpp
index 88929343c..1f42cfe48 100644
--- a/src/share/vm/gc_interface/collectedHeap.hpp
+++ b/src/share/vm/gc_interface/collectedHeap.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
#define SHARE_VM_GC_INTERFACE_COLLECTEDHEAP_HPP
#include "gc_interface/gcCause.hpp"
+#include "gc_implementation/shared/gcWhen.hpp"
#include "memory/allocation.hpp"
#include "memory/barrierSet.hpp"
#include "runtime/handles.hpp"
@@ -38,11 +39,16 @@
// class defines the functions that a heap must implement, and contains
// infrastructure common to all heaps.
-class BarrierSet;
-class ThreadClosure;
class AdaptiveSizePolicy;
-class Thread;
+class BarrierSet;
class CollectorPolicy;
+class GCHeapSummary;
+class GCTimer;
+class GCTracer;
+class MetaspaceSummary;
+class Thread;
+class ThreadClosure;
+class VirtualSpaceSummary;
class GCMessage : public FormatBuffer<1024> {
public:
@@ -128,16 +134,16 @@ class CollectedHeap : public CHeapObj<mtInternal> {
virtual void resize_all_tlabs();
// Allocate from the current thread's TLAB, with broken-out slow path.
- inline static HeapWord* allocate_from_tlab(Thread* thread, size_t size);
- static HeapWord* allocate_from_tlab_slow(Thread* thread, size_t size);
+ inline static HeapWord* allocate_from_tlab(KlassHandle klass, Thread* thread, size_t size);
+ static HeapWord* allocate_from_tlab_slow(KlassHandle klass, Thread* thread, size_t size);
// Allocate an uninitialized block of the given size, or returns NULL if
// this is impossible.
- inline static HeapWord* common_mem_allocate_noinit(size_t size, TRAPS);
+ inline static HeapWord* common_mem_allocate_noinit(KlassHandle klass, size_t size, TRAPS);
// Like allocate_init, but the block returned by a successful allocation
// is guaranteed initialized to zeros.
- inline static HeapWord* common_mem_allocate_init(size_t size, TRAPS);
+ inline static HeapWord* common_mem_allocate_init(KlassHandle klass, size_t size, TRAPS);
// Helper functions for (VM) allocation.
inline static void post_allocation_setup_common(KlassHandle klass, HeapWord* obj);
@@ -166,6 +172,8 @@ class CollectedHeap : public CHeapObj<mtInternal> {
// Fill with a single object (either an int array or a java.lang.Object).
static inline void fill_with_object_impl(HeapWord* start, size_t words, bool zap = true);
+ virtual void trace_heap(GCWhen::Type when, GCTracer* tracer);
+
// Verification functions
virtual void check_for_bad_heap_word_value(HeapWord* addr, size_t size)
PRODUCT_RETURN;
@@ -202,8 +210,6 @@ class CollectedHeap : public CHeapObj<mtInternal> {
MemRegion reserved_region() const { return _reserved; }
address base() const { return (address)reserved_region().start(); }
- // Future cleanup here. The following functions should specify bytes or
- // heapwords as part of their signature.
virtual size_t capacity() const = 0;
virtual size_t used() const = 0;
@@ -550,8 +556,13 @@ class CollectedHeap : public CHeapObj<mtInternal> {
virtual void prepare_for_verify() = 0;
// Generate any dumps preceding or following a full gc
- void pre_full_gc_dump();
- void post_full_gc_dump();
+ void pre_full_gc_dump(GCTimer* timer);
+ void post_full_gc_dump(GCTimer* timer);
+
+ VirtualSpaceSummary create_heap_space_summary();
+ GCHeapSummary create_heap_summary();
+
+ MetaspaceSummary create_metaspace_summary();
// Print heap information on the given outputStream.
virtual void print_on(outputStream* st) const = 0;
@@ -560,7 +571,7 @@ class CollectedHeap : public CHeapObj<mtInternal> {
print_on(tty);
}
// Print more detailed heap information on the given
- // outputStream. The default behaviour is to call print_on(). It is
+ // outputStream. The default behavior is to call print_on(). It is
// up to each subclass to override it and add any additional output
// it needs.
virtual void print_extended_on(outputStream* st) const {
@@ -589,23 +600,11 @@ class CollectedHeap : public CHeapObj<mtInternal> {
// Default implementation does nothing.
virtual void print_tracing_info() const = 0;
- // If PrintHeapAtGC is set call the appropriate routi
- void print_heap_before_gc() {
- if (PrintHeapAtGC) {
- Universe::print_heap_before_gc();
- }
- if (_gc_heap_log != NULL) {
- _gc_heap_log->log_heap_before();
- }
- }
- void print_heap_after_gc() {
- if (PrintHeapAtGC) {
- Universe::print_heap_after_gc();
- }
- if (_gc_heap_log != NULL) {
- _gc_heap_log->log_heap_after();
- }
- }
+ void print_heap_before_gc();
+ void print_heap_after_gc();
+
+ void trace_heap_before_gc(GCTracer* gc_tracer);
+ void trace_heap_after_gc(GCTracer* gc_tracer);
// Heap verification
virtual void verify(bool silent, VerifyOption option) = 0;
@@ -619,7 +618,7 @@ class CollectedHeap : public CHeapObj<mtInternal> {
inline bool promotion_should_fail();
// Reset the PromotionFailureALot counters. Should be called at the end of a
- // GC in which promotion failure ocurred.
+ // GC in which promotion failure occurred.
inline void reset_promotion_should_fail(volatile size_t* count);
inline void reset_promotion_should_fail();
#endif // #ifndef PRODUCT
diff --git a/src/share/vm/gc_interface/collectedHeap.inline.hpp b/src/share/vm/gc_interface/collectedHeap.inline.hpp
index c57b057c6..d17b82f21 100644
--- a/src/share/vm/gc_interface/collectedHeap.inline.hpp
+++ b/src/share/vm/gc_interface/collectedHeap.inline.hpp
@@ -25,6 +25,7 @@
#ifndef SHARE_VM_GC_INTERFACE_COLLECTEDHEAP_INLINE_HPP
#define SHARE_VM_GC_INTERFACE_COLLECTEDHEAP_INLINE_HPP
+#include "gc_interface/allocTracer.hpp"
#include "gc_interface/collectedHeap.hpp"
#include "memory/threadLocalAllocBuffer.inline.hpp"
#include "memory/universe.hpp"
@@ -107,7 +108,7 @@ void CollectedHeap::post_allocation_setup_array(KlassHandle klass,
post_allocation_notify(klass, (oop)obj);
}
-HeapWord* CollectedHeap::common_mem_allocate_noinit(size_t size, TRAPS) {
+HeapWord* CollectedHeap::common_mem_allocate_noinit(KlassHandle klass, size_t size, TRAPS) {
// Clear unhandled oops for memory allocation. Memory allocation might
// not take out a lock if from tlab, so clear here.
@@ -120,7 +121,7 @@ HeapWord* CollectedHeap::common_mem_allocate_noinit(size_t size, TRAPS) {
HeapWord* result = NULL;
if (UseTLAB) {
- result = CollectedHeap::allocate_from_tlab(THREAD, size);
+ result = allocate_from_tlab(klass, THREAD, size);
if (result != NULL) {
assert(!HAS_PENDING_EXCEPTION,
"Unexpected exception, will result in uninitialized storage");
@@ -136,6 +137,9 @@ HeapWord* CollectedHeap::common_mem_allocate_noinit(size_t size, TRAPS) {
assert(!HAS_PENDING_EXCEPTION,
"Unexpected exception, will result in uninitialized storage");
THREAD->incr_allocated_bytes(size * HeapWordSize);
+
+ AllocTracer::send_allocation_outside_tlab_event(klass, size * HeapWordSize);
+
return result;
}
@@ -165,13 +169,13 @@ HeapWord* CollectedHeap::common_mem_allocate_noinit(size_t size, TRAPS) {
}
}
-HeapWord* CollectedHeap::common_mem_allocate_init(size_t size, TRAPS) {
- HeapWord* obj = common_mem_allocate_noinit(size, CHECK_NULL);
+HeapWord* CollectedHeap::common_mem_allocate_init(KlassHandle klass, size_t size, TRAPS) {
+ HeapWord* obj = common_mem_allocate_noinit(klass, size, CHECK_NULL);
init_obj(obj, size);
return obj;
}
-HeapWord* CollectedHeap::allocate_from_tlab(Thread* thread, size_t size) {
+HeapWord* CollectedHeap::allocate_from_tlab(KlassHandle klass, Thread* thread, size_t size) {
assert(UseTLAB, "should use UseTLAB");
HeapWord* obj = thread->tlab().allocate(size);
@@ -179,7 +183,7 @@ HeapWord* CollectedHeap::allocate_from_tlab(Thread* thread, size_t size) {
return obj;
}
// Otherwise...
- return allocate_from_tlab_slow(thread, size);
+ return allocate_from_tlab_slow(klass, thread, size);
}
void CollectedHeap::init_obj(HeapWord* obj, size_t size) {
@@ -194,7 +198,7 @@ oop CollectedHeap::obj_allocate(KlassHandle klass, int size, TRAPS) {
debug_only(check_for_valid_allocation_state());
assert(!Universe::heap()->is_gc_active(), "Allocation during gc not allowed");
assert(size >= 0, "int won't convert to size_t");
- HeapWord* obj = common_mem_allocate_init(size, CHECK_NULL);
+ HeapWord* obj = common_mem_allocate_init(klass, size, CHECK_NULL);
post_allocation_setup_obj(klass, obj);
NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value(obj, size));
return (oop)obj;
@@ -207,7 +211,7 @@ oop CollectedHeap::array_allocate(KlassHandle klass,
debug_only(check_for_valid_allocation_state());
assert(!Universe::heap()->is_gc_active(), "Allocation during gc not allowed");
assert(size >= 0, "int won't convert to size_t");
- HeapWord* obj = common_mem_allocate_init(size, CHECK_NULL);
+ HeapWord* obj = common_mem_allocate_init(klass, size, CHECK_NULL);
post_allocation_setup_array(klass, obj, length);
NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value(obj, size));
return (oop)obj;
@@ -220,7 +224,7 @@ oop CollectedHeap::array_allocate_nozero(KlassHandle klass,
debug_only(check_for_valid_allocation_state());
assert(!Universe::heap()->is_gc_active(), "Allocation during gc not allowed");
assert(size >= 0, "int won't convert to size_t");
- HeapWord* obj = common_mem_allocate_noinit(size, CHECK_NULL);
+ HeapWord* obj = common_mem_allocate_noinit(klass, size, CHECK_NULL);
((oop)obj)->set_klass_gap(0);
post_allocation_setup_array(klass, obj, length);
#ifndef PRODUCT
diff --git a/src/share/vm/gc_interface/gcCause.cpp b/src/share/vm/gc_interface/gcCause.cpp
index 0ac45d911..e7e7e43f4 100644
--- a/src/share/vm/gc_interface/gcCause.cpp
+++ b/src/share/vm/gc_interface/gcCause.cpp
@@ -72,6 +72,9 @@ const char* GCCause::to_string(GCCause::Cause cause) {
case _cms_final_remark:
return "CMS Final Remark";
+ case _cms_concurrent_mark:
+ return "CMS Concurrent Mark";
+
case _old_generation_expanded_on_last_scavenge:
return "Old Generation Expanded On Last Scavenge";
diff --git a/src/share/vm/gc_interface/gcCause.hpp b/src/share/vm/gc_interface/gcCause.hpp
index 58abc2e6f..06f11882c 100644
--- a/src/share/vm/gc_interface/gcCause.hpp
+++ b/src/share/vm/gc_interface/gcCause.hpp
@@ -60,6 +60,7 @@ class GCCause : public AllStatic {
_cms_generation_full,
_cms_initial_mark,
_cms_final_remark,
+ _cms_concurrent_mark,
_old_generation_expanded_on_last_scavenge,
_old_generation_too_full_to_scavenge,
diff --git a/src/share/vm/gc_interface/gcName.hpp b/src/share/vm/gc_interface/gcName.hpp
new file mode 100644
index 000000000..c48c24838
--- /dev/null
+++ b/src/share/vm/gc_interface/gcName.hpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2002, 2013, 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_INTERFACE_GCNAME_HPP
+#define SHARE_VM_GC_INTERFACE_GCNAME_HPP
+
+#include "utilities/debug.hpp"
+
+enum GCName {
+ ParallelOld,
+ SerialOld,
+ PSMarkSweep,
+ ParallelScavenge,
+ DefNew,
+ ParNew,
+ G1New,
+ ConcurrentMarkSweep,
+ G1Old,
+ GCNameEndSentinel
+};
+
+class GCNameHelper {
+ public:
+ static const char* to_string(GCName name) {
+ switch(name) {
+ case ParallelOld: return "ParallelOld";
+ case SerialOld: return "SerialOld";
+ case PSMarkSweep: return "PSMarkSweep";
+ case ParallelScavenge: return "ParallelScavenge";
+ case DefNew: return "DefNew";
+ case ParNew: return "ParNew";
+ case G1New: return "G1New";
+ case ConcurrentMarkSweep: return "ConcurrentMarkSweep";
+ case G1Old: return "G1Old";
+ default: ShouldNotReachHere(); return NULL;
+ }
+ }
+};
+
+#endif // SHARE_VM_GC_INTERFACE_GCNAME_HPP
diff --git a/src/share/vm/memory/allocation.hpp b/src/share/vm/memory/allocation.hpp
index ebdb29cd2..65df6ee05 100644
--- a/src/share/vm/memory/allocation.hpp
+++ b/src/share/vm/memory/allocation.hpp
@@ -157,7 +157,8 @@ enum MemoryType {
mtJavaHeap = 0x0C00, // Java heap
mtClassShared = 0x0D00, // class data sharing
mtTest = 0x0E00, // Test type for verifying NMT
- mt_number_of_types = 0x000E, // number of memory types (mtDontTrack
+ mtTracing = 0x0F00, // memory used for Tracing
+ mt_number_of_types = 0x000F, // number of memory types (mtDontTrack
// is not included as validate type)
mtDontTrack = 0x0F00, // memory we do not or cannot track
mt_masks = 0x7F00,
diff --git a/src/share/vm/memory/defNewGeneration.cpp b/src/share/vm/memory/defNewGeneration.cpp
index 39bbd14c4..88afd70a7 100644
--- a/src/share/vm/memory/defNewGeneration.cpp
+++ b/src/share/vm/memory/defNewGeneration.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, 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,10 @@
#include "precompiled.hpp"
#include "gc_implementation/shared/collectorCounters.hpp"
#include "gc_implementation/shared/gcPolicyCounters.hpp"
+#include "gc_implementation/shared/gcHeapSummary.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
#include "gc_implementation/shared/spaceDecorator.hpp"
#include "memory/defNewGeneration.inline.hpp"
#include "memory/gcLocker.inline.hpp"
@@ -223,6 +227,8 @@ DefNewGeneration::DefNewGeneration(ReservedSpace rs,
_next_gen = NULL;
_tenuring_threshold = MaxTenuringThreshold;
_pretenure_size_threshold_words = PretenureSizeThreshold >> LogHeapWordSize;
+
+ _gc_timer = new (ResourceObj::C_HEAP, mtGC) STWGCTimer();
}
void DefNewGeneration::compute_space_boundaries(uintx minimum_eden_size,
@@ -558,12 +564,18 @@ void DefNewGeneration::collect(bool full,
size_t size,
bool is_tlab) {
assert(full || size > 0, "otherwise we don't want to collect");
+
GenCollectedHeap* gch = GenCollectedHeap::heap();
+
+ _gc_timer->register_gc_start(os::elapsed_counter());
+ DefNewTracer gc_tracer;
+ gc_tracer.report_gc_start(gch->gc_cause(), _gc_timer->gc_start());
+
_next_gen = gch->next_gen(this);
assert(_next_gen != NULL,
"This must be the youngest gen, and not the only gen");
- // If the next generation is too full to accomodate promotion
+ // If the next generation is too full to accommodate promotion
// from this generation, pass on collection; let the next generation
// do it.
if (!collection_attempt_is_safe()) {
@@ -577,10 +589,12 @@ void DefNewGeneration::collect(bool full,
init_assuming_no_promotion_failure();
- TraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, gclog_or_tty);
+ GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL);
// Capture heap used before collection (for printing).
size_t gch_prev_used = gch->used();
+ gch->trace_heap_before_gc(&gc_tracer);
+
SpecializationStats::clear();
// These can be shared for all code paths
@@ -631,9 +645,12 @@ void DefNewGeneration::collect(bool full,
FastKeepAliveClosure keep_alive(this, &scan_weak_ref);
ReferenceProcessor* rp = ref_processor();
rp->setup_policy(clear_all_soft_refs);
+ const ReferenceProcessorStats& stats =
rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers,
- NULL);
- if (!promotion_failed()) {
+ NULL, _gc_timer);
+ gc_tracer.report_gc_reference_stats(stats);
+
+ if (!_promotion_failed) {
// Swap the survivor spaces.
eden()->clear(SpaceDecorator::Mangle);
from()->clear(SpaceDecorator::Mangle);
@@ -680,6 +697,7 @@ void DefNewGeneration::collect(bool full,
// Inform the next generation that a promotion failure occurred.
_next_gen->promotion_failure_occurred();
+ gc_tracer.report_promotion_failed(_promotion_failed_info);
// Reset the PromotionFailureALot counters.
NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();)
@@ -689,11 +707,18 @@ void DefNewGeneration::collect(bool full,
to()->set_concurrent_iteration_safe_limit(to()->top());
SpecializationStats::print();
- // We need to use a monotonically non-deccreasing time in ms
+ // We need to use a monotonically non-decreasing time in ms
// or we will see time-warp warnings and os::javaTimeMillis()
// does not guarantee monotonicity.
jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
update_time_of_last_gc(now);
+
+ gch->trace_heap_after_gc(&gc_tracer);
+ gc_tracer.report_tenuring_threshold(tenuring_threshold());
+
+ _gc_timer->register_gc_end(os::elapsed_counter());
+
+ gc_tracer.report_gc_end(_gc_timer->gc_end(), _gc_timer->time_partitions());
}
class RemoveForwardPointerClosure: public ObjectClosure {
@@ -705,6 +730,7 @@ public:
void DefNewGeneration::init_assuming_no_promotion_failure() {
_promotion_failed = false;
+ _promotion_failed_info.reset();
from()->set_next_compaction_space(NULL);
}
@@ -726,7 +752,7 @@ void DefNewGeneration::remove_forwarding_pointers() {
}
void DefNewGeneration::preserve_mark(oop obj, markOop m) {
- assert(promotion_failed() && m->must_be_preserved_for_promotion_failure(obj),
+ assert(_promotion_failed && m->must_be_preserved_for_promotion_failure(obj),
"Oversaving!");
_objs_with_preserved_marks.push(obj);
_preserved_marks_of_objs.push(m);
@@ -744,6 +770,7 @@ void DefNewGeneration::handle_promotion_failure(oop old) {
old->size());
}
_promotion_failed = true;
+ _promotion_failed_info.register_copy_failure(old->size());
preserve_mark_if_necessary(old, old->mark());
// forward to self
old->forward_to(old);
@@ -962,6 +989,10 @@ void DefNewGeneration::record_spaces_top() {
from()->set_top_for_allocations();
}
+void DefNewGeneration::ref_processor_init() {
+ Generation::ref_processor_init();
+}
+
void DefNewGeneration::update_counters() {
if (UsePerfData) {
diff --git a/src/share/vm/memory/defNewGeneration.hpp b/src/share/vm/memory/defNewGeneration.hpp
index ee2871820..c538e0a4f 100644
--- a/src/share/vm/memory/defNewGeneration.hpp
+++ b/src/share/vm/memory/defNewGeneration.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, 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,12 +28,14 @@
#include "gc_implementation/shared/ageTable.hpp"
#include "gc_implementation/shared/cSpaceCounters.hpp"
#include "gc_implementation/shared/generationCounters.hpp"
+#include "gc_implementation/shared/copyFailedInfo.hpp"
#include "memory/generation.inline.hpp"
#include "utilities/stack.hpp"
class EdenSpace;
class ContiguousSpace;
class ScanClosure;
+class STWGCTimer;
// DefNewGeneration is a young generation containing eden, from- and
// to-space.
@@ -46,15 +48,17 @@ protected:
uint _tenuring_threshold; // Tenuring threshold for next collection.
ageTable _age_table;
// Size of object to pretenure in words; command line provides bytes
- size_t _pretenure_size_threshold_words;
+ size_t _pretenure_size_threshold_words;
ageTable* age_table() { return &_age_table; }
+
// Initialize state to optimistically assume no promotion failure will
// happen.
void init_assuming_no_promotion_failure();
// True iff a promotion has failed in the current collection.
bool _promotion_failed;
bool promotion_failed() { return _promotion_failed; }
+ PromotionFailedInfo _promotion_failed_info;
// Handling promotion failure. A young generation collection
// can fail if a live object cannot be copied out of its
@@ -132,6 +136,8 @@ protected:
ContiguousSpace* _from_space;
ContiguousSpace* _to_space;
+ STWGCTimer* _gc_timer;
+
enum SomeProtectedConstants {
// Generations are GenGrain-aligned and have size that are multiples of
// GenGrain.
@@ -203,6 +209,8 @@ protected:
DefNewGeneration(ReservedSpace rs, size_t initial_byte_size, int level,
const char* policy="Copy");
+ virtual void ref_processor_init();
+
virtual Generation::Name kind() { return Generation::DefNew; }
// Accessing spaces
diff --git a/src/share/vm/memory/genCollectedHeap.cpp b/src/share/vm/memory/genCollectedHeap.cpp
index 8c2eb34d2..a74533d43 100644
--- a/src/share/vm/memory/genCollectedHeap.cpp
+++ b/src/share/vm/memory/genCollectedHeap.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, 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 "classfile/vmSymbols.hpp"
#include "code/icBuffer.hpp"
#include "gc_implementation/shared/collectorCounters.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "memory/filemap.hpp"
@@ -388,7 +389,7 @@ void GenCollectedHeap::do_collection(bool full,
const char* gc_cause_prefix = complete ? "Full GC" : "GC";
gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps);
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
- TraceTime t(GCCauseString(gc_cause_prefix, gc_cause()), PrintGCDetails, false, gclog_or_tty);
+ GCTraceTime t(GCCauseString(gc_cause_prefix, gc_cause()), PrintGCDetails, false, NULL);
gc_prologue(complete);
increment_total_collections(complete);
@@ -417,10 +418,11 @@ void GenCollectedHeap::do_collection(bool full,
// The full_collections increment was missed above.
increment_total_full_collections();
}
- pre_full_gc_dump(); // do any pre full gc dumps
+ pre_full_gc_dump(NULL); // do any pre full gc dumps
}
// Timer for individual generations. Last argument is false: no CR
- TraceTime t1(_gens[i]->short_name(), PrintGCDetails, false, gclog_or_tty);
+ // FIXME: We should try to start the timing earlier to cover more of the GC pause
+ GCTraceTime t1(_gens[i]->short_name(), PrintGCDetails, false, NULL);
TraceCollectorStats tcs(_gens[i]->counters());
TraceMemoryManagerStats tmms(_gens[i]->kind(),gc_cause());
@@ -534,7 +536,8 @@ void GenCollectedHeap::do_collection(bool full,
complete = complete || (max_level_collected == n_gens() - 1);
if (complete) { // We did a "major" collection
- post_full_gc_dump(); // do any post full gc dumps
+ // FIXME: See comment at pre_full_gc_dump call
+ post_full_gc_dump(NULL); // do any post full gc dumps
}
if (PrintGCDetails) {
diff --git a/src/share/vm/memory/genMarkSweep.cpp b/src/share/vm/memory/genMarkSweep.cpp
index 6d0fd9b49..e53e742be 100644
--- a/src/share/vm/memory/genMarkSweep.cpp
+++ b/src/share/vm/memory/genMarkSweep.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, 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,10 @@
#include "classfile/vmSymbols.hpp"
#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
+#include "gc_implementation/shared/gcHeapSummary.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "memory/genCollectedHeap.hpp"
#include "memory/genMarkSweep.hpp"
@@ -65,7 +69,9 @@ void GenMarkSweep::invoke_at_safepoint(int level, ReferenceProcessor* rp,
_ref_processor = rp;
rp->setup_policy(clear_all_softrefs);
- TraceTime t1(GCCauseString("Full GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, gclog_or_tty);
+ GCTraceTime t1(GCCauseString("Full GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL);
+
+ gch->trace_heap_before_gc(_gc_tracer);
// When collecting the permanent generation Method*s may be moving,
// so we either have to flush all bcp data or convert it into bci.
@@ -155,6 +161,8 @@ void GenMarkSweep::invoke_at_safepoint(int level, ReferenceProcessor* rp,
// does not guarantee monotonicity.
jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
gch->update_time_of_last_gc(now);
+
+ gch->trace_heap_after_gc(_gc_tracer);
}
void GenMarkSweep::allocate_stacks() {
@@ -192,7 +200,7 @@ void GenMarkSweep::deallocate_stacks() {
void GenMarkSweep::mark_sweep_phase1(int level,
bool clear_all_softrefs) {
// Recursively traverse all live objects and mark them
- TraceTime tm("phase 1", PrintGC && Verbose, true, gclog_or_tty);
+ GCTraceTime tm("phase 1", PrintGC && Verbose, true, _gc_timer);
trace(" 1");
GenCollectedHeap* gch = GenCollectedHeap::heap();
@@ -219,8 +227,10 @@ void GenMarkSweep::mark_sweep_phase1(int level,
// Process reference objects found during marking
{
ref_processor()->setup_policy(clear_all_softrefs);
- ref_processor()->process_discovered_references(
- &is_alive, &keep_alive, &follow_stack_closure, NULL);
+ const ReferenceProcessorStats& stats =
+ ref_processor()->process_discovered_references(
+ &is_alive, &keep_alive, &follow_stack_closure, NULL, _gc_timer);
+ gc_tracer()->report_gc_reference_stats(stats);
}
// This is the point where the entire marking should have completed.
@@ -240,6 +250,8 @@ void GenMarkSweep::mark_sweep_phase1(int level,
// Clean up unreferenced symbols in symbol table.
SymbolTable::unlink();
+
+ gc_tracer()->report_object_count_after_gc(&is_alive);
}
@@ -259,7 +271,7 @@ void GenMarkSweep::mark_sweep_phase2() {
GenCollectedHeap* gch = GenCollectedHeap::heap();
- TraceTime tm("phase 2", PrintGC && Verbose, true, gclog_or_tty);
+ GCTraceTime tm("phase 2", PrintGC && Verbose, true, _gc_timer);
trace("2");
gch->prepare_for_compaction();
@@ -276,7 +288,7 @@ void GenMarkSweep::mark_sweep_phase3(int level) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
// Adjust the pointers to reflect the new locations
- TraceTime tm("phase 3", PrintGC && Verbose, true, gclog_or_tty);
+ GCTraceTime tm("phase 3", PrintGC && Verbose, true, _gc_timer);
trace("3");
// Need new claim bits for the pointer adjustment tracing.
@@ -331,7 +343,7 @@ void GenMarkSweep::mark_sweep_phase4() {
// to use a higher index (saved from phase2) when verifying perm_gen.
GenCollectedHeap* gch = GenCollectedHeap::heap();
- TraceTime tm("phase 4", PrintGC && Verbose, true, gclog_or_tty);
+ GCTraceTime tm("phase 4", PrintGC && Verbose, true, _gc_timer);
trace("4");
GenCompactClosure blk;
diff --git a/src/share/vm/memory/generation.cpp b/src/share/vm/memory/generation.cpp
index b60887465..9fa46b34a 100644
--- a/src/share/vm/memory/generation.cpp
+++ b/src/share/vm/memory/generation.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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,8 @@
*/
#include "precompiled.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTrace.hpp"
#include "gc_implementation/shared/spaceDecorator.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "memory/allocation.inline.hpp"
@@ -624,12 +626,26 @@ void OneContigSpaceCardGeneration::collect(bool full,
bool clear_all_soft_refs,
size_t size,
bool is_tlab) {
+ GenCollectedHeap* gch = GenCollectedHeap::heap();
+
SpecializationStats::clear();
// Temporarily expand the span of our ref processor, so
// refs discovery is over the entire heap, not just this generation
ReferenceProcessorSpanMutator
- x(ref_processor(), GenCollectedHeap::heap()->reserved_region());
+ x(ref_processor(), gch->reserved_region());
+
+ STWGCTimer* gc_timer = GenMarkSweep::gc_timer();
+ gc_timer->register_gc_start(os::elapsed_counter());
+
+ SerialOldTracer* gc_tracer = GenMarkSweep::gc_tracer();
+ gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start());
+
GenMarkSweep::invoke_at_safepoint(_level, ref_processor(), clear_all_soft_refs);
+
+ gc_timer->register_gc_end(os::elapsed_counter());
+
+ gc_tracer->report_gc_end(os::elapsed_counter(), gc_timer->time_partitions());
+
SpecializationStats::print();
}
diff --git a/src/share/vm/memory/heapInspection.cpp b/src/share/vm/memory/heapInspection.cpp
index d93104954..2afecb680 100644
--- a/src/share/vm/memory/heapInspection.cpp
+++ b/src/share/vm/memory/heapInspection.cpp
@@ -95,7 +95,7 @@ KlassInfoEntry* KlassInfoBucket::lookup(Klass* const k) {
}
elt = elt->next();
}
- elt = new KlassInfoEntry(k, list());
+ elt = new (std::nothrow) KlassInfoEntry(k, list());
// We may be out of space to allocate the new entry.
if (elt != NULL) {
set_list(elt);
@@ -127,13 +127,15 @@ void KlassInfoTable::AllClassesFinder::do_klass(Klass* k) {
_table->lookup(k);
}
-KlassInfoTable::KlassInfoTable(int size, HeapWord* ref,
- bool need_class_stats) {
+KlassInfoTable::KlassInfoTable(bool need_class_stats) {
+ _size_of_instances_in_words = 0;
_size = 0;
- _ref = ref;
- _buckets = NEW_C_HEAP_ARRAY(KlassInfoBucket, size, mtInternal);
+ _ref = (HeapWord*) Universe::boolArrayKlassObj();
+ _buckets =
+ (KlassInfoBucket*) AllocateHeap(sizeof(KlassInfoBucket) * _num_buckets,
+ mtInternal, 0, AllocFailStrategy::RETURN_NULL);
if (_buckets != NULL) {
- _size = size;
+ _size = _num_buckets;
for (int index = 0; index < _size; index++) {
_buckets[index].initialize();
}
@@ -179,6 +181,7 @@ bool KlassInfoTable::record_instance(const oop obj) {
if (elt != NULL) {
elt->set_count(elt->count() + 1);
elt->set_words(elt->words() + obj->size());
+ _size_of_instances_in_words += obj->size();
return true;
} else {
return false;
@@ -192,14 +195,18 @@ void KlassInfoTable::iterate(KlassInfoClosure* cic) {
}
}
+size_t KlassInfoTable::size_of_instances_in_words() const {
+ return _size_of_instances_in_words;
+}
+
int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) {
return (*e1)->compare(*e1,*e2);
}
-KlassInfoHisto::KlassInfoHisto(KlassInfoTable* cit, const char* title, int estimatedCount) :
+KlassInfoHisto::KlassInfoHisto(KlassInfoTable* cit, const char* title) :
_cit(cit),
_title(title) {
- _elements = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<KlassInfoEntry*>(estimatedCount,true);
+ _elements = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<KlassInfoEntry*>(_histo_initial_size, true);
}
KlassInfoHisto::~KlassInfoHisto() {
@@ -444,25 +451,37 @@ class RecordInstanceClosure : public ObjectClosure {
private:
KlassInfoTable* _cit;
size_t _missed_count;
+ BoolObjectClosure* _filter;
public:
- RecordInstanceClosure(KlassInfoTable* cit) :
- _cit(cit), _missed_count(0) {}
+ RecordInstanceClosure(KlassInfoTable* cit, BoolObjectClosure* filter) :
+ _cit(cit), _missed_count(0), _filter(filter) {}
void do_object(oop obj) {
- if (!_cit->record_instance(obj)) {
- _missed_count++;
+ if (should_visit(obj)) {
+ if (!_cit->record_instance(obj)) {
+ _missed_count++;
+ }
}
}
size_t missed_count() { return _missed_count; }
+
+ private:
+ bool should_visit(oop obj) {
+ return _filter == NULL || _filter->do_object_b(obj);
+ }
};
-void HeapInspection::heap_inspection(outputStream* st, bool need_prologue) {
+size_t HeapInspection::populate_table(KlassInfoTable* cit, BoolObjectClosure *filter) {
+ ResourceMark rm;
+
+ RecordInstanceClosure ric(cit, filter);
+ Universe::heap()->object_iterate(&ric);
+ return ric.missed_count();
+}
+
+void HeapInspection::heap_inspection(outputStream* st) {
ResourceMark rm;
- // Get some random number for ref (the hash key)
- HeapWord* ref = (HeapWord*) Universe::boolArrayKlassObj();
- CollectedHeap* heap = Universe::heap();
- bool is_shared_heap = false;
if (_print_help) {
for (int c=0; c<KlassSizeStats::_num_columns; c++) {
@@ -482,39 +501,30 @@ void HeapInspection::heap_inspection(outputStream* st, bool need_prologue) {
return;
}
- // Collect klass instance info
- KlassInfoTable cit(KlassInfoTable::cit_size, ref, _print_class_stats);
+ KlassInfoTable cit(_print_class_stats);
if (!cit.allocation_failed()) {
- // Iterate over objects in the heap
- RecordInstanceClosure ric(&cit);
- Universe::heap()->object_iterate(&ric);
-
- // Report if certain classes are not counted because of
- // running out of C-heap for the histogram.
- size_t missed_count = ric.missed_count();
+ size_t missed_count = populate_table(&cit);
if (missed_count != 0) {
st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT
" total instances in data below",
missed_count);
}
+
// Sort and print klass instance info
const char *title = "\n"
" num #instances #bytes class name\n"
"----------------------------------------------";
- KlassInfoHisto histo(&cit, title, KlassInfoHisto::histo_initial_size);
+ KlassInfoHisto histo(&cit, title);
HistoClosure hc(&histo);
+
cit.iterate(&hc);
+
histo.sort();
histo.print_histo_on(st, _print_class_stats, _csv_format, _columns);
} else {
st->print_cr("WARNING: Ran out of C-heap; histogram not generated");
}
st->flush();
-
- if (need_prologue && is_shared_heap) {
- SharedHeap* sh = (SharedHeap*)heap;
- sh->gc_epilogue(false /* !full */); // release all acquired locks, etc.
- }
}
class FindInstanceClosure : public ObjectClosure {
diff --git a/src/share/vm/memory/heapInspection.hpp b/src/share/vm/memory/heapInspection.hpp
index ccf39bad5..c286e4865 100644
--- a/src/share/vm/memory/heapInspection.hpp
+++ b/src/share/vm/memory/heapInspection.hpp
@@ -26,6 +26,7 @@
#define SHARE_VM_MEMORY_HEAPINSPECTION_HPP
#include "memory/allocation.inline.hpp"
+#include "memory/klassInfoClosure.hpp"
#include "oops/oop.inline.hpp"
#include "oops/annotations.hpp"
#include "utilities/macros.hpp"
@@ -203,12 +204,6 @@ class KlassInfoEntry: public CHeapObj<mtInternal> {
const char* name() const;
};
-class KlassInfoClosure: public StackObj {
- public:
- // Called for each KlassInfoEntry.
- virtual void do_cinfo(KlassInfoEntry* cie) = 0;
-};
-
class KlassInfoBucket: public CHeapObj<mtInternal> {
private:
KlassInfoEntry* _list;
@@ -224,6 +219,8 @@ class KlassInfoBucket: public CHeapObj<mtInternal> {
class KlassInfoTable: public StackObj {
private:
int _size;
+ static const int _num_buckets = 20011;
+ size_t _size_of_instances_in_words;
// An aligned reference address (typically the least
// address in the perm gen) used for hashing klass
@@ -242,21 +239,19 @@ class KlassInfoTable: public StackObj {
};
public:
- // Table size
- enum {
- cit_size = 20011
- };
- KlassInfoTable(int size, HeapWord* ref, bool need_class_stats);
+ KlassInfoTable(bool need_class_stats);
~KlassInfoTable();
bool record_instance(const oop obj);
void iterate(KlassInfoClosure* cic);
bool allocation_failed() { return _buckets == NULL; }
+ size_t size_of_instances_in_words() const;
friend class KlassInfoHisto;
};
class KlassInfoHisto : public StackObj {
private:
+ static const int _histo_initial_size = 1000;
KlassInfoTable *_cit;
GrowableArray<KlassInfoEntry*>* _elements;
GrowableArray<KlassInfoEntry*>* elements() const { return _elements; }
@@ -334,11 +329,7 @@ class KlassInfoHisto : public StackObj {
}
public:
- enum {
- histo_initial_size = 1000
- };
- KlassInfoHisto(KlassInfoTable* cit, const char* title,
- int estimatedCount);
+ KlassInfoHisto(KlassInfoTable* cit, const char* title);
~KlassInfoHisto();
void add(KlassInfoEntry* cie);
void print_histo_on(outputStream* st, bool print_class_stats, bool csv_format, const char *columns);
@@ -347,6 +338,11 @@ class KlassInfoHisto : public StackObj {
#endif // INCLUDE_SERVICES
+// These declarations are needed since teh declaration of KlassInfoTable and
+// KlassInfoClosure are guarded by #if INLCUDE_SERVICES
+class KlassInfoTable;
+class KlassInfoClosure;
+
class HeapInspection : public StackObj {
bool _csv_format; // "comma separated values" format for spreadsheet.
bool _print_help;
@@ -357,8 +353,11 @@ class HeapInspection : public StackObj {
bool print_class_stats, const char *columns) :
_csv_format(csv_format), _print_help(print_help),
_print_class_stats(print_class_stats), _columns(columns) {}
- void heap_inspection(outputStream* st, bool need_prologue) NOT_SERVICES_RETURN;
+ void heap_inspection(outputStream* st) NOT_SERVICES_RETURN;
+ size_t populate_table(KlassInfoTable* cit, BoolObjectClosure* filter = NULL) NOT_SERVICES_RETURN;
static void find_instances_at_safepoint(Klass* k, GrowableArray<oop>* result) NOT_SERVICES_RETURN;
+ private:
+ void iterate_over_heap(KlassInfoTable* cit, BoolObjectClosure* filter = NULL);
};
#endif // SHARE_VM_MEMORY_HEAPINSPECTION_HPP
diff --git a/src/share/vm/memory/klassInfoClosure.hpp b/src/share/vm/memory/klassInfoClosure.hpp
new file mode 100644
index 000000000..b945a19e0
--- /dev/null
+++ b/src/share/vm/memory/klassInfoClosure.hpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013, 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_MEMORY_KLASSINFOCLOSURE_HPP
+#define SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP
+
+class KlassInfoEntry;
+
+class KlassInfoClosure : public StackObj {
+ public:
+ // Called for each KlassInfoEntry.
+ virtual void do_cinfo(KlassInfoEntry* cie) = 0;
+};
+
+#endif // SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP
diff --git a/src/share/vm/memory/metaspace.hpp b/src/share/vm/memory/metaspace.hpp
index 70acbb166..cd499341c 100644
--- a/src/share/vm/memory/metaspace.hpp
+++ b/src/share/vm/memory/metaspace.hpp
@@ -193,7 +193,10 @@ class Metaspace : public CHeapObj<mtClass> {
};
class MetaspaceAux : AllStatic {
+ static size_t free_chunks_total(Metaspace::MetadataType mdtype);
+ static size_t free_chunks_total_in_bytes(Metaspace::MetadataType mdtype);
+ public:
// Statistics for class space and data space in metaspace.
// These methods iterate over the classloader data graph
@@ -205,10 +208,6 @@ class MetaspaceAux : AllStatic {
// Iterates over the virtual space list.
static size_t reserved_in_bytes(Metaspace::MetadataType mdtype);
- static size_t free_chunks_total(Metaspace::MetadataType mdtype);
- static size_t free_chunks_total_in_bytes(Metaspace::MetadataType mdtype);
-
- public:
// Running sum of space in all Metachunks that has been
// allocated to a Metaspace. This is used instead of
// iterating over all the classloaders. One for each
diff --git a/src/share/vm/memory/oopFactory.hpp b/src/share/vm/memory/oopFactory.hpp
index bd0346690..1d14010e2 100644
--- a/src/share/vm/memory/oopFactory.hpp
+++ b/src/share/vm/memory/oopFactory.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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 "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
+#include "memory/referenceType.hpp"
#include "memory/universe.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/oop.hpp"
diff --git a/src/share/vm/memory/referenceProcessor.cpp b/src/share/vm/memory/referenceProcessor.cpp
index 20ae92ac0..1333c082c 100644
--- a/src/share/vm/memory/referenceProcessor.cpp
+++ b/src/share/vm/memory/referenceProcessor.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, 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,8 @@
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
+#include "gc_implementation/shared/gcTimer.hpp"
+#include "gc_implementation/shared/gcTraceTime.hpp"
#include "gc_interface/collectedHeap.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "memory/referencePolicy.hpp"
@@ -180,11 +182,20 @@ void ReferenceProcessor::update_soft_ref_master_clock() {
// past clock value.
}
-void ReferenceProcessor::process_discovered_references(
+size_t ReferenceProcessor::total_count(DiscoveredList lists[]) {
+ size_t total = 0;
+ for (uint i = 0; i < _max_num_q; ++i) {
+ total += lists[i].length();
+ }
+ return total;
+}
+
+ReferenceProcessorStats ReferenceProcessor::process_discovered_references(
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
- AbstractRefProcTaskExecutor* task_executor) {
+ AbstractRefProcTaskExecutor* task_executor,
+ GCTimer* gc_timer) {
NOT_PRODUCT(verify_ok_to_handle_reflists());
assert(!enqueuing_is_done(), "If here enqueuing should not be complete");
@@ -202,34 +213,43 @@ void ReferenceProcessor::process_discovered_references(
_soft_ref_timestamp_clock = java_lang_ref_SoftReference::clock();
bool trace_time = PrintGCDetails && PrintReferenceGC;
+
// Soft references
+ size_t soft_count = 0;
{
- TraceTime tt("SoftReference", trace_time, false, gclog_or_tty);
- process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,
- is_alive, keep_alive, complete_gc, task_executor);
+ GCTraceTime tt("SoftReference", trace_time, false, gc_timer);
+ soft_count =
+ process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,
+ is_alive, keep_alive, complete_gc, task_executor);
}
update_soft_ref_master_clock();
// Weak references
+ size_t weak_count = 0;
{
- TraceTime tt("WeakReference", trace_time, false, gclog_or_tty);
- process_discovered_reflist(_discoveredWeakRefs, NULL, true,
- is_alive, keep_alive, complete_gc, task_executor);
+ GCTraceTime tt("WeakReference", trace_time, false, gc_timer);
+ weak_count =
+ process_discovered_reflist(_discoveredWeakRefs, NULL, true,
+ is_alive, keep_alive, complete_gc, task_executor);
}
// Final references
+ size_t final_count = 0;
{
- TraceTime tt("FinalReference", trace_time, false, gclog_or_tty);
- process_discovered_reflist(_discoveredFinalRefs, NULL, false,
- is_alive, keep_alive, complete_gc, task_executor);
+ GCTraceTime tt("FinalReference", trace_time, false, gc_timer);
+ final_count =
+ process_discovered_reflist(_discoveredFinalRefs, NULL, false,
+ is_alive, keep_alive, complete_gc, task_executor);
}
// Phantom references
+ size_t phantom_count = 0;
{
- TraceTime tt("PhantomReference", trace_time, false, gclog_or_tty);
- process_discovered_reflist(_discoveredPhantomRefs, NULL, false,
- is_alive, keep_alive, complete_gc, task_executor);
+ GCTraceTime tt("PhantomReference", trace_time, false, gc_timer);
+ phantom_count =
+ process_discovered_reflist(_discoveredPhantomRefs, NULL, false,
+ is_alive, keep_alive, complete_gc, task_executor);
}
// Weak global JNI references. It would make more sense (semantically) to
@@ -238,12 +258,14 @@ void ReferenceProcessor::process_discovered_references(
// thus use JNI weak references to circumvent the phantom references and
// resurrect a "post-mortem" object.
{
- TraceTime tt("JNI Weak Reference", trace_time, false, gclog_or_tty);
+ GCTraceTime tt("JNI Weak Reference", trace_time, false, gc_timer);
if (task_executor != NULL) {
task_executor->set_single_threaded_mode();
}
process_phaseJNI(is_alive, keep_alive, complete_gc);
}
+
+ return ReferenceProcessorStats(soft_count, weak_count, final_count, phantom_count);
}
#ifndef PRODUCT
@@ -878,7 +900,7 @@ void ReferenceProcessor::balance_all_queues() {
balance_queues(_discoveredPhantomRefs);
}
-void
+size_t
ReferenceProcessor::process_discovered_reflist(
DiscoveredList refs_lists[],
ReferencePolicy* policy,
@@ -901,12 +923,11 @@ ReferenceProcessor::process_discovered_reflist(
must_balance) {
balance_queues(refs_lists);
}
+
+ size_t total_list_count = total_count(refs_lists);
+
if (PrintReferenceGC && PrintGCDetails) {
- size_t total = 0;
- for (uint i = 0; i < _max_num_q; ++i) {
- total += refs_lists[i].length();
- }
- gclog_or_tty->print(", %u refs", total);
+ gclog_or_tty->print(", %u refs", total_list_count);
}
// Phase 1 (soft refs only):
@@ -951,6 +972,8 @@ ReferenceProcessor::process_discovered_reflist(
is_alive, keep_alive, complete_gc);
}
}
+
+ return total_list_count;
}
void ReferenceProcessor::clean_up_discovered_references() {
@@ -1266,14 +1289,15 @@ void ReferenceProcessor::preclean_discovered_references(
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
- YieldClosure* yield) {
+ YieldClosure* yield,
+ GCTimer* gc_timer) {
NOT_PRODUCT(verify_ok_to_handle_reflists());
// Soft references
{
- TraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC,
- false, gclog_or_tty);
+ GCTraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC,
+ false, gc_timer);
for (uint i = 0; i < _max_num_q; i++) {
if (yield->should_return()) {
return;
@@ -1285,8 +1309,8 @@ void ReferenceProcessor::preclean_discovered_references(
// Weak references
{
- TraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC,
- false, gclog_or_tty);
+ GCTraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC,
+ false, gc_timer);
for (uint i = 0; i < _max_num_q; i++) {
if (yield->should_return()) {
return;
@@ -1298,8 +1322,8 @@ void ReferenceProcessor::preclean_discovered_references(
// Final references
{
- TraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC,
- false, gclog_or_tty);
+ GCTraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC,
+ false, gc_timer);
for (uint i = 0; i < _max_num_q; i++) {
if (yield->should_return()) {
return;
@@ -1311,8 +1335,8 @@ void ReferenceProcessor::preclean_discovered_references(
// Phantom references
{
- TraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC,
- false, gclog_or_tty);
+ GCTraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC,
+ false, gc_timer);
for (uint i = 0; i < _max_num_q; i++) {
if (yield->should_return()) {
return;
diff --git a/src/share/vm/memory/referenceProcessor.hpp b/src/share/vm/memory/referenceProcessor.hpp
index 1050863f4..252cc6d62 100644
--- a/src/share/vm/memory/referenceProcessor.hpp
+++ b/src/share/vm/memory/referenceProcessor.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,8 +26,12 @@
#define SHARE_VM_MEMORY_REFERENCEPROCESSOR_HPP
#include "memory/referencePolicy.hpp"
+#include "memory/referenceProcessorStats.hpp"
+#include "memory/referenceType.hpp"
#include "oops/instanceRefKlass.hpp"
+class GCTimer;
+
// ReferenceProcessor class encapsulates the per-"collector" processing
// of java.lang.Reference objects for GC. The interface is useful for supporting
// a generational abstraction, in particular when there are multiple
@@ -204,6 +208,10 @@ public:
};
class ReferenceProcessor : public CHeapObj<mtGC> {
+
+ private:
+ size_t total_count(DiscoveredList lists[]);
+
protected:
// Compatibility with pre-4965777 JDK's
static bool _pending_list_uses_discovered_field;
@@ -282,13 +290,13 @@ class ReferenceProcessor : public CHeapObj<mtGC> {
}
// Process references with a certain reachability level.
- void process_discovered_reflist(DiscoveredList refs_lists[],
- ReferencePolicy* policy,
- bool clear_referent,
- BoolObjectClosure* is_alive,
- OopClosure* keep_alive,
- VoidClosure* complete_gc,
- AbstractRefProcTaskExecutor* task_executor);
+ size_t process_discovered_reflist(DiscoveredList refs_lists[],
+ ReferencePolicy* policy,
+ bool clear_referent,
+ BoolObjectClosure* is_alive,
+ OopClosure* keep_alive,
+ VoidClosure* complete_gc,
+ AbstractRefProcTaskExecutor* task_executor);
void process_phaseJNI(BoolObjectClosure* is_alive,
OopClosure* keep_alive,
@@ -349,7 +357,8 @@ class ReferenceProcessor : public CHeapObj<mtGC> {
void preclean_discovered_references(BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
- YieldClosure* yield);
+ YieldClosure* yield,
+ GCTimer* gc_timer);
// Delete entries in the discovered lists that have
// either a null referent or are not active. Such
@@ -500,12 +509,13 @@ class ReferenceProcessor : public CHeapObj<mtGC> {
bool discover_reference(oop obj, ReferenceType rt);
// Process references found during GC (called by the garbage collector)
- void process_discovered_references(BoolObjectClosure* is_alive,
- OopClosure* keep_alive,
- VoidClosure* complete_gc,
- AbstractRefProcTaskExecutor* task_executor);
+ ReferenceProcessorStats
+ process_discovered_references(BoolObjectClosure* is_alive,
+ OopClosure* keep_alive,
+ VoidClosure* complete_gc,
+ AbstractRefProcTaskExecutor* task_executor,
+ GCTimer *gc_timer);
- public:
// Enqueue references at end of GC (called by the garbage collector)
bool enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor = NULL);
diff --git a/src/share/vm/memory/referenceProcessorStats.hpp b/src/share/vm/memory/referenceProcessorStats.hpp
new file mode 100644
index 000000000..7f4a05ba9
--- /dev/null
+++ b/src/share/vm/memory/referenceProcessorStats.hpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012 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_MEMORY_REFERENCEPROCESSORSTATS_HPP
+#define SHARE_VM_MEMORY_REFERENCEPROCESSORSTATS_HPP
+
+#include "utilities/globalDefinitions.hpp"
+
+class ReferenceProcessor;
+
+// ReferenceProcessorStats contains statistics about how many references that
+// have been traversed when processing references during garbage collection.
+class ReferenceProcessorStats {
+ size_t _soft_count;
+ size_t _weak_count;
+ size_t _final_count;
+ size_t _phantom_count;
+
+ public:
+ ReferenceProcessorStats() :
+ _soft_count(0),
+ _weak_count(0),
+ _final_count(0),
+ _phantom_count(0) {}
+
+ ReferenceProcessorStats(size_t soft_count,
+ size_t weak_count,
+ size_t final_count,
+ size_t phantom_count) :
+ _soft_count(soft_count),
+ _weak_count(weak_count),
+ _final_count(final_count),
+ _phantom_count(phantom_count)
+ {}
+
+ size_t soft_count() const {
+ return _soft_count;
+ }
+
+ size_t weak_count() const {
+ return _weak_count;
+ }
+
+ size_t final_count() const {
+ return _final_count;
+ }
+
+ size_t phantom_count() const {
+ return _phantom_count;
+ }
+};
+#endif
diff --git a/src/share/vm/memory/referenceType.hpp b/src/share/vm/memory/referenceType.hpp
new file mode 100644
index 000000000..9496e41ed
--- /dev/null
+++ b/src/share/vm/memory/referenceType.hpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, 2013, 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_MEMORY_REFRERENCETYPE_HPP
+#define SHARE_VM_MEMORY_REFRERENCETYPE_HPP
+
+#include "utilities/debug.hpp"
+
+// ReferenceType is used to distinguish between java/lang/ref/Reference subclasses
+
+enum ReferenceType {
+ REF_NONE, // Regular class
+ REF_OTHER, // Subclass of java/lang/ref/Reference, but not subclass of one of the classes below
+ REF_SOFT, // Subclass of java/lang/ref/SoftReference
+ REF_WEAK, // Subclass of java/lang/ref/WeakReference
+ REF_FINAL, // Subclass of java/lang/ref/FinalReference
+ REF_PHANTOM // Subclass of java/lang/ref/PhantomReference
+};
+
+#endif // SHARE_VM_MEMORY_REFRERENCETYPE_HPP
diff --git a/src/share/vm/memory/universe.cpp b/src/share/vm/memory/universe.cpp
index 22af6d690..e98ef0c77 100644
--- a/src/share/vm/memory/universe.cpp
+++ b/src/share/vm/memory/universe.cpp
@@ -819,12 +819,14 @@ jint Universe::initialize_heap() {
// keep the Universe::narrow_oop_base() set in Universe::reserve_heap()
Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
if (verbose) {
- tty->print(", Compressed Oops with base: "PTR_FORMAT, Universe::narrow_oop_base());
+ tty->print(", %s: "PTR_FORMAT,
+ narrow_oop_mode_to_string(HeapBasedNarrowOop),
+ Universe::narrow_oop_base());
}
} else {
Universe::set_narrow_oop_base(0);
if (verbose) {
- tty->print(", zero based Compressed Oops");
+ tty->print(", %s", narrow_oop_mode_to_string(ZeroBasedNarrowOop));
}
#ifdef _WIN64
if (!Universe::narrow_oop_use_implicit_null_checks()) {
@@ -839,7 +841,7 @@ jint Universe::initialize_heap() {
} else {
Universe::set_narrow_oop_shift(0);
if (verbose) {
- tty->print(", 32-bits Oops");
+ tty->print(", %s", narrow_oop_mode_to_string(UnscaledNarrowOop));
}
}
}
@@ -946,6 +948,33 @@ void Universe::update_heap_info_at_gc() {
}
+const char* Universe::narrow_oop_mode_to_string(Universe::NARROW_OOP_MODE mode) {
+ switch (mode) {
+ case UnscaledNarrowOop:
+ return "32-bits Oops";
+ case ZeroBasedNarrowOop:
+ return "zero based Compressed Oops";
+ case HeapBasedNarrowOop:
+ return "Compressed Oops with base";
+ }
+
+ ShouldNotReachHere();
+ return "";
+}
+
+
+Universe::NARROW_OOP_MODE Universe::narrow_oop_mode() {
+ if (narrow_oop_base() != 0) {
+ return HeapBasedNarrowOop;
+ }
+
+ if (narrow_oop_shift() != 0) {
+ return ZeroBasedNarrowOop;
+ }
+
+ return UnscaledNarrowOop;
+}
+
void universe2_init() {
EXCEPTION_MARK;
diff --git a/src/share/vm/memory/universe.hpp b/src/share/vm/memory/universe.hpp
index 6daf75d2c..b9ff266a0 100644
--- a/src/share/vm/memory/universe.hpp
+++ b/src/share/vm/memory/universe.hpp
@@ -253,19 +253,6 @@ class Universe: AllStatic {
return m;
}
- // Narrow Oop encoding mode:
- // 0 - Use 32-bits oops without encoding when
- // NarrowOopHeapBaseMin + heap_size < 4Gb
- // 1 - Use zero based compressed oops with encoding when
- // NarrowOopHeapBaseMin + heap_size < 32Gb
- // 2 - Use compressed oops with heap base + encoding.
- enum NARROW_OOP_MODE {
- UnscaledNarrowOop = 0,
- ZeroBasedNarrowOop = 1,
- HeapBasedNarrowOop = 2
- };
- static char* preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode);
- static char* preferred_metaspace_base(size_t heap_size, NARROW_OOP_MODE mode);
static void set_narrow_oop_base(address base) {
assert(UseCompressedOops, "no compressed oops?");
_narrow_oop._base = base;
@@ -380,6 +367,21 @@ class Universe: AllStatic {
static CollectedHeap* heap() { return _collectedHeap; }
// For UseCompressedOops
+ // Narrow Oop encoding mode:
+ // 0 - Use 32-bits oops without encoding when
+ // NarrowOopHeapBaseMin + heap_size < 4Gb
+ // 1 - Use zero based compressed oops with encoding when
+ // NarrowOopHeapBaseMin + heap_size < 32Gb
+ // 2 - Use compressed oops with heap base + encoding.
+ enum NARROW_OOP_MODE {
+ UnscaledNarrowOop = 0,
+ ZeroBasedNarrowOop = 1,
+ HeapBasedNarrowOop = 2
+ };
+ static NARROW_OOP_MODE narrow_oop_mode();
+ static const char* narrow_oop_mode_to_string(NARROW_OOP_MODE mode);
+ static char* preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode);
+ static char* preferred_metaspace_base(size_t heap_size, NARROW_OOP_MODE mode);
static address narrow_oop_base() { return _narrow_oop._base; }
static bool is_narrow_oop_base(void* addr) { return (narrow_oop_base() == (address)addr); }
static int narrow_oop_shift() { return _narrow_oop._shift; }
diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp
index e158cdf3c..7d09f8132 100644
--- a/src/share/vm/oops/instanceKlass.hpp
+++ b/src/share/vm/oops/instanceKlass.hpp
@@ -26,6 +26,7 @@
#define SHARE_VM_OOPS_INSTANCEKLASS_HPP
#include "classfile/classLoaderData.hpp"
+#include "memory/referenceType.hpp"
#include "oops/annotations.hpp"
#include "oops/constMethod.hpp"
#include "oops/fieldInfo.hpp"
@@ -37,6 +38,7 @@
#include "utilities/accessFlags.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/macros.hpp"
+#include "trace/traceMacros.hpp"
// An InstanceKlass is the VM level representation of a Java class.
// It contains all information needed for at class at execution runtime.
diff --git a/src/share/vm/oops/klass.cpp b/src/share/vm/oops/klass.cpp
index f7a7334af..473942556 100644
--- a/src/share/vm/oops/klass.cpp
+++ b/src/share/vm/oops/klass.cpp
@@ -37,6 +37,7 @@
#include "oops/klass.inline.hpp"
#include "oops/oop.inline2.hpp"
#include "runtime/atomic.hpp"
+#include "trace/traceMacros.hpp"
#include "utilities/stack.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
@@ -168,7 +169,7 @@ Klass::Klass() {
set_next_sibling(NULL);
set_next_link(NULL);
set_alloc_count(0);
- TRACE_SET_KLASS_TRACE_ID(this, 0);
+ TRACE_INIT_ID(this);
set_prototype_header(markOopDesc::prototype());
set_biased_lock_revocation_count(0);
diff --git a/src/share/vm/opto/compile.cpp b/src/share/vm/opto/compile.cpp
index 3222e2596..cd650b001 100644
--- a/src/share/vm/opto/compile.cpp
+++ b/src/share/vm/opto/compile.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -63,6 +63,7 @@
#include "runtime/signature.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/timer.hpp"
+#include "trace/tracing.hpp"
#include "utilities/copy.hpp"
#ifdef TARGET_ARCH_MODEL_x86_32
# include "adfiles/ad_x86_32.hpp"
@@ -786,7 +787,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
if (failing()) return;
- print_method("Before RemoveUseless", 3);
+ print_method(PHASE_BEFORE_REMOVEUSELESS, 3);
// Remove clutter produced by parsing.
if (!failing()) {
@@ -1801,9 +1802,9 @@ void Compile::inline_string_calls(bool parse_time) {
{
ResourceMark rm;
- print_method("Before StringOpts", 3);
+ print_method(PHASE_BEFORE_STRINGOPTS, 3);
PhaseStringOpts pso(initial_gvn(), for_igvn());
- print_method("After StringOpts", 3);
+ print_method(PHASE_AFTER_STRINGOPTS, 3);
}
// now inline anything that we skipped the first time around
@@ -1958,7 +1959,7 @@ void Compile::Optimize() {
NOT_PRODUCT( verify_graph_edges(); )
- print_method("After Parsing");
+ print_method(PHASE_AFTER_PARSING);
{
// Iterative Global Value Numbering, including ideal transforms
@@ -1969,7 +1970,7 @@ void Compile::Optimize() {
igvn.optimize();
}
- print_method("Iter GVN 1", 2);
+ print_method(PHASE_ITER_GVN1, 2);
if (failing()) return;
@@ -1978,7 +1979,7 @@ void Compile::Optimize() {
inline_incrementally(igvn);
}
- print_method("Incremental Inline", 2);
+ print_method(PHASE_INCREMENTAL_INLINE, 2);
if (failing()) return;
@@ -1987,7 +1988,7 @@ void Compile::Optimize() {
// Inline valueOf() methods now.
inline_boxing_calls(igvn);
- print_method("Incremental Boxing Inline", 2);
+ print_method(PHASE_INCREMENTAL_BOXING_INLINE, 2);
if (failing()) return;
}
@@ -2002,7 +2003,7 @@ void Compile::Optimize() {
// Cleanup graph (remove dead nodes).
TracePhase t2("idealLoop", &_t_idealLoop, true);
PhaseIdealLoop ideal_loop( igvn, false, true );
- if (major_progress()) print_method("PhaseIdealLoop before EA", 2);
+ if (major_progress()) print_method(PHASE_PHASEIDEAL_BEFORE_EA, 2);
if (failing()) return;
}
ConnectionGraph::do_analysis(this, &igvn);
@@ -2011,7 +2012,7 @@ void Compile::Optimize() {
// Optimize out fields loads from scalar replaceable allocations.
igvn.optimize();
- print_method("Iter GVN after EA", 2);
+ print_method(PHASE_ITER_GVN_AFTER_EA, 2);
if (failing()) return;
@@ -2022,7 +2023,7 @@ void Compile::Optimize() {
igvn.set_delay_transform(false);
igvn.optimize();
- print_method("Iter GVN after eliminating allocations and locks", 2);
+ print_method(PHASE_ITER_GVN_AFTER_ELIMINATION, 2);
if (failing()) return;
}
@@ -2038,7 +2039,7 @@ void Compile::Optimize() {
TracePhase t2("idealLoop", &_t_idealLoop, true);
PhaseIdealLoop ideal_loop( igvn, true );
loop_opts_cnt--;
- if (major_progress()) print_method("PhaseIdealLoop 1", 2);
+ if (major_progress()) print_method(PHASE_PHASEIDEALLOOP1, 2);
if (failing()) return;
}
// Loop opts pass if partial peeling occurred in previous pass
@@ -2046,7 +2047,7 @@ void Compile::Optimize() {
TracePhase t3("idealLoop", &_t_idealLoop, true);
PhaseIdealLoop ideal_loop( igvn, false );
loop_opts_cnt--;
- if (major_progress()) print_method("PhaseIdealLoop 2", 2);
+ if (major_progress()) print_method(PHASE_PHASEIDEALLOOP2, 2);
if (failing()) return;
}
// Loop opts pass for loop-unrolling before CCP
@@ -2054,7 +2055,7 @@ void Compile::Optimize() {
TracePhase t4("idealLoop", &_t_idealLoop, true);
PhaseIdealLoop ideal_loop( igvn, false );
loop_opts_cnt--;
- if (major_progress()) print_method("PhaseIdealLoop 3", 2);
+ if (major_progress()) print_method(PHASE_PHASEIDEALLOOP3, 2);
}
if (!failing()) {
// Verify that last round of loop opts produced a valid graph
@@ -2071,7 +2072,7 @@ void Compile::Optimize() {
TracePhase t2("ccp", &_t_ccp, true);
ccp.do_transform();
}
- print_method("PhaseCPP 1", 2);
+ print_method(PHASE_CPP1, 2);
assert( true, "Break here to ccp.dump_old2new_map()");
@@ -2082,7 +2083,7 @@ void Compile::Optimize() {
igvn.optimize();
}
- print_method("Iter GVN 2", 2);
+ print_method(PHASE_ITER_GVN2, 2);
if (failing()) return;
@@ -2095,7 +2096,7 @@ void Compile::Optimize() {
assert( cnt++ < 40, "infinite cycle in loop optimization" );
PhaseIdealLoop ideal_loop( igvn, true);
loop_opts_cnt--;
- if (major_progress()) print_method("PhaseIdealLoop iterations", 2);
+ if (major_progress()) print_method(PHASE_PHASEIDEALLOOP_ITERATIONS, 2);
if (failing()) return;
}
}
@@ -2128,7 +2129,7 @@ void Compile::Optimize() {
}
}
- print_method("Optimize finished", 2);
+ print_method(PHASE_OPTIMIZE_FINISHED, 2);
}
@@ -2176,7 +2177,7 @@ void Compile::Code_Gen() {
cfg.GlobalCodeMotion(m,unique(),proj_list);
if (failing()) return;
- print_method("Global code motion", 2);
+ print_method(PHASE_GLOBAL_CODE_MOTION, 2);
NOT_PRODUCT( verify_graph_edges(); )
@@ -2229,7 +2230,7 @@ void Compile::Code_Gen() {
Output();
}
- print_method("Final Code");
+ print_method(PHASE_FINAL_CODE);
// He's dead, Jim.
_cfg = (PhaseCFG*)0xdeadbeef;
@@ -3316,8 +3317,16 @@ void Compile::record_failure(const char* reason) {
// Record the first failure reason.
_failure_reason = reason;
}
+
+ EventCompilerFailure event;
+ if (event.should_commit()) {
+ event.set_compileID(Compile::compile_id());
+ event.set_failure(reason);
+ event.commit();
+ }
+
if (!C->failure_reason_is(C2Compiler::retry_no_subsuming_loads())) {
- C->print_method(_failure_reason);
+ C->print_method(PHASE_FAILURE);
}
_root = NULL; // flush the graph, too
}
diff --git a/src/share/vm/opto/compile.hpp b/src/share/vm/opto/compile.hpp
index e0f1cd23d..60787464b 100644
--- a/src/share/vm/opto/compile.hpp
+++ b/src/share/vm/opto/compile.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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,10 +36,12 @@
#include "libadt/vectset.hpp"
#include "memory/resourceArea.hpp"
#include "opto/idealGraphPrinter.hpp"
+#include "opto/phasetype.hpp"
#include "opto/phase.hpp"
#include "opto/regmask.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/vmThread.hpp"
+#include "trace/tracing.hpp"
class Block;
class Bundle;
@@ -322,6 +324,7 @@ class Compile : public Phase {
IdealGraphPrinter* _printer;
#endif
+
// Node management
uint _unique; // Counter for unique Node indices
VectorSet _dead_node_list; // Set of dead nodes
@@ -573,17 +576,43 @@ class Compile : public Phase {
bool has_method_handle_invokes() const { return _has_method_handle_invokes; }
void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; }
+ jlong _latest_stage_start_counter;
+
void begin_method() {
#ifndef PRODUCT
if (_printer) _printer->begin_method(this);
#endif
+ C->_latest_stage_start_counter = os::elapsed_counter();
}
- void print_method(const char * name, int level = 1) {
+
+ void print_method(CompilerPhaseType cpt, int level = 1) {
+ EventCompilerPhase event(UNTIMED);
+ if (event.should_commit()) {
+ event.set_starttime(C->_latest_stage_start_counter);
+ event.set_endtime(os::elapsed_counter());
+ event.set_phase((u1) cpt);
+ event.set_compileID(C->_compile_id);
+ event.set_phaseLevel(level);
+ event.commit();
+ }
+
+
#ifndef PRODUCT
- if (_printer) _printer->print_method(this, name, level);
+ if (_printer) _printer->print_method(this, CompilerPhaseTypeHelper::to_string(cpt), level);
#endif
+ C->_latest_stage_start_counter = os::elapsed_counter();
}
- void end_method() {
+
+ void end_method(int level = 1) {
+ EventCompilerPhase event(UNTIMED);
+ if (event.should_commit()) {
+ event.set_starttime(C->_latest_stage_start_counter);
+ event.set_endtime(os::elapsed_counter());
+ event.set_phase((u1) PHASE_END);
+ event.set_compileID(C->_compile_id);
+ event.set_phaseLevel(level);
+ event.commit();
+ }
#ifndef PRODUCT
if (_printer) _printer->end_method();
#endif
diff --git a/src/share/vm/opto/escape.cpp b/src/share/vm/opto/escape.cpp
index 96f0011b3..fd561a0c2 100644
--- a/src/share/vm/opto/escape.cpp
+++ b/src/share/vm/opto/escape.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, 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,7 +277,7 @@ bool ConnectionGraph::compute_escape() {
// scalar replaceable objects.
split_unique_types(alloc_worklist);
if (C->failing()) return false;
- C->print_method("After Escape Analysis", 2);
+ C->print_method(PHASE_AFTER_EA, 2);
#ifdef ASSERT
} else if (Verbose && (PrintEscapeAnalysis || PrintEliminateAllocations)) {
diff --git a/src/share/vm/opto/library_call.cpp b/src/share/vm/opto/library_call.cpp
index 609b70226..728d89253 100644
--- a/src/share/vm/opto/library_call.cpp
+++ b/src/share/vm/opto/library_call.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, 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,6 +38,7 @@
#include "opto/subnode.hpp"
#include "prims/nativeLookup.hpp"
#include "runtime/sharedRuntime.hpp"
+#include "trace/traceMacros.hpp"
class LibraryIntrinsic : public InlineCallGenerator {
// Extend the set of intrinsics known to the runtime:
diff --git a/src/share/vm/opto/loopnode.cpp b/src/share/vm/opto/loopnode.cpp
index c323d02f8..ab05d186b 100644
--- a/src/share/vm/opto/loopnode.cpp
+++ b/src/share/vm/opto/loopnode.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, 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
@@ -440,7 +440,7 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
// ---- SUCCESS! Found A Trip-Counted Loop! -----
//
assert(x->Opcode() == Op_Loop, "regular loops only");
- C->print_method("Before CountedLoop", 3);
+ C->print_method(PHASE_BEFORE_CLOOPS, 3);
Node *hook = new (C) Node(6);
@@ -791,7 +791,7 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
}
#endif
- C->print_method("After CountedLoop", 3);
+ C->print_method(PHASE_AFTER_CLOOPS, 3);
return true;
}
@@ -2164,7 +2164,7 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool skip_loop_opts)
// Split shared headers and insert loop landing pads.
// Do not bother doing this on the Root loop of course.
if( !_verify_me && !_verify_only && _ltree_root->_child ) {
- C->print_method("Before beautify loops", 3);
+ C->print_method(PHASE_BEFORE_BEAUTIFY_LOOPS, 3);
if( _ltree_root->_child->beautify_loops( this ) ) {
// Re-build loop tree!
_ltree_root->_child = NULL;
@@ -2178,7 +2178,7 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool skip_loop_opts)
// Reset loop nesting depth
_ltree_root->set_nest( 0 );
- C->print_method("After beautify loops", 3);
+ C->print_method(PHASE_AFTER_BEAUTIFY_LOOPS, 3);
}
}
diff --git a/src/share/vm/opto/matcher.cpp b/src/share/vm/opto/matcher.cpp
index 91b4448c9..4f3aad763 100644
--- a/src/share/vm/opto/matcher.cpp
+++ b/src/share/vm/opto/matcher.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -317,7 +317,7 @@ void Matcher::match( ) {
find_shared( C->root() );
find_shared( C->top() );
- C->print_method("Before Matching");
+ C->print_method(PHASE_BEFORE_MATCHING);
// Create new ideal node ConP #NULL even if it does exist in old space
// to avoid false sharing if the corresponding mach node is not used.
@@ -1848,7 +1848,7 @@ void Matcher::ReduceOper( State *s, int rule, Node *&mem, MachNode *mach ) {
for( uint i=0; kid != NULL && i<2; kid = s->_kids[1], i++ ) { // binary tree
int newrule;
- if( i == 0 )
+ if( i == 0)
newrule = kid->_rule[_leftOp[rule]];
else
newrule = kid->_rule[_rightOp[rule]];
diff --git a/src/share/vm/opto/phasetype.hpp b/src/share/vm/opto/phasetype.hpp
new file mode 100644
index 000000000..ba769d410
--- /dev/null
+++ b/src/share/vm/opto/phasetype.hpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2012, 2013, 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_OPTO_PHASETYPE_HPP
+#define SHARE_VM_OPTO_PHASETYPE_HPP
+
+enum CompilerPhaseType {
+ PHASE_BEFORE_STRINGOPTS,
+ PHASE_AFTER_STRINGOPTS,
+ PHASE_BEFORE_REMOVEUSELESS,
+ PHASE_AFTER_PARSING,
+ PHASE_ITER_GVN1,
+ PHASE_PHASEIDEAL_BEFORE_EA,
+ PHASE_ITER_GVN_AFTER_EA,
+ PHASE_ITER_GVN_AFTER_ELIMINATION,
+ PHASE_PHASEIDEALLOOP1,
+ PHASE_PHASEIDEALLOOP2,
+ PHASE_PHASEIDEALLOOP3,
+ PHASE_CPP1,
+ PHASE_ITER_GVN2,
+ PHASE_PHASEIDEALLOOP_ITERATIONS,
+ PHASE_OPTIMIZE_FINISHED,
+ PHASE_GLOBAL_CODE_MOTION,
+ PHASE_FINAL_CODE,
+ PHASE_AFTER_EA,
+ PHASE_BEFORE_CLOOPS,
+ PHASE_AFTER_CLOOPS,
+ PHASE_BEFORE_BEAUTIFY_LOOPS,
+ PHASE_AFTER_BEAUTIFY_LOOPS,
+ PHASE_BEFORE_MATCHING,
+ PHASE_INCREMENTAL_INLINE,
+ PHASE_INCREMENTAL_BOXING_INLINE,
+ PHASE_END,
+ PHASE_FAILURE,
+
+ PHASE_NUM_TYPES
+};
+
+class CompilerPhaseTypeHelper {
+ public:
+ static const char* to_string(CompilerPhaseType cpt) {
+ switch (cpt) {
+ case PHASE_BEFORE_STRINGOPTS: return "Before StringOpts";
+ case PHASE_AFTER_STRINGOPTS: return "After StringOpts";
+ case PHASE_BEFORE_REMOVEUSELESS: return "Before RemoveUseless";
+ case PHASE_AFTER_PARSING: return "After Parsing";
+ case PHASE_ITER_GVN1: return "Iter GVN 1";
+ case PHASE_PHASEIDEAL_BEFORE_EA: return "PhaseIdealLoop before EA";
+ case PHASE_ITER_GVN_AFTER_EA: return "Iter GVN after EA";
+ case PHASE_ITER_GVN_AFTER_ELIMINATION: return "Iter GVN after eliminating allocations and locks";
+ case PHASE_PHASEIDEALLOOP1: return "PhaseIdealLoop 1";
+ case PHASE_PHASEIDEALLOOP2: return "PhaseIdealLoop 2";
+ case PHASE_PHASEIDEALLOOP3: return "PhaseIdealLoop 3";
+ case PHASE_CPP1: return "PhaseCPP 1";
+ case PHASE_ITER_GVN2: return "Iter GVN 2";
+ case PHASE_PHASEIDEALLOOP_ITERATIONS: return "PhaseIdealLoop iterations";
+ case PHASE_OPTIMIZE_FINISHED: return "Optimize finished";
+ case PHASE_GLOBAL_CODE_MOTION: return "Global code motion";
+ case PHASE_FINAL_CODE: return "Final Code";
+ case PHASE_AFTER_EA: return "After Escape Analysis";
+ case PHASE_BEFORE_CLOOPS: return "Before CountedLoop";
+ case PHASE_AFTER_CLOOPS: return "After CountedLoop";
+ case PHASE_BEFORE_BEAUTIFY_LOOPS: return "Before beautify loops";
+ case PHASE_AFTER_BEAUTIFY_LOOPS: return "After beautify loops";
+ case PHASE_BEFORE_MATCHING: return "Before Matching";
+ case PHASE_INCREMENTAL_INLINE: return "Incremental Inline";
+ case PHASE_INCREMENTAL_BOXING_INLINE: return "Incremental Boxing Inline";
+ case PHASE_END: return "End";
+ case PHASE_FAILURE: return "Failure";
+ default:
+ ShouldNotReachHere();
+ return NULL;
+ }
+ }
+};
+
+#endif //SHARE_VM_OPTO_PHASETYPE_HPP
diff --git a/src/share/vm/precompiled/precompiled.hpp b/src/share/vm/precompiled/precompiled.hpp
index 118fe9c1b..d4be22e6c 100644
--- a/src/share/vm/precompiled/precompiled.hpp
+++ b/src/share/vm/precompiled/precompiled.hpp
@@ -26,7 +26,6 @@
// or if the user passes USE_PRECOMPILED_HEADER=0 to the makefiles.
#ifndef DONT_USE_PRECOMPILED_HEADER
-
# include "asm/assembler.hpp"
# include "asm/assembler.inline.hpp"
# include "asm/codeBuffer.hpp"
diff --git a/src/share/vm/prims/jni.cpp b/src/share/vm/prims/jni.cpp
index 2c81df1ab..85f3e2e0e 100644
--- a/src/share/vm/prims/jni.cpp
+++ b/src/share/vm/prims/jni.cpp
@@ -74,7 +74,6 @@
#include "runtime/vm_operations.hpp"
#include "services/runtimeService.hpp"
#include "trace/tracing.hpp"
-#include "trace/traceEventTypes.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
@@ -5014,6 +5013,7 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args_) {
#ifndef PRODUCT
+#include "gc_implementation/shared/gcTimer.hpp"
#include "gc_interface/collectedHeap.hpp"
#if INCLUDE_ALL_GCS
#include "gc_implementation/g1/heapRegionRemSet.hpp"
@@ -5031,6 +5031,7 @@ void execute_internal_vm_tests() {
if (ExecuteInternalVMTests) {
tty->print_cr("Running internal VM tests");
run_unit_test(GlobalDefinitions::test_globals());
+ run_unit_test(GCTimerAllTest::all());
run_unit_test(arrayOopDesc::test_max_array_length());
run_unit_test(CollectedHeap::test_is_in());
run_unit_test(QuickSort::test_quick_sort());
@@ -5131,9 +5132,11 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, v
JvmtiExport::post_thread_start(thread);
}
- EVENT_BEGIN(TraceEventThreadStart, event);
- EVENT_COMMIT(event,
- EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(thread->threadObj())));
+ EventThreadStart event;
+ if (event.should_commit()) {
+ event.set_javalangthread(java_lang_Thread::thread_id(thread->threadObj()));
+ event.commit();
+ }
// Check if we should compile all classes on bootclasspath
NOT_PRODUCT(if (CompileTheWorld) ClassLoader::compile_the_world();)
@@ -5334,9 +5337,11 @@ static jint attach_current_thread(JavaVM *vm, void **penv, void *_args, bool dae
JvmtiExport::post_thread_start(thread);
}
- EVENT_BEGIN(TraceEventThreadStart, event);
- EVENT_COMMIT(event,
- EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(thread->threadObj())));
+ EventThreadStart event;
+ if (event.should_commit()) {
+ event.set_javalangthread(java_lang_Thread::thread_id(thread->threadObj()));
+ event.commit();
+ }
*(JNIEnv**)penv = thread->jni_environment();
diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp
index 733d04a1b..8df99043d 100644
--- a/src/share/vm/prims/jvm.cpp
+++ b/src/share/vm/prims/jvm.cpp
@@ -59,6 +59,7 @@
#include "services/attachListener.hpp"
#include "services/management.hpp"
#include "services/threadService.hpp"
+#include "trace/tracing.hpp"
#include "utilities/copy.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/dtrace.hpp"
@@ -2999,6 +3000,8 @@ JVM_ENTRY(void, JVM_Sleep(JNIEnv* env, jclass threadClass, jlong millis))
millis);
#endif /* USDT2 */
+ EventThreadSleep event;
+
if (millis == 0) {
// When ConvertSleepToYield is on, this matches the classic VM implementation of
// JVM_Sleep. Critical for similar threading behaviour (Win32)
@@ -3019,6 +3022,10 @@ JVM_ENTRY(void, JVM_Sleep(JNIEnv* env, jclass threadClass, jlong millis))
// An asynchronous exception (e.g., ThreadDeathException) could have been thrown on
// us while we were sleeping. We do not overwrite those.
if (!HAS_PENDING_EXCEPTION) {
+ if (event.should_commit()) {
+ event.set_time(millis);
+ event.commit();
+ }
#ifndef USDT2
HS_DTRACE_PROBE1(hotspot, thread__sleep__end,1);
#else /* USDT2 */
@@ -3032,6 +3039,10 @@ JVM_ENTRY(void, JVM_Sleep(JNIEnv* env, jclass threadClass, jlong millis))
}
thread->osthread()->set_state(old_state);
}
+ if (event.should_commit()) {
+ event.set_time(millis);
+ event.commit();
+ }
#ifndef USDT2
HS_DTRACE_PROBE1(hotspot, thread__sleep__end,0);
#else /* USDT2 */
diff --git a/src/share/vm/prims/jvmtiGen.java b/src/share/vm/prims/jvmtiGen.java
index 74191ed60..f2cdbe9ae 100644
--- a/src/share/vm/prims/jvmtiGen.java
+++ b/src/share/vm/prims/jvmtiGen.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, 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
@@ -31,7 +31,6 @@ import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
-
// For write operation
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
@@ -129,6 +128,7 @@ public class jvmtiGen
factory.setNamespaceAware(true);
factory.setValidating(true);
+ factory.setXIncludeAware(true);
try {
File datafile = new File(inFileName);
diff --git a/src/share/vm/prims/jvmtiImpl.cpp b/src/share/vm/prims/jvmtiImpl.cpp
index c569b8fdc..6f8b41297 100644
--- a/src/share/vm/prims/jvmtiImpl.cpp
+++ b/src/share/vm/prims/jvmtiImpl.cpp
@@ -360,19 +360,14 @@ void VM_ChangeBreakpoints::doit() {
case CLEAR_BREAKPOINT:
_breakpoints->clear_at_safepoint(*_bp);
break;
- case CLEAR_ALL_BREAKPOINT:
- _breakpoints->clearall_at_safepoint();
- break;
default:
assert(false, "Unknown operation");
}
}
void VM_ChangeBreakpoints::oops_do(OopClosure* f) {
- // This operation keeps breakpoints alive
- if (_breakpoints != NULL) {
- _breakpoints->oops_do(f);
- }
+ // The JvmtiBreakpoints in _breakpoints will be visited via
+ // JvmtiExport::oops_do.
if (_bp != NULL) {
_bp->oops_do(f);
}
@@ -433,23 +428,13 @@ void JvmtiBreakpoints::clear_at_safepoint(JvmtiBreakpoint& bp) {
}
}
-void JvmtiBreakpoints::clearall_at_safepoint() {
- assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
-
- int len = _bps.length();
- for (int i=0; i<len; i++) {
- _bps.at(i).clear();
- }
- _bps.clear();
-}
-
int JvmtiBreakpoints::length() { return _bps.length(); }
int JvmtiBreakpoints::set(JvmtiBreakpoint& bp) {
if ( _bps.find(bp) != -1) {
return JVMTI_ERROR_DUPLICATE;
}
- VM_ChangeBreakpoints set_breakpoint(this,VM_ChangeBreakpoints::SET_BREAKPOINT, &bp);
+ VM_ChangeBreakpoints set_breakpoint(VM_ChangeBreakpoints::SET_BREAKPOINT, &bp);
VMThread::execute(&set_breakpoint);
return JVMTI_ERROR_NONE;
}
@@ -459,7 +444,7 @@ int JvmtiBreakpoints::clear(JvmtiBreakpoint& bp) {
return JVMTI_ERROR_NOT_FOUND;
}
- VM_ChangeBreakpoints clear_breakpoint(this,VM_ChangeBreakpoints::CLEAR_BREAKPOINT, &bp);
+ VM_ChangeBreakpoints clear_breakpoint(VM_ChangeBreakpoints::CLEAR_BREAKPOINT, &bp);
VMThread::execute(&clear_breakpoint);
return JVMTI_ERROR_NONE;
}
@@ -490,11 +475,6 @@ void JvmtiBreakpoints::clearall_in_class_at_safepoint(Klass* klass) {
}
}
-void JvmtiBreakpoints::clearall() {
- VM_ChangeBreakpoints clearall_breakpoint(this,VM_ChangeBreakpoints::CLEAR_ALL_BREAKPOINT);
- VMThread::execute(&clearall_breakpoint);
-}
-
//
// class JvmtiCurrentBreakpoints
//
diff --git a/src/share/vm/prims/jvmtiImpl.hpp b/src/share/vm/prims/jvmtiImpl.hpp
index 204bd83f1..c7beb1762 100644
--- a/src/share/vm/prims/jvmtiImpl.hpp
+++ b/src/share/vm/prims/jvmtiImpl.hpp
@@ -204,47 +204,6 @@ public:
///////////////////////////////////////////////////////////////
//
-// class VM_ChangeBreakpoints
-// Used by : JvmtiBreakpoints
-// Used by JVMTI methods: none directly.
-// Note: A Helper class.
-//
-// VM_ChangeBreakpoints implements a VM_Operation for ALL modifications to the JvmtiBreakpoints class.
-//
-
-class VM_ChangeBreakpoints : public VM_Operation {
-private:
- JvmtiBreakpoints* _breakpoints;
- int _operation;
- JvmtiBreakpoint* _bp;
-
-public:
- enum { SET_BREAKPOINT=0, CLEAR_BREAKPOINT=1, CLEAR_ALL_BREAKPOINT=2 };
-
- VM_ChangeBreakpoints(JvmtiBreakpoints* breakpoints, int operation) {
- _breakpoints = breakpoints;
- _bp = NULL;
- _operation = operation;
- assert(breakpoints != NULL, "breakpoints != NULL");
- assert(operation == CLEAR_ALL_BREAKPOINT, "unknown breakpoint operation");
- }
- VM_ChangeBreakpoints(JvmtiBreakpoints* breakpoints, int operation, JvmtiBreakpoint *bp) {
- _breakpoints = breakpoints;
- _bp = bp;
- _operation = operation;
- assert(breakpoints != NULL, "breakpoints != NULL");
- assert(bp != NULL, "bp != NULL");
- assert(operation == SET_BREAKPOINT || operation == CLEAR_BREAKPOINT , "unknown breakpoint operation");
- }
-
- VMOp_Type type() const { return VMOp_ChangeBreakpoints; }
- void doit();
- void oops_do(OopClosure* f);
-};
-
-
-///////////////////////////////////////////////////////////////
-//
// class JvmtiBreakpoints
// Used by : JvmtiCurrentBreakpoints
// Used by JVMTI methods: none directly
@@ -271,7 +230,6 @@ private:
friend class VM_ChangeBreakpoints;
void set_at_safepoint(JvmtiBreakpoint& bp);
void clear_at_safepoint(JvmtiBreakpoint& bp);
- void clearall_at_safepoint();
static void do_element(GrowableElement *e);
@@ -286,7 +244,6 @@ public:
int set(JvmtiBreakpoint& bp);
int clear(JvmtiBreakpoint& bp);
void clearall_in_class_at_safepoint(Klass* klass);
- void clearall();
void gc_epilogue();
};
@@ -344,6 +301,40 @@ bool JvmtiCurrentBreakpoints::is_breakpoint(address bcp) {
return false;
}
+
+///////////////////////////////////////////////////////////////
+//
+// class VM_ChangeBreakpoints
+// Used by : JvmtiBreakpoints
+// Used by JVMTI methods: none directly.
+// Note: A Helper class.
+//
+// VM_ChangeBreakpoints implements a VM_Operation for ALL modifications to the JvmtiBreakpoints class.
+//
+
+class VM_ChangeBreakpoints : public VM_Operation {
+private:
+ JvmtiBreakpoints* _breakpoints;
+ int _operation;
+ JvmtiBreakpoint* _bp;
+
+public:
+ enum { SET_BREAKPOINT=0, CLEAR_BREAKPOINT=1 };
+
+ VM_ChangeBreakpoints(int operation, JvmtiBreakpoint *bp) {
+ JvmtiBreakpoints& current_bps = JvmtiCurrentBreakpoints::get_jvmti_breakpoints();
+ _breakpoints = &current_bps;
+ _bp = bp;
+ _operation = operation;
+ assert(bp != NULL, "bp != NULL");
+ }
+
+ VMOp_Type type() const { return VMOp_ChangeBreakpoints; }
+ void doit();
+ void oops_do(OopClosure* f);
+};
+
+
///////////////////////////////////////////////////////////////
// The get/set local operations must only be done by the VM thread
// because the interpreter version needs to access oop maps, which can
diff --git a/src/share/vm/prims/unsafe.cpp b/src/share/vm/prims/unsafe.cpp
index f30ab81ae..e37b0c80d 100644
--- a/src/share/vm/prims/unsafe.cpp
+++ b/src/share/vm/prims/unsafe.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, 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,6 +36,7 @@
#include "runtime/reflection.hpp"
#include "runtime/synchronizer.hpp"
#include "services/threadService.hpp"
+#include "trace/tracing.hpp"
#include "utilities/copy.hpp"
#include "utilities/dtrace.hpp"
@@ -1204,6 +1205,7 @@ UNSAFE_END
UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time))
UnsafeWrapper("Unsafe_Park");
+ EventThreadPark event;
#ifndef USDT2
HS_DTRACE_PROBE3(hotspot, thread__park__begin, thread->parker(), (int) isAbsolute, time);
#else /* USDT2 */
@@ -1218,6 +1220,13 @@ UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute,
HOTSPOT_THREAD_PARK_END(
(uintptr_t) thread->parker());
#endif /* USDT2 */
+ if (event.should_commit()) {
+ oop obj = thread->current_park_blocker();
+ event.set_klass(obj ? obj->klass() : NULL);
+ event.set_timeout(time);
+ event.set_address(obj ? (TYPE_ADDRESS) (uintptr_t) obj : 0);
+ event.commit();
+ }
UNSAFE_END
UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread))
diff --git a/src/share/vm/runtime/frame.hpp b/src/share/vm/runtime/frame.hpp
index 1baa38fb6..87581ab8d 100644
--- a/src/share/vm/runtime/frame.hpp
+++ b/src/share/vm/runtime/frame.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -134,6 +134,7 @@ class frame VALUE_OBJ_CLASS_SPEC {
bool is_interpreted_frame() const;
bool is_java_frame() const;
bool is_entry_frame() const; // Java frame called from C?
+ bool is_stub_frame() const;
bool is_ignored_frame() const;
bool is_native_frame() const;
bool is_runtime_frame() const;
diff --git a/src/share/vm/runtime/frame.inline.hpp b/src/share/vm/runtime/frame.inline.hpp
index 7c1890438..e00d2cf9d 100644
--- a/src/share/vm/runtime/frame.inline.hpp
+++ b/src/share/vm/runtime/frame.inline.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -79,6 +79,10 @@ inline bool frame::is_entry_frame() const {
return StubRoutines::returns_to_call_stub(pc());
}
+inline bool frame::is_stub_frame() const {
+ return StubRoutines::is_stub_code(pc()) || (_cb != NULL && _cb->is_adapter_blob());
+}
+
inline bool frame::is_first_frame() const {
return is_entry_frame() && entry_frame_is_first();
}
diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp
index aec1736a4..b1adcf7fc 100644
--- a/src/share/vm/runtime/globals.hpp
+++ b/src/share/vm/runtime/globals.hpp
@@ -2311,6 +2311,10 @@ class CommandLineFlags {
"Print diagnostic message when GC is stalled" \
"by JNI critical section") \
\
+ experimental(double, ObjectCountCutOffPercent, 0.5, \
+ "The percentage of the used heap that the instances of a class " \
+ "must occupy for the class to generate a trace event.") \
+ \
/* GC log rotation setting */ \
\
product(bool, UseGCLogFileRotation, false, \
@@ -3688,7 +3692,13 @@ class CommandLineFlags {
experimental(uintx, ArrayAllocatorMallocLimit, \
SOLARIS_ONLY(64*K) NOT_SOLARIS(max_uintx), \
"Allocation less than this value will be allocated " \
- "using malloc. Larger allocations will use mmap.")
+ "using malloc. Larger allocations will use mmap.") \
+ \
+ product(bool, EnableTracing, false, \
+ "Enable event-based tracing") \
+ product(bool, UseLockedTracing, false, \
+ "Use locked-tracing when doing event-based tracing")
+
/*
* Macros for factoring of globals
diff --git a/src/share/vm/runtime/java.cpp b/src/share/vm/runtime/java.cpp
index f9be22344..7795fb92a 100644
--- a/src/share/vm/runtime/java.cpp
+++ b/src/share/vm/runtime/java.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -60,7 +60,6 @@
#include "services/memReporter.hpp"
#include "services/memTracker.hpp"
#include "trace/tracing.hpp"
-#include "trace/traceEventTypes.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/histogram.hpp"
@@ -528,9 +527,12 @@ void before_exit(JavaThread * thread) {
JvmtiExport::post_thread_end(thread);
}
- EVENT_BEGIN(TraceEventThreadEnd, event);
- EVENT_COMMIT(event,
- EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(thread->threadObj())));
+
+ EventThreadEnd event;
+ if (event.should_commit()) {
+ event.set_javalangthread(java_lang_Thread::thread_id(thread->threadObj()));
+ event.commit();
+ }
// Always call even when there are not JVMTI environments yet, since environments
// may be attached late and JVMTI must track phases of VM execution
diff --git a/src/share/vm/runtime/mutexLocker.cpp b/src/share/vm/runtime/mutexLocker.cpp
index c386ae8f4..14e65081d 100644
--- a/src/share/vm/runtime/mutexLocker.cpp
+++ b/src/share/vm/runtime/mutexLocker.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -270,13 +270,12 @@ void mutex_init() {
def(MethodCompileQueue_lock , Monitor, nonleaf+4, true );
def(Debug2_lock , Mutex , nonleaf+4, true );
def(Debug3_lock , Mutex , nonleaf+4, true );
- def(ProfileVM_lock , Monitor, nonleaf+4, false); // used for profiling of the VMThread
+ def(ProfileVM_lock , Monitor, special, false); // used for profiling of the VMThread
def(CompileThread_lock , Monitor, nonleaf+5, false );
- def(JfrQuery_lock , Monitor, nonleaf, true); // JFR locks, keep these in consecutive order
- def(JfrMsg_lock , Monitor, nonleaf+2, true);
- def(JfrBuffer_lock , Mutex, nonleaf+3, true);
- def(JfrStream_lock , Mutex, nonleaf+4, true);
+ def(JfrMsg_lock , Monitor, leaf, true);
+ def(JfrBuffer_lock , Mutex, nonleaf+1, true);
+ def(JfrStream_lock , Mutex, nonleaf+2, true);
def(PeriodicTask_lock , Monitor, nonleaf+5, true);
}
diff --git a/src/share/vm/runtime/objectMonitor.cpp b/src/share/vm/runtime/objectMonitor.cpp
index 27b6243a5..523887502 100644
--- a/src/share/vm/runtime/objectMonitor.cpp
+++ b/src/share/vm/runtime/objectMonitor.cpp
@@ -36,7 +36,10 @@
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.inline.hpp"
#include "services/threadService.hpp"
+#include "trace/tracing.hpp"
+#include "trace/traceMacros.hpp"
#include "utilities/dtrace.hpp"
+#include "utilities/macros.hpp"
#include "utilities/preserveException.hpp"
#ifdef TARGET_OS_FAMILY_linux
# include "os_linux.inline.hpp"
@@ -371,6 +374,8 @@ void ATTR ObjectMonitor::enter(TRAPS) {
// Ensure the object-monitor relationship remains stable while there's contention.
Atomic::inc_ptr(&_count);
+ EventJavaMonitorEnter event;
+
{ // Change java thread status to indicate blocked on monitor enter.
JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this);
@@ -402,7 +407,7 @@ void ATTR ObjectMonitor::enter(TRAPS) {
//
_recursions = 0 ;
_succ = NULL ;
- exit (Self) ;
+ exit (false, Self) ;
jt->java_suspend_self();
}
@@ -435,6 +440,14 @@ void ATTR ObjectMonitor::enter(TRAPS) {
if (JvmtiExport::should_post_monitor_contended_entered()) {
JvmtiExport::post_monitor_contended_entered(jt, this);
}
+
+ if (event.should_commit()) {
+ event.set_klass(((oop)this->object())->klass());
+ event.set_previousOwner((TYPE_JAVALANGTHREAD)_previous_owner_tid);
+ event.set_address((TYPE_ADDRESS)(uintptr_t)(this->object_addr()));
+ event.commit();
+ }
+
if (ObjectMonitor::_sync_ContendedLockAttempts != NULL) {
ObjectMonitor::_sync_ContendedLockAttempts->inc() ;
}
@@ -917,7 +930,7 @@ void ObjectMonitor::UnlinkAfterAcquire (Thread * Self, ObjectWaiter * SelfNode)
// Both impinge on OS scalability. Given that, at most one thread parked on
// a monitor will use a timer.
-void ATTR ObjectMonitor::exit(TRAPS) {
+void ATTR ObjectMonitor::exit(bool not_suspended, TRAPS) {
Thread * Self = THREAD ;
if (THREAD != _owner) {
if (THREAD->is_lock_owned((address) _owner)) {
@@ -954,6 +967,14 @@ void ATTR ObjectMonitor::exit(TRAPS) {
_Responsible = NULL ;
}
+#if INCLUDE_TRACE
+ // get the owner's thread id for the MonitorEnter event
+ // if it is enabled and the thread isn't suspended
+ if (not_suspended && Tracing::is_event_enabled(TraceJavaMonitorEnterEvent)) {
+ _previous_owner_tid = SharedRuntime::get_java_tid(Self);
+ }
+#endif
+
for (;;) {
assert (THREAD == _owner, "invariant") ;
@@ -1343,7 +1364,7 @@ intptr_t ObjectMonitor::complete_exit(TRAPS) {
guarantee(Self == _owner, "complete_exit not owner");
intptr_t save = _recursions; // record the old recursion count
_recursions = 0; // set the recursion level to be 0
- exit (Self) ; // exit the monitor
+ exit (true, Self) ; // exit the monitor
guarantee (_owner != Self, "invariant");
return save;
}
@@ -1397,6 +1418,20 @@ static int Adjust (volatile int * adr, int dx) {
for (v = *adr ; Atomic::cmpxchg (v + dx, adr, v) != v; v = *adr) ;
return v ;
}
+
+// helper method for posting a monitor wait event
+void ObjectMonitor::post_monitor_wait_event(EventJavaMonitorWait* event,
+ jlong notifier_tid,
+ jlong timeout,
+ bool timedout) {
+ event->set_klass(((oop)this->object())->klass());
+ event->set_timeout((TYPE_ULONG)timeout);
+ event->set_address((TYPE_ADDRESS)(uintptr_t)(this->object_addr()));
+ event->set_notifier((TYPE_OSTHREAD)notifier_tid);
+ event->set_timedOut((TYPE_BOOLEAN)timedout);
+ event->commit();
+}
+
// -----------------------------------------------------------------------------
// Wait/Notify/NotifyAll
//
@@ -1412,6 +1447,8 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
// Throw IMSX or IEX.
CHECK_OWNER();
+ EventJavaMonitorWait event;
+
// check for a pending interrupt
if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
// post monitor waited event. Note that this is past-tense, we are done waiting.
@@ -1420,10 +1457,14 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
// wait was not timed out due to thread interrupt.
JvmtiExport::post_monitor_waited(jt, this, false);
}
+ if (event.should_commit()) {
+ post_monitor_wait_event(&event, 0, millis, false);
+ }
TEVENT (Wait - Throw IEX) ;
THROW(vmSymbols::java_lang_InterruptedException());
return ;
}
+
TEVENT (Wait) ;
assert (Self->_Stalled == 0, "invariant") ;
@@ -1455,7 +1496,7 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
intptr_t save = _recursions; // record the old recursion count
_waiters++; // increment the number of waiters
_recursions = 0; // set the recursion level to be 1
- exit (Self) ; // exit the monitor
+ exit (true, Self) ; // exit the monitor
guarantee (_owner != Self, "invariant") ;
// As soon as the ObjectMonitor's ownership is dropped in the exit()
@@ -1555,6 +1596,11 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
if (JvmtiExport::should_post_monitor_waited()) {
JvmtiExport::post_monitor_waited(jt, this, ret == OS_TIMEOUT);
}
+
+ if (event.should_commit()) {
+ post_monitor_wait_event(&event, node._notifier_tid, millis, ret == OS_TIMEOUT);
+ }
+
OrderAccess::fence() ;
assert (Self->_Stalled != 0, "invariant") ;
@@ -1634,6 +1680,8 @@ void ObjectMonitor::notify(TRAPS) {
iterator->TState = ObjectWaiter::TS_ENTER ;
}
iterator->_notified = 1 ;
+ Thread * Self = THREAD;
+ iterator->_notifier_tid = Self->osthread()->thread_id();
ObjectWaiter * List = _EntryList ;
if (List != NULL) {
@@ -1758,6 +1806,8 @@ void ObjectMonitor::notifyAll(TRAPS) {
guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
guarantee (iterator->_notified == 0, "invariant") ;
iterator->_notified = 1 ;
+ Thread * Self = THREAD;
+ iterator->_notifier_tid = Self->osthread()->thread_id();
if (Policy != 4) {
iterator->TState = ObjectWaiter::TS_ENTER ;
}
diff --git a/src/share/vm/runtime/objectMonitor.hpp b/src/share/vm/runtime/objectMonitor.hpp
index df4b0279c..f0e6ed5f8 100644
--- a/src/share/vm/runtime/objectMonitor.hpp
+++ b/src/share/vm/runtime/objectMonitor.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, 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,7 +29,6 @@
#include "runtime/park.hpp"
#include "runtime/perfData.hpp"
-
// ObjectWaiter serves as a "proxy" or surrogate thread.
// TODO-FIXME: Eliminate ObjectWaiter and use the thread-specific
// ParkEvent instead. Beware, however, that the JVMTI code
@@ -43,6 +42,7 @@ class ObjectWaiter : public StackObj {
ObjectWaiter * volatile _next;
ObjectWaiter * volatile _prev;
Thread* _thread;
+ jlong _notifier_tid;
ParkEvent * _event;
volatile int _notified ;
volatile TStates TState ;
@@ -55,6 +55,9 @@ class ObjectWaiter : public StackObj {
void wait_reenter_end(ObjectMonitor *mon);
};
+// forward declaration to avoid include tracing.hpp
+class EventJavaMonitorWait;
+
// WARNING:
// This is a very sensitive and fragile class. DO NOT make any
// change unless you are fully aware of the underlying semantics.
@@ -151,6 +154,7 @@ class ObjectMonitor {
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;
+ _previous_owner_tid = 0;
}
~ObjectMonitor() {
@@ -192,7 +196,7 @@ public:
bool try_enter (TRAPS) ;
void enter(TRAPS);
- void exit(TRAPS);
+ void exit(bool not_suspended, TRAPS);
void wait(jlong millis, bool interruptable, TRAPS);
void notify(TRAPS);
void notifyAll(TRAPS);
@@ -218,6 +222,10 @@ public:
void ctAsserts () ;
void ExitEpilog (Thread * Self, ObjectWaiter * Wakee) ;
bool ExitSuspendEquivalent (JavaThread * Self) ;
+ void post_monitor_wait_event(EventJavaMonitorWait * event,
+ jlong notifier_tid,
+ jlong timeout,
+ bool timedout);
private:
friend class ObjectSynchronizer;
@@ -240,6 +248,7 @@ public:
protected: // protected for jvmtiRawMonitor
void * volatile _owner; // pointer to owning thread OR BasicLock
+ volatile jlong _previous_owner_tid; // thread id of the previous owner of the monitor
volatile intptr_t _recursions; // recursion count, 0 for first entry
private:
int OwnerIsThread ; // _owner is (Thread *) vs SP/BasicLock
diff --git a/src/share/vm/runtime/os.cpp b/src/share/vm/runtime/os.cpp
index e9c5b2612..7775d9410 100644
--- a/src/share/vm/runtime/os.cpp
+++ b/src/share/vm/runtime/os.cpp
@@ -265,8 +265,7 @@ static void signal_thread_entry(JavaThread* thread, TRAPS) {
VMThread::execute(&op1);
Universe::print_heap_at_SIGBREAK();
if (PrintClassHistogram) {
- VM_GC_HeapInspection op1(gclog_or_tty, true /* force full GC before heap inspection */,
- true /* need_prologue */);
+ VM_GC_HeapInspection op1(gclog_or_tty, true /* force full GC before heap inspection */);
VMThread::execute(&op1);
}
if (JvmtiExport::should_post_data_dump()) {
@@ -1444,11 +1443,16 @@ int os::get_line_chars(int fd, char* buf, const size_t bsize){
return (int) i;
}
+void os::SuspendedThreadTask::run() {
+ assert(Threads_lock->owned_by_self() || (_thread == VMThread::vm_thread()), "must have threads lock to call this");
+ internal_do_task();
+ _done = true;
+}
+
bool os::create_stack_guard_pages(char* addr, size_t bytes) {
return os::pd_create_stack_guard_pages(addr, bytes);
}
-
char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint) {
char* result = pd_reserve_memory(bytes, addr, alignment_hint);
if (result != NULL) {
@@ -1551,3 +1555,19 @@ void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) {
pd_realign_memory(addr, bytes, alignment_hint);
}
+#ifndef TARGET_OS_FAMILY_windows
+/* try to switch state from state "from" to state "to"
+ * returns the state set after the method is complete
+ */
+os::SuspendResume::State os::SuspendResume::switch_state(os::SuspendResume::State from,
+ os::SuspendResume::State to)
+{
+ os::SuspendResume::State result =
+ (os::SuspendResume::State) Atomic::cmpxchg((jint) to, (jint *) &_state, (jint) from);
+ if (result == from) {
+ // success
+ return to;
+ }
+ return result;
+}
+#endif
diff --git a/src/share/vm/runtime/os.hpp b/src/share/vm/runtime/os.hpp
index 51fc54ddc..3f2554399 100644
--- a/src/share/vm/runtime/os.hpp
+++ b/src/share/vm/runtime/os.hpp
@@ -781,6 +781,104 @@ class os: AllStatic {
// ResumeThread call)
static void pause();
+ class SuspendedThreadTaskContext {
+ public:
+ SuspendedThreadTaskContext(Thread* thread, void *ucontext) : _thread(thread), _ucontext(ucontext) {}
+ Thread* thread() const { return _thread; }
+ void* ucontext() const { return _ucontext; }
+ private:
+ Thread* _thread;
+ void* _ucontext;
+ };
+
+ class SuspendedThreadTask {
+ public:
+ SuspendedThreadTask(Thread* thread) : _thread(thread), _done(false) {}
+ virtual ~SuspendedThreadTask() {}
+ void run();
+ bool is_done() { return _done; }
+ virtual void do_task(const SuspendedThreadTaskContext& context) = 0;
+ protected:
+ private:
+ void internal_do_task();
+ Thread* _thread;
+ bool _done;
+ };
+
+#ifndef TARGET_OS_FAMILY_windows
+ // Suspend/resume support
+ // Protocol:
+ //
+ // a thread starts in SR_RUNNING
+ //
+ // SR_RUNNING can go to
+ // * SR_SUSPEND_REQUEST when the WatcherThread wants to suspend it
+ // SR_SUSPEND_REQUEST can go to
+ // * SR_RUNNING if WatcherThread decides it waited for SR_SUSPENDED too long (timeout)
+ // * SR_SUSPENDED if the stopped thread receives the signal and switches state
+ // SR_SUSPENDED can go to
+ // * SR_WAKEUP_REQUEST when the WatcherThread has done the work and wants to resume
+ // SR_WAKEUP_REQUEST can go to
+ // * SR_RUNNING when the stopped thread receives the signal
+ // * SR_WAKEUP_REQUEST on timeout (resend the signal and try again)
+ class SuspendResume {
+ public:
+ enum State {
+ SR_RUNNING,
+ SR_SUSPEND_REQUEST,
+ SR_SUSPENDED,
+ SR_WAKEUP_REQUEST
+ };
+
+ private:
+ volatile State _state;
+
+ private:
+ /* try to switch state from state "from" to state "to"
+ * returns the state set after the method is complete
+ */
+ State switch_state(State from, State to);
+
+ public:
+ SuspendResume() : _state(SR_RUNNING) { }
+
+ State state() const { return _state; }
+
+ State request_suspend() {
+ return switch_state(SR_RUNNING, SR_SUSPEND_REQUEST);
+ }
+
+ State cancel_suspend() {
+ return switch_state(SR_SUSPEND_REQUEST, SR_RUNNING);
+ }
+
+ State suspended() {
+ return switch_state(SR_SUSPEND_REQUEST, SR_SUSPENDED);
+ }
+
+ State request_wakeup() {
+ return switch_state(SR_SUSPENDED, SR_WAKEUP_REQUEST);
+ }
+
+ State running() {
+ return switch_state(SR_WAKEUP_REQUEST, SR_RUNNING);
+ }
+
+ bool is_running() const {
+ return _state == SR_RUNNING;
+ }
+
+ bool is_suspend_request() const {
+ return _state == SR_SUSPEND_REQUEST;
+ }
+
+ bool is_suspended() const {
+ return _state == SR_SUSPENDED;
+ }
+ };
+#endif
+
+
protected:
static long _rand_seed; // seed for random number generator
static int _processor_count; // number of processors
diff --git a/src/share/vm/runtime/perfData.cpp b/src/share/vm/runtime/perfData.cpp
index 777ea27f9..60b71fde1 100644
--- a/src/share/vm/runtime/perfData.cpp
+++ b/src/share/vm/runtime/perfData.cpp
@@ -323,6 +323,10 @@ void PerfDataManager::add_item(PerfData* p, bool sampled) {
}
}
+PerfData* PerfDataManager::find_by_name(const char* name) {
+ return _all->find_by_name(name);
+}
+
PerfDataList* PerfDataManager::all() {
MutexLocker ml(PerfDataManager_lock);
diff --git a/src/share/vm/runtime/perfData.hpp b/src/share/vm/runtime/perfData.hpp
index 07dc9c956..94996df1a 100644
--- a/src/share/vm/runtime/perfData.hpp
+++ b/src/share/vm/runtime/perfData.hpp
@@ -693,6 +693,9 @@ class PerfDataManager : AllStatic {
// the given name.
static bool exists(const char* name) { return _all->contains(name); }
+ // method to search for a instrumentation object by name
+ static PerfData* find_by_name(const char* name);
+
// method to map a CounterNS enumeration to a namespace string
static const char* ns_to_string(CounterNS ns) {
return _name_spaces[ns];
diff --git a/src/share/vm/runtime/stubRoutines.hpp b/src/share/vm/runtime/stubRoutines.hpp
index 91f273e65..7ad663713 100644
--- a/src/share/vm/runtime/stubRoutines.hpp
+++ b/src/share/vm/runtime/stubRoutines.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -223,6 +223,8 @@ class StubRoutines: AllStatic {
static void initialize1(); // must happen before universe::genesis
static void initialize2(); // must happen after universe::genesis
+ static bool is_stub_code(address addr) { return contains(addr); }
+
static bool contains(address addr) {
return
(_code1 != NULL && _code1->blob_contains(addr)) ||
diff --git a/src/share/vm/runtime/sweeper.cpp b/src/share/vm/runtime/sweeper.cpp
index 2921b2544..ebecda50b 100644
--- a/src/share/vm/runtime/sweeper.cpp
+++ b/src/share/vm/runtime/sweeper.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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,6 +36,7 @@
#include "runtime/os.hpp"
#include "runtime/sweeper.hpp"
#include "runtime/vm_operations.hpp"
+#include "trace/tracing.hpp"
#include "utilities/events.hpp"
#include "utilities/xmlstream.hpp"
@@ -130,6 +131,9 @@ void NMethodSweeper::record_sweep(nmethod* nm, int line) {
long NMethodSweeper::_traversals = 0; // No. of stack traversals performed
nmethod* NMethodSweeper::_current = NULL; // Current nmethod
int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache
+int NMethodSweeper::_flushed_count = 0; // Nof. nmethods flushed in current sweep
+int NMethodSweeper::_zombified_count = 0; // Nof. nmethods made zombie in current sweep
+int NMethodSweeper::_marked_count = 0; // Nof. nmethods marked for reclaim in current sweep
volatile int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass
volatile int NMethodSweeper::_sweep_started = 0; // Whether a sweep is in progress.
@@ -143,6 +147,15 @@ int NMethodSweeper::_highest_marked = 0;
int NMethodSweeper::_dead_compile_ids = 0;
long NMethodSweeper::_last_flush_traversal_id = 0;
+int NMethodSweeper::_number_of_flushes = 0; // Total of full traversals caused by full cache
+int NMethodSweeper::_total_nof_methods_reclaimed = 0;
+jlong NMethodSweeper::_total_time_sweeping = 0;
+jlong NMethodSweeper::_total_time_this_sweep = 0;
+jlong NMethodSweeper::_peak_sweep_time = 0;
+jlong NMethodSweeper::_peak_sweep_fraction_time = 0;
+jlong NMethodSweeper::_total_disconnect_time = 0;
+jlong NMethodSweeper::_peak_disconnect_time = 0;
+
class MarkActivationClosure: public CodeBlobClosure {
public:
virtual void do_code_blob(CodeBlob* cb) {
@@ -176,6 +189,8 @@ void NMethodSweeper::scan_stacks() {
_invocations = NmethodSweepFraction;
_current = CodeCache::first_nmethod();
_traversals += 1;
+ _total_time_this_sweep = 0;
+
if (PrintMethodFlushing) {
tty->print_cr("### Sweep: stack traversal %d", _traversals);
}
@@ -229,12 +244,13 @@ void NMethodSweeper::possibly_sweep() {
}
void NMethodSweeper::sweep_code_cache() {
-#ifdef ASSERT
- jlong sweep_start;
- if (PrintMethodFlushing) {
- sweep_start = os::javaTimeMillis();
- }
-#endif
+
+ jlong sweep_start_counter = os::elapsed_counter();
+
+ _flushed_count = 0;
+ _zombified_count = 0;
+ _marked_count = 0;
+
if (PrintMethodFlushing && Verbose) {
tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_nmethods(), _invocations);
}
@@ -302,14 +318,34 @@ void NMethodSweeper::sweep_code_cache() {
}
}
+ jlong sweep_end_counter = os::elapsed_counter();
+ jlong sweep_time = sweep_end_counter - sweep_start_counter;
+ _total_time_sweeping += sweep_time;
+ _total_time_this_sweep += sweep_time;
+ _peak_sweep_fraction_time = MAX2(sweep_time, _peak_sweep_fraction_time);
+ _total_nof_methods_reclaimed += _flushed_count;
+
+ EventSweepCodeCache event(UNTIMED);
+ if (event.should_commit()) {
+ event.set_starttime(sweep_start_counter);
+ event.set_endtime(sweep_end_counter);
+ event.set_sweepIndex(_traversals);
+ event.set_sweepFractionIndex(NmethodSweepFraction - _invocations + 1);
+ event.set_sweptCount(todo);
+ event.set_flushedCount(_flushed_count);
+ event.set_markedCount(_marked_count);
+ event.set_zombifiedCount(_zombified_count);
+ event.commit();
+ }
+
#ifdef ASSERT
if(PrintMethodFlushing) {
- jlong sweep_end = os::javaTimeMillis();
- tty->print_cr("### sweeper: sweep time(%d): " INT64_FORMAT, _invocations, sweep_end - sweep_start);
+ tty->print_cr("### sweeper: sweep time(%d): " INT64_FORMAT, _invocations, (jlong)sweep_time);
}
#endif
if (_invocations == 1) {
+ _peak_sweep_time = MAX2(_peak_sweep_time, _total_time_this_sweep);
log_sweep("finished");
}
@@ -388,12 +424,14 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm);
}
release_nmethod(nm);
+ _flushed_count++;
} else {
if (PrintMethodFlushing && Verbose) {
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm);
}
nm->mark_for_reclamation();
_resweep = true;
+ _marked_count++;
SWEEP(nm);
}
} else if (nm->is_not_entrant()) {
@@ -405,6 +443,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
}
nm->make_zombie();
_resweep = true;
+ _zombified_count++;
SWEEP(nm);
} else {
// Still alive, clean up its inline caches
@@ -420,13 +459,16 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
// Unloaded code, just make it a zombie
if (PrintMethodFlushing && Verbose)
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (unloaded) being made zombie", nm->compile_id(), nm);
+
if (nm->is_osr_method()) {
SWEEP(nm);
// No inline caches will ever point to osr methods, so we can just remove it
release_nmethod(nm);
+ _flushed_count++;
} else {
nm->make_zombie();
_resweep = true;
+ _zombified_count++;
SWEEP(nm);
}
} else {
@@ -484,7 +526,7 @@ void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) {
// If there was a race in detecting full code cache, only run
// one vm op for it or keep the compiler shut off
- debug_only(jlong start = os::javaTimeMillis();)
+ jlong disconnect_start_counter = os::elapsed_counter();
// Traverse the code cache trying to dump the oldest nmethods
int curr_max_comp_id = CompileBroker::get_compilation_id();
@@ -541,13 +583,28 @@ void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) {
_last_full_flush_time = os::javaTimeMillis();
}
+ jlong disconnect_end_counter = os::elapsed_counter();
+ jlong disconnect_time = disconnect_end_counter - disconnect_start_counter;
+ _total_disconnect_time += disconnect_time;
+ _peak_disconnect_time = MAX2(disconnect_time, _peak_disconnect_time);
+
+ EventCleanCodeCache event(UNTIMED);
+ if (event.should_commit()) {
+ event.set_starttime(disconnect_start_counter);
+ event.set_endtime(disconnect_end_counter);
+ event.set_disconnectedCount(disconnected);
+ event.set_madeNonEntrantCount(made_not_entrant);
+ event.commit();
+ }
+ _number_of_flushes++;
+
// After two more traversals the sweeper will get rid of unrestored nmethods
_last_flush_traversal_id = _traversals;
_resweep = true;
#ifdef ASSERT
- jlong end = os::javaTimeMillis();
+
if(PrintMethodFlushing && Verbose) {
- tty->print_cr("### sweeper: unload time: " INT64_FORMAT, end-start);
+ tty->print_cr("### sweeper: unload time: " INT64_FORMAT, (jlong)disconnect_time);
}
#endif
}
diff --git a/src/share/vm/runtime/sweeper.hpp b/src/share/vm/runtime/sweeper.hpp
index ff63029f1..4bad5bd9b 100644
--- a/src/share/vm/runtime/sweeper.hpp
+++ b/src/share/vm/runtime/sweeper.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -31,9 +31,12 @@
//
class NMethodSweeper : public AllStatic {
- static long _traversals; // Stack traversal count
- static nmethod* _current; // Current nmethod
- static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache
+ static long _traversals; // Stack scan count, also sweep ID.
+ static nmethod* _current; // Current nmethod
+ static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache
+ static int _flushed_count; // Nof. nmethods flushed in current sweep
+ static int _zombified_count; // Nof. nmethods made zombie in current sweep
+ static int _marked_count; // Nof. nmethods marked for reclaim in current sweep
static volatile int _invocations; // No. of invocations left until we are completed with this pass
static volatile int _sweep_started; // Flag to control conc sweeper
@@ -53,6 +56,16 @@ class NMethodSweeper : public AllStatic {
static int _highest_marked; // highest compile id dumped at last emergency unloading
static int _dead_compile_ids; // number of compile ids that where not in the cache last flush
+ // Stat counters
+ static int _number_of_flushes; // Total of full traversals caused by full cache
+ static int _total_nof_methods_reclaimed; // Accumulated nof methods flushed
+ static jlong _total_time_sweeping; // Accumulated time sweeping
+ static jlong _total_time_this_sweep; // Total time this sweep
+ static jlong _peak_sweep_time; // Peak time for a full sweep
+ static jlong _peak_sweep_fraction_time; // Peak time sweeping one fraction
+ static jlong _total_disconnect_time; // Total time cleaning code mem
+ static jlong _peak_disconnect_time; // Peak time cleaning code mem
+
static void process_nmethod(nmethod *nm);
static void release_nmethod(nmethod* nm);
@@ -60,7 +73,14 @@ class NMethodSweeper : public AllStatic {
static bool sweep_in_progress();
public:
- static long traversal_count() { return _traversals; }
+ static long traversal_count() { return _traversals; }
+ static int number_of_flushes() { return _number_of_flushes; }
+ static int total_nof_methods_reclaimed() { return _total_nof_methods_reclaimed; }
+ static jlong total_time_sweeping() { return _total_time_sweeping; }
+ static jlong peak_sweep_time() { return _peak_sweep_time; }
+ static jlong peak_sweep_fraction_time() { return _peak_sweep_fraction_time; }
+ static jlong total_disconnect_time() { return _total_disconnect_time; }
+ static jlong peak_disconnect_time() { return _peak_disconnect_time; }
#ifdef ASSERT
// Keep track of sweeper activity in the ring buffer
diff --git a/src/share/vm/runtime/synchronizer.cpp b/src/share/vm/runtime/synchronizer.cpp
index ede9affb9..015dd757b 100644
--- a/src/share/vm/runtime/synchronizer.cpp
+++ b/src/share/vm/runtime/synchronizer.cpp
@@ -213,7 +213,7 @@ void ObjectSynchronizer::fast_exit(oop object, BasicLock* lock, TRAPS) {
}
}
- ObjectSynchronizer::inflate(THREAD, object)->exit (THREAD) ;
+ ObjectSynchronizer::inflate(THREAD, object)->exit (true, THREAD) ;
}
// -----------------------------------------------------------------------------
@@ -343,7 +343,7 @@ void ObjectSynchronizer::jni_exit(oop obj, Thread* THREAD) {
// If this thread has locked the object, exit the monitor. Note: can't use
// monitor->check(CHECK); must exit even if an exception is pending.
if (monitor->check(THREAD)) {
- monitor->exit(THREAD);
+ monitor->exit(true, THREAD);
}
}
diff --git a/src/share/vm/runtime/task.cpp b/src/share/vm/runtime/task.cpp
index 9d2286f2d..ef57dcd68 100644
--- a/src/share/vm/runtime/task.cpp
+++ b/src/share/vm/runtime/task.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -114,9 +114,11 @@ PeriodicTask::~PeriodicTask() {
disenroll();
}
+/* enroll could be called from a JavaThread, so we have to check for
+ * safepoint when taking the lock to avoid deadlocking */
void PeriodicTask::enroll() {
MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ?
- NULL : PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
+ NULL : PeriodicTask_lock);
if (_num_tasks == PeriodicTask::max_tasks) {
fatal("Overflow in PeriodicTask table");
@@ -131,9 +133,11 @@ void PeriodicTask::enroll() {
}
}
+/* disenroll could be called from a JavaThread, so we have to check for
+ * safepoint when taking the lock to avoid deadlocking */
void PeriodicTask::disenroll() {
MutexLockerEx ml(PeriodicTask_lock->owned_by_self() ?
- NULL : PeriodicTask_lock, Mutex::_no_safepoint_check_flag);
+ NULL : PeriodicTask_lock);
int index;
for(index = 0; index < _num_tasks && _tasks[index] != this; index++)
diff --git a/src/share/vm/runtime/thread.cpp b/src/share/vm/runtime/thread.cpp
index 7c3e256e2..79642c2e4 100644
--- a/src/share/vm/runtime/thread.cpp
+++ b/src/share/vm/runtime/thread.cpp
@@ -77,7 +77,8 @@
#include "services/management.hpp"
#include "services/memTracker.hpp"
#include "services/threadService.hpp"
-#include "trace/traceEventTypes.hpp"
+#include "trace/tracing.hpp"
+#include "trace/traceMacros.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
@@ -238,7 +239,6 @@ Thread::Thread() {
CHECK_UNHANDLED_OOPS_ONLY(_gc_locked_out_count = 0;)
_jvmti_env_iteration_count = 0;
set_allocated_bytes(0);
- set_trace_buffer(NULL);
_vm_operation_started_count = 0;
_vm_operation_completed_count = 0;
_current_pending_monitor = NULL;
@@ -1659,9 +1659,11 @@ void JavaThread::run() {
JvmtiExport::post_thread_start(this);
}
- EVENT_BEGIN(TraceEventThreadStart, event);
- EVENT_COMMIT(event,
- EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(this->threadObj())));
+ EventThreadStart event;
+ if (event.should_commit()) {
+ event.set_javalangthread(java_lang_Thread::thread_id(this->threadObj()));
+ event.commit();
+ }
// We call another function to do the rest so we are sure that the stack addresses used
// from there will be lower than the stack base just computed
@@ -1791,9 +1793,11 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
// Called before the java thread exit since we want to read info
// from java_lang_Thread object
- EVENT_BEGIN(TraceEventThreadEnd, event);
- EVENT_COMMIT(event,
- EVENT_SET(event, javalangthread, java_lang_Thread::thread_id(this->threadObj())));
+ EventThreadEnd event;
+ if (event.should_commit()) {
+ event.set_javalangthread(java_lang_Thread::thread_id(this->threadObj()));
+ event.commit();
+ }
// Call after last event on thread
EVENT_THREAD_EXIT(this);
@@ -3648,8 +3652,8 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
// Notify JVMTI agents that VM initialization is complete - nop if no agents.
JvmtiExport::post_vm_initialized();
- if (!TRACE_START()) {
- vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION));
+ if (TRACE_START() != JNI_OK) {
+ vm_exit_during_initialization("Failed to start tracing backend.");
}
if (CleanChunkPoolAsync) {
diff --git a/src/share/vm/runtime/thread.hpp b/src/share/vm/runtime/thread.hpp
index 71007590b..8b8e6dd4e 100644
--- a/src/share/vm/runtime/thread.hpp
+++ b/src/share/vm/runtime/thread.hpp
@@ -47,7 +47,8 @@
#include "services/memRecorder.hpp"
#endif // INCLUDE_NMT
-#include "trace/tracing.hpp"
+#include "trace/traceBackend.hpp"
+#include "trace/traceMacros.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/top.hpp"
#if INCLUDE_ALL_GCS
@@ -258,7 +259,7 @@ class Thread: public ThreadShadow {
jlong _allocated_bytes; // Cumulative number of bytes allocated on
// the Java heap
- TRACE_BUFFER _trace_buffer; // Thread-local buffer for tracing
+ TRACE_DATA _trace_data; // Thread-local data for tracing
int _vm_operation_started_count; // VM_Operation support
int _vm_operation_completed_count; // VM_Operation support
@@ -449,8 +450,7 @@ class Thread: public ThreadShadow {
return allocated_bytes;
}
- TRACE_BUFFER trace_buffer() { return _trace_buffer; }
- void set_trace_buffer(TRACE_BUFFER buf) { _trace_buffer = buf; }
+ TRACE_DATA* trace_data() { return &_trace_data; }
// VM operation support
int vm_operation_ticket() { return ++_vm_operation_started_count; }
diff --git a/src/share/vm/runtime/timer.cpp b/src/share/vm/runtime/timer.cpp
index 838262650..12c32660b 100644
--- a/src/share/vm/runtime/timer.cpp
+++ b/src/share/vm/runtime/timer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -39,6 +39,11 @@
# include "os_bsd.inline.hpp"
#endif
+double TimeHelper::counter_to_seconds(jlong counter) {
+ double count = (double) counter;
+ double freq = (double) os::elapsed_frequency();
+ return counter/freq;
+}
void elapsedTimer::add(elapsedTimer t) {
_counter += t._counter;
@@ -59,9 +64,7 @@ void elapsedTimer::stop() {
}
double elapsedTimer::seconds() const {
- double count = (double) _counter;
- double freq = (double) os::elapsed_frequency();
- return count/freq;
+ return TimeHelper::counter_to_seconds(_counter);
}
jlong elapsedTimer::milliseconds() const {
@@ -90,9 +93,7 @@ void TimeStamp::update() {
double TimeStamp::seconds() const {
assert(is_updated(), "must not be clear");
jlong new_count = os::elapsed_counter();
- double count = (double) new_count - _counter;
- double freq = (double) os::elapsed_frequency();
- return count/freq;
+ return TimeHelper::counter_to_seconds(new_count - _counter);
}
jlong TimeStamp::milliseconds() const {
@@ -110,19 +111,15 @@ jlong TimeStamp::ticks_since_update() const {
}
TraceTime::TraceTime(const char* title,
- bool doit,
- bool print_cr,
- outputStream* logfile) {
+ bool doit) {
_active = doit;
_verbose = true;
- _print_cr = print_cr;
- _logfile = (logfile != NULL) ? logfile : tty;
if (_active) {
_accum = NULL;
- _logfile->stamp(PrintGCTimeStamps);
- _logfile->print("[%s", title);
- _logfile->flush();
+ tty->stamp(PrintGCTimeStamps);
+ tty->print("[%s", title);
+ tty->flush();
_t.start();
}
}
@@ -130,17 +127,14 @@ TraceTime::TraceTime(const char* title,
TraceTime::TraceTime(const char* title,
elapsedTimer* accumulator,
bool doit,
- bool verbose,
- outputStream* logfile) {
+ bool verbose) {
_active = doit;
_verbose = verbose;
- _print_cr = true;
- _logfile = (logfile != NULL) ? logfile : tty;
if (_active) {
if (_verbose) {
- _logfile->stamp(PrintGCTimeStamps);
- _logfile->print("[%s", title);
- _logfile->flush();
+ tty->stamp(PrintGCTimeStamps);
+ tty->print("[%s", title);
+ tty->flush();
}
_accum = accumulator;
_t.start();
@@ -152,12 +146,8 @@ TraceTime::~TraceTime() {
_t.stop();
if (_accum!=NULL) _accum->add(_t);
if (_verbose) {
- if (_print_cr) {
- _logfile->print_cr(", %3.7f secs]", _t.seconds());
- } else {
- _logfile->print(", %3.7f secs]", _t.seconds());
- }
- _logfile->flush();
+ tty->print_cr(", %3.7f secs]", _t.seconds());
+ tty->flush();
}
}
}
diff --git a/src/share/vm/runtime/timer.hpp b/src/share/vm/runtime/timer.hpp
index 388a821c1..7e694d5bd 100644
--- a/src/share/vm/runtime/timer.hpp
+++ b/src/share/vm/runtime/timer.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -82,21 +82,16 @@ class TraceTime: public StackObj {
private:
bool _active; // do timing
bool _verbose; // report every timing
- bool _print_cr; // add a CR to the end of the timer report
elapsedTimer _t; // timer
elapsedTimer* _accum; // accumulator
- outputStream* _logfile; // output log file
public:
- // Constuctors
+ // Constructors
TraceTime(const char* title,
- bool doit = true,
- bool print_cr = true,
- outputStream *logfile = NULL);
+ bool doit = true);
TraceTime(const char* title,
elapsedTimer* accumulator,
bool doit = true,
- bool verbose = false,
- outputStream *logfile = NULL );
+ bool verbose = false);
~TraceTime();
// Accessors
@@ -125,4 +120,9 @@ class TraceCPUTime: public StackObj {
~TraceCPUTime();
};
+class TimeHelper {
+ public:
+ static double counter_to_seconds(jlong counter);
+};
+
#endif // SHARE_VM_RUNTIME_TIMER_HPP
diff --git a/src/share/vm/runtime/vmStructs.cpp b/src/share/vm/runtime/vmStructs.cpp
index 6e12cd447..dff270f16 100644
--- a/src/share/vm/runtime/vmStructs.cpp
+++ b/src/share/vm/runtime/vmStructs.cpp
@@ -60,6 +60,7 @@
#include "memory/generationSpec.hpp"
#include "memory/heap.hpp"
#include "memory/metablock.hpp"
+#include "memory/referenceType.hpp"
#include "memory/space.hpp"
#include "memory/tenuredGeneration.hpp"
#include "memory/universe.hpp"
diff --git a/src/share/vm/runtime/vmThread.cpp b/src/share/vm/runtime/vmThread.cpp
index 8c321721e..bdb508208 100644
--- a/src/share/vm/runtime/vmThread.cpp
+++ b/src/share/vm/runtime/vmThread.cpp
@@ -35,6 +35,7 @@
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
#include "services/runtimeService.hpp"
+#include "trace/tracing.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
#include "utilities/xmlstream.hpp"
@@ -365,7 +366,23 @@ void VMThread::evaluate_operation(VM_Operation* op) {
(char *) op->name(), strlen(op->name()),
op->evaluation_mode());
#endif /* USDT2 */
+
+ EventExecuteVMOperation event;
+
op->evaluate();
+
+ if (event.should_commit()) {
+ bool is_concurrent = op->evaluate_concurrently();
+ event.set_operation(op->type());
+ event.set_safepoint(op->evaluate_at_safepoint());
+ event.set_blocking(!is_concurrent);
+ // Only write caller thread information for non-concurrent vm operations.
+ // For concurrent vm operations, the thread id is set to 0 indicating thread is unknown.
+ // This is because the caller thread could have exited already.
+ event.set_caller(is_concurrent ? 0 : op->calling_thread()->osthread()->thread_id());
+ event.commit();
+ }
+
#ifndef USDT2
HS_DTRACE_PROBE3(hotspot, vmops__end, op->name(), strlen(op->name()),
op->evaluation_mode());
@@ -601,7 +618,7 @@ void VMThread::execute(VM_Operation* op) {
{
VMOperationQueue_lock->lock_without_safepoint_check();
bool ok = _vm_queue->add(op);
- op->set_timestamp(os::javaTimeMillis());
+ op->set_timestamp(os::javaTimeMillis());
VMOperationQueue_lock->notify();
VMOperationQueue_lock->unlock();
// VM_Operation got skipped
diff --git a/src/share/vm/runtime/vm_operations.cpp b/src/share/vm/runtime/vm_operations.cpp
index 53ea0bd98..5166cfdaa 100644
--- a/src/share/vm/runtime/vm_operations.cpp
+++ b/src/share/vm/runtime/vm_operations.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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,6 +37,7 @@
#include "runtime/thread.inline.hpp"
#include "runtime/vm_operations.hpp"
#include "services/threadService.hpp"
+#include "trace/tracing.hpp"
#define VM_OP_NAME_INITIALIZE(name) #name,
@@ -62,19 +63,21 @@ void VM_Operation::evaluate() {
}
}
+const char* VM_Operation::mode_to_string(Mode mode) {
+ switch(mode) {
+ case _safepoint : return "safepoint";
+ case _no_safepoint : return "no safepoint";
+ case _concurrent : return "concurrent";
+ case _async_safepoint: return "async safepoint";
+ default : return "unknown";
+ }
+}
// Called by fatal error handler.
void VM_Operation::print_on_error(outputStream* st) const {
st->print("VM_Operation (" PTR_FORMAT "): ", this);
st->print("%s", name());
- const char* mode;
- switch(evaluation_mode()) {
- case _safepoint : mode = "safepoint"; break;
- case _no_safepoint : mode = "no safepoint"; break;
- case _concurrent : mode = "concurrent"; break;
- case _async_safepoint: mode = "async safepoint"; break;
- default : mode = "unknown"; break;
- }
+ const char* mode = mode_to_string(evaluation_mode());
st->print(", mode: %s", mode);
if (calling_thread()) {
diff --git a/src/share/vm/runtime/vm_operations.hpp b/src/share/vm/runtime/vm_operations.hpp
index 9d79b2c0d..b6555b457 100644
--- a/src/share/vm/runtime/vm_operations.hpp
+++ b/src/share/vm/runtime/vm_operations.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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,6 +178,8 @@ class VM_Operation: public CHeapObj<mtInternal> {
evaluation_mode() == _async_safepoint;
}
+ static const char* mode_to_string(Mode mode);
+
// Debugging
void print_on_error(outputStream* st) const;
const char* name() const { return _names[type()]; }
diff --git a/src/share/vm/services/attachListener.cpp b/src/share/vm/services/attachListener.cpp
index 564b20f4b..bf002e7fa 100644
--- a/src/share/vm/services/attachListener.cpp
+++ b/src/share/vm/services/attachListener.cpp
@@ -227,7 +227,7 @@ static jint heap_inspection(AttachOperation* op, outputStream* out) {
}
live_objects_only = strcmp(arg0, "-live") == 0;
}
- VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */, true /* need_prologue */);
+ VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */);
VMThread::execute(&heapop);
return JNI_OK;
}
diff --git a/src/share/vm/services/diagnosticArgument.cpp b/src/share/vm/services/diagnosticArgument.cpp
index 022687db4..e3e140532 100644
--- a/src/share/vm/services/diagnosticArgument.cpp
+++ b/src/share/vm/services/diagnosticArgument.cpp
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "memory/allocation.inline.hpp"
+#include "memory/resourceArea.hpp"
#include "runtime/thread.hpp"
#include "services/diagnosticArgument.hpp"
@@ -86,9 +87,18 @@ void GenDCmdArgument::to_string(StringArrayArgument* f, char* buf, size_t len) {
template <> void DCmdArgument<jlong>::parse_value(const char* str,
size_t len, TRAPS) {
- if (str == NULL || sscanf(str, JLONG_FORMAT, &_value) != 1) {
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
- "Integer parsing error in diagnostic command arguments\n");
+ int scanned = -1;
+ if (str == NULL
+ || sscanf(str, JLONG_FORMAT"%n", &_value, &scanned) != 1
+ || (size_t)scanned != len)
+ {
+ ResourceMark rm;
+
+ char* buf = NEW_RESOURCE_ARRAY(char, len + 1);
+ strncpy(buf, str, len);
+ buf[len] = '\0';
+ Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(),
+ "Integer parsing error in command argument '%s'. Could not parse: %s.", _name, buf);
}
}
@@ -96,7 +106,7 @@ template <> void DCmdArgument<jlong>::init_value(TRAPS) {
if (has_default()) {
this->parse_value(_default_string, strlen(_default_string), THREAD);
if (HAS_PENDING_EXCEPTION) {
- fatal("Default string must be parsable");
+ fatal("Default string must be parseable");
}
} else {
set_value(0);
@@ -116,8 +126,13 @@ template <> void DCmdArgument<bool>::parse_value(const char* str,
} else if (len == strlen("false") && strncasecmp(str, "false", len) == 0) {
set_value(false);
} else {
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
- "Boolean parsing error in diagnostic command arguments");
+ ResourceMark rm;
+
+ char* buf = NEW_RESOURCE_ARRAY(char, len + 1);
+ strncpy(buf, str, len);
+ buf[len] = '\0';
+ Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(),
+ "Boolean parsing error in command argument '%s'. Could not parse: %s.", _name, buf);
}
}
}
@@ -168,7 +183,7 @@ template <> void DCmdArgument<NanoTimeArgument>::parse_value(const char* str,
size_t len, TRAPS) {
if (str == NULL) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
- "Integer parsing error nanotime value: syntax error");
+ "Integer parsing error nanotime value: syntax error, value is null");
}
int argc = sscanf(str, JLONG_FORMAT, &_value._time);
diff --git a/src/share/vm/services/diagnosticCommand.cpp b/src/share/vm/services/diagnosticCommand.cpp
index 5deaae0d4..79c922a85 100644
--- a/src/share/vm/services/diagnosticCommand.cpp
+++ b/src/share/vm/services/diagnosticCommand.cpp
@@ -320,8 +320,7 @@ ClassHistogramDCmd::ClassHistogramDCmd(outputStream* output, bool heap) :
void ClassHistogramDCmd::execute(DCmdSource source, TRAPS) {
VM_GC_HeapInspection heapop(output(),
- !_all.value() /* request full gc if false */,
- true /* need_prologue */);
+ !_all.value() /* request full gc if false */);
VMThread::execute(&heapop);
}
@@ -361,8 +360,7 @@ void ClassStatsDCmd::execute(DCmdSource source, TRAPS) {
}
VM_GC_HeapInspection heapop(output(),
- true, /* request_full_gc */
- true /* need_prologue */);
+ true /* request_full_gc */);
heapop.set_csv_format(_csv.value());
heapop.set_print_help(_help.value());
heapop.set_print_class_stats(true);
diff --git a/src/share/vm/services/memBaseline.cpp b/src/share/vm/services/memBaseline.cpp
index b090e95ac..c2d04106c 100644
--- a/src/share/vm/services/memBaseline.cpp
+++ b/src/share/vm/services/memBaseline.cpp
@@ -41,6 +41,7 @@ MemType2Name MemBaseline::MemType2NameMap[NUMBER_OF_MEMORY_TYPE] = {
{mtOther, "Other"},
{mtSymbol, "Symbol"},
{mtNMT, "Memory Tracking"},
+ {mtTracing, "Tracing"},
{mtChunk, "Pooled Free Chunks"},
{mtClassShared,"Shared spaces for classes"},
{mtTest, "Test"},
diff --git a/src/share/vm/trace/noTraceBackend.hpp b/src/share/vm/trace/noTraceBackend.hpp
new file mode 100644
index 000000000..475548726
--- /dev/null
+++ b/src/share/vm/trace/noTraceBackend.hpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013, 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_TRACE_NOTRACEBACKEND_HPP
+#define SHARE_VM_TRACE_NOTRACEBACKEND_HPP
+
+#include "prims/jni.h"
+
+typedef jlong TracingTime;
+typedef jlong RelativeTracingTime;
+
+class NoTraceBackend {
+public:
+ static TracingTime time() {
+ return 0;
+ }
+};
+
+class TraceThreadData {
+public:
+ TraceThreadData() {}
+};
+
+typedef NoTraceBackend Tracing;
+
+#endif
+
+
diff --git a/src/share/vm/trace/trace.dtd b/src/share/vm/trace/trace.dtd
new file mode 100644
index 000000000..a61984aaa
--- /dev/null
+++ b/src/share/vm/trace/trace.dtd
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2012, 2013, 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.
+
+-->
+
+<!ELEMENT trace (xi:include, relation_decls, events*, xi:include, xi:include)>
+<!ELEMENT types (content_types, primary_types)>
+<!ELEMENT content_types (content_type|struct_type)*>
+<!ELEMENT content_type (value|structvalue|structarray|array)*>
+<!ELEMENT struct_type (value*)>
+<!ELEMENT primary_types (primary_type*)>
+<!ELEMENT primary_type EMPTY>
+<!ELEMENT relation_decls (relation_decl*)>
+<!ELEMENT relation_decl EMPTY>
+<!ELEMENT events (event|struct)*>
+<!ELEMENT event (value|structvalue)*>
+<!ELEMENT struct (value|structvalue)*>
+<!ELEMENT value EMPTY>
+<!ELEMENT structvalue EMPTY>
+<!ELEMENT structarray EMPTY>
+<!ELEMENT array EMPTY>
+<!ATTLIST content_type id CDATA #REQUIRED
+ hr_name CDATA #REQUIRED
+ type CDATA #REQUIRED
+ jvm_type CDATA #IMPLIED
+ builtin_type CDATA #IMPLIED>
+<!ATTLIST struct_type id CDATA #REQUIRED>
+<!ATTLIST structarray type CDATA #REQUIRED
+ field CDATA #REQUIRED
+ label CDATA #REQUIRED>
+<!ATTLIST primary_type symbol CDATA #REQUIRED
+ datatype CDATA #REQUIRED
+ contenttype CDATA #REQUIRED
+ type CDATA #REQUIRED
+ sizeop CDATA #REQUIRED>
+<!ATTLIST relation_decl id CDATA #REQUIRED
+ uri CDATA #REQUIRED>
+<!ATTLIST event id CDATA #REQUIRED
+ path CDATA #REQUIRED
+ label CDATA #REQUIRED
+ description CDATA #IMPLIED
+ has_thread CDATA "false"
+ ignore_check CDATA "false"
+ has_stacktrace CDATA "false"
+ is_instant CDATA "false"
+ is_constant CDATA "false"
+ is_requestable CDATA "false">
+<!ATTLIST struct id CDATA #REQUIRED>
+<!ATTLIST value type CDATA #REQUIRED
+ field CDATA #REQUIRED
+ label CDATA #REQUIRED
+ description CDATA #IMPLIED
+ relation CDATA "NOT_AVAILABLE"
+ transition CDATA "NONE">
+<!ATTLIST array type CDATA #REQUIRED
+ field CDATA #REQUIRED
+ label CDATA #REQUIRED
+ description CDATA #IMPLIED>
+<!ATTLIST structarray type CDATA #REQUIRED
+ field CDATA #REQUIRED
+ label CDATA #REQUIRED
+ description CDATA #IMPLIED>
+<!ATTLIST structvalue type CDATA #REQUIRED
+ field CDATA #REQUIRED
+ label CDATA #REQUIRED
+ description CDATA #IMPLIED>
diff --git a/src/share/vm/trace/trace.xml b/src/share/vm/trace/trace.xml
new file mode 100644
index 000000000..c530bbc3c
--- /dev/null
+++ b/src/share/vm/trace/trace.xml
@@ -0,0 +1,367 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2012, 2013, 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 trace SYSTEM "trace.dtd" [
+<!ENTITY % xinclude SYSTEM "xinclude.mod">
+%xinclude;
+]>
+
+<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="JAVALANGTHREAD" field="javalangthread" label="Java Thread"/>
+ </event>
+
+ <event id="ThreadEnd" path="java/thread_end" label="Java Thread End"
+ has_thread="true" is_instant="true">
+ <value type="JAVALANGTHREAD" field="javalangthread" 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="JAVALANGTHREAD" 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="OSTHREAD" 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="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>
+
+ <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="capacity" label="Capacity" description="Total available memory to allocate in" />
+ <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" />
+ <structvalue type="MetaspaceSizes" field="metaspace" label="Total"/>
+ <structvalue type="MetaspaceSizes" field="dataSpace" label="Data"/>
+ <structvalue type="MetaspaceSizes" field="classSpace" label="Class"/>
+ </event>
+
+ <event id="PSHeapSummary" path="vm/gc/heap/ps_summary" label="ParallelScavengeHeap 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="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="RELATIVE_TICKS" field="sumOfPauses" label="Sum of Pauses" description="Sum of all the times in which Java execution was paused during the garbage collection" />
+ <value type="RELATIVE_TICKS" 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="EvacuationInfo" path="vm/gc/detailed/evacuation_info" label="Evacuation Info" 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="BytesCopied"/>
+ <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>
+
+ <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="OSTHREAD" 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>
+
+ <!-- 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>
+
+ <!-- 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="USHORT" field="sweepFractionIndex" label="Fraction Index"/>
+ <value type="UINT" field="sweptCount" label="Methods Swept"/>
+ <value type="UINT" field="flushedCount" label="Methods Flushed"/>
+ <value type="UINT" field="markedCount" label="Methods Reclaim"/>
+ <value type="UINT" field="zombifiedCount" label="Methods Zombified"/>
+ </event>
+
+ <event id="CleanCodeCache" path="vm/code_sweeper/clean" label="Clean Code Cache"
+ description="Clean code cache from oldest methods"
+ has_thread="true" is_requestable="false" is_constant="false">
+ <value type="UINT" field="disconnectedCount" label="Methods Disconnected"/>
+ <value type="UINT" field="madeNonEntrantCount" label="Methods Made Non-Entrant"/>
+ </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="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="OSTHREAD" 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>
+</trace>
diff --git a/src/share/vm/trace/traceBackend.hpp b/src/share/vm/trace/traceBackend.hpp
new file mode 100644
index 000000000..cd348dfa4
--- /dev/null
+++ b/src/share/vm/trace/traceBackend.hpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2012, 2013, 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_TRACE_TRACEBACKEND_HPP
+#define SHARE_VM_TRACE_TRACEBACKEND_HPP
+
+#include "utilities/macros.hpp"
+
+#if INCLUDE_TRACE
+
+#include "runtime/globals.hpp"
+#include "runtime/os.hpp"
+#include "trace/traceTime.hpp"
+#include "tracefiles/traceEventIds.hpp"
+
+class TraceBackend {
+public:
+ static bool enabled(void) {
+ return EnableTracing;
+ }
+
+ static bool is_event_enabled(TraceEventId id) {
+ return enabled();
+ }
+
+ static TracingTime time() {
+ return os::elapsed_counter();
+ }
+
+ static TracingTime time_adjustment(jlong time) {
+ return time;
+ }
+
+ static void on_unloading_classes(void) {
+ }
+};
+
+class TraceThreadData {
+public:
+ TraceThreadData() {}
+};
+
+typedef TraceBackend Tracing;
+
+#else /* INCLUDE_TRACE */
+
+#include "trace/noTraceBackend.hpp"
+
+#endif /* INCLUDE_TRACE */
+#endif /* SHARE_VM_TRACE_TRACEBACKEND_HPP */
diff --git a/src/share/vm/trace/traceDataTypes.hpp b/src/share/vm/trace/traceDataTypes.hpp
new file mode 100644
index 000000000..437ac447e
--- /dev/null
+++ b/src/share/vm/trace/traceDataTypes.hpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2012, 2013, 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_TRACE_TRACEDATATYPES_HPP
+#define SHARE_VM_TRACE_TRACEDATATYPES_HPP
+
+#include <stddef.h>
+
+#include "utilities/globalDefinitions.hpp"
+
+enum {
+ CONTENT_TYPE_NONE = 0,
+ CONTENT_TYPE_BYTES = 1,
+ CONTENT_TYPE_EPOCHMILLIS = 2,
+ CONTENT_TYPE_MILLIS = 3,
+ CONTENT_TYPE_NANOS = 4,
+ CONTENT_TYPE_TICKS = 5,
+ CONTENT_TYPE_ADDRESS = 6,
+
+ CONTENT_TYPE_OSTHREAD,
+ CONTENT_TYPE_JAVALANGTHREAD,
+ CONTENT_TYPE_STACKTRACE,
+ CONTENT_TYPE_CLASS,
+ CONTENT_TYPE_PERCENTAGE,
+
+ JVM_CONTENT_TYPES_START = 30,
+ JVM_CONTENT_TYPES_END = 100
+};
+
+enum ReservedEvent {
+ EVENT_PRODUCERS,
+ EVENT_CHECKPOINT,
+ EVENT_BUFFERLOST,
+
+ NUM_RESERVED_EVENTS
+};
+
+typedef enum ReservedEvent ReservedEvent;
+
+typedef u8 classid;
+typedef u8 stacktraceid;
+typedef u8 methodid;
+typedef u8 fieldid;
+
+#endif // SHARE_VM_TRACE_TRACEDATATYPES_HPP
+
diff --git a/src/share/vm/trace/traceEvent.hpp b/src/share/vm/trace/traceEvent.hpp
new file mode 100644
index 000000000..364c2df48
--- /dev/null
+++ b/src/share/vm/trace/traceEvent.hpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2012, 2013, 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_TRACE_TRACEEVENT_HPP
+#define SHARE_VM_TRACE_TRACEEVENT_HPP
+
+enum EventStartTime {
+ UNTIMED,
+ TIMED
+};
+
+#include "utilities/macros.hpp"
+
+#if INCLUDE_TRACE
+
+#include "trace/traceBackend.hpp"
+#include "trace/tracing.hpp"
+#include "tracefiles/traceEventIds.hpp"
+#include "tracefiles/traceTypes.hpp"
+
+template<typename T>
+class TraceEvent : public StackObj {
+ protected:
+ jlong _startTime;
+ jlong _endTime;
+
+ private:
+ bool _started;
+#ifdef ASSERT
+ bool _committed;
+ bool _cancelled;
+ protected:
+ bool _ignore_check;
+#endif
+
+ public:
+ TraceEvent(EventStartTime timing=TIMED) :
+ _startTime(0),
+ _endTime(0),
+ _started(false)
+#ifdef ASSERT
+ ,
+ _committed(false),
+ _cancelled(false),
+ _ignore_check(false)
+#endif
+ {
+ if (T::is_enabled()) {
+ _started = true;
+ if (timing == TIMED && !T::isInstant) {
+ static_cast<T *>(this)->set_starttime(Tracing::time());
+ }
+ }
+ }
+
+ static bool is_enabled() {
+ return Tracing::is_event_enabled(T::eventId);
+ }
+
+ bool should_commit() {
+ return _started;
+ }
+
+ void ignoreCheck() {
+ DEBUG_ONLY(_ignore_check = true);
+ }
+
+ void commit() {
+ if (!should_commit()) {
+ cancel();
+ return;
+ }
+ if (_endTime == 0) {
+ static_cast<T*>(this)->set_endtime(Tracing::time());
+ }
+ if (static_cast<T*>(this)->should_write()) {
+ static_cast<T*>(this)->writeEvent();
+ }
+ set_commited();
+ }
+
+ void set_starttime(jlong time) {
+ _startTime = time;
+ }
+
+ void set_endtime(jlong time) {
+ _endTime = time;
+ }
+
+ TraceEventId id() const {
+ return T::eventId;
+ }
+
+ bool is_instant() const {
+ return T::isInstant;
+ }
+
+ bool is_requestable() const {
+ return T::isRequestable;
+ }
+
+ bool has_thread() const {
+ return T::hasThread;
+ }
+
+ bool has_stacktrace() const {
+ return T::hasStackTrace;
+ }
+
+ void cancel() {
+ assert(!_committed && !_cancelled, "event was already committed/cancelled");
+ DEBUG_ONLY(_cancelled = true);
+ }
+
+ void set_commited() {
+ assert(!_committed, "event has already been committed");
+ DEBUG_ONLY(_committed = true);
+ }
+
+ ~TraceEvent() {
+ if (_started) {
+ assert(_ignore_check || _committed || _cancelled, "event was not committed/cancelled");
+ }
+ }
+};
+
+#endif /* INCLUDE_TRACE */
+
+#endif /* SHARE_VM_TRACE_TRACEEVENT_HPP */
diff --git a/src/share/vm/trace/traceEventClasses.xsl b/src/share/vm/trace/traceEventClasses.xsl
new file mode 100644
index 000000000..70ac9c037
--- /dev/null
+++ b/src/share/vm/trace/traceEventClasses.xsl
@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2012, 2013, 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.
+-->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:output method="text" indent="no" omit-xml-declaration="yes"/>
+<xsl:import href="xsl_util.xsl"/>
+
+<xsl:template match="/">
+ <xsl:call-template name="file-header"/>
+
+#ifndef TRACEFILES_TRACEEVENTCLASSES_HPP
+#define TRACEFILES_TRACEEVENTCLASSES_HPP
+
+// On purpose outside the INCLUDE_TRACE
+// Some parts of traceEvent.hpp are used outside of
+// INCLUDE_TRACE
+
+#include "memory/resourceArea.hpp"
+#include "tracefiles/traceTypes.hpp"
+#include "trace/traceEvent.hpp"
+#include "utilities/macros.hpp"
+
+#if INCLUDE_TRACE
+
+
+#include "trace/traceStream.hpp"
+#include "utilities/ostream.hpp"
+
+ <xsl:apply-templates select="trace/events/struct" mode="trace"/>
+ <xsl:apply-templates select="trace/events/event" mode="trace"/>
+
+#else
+
+class TraceEvent {
+public:
+ TraceEvent() {}
+ void set_starttime(jlong time) const {}
+ void set_endtime(jlong time) const {}
+ bool should_commit() const { return false; }
+ void commit() const {}
+};
+
+ <xsl:apply-templates select="trace/events/struct" mode="empty"/>
+ <xsl:apply-templates select="trace/events/event" mode="empty"/>
+
+#endif
+
+#endif
+</xsl:template>
+
+<xsl:template match="struct" mode="trace">
+struct TraceStruct<xsl:value-of select="@id"/>
+{
+private:
+<xsl:apply-templates select="value" mode="write-fields"/>
+public:
+<xsl:apply-templates select="value" mode="write-setters"/>
+
+ void writeStruct(TraceStream&amp; ts) {
+<xsl:apply-templates select="value" mode="write-data"/>
+ }
+};
+
+</xsl:template>
+
+<xsl:template match="struct" mode="empty">
+struct TraceStruct<xsl:value-of select="@id"/>
+{
+public:
+<xsl:apply-templates select="value" mode="write-empty-setters"/>
+};
+</xsl:template>
+
+
+<xsl:template match="event" mode="empty">
+ <xsl:value-of select="concat('class Event', @id, ' : public TraceEvent')"/>
+{
+ public:
+<xsl:value-of select="concat(' Event', @id, '(bool ignore=true) {}')"/>
+<xsl:text>
+</xsl:text>
+
+<xsl:apply-templates select="value|structvalue|transition_value|relation" mode="write-empty-setters"/>
+};
+
+</xsl:template>
+
+
+<xsl:template match="event" mode="trace">
+ <xsl:value-of select="concat('class Event', @id, ' : public TraceEvent&lt;Event', @id, '&gt;')"/>
+{
+ public:
+ static const bool hasThread = <xsl:value-of select="@has_thread"/>;
+ static const bool hasStackTrace = <xsl:value-of select="@has_stacktrace"/>;
+ static const bool isInstant = <xsl:value-of select="@is_instant"/>;
+ static const bool isRequestable = <xsl:value-of select="@is_requestable"/>;
+ static const TraceEventId eventId = <xsl:value-of select="concat('Trace', @id, 'Event')"/>;
+
+ private:
+<xsl:apply-templates select="value|structvalue|transition_value|relation" mode="write-fields"/>
+
+ void writeEventContent(void) {
+ TraceStream ts(*tty);
+ ts.print("<xsl:value-of select="@label"/>: [");
+<xsl:apply-templates select="value|structvalue" mode="write-data"/>
+ ts.print("]\n");
+ }
+
+ public:
+<xsl:apply-templates select="value|structvalue|transition_value|relation" mode="write-setters"/>
+
+ bool should_write(void) {
+ return true;
+ }
+<xsl:text>
+
+</xsl:text>
+ <xsl:value-of select="concat(' Event', @id, '(EventStartTime timing=TIMED) : TraceEvent&lt;Event', @id, '&gt;(timing) {}', $newline)"/>
+ void writeEvent(void) {
+ ResourceMark rm;
+ if (UseLockedTracing) {
+ ttyLocker lock;
+ writeEventContent();
+ } else {
+ writeEventContent();
+ }
+ }
+};
+
+</xsl:template>
+
+<xsl:template match="value|transition_value|relation" mode="write-empty-setters">
+ <xsl:param name="cls"/>
+ <xsl:variable name="type" select="@type"/>
+ <xsl:variable name="wt" select="//primary_type[@symbol=$type]/@type"/>
+ <xsl:value-of select="concat(' void set_', @field, '(', $wt, ' value) { }')"/>
+ <xsl:if test="position() != last()">
+ <xsl:text>
+</xsl:text>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="structvalue" mode="write-empty-setters">
+ <xsl:param name="cls"/>
+ <xsl:value-of select="concat(' void set_', @field, '(const TraceStruct', @type, '&amp; value) { }')"/>
+ <xsl:if test="position() != last()">
+ <xsl:text>
+</xsl:text>
+ </xsl:if>
+</xsl:template>
+
+
+<xsl:template match="value[@type='TICKS']" mode="write-setters">
+#if INCLUDE_TRACE
+ <xsl:value-of select="concat('void set_', @field, '(jlong time) { _', @field, ' = time; }')"/>
+#else
+ <xsl:value-of select="concat('void set_', @field, '(jlong ignore) {}')"/>
+#endif
+</xsl:template>
+
+<xsl:template match="value[@type='RELATIVE_TICKS']" mode="write-setters">
+#if INCLUDE_TRACE
+ <xsl:value-of select="concat('void set_', @field, '(jlong time) { _', @field, ' = time; }')"/>
+#else
+ <xsl:value-of select="concat('void set_', @field, '(jlong ignore) {}')"/>
+#endif
+</xsl:template>
+
+<xsl:template match="value" mode="write-fields">
+ <xsl:variable name="type" select="@type"/>
+ <xsl:variable name="wt" select="//primary_type[@symbol=$type]/@type"/>
+ <xsl:value-of select="concat(' ', $wt, ' _', @field, ';')"/>
+ <xsl:if test="position() != last()">
+ <xsl:text>
+</xsl:text>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="structvalue" mode="write-fields">
+ <xsl:value-of select="concat(' TraceStruct', @type, ' _', @field, ';')"/>
+ <xsl:text>
+</xsl:text>
+</xsl:template>
+
+<xsl:template match="value|transition_value|relation" mode="write-setters">
+ <xsl:param name="cls"/>
+ <xsl:variable name="type" select="@type"/>
+ <xsl:variable name="wt" select="//primary_type[@symbol=$type]/@type"/>
+ <xsl:value-of select="concat(' void set_', @field, '(', $wt, ' value) { this->_', @field, ' = value; }')"/>
+ <xsl:if test="position() != last()">
+ <xsl:text>
+</xsl:text>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="structvalue" mode="write-setters">
+ <xsl:param name="cls"/>
+ <xsl:value-of select="concat(' void set_', @field, '(const TraceStruct', @type, '&amp; value) { this->_', @field, ' = value; }')"/>
+ <xsl:if test="position() != last()">
+ <xsl:text>
+</xsl:text>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="value" mode="write-data">
+ <xsl:variable name="type" select="@type"/>
+ <xsl:variable name="wt" select="//primary_type[@symbol=$type]/@writetype"/>
+ <xsl:value-of select="concat(' ts.print_val(&quot;', @label, '&quot;, _', @field, ');')"/>
+ <xsl:if test="position() != last()">
+ <xsl:text>
+ ts.print(", ");
+</xsl:text>
+ </xsl:if>
+</xsl:template>
+
+<xsl:template match="structvalue" mode="write-data">
+ <xsl:value-of select="concat(' _', @field, '.writeStruct(ts);')"/>
+ <xsl:if test="position() != last()">
+ <xsl:text>
+ ts.print(", ");
+</xsl:text>
+ </xsl:if>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/share/vm/trace/traceEventIds.xsl b/src/share/vm/trace/traceEventIds.xsl
new file mode 100644
index 000000000..737377cad
--- /dev/null
+++ b/src/share/vm/trace/traceEventIds.xsl
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2012, 2013, 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.
+-->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:output method="text" indent="no" omit-xml-declaration="yes"/>
+<xsl:import href="xsl_util.xsl"/>
+
+<xsl:template match="/">
+ <xsl:call-template name="file-header"/>
+
+#ifndef TRACEFILES_JFREVENTIDS_HPP
+#define TRACEFILES_JFREVENTIDS_HPP
+
+#include "utilities/macros.hpp"
+
+#if INCLUDE_TRACE
+
+#include "trace/traceDataTypes.hpp"
+
+/**
+ * Enum of the event types in the JVM
+ */
+enum TraceEventId {
+ _traceeventbase = (NUM_RESERVED_EVENTS-1), // Make sure we start at right index.
+
+ // Events -> enum entry
+<xsl:for-each select="trace/events/event">
+ <xsl:value-of select="concat(' Trace', @id, 'Event,', $newline)"/>
+</xsl:for-each>
+ MaxTraceEventId
+};
+
+/**
+ * Struct types in the JVM
+ */
+enum TraceStructId {
+<xsl:for-each select="trace/types/content_types/*">
+ <xsl:value-of select="concat(' Trace', @id, 'Struct,', $newline)"/>
+</xsl:for-each>
+<xsl:for-each select="trace/events/*">
+ <xsl:value-of select="concat(' Trace', @id, 'Struct,', $newline)"/>
+</xsl:for-each>
+ MaxTraceStructId
+};
+
+typedef enum TraceEventId TraceEventId;
+typedef enum TraceStructId TraceStructId;
+
+#endif
+#endif
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/share/vm/trace/traceMacros.hpp b/src/share/vm/trace/traceMacros.hpp
index 441031920..1a6dd6449 100644
--- a/src/share/vm/trace/traceMacros.hpp
+++ b/src/share/vm/trace/traceMacros.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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,22 +25,14 @@
#ifndef SHARE_VM_TRACE_TRACE_MACRO_HPP
#define SHARE_VM_TRACE_TRACE_MACRO_HPP
-#define EVENT_BEGIN(type, name)
-#define EVENT_SET(name, field, value)
-#define EVENT_COMMIT(name, ...)
-#define EVENT_STARTED(name, time)
-#define EVENT_ENDED(name, time)
#define EVENT_THREAD_EXIT(thread)
-#define TRACE_ENABLED 0
-
#define TRACE_INIT_ID(k)
-#define TRACE_BUFFER void*
+#define TRACE_DATA TraceThreadData
-#define TRACE_START() true
-#define TRACE_INITIALIZE() 0
+#define TRACE_START() JNI_OK
+#define TRACE_INITIALIZE() JNI_OK
-#define TRACE_SET_KLASS_TRACE_ID(x1, x2) do { } while (0)
#define TRACE_DEFINE_KLASS_METHODS typedef int ___IGNORED_hs_trace_type1
#define TRACE_DEFINE_KLASS_TRACE_ID typedef int ___IGNORED_hs_trace_type2
#define TRACE_DEFINE_OFFSET typedef int ___IGNORED_hs_trace_type3
diff --git a/src/share/vm/trace/traceStream.hpp b/src/share/vm/trace/traceStream.hpp
new file mode 100644
index 000000000..4acbbb884
--- /dev/null
+++ b/src/share/vm/trace/traceStream.hpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2012, 2013, 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_TRACE_TRACESTREAM_HPP
+#define SHARE_VM_TRACE_TRACESTREAM_HPP
+
+#include "utilities/macros.hpp"
+
+#if INCLUDE_TRACE
+
+#include "oops/klass.hpp"
+#include "oops/method.hpp"
+#include "oops/symbol.hpp"
+#include "utilities/ostream.hpp"
+
+class TraceStream : public StackObj {
+ private:
+ outputStream& _st;
+
+ public:
+ TraceStream(outputStream& stream): _st(stream) {}
+
+ void print_val(const char* label, u1 val) {
+ _st.print("%s = "UINT32_FORMAT, label, val);
+ }
+
+ void print_val(const char* label, u2 val) {
+ _st.print("%s = "UINT32_FORMAT, label, val);
+ }
+
+ void print_val(const char* label, s2 val) {
+ _st.print("%s = "INT32_FORMAT, label, val);
+ }
+
+ void print_val(const char* label, u4 val) {
+ _st.print("%s = "UINT32_FORMAT, label, val);
+ }
+
+ void print_val(const char* label, s4 val) {
+ _st.print("%s = "INT32_FORMAT, label, val);
+ }
+
+ void print_val(const char* label, u8 val) {
+ _st.print("%s = "UINT64_FORMAT, label, val);
+ }
+
+ void print_val(const char* label, s8 val) {
+ _st.print("%s = "INT64_FORMAT, label, val);
+ }
+
+ void print_val(const char* label, bool val) {
+ _st.print("%s = %s", label, val ? "true" : "false");
+ }
+
+ void print_val(const char* label, float val) {
+ _st.print("%s = %f", label, val);
+ }
+
+ void print_val(const char* label, double val) {
+ _st.print("%s = %f", label, val);
+ }
+
+ // Caller is machine generated code located in traceEventClasses.hpp
+ // Event<TraceId>::writeEvent() (pseudocode) contains the
+ // necessary ResourceMark for the resource allocations below.
+ // See traceEventClasses.xsl for details.
+ void print_val(const char* label, const Klass* const val) {
+ const char* description = "NULL";
+ if (val != NULL) {
+ Symbol* name = val->name();
+ if (name != NULL) {
+ description = name->as_C_string();
+ }
+ }
+ _st.print("%s = %s", label, description);
+ }
+
+ // Caller is machine generated code located in traceEventClasses.hpp
+ // Event<TraceId>::writeEvent() (pseudocode) contains the
+ // necessary ResourceMark for the resource allocations below.
+ // See traceEventClasses.xsl for details.
+ void print_val(const char* label, const Method* const val) {
+ const char* description = "NULL";
+ if (val != NULL) {
+ description = val->name_and_sig_as_C_string();
+ }
+ _st.print("%s = %s", label, description);
+ }
+
+ void print_val(const char* label, const char* val) {
+ _st.print("%s = '%s'", label, val);
+ }
+
+ void print(const char* val) {
+ _st.print(val);
+ }
+};
+
+#endif /* INCLUDE_TRACE */
+#endif /* SHARE_VM_TRACE_TRACESTREAM_HPP */
diff --git a/src/share/vm/trace/traceEventTypes.hpp b/src/share/vm/trace/traceTime.hpp
index e7448aaeb..3a0fe2037 100644
--- a/src/share/vm/trace/traceEventTypes.hpp
+++ b/src/share/vm/trace/traceTime.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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
@@ -22,9 +22,12 @@
*
*/
-#ifndef SHARE_VM_TRACE_TRACE_EVENT_TYPES_HPP
-#define SHARE_VM_TRACE_TRACE_EVENT_TYPES_HPP
+#ifndef SHARE_VM_TRACE_TRACETIME_HPP
+#define SHARE_VM_TRACE_TRACETIME_HPP
-/* Empty, just a placeholder for tracing events */
+#include "prims/jni.h"
+
+typedef jlong TracingTime;
+typedef jlong RelativeTracingTime;
#endif
diff --git a/src/share/vm/trace/traceTypes.xsl b/src/share/vm/trace/traceTypes.xsl
new file mode 100644
index 000000000..b06b604ce
--- /dev/null
+++ b/src/share/vm/trace/traceTypes.xsl
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2012, 2013, 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.
+-->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+<xsl:output method="text" indent="no" omit-xml-declaration="yes"/>
+<xsl:import href="xsl_util.xsl"/>
+
+<xsl:template match="/">
+ <xsl:call-template name="file-header"/>
+
+#ifndef TRACEFILES_JFRTYPES_HPP
+#define TRACEFILES_JFRTYPES_HPP
+
+#include "trace/traceDataTypes.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "oops/symbol.hpp"
+
+enum JVMContentType {
+ _not_a_content_type = (JVM_CONTENT_TYPES_START - 1),
+
+<xsl:for-each select="trace/types/content_types/content_type[@jvm_type]">
+ <xsl:value-of select="concat(' CONTENT_TYPE_', @jvm_type, ',', $newline)"/>
+</xsl:for-each>
+ NUM_JVM_CONTENT_TYPES
+};
+
+
+enum JVMEventRelations {
+ JVM_REL_NOT_AVAILABLE = 0,
+
+<xsl:for-each select="trace/relation_decls/relation_decl">
+ <xsl:value-of select="concat(' JVM_REL_', @id, ',', $newline)"/>
+</xsl:for-each>
+ NUM_EVENT_RELATIONS
+};
+
+/**
+ * Create typedefs for the JRA types:
+ * typedef s8 TYPE_LONG;
+ * typedef s4 TYPE_INTEGER;
+ * typedef const char * TYPE_STRING;
+ * ...
+ */
+<xsl:for-each select="trace/types/primary_types/primary_type">
+typedef <xsl:value-of select="@type"/> TYPE_<xsl:value-of select="@symbol"/>;
+</xsl:for-each>
+
+#endif // JFRFILES_JFRTYPES_HPP
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/src/share/vm/trace/tracetypes.xml b/src/share/vm/trace/tracetypes.xml
new file mode 100644
index 000000000..7f0460e69
--- /dev/null
+++ b/src/share/vm/trace/tracetypes.xml
@@ -0,0 +1,368 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2012, 2013, 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 types SYSTEM "trace.dtd">
+
+<!--
+
+Content types (complex) should create constant pool data
+in the recording.
+Currently at least, there is _NO_ verification that whatever
+writer you have is actually writing correctly. So BE CAREFUL!
+
+Declared with the 'content_type' tag.
+
+<type> is the ID type, i.e the integer type that resolves this. Most often
+U4 or U8, but for example really small number constants, like GCTYPE uses U1.
+
+<content-type> is where it gets interesting. 'builtin_type' means we're
+defining how we resolve one of the trace built-in types (Class, Thread etc),
+jvm_type means defining a new one for our own use.
+
+Example: (GcMode)
+
+<content_type id="GCMode" hr_name="GC mode" type="U1" jvm_type="GCMODE">
+ <value type="UTF8" field="desc" description="Description"/>
+</content_type>
+
+This creates a content type CONTENT_TYPE_GCMODE
+The field type referencing it is u1 (U1), and the constant pool struct has one field, the name.
+
+Before we can use it we need also define a primary field data type:
+
+<primary_type symbol="GCMODE" datatype="U1" contenttype="NONE"
+ type="u8" sizeop="sizeof(u1)"/>
+
+Now we can use the content + data type in declaring event fields.
+Remember however, that for us to be able to resolve the value later we must also add
+creating the constant pool data in VM_JFRCheckpoint::write_checkpoint
+
+ ...
+ //CGMODE
+ w->be_uint(CONTENT_TYPE_GCMODE);
+ w->be_uint(MM_GC_MODE_UNINITIALIZED);
+ for (i = 0; i < MM_GC_MODE_UNINITIALIZED; i++) {
+ w->uchar(i);
+ w->write_utf8(gcModeGetName(i));
+ }
+
+ -->
+
+ <types>
+ <content_types>
+ <content_type id="Thread" hr_name="Thread"
+ type="U4" builtin_type="OSTHREAD">
+ <value type="UTF8" field="name" label="Thread name"/>
+ </content_type>
+
+ <content_type id="VMThread" hr_name="VM Thread"
+ type="U8" jvm_type="VMTHREAD">
+ <value type="OSTHREAD" field="thread" label="VM Thread"/>
+ </content_type>
+
+ <!-- The first argument ("JavaThread") is misleading, it's really a
+ java.lang.Thread id (long), but Mission Control depends on the name
+ being "JavaThread" so it shouldn't be changed.
+ -->
+ <content_type id="JavaThread" hr_name="Java thread"
+ type="U8" builtin_type="JAVALANGTHREAD">
+ <value type="OSTHREAD" field="thread" label="OS Thread ID"/>
+ <value type="BYTES64" field="allocInsideTla"
+ label="Allocated bytes inside TLAs"/>
+ <value type="BYTES64" field="allocOutsideTla"
+ label="Allocated bytes outside TLAs"/>
+ <value type="THREADGROUP" field="group" label="Java Thread Group"/>
+ </content_type>
+
+ <content_type id="ThreadGroup" hr_name="Thread group"
+ type="U4" jvm_type="THREADGROUP">
+ <value type="THREADGROUP" field="parent" label="Parent"/>
+ <value type="UTF8" field="name" label="Name"/>
+ </content_type>
+
+ <content_type id="StackTrace" hr_name="Stacktrace"
+ type="U8" builtin_type="STACKTRACE">
+ <value type="BOOLEAN" field="truncated" label="Truncated"/>
+ <structarray type="StackFrame" field="frames" label="Stack frames"/>
+ </content_type>
+
+ <content_type id="Class" hr_name="Java class"
+ type="U8" builtin_type="CLASS">
+ <value type="CLASS" field="loaderClass" label="ClassLoader"/>
+ <value type="SYMBOL" field="name" label="Name"/>
+ <value type="SHORT" field="modifiers" label="Access modifiers"/>
+ </content_type>
+
+ <content_type id="Method" hr_name="Java method"
+ type="U8" jvm_type="METHOD">
+ <value type="CLASS" field="class" label="Class"/>
+ <value type="SYMBOL" field="name" label="Name"/>
+ <value type="SYMBOL" field="signature" label="Signature"/>
+ <value type="SHORT" field="modifiers" label="Access modifiers"/>
+ </content_type>
+
+ <content_type id="UTFConstant" hr_name="UTF constant"
+ type="U8" jvm_type="SYMBOL">
+ <value type="UTF8" field="utf8" label="UTF8 data"/>
+ </content_type>
+
+ <content_type id="ThreadState" hr_name="Java Thread State"
+ type="U2" jvm_type="THREADSTATE">
+ <value type="UTF8" field="name" label="Name"/>
+ </content_type>
+
+ <content_type id="FrameType" hr_name="Frame type"
+ type="U1" jvm_type="FRAMETYPE">
+ <value type="UTF8" field="desc" label="Description"/>
+ </content_type>
+
+ <struct_type id="StackFrame">
+ <value type="METHOD" field="method" label="Java Method"/>
+ <value type="INTEGER" field="line" label="Line number"/>
+ <value type="FRAMETYPE" field="type" label="Frame type"/>
+ </struct_type>
+
+ <content_type id="GCName" hr_name="GC Name"
+ type="U1" jvm_type="GCNAME">
+ <value type="UTF8" field="name" label="name" />
+ </content_type>
+
+ <content_type id="GCCause" hr_name="GC Cause"
+ type="U2" jvm_type="GCCAUSE">
+ <value type="UTF8" field="cause" label="cause" />
+ </content_type>
+
+ <content_type id="GCWhen" hr_name="GC When"
+ type="U1" jvm_type="GCWHEN">
+ <value type="UTF8" field="when" label="when" />
+ </content_type>
+
+ <content_type id="G1YCType" hr_name="G1 YC Type"
+ type="U1" jvm_type="G1YCTYPE">
+ <value type="UTF8" field="type" label="type" />
+ </content_type>
+
+ <content_type id="ReferenceType" hr_name="Reference Type"
+ type="U1" jvm_type="REFERENCETYPE">
+ <value type="UTF8" field="type" label="type" />
+ </content_type>
+
+ <content_type id="NARROW_OOP_MODE" hr_name="Narrow Oop Mode"
+ type="U1" jvm_type="NARROWOOPMODE">
+ <value type="UTF8" field="mode" label="mode" />
+ </content_type>
+
+ <content_type id="VMOperationType" hr_name="VM Operation Type"
+ type="U2" jvm_type="VMOPERATIONTYPE">
+ <value type="UTF8" field="type" label="type" />
+ </content_type>
+
+ <content_type id="CompilerPhaseType" hr_name="Compiler Phase Type"
+ type="U1" jvm_type="COMPILERPHASETYPE">
+ <value type="UTF8" field="phase" label="phase" />
+ </content_type>
+
+ </content_types>
+
+
+ <primary_types>
+ <!--
+ - primary_type takes these attributes:
+ - symbol INTEGER, LONG etc
+ - datatype The trace datatype, see enum DataType
+ - contenttype Either resolved content type or the semantic meaning
+ - type The actual type as used in structures etc
+ - sizeop A function/macro that can be applied on a single
+ - struct value of type "type" and yield the factual byte
+ - size we need to write. The % is replaced by the value
+ -->
+
+ <!-- SIGNED 64bit -->
+ <primary_type symbol="LONG" datatype="LONG" contenttype="NONE"
+ type="s8" sizeop="sizeof(s8)"/>
+
+ <!-- UNSIGNED 64bit -->
+ <primary_type symbol="ULONG" datatype="U8" contenttype="NONE"
+ type="u8" sizeop="sizeof(u8)"/>
+
+ <!-- SIGNED 32bit -->
+ <primary_type symbol="INTEGER" datatype="INT" contenttype="NONE"
+ type="s4" sizeop="sizeof(s4)"/>
+
+ <!-- UNSIGNED 32bit -->
+ <primary_type symbol="UINT" datatype="U4" contenttype="NONE"
+ type="unsigned" sizeop="sizeof(unsigned)"/>
+
+ <!-- UNSIGNED 16bit -->
+ <primary_type symbol="USHORT" datatype="U2" contenttype="NONE"
+ type="u2" sizeop="sizeof(u2)"/>
+
+ <!-- SIGNED 16bit -->
+ <primary_type symbol="SHORT" datatype="SHORT" contenttype="NONE"
+ type="s2" sizeop="sizeof(s2)"/>
+
+ <!-- SIGNED 8bit -->
+ <primary_type symbol="BYTE" datatype="BYTE" contenttype="NONE"
+ type="s1" sizeop="sizeof(s1)"/>
+
+ <!-- UNSIGNED 8bit -->
+ <primary_type symbol="UBYTE" datatype="U1" contenttype="NONE"
+ type="u1" sizeop="sizeof(u1)"/>
+
+ <!-- float 32bit -->
+ <primary_type symbol="FLOAT" datatype="FLOAT" contenttype="NONE"
+ type="float" sizeop="sizeof(float)"/>
+
+ <!-- float 64bit -->
+ <primary_type symbol="DOUBLE" datatype="DOUBLE" contenttype="NONE"
+ type="double" sizeop="sizeof(double)"/>
+
+ <!-- boolean type (1-byte) -->
+ <primary_type symbol="BOOLEAN" datatype="BOOLEAN" contenttype="NONE"
+ type="bool" sizeop="1"/>
+
+ <!-- 32-bit unsigned integer, SEMANTIC value BYTES -->
+ <primary_type symbol="BYTES" datatype="U4" contenttype="BYTES"
+ type="u4" sizeop="sizeof(u4)"/>
+
+ <primary_type symbol="IOBYTES" datatype="U4" contenttype="BYTES"
+ type="u4" sizeop="sizeof(u4)"/>
+
+ <!-- 64-bit unsigned integer, SEMANTIC value BYTES -->
+ <primary_type symbol="BYTES64" datatype="U8" contenttype="BYTES"
+ type="u8" sizeop="sizeof(u8)"/>
+
+ <!-- 64-bit unsigned integer, SEMANTIC value ABSOLUTE MILLISECONDS -->
+ <primary_type symbol="EPOCHMILLIS" datatype="LONG" contenttype="EPOCHMILLIS"
+ type="s8" sizeop="sizeof(s8)"/>
+
+ <!-- 64-bit unsigned integer, SEMANTIC value RELATIVE MILLISECONDS -->
+ <primary_type symbol="MILLIS" datatype="LONG" contenttype="MILLIS"
+ type="s8" sizeop="sizeof(s8)"/>
+
+ <!-- 64-bit unsigned integer, SEMANTIC value RELATIVE NANOSECONDS -->
+ <primary_type symbol="NANOS" datatype="LONG" contenttype="NANOS"
+ type="s8" sizeop="sizeof(s8)"/>
+
+ <!-- 64-bit signed integer, SEMANTIC value ABSOLUTE TICKS -->
+ <primary_type symbol="TICKS" datatype="LONG" contenttype="TICKS"
+ type="s8" sizeop="sizeof(s8)"/>
+
+ <!-- 64-bit signed integer, SEMANTIC value RELATIVE TICKS -->
+ <primary_type symbol="RELATIVE_TICKS" datatype="LONG" contenttype="TICKS"
+ type="s8" sizeop="sizeof(s8)"/>
+
+ <!-- 64-bit unsigned integer, SEMANTIC value ADDRESS (mem loc) -->
+ <primary_type symbol="ADDRESS" datatype="U8" contenttype="ADDRESS"
+ type="u8" sizeop="sizeof(u8)"/>
+
+ <!-- 32-bit float, SEMANTIC value PERCENTAGE (0.0-1.0) -->
+ <primary_type symbol="PERCENT" datatype="FLOAT" contenttype="PERCENTAGE"
+ type="float" sizeop="sizeof(float)"/>
+
+ <!-- UTF-encoded string, max length 64k -->
+ <primary_type symbol="UTF8" datatype="UTF8" contenttype="NONE"
+ type="const char *" sizeop="sizeof_utf(%)"/>
+
+ <!-- Symbol* constant. Note that this may currently ONLY be used by
+ classes, methods fields. This restriction might be lifted. -->
+ <primary_type symbol="SYMBOL" datatype="U8" contenttype="SYMBOL"
+ type="Symbol *" sizeop="sizeof(u8)"/>
+
+ <!-- A Klass *. The actual class is marked as "used" and will
+ eventually be written into the recording constant pool -->
+ <primary_type symbol="CLASS" datatype="U8" contenttype="CLASS"
+ type="Klass *" sizeop="sizeof(u8)"/>
+
+ <!-- A Method *. The method is marked as "used" and will eventually be
+ written into the recording constant pool. -->
+ <primary_type symbol="METHOD" datatype="U8" contenttype="METHOD"
+ type="Method *" sizeop="sizeof(u8)"/>
+
+ <!-- The type for stacktraces in the recording. Shoudl not be used by
+ events explicitly -->
+ <primary_type symbol="STACKTRACE" datatype="U8" contenttype="STACKTRACE"
+ type="u8" sizeop="sizeof(u8)"/>
+
+ <!-- OS Thread ID -->
+ <primary_type symbol="OSTHREAD" datatype="U4" contenttype="OSTHREAD"
+ type="u4" sizeop="sizeof(u4)"/>
+
+ <!-- VM Thread ID Note: changed from U2 to U8 for hotspot -->
+ <primary_type symbol="VMTHREAD" datatype="U8" contenttype="VMTHREAD"
+ type="u8" sizeop="sizeof(u8)"/>
+
+ <!-- Java Thread ID -->
+ <primary_type symbol="JAVALANGTHREAD" datatype="LONG"
+ contenttype="JAVALANGTHREAD" type="s8"
+ sizeop="sizeof(s8)"/>
+
+ <!-- Threadgroup THIS TYPE MAY NOT BE USED IN NORMAL EVENTS (ATM). Only
+ for thread constant pool // KK TODO: u8 should be ObjectP -->
+ <primary_type symbol="THREADGROUP" datatype="U4" contenttype="THREADGROUP"
+ type="u8"
+ sizeop="sizeof(u4)"/>
+
+ <!-- FRAMETYPE enum -->
+ <primary_type symbol="FRAMETYPE" datatype="U1" contenttype="FRAMETYPE"
+ type="u1" sizeop="sizeof(u1)"/>
+
+ <!-- THREADSTATE enum -->
+ <primary_type symbol="THREADSTATE" datatype="U2" contenttype="THREADSTATE"
+ type="u2" sizeop="sizeof(u2)"/>
+
+ <!-- GCName -->
+ <primary_type symbol="GCNAME" datatype="U1" contenttype="GCNAME"
+ type="u1" sizeop="sizeof(u1)" />
+
+ <!-- GCCAUSE -->
+ <primary_type symbol="GCCAUSE" datatype="U2" contenttype="GCCAUSE"
+ type="u2" sizeop="sizeof(u2)" />
+
+ <!-- GCWHEN -->
+ <primary_type symbol="GCWHEN" datatype="U1" contenttype="GCWHEN"
+ type="u1" sizeop="sizeof(u1)" />
+
+ <!-- G1YCType -->
+ <primary_type symbol="G1YCTYPE" datatype="U1" contenttype="G1YCTYPE"
+ type="u1" sizeop="sizeof(u1)" />
+
+ <!-- REFERENCETYPE -->
+ <primary_type symbol="REFERENCETYPE" datatype="U1"
+ contenttype="REFERENCETYPE" type="u1" sizeop="sizeof(u1)" />
+
+ <!-- NARROWOOPMODE -->
+ <primary_type symbol="NARROWOOPMODE" datatype="U1"
+ contenttype="NARROWOOPMODE" type="u1" sizeop="sizeof(u1)" />
+
+ <!-- COMPILERPHASETYPE -->
+ <primary_type symbol="COMPILERPHASETYPE" datatype="U1"
+ contenttype="COMPILERPHASETYPE" type="u1" sizeop="sizeof(u1)" />
+
+ <!-- VMOPERATIONTYPE -->
+ <primary_type symbol="VMOPERATIONTYPE" datatype="U2" contenttype="VMOPERATIONTYPE"
+ type="u2" sizeop="sizeof(u2)" />
+
+ </primary_types>
+</types>
diff --git a/src/share/vm/trace/tracing.hpp b/src/share/vm/trace/tracing.hpp
index c56e2dc2d..72530e745 100644
--- a/src/share/vm/trace/tracing.hpp
+++ b/src/share/vm/trace/tracing.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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 @@
#ifndef SHARE_VM_TRACE_TRACING_HPP
#define SHARE_VM_TRACE_TRACING_HPP
-#include "trace/traceMacros.hpp"
+#include "tracefiles/traceEventClasses.hpp"
+#include "tracefiles/traceEventIds.hpp"
#endif
diff --git a/src/share/vm/trace/xinclude.mod b/src/share/vm/trace/xinclude.mod
new file mode 100644
index 000000000..17d259cdf
--- /dev/null
+++ b/src/share/vm/trace/xinclude.mod
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2012, 2013, 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.
+
+-->
+
+<!--
+ Copyright (c) 2012, 2013, 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.
+
+-->
+<!ELEMENT xi:include (xi:fallback?) >
+<!ATTLIST xi:include
+ xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude"
+ href CDATA #IMPLIED
+ parse (xml|text) "xml"
+ xpointer CDATA #IMPLIED
+ encoding CDATA #IMPLIED
+ accept CDATA #IMPLIED
+ accept-language CDATA #IMPLIED >
+
+<!ELEMENT xi:fallback ANY>
+<!ATTLIST xi:fallback
+ xmlns:xi CDATA #FIXED "http://www.w3.org/2001/XInclude" >
diff --git a/src/share/vm/trace/xsl_util.xsl b/src/share/vm/trace/xsl_util.xsl
new file mode 100644
index 000000000..fb82914c7
--- /dev/null
+++ b/src/share/vm/trace/xsl_util.xsl
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2012, 2013, 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.
+-->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+
+<!-- utilities used when generating code -->
+
+<xsl:variable name="newline">
+ <xsl:text>&#xA;</xsl:text>
+</xsl:variable>
+
+<xsl:variable name="indent1">
+ <xsl:text>&#xA; </xsl:text>
+</xsl:variable>
+
+<xsl:variable name="indent2">
+ <xsl:text>&#xA; </xsl:text>
+</xsl:variable>
+
+<xsl:variable name="indent3">
+ <xsl:text>&#xA; </xsl:text>
+</xsl:variable>
+
+<xsl:variable name="indent4">
+ <xsl:text>&#xA; </xsl:text>
+</xsl:variable>
+
+<xsl:variable name="quote">
+ <xsl:text>"</xsl:text>
+</xsl:variable>
+
+<xsl:template name="file-header">
+ <xsl:text>/* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */</xsl:text>
+</xsl:template>
+
+<xsl:template name="string-replace-all">
+ <xsl:param name="text" />
+ <xsl:param name="replace" />
+ <xsl:param name="by" />
+ <xsl:choose>
+ <xsl:when test="contains($text, $replace)">
+ <xsl:value-of select="substring-before($text,$replace)" />
+ <xsl:value-of select="$by" />
+ <xsl:call-template name="string-replace-all">
+ <xsl:with-param name="text" select="substring-after($text,$replace)" />
+ <xsl:with-param name="replace" select="$replace" />
+ <xsl:with-param name="by" select="$by" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$text" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+
+</xsl:stylesheet>
diff --git a/src/share/vm/utilities/globalDefinitions.hpp b/src/share/vm/utilities/globalDefinitions.hpp
index d9088307a..e7f3f3f70 100644
--- a/src/share/vm/utilities/globalDefinitions.hpp
+++ b/src/share/vm/utilities/globalDefinitions.hpp
@@ -763,18 +763,6 @@ inline BasicType as_BasicType(TosState state) {
TosState as_TosState(BasicType type);
-// ReferenceType is used to distinguish between java/lang/ref/Reference subclasses
-
-enum ReferenceType {
- REF_NONE, // Regular class
- REF_OTHER, // Subclass of java/lang/ref/Reference, but not subclass of one of the classes below
- REF_SOFT, // Subclass of java/lang/ref/SoftReference
- REF_WEAK, // Subclass of java/lang/ref/WeakReference
- REF_FINAL, // Subclass of java/lang/ref/FinalReference
- REF_PHANTOM // Subclass of java/lang/ref/PhantomReference
-};
-
-
// JavaThreadState keeps track of which part of the code a thread is executing in. This
// information is needed by the safepoint code.
//
diff --git a/src/share/vm/utilities/macros.hpp b/src/share/vm/utilities/macros.hpp
index a97e9e7d0..468c18fdd 100644
--- a/src/share/vm/utilities/macros.hpp
+++ b/src/share/vm/utilities/macros.hpp
@@ -160,6 +160,10 @@
#define NOT_NMT_RETURN_(code) { return code; }
#endif // INCLUDE_NMT
+#ifndef INCLUDE_TRACE
+#define INCLUDE_TRACE 1
+#endif // INCLUDE_TRACE
+
// COMPILER1 variant
#ifdef COMPILER1
#ifdef COMPILER2