From 8addc1418acf6d0cbba7c56429a12be2e1ebf521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Wed, 30 Oct 2019 19:43:52 +0100 Subject: [PATCH] 8226511: Implement JFR Event Streaming Co-authored-by: Erik Gahlin Co-authored-by: Mikhailo Seledtsov Reviewed-by: egahlin, mseledtsov, mgronlun --- src/hotspot/share/gc/g1/g1Trace.cpp | 4 +- .../gc/shenandoah/shenandoahJfrSupport.cpp | 1 - src/hotspot/share/gc/z/zTracer.cpp | 2 - src/hotspot/share/jfr/dcmd/jfrDcmds.cpp | 9 +- src/hotspot/share/jfr/dcmd/jfrDcmds.hpp | 1 + src/hotspot/share/jfr/jfr.cpp | 12 + src/hotspot/share/jfr/jfr.hpp | 3 + src/hotspot/share/jfr/jni/jfrJavaSupport.cpp | 168 ++++- src/hotspot/share/jfr/jni/jfrJavaSupport.hpp | 15 +- src/hotspot/share/jfr/jni/jfrJniMethod.cpp | 23 +- src/hotspot/share/jfr/jni/jfrJniMethod.hpp | 8 + .../jfr/jni/jfrJniMethodRegistration.cpp | 9 +- .../jfr/leakprofiler/chains/edgeStore.cpp | 1 + .../leakprofiler/checkpoint/eventEmitter.cpp | 4 +- .../checkpoint/objectSampleCheckpoint.cpp | 9 +- .../checkpoint/objectSampleWriter.cpp | 8 +- .../leakprofiler/checkpoint/rootResolver.cpp | 7 +- .../share/jfr/leakprofiler/leakProfiler.cpp | 2 + .../leakprofiler/sampling/objectSampler.cpp | 3 + .../share/jfr/metadata/jfrSerializer.hpp | 3 +- src/hotspot/share/jfr/metadata/metadata.xml | 113 ++- .../jfr/periodic/jfrNetworkUtilization.cpp | 74 +- .../share/jfr/periodic/jfrPeriodic.cpp | 15 +- .../jfr/periodic/jfrThreadCPULoadEvent.cpp | 15 +- .../periodic/sampling/jfrThreadSampler.cpp | 8 +- .../checkpoint/jfrCheckpointManager.cpp | 198 ++++-- .../checkpoint/jfrCheckpointManager.hpp | 28 +- .../checkpoint/jfrCheckpointWriter.cpp | 50 +- .../checkpoint/jfrCheckpointWriter.hpp | 9 +- .../recorder/checkpoint/jfrMetadataEvent.cpp | 66 +- .../recorder/checkpoint/jfrMetadataEvent.hpp | 5 +- .../checkpoint/types/jfrThreadGroup.cpp | 16 +- .../checkpoint/types/jfrThreadState.cpp | 50 +- .../checkpoint/types/jfrThreadState.hpp | 14 + .../jfr/recorder/checkpoint/types/jfrType.cpp | 69 +- .../jfr/recorder/checkpoint/types/jfrType.hpp | 24 +- .../checkpoint/types/jfrTypeManager.cpp | 202 +++--- .../checkpoint/types/jfrTypeManager.hpp | 10 +- .../recorder/checkpoint/types/jfrTypeSet.cpp | 11 +- .../recorder/checkpoint/types/jfrTypeSet.hpp | 2 +- .../checkpoint/types/traceid/jfrTraceId.cpp | 3 +- .../types/traceid/jfrTraceId.inline.hpp | 22 +- .../types/traceid/jfrTraceIdEpoch.cpp | 12 +- .../types/traceid/jfrTraceIdEpoch.hpp | 37 +- .../jfr/recorder/repository/jfrChunk.cpp | 226 ++++++ .../{jfrChunkState.hpp => jfrChunk.hpp} | 52 +- .../jfr/recorder/repository/jfrChunkState.cpp | 120 ---- .../recorder/repository/jfrChunkWriter.cpp | 295 ++++++-- .../recorder/repository/jfrChunkWriter.hpp | 29 +- .../recorder/repository/jfrEmergencyDump.cpp | 49 +- .../jfr/recorder/repository/jfrRepository.cpp | 60 +- .../jfr/recorder/repository/jfrRepository.hpp | 6 +- .../share/jfr/recorder/service/jfrPostBox.cpp | 12 +- .../share/jfr/recorder/service/jfrPostBox.hpp | 12 +- .../recorder/service/jfrRecorderService.cpp | 650 ++++++++++-------- .../recorder/service/jfrRecorderService.hpp | 5 +- .../recorder/service/jfrRecorderThread.cpp | 7 +- .../service/jfrRecorderThreadLoop.cpp | 4 + .../stacktrace/jfrStackTraceRepository.cpp | 36 +- .../stacktrace/jfrStackTraceRepository.hpp | 11 +- .../share/jfr/recorder/storage/jfrBuffer.cpp | 55 +- .../share/jfr/recorder/storage/jfrBuffer.hpp | 7 +- .../jfr/recorder/storage/jfrMemorySpace.hpp | 4 +- .../storage/jfrMemorySpace.inline.hpp | 1 + .../share/jfr/recorder/storage/jfrStorage.cpp | 78 ++- .../share/jfr/recorder/storage/jfrStorage.hpp | 3 +- .../recorder/storage/jfrStorageControl.cpp | 7 +- .../jfr/recorder/storage/jfrStorageUtils.hpp | 114 ++- .../storage/jfrStorageUtils.inline.hpp | 15 +- .../jfr/recorder/storage/jfrVirtualMemory.cpp | 1 - .../jfr/recorder/stringpool/jfrStringPool.cpp | 41 +- .../jfr/recorder/stringpool/jfrStringPool.hpp | 1 + .../share/jfr/support/jfrThreadLocal.cpp | 75 +- .../share/jfr/support/jfrThreadLocal.hpp | 10 +- .../share/jfr/support/jfrTraceIdExtension.hpp | 2 +- .../share/jfr/utilities/jfrAllocation.cpp | 3 +- .../jfr/utilities/jfrDoublyLinkedList.hpp | 6 +- .../share/jfr/utilities/jfrLogTagSets.hpp | 1 + .../share/jfr/utilities/jfrThreadIterator.cpp | 87 +++ .../share/jfr/utilities/jfrThreadIterator.hpp | 74 ++ src/hotspot/share/jfr/utilities/jfrTypes.hpp | 11 + .../share/jfr/writers/jfrJavaEventWriter.hpp | 4 +- .../share/jfr/writers/jfrStorageAdapter.hpp | 5 +- .../jfr/writers/jfrWriterHost.inline.hpp | 5 +- src/hotspot/share/logging/logTag.hpp | 1 + src/hotspot/share/runtime/mutexLocker.cpp | 2 +- .../share/classes/jdk/jfr/Recording.java | 32 +- .../classes/jdk/jfr/consumer/ChunkParser.java | 174 ----- .../classes/jdk/jfr/consumer/EventParser.java | 72 -- .../classes/jdk/jfr/consumer/EventStream.java | 364 ++++++++++ .../jdk/jfr/consumer/ObjectFactory.java | 85 --- .../jdk/jfr/consumer/RecordedClass.java | 20 +- .../jdk/jfr/consumer/RecordedClassLoader.java | 21 +- .../jdk/jfr/consumer/RecordedEvent.java | 53 +- .../jdk/jfr/consumer/RecordedFrame.java | 20 +- .../jdk/jfr/consumer/RecordedMethod.java | 20 +- .../jdk/jfr/consumer/RecordedObject.java | 138 +++- .../jdk/jfr/consumer/RecordedStackTrace.java | 20 +- .../jdk/jfr/consumer/RecordedThread.java | 22 +- .../jdk/jfr/consumer/RecordedThreadGroup.java | 22 +- .../jdk/jfr/consumer/RecordingFile.java | 65 +- .../jdk/jfr/consumer/RecordingStream.java | 362 ++++++++++ .../jdk/jfr/events/ActiveRecordingEvent.java | 13 +- .../jdk/jfr/events/ActiveSettingEvent.java | 9 +- .../jdk/jfr/internal/EventControl.java | 76 +- .../jfr/internal/EventInstrumentation.java | 131 ++-- .../classes/jdk/jfr/internal/EventWriter.java | 18 +- .../classes/jdk/jfr/internal/FilePurger.java | 73 ++ .../share/classes/jdk/jfr/internal/JVM.java | 39 +- .../classes/jdk/jfr/internal/LogTag.java | 14 +- .../classes/jdk/jfr/internal/LongMap.java | 257 +++++++ .../jdk/jfr/internal/MetadataDescriptor.java | 7 +- .../jdk/jfr/internal/MetadataReader.java | 9 +- .../jdk/jfr/internal/MetadataRepository.java | 22 +- .../jdk/jfr/internal/MetadataWriter.java | 8 +- .../jdk/jfr/internal/PlatformEventType.java | 4 +- .../jdk/jfr/internal/PlatformRecorder.java | 50 +- .../jdk/jfr/internal/PlatformRecording.java | 34 +- .../classes/jdk/jfr/internal/Repository.java | 17 +- .../jdk/jfr/internal/RepositoryChunk.java | 14 +- .../jdk/jfr/internal/RequestEngine.java | 42 +- .../jdk/jfr/internal/SecuritySupport.java | 58 +- .../jdk/jfr/internal/SettingsManager.java | 23 +- .../classes/jdk/jfr/internal/TypeLibrary.java | 1 + .../share/classes/jdk/jfr/internal/Utils.java | 40 +- .../consumer/AbstractEventStream.java | 273 ++++++++ .../jfr/internal/consumer/ChunkHeader.java | 163 ++++- .../jfr/internal/consumer/ChunkParser.java | 451 ++++++++++++ .../jfr/internal/consumer/ConstantLookup.java | 62 ++ .../{ => internal}/consumer/ConstantMap.java | 99 ++- .../jdk/jfr/internal/consumer/Dispatcher.java | 188 +++++ .../consumer/EventDirectoryStream.java | 209 ++++++ .../internal/consumer/EventFileStream.java | 147 ++++ .../jfr/internal/consumer/EventParser.java | 198 ++++++ .../jdk/jfr/internal/consumer/FileAccess.java | 73 ++ .../jfr/internal/consumer/JdkJfrConsumer.java | 101 +++ .../jfr/internal/consumer/ObjectContext.java | 77 +++ .../jfr/internal/consumer/ObjectFactory.java | 153 +++++ .../jfr/{ => internal}/consumer/Parser.java | 17 +- .../consumer/ParserFactory.java | 203 ++++-- .../jfr/internal/consumer/ParserFilter.java | 80 +++ .../jfr/internal/consumer/RecordingInput.java | 231 +++++-- .../internal/consumer/RepositoryFiles.java | 230 +++++++ .../consumer/StreamConfiguration.java | 124 ++++ .../jfr/internal/consumer/StringParser.java | 222 ++++++ .../consumer/TimeConverter.java | 22 +- .../jdk/jfr/internal/dcmd/DCmdConfigure.java | 7 +- .../jdk/jfr/internal/dcmd/DCmdStart.java | 17 +- .../jdk/jfr/internal/tool/Disassemble.java | 5 +- .../jfr/internal/tool/EventPrintWriter.java | 10 +- .../jdk/jfr/internal/tool/Metadata.java | 7 +- .../jdk/jfr/internal/tool/Summary.java | 5 +- src/jdk.jfr/share/conf/jfr/default.jfc | 32 +- src/jdk.jfr/share/conf/jfr/profile.jfc | 32 +- .../gtest/jfr/test_networkUtilization.cpp | 170 +++-- test/hotspot/gtest/jfr/test_threadCpuLoad.cpp | 22 +- test/jdk/ProblemList.txt | 2 +- .../jdk/jfr/api/consumer/TestReadTwice.java | 3 +- .../jfr/api/consumer/TestRecordingFile.java | 8 +- .../api/consumer/TestRecordingInternals.java | 3 +- .../filestream/TestMultipleChunk.java | 86 +++ .../api/consumer/filestream/TestOrdered.java | 152 ++++ .../api/consumer/filestream/TestReuse.java | 128 ++++ .../recordingstream/EventProducer.java | 58 ++ .../recordingstream/TestAwaitTermination.java | 78 +++ .../consumer/recordingstream/TestClose.java | 128 ++++ .../recordingstream/TestConstructor.java | 69 ++ .../consumer/recordingstream/TestDisable.java | 92 +++ .../consumer/recordingstream/TestEnable.java | 79 +++ .../consumer/recordingstream/TestMaxAge.java | 61 ++ .../consumer/recordingstream/TestOnClose.java | 95 +++ .../recordingstream/TestOnErrorAsync.java | 206 ++++++ .../recordingstream/TestOnErrorSync.java | 241 +++++++ .../consumer/recordingstream/TestOnEvent.java | 155 +++++ .../consumer/recordingstream/TestOnFlush.java | 99 +++ .../recordingstream/TestRecursive.java | 197 ++++++ .../consumer/recordingstream/TestRemove.java | 149 ++++ .../recordingstream/TestSetEndTime.java | 175 +++++ .../recordingstream/TestSetFlushInterval.java | 62 ++ .../recordingstream/TestSetMaxAge.java | 60 ++ .../recordingstream/TestSetMaxSize.java | 58 ++ .../recordingstream/TestSetSettings.java | 68 ++ .../recordingstream/TestSetStartTime.java | 138 ++++ .../consumer/recordingstream/TestStart.java | 151 ++++ .../recordingstream/TestStartAsync.java | 86 +++ .../consumer/recordingstream/TestUtils.java | 65 ++ .../security/DriverRecordingDumper.java | 40 +- .../security/TestMissingPermission.java | 70 ++ .../consumer/security/TestRecordingFile.java | 55 ++ .../security/TestRecordingStream.java | 60 ++ .../consumer/security/TestStreamingFile.java | 55 ++ .../consumer/security/TestStreamingLocal.java | 70 ++ .../security/TestStreamingRemote.java | 117 ++++ .../consumer/security/local-streaming.policy | 4 + .../consumer/security/no-permission.policy | 3 + .../api/consumer/streaming/TestChunkGap.java | 111 +++ .../consumer/streaming/TestEmptyChunks.java | 84 +++ .../consumer/streaming/TestEnableEvents.java | 99 +++ .../streaming/TestEventRegistration.java | 81 +++ .../consumer/streaming/TestFilledChunks.java | 82 +++ .../api/consumer/streaming/TestFiltering.java | 81 +++ .../consumer/streaming/TestLatestEvent.java | 135 ++++ .../streaming/TestRecordingBefore.java | 98 +++ .../consumer/streaming/TestRemovedChunks.java | 126 ++++ .../streaming/TestRepositoryMigration.java | 108 +++ .../streaming/TestRepositoryProperty.java | 110 +++ .../streaming/TestStartMultiChunk.java | 122 ++++ .../streaming/TestStartSingleChunk.java | 91 +++ .../api/consumer/streaming/TestUnstarted.java | 49 +- .../jdk/jfr/api/event/TestEventDuration.java | 67 ++ .../recording/time/TestSetFlushInterval.java | 86 +++ .../metadata/TestLookForUntestedEvents.java | 13 +- .../jfr/event/oldobject/TestLargeRootSet.java | 107 ++- test/jdk/jdk/jfr/event/runtime/TestFlush.java | 166 +++++ .../jfr/jcmd/TestJcmdStartFlushInterval.java | 56 ++ test/jdk/jdk/jfr/jvm/TestThreadExclusion.java | 151 ++++ test/jdk/jdk/jfr/jvm/TestUnsupportedVM.java | 48 +- .../jfr/startupargs/TestFlushInterval.java | 55 ++ test/lib/jdk/test/lib/jfr/EventNames.java | 6 + 219 files changed, 12935 insertions(+), 2234 deletions(-) create mode 100644 src/hotspot/share/jfr/recorder/repository/jfrChunk.cpp rename src/hotspot/share/jfr/recorder/repository/{jfrChunkState.hpp => jfrChunk.hpp} (64%) delete mode 100644 src/hotspot/share/jfr/recorder/repository/jfrChunkState.cpp create mode 100644 src/hotspot/share/jfr/utilities/jfrThreadIterator.cpp create mode 100644 src/hotspot/share/jfr/utilities/jfrThreadIterator.hpp delete mode 100644 src/jdk.jfr/share/classes/jdk/jfr/consumer/ChunkParser.java delete mode 100644 src/jdk.jfr/share/classes/jdk/jfr/consumer/EventParser.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/consumer/EventStream.java delete mode 100644 src/jdk.jfr/share/classes/jdk/jfr/consumer/ObjectFactory.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/FilePurger.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/LongMap.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/AbstractEventStream.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ConstantLookup.java rename src/jdk.jfr/share/classes/jdk/jfr/{ => internal}/consumer/ConstantMap.java (57%) create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/Dispatcher.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventDirectoryStream.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventFileStream.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/FileAccess.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/JdkJfrConsumer.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ObjectContext.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ObjectFactory.java rename src/jdk.jfr/share/classes/jdk/jfr/{ => internal}/consumer/Parser.java (75%) rename src/jdk.jfr/share/classes/jdk/jfr/{ => internal}/consumer/ParserFactory.java (61%) create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFilter.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RepositoryFiles.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/StreamConfiguration.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/StringParser.java rename src/jdk.jfr/share/classes/jdk/jfr/{ => internal}/consumer/TimeConverter.java (96%) create mode 100644 test/jdk/jdk/jfr/api/consumer/filestream/TestMultipleChunk.java create mode 100644 test/jdk/jdk/jfr/api/consumer/filestream/TestOrdered.java create mode 100644 test/jdk/jdk/jfr/api/consumer/filestream/TestReuse.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/EventProducer.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestAwaitTermination.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestClose.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestConstructor.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestDisable.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestEnable.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestMaxAge.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestOnClose.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestOnErrorAsync.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestOnErrorSync.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestOnEvent.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestOnFlush.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestRecursive.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestRemove.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestSetEndTime.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestSetFlushInterval.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestSetMaxAge.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestSetMaxSize.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestSetSettings.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestSetStartTime.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestStart.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestStartAsync.java create mode 100644 test/jdk/jdk/jfr/api/consumer/recordingstream/TestUtils.java rename src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/RecordingInternals.java => test/jdk/jdk/jfr/api/consumer/security/DriverRecordingDumper.java (62%) create mode 100644 test/jdk/jdk/jfr/api/consumer/security/TestMissingPermission.java create mode 100644 test/jdk/jdk/jfr/api/consumer/security/TestRecordingFile.java create mode 100644 test/jdk/jdk/jfr/api/consumer/security/TestRecordingStream.java create mode 100644 test/jdk/jdk/jfr/api/consumer/security/TestStreamingFile.java create mode 100644 test/jdk/jdk/jfr/api/consumer/security/TestStreamingLocal.java create mode 100644 test/jdk/jdk/jfr/api/consumer/security/TestStreamingRemote.java create mode 100644 test/jdk/jdk/jfr/api/consumer/security/local-streaming.policy create mode 100644 test/jdk/jdk/jfr/api/consumer/security/no-permission.policy create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestChunkGap.java create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestEmptyChunks.java create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestEnableEvents.java create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestEventRegistration.java create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestFilledChunks.java create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestFiltering.java create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestLatestEvent.java create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestRecordingBefore.java create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestRemovedChunks.java create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestRepositoryMigration.java create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestRepositoryProperty.java create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestStartMultiChunk.java create mode 100644 test/jdk/jdk/jfr/api/consumer/streaming/TestStartSingleChunk.java rename src/jdk.jfr/share/classes/jdk/jfr/consumer/LongMap.java => test/jdk/jdk/jfr/api/consumer/streaming/TestUnstarted.java (59%) create mode 100644 test/jdk/jdk/jfr/api/event/TestEventDuration.java create mode 100644 test/jdk/jdk/jfr/api/recording/time/TestSetFlushInterval.java create mode 100644 test/jdk/jdk/jfr/event/runtime/TestFlush.java create mode 100644 test/jdk/jdk/jfr/jcmd/TestJcmdStartFlushInterval.java create mode 100644 test/jdk/jdk/jfr/jvm/TestThreadExclusion.java create mode 100644 test/jdk/jdk/jfr/startupargs/TestFlushInterval.java diff --git a/src/hotspot/share/gc/g1/g1Trace.cpp b/src/hotspot/share/gc/g1/g1Trace.cpp index 59039e081d5..3555cd45183 100644 --- a/src/hotspot/share/gc/g1/g1Trace.cpp +++ b/src/hotspot/share/gc/g1/g1Trace.cpp @@ -59,10 +59,10 @@ public: }; static void register_jfr_type_constants() { - JfrSerializer::register_serializer(TYPE_G1HEAPREGIONTYPE, false, true, + JfrSerializer::register_serializer(TYPE_G1HEAPREGIONTYPE, true, new G1HeapRegionTypeConstant()); - JfrSerializer::register_serializer(TYPE_G1YCTYPE, false, true, + JfrSerializer::register_serializer(TYPE_G1YCTYPE, true, new G1YCTypeConstant()); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.cpp b/src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.cpp index 2f3bac76643..526068df7d3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahJfrSupport.cpp @@ -47,7 +47,6 @@ public: void ShenandoahJFRSupport::register_jfr_type_serializers() { JfrSerializer::register_serializer(TYPE_SHENANDOAHHEAPREGIONSTATE, - false, true, new ShenandoahHeapRegionStateConstant()); } diff --git a/src/hotspot/share/gc/z/zTracer.cpp b/src/hotspot/share/gc/z/zTracer.cpp index 82747f3878a..7c7adac14b9 100644 --- a/src/hotspot/share/gc/z/zTracer.cpp +++ b/src/hotspot/share/gc/z/zTracer.cpp @@ -59,11 +59,9 @@ public: static void register_jfr_type_serializers() { JfrSerializer::register_serializer(TYPE_ZSTATISTICSCOUNTERTYPE, - false /* require_safepoint */, true /* permit_cache */, new ZStatisticsCounterTypeConstant()); JfrSerializer::register_serializer(TYPE_ZSTATISTICSSAMPLERTYPE, - false /* require_safepoint */, true /* permit_cache */, new ZStatisticsSamplerTypeConstant()); } diff --git a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp index 0966dfee64c..905467dd05d 100644 --- a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp +++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp @@ -349,6 +349,7 @@ JfrStartFlightRecordingDCmd::JfrStartFlightRecordingDCmd(outputStream* output, _filename("filename", "Resulting recording filename, e.g. \\\"" JFR_FILENAME_EXAMPLE "\\\"", "STRING", false), _maxage("maxage", "Maximum time to keep recorded data (on disk) in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 60m, or 0 for no limit", "NANOTIME", false, "0"), _maxsize("maxsize", "Maximum amount of bytes to keep (on disk) in (k)B, (M)B or (G)B, e.g. 500M, or 0 for no limit", "MEMORY SIZE", false, "0"), + _flush_interval("flush-interval", "Minimum time before flushing buffers, measured in (s)econds, e.g. 4 s, or 0 for flushing when a recording ends", "NANOTIME", false, "1s"), _dump_on_exit("dumponexit", "Dump running recording when JVM shuts down", "BOOLEAN", false), _path_to_gc_roots("path-to-gc-roots", "Collect path to GC roots", "BOOLEAN", false, "false") { _dcmdparser.add_dcmd_option(&_name); @@ -359,6 +360,7 @@ JfrStartFlightRecordingDCmd::JfrStartFlightRecordingDCmd(outputStream* output, _dcmdparser.add_dcmd_option(&_filename); _dcmdparser.add_dcmd_option(&_maxage); _dcmdparser.add_dcmd_option(&_maxsize); + _dcmdparser.add_dcmd_option(&_flush_interval); _dcmdparser.add_dcmd_option(&_dump_on_exit); _dcmdparser.add_dcmd_option(&_path_to_gc_roots); }; @@ -411,6 +413,10 @@ void JfrStartFlightRecordingDCmd::execute(DCmdSource source, TRAPS) { maxsize = JfrJavaSupport::new_java_lang_Long(_maxsize.value()._size, CHECK); } + jobject flush_interval = NULL; + if (_flush_interval.is_set()) { + flush_interval = JfrJavaSupport::new_java_lang_Long(_flush_interval.value()._nanotime, CHECK); + } jobject duration = NULL; if (_duration.is_set()) { duration = JfrJavaSupport::new_java_lang_Long(_duration.value()._nanotime, CHECK); @@ -464,7 +470,7 @@ void JfrStartFlightRecordingDCmd::execute(DCmdSource source, TRAPS) { static const char method[] = "execute"; static const char signature[] = "(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/Long;" "Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/String;" - "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/lang/String;"; + "Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Boolean;Ljava/lang/Boolean;)Ljava/lang/String;"; JfrJavaArguments execute_args(&result, klass, method, signature, CHECK); execute_args.set_receiver(h_dcmd_instance); @@ -478,6 +484,7 @@ void JfrStartFlightRecordingDCmd::execute(DCmdSource source, TRAPS) { execute_args.push_jobject(filename); execute_args.push_jobject(maxage); execute_args.push_jobject(maxsize); + execute_args.push_jobject(flush_interval); execute_args.push_jobject(dump_on_exit); execute_args.push_jobject(path_to_gc_roots); diff --git a/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp b/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp index 9281638f466..09a3552d76e 100644 --- a/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp +++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.hpp @@ -90,6 +90,7 @@ class JfrStartFlightRecordingDCmd : public DCmdWithParser { DCmdArgument _filename; DCmdArgument _maxage; DCmdArgument _maxsize; + DCmdArgument _flush_interval; DCmdArgument _dump_on_exit; DCmdArgument _path_to_gc_roots; diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index 67102256633..8a38640973a 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -71,6 +71,18 @@ void Jfr::on_thread_exit(Thread* t) { JfrThreadLocal::on_exit(t); } +void Jfr::exclude_thread(Thread* t) { + JfrThreadLocal::exclude(t); +} + +void Jfr::include_thread(Thread* t) { + JfrThreadLocal::include(t); +} + +bool Jfr::is_excluded(Thread* t) { + return t != NULL && t->jfr_thread_local()->is_excluded(); +} + void Jfr::on_java_thread_dismantle(JavaThread* jt) { if (JfrRecorder::is_recording()) { JfrCheckpointManager::write_thread_checkpoint(jt); diff --git a/src/hotspot/share/jfr/jfr.hpp b/src/hotspot/share/jfr/jfr.hpp index 20664746f19..dcba410898e 100644 --- a/src/hotspot/share/jfr/jfr.hpp +++ b/src/hotspot/share/jfr/jfr.hpp @@ -53,6 +53,9 @@ class Jfr : AllStatic { static bool on_flight_recorder_option(const JavaVMOption** option, char* delimiter); static bool on_start_flight_recording_option(const JavaVMOption** option, char* delimiter); static void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f); + static void exclude_thread(Thread* thread); + static bool is_excluded(Thread* thread); + static void include_thread(Thread* thread); }; #endif // SHARE_JFR_JFR_HPP diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp index 6bb99ee56f7..fdfff89bbab 100644 --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp @@ -23,7 +23,6 @@ */ #include "precompiled.hpp" -#include "jni.h" #include "classfile/javaClasses.inline.hpp" #include "classfile/modules.hpp" #include "classfile/symbolTable.hpp" @@ -42,9 +41,11 @@ #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/java.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/semaphore.inline.hpp" #include "runtime/synchronizer.hpp" #include "runtime/thread.inline.hpp" #include "runtime/threadSMR.hpp" +#include "utilities/growableArray.hpp" #ifdef ASSERT void JfrJavaSupport::check_java_thread_in_vm(Thread* t) { @@ -58,6 +59,12 @@ void JfrJavaSupport::check_java_thread_in_native(Thread* t) { assert(t->is_Java_thread(), "invariant"); assert(((JavaThread*)t)->thread_state() == _thread_in_native, "invariant"); } + +static void check_new_unstarted_java_thread(Thread* t) { + assert(t != NULL, "invariant"); + assert(t->is_Java_thread(), "invariant"); + assert(((JavaThread*)t)->thread_state() == _thread_new, "invariant"); +} #endif /* @@ -93,6 +100,21 @@ void JfrJavaSupport::destroy_global_jni_handle(jobject handle) { JNIHandles::destroy_global(handle); } +jweak JfrJavaSupport::global_weak_jni_handle(const oop obj, Thread* t) { + DEBUG_ONLY(check_java_thread_in_vm(t)); + HandleMark hm(t); + return JNIHandles::make_weak_global(Handle(t, obj)); +} + +jweak JfrJavaSupport::global_weak_jni_handle(const jobject handle, Thread* t) { + const oop obj = JNIHandles::resolve(handle); + return obj == NULL ? NULL : global_weak_jni_handle(obj, t); +} + +void JfrJavaSupport::destroy_global_weak_jni_handle(jweak handle) { + JNIHandles::destroy_weak_global(handle); +} + oop JfrJavaSupport::resolve_non_null(jobject obj) { return JNIHandles::resolve_non_null(obj); } @@ -603,9 +625,149 @@ bool JfrJavaSupport::is_jdk_jfr_module_available(outputStream* stream, TRAPS) { return true; } -jlong JfrJavaSupport::jfr_thread_id(jobject target_thread) { +class ThreadExclusionListAccess : public StackObj { + private: + static Semaphore _mutex_semaphore; + public: + ThreadExclusionListAccess() { _mutex_semaphore.wait(); } + ~ThreadExclusionListAccess() { _mutex_semaphore.signal(); } +}; + +Semaphore ThreadExclusionListAccess::_mutex_semaphore(1); +static GrowableArray* exclusion_list = NULL; + +static bool equals(const jweak excluded_thread, Handle target_thread) { + return JfrJavaSupport::resolve_non_null(excluded_thread) == target_thread(); +} + +static int find_exclusion_thread_idx(Handle thread) { + if (exclusion_list != NULL) { + for (int i = 0; i < exclusion_list->length(); ++i) { + if (equals(exclusion_list->at(i), thread)) { + return i; + } + } + } + return -1; +} + +static Handle as_handle(jobject thread) { + return Handle(Thread::current(), JfrJavaSupport::resolve_non_null(thread)); +} + +static bool thread_is_not_excluded(Handle thread) { + return -1 == find_exclusion_thread_idx(thread); +} + +static bool thread_is_not_excluded(jobject thread) { + return thread_is_not_excluded(as_handle(thread)); +} + +static bool is_thread_excluded(jobject thread) { + return !thread_is_not_excluded(thread); +} + +#ifdef ASSERT +static bool is_thread_excluded(Handle thread) { + return !thread_is_not_excluded(thread); +} +#endif // ASSERT + +static int add_thread_to_exclusion_list(jobject thread) { + ThreadExclusionListAccess lock; + if (exclusion_list == NULL) { + exclusion_list = new (ResourceObj::C_HEAP, mtTracing) GrowableArray(10, true, mtTracing); + } + assert(exclusion_list != NULL, "invariant"); + assert(thread_is_not_excluded(thread), "invariant"); + jweak ref = JfrJavaSupport::global_weak_jni_handle(thread, Thread::current()); + const int idx = exclusion_list->append(ref); + assert(is_thread_excluded(thread), "invariant"); + return idx; +} + +static void remove_thread_from_exclusion_list(Handle thread) { + assert(exclusion_list != NULL, "invariant"); + assert(is_thread_excluded(thread), "invariant"); + assert(exclusion_list != NULL, "invariant"); + const int idx = find_exclusion_thread_idx(thread); + assert(idx >= 0, "invariant"); + assert(idx < exclusion_list->length(), "invariant"); + JfrJavaSupport::destroy_global_weak_jni_handle(exclusion_list->at(idx)); + exclusion_list->delete_at(idx); + assert(thread_is_not_excluded(thread), "invariant"); + if (0 == exclusion_list->length()) { + delete exclusion_list; + exclusion_list = NULL; + } +} + +static void remove_thread_from_exclusion_list(jobject thread) { + ThreadExclusionListAccess lock; + remove_thread_from_exclusion_list(as_handle(thread)); +} + +// includes removal +static bool check_exclusion_state_on_thread_start(JavaThread* jt) { + Handle h_obj(jt, jt->threadObj()); + ThreadExclusionListAccess lock; + if (thread_is_not_excluded(h_obj)) { + return false; + } + remove_thread_from_exclusion_list(h_obj); + return true; +} + +jlong JfrJavaSupport::jfr_thread_id(jobject thread) { ThreadsListHandle tlh; JavaThread* native_thread = NULL; - (void)tlh.cv_internal_thread_to_JavaThread(target_thread, &native_thread, NULL); + (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL); return native_thread != NULL ? JFR_THREAD_ID(native_thread) : 0; } + +void JfrJavaSupport::exclude(jobject thread) { + HandleMark hm; + ThreadsListHandle tlh; + JavaThread* native_thread = NULL; + (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL); + if (native_thread != NULL) { + JfrThreadLocal::exclude(native_thread); + } else { + // not started yet, track the thread oop + add_thread_to_exclusion_list(thread); + } +} + +void JfrJavaSupport::include(jobject thread) { + HandleMark hm; + ThreadsListHandle tlh; + JavaThread* native_thread = NULL; + (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL); + if (native_thread != NULL) { + JfrThreadLocal::include(native_thread); + } else { + // not started yet, untrack the thread oop + remove_thread_from_exclusion_list(thread); + } +} + +bool JfrJavaSupport::is_excluded(jobject thread) { + HandleMark hm; + ThreadsListHandle tlh; + JavaThread* native_thread = NULL; + (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL); + return native_thread != NULL ? native_thread->jfr_thread_local()->is_excluded() : is_thread_excluded(thread); +} + +void JfrJavaSupport::on_thread_start(Thread* t) { + assert(t != NULL, "invariant"); + assert(Thread::current() == t, "invariant"); + if (!t->is_Java_thread()) { + return; + } + DEBUG_ONLY(check_new_unstarted_java_thread(t);) + HandleMark hm; + if (check_exclusion_state_on_thread_start((JavaThread*)t)) { + JfrThreadLocal::exclude(t); + } +} diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp index 04545555678..762e2184bfe 100644 --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.hpp @@ -29,18 +29,21 @@ #include "utilities/exceptions.hpp" class Klass; -class JavaThread; class outputStream; class JfrJavaSupport : public AllStatic { public: static jobject local_jni_handle(const oop obj, Thread* t); static jobject local_jni_handle(const jobject handle, Thread* t); - static void destroy_local_jni_handle(const jobject handle); + static void destroy_local_jni_handle(jobject handle); static jobject global_jni_handle(const oop obj, Thread* t); static jobject global_jni_handle(const jobject handle, Thread* t); - static void destroy_global_jni_handle(const jobject handle); + static void destroy_global_jni_handle(jobject handle); + + static jweak global_weak_jni_handle(const oop obj, Thread* t); + static jweak global_weak_jni_handle(const jobject handle, Thread* t); + static void destroy_global_weak_jni_handle(jweak handle); static oop resolve_non_null(jobject obj); static void notify_all(jobject obj, TRAPS); @@ -85,7 +88,11 @@ class JfrJavaSupport : public AllStatic { static bool is_jdk_jfr_module_available(); static bool is_jdk_jfr_module_available(outputStream* stream, TRAPS); - static jlong jfr_thread_id(jobject target_thread); + static jlong jfr_thread_id(jobject thread); + static void exclude(jobject thread); + static void include(jobject thread); + static bool is_excluded(jobject thread); + static void on_thread_start(Thread* t); // critical static void abort(jstring errorMsg, TRAPS); diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index a5d9a5ed750..b147a3d634a 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -284,6 +284,10 @@ JVM_ENTRY_NO_ENV(jboolean, jfr_event_writer_flush(JNIEnv* env, jclass cls, jobje return JfrJavaEventWriter::flush(writer, used_size, requested_size, thread); JVM_END +JVM_ENTRY_NO_ENV(void, jfr_flush(JNIEnv* env, jobject jvm)) + JfrRepository::flush(thread); +JVM_END + JVM_ENTRY_NO_ENV(void, jfr_set_repository_location(JNIEnv* env, jobject repo, jstring location)) return JfrRepository::set_path(location, thread); JVM_END @@ -311,3 +315,20 @@ JVM_END JVM_ENTRY_NO_ENV(void, jfr_emit_old_object_samples(JNIEnv* env, jobject jvm, jlong cutoff_ticks, jboolean emit_all)) LeakProfiler::emit_events(cutoff_ticks, emit_all == JNI_TRUE); JVM_END + +JVM_ENTRY_NO_ENV(void, jfr_exclude_thread(JNIEnv* env, jobject jvm, jobject t)) + JfrJavaSupport::exclude(t); +JVM_END + +JVM_ENTRY_NO_ENV(void, jfr_include_thread(JNIEnv* env, jobject jvm, jobject t)) + JfrJavaSupport::include(t); +JVM_END + +JVM_ENTRY_NO_ENV(jboolean, jfr_is_thread_excluded(JNIEnv* env, jobject jvm, jobject t)) + return JfrJavaSupport::is_excluded(t); +JVM_END + +JVM_ENTRY_NO_ENV(jlong, jfr_chunk_start_nanos(JNIEnv* env, jobject jvm)) + return JfrRepository::current_chunk_start_nanos(); +JVM_END + diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp index 522ac2bd902..85427e46d82 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp @@ -113,6 +113,7 @@ jobject JNICALL jfr_new_event_writer(JNIEnv* env, jclass cls); jboolean JNICALL jfr_event_writer_flush(JNIEnv* env, jclass cls, jobject writer, jint used_size, jint requested_size); +void JNICALL jfr_flush(JNIEnv* env, jobject jvm); void JNICALL jfr_abort(JNIEnv* env, jobject jvm, jstring errorMsg); jlong JNICALL jfr_get_epoch_address(JNIEnv* env, jobject jvm); @@ -131,6 +132,13 @@ void JNICALL jfr_emit_old_object_samples(JNIEnv* env, jobject jvm, jlong cutoff_ jboolean JNICALL jfr_should_rotate_disk(JNIEnv* env, jobject jvm); +void JNICALL jfr_exclude_thread(JNIEnv* env, jobject jvm, jobject t); + +void JNICALL jfr_include_thread(JNIEnv* env, jobject jvm, jobject t); + +jboolean JNICALL jfr_is_thread_excluded(JNIEnv* env, jobject jvm, jobject t); + +jlong JNICALL jfr_chunk_start_nanos(JNIEnv* env, jobject jvm); #ifdef __cplusplus } diff --git a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp index 174126034ee..4a0235a782d 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethodRegistration.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -70,6 +70,7 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) { (char*)"getEventWriter", (char*)"()Ljava/lang/Object;", (void*)jfr_get_event_writer, (char*)"newEventWriter", (char*)"()Ljdk/jfr/internal/EventWriter;", (void*)jfr_new_event_writer, (char*)"flush", (char*)"(Ljdk/jfr/internal/EventWriter;II)Z", (void*)jfr_event_writer_flush, + (char*)"flush", (char*)"()V", (void*)jfr_flush, (char*)"setRepositoryLocation", (char*)"(Ljava/lang/String;)V", (void*)jfr_set_repository_location, (char*)"abort", (char*)"(Ljava/lang/String;)V", (void*)jfr_abort, (char*)"getEpochAddress", (char*)"()J",(void*)jfr_get_epoch_address, @@ -79,7 +80,11 @@ JfrJniMethodRegistration::JfrJniMethodRegistration(JNIEnv* env) { (char*)"getUnloadedEventClassCount", (char*)"()J", (void*)jfr_get_unloaded_event_classes_count, (char*)"setCutoff", (char*)"(JJ)Z", (void*)jfr_set_cutoff, (char*)"emitOldObjectSamples", (char*)"(JZ)V", (void*)jfr_emit_old_object_samples, - (char*)"shouldRotateDisk", (char*)"()Z", (void*)jfr_should_rotate_disk + (char*)"shouldRotateDisk", (char*)"()Z", (void*)jfr_should_rotate_disk, + (char*)"exclude", (char*)"(Ljava/lang/Thread;)V", (void*)jfr_exclude_thread, + (char*)"include", (char*)"(Ljava/lang/Thread;)V", (void*)jfr_include_thread, + (char*)"isExcluded", (char*)"(Ljava/lang/Thread;)Z", (void*)jfr_is_thread_excluded, + (char*)"getChunkStartNanos", (char*)"()J", (void*)jfr_chunk_start_nanos }; const size_t method_array_length = sizeof(method) / sizeof(JNINativeMethod); diff --git a/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp b/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp index d2a400e647e..929ec57b2b8 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp @@ -259,6 +259,7 @@ void EdgeStore::put_chain(const Edge* chain, size_t length) { assert(leak_context_edge->parent() == NULL, "invariant"); if (1 == length) { + store_gc_root_id_in_leak_context_edge(leak_context_edge, leak_context_edge); return; } diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.cpp index 47e6f69092b..079eeabe703 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/eventEmitter.cpp @@ -34,6 +34,7 @@ #include "memory/resourceArea.hpp" #include "oops/markWord.hpp" #include "oops/oop.inline.hpp" +#include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" #include "runtime/vmThread.hpp" @@ -51,8 +52,8 @@ EventEmitter::~EventEmitter() { } void EventEmitter::emit(ObjectSampler* sampler, int64_t cutoff_ticks, bool emit_all) { + assert(JfrStream_lock->owned_by_self(), "invariant"); assert(sampler != NULL, "invariant"); - ResourceMark rm; EdgeStore edge_store; if (cutoff_ticks <= 0) { @@ -68,6 +69,7 @@ void EventEmitter::emit(ObjectSampler* sampler, int64_t cutoff_ticks, bool emit_ } size_t EventEmitter::write_events(ObjectSampler* object_sampler, EdgeStore* edge_store, bool emit_all) { + assert_locked_or_safepoint(JfrStream_lock); assert(_thread == Thread::current(), "invariant"); assert(_thread->jfr_thread_local() == _jfr_thread_local, "invariant"); assert(object_sampler != NULL, "invariant"); diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp index c687480606b..fa88ec2b470 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp @@ -37,6 +37,7 @@ #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" #include "jfr/utilities/jfrHashtable.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" #include "runtime/thread.hpp" #include "utilities/growableArray.hpp" @@ -271,7 +272,7 @@ void StackTraceBlobInstaller::install(ObjectSample* sample) { } const JfrStackTrace* const stack_trace = resolve(sample); DEBUG_ONLY(validate_stack_trace(sample, stack_trace)); - JfrCheckpointWriter writer(false, true, Thread::current()); + JfrCheckpointWriter writer; writer.write_type(TYPE_STACKTRACE); writer.write_count(1); ObjectSampleCheckpoint::write_stacktrace(stack_trace, writer); @@ -291,6 +292,7 @@ static void install_stack_traces(const ObjectSampler* sampler, JfrStackTraceRepo // caller needs ResourceMark void ObjectSampleCheckpoint::on_rotation(const ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repo) { + assert(JfrStream_lock->owned_by_self(), "invariant"); assert(sampler != NULL, "invariant"); assert(LeakProfiler::is_running(), "invariant"); install_stack_traces(sampler, stack_trace_repo); @@ -388,7 +390,7 @@ class BlobWriter { static void write_sample_blobs(const ObjectSampler* sampler, bool emit_all, Thread* thread) { // sample set is predicated on time of last sweep const jlong last_sweep = emit_all ? max_jlong : sampler->last_sweep().value(); - JfrCheckpointWriter writer(false, false, thread); + JfrCheckpointWriter writer(thread, false); BlobWriter cbw(sampler, writer, last_sweep); iterate_samples(cbw, true); // reset blob write states @@ -397,13 +399,14 @@ static void write_sample_blobs(const ObjectSampler* sampler, bool emit_all, Thre } void ObjectSampleCheckpoint::write(const ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread) { + assert_locked_or_safepoint(JfrStream_lock); assert(sampler != NULL, "invariant"); assert(edge_store != NULL, "invariant"); assert(thread != NULL, "invariant"); write_sample_blobs(sampler, emit_all, thread); // write reference chains if (!edge_store->is_empty()) { - JfrCheckpointWriter writer(false, true, thread); + JfrCheckpointWriter writer(thread); ObjectSampleWriter osw(writer, edge_store); edge_store->iterate(osw); } diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp index 18be19fbbb1..1d10f4e58fe 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp @@ -355,10 +355,6 @@ int __write_root_description_info__(JfrCheckpointWriter* writer, const void* di) static traceid get_gc_root_description_info_id(const Edge& edge, traceid id) { assert(edge.is_root(), "invariant"); - if (EdgeUtils::is_leak_edge(edge)) { - return 0; - } - if (root_infos == NULL) { root_infos = new RootDescriptionInfo(); } @@ -606,8 +602,8 @@ class RootType : public JfrSerializer { static void register_serializers() { static bool is_registered = false; if (!is_registered) { - JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, false, true, new RootSystemType()); - JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, false, true, new RootType()); + JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, true, new RootSystemType()); + JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, true, new RootType()); is_registered = true; } } diff --git a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp index 19f6a86631b..79656e3b394 100644 --- a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp +++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp @@ -29,6 +29,7 @@ #include "gc/shared/strongRootsScope.hpp" #include "jfr/leakprofiler/utilities/unifiedOop.hpp" #include "jfr/leakprofiler/checkpoint/rootResolver.hpp" +#include "jfr/utilities/jfrThreadIterator.hpp" #include "memory/iterator.hpp" #include "memory/universe.hpp" #include "oops/klass.hpp" @@ -36,7 +37,6 @@ #include "prims/jvmtiThreadState.hpp" #include "runtime/frame.inline.hpp" #include "runtime/mutexLocker.hpp" -#include "runtime/threadSMR.inline.hpp" #include "runtime/vframe_hp.hpp" #include "services/management.hpp" #include "utilities/growableArray.hpp" @@ -256,8 +256,9 @@ class ReferenceToThreadRootClosure : public StackObj { public: ReferenceToThreadRootClosure(RootCallback& callback) :_callback(callback), _complete(false) { assert_locked_or_safepoint(Threads_lock); - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { - if (do_thread_roots(jt)) { + JfrJavaThreadIterator iter; + while (iter.has_next()) { + if (do_thread_roots(iter.next())) { return; } } diff --git a/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp b/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp index 97e6f0de620..b162b46739c 100644 --- a/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp +++ b/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp @@ -31,6 +31,7 @@ #include "jfr/recorder/service/jfrOptionSet.hpp" #include "logging/log.hpp" #include "memory/iterator.hpp" +#include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" #include "runtime/vmThread.hpp" @@ -92,6 +93,7 @@ void LeakProfiler::emit_events(int64_t cutoff_ticks, bool emit_all) { if (!is_running()) { return; } + MutexLocker lock(JfrStream_lock); // exclusive access to object sampler instance ObjectSampler* const sampler = ObjectSampler::acquire(); assert(sampler != NULL, "invariant"); diff --git a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp index f72b6d8d347..9d23b983f13 100644 --- a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp +++ b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp @@ -110,6 +110,9 @@ static traceid get_thread_id(JavaThread* thread) { } const JfrThreadLocal* const tl = thread->jfr_thread_local(); assert(tl != NULL, "invariant"); + if (tl->is_excluded()) { + return 0; + } if (!tl->has_thread_blob()) { JfrCheckpointManager::create_thread_blob(thread); } diff --git a/src/hotspot/share/jfr/metadata/jfrSerializer.hpp b/src/hotspot/share/jfr/metadata/jfrSerializer.hpp index e13dc560c7e..57ae3554b0d 100644 --- a/src/hotspot/share/jfr/metadata/jfrSerializer.hpp +++ b/src/hotspot/share/jfr/metadata/jfrSerializer.hpp @@ -70,7 +70,8 @@ class JfrSerializer : public CHeapObj { public: virtual ~JfrSerializer() {} - static bool register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, JfrSerializer* serializer); + virtual void on_rotation() {} + static bool register_serializer(JfrTypeId id, bool permit_cache, JfrSerializer* serializer); virtual void serialize(JfrCheckpointWriter& writer) = 0; }; diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index ca2c5895490..7d24f8abef3 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -154,7 +154,7 @@ - + @@ -162,27 +162,27 @@ - + - + - + - + @@ -442,7 +442,7 @@ - + @@ -484,7 +484,7 @@ - + @@ -585,21 +585,21 @@ - - - @@ -1004,6 +1004,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1183,35 +1219,40 @@ - + + + + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -1223,5 +1264,5 @@ - + diff --git a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp index 9958818061d..610abccf373 100644 --- a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp +++ b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. * 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,7 +39,7 @@ struct InterfaceEntry { traceid id; uint64_t bytes_in; uint64_t bytes_out; - bool in_use; + mutable bool written; }; static GrowableArray* _interfaces = NULL; @@ -71,7 +71,7 @@ static InterfaceEntry& new_entry(const NetworkInterface* iface, GrowableArrayget_bytes_in(); entry.bytes_out = iface->get_bytes_out(); - entry.in_use = false; + entry.written = false; return _interfaces->at(_interfaces->append(entry)); } @@ -108,6 +108,39 @@ static uint64_t rate_per_second(uint64_t current, uint64_t old, const JfrTickspa return ((current - old) * NANOSECS_PER_SEC) / interval.nanoseconds(); } +class JfrNetworkInterfaceName : public JfrSerializer { + public: + void serialize(JfrCheckpointWriter& writer) {} // we write each constant lazily + + void on_rotation() { + for (int i = 0; i < _interfaces->length(); ++i) { + const InterfaceEntry& entry = _interfaces->at(i); + if (entry.written) { + entry.written = false; + } + } + } +}; + +static bool register_network_interface_name_serializer() { + assert(_interfaces != NULL, "invariant"); + return JfrSerializer::register_serializer(TYPE_NETWORKINTERFACENAME, + false, // disallow caching; we want a callback every rotation + new JfrNetworkInterfaceName()); +} + +static void write_interface_constant(const InterfaceEntry& entry) { + if (entry.written) { + return; + } + JfrCheckpointWriter writer; + writer.write_type(TYPE_NETWORKINTERFACENAME); + writer.write_count(1); + writer.write_key(entry.id); + writer.write(entry.name); + entry.written = true; +} + static bool get_interfaces(NetworkInterface** network_interfaces) { const int ret_val = JfrOSInterface::network_utilization(network_interfaces); if (ret_val == OS_ERR) { @@ -117,39 +150,6 @@ static bool get_interfaces(NetworkInterface** network_interfaces) { return ret_val != FUNCTIONALITY_NOT_IMPLEMENTED; } -class JfrNetworkInterfaceName : public JfrSerializer { - public: - void serialize(JfrCheckpointWriter& writer) { - assert(_interfaces != NULL, "invariant"); - const JfrCheckpointContext ctx = writer.context(); - const intptr_t count_offset = writer.reserve(sizeof(u4)); // Don't know how many yet - int active_interfaces = 0; - for (int i = 0; i < _interfaces->length(); ++i) { - InterfaceEntry& entry = _interfaces->at(i); - if (entry.in_use) { - entry.in_use = false; - writer.write_key(entry.id); - writer.write(entry.name); - ++active_interfaces; - } - } - if (active_interfaces == 0) { - // nothing to write, restore context - writer.set_context(ctx); - return; - } - writer.write_count(active_interfaces, count_offset); - } -}; - -static bool register_network_interface_name_serializer() { - assert(_interfaces != NULL, "invariant"); - return JfrSerializer::register_serializer(TYPE_NETWORKINTERFACENAME, - false, // require safepoint - false, // disallow caching; we want a callback every rotation - new JfrNetworkInterfaceName()); -} - void JfrNetworkUtilization::send_events() { ResourceMark rm; NetworkInterface* network_interfaces; @@ -169,7 +169,7 @@ void JfrNetworkUtilization::send_events() { const uint64_t read_rate = rate_per_second(current_bytes_in, entry.bytes_in, interval); const uint64_t write_rate = rate_per_second(current_bytes_out, entry.bytes_out, interval); if (read_rate > 0 || write_rate > 0) { - entry.in_use = true; + write_interface_constant(entry); EventNetworkUtilization event(UNTIMED); event.set_starttime(cur_time); event.set_endtime(cur_time); diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 7559797e519..526574146bc 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -44,6 +44,7 @@ #include "jfr/periodic/jfrNetworkUtilization.hpp" #include "jfr/recorder/jfrRecorder.hpp" #include "jfr/support/jfrThreadId.hpp" +#include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfrfiles/jfrPeriodic.hpp" #include "logging/log.hpp" @@ -56,7 +57,6 @@ #include "runtime/os.hpp" #include "runtime/os_perf.hpp" #include "runtime/thread.inline.hpp" -#include "runtime/threadSMR.hpp" #include "runtime/sweeper.hpp" #include "runtime/vmThread.hpp" #include "services/classLoadingService.hpp" @@ -410,13 +410,12 @@ TRACE_REQUEST_FUNC(ThreadAllocationStatistics) { GrowableArray allocated(initial_size); GrowableArray thread_ids(initial_size); JfrTicks time_stamp = JfrTicks::now(); - { - // Collect allocation statistics while holding threads lock - MutexLocker ml(Threads_lock); - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { - allocated.append(jt->cooked_allocated_bytes()); - thread_ids.append(JFR_THREAD_ID(jt)); - } + JfrJavaThreadIterator iter; + while (iter.has_next()) { + JavaThread* const jt = iter.next(); + assert(jt != NULL, "invariant"); + allocated.append(jt->cooked_allocated_bytes()); + thread_ids.append(JFR_THREAD_ID(jt)); } // Write allocation statistics to buffer. diff --git a/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp b/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp index 86be9806264..f91d6c8de66 100644 --- a/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp +++ b/src/hotspot/share/jfr/periodic/jfrThreadCPULoadEvent.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. * 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,11 +28,10 @@ #include "jfr/periodic/jfrThreadCPULoadEvent.hpp" #include "jfr/support/jfrThreadId.hpp" #include "jfr/support/jfrThreadLocal.hpp" +#include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTime.hpp" #include "utilities/globalDefinitions.hpp" #include "runtime/os.hpp" -#include "runtime/thread.inline.hpp" -#include "runtime/threadSMR.inline.hpp" jlong JfrThreadCPULoadEvent::get_wallclock_time() { return os::javaTimeNanos(); @@ -115,8 +114,12 @@ void JfrThreadCPULoadEvent::send_events() { JfrTicks event_time = JfrTicks::now(); jlong cur_wallclock_time = JfrThreadCPULoadEvent::get_wallclock_time(); - JavaThreadIteratorWithHandle jtiwh; - while (JavaThread* jt = jtiwh.next()) { + JfrJavaThreadIterator iter; + int number_of_threads = 0; + while (iter.has_next()) { + JavaThread* const jt = iter.next(); + assert(jt != NULL, "invariant"); + ++number_of_threads; EventThreadCPULoad event(UNTIMED); if (JfrThreadCPULoadEvent::update_event(event, jt, cur_wallclock_time, processor_count)) { event.set_starttime(event_time); @@ -129,7 +132,7 @@ void JfrThreadCPULoadEvent::send_events() { event.commit(); } } - log_trace(jfr)("Measured CPU usage for %d threads in %.3f milliseconds", jtiwh.length(), + log_trace(jfr)("Measured CPU usage for %d threads in %.3f milliseconds", number_of_threads, (double)(JfrTicks::now() - event_time).milliseconds()); // Restore this thread's thread id periodic_thread_tl->set_thread_id(periodic_thread_id); diff --git a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp index 1de335bcdbc..5ca913c0aba 100644 --- a/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp +++ b/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp @@ -30,6 +30,7 @@ #include "jfr/recorder/service/jfrOptionSet.hpp" #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" #include "jfr/support/jfrThreadId.hpp" +#include "jfr/support/jfrThreadLocal.hpp" #include "jfr/utilities/jfrTime.hpp" #include "logging/log.hpp" #include "runtime/frame.inline.hpp" @@ -352,9 +353,14 @@ static void clear_transition_block(JavaThread* jt) { } } +static bool is_excluded(JavaThread* thread) { + assert(thread != NULL, "invariant"); + return thread->is_hidden_from_external_view() || thread->in_deopt_handler() || thread->jfr_thread_local()->is_excluded(); +} + bool JfrThreadSampleClosure::do_sample_thread(JavaThread* thread, JfrStackFrame* frames, u4 max_frames, JfrSampleType type) { assert(Threads_lock->owned_by_self(), "Holding the thread table lock."); - if (thread->is_hidden_from_external_view() || thread->in_deopt_handler()) { + if (is_excluded(thread)) { return false; } diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp index c40ab5f1d57..d5b121c1c15 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp @@ -37,11 +37,14 @@ #include "jfr/recorder/storage/jfrMemorySpace.inline.hpp" #include "jfr/recorder/storage/jfrStorageUtils.inline.hpp" #include "jfr/utilities/jfrBigEndian.hpp" +#include "jfr/utilities/jfrIterator.hpp" +#include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTypes.hpp" +#include "jfr/writers/jfrJavaEventWriter.hpp" #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "runtime/handles.inline.hpp" -#include "runtime/mutexLocker.hpp" +#include "runtime/mutex.hpp" #include "runtime/orderAccess.hpp" #include "runtime/os.inline.hpp" #include "runtime/safepoint.hpp" @@ -168,7 +171,7 @@ static BufferPtr lease_free(size_t size, JfrCheckpointMspace* mspace, size_t ret } bool JfrCheckpointManager::use_epoch_transition_mspace(const Thread* thread) const { - return _service_thread != thread && OrderAccess::load_acquire(&_checkpoint_epoch_state) != JfrTraceIdEpoch::epoch(); + return _service_thread != thread && _checkpoint_epoch_state != JfrTraceIdEpoch::epoch(); } static const size_t lease_retry = 10; @@ -181,12 +184,24 @@ BufferPtr JfrCheckpointManager::lease_buffer(Thread* thread, size_t size /* 0 */ return lease_free(size, manager._free_list_mspace, lease_retry, thread); } +JfrCheckpointMspace* JfrCheckpointManager::lookup(BufferPtr old) const { + assert(old != NULL, "invariant"); + return _free_list_mspace->in_free_list(old) ? _free_list_mspace : _epoch_transition_mspace; +} + +BufferPtr JfrCheckpointManager::lease_buffer(BufferPtr old, Thread* thread, size_t size /* 0 */) { + assert(old != NULL, "invariant"); + JfrCheckpointMspace* mspace = instance().lookup(old); + assert(mspace != NULL, "invariant"); + return lease_free(size, mspace, lease_retry, thread); +} + /* -* If the buffer was a "lease" from the free list, release back. -* -* The buffer is effectively invalidated for the thread post-return, -* and the caller should take means to ensure that it is not referenced. -*/ + * If the buffer was a lease, release back. + * + * The buffer is effectively invalidated for the thread post-return, + * and the caller should take means to ensure that it is not referenced. + */ static void release(BufferPtr const buffer, Thread* thread) { DEBUG_ONLY(assert_release(buffer);) buffer->clear_lease(); @@ -202,7 +217,7 @@ BufferPtr JfrCheckpointManager::flush(BufferPtr old, size_t used, size_t request return NULL; } // migration of in-flight information - BufferPtr const new_buffer = lease_buffer(thread, used + requested); + BufferPtr const new_buffer = lease_buffer(old, thread, used + requested); if (new_buffer != NULL) { migrate_outstanding_writes(old, new_buffer, used, requested); } @@ -213,8 +228,8 @@ BufferPtr JfrCheckpointManager::flush(BufferPtr old, size_t used, size_t request // offsets into the JfrCheckpointEntry static const juint starttime_offset = sizeof(jlong); static const juint duration_offset = starttime_offset + sizeof(jlong); -static const juint flushpoint_offset = duration_offset + sizeof(jlong); -static const juint types_offset = flushpoint_offset + sizeof(juint); +static const juint checkpoint_type_offset = duration_offset + sizeof(jlong); +static const juint types_offset = checkpoint_type_offset + sizeof(juint); static const juint payload_offset = types_offset + sizeof(juint); template @@ -234,21 +249,21 @@ static jlong duration(const u1* data) { return read_data(data + duration_offset); } -static bool is_flushpoint(const u1* data) { - return read_data(data + flushpoint_offset) == (juint)1; +static u1 checkpoint_type(const u1* data) { + return read_data(data + checkpoint_type_offset); } static juint number_of_types(const u1* data) { return read_data(data + types_offset); } -static void write_checkpoint_header(JfrChunkWriter& cw, int64_t offset_prev_cp_event, const u1* data) { +static void write_checkpoint_header(JfrChunkWriter& cw, int64_t delta_to_last_checkpoint, const u1* data) { cw.reserve(sizeof(u4)); cw.write(EVENT_CHECKPOINT); cw.write(starttime(data)); cw.write(duration(data)); - cw.write(offset_prev_cp_event); - cw.write(is_flushpoint(data)); + cw.write(delta_to_last_checkpoint); + cw.write(checkpoint_type(data)); cw.write(number_of_types(data)); } @@ -261,9 +276,9 @@ static size_t write_checkpoint_event(JfrChunkWriter& cw, const u1* data) { assert(data != NULL, "invariant"); const int64_t event_begin = cw.current_offset(); const int64_t last_checkpoint_event = cw.last_checkpoint_offset(); - const int64_t delta = last_checkpoint_event == 0 ? 0 : last_checkpoint_event - event_begin; + const int64_t delta_to_last_checkpoint = last_checkpoint_event == 0 ? 0 : last_checkpoint_event - event_begin; const int64_t checkpoint_size = total_size(data); - write_checkpoint_header(cw, delta, data); + write_checkpoint_header(cw, delta_to_last_checkpoint, data); write_checkpoint_content(cw, data, checkpoint_size); const int64_t event_size = cw.current_offset() - event_begin; cw.write_padded_at_offset(event_size, event_begin); @@ -305,13 +320,13 @@ class CheckpointWriteOp { typedef CheckpointWriteOp WriteOperation; typedef ReleaseOp CheckpointReleaseOperation; -template