From b1b57742e75a38a015a697923a9df3846a6f4f6c Mon Sep 17 00:00:00 2001 From: erik_gahlin Date: Sat, 31 May 2025 00:27:55 +0200 Subject: [PATCH 01/10] Initial --- .gitignore | 1 - .../classes/java/io/FileInputStream.java | 13 +- .../classes/java/io/FileOutputStream.java | 12 +- .../classes/java/io/RandomAccessFile.java | 22 +- .../share/classes/java/lang/Throwable.java | 4 +- .../share/classes/java/net/Socket.java | 10 +- .../internal/event/ExceptionThrownEvent.java | 7 +- .../jdk/internal/event/FileReadEvent.java | 4 +- .../jdk/internal/event/FileWriteEvent.java | 4 +- .../jdk/internal/event/SocketReadEvent.java | 9 +- .../jdk/internal/event/SocketWriteEvent.java | 11 +- .../jdk/internal/event/ThrowableTracer.java | 22 +- .../classes/sun/nio/ch/FileChannelImpl.java | 32 +- .../jdk/jfr/{internal => }/Throttle.java | 54 ++-- .../jdk/jfr/events/ExceptionThrownEvent.java | 4 +- .../classes/jdk/jfr/events/FileReadEvent.java | 4 +- .../jdk/jfr/events/FileWriteEvent.java | 4 +- .../jdk/jfr/events/SocketReadEvent.java | 4 +- .../jdk/jfr/events/SocketWriteEvent.java | 4 +- .../jdk/jfr/internal/ClassInspector.java | 16 + .../jdk/jfr/internal/EventControl.java | 3 + .../jfr/internal/EventInstrumentation.java | 107 ++++++- .../classes/jdk/jfr/internal/JVMSupport.java | 2 +- .../jdk/jfr/internal/MetadataLoader.java | 5 +- .../jdk/jfr/internal/MetadataRepository.java | 6 +- .../jdk/jfr/internal/PlatformEventType.java | 16 +- .../internal/event/EventConfiguration.java | 29 ++ .../internal/settings/ThrottleSetting.java | 3 +- .../jdk/jfr/internal/settings/Throttler.java | 232 ++++++++++++++ .../settings/ThrottlerParameters.java | 94 ++++++ .../internal/settings/ThrottlerWindow.java | 100 ++++++ .../share/classes/jdk/jfr/package-info.java | 24 +- src/jdk.jfr/share/conf/jfr/default.jfc | 36 ++- src/jdk.jfr/share/conf/jfr/profile.jfc | 38 ++- .../metadata/annotations/TestThrottle.java | 290 ++++++++++++++++++ .../settings/TestSettingsAvailability.java | 14 +- .../jfr/startupargs/TestEventSettings.java | 4 +- 37 files changed, 1092 insertions(+), 152 deletions(-) rename src/jdk.jfr/share/classes/jdk/jfr/{internal => }/Throttle.java (60%) create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottlerParameters.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottlerWindow.java create mode 100644 test/jdk/jdk/jfr/api/metadata/annotations/TestThrottle.java diff --git a/.gitignore b/.gitignore index 9145a9fa67b06..57ed105e41bb5 100644 --- a/.gitignore +++ b/.gitignore @@ -23,5 +23,4 @@ NashornProfile.txt /.gdbinit /.lldbinit **/core.[0-9]* -*.rej *.orig diff --git a/src/java.base/share/classes/java/io/FileInputStream.java b/src/java.base/share/classes/java/io/FileInputStream.java index ab312fc8c5be0..aec653433849f 100644 --- a/src/java.base/share/classes/java/io/FileInputStream.java +++ b/src/java.base/share/classes/java/io/FileInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2025, 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 @@ -217,10 +217,12 @@ private int traceRead0() throws IOException { bytesRead = 1; } } finally { - long duration = FileReadEvent.timestamp() - start; - if (FileReadEvent.shouldCommit(duration)) { + long end = FileReadEvent.timestamp(); + long duration = end - start; + if (FileReadEvent.shouldThrottleCommit(duration, end)) { FileReadEvent.commit(start, duration, path, bytesRead, endOfFile); } + } return result; } @@ -241,8 +243,9 @@ private int traceReadBytes(byte b[], int off, int len) throws IOException { start = FileReadEvent.timestamp(); bytesRead = readBytes(b, off, len); } finally { - long duration = FileReadEvent.timestamp() - start; - if (FileReadEvent.shouldCommit(duration)) { + long end = FileReadEvent.timestamp(); + long duration = end - start; + if (FileReadEvent.shouldThrottleCommit(duration, end)) { if (bytesRead < 0) { FileReadEvent.commit(start, duration, path, 0L, true); } else { diff --git a/src/java.base/share/classes/java/io/FileOutputStream.java b/src/java.base/share/classes/java/io/FileOutputStream.java index 6c5a30ea43232..ebedce2b73e4b 100644 --- a/src/java.base/share/classes/java/io/FileOutputStream.java +++ b/src/java.base/share/classes/java/io/FileOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2025, 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 @@ -272,8 +272,9 @@ private void traceWrite(int b, boolean append) throws IOException { write(b, append); bytesWritten = 1; } finally { - long duration = FileWriteEvent.timestamp() - start; - if (FileWriteEvent.shouldCommit(duration)) { + long end = FileWriteEvent.timestamp(); + long duration = end - start; + if (FileWriteEvent.shouldThrottleCommit(duration, end)) { FileWriteEvent.commit(start, duration, path, bytesWritten); } } @@ -316,8 +317,9 @@ private void traceWriteBytes(byte b[], int off, int len, boolean append) throws writeBytes(b, off, len, append); bytesWritten = len; } finally { - long duration = FileWriteEvent.timestamp() - start; - if (FileWriteEvent.shouldCommit(duration)) { + long end = FileWriteEvent.timestamp(); + long duration = end - start; + if (FileWriteEvent.shouldThrottleCommit(duration, end)) { FileWriteEvent.commit(start, duration, path, bytesWritten); } } diff --git a/src/java.base/share/classes/java/io/RandomAccessFile.java b/src/java.base/share/classes/java/io/RandomAccessFile.java index c09f87afcdc45..9200022582b43 100644 --- a/src/java.base/share/classes/java/io/RandomAccessFile.java +++ b/src/java.base/share/classes/java/io/RandomAccessFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2025, 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 @@ -378,8 +378,9 @@ private int traceRead0() throws IOException { bytesRead = 1; } } finally { - long duration = FileReadEvent.timestamp() - start; - if (FileReadEvent.shouldCommit(duration)) { + long end = FileReadEvent.timestamp(); + long duration = end - start; + if (FileReadEvent.shouldThrottleCommit(duration, end)) { FileReadEvent.commit(start, duration, path, bytesRead, endOfFile); } } @@ -409,8 +410,9 @@ private int traceReadBytes0(byte b[], int off, int len) throws IOException { start = FileReadEvent.timestamp(); bytesRead = readBytes0(b, off, len); } finally { - long duration = FileReadEvent.timestamp() - start; - if (FileReadEvent.shouldCommit(duration)) { + long end = FileReadEvent.timestamp(); + long duration = end - start; + if (FileReadEvent.shouldThrottleCommit(duration, end)) { if (bytesRead < 0) { FileReadEvent.commit(start, duration, path, 0L, true); } else { @@ -588,8 +590,9 @@ private void traceImplWrite(int b) throws IOException { implWrite(b); bytesWritten = 1; } finally { - long duration = FileWriteEvent.timestamp() - start; - if (FileWriteEvent.shouldCommit(duration)) { + long end = FileWriteEvent.timestamp(); + long duration = end - start; + if (FileWriteEvent.shouldThrottleCommit(duration, end)) { FileWriteEvent.commit(start, duration, path, bytesWritten); } } @@ -630,8 +633,9 @@ private void traceImplWriteBytes(byte b[], int off, int len) throws IOException implWriteBytes(b, off, len); bytesWritten = len; } finally { - long duration = FileWriteEvent.timestamp() - start; - if (FileWriteEvent.shouldCommit(duration)) { + long end = FileWriteEvent.timestamp(); + long duration = end - start; + if (FileWriteEvent.shouldThrottleCommit(duration, end)) { FileWriteEvent.commit(start, duration, path, bytesWritten); } } diff --git a/src/java.base/share/classes/java/lang/Throwable.java b/src/java.base/share/classes/java/lang/Throwable.java index 8c0ce29dbeefc..ac3325fc51417 100644 --- a/src/java.base/share/classes/java/lang/Throwable.java +++ b/src/java.base/share/classes/java/lang/Throwable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2025, 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 @@ -121,7 +121,7 @@ public class Throwable implements Serializable { * Flag set by jdk.internal.event.JFRTracing to indicate if * exceptions should be traced by JFR. */ - static volatile boolean jfrTracing; + static boolean jfrTracing; /** * The JVM saves some indication of the stack backtrace in this slot. diff --git a/src/java.base/share/classes/java/net/Socket.java b/src/java.base/share/classes/java/net/Socket.java index d2afa166a8888..7bd81f361fd10 100644 --- a/src/java.base/share/classes/java/net/Socket.java +++ b/src/java.base/share/classes/java/net/Socket.java @@ -965,8 +965,9 @@ public int read(byte[] b, int off, int len) throws IOException { } long start = SocketReadEvent.timestamp(); int nbytes = implRead(b, off, len); - long duration = SocketReadEvent.timestamp() - start; - if (SocketReadEvent.shouldCommit(duration)) { + long end = SocketReadEvent.timestamp(); + long duration = end - start; + if (SocketReadEvent.shouldThrottleCommit(duration, end)) { SocketReadEvent.emit(start, duration, nbytes, parent.getRemoteSocketAddress(), getSoTimeout()); } return nbytes; @@ -1081,8 +1082,9 @@ public void write(byte[] b, int off, int len) throws IOException { } long start = SocketWriteEvent.timestamp(); implWrite(b, off, len); - long duration = SocketWriteEvent.timestamp() - start; - if (SocketWriteEvent.shouldCommit(duration)) { + long end = SocketWriteEvent.timestamp(); + long duration = end - start; + if (SocketWriteEvent.shouldThrottleCommit(duration, end)) { SocketWriteEvent.emit(start, duration, len, parent.getRemoteSocketAddress()); } } diff --git a/src/java.base/share/classes/jdk/internal/event/ExceptionThrownEvent.java b/src/java.base/share/classes/jdk/internal/event/ExceptionThrownEvent.java index 45c13e3010d1c..355ee81c0fcbb 100644 --- a/src/java.base/share/classes/jdk/internal/event/ExceptionThrownEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/ExceptionThrownEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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,11 @@ public final class ExceptionThrownEvent extends Event { public String message; public Class thrownClass; + public static boolean shouldThrottleCommit(long timestamp) { + // Generated by JFR + return false; + } + public static void commit(long start, String message, Class thrownClass) { // Generated by JFR } diff --git a/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java b/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java index 34ff4e9d4ed3d..741897d837402 100644 --- a/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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,7 +45,7 @@ public static long timestamp() { return 0L; } - public static boolean shouldCommit(long duration) { + public static boolean shouldThrottleCommit(long duration, long timestamp) { // Generated by JFR return false; } diff --git a/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java b/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java index f6c279604305d..80e689c2b9c08 100644 --- a/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ public static long timestamp() { return 0L; } - public static boolean shouldCommit(long duration) { + public static boolean shouldThrottleCommit(long duration, long timestamp) { // Generated by JFR return false; } diff --git a/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java b/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java index d5f6c3241d9a0..da6d9eec60797 100644 --- a/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -76,7 +76,7 @@ public static void commit(long start, long duration, String host, String address * @param duration time in nanoseconds to complete the operation * @return true if the event should be commited */ - public static boolean shouldCommit(long duration) { + public static boolean shouldThrottleCommit(long duration, long timestamp) { // Generated by JFR return false; } @@ -118,8 +118,9 @@ public static long timestamp() { * @param timeout maximum time to wait */ public static void offer(long start, long nbytes, SocketAddress remote, long timeout) { - long duration = timestamp() - start; - if (shouldCommit(duration)) { + long end = timestamp(); + long duration = end - start; + if (shouldThrottleCommit(duration, end)) { emit(start, duration, nbytes, remote, timeout); } } diff --git a/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java b/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java index 7c56ef826a5c4..d0e0ad2cd04b5 100644 --- a/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -71,7 +71,7 @@ public static void commit(long start, long duration, String host, String address * @param duration time in nanoseconds to complete the operation * @return true if the event should be commited */ - public static boolean shouldCommit(long duration) { + public static boolean shouldThrottleCommit(long duration, long timestamp) { // Generated by JFR return false; } @@ -104,7 +104,7 @@ public static long timestamp() { * The duration of the operation is computed using the current * timestamp and the given start time. If the duration is meets * or exceeds the configured value (determined by calling the generated method - * {@link #shouldCommit(long)}), an event will be emitted by calling + * {@link #shouldThrottleCommit(long)}), an event will be emitted by calling * {@link #emit(long, long, long, SocketAddress)}. * * @param start the start time @@ -112,8 +112,9 @@ public static long timestamp() { * @param remote the address of the remote socket being written to */ public static void offer(long start, long bytesWritten, SocketAddress remote) { - long duration = timestamp() - start; - if (shouldCommit(duration)) { + long end = timestamp(); + long duration = end - start; + if (shouldThrottleCommit(duration, end)) { emit(start, duration, bytesWritten, remote); } } diff --git a/src/java.base/share/classes/jdk/internal/event/ThrowableTracer.java b/src/java.base/share/classes/jdk/internal/event/ThrowableTracer.java index f7076b44e909b..6502cbc80020e 100644 --- a/src/java.base/share/classes/jdk/internal/event/ThrowableTracer.java +++ b/src/java.base/share/classes/jdk/internal/event/ThrowableTracer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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,22 +37,24 @@ public static void traceError(Class clazz, String message) { if (OutOfMemoryError.class.isAssignableFrom(clazz)) { return; } - - if (ErrorThrownEvent.enabled()) { + if (ErrorThrownEvent.enabled() || ExceptionThrownEvent.enabled()) { long timestamp = ErrorThrownEvent.timestamp(); - ErrorThrownEvent.commit(timestamp, message, clazz); - } - if (ExceptionThrownEvent.enabled()) { - long timestamp = ExceptionThrownEvent.timestamp(); - ExceptionThrownEvent.commit(timestamp, message, clazz); + if (ErrorThrownEvent.enabled()) { + ErrorThrownEvent.commit(timestamp, message, clazz); + } + if (ExceptionThrownEvent.shouldThrottleCommit(timestamp)) { + ExceptionThrownEvent.commit(timestamp, message, clazz); + } } numThrowables.incrementAndGet(); } public static void traceThrowable(Class clazz, String message) { if (ExceptionThrownEvent.enabled()) { - long timestamp = ExceptionThrownEvent.timestamp(); - ExceptionThrownEvent.commit(timestamp, message, clazz); + long timestamp = ErrorThrownEvent.timestamp(); + if (ExceptionThrownEvent.shouldThrottleCommit(timestamp)) { + ExceptionThrownEvent.commit(timestamp, message, clazz); + } } numThrowables.incrementAndGet(); } diff --git a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java index 72de217a83ce6..56a3a8f177536 100644 --- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, 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 @@ -269,8 +269,9 @@ private int traceImplRead(ByteBuffer dst) throws IOException { start = FileReadEvent.timestamp(); bytesRead = implRead(dst); } finally { - long duration = FileReadEvent.timestamp() - start; - if (FileReadEvent.shouldCommit(duration)) { + long end = FileReadEvent.timestamp(); + long duration = end - start; + if (FileReadEvent.shouldThrottleCommit(duration, end)) { if (bytesRead < 0) { FileReadEvent.commit(start, duration, path, 0L, true); } else { @@ -331,8 +332,9 @@ private long traceImplRead(ByteBuffer[] dsts, int offset, int length) throws IOE start = FileReadEvent.timestamp(); bytesRead = implRead(dsts, offset, length); } finally { - long duration = FileReadEvent.timestamp() - start; - if (FileReadEvent.shouldCommit(duration)) { + long end = FileReadEvent.timestamp(); + long duration = end - start; + if (FileReadEvent.shouldThrottleCommit(duration, end)) { if (bytesRead < 0) { FileReadEvent.commit(start, duration, path, 0L, true); } else { @@ -390,8 +392,9 @@ private int traceImplWrite(ByteBuffer src) throws IOException { start = FileWriteEvent.timestamp(); bytesWritten = implWrite(src); } finally { - long duration = FileWriteEvent.timestamp() - start; - if (FileWriteEvent.shouldCommit(duration)) { + long end = FileWriteEvent.timestamp(); + long duration = end - start; + if (FileWriteEvent.shouldThrottleCommit(duration, end)) { long bytes = bytesWritten > 0 ? bytesWritten : 0; FileWriteEvent.commit(start, duration, path, bytes); } @@ -446,8 +449,9 @@ private long traceImplWrite(ByteBuffer[] srcs, int offset, int length) throws IO start = FileWriteEvent.timestamp(); bytesWritten = implWrite(srcs, offset, length); } finally { - long duration = FileWriteEvent.timestamp() - start; - if (FileWriteEvent.shouldCommit(duration)) { + long end = FileWriteEvent.timestamp(); + long duration = end - start; + if (FileWriteEvent.shouldThrottleCommit(duration, end)) { long bytes = bytesWritten > 0 ? bytesWritten : 0; FileWriteEvent.commit(start, duration, path, bytes); } @@ -1204,8 +1208,9 @@ private int traceImplRead(ByteBuffer dst, long position) throws IOException { start = FileReadEvent.timestamp(); bytesRead = implRead(dst, position); } finally { - long duration = FileReadEvent.timestamp() - start; - if (FileReadEvent.shouldCommit(duration)) { + long end = FileReadEvent.timestamp(); + long duration = end - start; + if (FileReadEvent.shouldThrottleCommit(duration, end)) { if (bytesRead < 0) { FileReadEvent.commit(start, duration, path, 0L, true); } else { @@ -1276,8 +1281,9 @@ private int traceImplWrite(ByteBuffer src, long position) throws IOException { start = FileWriteEvent.timestamp(); bytesWritten = implWrite(src, position); } finally { - long duration = FileWriteEvent.timestamp() - start; - if (FileWriteEvent.shouldCommit(duration)) { + long end = FileWriteEvent.timestamp(); + long duration = end - start; + if (FileWriteEvent.shouldThrottleCommit(duration, end)) { long bytes = bytesWritten > 0 ? bytesWritten : 0; FileWriteEvent.commit(start, duration, path, bytes); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Throttle.java b/src/jdk.jfr/share/classes/jdk/jfr/Throttle.java similarity index 60% rename from src/jdk.jfr/share/classes/jdk/jfr/internal/Throttle.java rename to src/jdk.jfr/share/classes/jdk/jfr/Throttle.java index 39409d008ab3d..c13311aef43ba 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Throttle.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Throttle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, Datadog, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -24,7 +24,7 @@ * questions. */ -package jdk.jfr.internal; +package jdk.jfr; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; @@ -32,14 +32,15 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import jdk.jfr.MetadataDefinition; - /** - * Event annotation, determines the event emission rate in events per time unit. - * - * This setting is only supported for JVM events. - * - * @since 16 + * Event annotation, specifies the maximum rate of events per time unit, (for + * example, {@code "100/s"}). + *

+ * If the event class annotated with {@code Throttle} are filtering by other + * settings, such as a {@link jdk.jfr.Threshold} or a user-defined setting, the + * throttling will happen after those settings have been applied. + * + * @since 25 */ @MetadataDefinition @Target({ ElementType.TYPE }) @@ -47,30 +48,33 @@ @Retention(RetentionPolicy.RUNTIME) public @interface Throttle { /** - * Settings name {@code "throttle"} for configuring an event emission rate in events per time unit. + * Setting name {@code "throttle"} for configuring throttled events. */ public static final String NAME = "throttle"; - public static final String DEFAULT = "off"; /** - * Throttle, for example {@code "100/s"}. + * The throttle rate, for example {@code "100/s"}. *

- * String representation of a non-negative {@code Long} value followed by a slash ("/") - * and one of the following units
- * {@code "ns"} (nanoseconds)
- * {@code "us"} (microseconds)
- * {@code "ms"} (milliseconds)
- * {@code "s"} (seconds)
- * {@code "m"} (minutes)
- * {@code "h"} (hours)
- * {@code "d"} (days)
+ * String representation of a non-negative {@code Long} value followed by a + * forward slash ("/") and one of the following units:
+ *

*

* Example values, {@code "6000/m"}, {@code "10/ms"} and {@code "200/s"}. - * When zero is specified, for example {@code "0/s"}, no events are emitted. - * When {@code "off"} is specified, all events are emitted. + *

+ * Specifying zero, for example {@code "0/s"}, results in no events being + * emitted. + *

+ * Specifying {@code "off"} (case-sensitive) results in all events being emitted. * * @return the throttle value, default {@code "off"} not {@code null} - * */ - String value() default DEFAULT; + String value() default "off"; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionThrownEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionThrownEvent.java index 22c87f3132d43..244ca181e8a9b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionThrownEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionThrownEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import jdk.jfr.Description; import jdk.jfr.Label; import jdk.jfr.Name; +import jdk.jfr.Throttle; import jdk.jfr.internal.MirrorEvent; import jdk.jfr.internal.RemoveFields; import jdk.jfr.internal.Type; @@ -38,6 +39,7 @@ @Category("Java Application") @Description("An object derived from java.lang.Exception has been created") @RemoveFields("duration") +@Throttle("off") public final class ExceptionThrownEvent extends MirrorEvent { @Label("Message") diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/FileReadEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/FileReadEvent.java index 84886d2493a54..bd9926c08d38e 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/events/FileReadEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/FileReadEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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,6 +30,7 @@ import jdk.jfr.Label; import jdk.jfr.DataAmount; import jdk.jfr.Name; +import jdk.jfr.Throttle; import jdk.jfr.internal.Type; import jdk.jfr.internal.MirrorEvent; @@ -38,6 +39,7 @@ @Category("Java Application") @Description("Reading data from a file") @StackFilter({"java.io.FileInputStream", "java.io.RandomAccessFile", "sun.nio.ch.FileChannelImpl"}) +@Throttle public final class FileReadEvent extends MirrorEvent { @Label("Path") diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/FileWriteEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/FileWriteEvent.java index 990f1845168a5..e7861eef1b64b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/events/FileWriteEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/FileWriteEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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,6 +30,7 @@ import jdk.jfr.Label; import jdk.jfr.DataAmount; import jdk.jfr.Name; +import jdk.jfr.Throttle; import jdk.jfr.internal.Type; import jdk.jfr.internal.MirrorEvent; @@ -38,6 +39,7 @@ @Category("Java Application") @Description("Writing data to a file") @StackFilter({"java.io.FileOutputStream", "java.io.RandomAccessFile", "sun.nio.ch.FileChannelImpl"}) +@Throttle public final class FileWriteEvent extends MirrorEvent { @Label("Path") diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/SocketReadEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/SocketReadEvent.java index 917eabd92067f..b2cdee4f8dccf 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/events/SocketReadEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/SocketReadEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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,7 @@ import jdk.jfr.DataAmount; import jdk.jfr.Name; import jdk.jfr.Timespan; +import jdk.jfr.Throttle; import jdk.jfr.internal.MirrorEvent; import jdk.jfr.internal.Type; @@ -38,6 +39,7 @@ @Label("Socket Read") @Category("Java Application") @Description("Reading data from a socket") +@Throttle public final class SocketReadEvent extends MirrorEvent { @Label("Remote Host") diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/SocketWriteEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/SocketWriteEvent.java index 92c85c132d4ad..661a4d1a68e2c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/events/SocketWriteEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/SocketWriteEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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,6 +30,7 @@ import jdk.jfr.Label; import jdk.jfr.DataAmount; import jdk.jfr.Name; +import jdk.jfr.Throttle; import jdk.jfr.internal.MirrorEvent; import jdk.jfr.internal.Type; @@ -37,6 +38,7 @@ @Label("Socket Write") @Category("Java Application") @Description("Writing data to a socket") +@Throttle public final class SocketWriteEvent extends MirrorEvent { @Label("Remote Host") diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java index d310c505da698..3646162e8f78f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/ClassInspector.java @@ -51,6 +51,7 @@ import jdk.jfr.Registered; import jdk.jfr.SettingControl; import jdk.jfr.SettingDefinition; +import jdk.jfr.Throttle; import jdk.jfr.internal.util.Bytecode; import jdk.jfr.internal.util.ImplicitFields; import jdk.jfr.internal.util.Bytecode.FieldDesc; @@ -64,6 +65,7 @@ final class ClassInspector { private static final ClassDesc ANNOTATION_NAME = classDesc(Name.class); private static final ClassDesc ANNOTATION_ENABLED = classDesc(Enabled.class); private static final ClassDesc ANNOTATION_REMOVE_FIELDS = classDesc(RemoveFields.class); + private static final ClassDesc ANNOTATION_THROTTLE = classDesc(Throttle.class); private static final String[] EMPTY_STRING_ARRAY = {}; private final ClassModel classModel; @@ -138,6 +140,20 @@ boolean isEnabled() { return true; } + boolean isThrottled() { + String result = annotationValue(ANNOTATION_THROTTLE, String.class, "off"); + if (result != null) { + return true; + } + if (superClass != null) { + Throttle t = superClass.getAnnotation(Throttle.class); + if (t != null) { + return true; + } + } + return false; + } + boolean hasStaticMethod(MethodDesc method) { for (MethodModel m : classModel.methods()) { if (Modifier.isStatic(m.flags().flagsMask())) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java index f43e45b724eb9..c2831c217896a 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java @@ -44,6 +44,7 @@ import jdk.jfr.SettingDefinition; import jdk.jfr.StackTrace; import jdk.jfr.Threshold; +import jdk.jfr.Throttle; import jdk.jfr.events.ActiveSettingEvent; import jdk.jfr.events.StackFilter; import jdk.jfr.internal.settings.CutoffSetting; @@ -54,6 +55,7 @@ import jdk.jfr.internal.settings.StackTraceSetting; import jdk.jfr.internal.settings.ThresholdSetting; import jdk.jfr.internal.settings.ThrottleSetting; +import jdk.jfr.internal.settings.Throttler; import jdk.jfr.internal.tracing.Modification; import jdk.jfr.internal.util.Utils; @@ -94,6 +96,7 @@ record NamedControl(String name, Control control) { } if (eventType.hasThrottle()) { addControl(Throttle.NAME, defineThrottle(eventType)); + eventType.setThrottler(new Throttler(eventType)); } if (eventType.hasLevel()) { addControl(Level.NAME, defineLevel(eventType)); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java index 96e6f36e5c849..89356cca9b9dd 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java @@ -60,7 +60,14 @@ * Class responsible for adding instrumentation to a subclass of {@link Event}. * */ -final class EventInstrumentation { +public final class EventInstrumentation { + public static final long MASK_THROTTLE = 1 << 62; + public static final long MASK_THROTTLE_CHECK = 1 << 63; + public static final long MASK_THROTTLE_BITS = MASK_THROTTLE | MASK_THROTTLE_CHECK; + public static final long MASK_THROTTLE_CHECK_SUCCESS = MASK_THROTTLE_CHECK | MASK_THROTTLE; + public static final long MASK_THROTTLE_CHECK_FAIL = MASK_THROTTLE_CHECK | 0; + public static final long MASK_NON_THROTTLE_BITS = ~MASK_THROTTLE_BITS; + private static final FieldDesc FIELD_EVENT_CONFIGURATION = FieldDesc.of(Object.class, "eventConfiguration"); private static final ClassDesc TYPE_EVENT_CONFIGURATION = classDesc(EventConfiguration.class); @@ -71,11 +78,17 @@ final class EventInstrumentation { private static final MethodDesc METHOD_BEGIN = MethodDesc.of("begin", "()V"); private static final MethodDesc METHOD_COMMIT = MethodDesc.of("commit", "()V"); private static final MethodDesc METHOD_DURATION = MethodDesc.of("duration", "(J)J"); + private static final MethodDesc METHOD_THROTTLE = MethodDesc.of("throttle", "(JJ)J"); private static final MethodDesc METHOD_ENABLED = MethodDesc.of("enabled", "()Z"); private static final MethodDesc METHOD_END = MethodDesc.of("end", "()V"); - private static final MethodDesc METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT = MethodDesc.of("shouldCommit", "(J)Z"); + private static final MethodDesc METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT_LONG = MethodDesc.of("shouldCommit", "(J)Z"); + private static final MethodDesc METHOD_EVENT_CONFIGURATION_SHOULD_THROTTLE_COMMIT_LONG_LONG = MethodDesc.of("shouldThrottleCommit", "(JJ)Z"); + private static final MethodDesc METHOD_EVENT_CONFIGURATION_SHOULD_THROTTLE_COMMIT_LONG = MethodDesc.of("shouldThrottleCommit", "(J)Z"); + private static final MethodDesc METHOD_EVENT_CONFIGURATION_GET_SETTING = MethodDesc.of("getSetting", SettingControl.class, int.class); private static final MethodDesc METHOD_EVENT_SHOULD_COMMIT = MethodDesc.of("shouldCommit", "()Z"); + private static final MethodDesc METHOD_EVENT_SHOULD_THROTTLE_COMMIT_LONG_LONG = MethodDesc.of("shouldThrottleCommit", "(JJ)Z"); + private static final MethodDesc METHOD_EVENT_SHOULD_THROTTLE_COMMIT_LONG = MethodDesc.of("shouldThrottleCommit", "(J)Z"); private static final MethodDesc METHOD_GET_EVENT_WRITER = MethodDesc.of("getEventWriter", "()" + TYPE_EVENT_WRITER.descriptorString()); private static final MethodDesc METHOD_IS_ENABLED = MethodDesc.of("isEnabled", "()Z"); private static final MethodDesc METHOD_RESET = MethodDesc.of("reset", "()V"); @@ -88,6 +101,7 @@ final class EventInstrumentation { private final MethodDesc staticCommitMethod; private final boolean untypedEventConfiguration; private final boolean guardEventConfiguration; + private final boolean throttled; /** * Creates an EventInstrumentation object. @@ -110,6 +124,11 @@ final class EventInstrumentation { this.eventClassDesc = inspector.getClassDesc(); this.staticCommitMethod = inspector.findStaticCommitMethod(); this.untypedEventConfiguration = hasUntypedConfiguration(); + if (inspector.isJDK()) { + this.throttled = inspector.hasStaticMethod(METHOD_EVENT_SHOULD_THROTTLE_COMMIT_LONG_LONG); + } else { + this.throttled = inspector.isThrottled(); + } } byte[] buildInstrumented() { @@ -147,6 +166,12 @@ private Consumer instrumentable(MethodModel method) { if (isMethod(method, METHOD_SHOULD_COMMIT_LONG)) { return this::methodShouldCommitStatic; } + if (isMethod(method, METHOD_EVENT_SHOULD_THROTTLE_COMMIT_LONG_LONG)) { + return this::methodShouldCommitThrottleStaticLongLong; + } + if (isMethod(method, METHOD_EVENT_SHOULD_THROTTLE_COMMIT_LONG)) { + return this::methodShouldCommitThrottleStaticLong; + } if (isMethod(method, METHOD_TIME_STAMP)) { return this::methodTimestamp; } @@ -188,11 +213,11 @@ private void methodEnd(CodeBuilder codeBuilder) { if (!inspector.hasDuration()) { throwMissingDuration(codeBuilder, "end"); } else { - codeBuilder.aload(0); - codeBuilder.aload(0); - getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_START_TIME); - invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_DURATION); - putfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); + setDuration(codeBuilder, cb -> { + codeBuilder.aload(0); + getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_START_TIME); + invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_DURATION); + }); codeBuilder.return_(); } } @@ -205,9 +230,8 @@ private void methodShouldCommit(CodeBuilder codeBuilder) { } // if (!eventConfiguration.shouldCommit(duration) goto fail; getEventConfiguration(codeBuilder); - codeBuilder.aload(0); - getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); - invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT); + getDuration(codeBuilder); + invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT_LONG); codeBuilder.ifeq(fail); List settingDescs = inspector.getSettings(); for (int index = 0; index < settingDescs.size(); index++) { @@ -222,6 +246,30 @@ private void methodShouldCommit(CodeBuilder codeBuilder) { codeBuilder.invokevirtual(eventClassDesc, sd.methodName(), mdesc); codeBuilder.ifeq(fail); } + if (throttled) { + // long d = eventConfiguration.throttle(this.duration); + // this.duration = d; + // if (d & MASK_THROTTLE_BIT == 0) { + // goto fail; + // } + getEventConfiguration(codeBuilder); + codeBuilder.aload(0); + getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_START_TIME); + codeBuilder.aload(0); + getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); + Bytecode.invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_THROTTLE); + int result = codeBuilder.allocateLocal(TypeKind.LONG); + codeBuilder.lstore(result); + codeBuilder.aload(0); + codeBuilder.lload(result); + putfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); + codeBuilder.lload(result); + codeBuilder.ldc(MASK_THROTTLE); + codeBuilder.land(); + codeBuilder.lconst_0(); + codeBuilder.lcmp(); + codeBuilder.ifeq(fail); + } // return true codeBuilder.iconst_1(); codeBuilder.ireturn(); @@ -294,6 +342,17 @@ private void methodTimestamp(CodeBuilder codeBuilder) { } private void methodShouldCommitStatic(CodeBuilder codeBuilder) { + methodShouldCommitStatic(codeBuilder, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT_LONG); + } + + private void methodShouldCommitThrottleStaticLongLong(CodeBuilder codeBuilder) { + methodShouldCommitStatic(codeBuilder, METHOD_EVENT_CONFIGURATION_SHOULD_THROTTLE_COMMIT_LONG_LONG); + } + private void methodShouldCommitThrottleStaticLong(CodeBuilder codeBuilder) { + methodShouldCommitStatic(codeBuilder, METHOD_EVENT_CONFIGURATION_SHOULD_THROTTLE_COMMIT_LONG); + } + + private void methodShouldCommitStatic(CodeBuilder codeBuilder, MethodDesc method) { Label fail = codeBuilder.newLabel(); if (guardEventConfiguration) { // if (eventConfiguration == null) goto fail; @@ -302,8 +361,10 @@ private void methodShouldCommitStatic(CodeBuilder codeBuilder) { } // return eventConfiguration.shouldCommit(duration); getEventConfiguration(codeBuilder); - codeBuilder.lload(0); - codeBuilder.invokevirtual(TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT.name(), METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT.descriptor()); + for (int i = 0 ; i < method.descriptor().parameterCount(); i++) { + codeBuilder.lload(2 * i); + } + codeBuilder.invokevirtual(TYPE_EVENT_CONFIGURATION, method.name(), method.descriptor()); codeBuilder.ireturn(); // fail: codeBuilder.labelBinding(fail); @@ -515,6 +576,28 @@ private static boolean isMethod(MethodModel m, MethodDesc desc) { return desc.matches(m); } + private void getDuration(CodeBuilder codeBuilder) { + codeBuilder.aload(0); + getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); + if (throttled) { + codeBuilder.loadConstant(MASK_NON_THROTTLE_BITS); + codeBuilder.land(); + } + } + + private void setDuration(CodeBuilder codeBuilder, Consumer expression) { + codeBuilder.aload(0); + expression.accept(codeBuilder); + if (throttled) { + codeBuilder.aload(0); + getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); + codeBuilder.loadConstant(MASK_THROTTLE_BITS); + codeBuilder.land(); + codeBuilder.lor(); + } + putfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); + } + private static void getEventWriter(CodeBuilder codeBuilder) { invokestatic(codeBuilder, TYPE_EVENT_WRITER, METHOD_GET_EVENT_WRITER); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java index ded1f78b76eff..8314437ce7283 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMSupport.java @@ -98,7 +98,7 @@ public static boolean isNotAvailable() { public static void tryToInitializeJVM() { } - static long nanosToTicks(long nanos) { + public static long nanosToTicks(long nanos) { return (long) (nanos * JVM.getTimeConversionFactor()); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataLoader.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataLoader.java index 60db375c87686..2d1332aed06b4 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataLoader.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataLoader.java @@ -45,11 +45,12 @@ import jdk.jfr.Relational; import jdk.jfr.StackTrace; import jdk.jfr.Threshold; +import jdk.jfr.Throttle; import jdk.jfr.TransitionFrom; import jdk.jfr.TransitionTo; import jdk.jfr.Unsigned; import jdk.jfr.internal.util.Utils; - +import jdk.jfr.internal.settings.ThrottleSetting; public final class MetadataLoader { // Caching to reduce allocation pressure and heap usage @@ -320,7 +321,7 @@ private Map buildTypeMap() { aes.add(new AnnotationElement(Cutoff.class, Cutoff.INFINITY)); } if (t.throttle) { - aes.add(new AnnotationElement(Throttle.class, Throttle.DEFAULT)); + aes.add(new AnnotationElement(Throttle.class, ThrottleSetting.DEFAULT_VALUE)); } } if (t.experimental) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java index 1c9c985fb26db..7f7c4a3e338cc 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java @@ -45,11 +45,13 @@ import jdk.jfr.Name; import jdk.jfr.Period; import jdk.jfr.SettingControl; +import jdk.jfr.Throttle; import jdk.jfr.ValueDescriptor; import jdk.jfr.internal.consumer.RepositoryFiles; import jdk.jfr.internal.event.EventConfiguration; import jdk.jfr.internal.management.HiddenWait; import jdk.jfr.internal.periodic.PeriodicEvents; +import jdk.jfr.internal.settings.Throttler; import jdk.jfr.internal.util.Utils; public final class MetadataRepository { @@ -210,9 +212,11 @@ private EventConfiguration makeConfiguration(Class= platformEventType.getThresholdTicks(); } + // Accessed by generated code in event class. Used by: + // static boolean shouldThrottleCommit(long duration, long timestamp) + public boolean shouldThrottleCommit(long duration, long timestamp) { + return isEnabled() && duration >= platformEventType.getThresholdTicks() && throttler.sample(timestamp); + } + + // Caller must of Event::shouldThrottleCommit must check enablement. + // Accessed by generated code in event class. Used by: + // static boolean shouldThrottleCommit(long timestamp) + public boolean shouldThrottleCommit(long timestamp) { + return throttler.sample(timestamp); + } + // Accessed by generated code in event class public SettingControl getSetting(int index) { return settings[index]; @@ -53,6 +69,19 @@ public boolean isEnabled() { return platformEventType.isCommittable(); } + public long throttle(long startTime, long rawDuration) { + // We have already tried to throttle, return as is + if ((rawDuration & EventInstrumentation.MASK_THROTTLE_BITS) != 0) { + return rawDuration; + } + long endTime = startTime + rawDuration; + if (throttler.sample(endTime)) { + return rawDuration | EventInstrumentation.MASK_THROTTLE_CHECK_SUCCESS; + } else { + return rawDuration | EventInstrumentation.MASK_THROTTLE_CHECK_FAIL; + } + } + // Not really part of the configuration, but the method // needs to be somewhere the event class can access, // but not part of the public API. diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java index 800443cfaed01..ab26b5fcd3146 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottleSetting.java @@ -38,7 +38,6 @@ import jdk.jfr.Name; import jdk.jfr.SettingControl; import jdk.jfr.internal.PlatformEventType; -import jdk.jfr.internal.Throttle; import jdk.jfr.internal.Type; import jdk.jfr.internal.util.Rate; import jdk.jfr.internal.util.TimespanUnit; @@ -49,7 +48,7 @@ @Description("Throttles the emission rate for an event") @Name(Type.SETTINGS_PREFIX + "Throttle") public final class ThrottleSetting extends SettingControl { - public static final String DEFAULT_VALUE = Throttle.DEFAULT; + public static final String DEFAULT_VALUE = "off"; private final PlatformEventType eventType; private final String defaultValue; private String value; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java new file mode 100644 index 0000000000000..605d5aa993772 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.internal.settings; + +import java.util.Random; +import java.util.concurrent.locks.ReentrantLock; +import jdk.jfr.internal.PlatformEventType; +public final class Throttler { + private static final ThrottlerParameters DISABLED_PARAMETERS = new ThrottlerParameters(0, 0, 0); + private static final long MILLIUNITS = 1000; + private static final long MINUTE = 60 * MILLIUNITS; + private static final long TEN_PER_1000_MS_IN_MINUTES = 600; + private static final long HOUR = 60 * MINUTE; + private static final long TEN_PER_1000_MS_IN_HOURS = 36000; + private static final long TEN_PER_1000_MS_IN_DAYS = 864000; + private static final long EVENT_THROTTLER_OFF = -2; + + private final ReentrantLock lock = new ReentrantLock(); + private final Random randomGenerator = new Random(); + private final ThrottlerWindow window0 = new ThrottlerWindow(); + private final ThrottlerWindow window1 = new ThrottlerWindow(); + + private volatile ThrottlerWindow activeWindow = window0; + + // Guarded by lock + private double averagePopulationSize; + private double ewmaPopulationSize; + private long accumulatedDebtCarryLimit; + private long accumulatedDebtCarryCount; + private ThrottlerParameters lastParameters = new ThrottlerParameters(0, 0, 0); + private long sampleSize; + private long periodMillis; + private volatile boolean disabled; + private boolean update = true; + + public Throttler(PlatformEventType t) { + } + // Not synchronized in fast path, but uses volatile reads. + public boolean sample(long ticks) { + if (disabled) { + return true; + } + ThrottlerWindow current = activeWindow; + if (current.isExpired(ticks)) { + if (lock.tryLock()) { + try { + rotateWindow(ticks); + } finally { + lock.unlock(); + } + } + return activeWindow.sample(); + } + return current.sample(); + } + + public void configure(long sampleSize, long periodMillis) { + lock.lock(); + try { + this.sampleSize = sampleSize; + this.periodMillis = periodMillis; + this.update = true; + this.activeWindow = configure(nextWindowParameters(), activeWindow); + } finally { + lock.unlock(); + } + } + + private ThrottlerWindow configure(ThrottlerParameters parameters, ThrottlerWindow expired) { + if (parameters.reconfigure) { + // Store updated params once to both windows + expired.parameters = parameters; + nextWindow(expired).parameters = parameters; + configure(parameters); + } + ThrottlerWindow next = setRate(parameters, expired); + next.initialize(parameters); + return next; + } + + private void configure(ThrottlerParameters parameters) { + averagePopulationSize = 0; + ewmaPopulationSize = computeEwmaAlphaCoefficient(parameters.windowLookBackCount); + accumulatedDebtCarryLimit = computeAccumulatedDebtCarryLimit(parameters); + accumulatedDebtCarryCount = accumulatedDebtCarryLimit; + parameters.reconfigure = false; + } + + private void rotateWindow(long ticks) { + ThrottlerWindow current = activeWindow; + if (current.isExpired(ticks)) { + activeWindow = configure(current.parameters.copy(), current); + } + } + + private ThrottlerWindow setRate(ThrottlerParameters parameters, ThrottlerWindow expired) { + ThrottlerWindow next = nextWindow(expired); + long projectedSampleSize = parameters.samplePointsPerWindow + amortizedDebt(expired); + if (projectedSampleSize == 0) { + next.projectedPopulationSize = 0; + return next; + } + next.samplingInterval = deriveSamplingInterval(projectedSampleSize, expired); + next.projectedPopulationSize = projectedSampleSize * next.samplingInterval; + return next; + } + + private long amortizedDebt(ThrottlerWindow expired) { + long accumulatedDebt = expired.accumulatedDebt(); + if (accumulatedDebtCarryCount == accumulatedDebtCarryLimit) { + accumulatedDebtCarryCount = 1; + return 0; + } + accumulatedDebtCarryCount++; + return -accumulatedDebt; + } + + private long deriveSamplingInterval(double sampleSize, ThrottlerWindow expired) { + double populationSize = projectPopulationSize(expired); + if (adjustBoundary(populationSize) <= adjustBoundary(sampleSize)) { + return 1; + } + double projectProbability = adjustBoundary(sampleSize) / adjustBoundary(populationSize); + return nextGeometric(adjustBoundary(projectProbability), randomGenerator.nextDouble()); + } + double projectPopulationSize(ThrottlerWindow expired) { + averagePopulationSize = exponentiallyWeightedMovingAverage(expired.populationSize(), ewmaPopulationSize, averagePopulationSize); + return averagePopulationSize; + } + + private static long nextGeometric(double p, double u) { + return (long) Math.ceil(Math.log(1.0 - adjustBoundary(u)) / Math.log(1.0 - p)); + } + + private static double adjustBoundary(double u) { + if (u == 0.0) { + return 0.01; + } + if (u == 1.0) { + return 0.99; + } + return u; + } + + private void normalize() { + if (periodMillis == MILLIUNITS) { + return; + } + if (periodMillis == MINUTE) { + if (sampleSize >= TEN_PER_1000_MS_IN_MINUTES) { + sampleSize /= 60; + periodMillis /= 60; + } + return; + } + if (periodMillis == HOUR) { + if (sampleSize >= TEN_PER_1000_MS_IN_HOURS) { + sampleSize /= 3600; + periodMillis /= 3600; + } + return; + } + if (sampleSize >= TEN_PER_1000_MS_IN_DAYS) { + sampleSize /= 86400; + periodMillis /= 86400; + } + } + + private ThrottlerParameters nextWindowParameters() { + if (update) { + return updateParameters(); + } + return disabled ? DISABLED_PARAMETERS : lastParameters; + } + + private ThrottlerParameters updateParameters() { + disabled = is_disabled(sampleSize); + if (disabled) { + return DISABLED_PARAMETERS; + } + normalize(); + lastParameters.setSamplePointsAndWindowDuration(sampleSize, periodMillis); + lastParameters.reconfigure = true; + update = false; + return lastParameters; + } + + private boolean is_disabled(long eventSampleSize) { + return eventSampleSize == EVENT_THROTTLER_OFF; + } + + private double exponentiallyWeightedMovingAverage(double y, double alpha, double s) { + return adjustBoundary(alpha) * adjustBoundary(y) + (1 - adjustBoundary(alpha)) * adjustBoundary(s); + } + + private double computeEwmaAlphaCoefficient(long lookBackCount) { + return lookBackCount <= 1 ? 1.0 : 1.0 / lookBackCount; + } + + private long computeAccumulatedDebtCarryLimit(ThrottlerParameters parameters) { + if (parameters.windowDurationMillis == 0 || parameters.windowDurationMillis >= 1000) { + return 1; + } + return 1000 / parameters.windowDurationMillis; + } + + private ThrottlerWindow nextWindow(ThrottlerWindow expired) { + return expired == window0 ? window1 : window0; + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottlerParameters.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottlerParameters.java new file mode 100644 index 0000000000000..68908fda2a6dd --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottlerParameters.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.internal.settings; + +final class ThrottlerParameters { + private static final long LOW_RATE_UPPER_BOUND = 9; + private static final long WINDOW_DIVISOR = 5; + private static final long MILLIUNITS = 1000; + private static final long MINUTE = 60 * MILLIUNITS; + private static final long TEN_PER_1000_MS_IN_MINUTES = 600; + private static final long HOUR = 60 * MINUTE; + private static final long TEN_PER_1000_MS_IN_HOURS = 36000; + private static final long DAY = 24 * HOUR; + private static final long TEN_PER_1000_MS_IN_DAYS = 864000; + private static final long DEFAULT_WINDOWS_LOOKBACK_COUNT = 25; // 25 windows == 5 seconds (for default window duration of 200 ms) + + long samplePointsPerWindow; + long windowDurationMillis; + long windowLookBackCount; + boolean reconfigure; + + ThrottlerParameters(long samplePointsPerWindow, long windowDuration, long windowLockBackCount) { + this.samplePointsPerWindow = samplePointsPerWindow; + this.windowDurationMillis = windowDuration; + this.windowLookBackCount = windowLockBackCount; + } + + public ThrottlerParameters copy() { + return new ThrottlerParameters(samplePointsPerWindow, windowDurationMillis, windowLookBackCount); + } + + void setSamplePointsAndWindowDuration(long sampleSize, long periodMillis) { + try { + if (sampleSize <= LOW_RATE_UPPER_BOUND) { + samplePointsPerWindow = sampleSize; + windowDurationMillis = periodMillis; + return; + } + if (periodMillis == MINUTE && sampleSize < TEN_PER_1000_MS_IN_MINUTES) { + samplePointsPerWindow = sampleSize; + windowDurationMillis = periodMillis; + return; + } + if (periodMillis == HOUR && sampleSize < TEN_PER_1000_MS_IN_HOURS) { + samplePointsPerWindow = sampleSize; + windowDurationMillis = periodMillis; + return; + } + if (periodMillis == DAY && sampleSize < TEN_PER_1000_MS_IN_DAYS) { + samplePointsPerWindow = sampleSize; + windowDurationMillis = periodMillis; + return; + } + samplePointsPerWindow = sampleSize / WINDOW_DIVISOR; + windowDurationMillis = periodMillis / WINDOW_DIVISOR; + } finally { + updateWindowLookback(); + } + } + + private void updateWindowLookback() { + if (windowDurationMillis <= MILLIUNITS) { + windowLookBackCount = DEFAULT_WINDOWS_LOOKBACK_COUNT; // 5 seconds + return; + } + if (windowDurationMillis == MINUTE) { + windowLookBackCount = 5; // 5 windows == 5 minutes + return; + } + windowLookBackCount = 1; // 1 window == 1 hour or 1 day + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottlerWindow.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottlerWindow.java new file mode 100644 index 0000000000000..1f772dd1953c7 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottlerWindow.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.internal.settings; + +import jdk.jfr.internal.JVMSupport; + +import java.util.StringJoiner; +import java.util.concurrent.atomic.AtomicLong; +import jdk.jfr.internal.JVM; + +final class ThrottlerWindow { + private final AtomicLong measuredPopulationSize = new AtomicLong(); + // Guarded by Throttler.lock. + ThrottlerParameters parameters = new ThrottlerParameters(0, 0, 0); + long samplingInterval = 1; + long projectedPopulationSize; + + private volatile long endTicks; + + void initialize(ThrottlerParameters parameters) { + if (parameters.windowDurationMillis == 0) { + endTicks = 0; + return; + } + measuredPopulationSize.set(0); + endTicks = JVM.counterTime() + + JVMSupport.nanosToTicks(1_000_000L * parameters.windowDurationMillis); + } + + boolean isExpired(long timestamp) { + long endTicks = this.endTicks; + if (timestamp == 0) { + return JVM.counterTime() >= endTicks; + } else { + return timestamp >= endTicks; + } + } + + boolean sample() { + long ordinal = measuredPopulationSize.incrementAndGet(); + return ordinal <= projectedPopulationSize && ordinal % samplingInterval == 0; + } + + long maxSampleSize() { + return samplingInterval == 0 ? 0 : projectedPopulationSize / samplingInterval; + } + + long sampleSize() { + long size = populationSize(); + return size > projectedPopulationSize ? maxSampleSize() : size / samplingInterval; + } + + long populationSize() { + return measuredPopulationSize.get(); + } + + long accumulatedDebt() { + if (projectedPopulationSize == 0) { + return 0; + } + return parameters.samplePointsPerWindow - maxSampleSize() + debt(); + } + + long debt() { + if (projectedPopulationSize == 0) { + return 0; + } + return sampleSize() - parameters.samplePointsPerWindow; + } + + public String toString() { + StringJoiner sb = new StringJoiner(", "); + sb.add("measuredPopulationSize=" + measuredPopulationSize); + sb.add("samplingInterval=" + samplingInterval); + sb.add("projectedPopulationSize=" + projectedPopulationSize); + return sb.toString(); + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/package-info.java b/src/jdk.jfr/share/classes/jdk/jfr/package-info.java index bd5b197d7fce2..54866ec508f59 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/package-info.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, 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 @@ -177,6 +177,28 @@ * {@code "false"} * * + * {@code throttle} + * Specifies the maximum rate of events per time unit. + * {@code "off"} (no throttling) + * + * "off", if events should not be throttled, otherwise a string representation of a positive {@code Long} value followed by forward slash ("/") and one of the following units: + *

+ * + * + * {@code "off"}
+ * {@code "100/s"}
+ * {@code "1000/m"} + * + * + * * {@code filter} * Specifies the filter for the event * {@code ""} (empty string) diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index 293af26746f1a..8ef65d73b5881 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -759,31 +759,35 @@ true true - 20 ms + 20 ms true true - 20 ms + 1 ms + 100/s true true - 20 ms + 1 ms + 100/s true true - 20 ms + 1 ms + 100/s true true - 20 ms + 1 ms + 100/s @@ -826,8 +830,9 @@ - false + true true + 100/s @@ -1126,20 +1131,27 @@ - + - - + + - + + + + + + + + @@ -1167,10 +1179,6 @@ 20 ms - 20 ms - - 20 ms - diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index 89a9022d11eb4..b5fad05fc4c72 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -759,31 +759,35 @@ true true - 10 ms + 10 ms true true - 10 ms + 1 ms + 300/s true true - 10 ms + 1 ms + 300/s true true - 10 ms + 1 ms + 300/s true true - 10 ms + 1 ms + 300/s @@ -826,8 +830,9 @@ - false + true true + 300/s @@ -1125,21 +1130,28 @@ - + - - + + - + - + + + + + + + + @@ -1166,10 +1178,6 @@ 10 ms - 10 ms - - 10 ms - diff --git a/test/jdk/jdk/jfr/api/metadata/annotations/TestThrottle.java b/test/jdk/jdk/jfr/api/metadata/annotations/TestThrottle.java new file mode 100644 index 0000000000000..da3bd311abb72 --- /dev/null +++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestThrottle.java @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2025, 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. + */ + +package jdk.jfr.api.metadata.annotations; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Constructor; +import java.time.Duration; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +import jdk.jfr.AnnotationElement; +import jdk.jfr.Event; +import jdk.jfr.EventType; +import jdk.jfr.MetadataDefinition; +import jdk.jfr.Name; +import jdk.jfr.Threshold; +import jdk.jfr.Enabled; +import jdk.jfr.Recording; +import jdk.jfr.SettingDefinition; +import jdk.jfr.SettingDescriptor; +import jdk.jfr.Throttle; +import jdk.jfr.ValueDescriptor; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingStream; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.Events; +import jdk.jfr.SettingControl; + +/** + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.api.metadata.annotations.TestThrottle + */ +public class TestThrottle { + + @Throttle("off") + @Enabled(false) + public static class ThrottledDisabledEvent extends Event { + } + + @Throttle("off") + public static class ThrottledOffEvent extends Event { + } + + @Throttle("0/s") + public static class ThrottledZeroRateEvent extends Event { + } + + @Throttle("10000000/s") + public static class ThrottledHighRateEvent extends Event { + } + + @Throttle("off") + @Threshold("5 h") + public static class ThrottledThresholdedEvent extends Event { + } + + @Throttle("50/s") + public static class ThrottledNormalRateEvent extends Event { + public int index; + } + + static class TestSetting extends SettingControl { + private boolean value; + + @Override + public String combine(Set values) { + if (values.contains("true")) { + return "true"; + } + if (values.contains("false")) { + return "false"; + } + return "true"; + } + + @Override + public void setValue(String text) { + value = Boolean.parseBoolean(text); + } + + @Override + public String getValue() { + return "" + value; + } + } + + @Throttle("10000000/s") + public static class ThrottledUserdefinedEvent extends Event { + @SettingDefinition + public boolean test(TestSetting control) { + return control.value; + } + } + + @Throttle("50/s") + public static class ThrottledReuseEvent extends Event { + public int index; + } + + public static void main(String[] args) throws Exception { + testThrottleDisabled(); + testThrottledOff(); + testThottleZeroRate(); + testThrottleHighRate(); + testThrottleThresholded(); + testThrottleNormalRate(); + testThrottleUserdefined(); + } + + private static void testThrottleDisabled() throws Exception { + testEvent(ThrottledDisabledEvent.class, false); + } + + private static void testThrottledOff() throws Exception { + testEvent(ThrottledOffEvent.class, true); + } + + private static void testThottleZeroRate() throws Exception { + testEvent(ThrottledZeroRateEvent.class, false); + } + + private static void testThrottleHighRate() throws Exception { + testEvent(ThrottledHighRateEvent.class, true); + } + + private static void testThrottleThresholded() throws Exception { + testEvent(ThrottledThresholdedEvent.class, false); + } + + private static void testThrottleNormalRate() throws Exception { + try (RecordingStream rs = new RecordingStream()) { + AtomicInteger lastIndex = new AtomicInteger(); + AtomicInteger throttled = new AtomicInteger(); + rs.onEvent(ThrottledNormalRateEvent.class.getName(), e -> { + int index = e.getInt("index"); + if (lastIndex.get() + 1 != index) { + throttled.incrementAndGet(); + } + lastIndex.set(index); + }); + rs.startAsync(); + int index = 1; + while (throttled.get() < 30) { + ThrottledNormalRateEvent e = new ThrottledNormalRateEvent(); + e.index = index; + e.commit(); + index++; + Thread.sleep(3); + } + } + } + + private static void testThrottleUserdefined() throws Exception { + testThrottleUserdefined("false", "1000000/s", false); + testThrottleUserdefined("true", "10000000/s", true); + testThrottleUserdefined("true", "0/s", false); + testThrottleUserdefined("true", "off", true); + testThrottleUserdefined("false", "off", false); + } + + private static void testThrottleUserdefined(String test, String throttle, boolean emit) throws Exception { + String eventName = ThrottledUserdefinedEvent.class.getName(); + try (Recording r = new Recording()) { + r.enable(eventName).with("test", test).with("throttle", throttle); + r.start(); + + ThrottledUserdefinedEvent e1 = new ThrottledUserdefinedEvent(); + e1.commit(); + + ThrottledUserdefinedEvent e2 = new ThrottledUserdefinedEvent(); + e2.begin(); + e2.commit(); + + ThrottledUserdefinedEvent e3 = new ThrottledUserdefinedEvent(); + e3.begin(); + e3.end(); + e3.commit(); + + ThrottledUserdefinedEvent e4 = new ThrottledUserdefinedEvent(); + if (e4.shouldCommit()) { + e4.commit(); + } + assertShouldCommit(e4, emit); + + ThrottledUserdefinedEvent e5 = new ThrottledUserdefinedEvent(); + assertShouldCommit(e5, emit); + if (e5.shouldCommit()) { + e5.commit(); + } + + r.stop(); + assertEvents(r, eventName, emit ? 5 : 0); + } + } + + @SuppressWarnings("unchecked") + private static void testEvent(Class eventClass, boolean shouldCommit) throws Exception { + try (Recording r = new Recording()) { + r.start(); + Constructor c = (Constructor) eventClass.getConstructor(); + for (int i = 0; i < 17; i++) { + Event e = c.newInstance(); + if (i % 5 == 0) { + assertShouldCommit(e, shouldCommit); + } + e.commit(); + if (i % 3 == 0) { + assertShouldCommit(e, shouldCommit); + } + } + for (int i = 0; i < 50; i++) { + Event e = c.newInstance(); + e.begin(); + if (i % 5 == 0) { + assertShouldCommit(e, shouldCommit); + } + e.end(); + if (i % 3 == 0) { + assertShouldCommit(e, shouldCommit); + } + e.commit(); + if (i % 7 == 0) { + assertShouldCommit(e, shouldCommit); + } + } + for (int i = 0; i < 11; i++) { + Event e = c.newInstance(); + e.begin(); + e.commit(); + if (i % 7 == 0) { + assertShouldCommit(e, shouldCommit); + } + } + if (shouldCommit) { + assertEvents(r, eventClass.getName(), 17 + 50 + 11); + } + } + } + + private static void assertEvents(Recording r, String name, int expected) throws Exception { + int count = 0; + for (RecordedEvent event : Events.fromRecording(r)) { + if (event.getEventType().getName().equals(name)) { + count++; + } + } + if (count != expected) { + throw new Exception("Expected " + expected + " " + name + " events, but found " + count); + } + } + + private static void assertShouldCommit(Event e, boolean expected) throws Exception { + if (e.shouldCommit() != expected) { + throw new Exception("Expected " + e.getClass() + "::shouldCommit() to return " + expected); + } + } +} diff --git a/test/jdk/jdk/jfr/api/recording/settings/TestSettingsAvailability.java b/test/jdk/jdk/jfr/api/recording/settings/TestSettingsAvailability.java index dc22644b4d034..bb23e56a2fed3 100644 --- a/test/jdk/jdk/jfr/api/recording/settings/TestSettingsAvailability.java +++ b/test/jdk/jdk/jfr/api/recording/settings/TestSettingsAvailability.java @@ -66,7 +66,7 @@ private static void testSettingPersistence() throws IOException, Exception { for (EventType parsedType : rf.readEventTypes()) { EventType inMem = inMemoryTypes.get(parsedType.getName()); if (inMem == null) { - throw new Exception("Superflous event type " + parsedType.getName() + " in recording"); + throw new Exception("Superfluous event type " + parsedType.getName() + " in recording"); } Set inMemsettings = new HashSet<>(); for (SettingDescriptor sd : inMem.getSettingDescriptors()) { @@ -75,7 +75,7 @@ private static void testSettingPersistence() throws IOException, Exception { for (SettingDescriptor parsedSetting : parsedType.getSettingDescriptors()) { if (!inMemsettings.contains(parsedSetting.getName())) { - throw new Exception("Superflous setting " + parsedSetting.getName() + " in " + parsedType.getName()); + throw new Exception("Superfluous setting " + parsedSetting.getName() + " in " + parsedType.getName()); } inMemsettings.remove(parsedSetting.getName()); } @@ -89,14 +89,14 @@ private static void testSettingPersistence() throws IOException, Exception { private static void testKnownSettings() throws Exception { testSetting(EventNames.JVMInformation, "enabled", "period"); - testSetting(EventNames.FileRead, "enabled", "threshold", "stackTrace"); - testSetting(EventNames.FileWrite, "enabled", "threshold","stackTrace"); + testSetting(EventNames.FileRead, "enabled", "threshold", "stackTrace", "throttle"); + testSetting(EventNames.FileWrite, "enabled", "threshold","stackTrace", "throttle"); testSetting(EventNames.ExceptionStatistics, "enabled", "period"); - testSetting(EventNames.SocketRead, "enabled", "threshold", "stackTrace"); - testSetting(EventNames.SocketWrite, "enabled", "threshold", "stackTrace"); + testSetting(EventNames.SocketRead, "enabled", "threshold", "stackTrace", "throttle"); + testSetting(EventNames.SocketWrite, "enabled", "threshold", "stackTrace", "throttle"); testSetting(EventNames.ActiveRecording, "enabled"); testSetting(EventNames.ActiveSetting, "enabled"); - testSetting(EventNames.JavaExceptionThrow, "enabled", "stackTrace"); + testSetting(EventNames.JavaExceptionThrow, "enabled", "stackTrace", "throttle"); } private static void testSetting(String eventName, String... settingNames) throws Exception { diff --git a/test/jdk/jdk/jfr/startupargs/TestEventSettings.java b/test/jdk/jdk/jfr/startupargs/TestEventSettings.java index 37af394affdfe..c86a6331c52e0 100644 --- a/test/jdk/jdk/jfr/startupargs/TestEventSettings.java +++ b/test/jdk/jdk/jfr/startupargs/TestEventSettings.java @@ -51,7 +51,7 @@ * jdk.jfr.startupargs.TestEventSettings multipleSettings * * @run main/othervm - * -XX:StartFlightRecording:class-loading=true,socket-threshold=100ms + * -XX:StartFlightRecording:class-loading=true,locking-threshold=100ms * jdk.jfr.startupargs.TestEventSettings jfcOptions */ public class TestEventSettings { @@ -70,7 +70,7 @@ public static void main(String... args) throws Exception { } case "jfcOptions" -> { assertSetting("jdk.ClassDefine#enabled","true"); - assertSetting("jdk.SocketRead#threshold", "100 ms"); + assertSetting("jdk.JavaMonitorEnter#threshold", "100 ms"); } default -> throw new Exception("Uknown tes " + subTest); } From 333515e3498df99b6e781a104c14c35affe60c3d Mon Sep 17 00:00:00 2001 From: erik_gahlin Date: Sat, 31 May 2025 13:01:45 +0200 Subject: [PATCH 02/10] Fix whitespace --- src/jdk.jfr/share/classes/jdk/jfr/Throttle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Throttle.java b/src/jdk.jfr/share/classes/jdk/jfr/Throttle.java index c13311aef43ba..8601c0e5638f9 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Throttle.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Throttle.java @@ -39,7 +39,7 @@ * If the event class annotated with {@code Throttle} are filtering by other * settings, such as a {@link jdk.jfr.Threshold} or a user-defined setting, the * throttling will happen after those settings have been applied. - * + * * @since 25 */ @MetadataDefinition From 27ded8e50f23f35bd2be88ac45528cab9f3bf59e Mon Sep 17 00:00:00 2001 From: erik_gahlin Date: Sat, 31 May 2025 15:00:10 +0200 Subject: [PATCH 03/10] Fix typos --- src/jdk.jfr/share/classes/jdk/jfr/Throttle.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Throttle.java b/src/jdk.jfr/share/classes/jdk/jfr/Throttle.java index 8601c0e5638f9..9762c4a880663 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Throttle.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Throttle.java @@ -36,7 +36,7 @@ * Event annotation, specifies the maximum rate of events per time unit, (for * example, {@code "100/s"}). *

- * If the event class annotated with {@code Throttle} are filtering by other + * If the event class annotated with {@code Throttle} are filtered by other * settings, such as a {@link jdk.jfr.Threshold} or a user-defined setting, the * throttling will happen after those settings have been applied. * @@ -55,7 +55,7 @@ /** * The throttle rate, for example {@code "100/s"}. *

- * String representation of a non-negative {@code Long} value followed by a + * String representation of a non-negative {@code long} value followed by a * forward slash ("/") and one of the following units:
*

    *
  • {@code "ns"} (nanoseconds)
  • From 73943e7a8029ec1f778592fce65b99d05a1a6574 Mon Sep 17 00:00:00 2001 From: erik_gahlin Date: Sat, 31 May 2025 15:11:32 +0200 Subject: [PATCH 04/10] Consistent annotation --- .gitignore | 1 + .../share/classes/jdk/jfr/events/ExceptionThrownEvent.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 57ed105e41bb5..9145a9fa67b06 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,5 @@ NashornProfile.txt /.gdbinit /.lldbinit **/core.[0-9]* +*.rej *.orig diff --git a/src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionThrownEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionThrownEvent.java index 244ca181e8a9b..41945aaf66cd2 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionThrownEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/events/ExceptionThrownEvent.java @@ -39,7 +39,7 @@ @Category("Java Application") @Description("An object derived from java.lang.Exception has been created") @RemoveFields("duration") -@Throttle("off") +@Throttle public final class ExceptionThrownEvent extends MirrorEvent { @Label("Message") From d0097506fd1ccfe9b163088da17b0cfb374dc158 Mon Sep 17 00:00:00 2001 From: erik_gahlin Date: Sun, 1 Jun 2025 22:52:35 +0200 Subject: [PATCH 05/10] Some reviewer feedback --- src/jdk.jfr/share/classes/jdk/jfr/Throttle.java | 2 +- .../jdk/jfr/internal/settings/Throttler.java | 13 +++++++------ .../jdk/jfr/internal/settings/ThrottlerWindow.java | 3 +-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Throttle.java b/src/jdk.jfr/share/classes/jdk/jfr/Throttle.java index 9762c4a880663..7b9771eba2be7 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Throttle.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Throttle.java @@ -36,7 +36,7 @@ * Event annotation, specifies the maximum rate of events per time unit, (for * example, {@code "100/s"}). *

    - * If the event class annotated with {@code Throttle} are filtered by other + * If the event class annotated with {@code Throttle} is filtered by other * settings, such as a {@link jdk.jfr.Threshold} or a user-defined setting, the * throttling will happen after those settings have been applied. * diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java index 605d5aa993772..53e2f92c9d15d 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java @@ -52,7 +52,7 @@ public final class Throttler { private ThrottlerParameters lastParameters = new ThrottlerParameters(0, 0, 0); private long sampleSize; private long periodMillis; - private volatile boolean disabled; + private boolean disabled; private boolean update = true; public Throttler(PlatformEventType t) { @@ -117,7 +117,7 @@ private void rotateWindow(long ticks) { private ThrottlerWindow setRate(ThrottlerParameters parameters, ThrottlerWindow expired) { ThrottlerWindow next = nextWindow(expired); - long projectedSampleSize = parameters.samplePointsPerWindow + amortizedDebt(expired); + long projectedSampleSize = parameters.samplePointsPerWindow + amortizeDebt(expired); if (projectedSampleSize == 0) { next.projectedPopulationSize = 0; return next; @@ -127,7 +127,7 @@ private ThrottlerWindow setRate(ThrottlerParameters parameters, ThrottlerWindow return next; } - private long amortizedDebt(ThrottlerWindow expired) { + private long amortizeDebt(ThrottlerWindow expired) { long accumulatedDebt = expired.accumulatedDebt(); if (accumulatedDebtCarryCount == accumulatedDebtCarryLimit) { accumulatedDebtCarryCount = 1; @@ -145,9 +145,10 @@ private long deriveSamplingInterval(double sampleSize, ThrottlerWindow expired) double projectProbability = adjustBoundary(sampleSize) / adjustBoundary(populationSize); return nextGeometric(adjustBoundary(projectProbability), randomGenerator.nextDouble()); } - double projectPopulationSize(ThrottlerWindow expired) { - averagePopulationSize = exponentiallyWeightedMovingAverage(expired.populationSize(), ewmaPopulationSize, averagePopulationSize); - return averagePopulationSize; + + private double projectPopulationSize(ThrottlerWindow expired) { + averagePopulationSize = exponentiallyWeightedMovingAverage(expired.populationSize(), ewmaPopulationSize, averagePopulationSize); + return averagePopulationSize; } private static long nextGeometric(double p, double u) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottlerWindow.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottlerWindow.java index 1f772dd1953c7..31fb6cab63c94 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottlerWindow.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/ThrottlerWindow.java @@ -45,8 +45,7 @@ void initialize(ThrottlerParameters parameters) { return; } measuredPopulationSize.set(0); - endTicks = JVM.counterTime() + - JVMSupport.nanosToTicks(1_000_000L * parameters.windowDurationMillis); + endTicks = JVM.counterTime() + JVMSupport.nanosToTicks(1_000_000L * parameters.windowDurationMillis); } boolean isExpired(long timestamp) { From 7fa2db19c8d5b2f83a9dc274daf38f668e79bacf Mon Sep 17 00:00:00 2001 From: erik_gahlin Date: Tue, 3 Jun 2025 14:47:30 +0200 Subject: [PATCH 06/10] Fix adjust boundary --- .../classes/jdk/jfr/internal/settings/Throttler.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java index 53e2f92c9d15d..df8f5a587008c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java @@ -139,11 +139,11 @@ private long amortizeDebt(ThrottlerWindow expired) { private long deriveSamplingInterval(double sampleSize, ThrottlerWindow expired) { double populationSize = projectPopulationSize(expired); - if (adjustBoundary(populationSize) <= adjustBoundary(sampleSize)) { + if (populationSize <= sampleSize) { return 1; } - double projectProbability = adjustBoundary(sampleSize) / adjustBoundary(populationSize); - return nextGeometric(adjustBoundary(projectProbability), randomGenerator.nextDouble()); + double projectProbability = sampleSize / populationSize; + return nextGeometric(projectProbability, randomGenerator.nextDouble()); } private double projectPopulationSize(ThrottlerWindow expired) { @@ -213,7 +213,7 @@ private boolean is_disabled(long eventSampleSize) { } private double exponentiallyWeightedMovingAverage(double y, double alpha, double s) { - return adjustBoundary(alpha) * adjustBoundary(y) + (1 - adjustBoundary(alpha)) * adjustBoundary(s); + return alpha * y + (1 - alpha) * s; } private double computeEwmaAlphaCoefficient(long lookBackCount) { From 7f26f1720a1202e49a3daa385d24168a87e51100 Mon Sep 17 00:00:00 2001 From: erik_gahlin Date: Thu, 5 Jun 2025 11:22:31 +0200 Subject: [PATCH 07/10] Use offer method --- .../classes/java/io/FileInputStream.java | 20 +- .../classes/java/io/FileOutputStream.java | 12 +- .../classes/java/io/RandomAccessFile.java | 31 +- .../share/classes/java/net/Socket.java | 12 +- .../jdk/internal/event/FileReadEvent.java | 24 +- .../jdk/internal/event/FileWriteEvent.java | 23 +- .../jdk/internal/event/SocketReadEvent.java | 3 +- .../jdk/internal/event/SocketWriteEvent.java | 5 +- .../classes/sun/nio/ch/FileChannelImpl.java | 57 +-- t.txt | 410 ++++++++++++++++++ 10 files changed, 482 insertions(+), 115 deletions(-) create mode 100644 t.txt diff --git a/src/java.base/share/classes/java/io/FileInputStream.java b/src/java.base/share/classes/java/io/FileInputStream.java index aec653433849f..f112691ebc78e 100644 --- a/src/java.base/share/classes/java/io/FileInputStream.java +++ b/src/java.base/share/classes/java/io/FileInputStream.java @@ -205,24 +205,18 @@ public int read() throws IOException { private int traceRead0() throws IOException { int result = 0; - boolean endOfFile = false; long bytesRead = 0; long start = 0; try { start = FileReadEvent.timestamp(); result = read0(); if (result < 0) { - endOfFile = true; + bytesRead = -1; } else { bytesRead = 1; } } finally { - long end = FileReadEvent.timestamp(); - long duration = end - start; - if (FileReadEvent.shouldThrottleCommit(duration, end)) { - FileReadEvent.commit(start, duration, path, bytesRead, endOfFile); - } - + FileReadEvent.offer(start, path, bytesRead); } return result; } @@ -243,15 +237,7 @@ private int traceReadBytes(byte b[], int off, int len) throws IOException { start = FileReadEvent.timestamp(); bytesRead = readBytes(b, off, len); } finally { - long end = FileReadEvent.timestamp(); - long duration = end - start; - if (FileReadEvent.shouldThrottleCommit(duration, end)) { - if (bytesRead < 0) { - FileReadEvent.commit(start, duration, path, 0L, true); - } else { - FileReadEvent.commit(start, duration, path, bytesRead, false); - } - } + FileReadEvent.offer(start, path, bytesRead); } return bytesRead; } diff --git a/src/java.base/share/classes/java/io/FileOutputStream.java b/src/java.base/share/classes/java/io/FileOutputStream.java index ebedce2b73e4b..f44eaee13b131 100644 --- a/src/java.base/share/classes/java/io/FileOutputStream.java +++ b/src/java.base/share/classes/java/io/FileOutputStream.java @@ -272,11 +272,7 @@ private void traceWrite(int b, boolean append) throws IOException { write(b, append); bytesWritten = 1; } finally { - long end = FileWriteEvent.timestamp(); - long duration = end - start; - if (FileWriteEvent.shouldThrottleCommit(duration, end)) { - FileWriteEvent.commit(start, duration, path, bytesWritten); - } + FileWriteEvent.offer(start, path, bytesWritten); } } @@ -317,11 +313,7 @@ private void traceWriteBytes(byte b[], int off, int len, boolean append) throws writeBytes(b, off, len, append); bytesWritten = len; } finally { - long end = FileWriteEvent.timestamp(); - long duration = end - start; - if (FileWriteEvent.shouldThrottleCommit(duration, end)) { - FileWriteEvent.commit(start, duration, path, bytesWritten); - } + FileWriteEvent.offer(start, path, bytesWritten); } } diff --git a/src/java.base/share/classes/java/io/RandomAccessFile.java b/src/java.base/share/classes/java/io/RandomAccessFile.java index 9200022582b43..f3a20634d61dc 100644 --- a/src/java.base/share/classes/java/io/RandomAccessFile.java +++ b/src/java.base/share/classes/java/io/RandomAccessFile.java @@ -367,22 +367,17 @@ public int read() throws IOException { private int traceRead0() throws IOException { int result = 0; long bytesRead = 0; - boolean endOfFile = false; long start = 0; try { start = FileReadEvent.timestamp(); result = read0(); if (result < 0) { - endOfFile = true; + bytesRead = -1; } else { bytesRead = 1; } } finally { - long end = FileReadEvent.timestamp(); - long duration = end - start; - if (FileReadEvent.shouldThrottleCommit(duration, end)) { - FileReadEvent.commit(start, duration, path, bytesRead, endOfFile); - } + FileReadEvent.offer(start, path, bytesRead); } return result; } @@ -410,15 +405,7 @@ private int traceReadBytes0(byte b[], int off, int len) throws IOException { start = FileReadEvent.timestamp(); bytesRead = readBytes0(b, off, len); } finally { - long end = FileReadEvent.timestamp(); - long duration = end - start; - if (FileReadEvent.shouldThrottleCommit(duration, end)) { - if (bytesRead < 0) { - FileReadEvent.commit(start, duration, path, 0L, true); - } else { - FileReadEvent.commit(start, duration, path, bytesRead, false); - } - } + FileReadEvent.offer(start, path, bytesRead); } return bytesRead; } @@ -590,11 +577,7 @@ private void traceImplWrite(int b) throws IOException { implWrite(b); bytesWritten = 1; } finally { - long end = FileWriteEvent.timestamp(); - long duration = end - start; - if (FileWriteEvent.shouldThrottleCommit(duration, end)) { - FileWriteEvent.commit(start, duration, path, bytesWritten); - } + FileWriteEvent.offer(start, path, bytesWritten); } } @@ -633,11 +616,7 @@ private void traceImplWriteBytes(byte b[], int off, int len) throws IOException implWriteBytes(b, off, len); bytesWritten = len; } finally { - long end = FileWriteEvent.timestamp(); - long duration = end - start; - if (FileWriteEvent.shouldThrottleCommit(duration, end)) { - FileWriteEvent.commit(start, duration, path, bytesWritten); - } + FileWriteEvent.offer(start, path, bytesWritten); } } diff --git a/src/java.base/share/classes/java/net/Socket.java b/src/java.base/share/classes/java/net/Socket.java index 7bd81f361fd10..2905a51b402c6 100644 --- a/src/java.base/share/classes/java/net/Socket.java +++ b/src/java.base/share/classes/java/net/Socket.java @@ -965,11 +965,7 @@ public int read(byte[] b, int off, int len) throws IOException { } long start = SocketReadEvent.timestamp(); int nbytes = implRead(b, off, len); - long end = SocketReadEvent.timestamp(); - long duration = end - start; - if (SocketReadEvent.shouldThrottleCommit(duration, end)) { - SocketReadEvent.emit(start, duration, nbytes, parent.getRemoteSocketAddress(), getSoTimeout()); - } + SocketReadEvent.offer(start, nbytes, parent.getRemoteSocketAddress(), getSoTimeout()); return nbytes; } @@ -1082,11 +1078,7 @@ public void write(byte[] b, int off, int len) throws IOException { } long start = SocketWriteEvent.timestamp(); implWrite(b, off, len); - long end = SocketWriteEvent.timestamp(); - long duration = end - start; - if (SocketWriteEvent.shouldThrottleCommit(duration, end)) { - SocketWriteEvent.emit(start, duration, len, parent.getRemoteSocketAddress()); - } + SocketWriteEvent.offer(start, len, parent.getRemoteSocketAddress()); } private void implWrite(byte[] b, int off, int len) throws IOException { diff --git a/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java b/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java index 741897d837402..77b2568802e83 100644 --- a/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java @@ -45,11 +45,33 @@ public static long timestamp() { return 0L; } - public static boolean shouldThrottleCommit(long duration, long timestamp) { + public static boolean shouldThrottleCommit(long duration, long end) { // Generated by JFR return false; } + /** + * Helper method to offer the data needed to potentially commit an event. + * The duration of the operation is computed using the current + * timestamp and the given start time. If the duration meets + * or exceeds the configured value and is not throttled (determined by calling the + * generated method {@link #shouldThrottleCommit(long, long)}), an event will be + * emitted by calling {@link #commit(long, long, String, long, boolean)} + * + * @param start the start time + * @param path the path + * @param bytesRead the number of bytes that were read, or -1 if the end of the file was reached + */ + public static void offer(long start, String path, long bytesRead) { + long end = timestamp(); + long duration = end - start; + if (shouldThrottleCommit(duration, end)) { + boolean endOfFile = bytesRead < 0; + long bytes = endOfFile ? 0 : bytesRead; + commit(start, duration, path, bytes, endOfFile); + } + } + public static void commit(long start, long duration, String path, long bytesRead, boolean endOfFile) { // Generated by JFR } diff --git a/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java b/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java index 80e689c2b9c08..3fa7dbe9822ef 100644 --- a/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java @@ -44,11 +44,32 @@ public static long timestamp() { return 0L; } - public static boolean shouldThrottleCommit(long duration, long timestamp) { + public static boolean shouldThrottleCommit(long duration, long end) { // Generated by JFR return false; } + /** + * Helper method to offer the data needed to potentially commit an event. + * The duration of the operation is computed using the current + * timestamp and the given start time. If the duration meets + * or exceeds the configured value and is not throttled (determined by calling the + * generated method {@link #shouldThrottleCommit(long, long)}), an event will be + * emitted by calling {@link #commit(long, long, String, long)} + * + * @param start the start time + * @param path the path + * @param bytesRead the number of bytes that were written, or -1 if the end of the file was reached + */ + public static void offer(long start, String path, long bytesWritten) { + long end = timestamp(); + long duration = end - start; + if (shouldThrottleCommit(duration, end)) { + long bytes = bytesWritten > 0 ? bytesWritten : 0; + commit(start, duration, path, bytes); + } + } + public static void commit(long start, long duration, String path, long bytesWritten) { // Generated by JFR } diff --git a/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java b/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java index da6d9eec60797..09b3f23b07f66 100644 --- a/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java @@ -74,9 +74,10 @@ public static void commit(long start, long duration, String host, String address * of this method is generated automatically if jfr is enabled. * * @param duration time in nanoseconds to complete the operation + * @param end timestamp at the end of the operation * @return true if the event should be commited */ - public static boolean shouldThrottleCommit(long duration, long timestamp) { + public static boolean shouldThrottleCommit(long duration, long end) { // Generated by JFR return false; } diff --git a/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java b/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java index d0e0ad2cd04b5..12d8ffbf65b3e 100644 --- a/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java @@ -68,10 +68,11 @@ public static void commit(long start, long duration, String host, String address * must exceed some threshold in order to commit the event. The implementation * of this method is generated automatically if jfr is enabled. * - * @param duration time in nanoseconds to complete the operation + * @param duration time to complete the operation + * @param end timestamp at the end of the operation * @return true if the event should be commited */ - public static boolean shouldThrottleCommit(long duration, long timestamp) { + public static boolean shouldThrottleCommit(long duration, long end) { // Generated by JFR return false; } diff --git a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java index 56a3a8f177536..ceeea75b0fd6b 100644 --- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java @@ -269,15 +269,7 @@ private int traceImplRead(ByteBuffer dst) throws IOException { start = FileReadEvent.timestamp(); bytesRead = implRead(dst); } finally { - long end = FileReadEvent.timestamp(); - long duration = end - start; - if (FileReadEvent.shouldThrottleCommit(duration, end)) { - if (bytesRead < 0) { - FileReadEvent.commit(start, duration, path, 0L, true); - } else { - FileReadEvent.commit(start, duration, path, bytesRead, false); - } - } + FileReadEvent.offer(start, path, bytesRead); } return bytesRead; } @@ -333,14 +325,7 @@ private long traceImplRead(ByteBuffer[] dsts, int offset, int length) throws IOE bytesRead = implRead(dsts, offset, length); } finally { long end = FileReadEvent.timestamp(); - long duration = end - start; - if (FileReadEvent.shouldThrottleCommit(duration, end)) { - if (bytesRead < 0) { - FileReadEvent.commit(start, duration, path, 0L, true); - } else { - FileReadEvent.commit(start, duration, path, bytesRead, false); - } - } + FileReadEvent.offer(start, path, bytesRead); } return bytesRead; } @@ -386,20 +371,15 @@ private int implWrite(ByteBuffer src) throws IOException { } private int traceImplWrite(ByteBuffer src) throws IOException { - int bytesWritten = 0; + int bytes = 0; long start = 0; try { start = FileWriteEvent.timestamp(); - bytesWritten = implWrite(src); + bytes = implWrite(src); } finally { - long end = FileWriteEvent.timestamp(); - long duration = end - start; - if (FileWriteEvent.shouldThrottleCommit(duration, end)) { - long bytes = bytesWritten > 0 ? bytesWritten : 0; - FileWriteEvent.commit(start, duration, path, bytes); - } + FileWriteEvent.offer(start, path, bytes); } - return bytesWritten; + return bytes; } @Override @@ -449,12 +429,7 @@ private long traceImplWrite(ByteBuffer[] srcs, int offset, int length) throws IO start = FileWriteEvent.timestamp(); bytesWritten = implWrite(srcs, offset, length); } finally { - long end = FileWriteEvent.timestamp(); - long duration = end - start; - if (FileWriteEvent.shouldThrottleCommit(duration, end)) { - long bytes = bytesWritten > 0 ? bytesWritten : 0; - FileWriteEvent.commit(start, duration, path, bytes); - } + FileWriteEvent.offer(start, path, bytesWritten); } return bytesWritten; } @@ -1208,15 +1183,7 @@ private int traceImplRead(ByteBuffer dst, long position) throws IOException { start = FileReadEvent.timestamp(); bytesRead = implRead(dst, position); } finally { - long end = FileReadEvent.timestamp(); - long duration = end - start; - if (FileReadEvent.shouldThrottleCommit(duration, end)) { - if (bytesRead < 0) { - FileReadEvent.commit(start, duration, path, 0L, true); - } else { - FileReadEvent.commit(start, duration, path, bytesRead, false); - } - } + FileReadEvent.offer(start, path, bytesRead); } return bytesRead; } @@ -1281,12 +1248,8 @@ private int traceImplWrite(ByteBuffer src, long position) throws IOException { start = FileWriteEvent.timestamp(); bytesWritten = implWrite(src, position); } finally { - long end = FileWriteEvent.timestamp(); - long duration = end - start; - if (FileWriteEvent.shouldThrottleCommit(duration, end)) { - long bytes = bytesWritten > 0 ? bytesWritten : 0; - FileWriteEvent.commit(start, duration, path, bytes); - } + long bytes = bytesWritten > 0 ? bytesWritten : 0; + FileWriteEvent.offer(start, path, bytes); } return bytesWritten; } diff --git a/t.txt b/t.txt new file mode 100644 index 0000000000000..66754a95b68aa --- /dev/null +++ b/t.txt @@ -0,0 +1,410 @@ +diff --git a/src/java.base/share/classes/java/io/FileInputStream.java b/src/java.base/share/classes/java/io/FileInputStream.java +index aec65343384..f112691ebc7 100644 +--- a/src/java.base/share/classes/java/io/FileInputStream.java ++++ b/src/java.base/share/classes/java/io/FileInputStream.java +@@ -205,24 +205,18 @@ public int read() throws IOException { + + private int traceRead0() throws IOException { + int result = 0; +- boolean endOfFile = false; + long bytesRead = 0; + long start = 0; + try { + start = FileReadEvent.timestamp(); + result = read0(); + if (result < 0) { +- endOfFile = true; ++ bytesRead = -1; + } else { + bytesRead = 1; + } + } finally { +- long end = FileReadEvent.timestamp(); +- long duration = end - start; +- if (FileReadEvent.shouldThrottleCommit(duration, end)) { +- FileReadEvent.commit(start, duration, path, bytesRead, endOfFile); +- } +- ++ FileReadEvent.offer(start, path, bytesRead); + } + return result; + } +@@ -243,15 +237,7 @@ private int traceReadBytes(byte b[], int off, int len) throws IOException { + start = FileReadEvent.timestamp(); + bytesRead = readBytes(b, off, len); + } finally { +- long end = FileReadEvent.timestamp(); +- long duration = end - start; +- if (FileReadEvent.shouldThrottleCommit(duration, end)) { +- if (bytesRead < 0) { +- FileReadEvent.commit(start, duration, path, 0L, true); +- } else { +- FileReadEvent.commit(start, duration, path, bytesRead, false); +- } +- } ++ FileReadEvent.offer(start, path, bytesRead); + } + return bytesRead; + } +diff --git a/src/java.base/share/classes/java/io/FileOutputStream.java b/src/java.base/share/classes/java/io/FileOutputStream.java +index ebedce2b73e..f44eaee13b1 100644 +--- a/src/java.base/share/classes/java/io/FileOutputStream.java ++++ b/src/java.base/share/classes/java/io/FileOutputStream.java +@@ -272,11 +272,7 @@ private void traceWrite(int b, boolean append) throws IOException { + write(b, append); + bytesWritten = 1; + } finally { +- long end = FileWriteEvent.timestamp(); +- long duration = end - start; +- if (FileWriteEvent.shouldThrottleCommit(duration, end)) { +- FileWriteEvent.commit(start, duration, path, bytesWritten); +- } ++ FileWriteEvent.offer(start, path, bytesWritten); + } + } + +@@ -317,11 +313,7 @@ private void traceWriteBytes(byte b[], int off, int len, boolean append) throws + writeBytes(b, off, len, append); + bytesWritten = len; + } finally { +- long end = FileWriteEvent.timestamp(); +- long duration = end - start; +- if (FileWriteEvent.shouldThrottleCommit(duration, end)) { +- FileWriteEvent.commit(start, duration, path, bytesWritten); +- } ++ FileWriteEvent.offer(start, path, bytesWritten); + } + } + +diff --git a/src/java.base/share/classes/java/io/RandomAccessFile.java b/src/java.base/share/classes/java/io/RandomAccessFile.java +index 9200022582b..f3a20634d61 100644 +--- a/src/java.base/share/classes/java/io/RandomAccessFile.java ++++ b/src/java.base/share/classes/java/io/RandomAccessFile.java +@@ -367,22 +367,17 @@ public int read() throws IOException { + private int traceRead0() throws IOException { + int result = 0; + long bytesRead = 0; +- boolean endOfFile = false; + long start = 0; + try { + start = FileReadEvent.timestamp(); + result = read0(); + if (result < 0) { +- endOfFile = true; ++ bytesRead = -1; + } else { + bytesRead = 1; + } + } finally { +- long end = FileReadEvent.timestamp(); +- long duration = end - start; +- if (FileReadEvent.shouldThrottleCommit(duration, end)) { +- FileReadEvent.commit(start, duration, path, bytesRead, endOfFile); +- } ++ FileReadEvent.offer(start, path, bytesRead); + } + return result; + } +@@ -410,15 +405,7 @@ private int traceReadBytes0(byte b[], int off, int len) throws IOException { + start = FileReadEvent.timestamp(); + bytesRead = readBytes0(b, off, len); + } finally { +- long end = FileReadEvent.timestamp(); +- long duration = end - start; +- if (FileReadEvent.shouldThrottleCommit(duration, end)) { +- if (bytesRead < 0) { +- FileReadEvent.commit(start, duration, path, 0L, true); +- } else { +- FileReadEvent.commit(start, duration, path, bytesRead, false); +- } +- } ++ FileReadEvent.offer(start, path, bytesRead); + } + return bytesRead; + } +@@ -590,11 +577,7 @@ private void traceImplWrite(int b) throws IOException { + implWrite(b); + bytesWritten = 1; + } finally { +- long end = FileWriteEvent.timestamp(); +- long duration = end - start; +- if (FileWriteEvent.shouldThrottleCommit(duration, end)) { +- FileWriteEvent.commit(start, duration, path, bytesWritten); +- } ++ FileWriteEvent.offer(start, path, bytesWritten); + } + } + +@@ -633,11 +616,7 @@ private void traceImplWriteBytes(byte b[], int off, int len) throws IOException + implWriteBytes(b, off, len); + bytesWritten = len; + } finally { +- long end = FileWriteEvent.timestamp(); +- long duration = end - start; +- if (FileWriteEvent.shouldThrottleCommit(duration, end)) { +- FileWriteEvent.commit(start, duration, path, bytesWritten); +- } ++ FileWriteEvent.offer(start, path, bytesWritten); + } + } + +diff --git a/src/java.base/share/classes/java/net/Socket.java b/src/java.base/share/classes/java/net/Socket.java +index 7bd81f361fd..2905a51b402 100644 +--- a/src/java.base/share/classes/java/net/Socket.java ++++ b/src/java.base/share/classes/java/net/Socket.java +@@ -965,11 +965,7 @@ public int read(byte[] b, int off, int len) throws IOException { + } + long start = SocketReadEvent.timestamp(); + int nbytes = implRead(b, off, len); +- long end = SocketReadEvent.timestamp(); +- long duration = end - start; +- if (SocketReadEvent.shouldThrottleCommit(duration, end)) { +- SocketReadEvent.emit(start, duration, nbytes, parent.getRemoteSocketAddress(), getSoTimeout()); +- } ++ SocketReadEvent.offer(start, nbytes, parent.getRemoteSocketAddress(), getSoTimeout()); + return nbytes; + } + +@@ -1082,11 +1078,7 @@ public void write(byte[] b, int off, int len) throws IOException { + } + long start = SocketWriteEvent.timestamp(); + implWrite(b, off, len); +- long end = SocketWriteEvent.timestamp(); +- long duration = end - start; +- if (SocketWriteEvent.shouldThrottleCommit(duration, end)) { +- SocketWriteEvent.emit(start, duration, len, parent.getRemoteSocketAddress()); +- } ++ SocketWriteEvent.offer(start, len, parent.getRemoteSocketAddress()); + } + + private void implWrite(byte[] b, int off, int len) throws IOException { +diff --git a/src/java.base/share/classes/jdk/internal/event/FileForceEvent.java b/src/java.base/share/classes/jdk/internal/event/FileForceEvent.java +index f6dec6c8a5e..fe7c351ca53 100644 +--- a/src/java.base/share/classes/jdk/internal/event/FileForceEvent.java ++++ b/src/java.base/share/classes/jdk/internal/event/FileForceEvent.java +@@ -43,7 +43,7 @@ public class FileForceEvent extends Event { + /** + * Helper method to offer the data needed to potentially commit an event. + * The duration of the operation is computed using the current +- * timestamp and the given start time. If the duration is meets ++ * timestamp and the given start time. If the duration is meets + * or exceeds the configured value (determined by calling the generated method + * {@link #shouldCommit(long)}), an event will be emitted by calling + * {@link #commit(long, long, String, boolean)}. +diff --git a/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java b/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java +index 741897d8374..eb711687cc4 100644 +--- a/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java ++++ b/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java +@@ -45,11 +45,33 @@ public static long timestamp() { + return 0L; + } + +- public static boolean shouldThrottleCommit(long duration, long timestamp) { ++ static boolean shouldThrottleCommit(long duration, long end) { + // Generated by JFR + return false; + } + ++ /** ++ * Helper method to offer the data needed to potentially commit an event. ++ * The duration of the operation is computed using the current ++ * timestamp and the given start time. If the duration meets ++ * or exceeds the configured value and is not throttled (determined by calling the ++ * generated method {@link #shouldThrottleCommit(long, long)}), an event will be ++ * emitted by calling {@link #commit(long, long, String, long, boolean)} ++ * ++ * @param start the start time ++ * @param path the path ++ * @param bytesRead the number of bytes that were read, or -1 if the end of the file was reached ++ */ ++ public static void offer(long start, String path, long bytesRead) { ++ long end = timestamp(); ++ long duration = end - start; ++ if (shouldThrottleCommit(duration, end)) { ++ boolean endOfFile = bytesRead < 0; ++ long bytes = endOfFile ? 0 : bytesRead; ++ commit(start, duration, path, bytes, endOfFile); ++ } ++ } ++ + public static void commit(long start, long duration, String path, long bytesRead, boolean endOfFile) { + // Generated by JFR + } +diff --git a/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java b/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java +index 80e689c2b9c..8b3d6ab0e5d 100644 +--- a/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java ++++ b/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java +@@ -44,11 +44,32 @@ public static long timestamp() { + return 0L; + } + +- public static boolean shouldThrottleCommit(long duration, long timestamp) { ++ static boolean shouldThrottleCommit(long duration, long end) { + // Generated by JFR + return false; + } + ++ /** ++ * Helper method to offer the data needed to potentially commit an event. ++ * The duration of the operation is computed using the current ++ * timestamp and the given start time. If the duration meets ++ * or exceeds the configured value and is not throttled (determined by calling the ++ * generated method {@link #shouldThrottleCommit(long, long)}), an event will be ++ * emitted by calling {@link #commit(long, long, String, long)} ++ * ++ * @param start the start time ++ * @param path the path ++ * @param bytesRead the number of bytes that were written, or -1 if the end of the file was reached ++ */ ++ public static void offer(long start, String path, long bytesWritten) { ++ long end = timestamp(); ++ long duration = end - start; ++ if (shouldThrottleCommit(duration, end)) { ++ long bytes = bytesWritten > 0 ? bytesWritten : 0; ++ commit(start, duration, path, bytes); ++ } ++ } ++ + public static void commit(long start, long duration, String path, long bytesWritten) { + // Generated by JFR + } +diff --git a/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java b/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java +index da6d9eec607..48a15214a30 100644 +--- a/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java ++++ b/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java +@@ -74,9 +74,10 @@ public static void commit(long start, long duration, String host, String address + * of this method is generated automatically if jfr is enabled. + * + * @param duration time in nanoseconds to complete the operation ++ * @param end timestamp at the end of the operation + * @return true if the event should be commited + */ +- public static boolean shouldThrottleCommit(long duration, long timestamp) { ++ static boolean shouldThrottleCommit(long duration, long end) { + // Generated by JFR + return false; + } +diff --git a/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java b/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java +index d0e0ad2cd04..7b398647198 100644 +--- a/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java ++++ b/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java +@@ -69,9 +69,10 @@ public static void commit(long start, long duration, String host, String address + * of this method is generated automatically if jfr is enabled. + * + * @param duration time in nanoseconds to complete the operation ++ * @param end timestamp at the end of the operation + * @return true if the event should be commited + */ +- public static boolean shouldThrottleCommit(long duration, long timestamp) { ++ static boolean shouldThrottleCommit(long duration, long end) { + // Generated by JFR + return false; + } +diff --git a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +index 56a3a8f1775..ceeea75b0fd 100644 +--- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java ++++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +@@ -269,15 +269,7 @@ private int traceImplRead(ByteBuffer dst) throws IOException { + start = FileReadEvent.timestamp(); + bytesRead = implRead(dst); + } finally { +- long end = FileReadEvent.timestamp(); +- long duration = end - start; +- if (FileReadEvent.shouldThrottleCommit(duration, end)) { +- if (bytesRead < 0) { +- FileReadEvent.commit(start, duration, path, 0L, true); +- } else { +- FileReadEvent.commit(start, duration, path, bytesRead, false); +- } +- } ++ FileReadEvent.offer(start, path, bytesRead); + } + return bytesRead; + } +@@ -333,14 +325,7 @@ private long traceImplRead(ByteBuffer[] dsts, int offset, int length) throws IOE + bytesRead = implRead(dsts, offset, length); + } finally { + long end = FileReadEvent.timestamp(); +- long duration = end - start; +- if (FileReadEvent.shouldThrottleCommit(duration, end)) { +- if (bytesRead < 0) { +- FileReadEvent.commit(start, duration, path, 0L, true); +- } else { +- FileReadEvent.commit(start, duration, path, bytesRead, false); +- } +- } ++ FileReadEvent.offer(start, path, bytesRead); + } + return bytesRead; + } +@@ -386,20 +371,15 @@ private int implWrite(ByteBuffer src) throws IOException { + } + + private int traceImplWrite(ByteBuffer src) throws IOException { +- int bytesWritten = 0; ++ int bytes = 0; + long start = 0; + try { + start = FileWriteEvent.timestamp(); +- bytesWritten = implWrite(src); ++ bytes = implWrite(src); + } finally { +- long end = FileWriteEvent.timestamp(); +- long duration = end - start; +- if (FileWriteEvent.shouldThrottleCommit(duration, end)) { +- long bytes = bytesWritten > 0 ? bytesWritten : 0; +- FileWriteEvent.commit(start, duration, path, bytes); +- } ++ FileWriteEvent.offer(start, path, bytes); + } +- return bytesWritten; ++ return bytes; + } + + @Override +@@ -449,12 +429,7 @@ private long traceImplWrite(ByteBuffer[] srcs, int offset, int length) throws IO + start = FileWriteEvent.timestamp(); + bytesWritten = implWrite(srcs, offset, length); + } finally { +- long end = FileWriteEvent.timestamp(); +- long duration = end - start; +- if (FileWriteEvent.shouldThrottleCommit(duration, end)) { +- long bytes = bytesWritten > 0 ? bytesWritten : 0; +- FileWriteEvent.commit(start, duration, path, bytes); +- } ++ FileWriteEvent.offer(start, path, bytesWritten); + } + return bytesWritten; + } +@@ -1208,15 +1183,7 @@ private int traceImplRead(ByteBuffer dst, long position) throws IOException { + start = FileReadEvent.timestamp(); + bytesRead = implRead(dst, position); + } finally { +- long end = FileReadEvent.timestamp(); +- long duration = end - start; +- if (FileReadEvent.shouldThrottleCommit(duration, end)) { +- if (bytesRead < 0) { +- FileReadEvent.commit(start, duration, path, 0L, true); +- } else { +- FileReadEvent.commit(start, duration, path, bytesRead, false); +- } +- } ++ FileReadEvent.offer(start, path, bytesRead); + } + return bytesRead; + } +@@ -1281,12 +1248,8 @@ private int traceImplWrite(ByteBuffer src, long position) throws IOException { + start = FileWriteEvent.timestamp(); + bytesWritten = implWrite(src, position); + } finally { +- long end = FileWriteEvent.timestamp(); +- long duration = end - start; +- if (FileWriteEvent.shouldThrottleCommit(duration, end)) { +- long bytes = bytesWritten > 0 ? bytesWritten : 0; +- FileWriteEvent.commit(start, duration, path, bytes); +- } ++ long bytes = bytesWritten > 0 ? bytesWritten : 0; ++ FileWriteEvent.offer(start, path, bytes); + } + return bytesWritten; + } From d7ac33191196c9b537ff3209fb022c07adef9d73 Mon Sep 17 00:00:00 2001 From: erik_gahlin Date: Thu, 5 Jun 2025 11:29:04 +0200 Subject: [PATCH 08/10] Fix whitespace --- .../classes/jdk/jfr/internal/EventInstrumentation.java | 6 +++--- .../api/recording/settings/TestSettingsAvailability.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java index 89356cca9b9dd..7f0ed76586a8b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java @@ -61,8 +61,8 @@ * */ public final class EventInstrumentation { - public static final long MASK_THROTTLE = 1 << 62; - public static final long MASK_THROTTLE_CHECK = 1 << 63; + public static final long MASK_THROTTLE = 1 << 62; + public static final long MASK_THROTTLE_CHECK = 1 << 63; public static final long MASK_THROTTLE_BITS = MASK_THROTTLE | MASK_THROTTLE_CHECK; public static final long MASK_THROTTLE_CHECK_SUCCESS = MASK_THROTTLE_CHECK | MASK_THROTTLE; public static final long MASK_THROTTLE_CHECK_FAIL = MASK_THROTTLE_CHECK | 0; @@ -590,7 +590,7 @@ private void setDuration(CodeBuilder codeBuilder, Consumer expressi expression.accept(codeBuilder); if (throttled) { codeBuilder.aload(0); - getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); + getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION); codeBuilder.loadConstant(MASK_THROTTLE_BITS); codeBuilder.land(); codeBuilder.lor(); diff --git a/test/jdk/jdk/jfr/api/recording/settings/TestSettingsAvailability.java b/test/jdk/jdk/jfr/api/recording/settings/TestSettingsAvailability.java index bb23e56a2fed3..7c6e6fa276b3c 100644 --- a/test/jdk/jdk/jfr/api/recording/settings/TestSettingsAvailability.java +++ b/test/jdk/jdk/jfr/api/recording/settings/TestSettingsAvailability.java @@ -90,7 +90,7 @@ private static void testSettingPersistence() throws IOException, Exception { private static void testKnownSettings() throws Exception { testSetting(EventNames.JVMInformation, "enabled", "period"); testSetting(EventNames.FileRead, "enabled", "threshold", "stackTrace", "throttle"); - testSetting(EventNames.FileWrite, "enabled", "threshold","stackTrace", "throttle"); + testSetting(EventNames.FileWrite, "enabled", "threshold", "stackTrace", "throttle"); testSetting(EventNames.ExceptionStatistics, "enabled", "period"); testSetting(EventNames.SocketRead, "enabled", "threshold", "stackTrace", "throttle"); testSetting(EventNames.SocketWrite, "enabled", "threshold", "stackTrace", "throttle"); From 8beb194a5c8a9d6d30d1333f47c8813af309f235 Mon Sep 17 00:00:00 2001 From: erik_gahlin Date: Thu, 5 Jun 2025 11:34:55 +0200 Subject: [PATCH 09/10] Remove the mistakenly added file. --- t.txt | 410 ---------------------------------------------------------- 1 file changed, 410 deletions(-) delete mode 100644 t.txt diff --git a/t.txt b/t.txt deleted file mode 100644 index 66754a95b68aa..0000000000000 --- a/t.txt +++ /dev/null @@ -1,410 +0,0 @@ -diff --git a/src/java.base/share/classes/java/io/FileInputStream.java b/src/java.base/share/classes/java/io/FileInputStream.java -index aec65343384..f112691ebc7 100644 ---- a/src/java.base/share/classes/java/io/FileInputStream.java -+++ b/src/java.base/share/classes/java/io/FileInputStream.java -@@ -205,24 +205,18 @@ public int read() throws IOException { - - private int traceRead0() throws IOException { - int result = 0; -- boolean endOfFile = false; - long bytesRead = 0; - long start = 0; - try { - start = FileReadEvent.timestamp(); - result = read0(); - if (result < 0) { -- endOfFile = true; -+ bytesRead = -1; - } else { - bytesRead = 1; - } - } finally { -- long end = FileReadEvent.timestamp(); -- long duration = end - start; -- if (FileReadEvent.shouldThrottleCommit(duration, end)) { -- FileReadEvent.commit(start, duration, path, bytesRead, endOfFile); -- } -- -+ FileReadEvent.offer(start, path, bytesRead); - } - return result; - } -@@ -243,15 +237,7 @@ private int traceReadBytes(byte b[], int off, int len) throws IOException { - start = FileReadEvent.timestamp(); - bytesRead = readBytes(b, off, len); - } finally { -- long end = FileReadEvent.timestamp(); -- long duration = end - start; -- if (FileReadEvent.shouldThrottleCommit(duration, end)) { -- if (bytesRead < 0) { -- FileReadEvent.commit(start, duration, path, 0L, true); -- } else { -- FileReadEvent.commit(start, duration, path, bytesRead, false); -- } -- } -+ FileReadEvent.offer(start, path, bytesRead); - } - return bytesRead; - } -diff --git a/src/java.base/share/classes/java/io/FileOutputStream.java b/src/java.base/share/classes/java/io/FileOutputStream.java -index ebedce2b73e..f44eaee13b1 100644 ---- a/src/java.base/share/classes/java/io/FileOutputStream.java -+++ b/src/java.base/share/classes/java/io/FileOutputStream.java -@@ -272,11 +272,7 @@ private void traceWrite(int b, boolean append) throws IOException { - write(b, append); - bytesWritten = 1; - } finally { -- long end = FileWriteEvent.timestamp(); -- long duration = end - start; -- if (FileWriteEvent.shouldThrottleCommit(duration, end)) { -- FileWriteEvent.commit(start, duration, path, bytesWritten); -- } -+ FileWriteEvent.offer(start, path, bytesWritten); - } - } - -@@ -317,11 +313,7 @@ private void traceWriteBytes(byte b[], int off, int len, boolean append) throws - writeBytes(b, off, len, append); - bytesWritten = len; - } finally { -- long end = FileWriteEvent.timestamp(); -- long duration = end - start; -- if (FileWriteEvent.shouldThrottleCommit(duration, end)) { -- FileWriteEvent.commit(start, duration, path, bytesWritten); -- } -+ FileWriteEvent.offer(start, path, bytesWritten); - } - } - -diff --git a/src/java.base/share/classes/java/io/RandomAccessFile.java b/src/java.base/share/classes/java/io/RandomAccessFile.java -index 9200022582b..f3a20634d61 100644 ---- a/src/java.base/share/classes/java/io/RandomAccessFile.java -+++ b/src/java.base/share/classes/java/io/RandomAccessFile.java -@@ -367,22 +367,17 @@ public int read() throws IOException { - private int traceRead0() throws IOException { - int result = 0; - long bytesRead = 0; -- boolean endOfFile = false; - long start = 0; - try { - start = FileReadEvent.timestamp(); - result = read0(); - if (result < 0) { -- endOfFile = true; -+ bytesRead = -1; - } else { - bytesRead = 1; - } - } finally { -- long end = FileReadEvent.timestamp(); -- long duration = end - start; -- if (FileReadEvent.shouldThrottleCommit(duration, end)) { -- FileReadEvent.commit(start, duration, path, bytesRead, endOfFile); -- } -+ FileReadEvent.offer(start, path, bytesRead); - } - return result; - } -@@ -410,15 +405,7 @@ private int traceReadBytes0(byte b[], int off, int len) throws IOException { - start = FileReadEvent.timestamp(); - bytesRead = readBytes0(b, off, len); - } finally { -- long end = FileReadEvent.timestamp(); -- long duration = end - start; -- if (FileReadEvent.shouldThrottleCommit(duration, end)) { -- if (bytesRead < 0) { -- FileReadEvent.commit(start, duration, path, 0L, true); -- } else { -- FileReadEvent.commit(start, duration, path, bytesRead, false); -- } -- } -+ FileReadEvent.offer(start, path, bytesRead); - } - return bytesRead; - } -@@ -590,11 +577,7 @@ private void traceImplWrite(int b) throws IOException { - implWrite(b); - bytesWritten = 1; - } finally { -- long end = FileWriteEvent.timestamp(); -- long duration = end - start; -- if (FileWriteEvent.shouldThrottleCommit(duration, end)) { -- FileWriteEvent.commit(start, duration, path, bytesWritten); -- } -+ FileWriteEvent.offer(start, path, bytesWritten); - } - } - -@@ -633,11 +616,7 @@ private void traceImplWriteBytes(byte b[], int off, int len) throws IOException - implWriteBytes(b, off, len); - bytesWritten = len; - } finally { -- long end = FileWriteEvent.timestamp(); -- long duration = end - start; -- if (FileWriteEvent.shouldThrottleCommit(duration, end)) { -- FileWriteEvent.commit(start, duration, path, bytesWritten); -- } -+ FileWriteEvent.offer(start, path, bytesWritten); - } - } - -diff --git a/src/java.base/share/classes/java/net/Socket.java b/src/java.base/share/classes/java/net/Socket.java -index 7bd81f361fd..2905a51b402 100644 ---- a/src/java.base/share/classes/java/net/Socket.java -+++ b/src/java.base/share/classes/java/net/Socket.java -@@ -965,11 +965,7 @@ public int read(byte[] b, int off, int len) throws IOException { - } - long start = SocketReadEvent.timestamp(); - int nbytes = implRead(b, off, len); -- long end = SocketReadEvent.timestamp(); -- long duration = end - start; -- if (SocketReadEvent.shouldThrottleCommit(duration, end)) { -- SocketReadEvent.emit(start, duration, nbytes, parent.getRemoteSocketAddress(), getSoTimeout()); -- } -+ SocketReadEvent.offer(start, nbytes, parent.getRemoteSocketAddress(), getSoTimeout()); - return nbytes; - } - -@@ -1082,11 +1078,7 @@ public void write(byte[] b, int off, int len) throws IOException { - } - long start = SocketWriteEvent.timestamp(); - implWrite(b, off, len); -- long end = SocketWriteEvent.timestamp(); -- long duration = end - start; -- if (SocketWriteEvent.shouldThrottleCommit(duration, end)) { -- SocketWriteEvent.emit(start, duration, len, parent.getRemoteSocketAddress()); -- } -+ SocketWriteEvent.offer(start, len, parent.getRemoteSocketAddress()); - } - - private void implWrite(byte[] b, int off, int len) throws IOException { -diff --git a/src/java.base/share/classes/jdk/internal/event/FileForceEvent.java b/src/java.base/share/classes/jdk/internal/event/FileForceEvent.java -index f6dec6c8a5e..fe7c351ca53 100644 ---- a/src/java.base/share/classes/jdk/internal/event/FileForceEvent.java -+++ b/src/java.base/share/classes/jdk/internal/event/FileForceEvent.java -@@ -43,7 +43,7 @@ public class FileForceEvent extends Event { - /** - * Helper method to offer the data needed to potentially commit an event. - * The duration of the operation is computed using the current -- * timestamp and the given start time. If the duration is meets -+ * timestamp and the given start time. If the duration is meets - * or exceeds the configured value (determined by calling the generated method - * {@link #shouldCommit(long)}), an event will be emitted by calling - * {@link #commit(long, long, String, boolean)}. -diff --git a/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java b/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java -index 741897d8374..eb711687cc4 100644 ---- a/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java -+++ b/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java -@@ -45,11 +45,33 @@ public static long timestamp() { - return 0L; - } - -- public static boolean shouldThrottleCommit(long duration, long timestamp) { -+ static boolean shouldThrottleCommit(long duration, long end) { - // Generated by JFR - return false; - } - -+ /** -+ * Helper method to offer the data needed to potentially commit an event. -+ * The duration of the operation is computed using the current -+ * timestamp and the given start time. If the duration meets -+ * or exceeds the configured value and is not throttled (determined by calling the -+ * generated method {@link #shouldThrottleCommit(long, long)}), an event will be -+ * emitted by calling {@link #commit(long, long, String, long, boolean)} -+ * -+ * @param start the start time -+ * @param path the path -+ * @param bytesRead the number of bytes that were read, or -1 if the end of the file was reached -+ */ -+ public static void offer(long start, String path, long bytesRead) { -+ long end = timestamp(); -+ long duration = end - start; -+ if (shouldThrottleCommit(duration, end)) { -+ boolean endOfFile = bytesRead < 0; -+ long bytes = endOfFile ? 0 : bytesRead; -+ commit(start, duration, path, bytes, endOfFile); -+ } -+ } -+ - public static void commit(long start, long duration, String path, long bytesRead, boolean endOfFile) { - // Generated by JFR - } -diff --git a/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java b/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java -index 80e689c2b9c..8b3d6ab0e5d 100644 ---- a/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java -+++ b/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java -@@ -44,11 +44,32 @@ public static long timestamp() { - return 0L; - } - -- public static boolean shouldThrottleCommit(long duration, long timestamp) { -+ static boolean shouldThrottleCommit(long duration, long end) { - // Generated by JFR - return false; - } - -+ /** -+ * Helper method to offer the data needed to potentially commit an event. -+ * The duration of the operation is computed using the current -+ * timestamp and the given start time. If the duration meets -+ * or exceeds the configured value and is not throttled (determined by calling the -+ * generated method {@link #shouldThrottleCommit(long, long)}), an event will be -+ * emitted by calling {@link #commit(long, long, String, long)} -+ * -+ * @param start the start time -+ * @param path the path -+ * @param bytesRead the number of bytes that were written, or -1 if the end of the file was reached -+ */ -+ public static void offer(long start, String path, long bytesWritten) { -+ long end = timestamp(); -+ long duration = end - start; -+ if (shouldThrottleCommit(duration, end)) { -+ long bytes = bytesWritten > 0 ? bytesWritten : 0; -+ commit(start, duration, path, bytes); -+ } -+ } -+ - public static void commit(long start, long duration, String path, long bytesWritten) { - // Generated by JFR - } -diff --git a/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java b/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java -index da6d9eec607..48a15214a30 100644 ---- a/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java -+++ b/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java -@@ -74,9 +74,10 @@ public static void commit(long start, long duration, String host, String address - * of this method is generated automatically if jfr is enabled. - * - * @param duration time in nanoseconds to complete the operation -+ * @param end timestamp at the end of the operation - * @return true if the event should be commited - */ -- public static boolean shouldThrottleCommit(long duration, long timestamp) { -+ static boolean shouldThrottleCommit(long duration, long end) { - // Generated by JFR - return false; - } -diff --git a/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java b/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java -index d0e0ad2cd04..7b398647198 100644 ---- a/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java -+++ b/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java -@@ -69,9 +69,10 @@ public static void commit(long start, long duration, String host, String address - * of this method is generated automatically if jfr is enabled. - * - * @param duration time in nanoseconds to complete the operation -+ * @param end timestamp at the end of the operation - * @return true if the event should be commited - */ -- public static boolean shouldThrottleCommit(long duration, long timestamp) { -+ static boolean shouldThrottleCommit(long duration, long end) { - // Generated by JFR - return false; - } -diff --git a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java -index 56a3a8f1775..ceeea75b0fd 100644 ---- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java -+++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java -@@ -269,15 +269,7 @@ private int traceImplRead(ByteBuffer dst) throws IOException { - start = FileReadEvent.timestamp(); - bytesRead = implRead(dst); - } finally { -- long end = FileReadEvent.timestamp(); -- long duration = end - start; -- if (FileReadEvent.shouldThrottleCommit(duration, end)) { -- if (bytesRead < 0) { -- FileReadEvent.commit(start, duration, path, 0L, true); -- } else { -- FileReadEvent.commit(start, duration, path, bytesRead, false); -- } -- } -+ FileReadEvent.offer(start, path, bytesRead); - } - return bytesRead; - } -@@ -333,14 +325,7 @@ private long traceImplRead(ByteBuffer[] dsts, int offset, int length) throws IOE - bytesRead = implRead(dsts, offset, length); - } finally { - long end = FileReadEvent.timestamp(); -- long duration = end - start; -- if (FileReadEvent.shouldThrottleCommit(duration, end)) { -- if (bytesRead < 0) { -- FileReadEvent.commit(start, duration, path, 0L, true); -- } else { -- FileReadEvent.commit(start, duration, path, bytesRead, false); -- } -- } -+ FileReadEvent.offer(start, path, bytesRead); - } - return bytesRead; - } -@@ -386,20 +371,15 @@ private int implWrite(ByteBuffer src) throws IOException { - } - - private int traceImplWrite(ByteBuffer src) throws IOException { -- int bytesWritten = 0; -+ int bytes = 0; - long start = 0; - try { - start = FileWriteEvent.timestamp(); -- bytesWritten = implWrite(src); -+ bytes = implWrite(src); - } finally { -- long end = FileWriteEvent.timestamp(); -- long duration = end - start; -- if (FileWriteEvent.shouldThrottleCommit(duration, end)) { -- long bytes = bytesWritten > 0 ? bytesWritten : 0; -- FileWriteEvent.commit(start, duration, path, bytes); -- } -+ FileWriteEvent.offer(start, path, bytes); - } -- return bytesWritten; -+ return bytes; - } - - @Override -@@ -449,12 +429,7 @@ private long traceImplWrite(ByteBuffer[] srcs, int offset, int length) throws IO - start = FileWriteEvent.timestamp(); - bytesWritten = implWrite(srcs, offset, length); - } finally { -- long end = FileWriteEvent.timestamp(); -- long duration = end - start; -- if (FileWriteEvent.shouldThrottleCommit(duration, end)) { -- long bytes = bytesWritten > 0 ? bytesWritten : 0; -- FileWriteEvent.commit(start, duration, path, bytes); -- } -+ FileWriteEvent.offer(start, path, bytesWritten); - } - return bytesWritten; - } -@@ -1208,15 +1183,7 @@ private int traceImplRead(ByteBuffer dst, long position) throws IOException { - start = FileReadEvent.timestamp(); - bytesRead = implRead(dst, position); - } finally { -- long end = FileReadEvent.timestamp(); -- long duration = end - start; -- if (FileReadEvent.shouldThrottleCommit(duration, end)) { -- if (bytesRead < 0) { -- FileReadEvent.commit(start, duration, path, 0L, true); -- } else { -- FileReadEvent.commit(start, duration, path, bytesRead, false); -- } -- } -+ FileReadEvent.offer(start, path, bytesRead); - } - return bytesRead; - } -@@ -1281,12 +1248,8 @@ private int traceImplWrite(ByteBuffer src, long position) throws IOException { - start = FileWriteEvent.timestamp(); - bytesWritten = implWrite(src, position); - } finally { -- long end = FileWriteEvent.timestamp(); -- long duration = end - start; -- if (FileWriteEvent.shouldThrottleCommit(duration, end)) { -- long bytes = bytesWritten > 0 ? bytesWritten : 0; -- FileWriteEvent.commit(start, duration, path, bytes); -- } -+ long bytes = bytesWritten > 0 ? bytesWritten : 0; -+ FileWriteEvent.offer(start, path, bytes); - } - return bytesWritten; - } From 45adc08142e648e26dcddd9bfe857732f06f4d7e Mon Sep 17 00:00:00 2001 From: erik_gahlin Date: Thu, 5 Jun 2025 12:06:31 +0200 Subject: [PATCH 10/10] Move the timestamp to before the try block, change bytes to bytesWritten and remove unnecessary code --- .../classes/java/io/FileInputStream.java | 6 ++-- .../classes/java/io/FileOutputStream.java | 6 ++-- .../classes/java/io/RandomAccessFile.java | 12 +++----- .../classes/sun/nio/ch/FileChannelImpl.java | 30 +++++++------------ 4 files changed, 19 insertions(+), 35 deletions(-) diff --git a/src/java.base/share/classes/java/io/FileInputStream.java b/src/java.base/share/classes/java/io/FileInputStream.java index f112691ebc78e..b5b4813cbb59d 100644 --- a/src/java.base/share/classes/java/io/FileInputStream.java +++ b/src/java.base/share/classes/java/io/FileInputStream.java @@ -206,9 +206,8 @@ public int read() throws IOException { private int traceRead0() throws IOException { int result = 0; long bytesRead = 0; - long start = 0; + long start = FileReadEvent.timestamp(); try { - start = FileReadEvent.timestamp(); result = read0(); if (result < 0) { bytesRead = -1; @@ -232,9 +231,8 @@ private int traceRead0() throws IOException { private int traceReadBytes(byte b[], int off, int len) throws IOException { int bytesRead = 0; - long start = 0; + long start = FileReadEvent.timestamp(); try { - start = FileReadEvent.timestamp(); bytesRead = readBytes(b, off, len); } finally { FileReadEvent.offer(start, path, bytesRead); diff --git a/src/java.base/share/classes/java/io/FileOutputStream.java b/src/java.base/share/classes/java/io/FileOutputStream.java index f44eaee13b131..022aa44397a18 100644 --- a/src/java.base/share/classes/java/io/FileOutputStream.java +++ b/src/java.base/share/classes/java/io/FileOutputStream.java @@ -266,9 +266,8 @@ private void open(String name, boolean append) throws FileNotFoundException { private void traceWrite(int b, boolean append) throws IOException { long bytesWritten = 0; - long start = 0; + long start = FileWriteEvent.timestamp(); try { - start = FileWriteEvent.timestamp(); write(b, append); bytesWritten = 1; } finally { @@ -307,9 +306,8 @@ private native void writeBytes(byte[] b, int off, int len, boolean append) private void traceWriteBytes(byte b[], int off, int len, boolean append) throws IOException { long bytesWritten = 0; - long start = 0; + long start = FileWriteEvent.timestamp(); try { - start = FileWriteEvent.timestamp(); writeBytes(b, off, len, append); bytesWritten = len; } finally { diff --git a/src/java.base/share/classes/java/io/RandomAccessFile.java b/src/java.base/share/classes/java/io/RandomAccessFile.java index f3a20634d61dc..339030e022c4c 100644 --- a/src/java.base/share/classes/java/io/RandomAccessFile.java +++ b/src/java.base/share/classes/java/io/RandomAccessFile.java @@ -367,9 +367,8 @@ public int read() throws IOException { private int traceRead0() throws IOException { int result = 0; long bytesRead = 0; - long start = 0; + long start = FileReadEvent.timestamp(); try { - start = FileReadEvent.timestamp(); result = read0(); if (result < 0) { bytesRead = -1; @@ -400,9 +399,8 @@ private int readBytes(byte[] b, int off, int len) throws IOException { private int traceReadBytes0(byte b[], int off, int len) throws IOException { int bytesRead = 0; - long start = 0; + long start = FileReadEvent.timestamp(); try { - start = FileReadEvent.timestamp(); bytesRead = readBytes0(b, off, len); } finally { FileReadEvent.offer(start, path, bytesRead); @@ -571,9 +569,8 @@ private void implWrite(int b) throws IOException { private void traceImplWrite(int b) throws IOException { long bytesWritten = 0; - long start = 0; + long start = FileWriteEvent.timestamp(); try { - start = FileWriteEvent.timestamp(); implWrite(b); bytesWritten = 1; } finally { @@ -610,9 +607,8 @@ private void implWriteBytes(byte[] b, int off, int len) throws IOException { private void traceImplWriteBytes(byte b[], int off, int len) throws IOException { long bytesWritten = 0; - long start = 0; + long start = FileWriteEvent.timestamp(); try { - start = FileWriteEvent.timestamp(); implWriteBytes(b, off, len); bytesWritten = len; } finally { diff --git a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java index ceeea75b0fd6b..240405c2f7c92 100644 --- a/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java @@ -264,9 +264,8 @@ private int implRead(ByteBuffer dst) throws IOException { private int traceImplRead(ByteBuffer dst) throws IOException { int bytesRead = 0; - long start = 0; + long start = FileReadEvent.timestamp(); try { - start = FileReadEvent.timestamp(); bytesRead = implRead(dst); } finally { FileReadEvent.offer(start, path, bytesRead); @@ -319,12 +318,10 @@ private long implRead(ByteBuffer[] dsts, int offset, int length) private long traceImplRead(ByteBuffer[] dsts, int offset, int length) throws IOException { long bytesRead = 0; - long start = 0; + long start = FileReadEvent.timestamp(); try { - start = FileReadEvent.timestamp(); bytesRead = implRead(dsts, offset, length); } finally { - long end = FileReadEvent.timestamp(); FileReadEvent.offer(start, path, bytesRead); } return bytesRead; @@ -371,15 +368,14 @@ private int implWrite(ByteBuffer src) throws IOException { } private int traceImplWrite(ByteBuffer src) throws IOException { - int bytes = 0; - long start = 0; + int bytesWritten = 0; + long start = FileWriteEvent.timestamp(); try { - start = FileWriteEvent.timestamp(); - bytes = implWrite(src); + bytesWritten = implWrite(src); } finally { - FileWriteEvent.offer(start, path, bytes); + FileWriteEvent.offer(start, path, bytesWritten); } - return bytes; + return bytesWritten; } @Override @@ -424,9 +420,8 @@ private long implWrite(ByteBuffer[] srcs, int offset, int length) throws IOExcep private long traceImplWrite(ByteBuffer[] srcs, int offset, int length) throws IOException { long bytesWritten = 0; - long start = 0; + long start = FileWriteEvent.timestamp(); try { - start = FileWriteEvent.timestamp(); bytesWritten = implWrite(srcs, offset, length); } finally { FileWriteEvent.offer(start, path, bytesWritten); @@ -1178,9 +1173,8 @@ private int implRead(ByteBuffer dst, long position) throws IOException { private int traceImplRead(ByteBuffer dst, long position) throws IOException { int bytesRead = 0; - long start = 0; + long start = FileReadEvent.timestamp(); try { - start = FileReadEvent.timestamp(); bytesRead = implRead(dst, position); } finally { FileReadEvent.offer(start, path, bytesRead); @@ -1243,13 +1237,11 @@ private int implWrite(ByteBuffer src, long position) throws IOException { private int traceImplWrite(ByteBuffer src, long position) throws IOException { int bytesWritten = 0; - long start = 0; + long start = FileWriteEvent.timestamp(); try { - start = FileWriteEvent.timestamp(); bytesWritten = implWrite(src, position); } finally { - long bytes = bytesWritten > 0 ? bytesWritten : 0; - FileWriteEvent.offer(start, path, bytes); + FileWriteEvent.offer(start, path, bytesWritten); } return bytesWritten; }