From 9353899bc5564827826ed94c0530497ff828e01b Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Thu, 8 Dec 2022 12:02:13 +0000 Subject: [PATCH] 8298175: JFR: Common timestamp for periodic events Reviewed-by: dholmes, mgronlun --- .../build/tools/jfr/GenerateJfrFiles.java | 10 ++++- src/hotspot/share/jfr/jni/jfrJniMethod.cpp | 4 +- .../share/jfr/periodic/jfrPeriodic.cpp | 12 ++++++ src/hotspot/share/utilities/ticks.hpp | 1 + .../share/classes/jdk/jfr/internal/JVM.java | 4 +- .../jdk/jfr/internal/RequestEngine.java | 37 ++++++++++--------- 6 files changed, 45 insertions(+), 23 deletions(-) diff --git a/make/src/classes/build/tools/jfr/GenerateJfrFiles.java b/make/src/classes/build/tools/jfr/GenerateJfrFiles.java index 712487ce32b..ed82128727d 100644 --- a/make/src/classes/build/tools/jfr/GenerateJfrFiles.java +++ b/make/src/classes/build/tools/jfr/GenerateJfrFiles.java @@ -573,9 +573,13 @@ private static void printJfrPeriodicHpp(Metadata metadata, File outputFile) thro out.write("#include \"jfrfiles/jfrEventIds.hpp\""); out.write("#include \"memory/allocation.hpp\""); out.write(""); + out.write("enum PeriodicType {BEGIN_CHUNK, INTERVAL, END_CHUNK};"); + out.write(""); out.write("class JfrPeriodicEventSet : public AllStatic {"); out.write(" public:"); - out.write(" static void requestEvent(JfrEventId id) {"); + out.write(" static void requestEvent(JfrEventId id, jlong timestamp, PeriodicType periodicType) {"); + out.write(" _timestamp = Ticks(timestamp);"); + out.write(" _type = periodicType;"); out.write(" switch(id) {"); out.write(" "); for (TypeElement e : metadata.getPeriodicEvents()) { @@ -595,6 +599,10 @@ private static void printJfrPeriodicHpp(Metadata metadata, File outputFile) thro out.write(" static void request" + e.name + "(void);"); out.write(""); } + out.write(" static Ticks timestamp(void);"); + out.write(" static Ticks _timestamp;"); + out.write(" static PeriodicType type(void);"); + out.write(" static PeriodicType _type;"); out.write("};"); out.write(""); out.write("#endif // INCLUDE_JFR"); diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp index 8ae2eb0c276..cf4aae2add5 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp @@ -238,8 +238,8 @@ JVM_ENTRY_NO_ENV(void, jfr_mark_chunk_final(JNIEnv * env, jobject jvm)) JfrRepository::mark_chunk_final(); JVM_END -JVM_ENTRY_NO_ENV(jboolean, jfr_emit_event(JNIEnv* env, jobject jvm, jlong eventTypeId, jlong timeStamp, jlong when)) - JfrPeriodicEventSet::requestEvent((JfrEventId)eventTypeId); +JVM_ENTRY_NO_ENV(jboolean, jfr_emit_event(JNIEnv* env, jobject jvm, jlong event_type_id, jlong timestamp, jlong periodic_type)) + JfrPeriodicEventSet::requestEvent((JfrEventId)event_type_id, timestamp, static_cast(periodic_type)); return thread->has_pending_exception() ? JNI_FALSE : JNI_TRUE; JVM_END diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index f43ccc254a7..79f42b6f425 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -81,6 +81,18 @@ */ #define TRACE_REQUEST_FUNC(id) void JfrPeriodicEventSet::request##id(void) +// Timestamp to correlate events in the same batch/generation +Ticks JfrPeriodicEventSet::_timestamp; +PeriodicType JfrPeriodicEventSet::_type; + +Ticks JfrPeriodicEventSet::timestamp(void) { + return _timestamp; +} + +PeriodicType JfrPeriodicEventSet::type(void) { + return _type; +} + TRACE_REQUEST_FUNC(JVMInformation) { ResourceMark rm; EventJVMInformation event; diff --git a/src/hotspot/share/utilities/ticks.hpp b/src/hotspot/share/utilities/ticks.hpp index 969f6792fbe..8d2bbc7ce1f 100644 --- a/src/hotspot/share/utilities/ticks.hpp +++ b/src/hotspot/share/utilities/ticks.hpp @@ -231,6 +231,7 @@ class TimeInstant : public Rep { friend class GranularTimer; friend class ObjectSample; friend class EventEmitter; + friend class JfrPeriodicEventSet; // GC unit tests friend class TimePartitionsTest; friend class GCTimerTest; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java index 2ebe586d083..605900a8638 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java @@ -118,11 +118,11 @@ private JVM() { * @param eventTypeId type id * * @param timestamp commit time for event - * @param when when it is being done {@link Periodic.When} + * @param periodicType when it is being done {@link PeriodicType.When} * * @return true if the event was committed */ - public native boolean emitEvent(long eventTypeId, long timestamp, long when); + public native boolean emitEvent(long eventTypeId, long timestamp, long periodicType); /** * Return a list of all classes deriving from {@link jdk.internal.event.Event} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/RequestEngine.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/RequestEngine.java index 2958e585893..1b144cdcd9a 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/RequestEngine.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/RequestEngine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * 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,9 @@ import jdk.jfr.EventType; public final class RequestEngine { + enum PeriodicType { + BEGIN_CHUNK, INTERVAL, END_CHUNK + } private static final JVM jvm = JVM.getJVM(); private static final ReentrantLock lock = new ReentrantLock(); @@ -62,13 +65,13 @@ private RequestHook(@SuppressWarnings("removal") AccessControlContext acc, Platf this(null, eventType, null); } - private void execute() { + private void execute(long timestamp, PeriodicType periodicType) { try { if (accessControllerContext == null) { // native if (type.isJDK()) { hook.run(); } else { - emitJVMEvent(type); + emitJVMEvent(type, timestamp, periodicType); } if (Logger.shouldLog(LogTag.JFR_SYSTEM, LogLevel.DEBUG)) { Logger.log(LogTag.JFR_SYSTEM, LogLevel.DEBUG, "Executed periodic hook for " + type.getLogName()); @@ -82,13 +85,13 @@ private void execute() { } } - private void emitJVMEvent(PlatformEventType type) { + private void emitJVMEvent(PlatformEventType type, long timestamp, PeriodicType periodicType) { try { // There should only be one thread in native at a time. // ReentrantLock is used to avoid JavaMonitorBlocked event // from synchronized block. lock.lock(); - jvm.emitEvent(type.getId(), JVM.counterTime(), 0); + jvm.emitEvent(type.getId(), timestamp, periodicType.ordinal()); } finally { lock.unlock(); } @@ -183,35 +186,33 @@ static void addHooks(List newEntries) { } static void doChunkEnd() { - doChunk(x -> x.isEndChunk()); + doChunk(x -> x.isEndChunk(), PeriodicType.END_CHUNK); } static void doChunkBegin() { - doChunk(x -> x.isBeginChunk()); + doChunk(x -> x.isBeginChunk(), PeriodicType.BEGIN_CHUNK); } - private static void doChunk(Predicate predicate) { + private static void doChunk(Predicate predicate, PeriodicType type) { + long timestamp = JVM.counterTime(); for (RequestHook requestHook : entries) { PlatformEventType s = requestHook.type; if (s.isEnabled() && predicate.test(s)) { - requestHook.execute(); + requestHook.execute(timestamp, type); } } } static long doPeriodic() { - return run_requests(entries); + return run_requests(entries, JVM.counterTime()); } // code copied from native impl. - private static long run_requests(Collection entries) { + private static long run_requests(Collection entries, long eventTimestamp) { long last = lastTimeMillis; - // Bug 9000556 - current time millis has rather lame resolution - // The use of os::elapsed_counter() is deliberate here, we don't - // want it exchanged for os::ft_elapsed_counter(). - // Keeping direct call os::elapsed_counter() here for reliable - // real time values in order to decide when registered requestable - // events are due. + // The interval for periodic events is typically at least 1 s, so + // System.currentTimeMillis() is sufficient. JVM.counterTime() lacks + // unit and has in the past been more unreliable. long now = System.currentTimeMillis(); long min = 0; long delta = 0; @@ -249,7 +250,7 @@ private static long run_requests(Collection entries) { // Bug 9000556 - don't try to compensate // for wait > period r_delta = 0; - he.execute(); + he.execute(eventTimestamp, PeriodicType.INTERVAL); } // calculate time left