8351594: JFR: Rate-limited sampling of Java events
Reviewed-by: mgronlun, alanb
This commit is contained in:
parent
c5daf89053
commit
eb770a060a
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -205,22 +205,17 @@ public class FileInputStream extends InputStream
|
|||||||
|
|
||||||
private int traceRead0() throws IOException {
|
private int traceRead0() throws IOException {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
boolean endOfFile = false;
|
|
||||||
long bytesRead = 0;
|
long bytesRead = 0;
|
||||||
long start = 0;
|
long start = FileReadEvent.timestamp();
|
||||||
try {
|
try {
|
||||||
start = FileReadEvent.timestamp();
|
|
||||||
result = read0();
|
result = read0();
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
endOfFile = true;
|
bytesRead = -1;
|
||||||
} else {
|
} else {
|
||||||
bytesRead = 1;
|
bytesRead = 1;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
long duration = FileReadEvent.timestamp() - start;
|
FileReadEvent.offer(start, path, bytesRead);
|
||||||
if (FileReadEvent.shouldCommit(duration)) {
|
|
||||||
FileReadEvent.commit(start, duration, path, bytesRead, endOfFile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -236,19 +231,11 @@ public class FileInputStream extends InputStream
|
|||||||
|
|
||||||
private int traceReadBytes(byte b[], int off, int len) throws IOException {
|
private int traceReadBytes(byte b[], int off, int len) throws IOException {
|
||||||
int bytesRead = 0;
|
int bytesRead = 0;
|
||||||
long start = 0;
|
long start = FileReadEvent.timestamp();
|
||||||
try {
|
try {
|
||||||
start = FileReadEvent.timestamp();
|
|
||||||
bytesRead = readBytes(b, off, len);
|
bytesRead = readBytes(b, off, len);
|
||||||
} finally {
|
} finally {
|
||||||
long duration = FileReadEvent.timestamp() - start;
|
FileReadEvent.offer(start, path, bytesRead);
|
||||||
if (FileReadEvent.shouldCommit(duration)) {
|
|
||||||
if (bytesRead < 0) {
|
|
||||||
FileReadEvent.commit(start, duration, path, 0L, true);
|
|
||||||
} else {
|
|
||||||
FileReadEvent.commit(start, duration, path, bytesRead, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -266,16 +266,12 @@ public class FileOutputStream extends OutputStream
|
|||||||
|
|
||||||
private void traceWrite(int b, boolean append) throws IOException {
|
private void traceWrite(int b, boolean append) throws IOException {
|
||||||
long bytesWritten = 0;
|
long bytesWritten = 0;
|
||||||
long start = 0;
|
long start = FileWriteEvent.timestamp();
|
||||||
try {
|
try {
|
||||||
start = FileWriteEvent.timestamp();
|
|
||||||
write(b, append);
|
write(b, append);
|
||||||
bytesWritten = 1;
|
bytesWritten = 1;
|
||||||
} finally {
|
} finally {
|
||||||
long duration = FileWriteEvent.timestamp() - start;
|
FileWriteEvent.offer(start, path, bytesWritten);
|
||||||
if (FileWriteEvent.shouldCommit(duration)) {
|
|
||||||
FileWriteEvent.commit(start, duration, path, bytesWritten);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,16 +306,12 @@ public class FileOutputStream extends OutputStream
|
|||||||
|
|
||||||
private void traceWriteBytes(byte b[], int off, int len, boolean append) throws IOException {
|
private void traceWriteBytes(byte b[], int off, int len, boolean append) throws IOException {
|
||||||
long bytesWritten = 0;
|
long bytesWritten = 0;
|
||||||
long start = 0;
|
long start = FileWriteEvent.timestamp();
|
||||||
try {
|
try {
|
||||||
start = FileWriteEvent.timestamp();
|
|
||||||
writeBytes(b, off, len, append);
|
writeBytes(b, off, len, append);
|
||||||
bytesWritten = len;
|
bytesWritten = len;
|
||||||
} finally {
|
} finally {
|
||||||
long duration = FileWriteEvent.timestamp() - start;
|
FileWriteEvent.offer(start, path, bytesWritten);
|
||||||
if (FileWriteEvent.shouldCommit(duration)) {
|
|
||||||
FileWriteEvent.commit(start, duration, path, bytesWritten);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -367,21 +367,16 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
|||||||
private int traceRead0() throws IOException {
|
private int traceRead0() throws IOException {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
long bytesRead = 0;
|
long bytesRead = 0;
|
||||||
boolean endOfFile = false;
|
long start = FileReadEvent.timestamp();
|
||||||
long start = 0;
|
|
||||||
try {
|
try {
|
||||||
start = FileReadEvent.timestamp();
|
|
||||||
result = read0();
|
result = read0();
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
endOfFile = true;
|
bytesRead = -1;
|
||||||
} else {
|
} else {
|
||||||
bytesRead = 1;
|
bytesRead = 1;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
long duration = FileReadEvent.timestamp() - start;
|
FileReadEvent.offer(start, path, bytesRead);
|
||||||
if (FileReadEvent.shouldCommit(duration)) {
|
|
||||||
FileReadEvent.commit(start, duration, path, bytesRead, endOfFile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -404,19 +399,11 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
|||||||
|
|
||||||
private int traceReadBytes0(byte b[], int off, int len) throws IOException {
|
private int traceReadBytes0(byte b[], int off, int len) throws IOException {
|
||||||
int bytesRead = 0;
|
int bytesRead = 0;
|
||||||
long start = 0;
|
long start = FileReadEvent.timestamp();
|
||||||
try {
|
try {
|
||||||
start = FileReadEvent.timestamp();
|
|
||||||
bytesRead = readBytes0(b, off, len);
|
bytesRead = readBytes0(b, off, len);
|
||||||
} finally {
|
} finally {
|
||||||
long duration = FileReadEvent.timestamp() - start;
|
FileReadEvent.offer(start, path, bytesRead);
|
||||||
if (FileReadEvent.shouldCommit(duration)) {
|
|
||||||
if (bytesRead < 0) {
|
|
||||||
FileReadEvent.commit(start, duration, path, 0L, true);
|
|
||||||
} else {
|
|
||||||
FileReadEvent.commit(start, duration, path, bytesRead, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
}
|
}
|
||||||
@ -582,16 +569,12 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
|||||||
|
|
||||||
private void traceImplWrite(int b) throws IOException {
|
private void traceImplWrite(int b) throws IOException {
|
||||||
long bytesWritten = 0;
|
long bytesWritten = 0;
|
||||||
long start = 0;
|
long start = FileWriteEvent.timestamp();
|
||||||
try {
|
try {
|
||||||
start = FileWriteEvent.timestamp();
|
|
||||||
implWrite(b);
|
implWrite(b);
|
||||||
bytesWritten = 1;
|
bytesWritten = 1;
|
||||||
} finally {
|
} finally {
|
||||||
long duration = FileWriteEvent.timestamp() - start;
|
FileWriteEvent.offer(start, path, bytesWritten);
|
||||||
if (FileWriteEvent.shouldCommit(duration)) {
|
|
||||||
FileWriteEvent.commit(start, duration, path, bytesWritten);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -624,16 +607,12 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
|
|||||||
|
|
||||||
private void traceImplWriteBytes(byte b[], int off, int len) throws IOException {
|
private void traceImplWriteBytes(byte b[], int off, int len) throws IOException {
|
||||||
long bytesWritten = 0;
|
long bytesWritten = 0;
|
||||||
long start = 0;
|
long start = FileWriteEvent.timestamp();
|
||||||
try {
|
try {
|
||||||
start = FileWriteEvent.timestamp();
|
|
||||||
implWriteBytes(b, off, len);
|
implWriteBytes(b, off, len);
|
||||||
bytesWritten = len;
|
bytesWritten = len;
|
||||||
} finally {
|
} finally {
|
||||||
long duration = FileWriteEvent.timestamp() - start;
|
FileWriteEvent.offer(start, path, bytesWritten);
|
||||||
if (FileWriteEvent.shouldCommit(duration)) {
|
|
||||||
FileWriteEvent.commit(start, duration, path, bytesWritten);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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
|
* Flag set by jdk.internal.event.JFRTracing to indicate if
|
||||||
* exceptions should be traced by JFR.
|
* 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.
|
* The JVM saves some indication of the stack backtrace in this slot.
|
||||||
|
@ -965,10 +965,7 @@ public class Socket implements java.io.Closeable {
|
|||||||
}
|
}
|
||||||
long start = SocketReadEvent.timestamp();
|
long start = SocketReadEvent.timestamp();
|
||||||
int nbytes = implRead(b, off, len);
|
int nbytes = implRead(b, off, len);
|
||||||
long duration = SocketReadEvent.timestamp() - start;
|
SocketReadEvent.offer(start, nbytes, parent.getRemoteSocketAddress(), getSoTimeout());
|
||||||
if (SocketReadEvent.shouldCommit(duration)) {
|
|
||||||
SocketReadEvent.emit(start, duration, nbytes, parent.getRemoteSocketAddress(), getSoTimeout());
|
|
||||||
}
|
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1081,10 +1078,7 @@ public class Socket implements java.io.Closeable {
|
|||||||
}
|
}
|
||||||
long start = SocketWriteEvent.timestamp();
|
long start = SocketWriteEvent.timestamp();
|
||||||
implWrite(b, off, len);
|
implWrite(b, off, len);
|
||||||
long duration = SocketWriteEvent.timestamp() - start;
|
SocketWriteEvent.offer(start, len, parent.getRemoteSocketAddress());
|
||||||
if (SocketWriteEvent.shouldCommit(duration)) {
|
|
||||||
SocketWriteEvent.emit(start, duration, len, parent.getRemoteSocketAddress());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void implWrite(byte[] b, int off, int len) throws IOException {
|
private void implWrite(byte[] b, int off, int len) throws IOException {
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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 String message;
|
||||||
public Class<?> thrownClass;
|
public Class<?> thrownClass;
|
||||||
|
|
||||||
|
public static boolean shouldThrottleCommit(long timestamp) {
|
||||||
|
// Generated by JFR
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static void commit(long start, String message, Class<?> thrownClass) {
|
public static void commit(long start, String message, Class<?> thrownClass) {
|
||||||
// Generated by JFR
|
// Generated by JFR
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -45,11 +45,33 @@ public final class FileReadEvent extends Event {
|
|||||||
return 0L;
|
return 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldCommit(long duration) {
|
public static boolean shouldThrottleCommit(long duration, long end) {
|
||||||
// Generated by JFR
|
// Generated by JFR
|
||||||
return false;
|
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) {
|
public static void commit(long start, long duration, String path, long bytesRead, boolean endOfFile) {
|
||||||
// Generated by JFR
|
// Generated by JFR
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -44,11 +44,32 @@ public final class FileWriteEvent extends Event {
|
|||||||
return 0L;
|
return 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldCommit(long duration) {
|
public static boolean shouldThrottleCommit(long duration, long end) {
|
||||||
// Generated by JFR
|
// Generated by JFR
|
||||||
return false;
|
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) {
|
public static void commit(long start, long duration, String path, long bytesWritten) {
|
||||||
// Generated by JFR
|
// Generated by JFR
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -74,9 +74,10 @@ public class SocketReadEvent extends Event {
|
|||||||
* of this method is generated automatically if jfr is enabled.
|
* of this method is generated automatically if jfr is enabled.
|
||||||
*
|
*
|
||||||
* @param duration time in nanoseconds to complete the operation
|
* @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
|
* @return true if the event should be commited
|
||||||
*/
|
*/
|
||||||
public static boolean shouldCommit(long duration) {
|
public static boolean shouldThrottleCommit(long duration, long end) {
|
||||||
// Generated by JFR
|
// Generated by JFR
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -118,8 +119,9 @@ public class SocketReadEvent extends Event {
|
|||||||
* @param timeout maximum time to wait
|
* @param timeout maximum time to wait
|
||||||
*/
|
*/
|
||||||
public static void offer(long start, long nbytes, SocketAddress remote, long timeout) {
|
public static void offer(long start, long nbytes, SocketAddress remote, long timeout) {
|
||||||
long duration = timestamp() - start;
|
long end = timestamp();
|
||||||
if (shouldCommit(duration)) {
|
long duration = end - start;
|
||||||
|
if (shouldThrottleCommit(duration, end)) {
|
||||||
emit(start, duration, nbytes, remote, timeout);
|
emit(start, duration, nbytes, remote, timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -68,10 +68,11 @@ public class SocketWriteEvent extends Event {
|
|||||||
* must exceed some threshold in order to commit the event. The implementation
|
* must exceed some threshold in order to commit the event. The implementation
|
||||||
* of this method is generated automatically if jfr is enabled.
|
* 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
|
* @return true if the event should be commited
|
||||||
*/
|
*/
|
||||||
public static boolean shouldCommit(long duration) {
|
public static boolean shouldThrottleCommit(long duration, long end) {
|
||||||
// Generated by JFR
|
// Generated by JFR
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -104,7 +105,7 @@ public class SocketWriteEvent extends Event {
|
|||||||
* The duration of the operation is computed using the current
|
* 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
|
* 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)}.
|
* {@link #emit(long, long, long, SocketAddress)}.
|
||||||
*
|
*
|
||||||
* @param start the start time
|
* @param start the start time
|
||||||
@ -112,8 +113,9 @@ public class SocketWriteEvent extends Event {
|
|||||||
* @param remote the address of the remote socket being written to
|
* @param remote the address of the remote socket being written to
|
||||||
*/
|
*/
|
||||||
public static void offer(long start, long bytesWritten, SocketAddress remote) {
|
public static void offer(long start, long bytesWritten, SocketAddress remote) {
|
||||||
long duration = timestamp() - start;
|
long end = timestamp();
|
||||||
if (shouldCommit(duration)) {
|
long duration = end - start;
|
||||||
|
if (shouldThrottleCommit(duration, end)) {
|
||||||
emit(start, duration, bytesWritten, remote);
|
emit(start, duration, bytesWritten, remote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -37,22 +37,24 @@ public final class ThrowableTracer {
|
|||||||
if (OutOfMemoryError.class.isAssignableFrom(clazz)) {
|
if (OutOfMemoryError.class.isAssignableFrom(clazz)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (ErrorThrownEvent.enabled() || ExceptionThrownEvent.enabled()) {
|
||||||
if (ErrorThrownEvent.enabled()) {
|
|
||||||
long timestamp = ErrorThrownEvent.timestamp();
|
long timestamp = ErrorThrownEvent.timestamp();
|
||||||
ErrorThrownEvent.commit(timestamp, message, clazz);
|
if (ErrorThrownEvent.enabled()) {
|
||||||
}
|
ErrorThrownEvent.commit(timestamp, message, clazz);
|
||||||
if (ExceptionThrownEvent.enabled()) {
|
}
|
||||||
long timestamp = ExceptionThrownEvent.timestamp();
|
if (ExceptionThrownEvent.shouldThrottleCommit(timestamp)) {
|
||||||
ExceptionThrownEvent.commit(timestamp, message, clazz);
|
ExceptionThrownEvent.commit(timestamp, message, clazz);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
numThrowables.incrementAndGet();
|
numThrowables.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void traceThrowable(Class<?> clazz, String message) {
|
public static void traceThrowable(Class<?> clazz, String message) {
|
||||||
if (ExceptionThrownEvent.enabled()) {
|
if (ExceptionThrownEvent.enabled()) {
|
||||||
long timestamp = ExceptionThrownEvent.timestamp();
|
long timestamp = ErrorThrownEvent.timestamp();
|
||||||
ExceptionThrownEvent.commit(timestamp, message, clazz);
|
if (ExceptionThrownEvent.shouldThrottleCommit(timestamp)) {
|
||||||
|
ExceptionThrownEvent.commit(timestamp, message, clazz);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
numThrowables.incrementAndGet();
|
numThrowables.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -264,19 +264,11 @@ public class FileChannelImpl
|
|||||||
|
|
||||||
private int traceImplRead(ByteBuffer dst) throws IOException {
|
private int traceImplRead(ByteBuffer dst) throws IOException {
|
||||||
int bytesRead = 0;
|
int bytesRead = 0;
|
||||||
long start = 0;
|
long start = FileReadEvent.timestamp();
|
||||||
try {
|
try {
|
||||||
start = FileReadEvent.timestamp();
|
|
||||||
bytesRead = implRead(dst);
|
bytesRead = implRead(dst);
|
||||||
} finally {
|
} finally {
|
||||||
long duration = FileReadEvent.timestamp() - start;
|
FileReadEvent.offer(start, path, bytesRead);
|
||||||
if (FileReadEvent.shouldCommit(duration)) {
|
|
||||||
if (bytesRead < 0) {
|
|
||||||
FileReadEvent.commit(start, duration, path, 0L, true);
|
|
||||||
} else {
|
|
||||||
FileReadEvent.commit(start, duration, path, bytesRead, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
}
|
}
|
||||||
@ -326,19 +318,11 @@ public class FileChannelImpl
|
|||||||
|
|
||||||
private long traceImplRead(ByteBuffer[] dsts, int offset, int length) throws IOException {
|
private long traceImplRead(ByteBuffer[] dsts, int offset, int length) throws IOException {
|
||||||
long bytesRead = 0;
|
long bytesRead = 0;
|
||||||
long start = 0;
|
long start = FileReadEvent.timestamp();
|
||||||
try {
|
try {
|
||||||
start = FileReadEvent.timestamp();
|
|
||||||
bytesRead = implRead(dsts, offset, length);
|
bytesRead = implRead(dsts, offset, length);
|
||||||
} finally {
|
} finally {
|
||||||
long duration = FileReadEvent.timestamp() - start;
|
FileReadEvent.offer(start, path, bytesRead);
|
||||||
if (FileReadEvent.shouldCommit(duration)) {
|
|
||||||
if (bytesRead < 0) {
|
|
||||||
FileReadEvent.commit(start, duration, path, 0L, true);
|
|
||||||
} else {
|
|
||||||
FileReadEvent.commit(start, duration, path, bytesRead, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
}
|
}
|
||||||
@ -385,16 +369,11 @@ public class FileChannelImpl
|
|||||||
|
|
||||||
private int traceImplWrite(ByteBuffer src) throws IOException {
|
private int traceImplWrite(ByteBuffer src) throws IOException {
|
||||||
int bytesWritten = 0;
|
int bytesWritten = 0;
|
||||||
long start = 0;
|
long start = FileWriteEvent.timestamp();
|
||||||
try {
|
try {
|
||||||
start = FileWriteEvent.timestamp();
|
|
||||||
bytesWritten = implWrite(src);
|
bytesWritten = implWrite(src);
|
||||||
} finally {
|
} finally {
|
||||||
long duration = FileWriteEvent.timestamp() - start;
|
FileWriteEvent.offer(start, path, bytesWritten);
|
||||||
if (FileWriteEvent.shouldCommit(duration)) {
|
|
||||||
long bytes = bytesWritten > 0 ? bytesWritten : 0;
|
|
||||||
FileWriteEvent.commit(start, duration, path, bytes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
@ -441,16 +420,11 @@ public class FileChannelImpl
|
|||||||
|
|
||||||
private long traceImplWrite(ByteBuffer[] srcs, int offset, int length) throws IOException {
|
private long traceImplWrite(ByteBuffer[] srcs, int offset, int length) throws IOException {
|
||||||
long bytesWritten = 0;
|
long bytesWritten = 0;
|
||||||
long start = 0;
|
long start = FileWriteEvent.timestamp();
|
||||||
try {
|
try {
|
||||||
start = FileWriteEvent.timestamp();
|
|
||||||
bytesWritten = implWrite(srcs, offset, length);
|
bytesWritten = implWrite(srcs, offset, length);
|
||||||
} finally {
|
} finally {
|
||||||
long duration = FileWriteEvent.timestamp() - start;
|
FileWriteEvent.offer(start, path, bytesWritten);
|
||||||
if (FileWriteEvent.shouldCommit(duration)) {
|
|
||||||
long bytes = bytesWritten > 0 ? bytesWritten : 0;
|
|
||||||
FileWriteEvent.commit(start, duration, path, bytes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
@ -1199,19 +1173,11 @@ public class FileChannelImpl
|
|||||||
|
|
||||||
private int traceImplRead(ByteBuffer dst, long position) throws IOException {
|
private int traceImplRead(ByteBuffer dst, long position) throws IOException {
|
||||||
int bytesRead = 0;
|
int bytesRead = 0;
|
||||||
long start = 0;
|
long start = FileReadEvent.timestamp();
|
||||||
try {
|
try {
|
||||||
start = FileReadEvent.timestamp();
|
|
||||||
bytesRead = implRead(dst, position);
|
bytesRead = implRead(dst, position);
|
||||||
} finally {
|
} finally {
|
||||||
long duration = FileReadEvent.timestamp() - start;
|
FileReadEvent.offer(start, path, bytesRead);
|
||||||
if (FileReadEvent.shouldCommit(duration)) {
|
|
||||||
if (bytesRead < 0) {
|
|
||||||
FileReadEvent.commit(start, duration, path, 0L, true);
|
|
||||||
} else {
|
|
||||||
FileReadEvent.commit(start, duration, path, bytesRead, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
}
|
}
|
||||||
@ -1271,16 +1237,11 @@ public class FileChannelImpl
|
|||||||
|
|
||||||
private int traceImplWrite(ByteBuffer src, long position) throws IOException {
|
private int traceImplWrite(ByteBuffer src, long position) throws IOException {
|
||||||
int bytesWritten = 0;
|
int bytesWritten = 0;
|
||||||
long start = 0;
|
long start = FileWriteEvent.timestamp();
|
||||||
try {
|
try {
|
||||||
start = FileWriteEvent.timestamp();
|
|
||||||
bytesWritten = implWrite(src, position);
|
bytesWritten = implWrite(src, position);
|
||||||
} finally {
|
} finally {
|
||||||
long duration = FileWriteEvent.timestamp() - start;
|
FileWriteEvent.offer(start, path, bytesWritten);
|
||||||
if (FileWriteEvent.shouldCommit(duration)) {
|
|
||||||
long bytes = bytesWritten > 0 ? bytesWritten : 0;
|
|
||||||
FileWriteEvent.commit(start, duration, path, bytes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
@ -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.
|
* Copyright (c) 2020, Datadog, Inc. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
@ -24,7 +24,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package jdk.jfr.internal;
|
package jdk.jfr;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Inherited;
|
import java.lang.annotation.Inherited;
|
||||||
@ -32,14 +32,15 @@ import java.lang.annotation.Retention;
|
|||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
import jdk.jfr.MetadataDefinition;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event annotation, determines the event emission rate in events per time unit.
|
* Event annotation, specifies the maximum rate of events per time unit, (for
|
||||||
|
* example, {@code "100/s"}).
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
*
|
*
|
||||||
* This setting is only supported for JVM events.
|
* @since 25
|
||||||
*
|
|
||||||
* @since 16
|
|
||||||
*/
|
*/
|
||||||
@MetadataDefinition
|
@MetadataDefinition
|
||||||
@Target({ ElementType.TYPE })
|
@Target({ ElementType.TYPE })
|
||||||
@ -47,30 +48,33 @@ import jdk.jfr.MetadataDefinition;
|
|||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface Throttle {
|
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 NAME = "throttle";
|
||||||
public static final String DEFAULT = "off";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throttle, for example {@code "100/s"}.
|
* The throttle rate, for example {@code "100/s"}.
|
||||||
* <p>
|
* <p>
|
||||||
* String representation of a non-negative {@code Long} value followed by a slash ("/")
|
* String representation of a non-negative {@code long} value followed by a
|
||||||
* and one of the following units<br>
|
* forward slash ("/") and one of the following units: <br>
|
||||||
* {@code "ns"} (nanoseconds)<br>
|
* <ul style="list-style-type:none">
|
||||||
* {@code "us"} (microseconds)<br>
|
* <li>{@code "ns"} (nanoseconds)</li>
|
||||||
* {@code "ms"} (milliseconds)<br>
|
* <li>{@code "us"} (microseconds)</li>
|
||||||
* {@code "s"} (seconds)<br>
|
* <li>{@code "ms"} (milliseconds)</li>
|
||||||
* {@code "m"} (minutes)<br>
|
* <li>{@code "s"} (seconds)</li>
|
||||||
* {@code "h"} (hours)<br>
|
* <li>{@code "m"} (minutes)</li>
|
||||||
* {@code "d"} (days)<br>
|
* <li>{@code "h"} (hours)</li>
|
||||||
|
* <li>{@code "d"} (days)</li>
|
||||||
|
* </ul>
|
||||||
* <p>
|
* <p>
|
||||||
* Example values, {@code "6000/m"}, {@code "10/ms"} and {@code "200/s"}.
|
* 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.
|
* <p>
|
||||||
* When {@code "off"} is specified, all events are emitted.
|
* Specifying zero, for example {@code "0/s"}, results in no events being
|
||||||
|
* emitted.
|
||||||
|
* <p>
|
||||||
|
* Specifying {@code "off"} (case-sensitive) results in all events being emitted.
|
||||||
*
|
*
|
||||||
* @return the throttle value, default {@code "off"} not {@code null}
|
* @return the throttle value, default {@code "off"} not {@code null}
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
String value() default DEFAULT;
|
String value() default "off";
|
||||||
}
|
}
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -29,6 +29,7 @@ import jdk.jfr.Category;
|
|||||||
import jdk.jfr.Description;
|
import jdk.jfr.Description;
|
||||||
import jdk.jfr.Label;
|
import jdk.jfr.Label;
|
||||||
import jdk.jfr.Name;
|
import jdk.jfr.Name;
|
||||||
|
import jdk.jfr.Throttle;
|
||||||
import jdk.jfr.internal.MirrorEvent;
|
import jdk.jfr.internal.MirrorEvent;
|
||||||
import jdk.jfr.internal.RemoveFields;
|
import jdk.jfr.internal.RemoveFields;
|
||||||
import jdk.jfr.internal.Type;
|
import jdk.jfr.internal.Type;
|
||||||
@ -38,6 +39,7 @@ import jdk.jfr.internal.Type;
|
|||||||
@Category("Java Application")
|
@Category("Java Application")
|
||||||
@Description("An object derived from java.lang.Exception has been created")
|
@Description("An object derived from java.lang.Exception has been created")
|
||||||
@RemoveFields("duration")
|
@RemoveFields("duration")
|
||||||
|
@Throttle
|
||||||
public final class ExceptionThrownEvent extends MirrorEvent {
|
public final class ExceptionThrownEvent extends MirrorEvent {
|
||||||
|
|
||||||
@Label("Message")
|
@Label("Message")
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -30,6 +30,7 @@ import jdk.jfr.Description;
|
|||||||
import jdk.jfr.Label;
|
import jdk.jfr.Label;
|
||||||
import jdk.jfr.DataAmount;
|
import jdk.jfr.DataAmount;
|
||||||
import jdk.jfr.Name;
|
import jdk.jfr.Name;
|
||||||
|
import jdk.jfr.Throttle;
|
||||||
import jdk.jfr.internal.Type;
|
import jdk.jfr.internal.Type;
|
||||||
import jdk.jfr.internal.MirrorEvent;
|
import jdk.jfr.internal.MirrorEvent;
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ import jdk.jfr.internal.MirrorEvent;
|
|||||||
@Category("Java Application")
|
@Category("Java Application")
|
||||||
@Description("Reading data from a file")
|
@Description("Reading data from a file")
|
||||||
@StackFilter({"java.io.FileInputStream", "java.io.RandomAccessFile", "sun.nio.ch.FileChannelImpl"})
|
@StackFilter({"java.io.FileInputStream", "java.io.RandomAccessFile", "sun.nio.ch.FileChannelImpl"})
|
||||||
|
@Throttle
|
||||||
public final class FileReadEvent extends MirrorEvent {
|
public final class FileReadEvent extends MirrorEvent {
|
||||||
|
|
||||||
@Label("Path")
|
@Label("Path")
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -30,6 +30,7 @@ import jdk.jfr.Description;
|
|||||||
import jdk.jfr.Label;
|
import jdk.jfr.Label;
|
||||||
import jdk.jfr.DataAmount;
|
import jdk.jfr.DataAmount;
|
||||||
import jdk.jfr.Name;
|
import jdk.jfr.Name;
|
||||||
|
import jdk.jfr.Throttle;
|
||||||
import jdk.jfr.internal.Type;
|
import jdk.jfr.internal.Type;
|
||||||
import jdk.jfr.internal.MirrorEvent;
|
import jdk.jfr.internal.MirrorEvent;
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ import jdk.jfr.internal.MirrorEvent;
|
|||||||
@Category("Java Application")
|
@Category("Java Application")
|
||||||
@Description("Writing data to a file")
|
@Description("Writing data to a file")
|
||||||
@StackFilter({"java.io.FileOutputStream", "java.io.RandomAccessFile", "sun.nio.ch.FileChannelImpl"})
|
@StackFilter({"java.io.FileOutputStream", "java.io.RandomAccessFile", "sun.nio.ch.FileChannelImpl"})
|
||||||
|
@Throttle
|
||||||
public final class FileWriteEvent extends MirrorEvent {
|
public final class FileWriteEvent extends MirrorEvent {
|
||||||
|
|
||||||
@Label("Path")
|
@Label("Path")
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -31,6 +31,7 @@ import jdk.jfr.Label;
|
|||||||
import jdk.jfr.DataAmount;
|
import jdk.jfr.DataAmount;
|
||||||
import jdk.jfr.Name;
|
import jdk.jfr.Name;
|
||||||
import jdk.jfr.Timespan;
|
import jdk.jfr.Timespan;
|
||||||
|
import jdk.jfr.Throttle;
|
||||||
import jdk.jfr.internal.MirrorEvent;
|
import jdk.jfr.internal.MirrorEvent;
|
||||||
import jdk.jfr.internal.Type;
|
import jdk.jfr.internal.Type;
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ import jdk.jfr.internal.Type;
|
|||||||
@Label("Socket Read")
|
@Label("Socket Read")
|
||||||
@Category("Java Application")
|
@Category("Java Application")
|
||||||
@Description("Reading data from a socket")
|
@Description("Reading data from a socket")
|
||||||
|
@Throttle
|
||||||
public final class SocketReadEvent extends MirrorEvent {
|
public final class SocketReadEvent extends MirrorEvent {
|
||||||
|
|
||||||
@Label("Remote Host")
|
@Label("Remote Host")
|
||||||
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -30,6 +30,7 @@ import jdk.jfr.Description;
|
|||||||
import jdk.jfr.Label;
|
import jdk.jfr.Label;
|
||||||
import jdk.jfr.DataAmount;
|
import jdk.jfr.DataAmount;
|
||||||
import jdk.jfr.Name;
|
import jdk.jfr.Name;
|
||||||
|
import jdk.jfr.Throttle;
|
||||||
import jdk.jfr.internal.MirrorEvent;
|
import jdk.jfr.internal.MirrorEvent;
|
||||||
import jdk.jfr.internal.Type;
|
import jdk.jfr.internal.Type;
|
||||||
|
|
||||||
@ -37,6 +38,7 @@ import jdk.jfr.internal.Type;
|
|||||||
@Label("Socket Write")
|
@Label("Socket Write")
|
||||||
@Category("Java Application")
|
@Category("Java Application")
|
||||||
@Description("Writing data to a socket")
|
@Description("Writing data to a socket")
|
||||||
|
@Throttle
|
||||||
public final class SocketWriteEvent extends MirrorEvent {
|
public final class SocketWriteEvent extends MirrorEvent {
|
||||||
|
|
||||||
@Label("Remote Host")
|
@Label("Remote Host")
|
||||||
|
@ -51,6 +51,7 @@ import jdk.jfr.Name;
|
|||||||
import jdk.jfr.Registered;
|
import jdk.jfr.Registered;
|
||||||
import jdk.jfr.SettingControl;
|
import jdk.jfr.SettingControl;
|
||||||
import jdk.jfr.SettingDefinition;
|
import jdk.jfr.SettingDefinition;
|
||||||
|
import jdk.jfr.Throttle;
|
||||||
import jdk.jfr.internal.util.Bytecode;
|
import jdk.jfr.internal.util.Bytecode;
|
||||||
import jdk.jfr.internal.util.ImplicitFields;
|
import jdk.jfr.internal.util.ImplicitFields;
|
||||||
import jdk.jfr.internal.util.Bytecode.FieldDesc;
|
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_NAME = classDesc(Name.class);
|
||||||
private static final ClassDesc ANNOTATION_ENABLED = classDesc(Enabled.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_REMOVE_FIELDS = classDesc(RemoveFields.class);
|
||||||
|
private static final ClassDesc ANNOTATION_THROTTLE = classDesc(Throttle.class);
|
||||||
private static final String[] EMPTY_STRING_ARRAY = {};
|
private static final String[] EMPTY_STRING_ARRAY = {};
|
||||||
|
|
||||||
private final ClassModel classModel;
|
private final ClassModel classModel;
|
||||||
@ -138,6 +140,20 @@ final class ClassInspector {
|
|||||||
return true;
|
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) {
|
boolean hasStaticMethod(MethodDesc method) {
|
||||||
for (MethodModel m : classModel.methods()) {
|
for (MethodModel m : classModel.methods()) {
|
||||||
if (Modifier.isStatic(m.flags().flagsMask())) {
|
if (Modifier.isStatic(m.flags().flagsMask())) {
|
||||||
|
@ -44,6 +44,7 @@ import jdk.jfr.SettingControl;
|
|||||||
import jdk.jfr.SettingDefinition;
|
import jdk.jfr.SettingDefinition;
|
||||||
import jdk.jfr.StackTrace;
|
import jdk.jfr.StackTrace;
|
||||||
import jdk.jfr.Threshold;
|
import jdk.jfr.Threshold;
|
||||||
|
import jdk.jfr.Throttle;
|
||||||
import jdk.jfr.events.ActiveSettingEvent;
|
import jdk.jfr.events.ActiveSettingEvent;
|
||||||
import jdk.jfr.events.StackFilter;
|
import jdk.jfr.events.StackFilter;
|
||||||
import jdk.jfr.internal.settings.CutoffSetting;
|
import jdk.jfr.internal.settings.CutoffSetting;
|
||||||
@ -55,6 +56,7 @@ import jdk.jfr.internal.settings.CPUThrottleSetting;
|
|||||||
import jdk.jfr.internal.settings.StackTraceSetting;
|
import jdk.jfr.internal.settings.StackTraceSetting;
|
||||||
import jdk.jfr.internal.settings.ThresholdSetting;
|
import jdk.jfr.internal.settings.ThresholdSetting;
|
||||||
import jdk.jfr.internal.settings.ThrottleSetting;
|
import jdk.jfr.internal.settings.ThrottleSetting;
|
||||||
|
import jdk.jfr.internal.settings.Throttler;
|
||||||
import jdk.jfr.internal.tracing.Modification;
|
import jdk.jfr.internal.tracing.Modification;
|
||||||
import jdk.jfr.internal.util.Utils;
|
import jdk.jfr.internal.util.Utils;
|
||||||
|
|
||||||
@ -95,6 +97,7 @@ public final class EventControl {
|
|||||||
}
|
}
|
||||||
if (eventType.hasThrottle()) {
|
if (eventType.hasThrottle()) {
|
||||||
addControl(Throttle.NAME, defineThrottle(eventType));
|
addControl(Throttle.NAME, defineThrottle(eventType));
|
||||||
|
eventType.setThrottler(new Throttler(eventType));
|
||||||
}
|
}
|
||||||
if (eventType.hasLevel()) {
|
if (eventType.hasLevel()) {
|
||||||
addControl(Level.NAME, defineLevel(eventType));
|
addControl(Level.NAME, defineLevel(eventType));
|
||||||
|
@ -60,7 +60,14 @@ import jdk.jfr.internal.util.ImplicitFields;
|
|||||||
* Class responsible for adding instrumentation to a subclass of {@link Event}.
|
* 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 FieldDesc FIELD_EVENT_CONFIGURATION = FieldDesc.of(Object.class, "eventConfiguration");
|
||||||
|
|
||||||
private static final ClassDesc TYPE_EVENT_CONFIGURATION = classDesc(EventConfiguration.class);
|
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_BEGIN = MethodDesc.of("begin", "()V");
|
||||||
private static final MethodDesc METHOD_COMMIT = MethodDesc.of("commit", "()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_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_ENABLED = MethodDesc.of("enabled", "()Z");
|
||||||
private static final MethodDesc METHOD_END = MethodDesc.of("end", "()V");
|
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_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_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_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_IS_ENABLED = MethodDesc.of("isEnabled", "()Z");
|
||||||
private static final MethodDesc METHOD_RESET = MethodDesc.of("reset", "()V");
|
private static final MethodDesc METHOD_RESET = MethodDesc.of("reset", "()V");
|
||||||
@ -88,6 +101,7 @@ final class EventInstrumentation {
|
|||||||
private final MethodDesc staticCommitMethod;
|
private final MethodDesc staticCommitMethod;
|
||||||
private final boolean untypedEventConfiguration;
|
private final boolean untypedEventConfiguration;
|
||||||
private final boolean guardEventConfiguration;
|
private final boolean guardEventConfiguration;
|
||||||
|
private final boolean throttled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an EventInstrumentation object.
|
* Creates an EventInstrumentation object.
|
||||||
@ -110,6 +124,11 @@ final class EventInstrumentation {
|
|||||||
this.eventClassDesc = inspector.getClassDesc();
|
this.eventClassDesc = inspector.getClassDesc();
|
||||||
this.staticCommitMethod = inspector.findStaticCommitMethod();
|
this.staticCommitMethod = inspector.findStaticCommitMethod();
|
||||||
this.untypedEventConfiguration = hasUntypedConfiguration();
|
this.untypedEventConfiguration = hasUntypedConfiguration();
|
||||||
|
if (inspector.isJDK()) {
|
||||||
|
this.throttled = inspector.hasStaticMethod(METHOD_EVENT_SHOULD_THROTTLE_COMMIT_LONG_LONG);
|
||||||
|
} else {
|
||||||
|
this.throttled = inspector.isThrottled();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] buildInstrumented() {
|
byte[] buildInstrumented() {
|
||||||
@ -147,6 +166,12 @@ final class EventInstrumentation {
|
|||||||
if (isMethod(method, METHOD_SHOULD_COMMIT_LONG)) {
|
if (isMethod(method, METHOD_SHOULD_COMMIT_LONG)) {
|
||||||
return this::methodShouldCommitStatic;
|
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)) {
|
if (isMethod(method, METHOD_TIME_STAMP)) {
|
||||||
return this::methodTimestamp;
|
return this::methodTimestamp;
|
||||||
}
|
}
|
||||||
@ -188,11 +213,11 @@ final class EventInstrumentation {
|
|||||||
if (!inspector.hasDuration()) {
|
if (!inspector.hasDuration()) {
|
||||||
throwMissingDuration(codeBuilder, "end");
|
throwMissingDuration(codeBuilder, "end");
|
||||||
} else {
|
} else {
|
||||||
codeBuilder.aload(0);
|
setDuration(codeBuilder, cb -> {
|
||||||
codeBuilder.aload(0);
|
codeBuilder.aload(0);
|
||||||
getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_START_TIME);
|
getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_START_TIME);
|
||||||
invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_DURATION);
|
invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_DURATION);
|
||||||
putfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION);
|
});
|
||||||
codeBuilder.return_();
|
codeBuilder.return_();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,9 +230,8 @@ final class EventInstrumentation {
|
|||||||
}
|
}
|
||||||
// if (!eventConfiguration.shouldCommit(duration) goto fail;
|
// if (!eventConfiguration.shouldCommit(duration) goto fail;
|
||||||
getEventConfiguration(codeBuilder);
|
getEventConfiguration(codeBuilder);
|
||||||
codeBuilder.aload(0);
|
getDuration(codeBuilder);
|
||||||
getfield(codeBuilder, eventClassDesc, ImplicitFields.FIELD_DURATION);
|
invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT_LONG);
|
||||||
invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT);
|
|
||||||
codeBuilder.ifeq(fail);
|
codeBuilder.ifeq(fail);
|
||||||
List<SettingDesc> settingDescs = inspector.getSettings();
|
List<SettingDesc> settingDescs = inspector.getSettings();
|
||||||
for (int index = 0; index < settingDescs.size(); index++) {
|
for (int index = 0; index < settingDescs.size(); index++) {
|
||||||
@ -222,6 +246,30 @@ final class EventInstrumentation {
|
|||||||
codeBuilder.invokevirtual(eventClassDesc, sd.methodName(), mdesc);
|
codeBuilder.invokevirtual(eventClassDesc, sd.methodName(), mdesc);
|
||||||
codeBuilder.ifeq(fail);
|
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
|
// return true
|
||||||
codeBuilder.iconst_1();
|
codeBuilder.iconst_1();
|
||||||
codeBuilder.ireturn();
|
codeBuilder.ireturn();
|
||||||
@ -294,6 +342,17 @@ final class EventInstrumentation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void methodShouldCommitStatic(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();
|
Label fail = codeBuilder.newLabel();
|
||||||
if (guardEventConfiguration) {
|
if (guardEventConfiguration) {
|
||||||
// if (eventConfiguration == null) goto fail;
|
// if (eventConfiguration == null) goto fail;
|
||||||
@ -302,8 +361,10 @@ final class EventInstrumentation {
|
|||||||
}
|
}
|
||||||
// return eventConfiguration.shouldCommit(duration);
|
// return eventConfiguration.shouldCommit(duration);
|
||||||
getEventConfiguration(codeBuilder);
|
getEventConfiguration(codeBuilder);
|
||||||
codeBuilder.lload(0);
|
for (int i = 0 ; i < method.descriptor().parameterCount(); i++) {
|
||||||
codeBuilder.invokevirtual(TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT.name(), METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT.descriptor());
|
codeBuilder.lload(2 * i);
|
||||||
|
}
|
||||||
|
codeBuilder.invokevirtual(TYPE_EVENT_CONFIGURATION, method.name(), method.descriptor());
|
||||||
codeBuilder.ireturn();
|
codeBuilder.ireturn();
|
||||||
// fail:
|
// fail:
|
||||||
codeBuilder.labelBinding(fail);
|
codeBuilder.labelBinding(fail);
|
||||||
@ -515,6 +576,28 @@ final class EventInstrumentation {
|
|||||||
return desc.matches(m);
|
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<CodeBuilder> 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) {
|
private static void getEventWriter(CodeBuilder codeBuilder) {
|
||||||
invokestatic(codeBuilder, TYPE_EVENT_WRITER, METHOD_GET_EVENT_WRITER);
|
invokestatic(codeBuilder, TYPE_EVENT_WRITER, METHOD_GET_EVENT_WRITER);
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ public final class JVMSupport {
|
|||||||
public static void tryToInitializeJVM() {
|
public static void tryToInitializeJVM() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static long nanosToTicks(long nanos) {
|
public static long nanosToTicks(long nanos) {
|
||||||
return (long) (nanos * JVM.getTimeConversionFactor());
|
return (long) (nanos * JVM.getTimeConversionFactor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,11 +45,12 @@ import jdk.jfr.Period;
|
|||||||
import jdk.jfr.Relational;
|
import jdk.jfr.Relational;
|
||||||
import jdk.jfr.StackTrace;
|
import jdk.jfr.StackTrace;
|
||||||
import jdk.jfr.Threshold;
|
import jdk.jfr.Threshold;
|
||||||
|
import jdk.jfr.Throttle;
|
||||||
import jdk.jfr.TransitionFrom;
|
import jdk.jfr.TransitionFrom;
|
||||||
import jdk.jfr.TransitionTo;
|
import jdk.jfr.TransitionTo;
|
||||||
import jdk.jfr.Unsigned;
|
import jdk.jfr.Unsigned;
|
||||||
import jdk.jfr.internal.util.Utils;
|
import jdk.jfr.internal.util.Utils;
|
||||||
|
import jdk.jfr.internal.settings.ThrottleSetting;
|
||||||
public final class MetadataLoader {
|
public final class MetadataLoader {
|
||||||
|
|
||||||
// Caching to reduce allocation pressure and heap usage
|
// Caching to reduce allocation pressure and heap usage
|
||||||
@ -320,7 +321,7 @@ public final class MetadataLoader {
|
|||||||
aes.add(new AnnotationElement(Cutoff.class, Cutoff.INFINITY));
|
aes.add(new AnnotationElement(Cutoff.class, Cutoff.INFINITY));
|
||||||
}
|
}
|
||||||
if (t.throttle) {
|
if (t.throttle) {
|
||||||
aes.add(new AnnotationElement(Throttle.class, Throttle.DEFAULT));
|
aes.add(new AnnotationElement(Throttle.class, ThrottleSetting.DEFAULT_VALUE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (t.experimental) {
|
if (t.experimental) {
|
||||||
|
@ -45,11 +45,13 @@ import jdk.jfr.EventType;
|
|||||||
import jdk.jfr.Name;
|
import jdk.jfr.Name;
|
||||||
import jdk.jfr.Period;
|
import jdk.jfr.Period;
|
||||||
import jdk.jfr.SettingControl;
|
import jdk.jfr.SettingControl;
|
||||||
|
import jdk.jfr.Throttle;
|
||||||
import jdk.jfr.ValueDescriptor;
|
import jdk.jfr.ValueDescriptor;
|
||||||
import jdk.jfr.internal.consumer.RepositoryFiles;
|
import jdk.jfr.internal.consumer.RepositoryFiles;
|
||||||
import jdk.jfr.internal.event.EventConfiguration;
|
import jdk.jfr.internal.event.EventConfiguration;
|
||||||
import jdk.jfr.internal.management.HiddenWait;
|
import jdk.jfr.internal.management.HiddenWait;
|
||||||
import jdk.jfr.internal.periodic.PeriodicEvents;
|
import jdk.jfr.internal.periodic.PeriodicEvents;
|
||||||
|
import jdk.jfr.internal.settings.Throttler;
|
||||||
import jdk.jfr.internal.util.Utils;
|
import jdk.jfr.internal.util.Utils;
|
||||||
|
|
||||||
public final class MetadataRepository {
|
public final class MetadataRepository {
|
||||||
@ -214,9 +216,11 @@ public final class MetadataRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
EventType eventType = PrivateAccess.getInstance().newEventType(pEventType);
|
EventType eventType = PrivateAccess.getInstance().newEventType(pEventType);
|
||||||
|
pEventType.setHasThrottle(pEventType.getAnnotation(Throttle.class) != null);
|
||||||
EventControl ec = new EventControl(pEventType, eventClass);
|
EventControl ec = new EventControl(pEventType, eventClass);
|
||||||
SettingControl[] settings = ec.getSettingControls().toArray(new SettingControl[0]);
|
SettingControl[] settings = ec.getSettingControls().toArray(new SettingControl[0]);
|
||||||
EventConfiguration configuration = new EventConfiguration(pEventType, eventType, ec, settings, eventType.getId());
|
Throttler throttler = pEventType.getThrottler();
|
||||||
|
EventConfiguration configuration = new EventConfiguration(pEventType, eventType, ec, settings, throttler, eventType.getId());
|
||||||
pEventType.setRegistered(true);
|
pEventType.setRegistered(true);
|
||||||
// If class is instrumented or should not be instrumented, mark as instrumented.
|
// If class is instrumented or should not be instrumented, mark as instrumented.
|
||||||
if (JVM.isInstrumented(eventClass) || !JVMSupport.shouldInstrument(pEventType.isJDK(), pEventType.getName())) {
|
if (JVM.isInstrumented(eventClass) || !JVMSupport.shouldInstrument(pEventType.isJDK(), pEventType.getName())) {
|
||||||
|
@ -35,6 +35,7 @@ import jdk.jfr.internal.periodic.PeriodicEvents;
|
|||||||
import jdk.jfr.internal.util.ImplicitFields;
|
import jdk.jfr.internal.util.ImplicitFields;
|
||||||
import jdk.jfr.internal.util.TimespanRate;
|
import jdk.jfr.internal.util.TimespanRate;
|
||||||
import jdk.jfr.internal.util.Utils;
|
import jdk.jfr.internal.util.Utils;
|
||||||
|
import jdk.jfr.internal.settings.Throttler;
|
||||||
import jdk.jfr.internal.tracing.Modification;
|
import jdk.jfr.internal.tracing.Modification;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,6 +73,7 @@ public final class PlatformEventType extends Type {
|
|||||||
private boolean registered = true;
|
private boolean registered = true;
|
||||||
private boolean committable = enabled && registered;
|
private boolean committable = enabled && registered;
|
||||||
private boolean hasLevel = false;
|
private boolean hasLevel = false;
|
||||||
|
private Throttler throttler;
|
||||||
|
|
||||||
// package private
|
// package private
|
||||||
PlatformEventType(String name, long id, boolean isJDK, boolean dynamicSettings) {
|
PlatformEventType(String name, long id, boolean isJDK, boolean dynamicSettings) {
|
||||||
@ -190,9 +192,11 @@ public final class PlatformEventType extends Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setThrottle(long eventSampleSize, long period_ms) {
|
public void setThrottle(long eventSampleSize, long periodInMillis) {
|
||||||
if (isJVM) {
|
if (isJVM) {
|
||||||
JVM.setThrottle(getId(), eventSampleSize, period_ms);
|
JVM.setThrottle(getId(), eventSampleSize, periodInMillis);
|
||||||
|
} else {
|
||||||
|
throttler.configure(eventSampleSize, periodInMillis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,4 +424,12 @@ public final class PlatformEventType extends Type {
|
|||||||
public long getStackFilterId() {
|
public long getStackFilterId() {
|
||||||
return startFilterId;
|
return startFilterId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Throttler getThrottler() {
|
||||||
|
return throttler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setThrottler(Throttler throttler) {
|
||||||
|
this.throttler = throttler;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,14 +28,17 @@ package jdk.jfr.internal.event;
|
|||||||
import jdk.jfr.EventType;
|
import jdk.jfr.EventType;
|
||||||
import jdk.jfr.SettingControl;
|
import jdk.jfr.SettingControl;
|
||||||
import jdk.jfr.internal.EventControl;
|
import jdk.jfr.internal.EventControl;
|
||||||
|
import jdk.jfr.internal.EventInstrumentation;
|
||||||
import jdk.jfr.internal.JVM;
|
import jdk.jfr.internal.JVM;
|
||||||
import jdk.jfr.internal.PlatformEventType;
|
import jdk.jfr.internal.PlatformEventType;
|
||||||
|
import jdk.jfr.internal.settings.Throttler;
|
||||||
|
|
||||||
public record EventConfiguration(
|
public record EventConfiguration(
|
||||||
PlatformEventType platformEventType,
|
PlatformEventType platformEventType,
|
||||||
EventType eventType,
|
EventType eventType,
|
||||||
EventControl eventControl,
|
EventControl eventControl,
|
||||||
SettingControl[] settings,
|
SettingControl[] settings,
|
||||||
|
Throttler throttler,
|
||||||
long id) {
|
long id) {
|
||||||
|
|
||||||
// Accessed by generated code in event class
|
// Accessed by generated code in event class
|
||||||
@ -43,6 +46,19 @@ public record EventConfiguration(
|
|||||||
return isEnabled() && duration >= platformEventType.getThresholdTicks();
|
return isEnabled() && duration >= 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
|
// Accessed by generated code in event class
|
||||||
public SettingControl getSetting(int index) {
|
public SettingControl getSetting(int index) {
|
||||||
return settings[index];
|
return settings[index];
|
||||||
@ -53,6 +69,19 @@ public record EventConfiguration(
|
|||||||
return platformEventType.isCommittable();
|
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
|
// Not really part of the configuration, but the method
|
||||||
// needs to be somewhere the event class can access,
|
// needs to be somewhere the event class can access,
|
||||||
// but not part of the public API.
|
// but not part of the public API.
|
||||||
|
@ -38,7 +38,6 @@ import jdk.jfr.MetadataDefinition;
|
|||||||
import jdk.jfr.Name;
|
import jdk.jfr.Name;
|
||||||
import jdk.jfr.SettingControl;
|
import jdk.jfr.SettingControl;
|
||||||
import jdk.jfr.internal.PlatformEventType;
|
import jdk.jfr.internal.PlatformEventType;
|
||||||
import jdk.jfr.internal.Throttle;
|
|
||||||
import jdk.jfr.internal.Type;
|
import jdk.jfr.internal.Type;
|
||||||
import jdk.jfr.internal.util.Rate;
|
import jdk.jfr.internal.util.Rate;
|
||||||
import jdk.jfr.internal.util.TimespanUnit;
|
import jdk.jfr.internal.util.TimespanUnit;
|
||||||
@ -49,7 +48,7 @@ import jdk.jfr.internal.util.Utils;
|
|||||||
@Description("Throttles the emission rate for an event")
|
@Description("Throttles the emission rate for an event")
|
||||||
@Name(Type.SETTINGS_PREFIX + "Throttle")
|
@Name(Type.SETTINGS_PREFIX + "Throttle")
|
||||||
public final class ThrottleSetting extends SettingControl {
|
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 PlatformEventType eventType;
|
||||||
private final String defaultValue;
|
private final String defaultValue;
|
||||||
private String value;
|
private String value;
|
||||||
|
@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* 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 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 + amortizeDebt(expired);
|
||||||
|
if (projectedSampleSize == 0) {
|
||||||
|
next.projectedPopulationSize = 0;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
next.samplingInterval = deriveSamplingInterval(projectedSampleSize, expired);
|
||||||
|
next.projectedPopulationSize = projectedSampleSize * next.samplingInterval;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long amortizeDebt(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 (populationSize <= sampleSize) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
double projectProbability = sampleSize / populationSize;
|
||||||
|
return nextGeometric(projectProbability, randomGenerator.nextDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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 alpha * y + (1 - alpha) * 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
}
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -177,6 +177,28 @@
|
|||||||
* {@code "false"}</td>
|
* {@code "false"}</td>
|
||||||
* </tr>
|
* </tr>
|
||||||
* <tr>
|
* <tr>
|
||||||
|
* <th scope="row">{@code throttle}</th>
|
||||||
|
* <td>Specifies the maximum rate of events per time unit.</td>
|
||||||
|
* <td>{@code "off"} (no throttling)</td>
|
||||||
|
* <td>
|
||||||
|
* "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:
|
||||||
|
* <ul style="list-style-type:none">
|
||||||
|
* <li>{@code "ns"} (nanoseconds)
|
||||||
|
* <li>{@code "us"} (microseconds)
|
||||||
|
* <li>{@code "ms"} (milliseconds)</li>
|
||||||
|
* <li>{@code "s"} (seconds)</li>
|
||||||
|
* <li>{@code "m"} (minutes)</li>
|
||||||
|
* <li>{@code "h"} (hours)</li>
|
||||||
|
* <li>{@code "d"} (days)</li>
|
||||||
|
* </ul>
|
||||||
|
* </td>
|
||||||
|
* <td>
|
||||||
|
* {@code "off"}<br>
|
||||||
|
* {@code "100/s"}<br>
|
||||||
|
* {@code "1000/m"}
|
||||||
|
* </td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
* <th scope="row">{@code filter}</th>
|
* <th scope="row">{@code filter}</th>
|
||||||
* <td>Specifies the filter for the event</td>
|
* <td>Specifies the filter for the event</td>
|
||||||
* <td>{@code ""} (empty string)</td>
|
* <td>{@code ""} (empty string)</td>
|
||||||
|
@ -769,31 +769,35 @@
|
|||||||
<event name="jdk.FileForce">
|
<event name="jdk.FileForce">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
<setting name="stackTrace">true</setting>
|
<setting name="stackTrace">true</setting>
|
||||||
<setting name="threshold" control="file-threshold">20 ms</setting>
|
<setting name="threshold">20 ms</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="jdk.FileRead">
|
<event name="jdk.FileRead">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
<setting name="stackTrace">true</setting>
|
<setting name="stackTrace">true</setting>
|
||||||
<setting name="threshold" control="file-threshold">20 ms</setting>
|
<setting name="threshold">1 ms</setting>
|
||||||
|
<setting name="throttle">100/s</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="jdk.FileWrite">
|
<event name="jdk.FileWrite">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
<setting name="stackTrace">true</setting>
|
<setting name="stackTrace">true</setting>
|
||||||
<setting name="threshold" control="file-threshold">20 ms</setting>
|
<setting name="threshold">1 ms</setting>
|
||||||
|
<setting name="throttle">100/s</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="jdk.SocketRead">
|
<event name="jdk.SocketRead">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
<setting name="stackTrace">true</setting>
|
<setting name="stackTrace">true</setting>
|
||||||
<setting name="threshold" control="socket-threshold">20 ms</setting>
|
<setting name="threshold">1 ms</setting>
|
||||||
|
<setting name="throttle">100/s</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="jdk.SocketWrite">
|
<event name="jdk.SocketWrite">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
<setting name="stackTrace">true</setting>
|
<setting name="stackTrace">true</setting>
|
||||||
<setting name="threshold" control="socket-threshold">20 ms</setting>
|
<setting name="threshold">1 ms</setting>
|
||||||
|
<setting name="throttle">100/s</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="jdk.Deserialization">
|
<event name="jdk.Deserialization">
|
||||||
@ -836,8 +840,9 @@
|
|||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="jdk.JavaExceptionThrow">
|
<event name="jdk.JavaExceptionThrow">
|
||||||
<setting name="enabled" control="enable-exceptions">false</setting>
|
<setting name="enabled" control="enable-exceptions">true</setting>
|
||||||
<setting name="stackTrace">true</setting>
|
<setting name="stackTrace">true</setting>
|
||||||
|
<setting name="throttle" control="exceptions-throttle-rate">100/s</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="jdk.JavaErrorThrow">
|
<event name="jdk.JavaErrorThrow">
|
||||||
@ -1136,20 +1141,27 @@
|
|||||||
<test name="thread-dump" operator="equal" value="999 d"/>
|
<test name="thread-dump" operator="equal" value="999 d"/>
|
||||||
</condition>
|
</condition>
|
||||||
|
|
||||||
<selection name="exceptions" default="errors" label="Exceptions">
|
<selection name="exceptions" default="throttled" label="Exceptions">
|
||||||
<option label="Off" name="off">off</option>
|
<option label="Off" name="off">off</option>
|
||||||
<option label="Errors Only" name="errors">errors</option>
|
<option label="Errors and 100 Exceptions Per Second" name="throttled">throttled</option>
|
||||||
<option label="All Exceptions, including Errors" name="all">all</option>
|
<option label="Errors and All Exceptions" name="all">all</option>
|
||||||
</selection>
|
</selection>
|
||||||
|
|
||||||
<condition name="enable-errors" true="true" false="false">
|
<condition name="enable-errors" true="true" false="false">
|
||||||
<or>
|
<or>
|
||||||
<test name="exceptions" operator="equal" value="errors"/>
|
<test name="exceptions" operator="equal" value="throttled"/>
|
||||||
<test name="exceptions" operator="equal" value="all"/>
|
<test name="exceptions" operator="equal" value="all"/>
|
||||||
</or>
|
</or>
|
||||||
</condition>
|
</condition>
|
||||||
|
|
||||||
<condition name="enable-exceptions" true="true" false="false">
|
<condition name="enable-exceptions" true="true" false="false">
|
||||||
|
<or>
|
||||||
|
<test name="exceptions" operator="equal" value="throttled"/>
|
||||||
|
<test name="exceptions" operator="equal" value="all"/>
|
||||||
|
</or>
|
||||||
|
</condition>
|
||||||
|
|
||||||
|
<condition name="exceptions-throttle-rate" true="off" false="100/s">
|
||||||
<test name="exceptions" operator="equal" value="all"/>
|
<test name="exceptions" operator="equal" value="all"/>
|
||||||
</condition>
|
</condition>
|
||||||
|
|
||||||
@ -1177,10 +1189,6 @@
|
|||||||
|
|
||||||
<text name="locking-threshold" label="Locking Threshold" contentType="timespan" minimum="0 s">20 ms</text>
|
<text name="locking-threshold" label="Locking Threshold" contentType="timespan" minimum="0 s">20 ms</text>
|
||||||
|
|
||||||
<text name="file-threshold" label="File I/O Threshold" contentType="timespan" minimum="0 s">20 ms</text>
|
|
||||||
|
|
||||||
<text name="socket-threshold" label="Socket I/O Threshold" contentType="timespan" minimum="0 s">20 ms</text>
|
|
||||||
|
|
||||||
<text name="method-timing" label="Method Timing" contentType="text"></text>
|
<text name="method-timing" label="Method Timing" contentType="text"></text>
|
||||||
|
|
||||||
<text name="method-trace" label="Method Trace" contentType="text"></text>
|
<text name="method-trace" label="Method Trace" contentType="text"></text>
|
||||||
|
@ -769,31 +769,35 @@
|
|||||||
<event name="jdk.FileForce">
|
<event name="jdk.FileForce">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
<setting name="stackTrace">true</setting>
|
<setting name="stackTrace">true</setting>
|
||||||
<setting name="threshold" control="file-threshold">10 ms</setting>
|
<setting name="threshold">10 ms</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="jdk.FileRead">
|
<event name="jdk.FileRead">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
<setting name="stackTrace">true</setting>
|
<setting name="stackTrace">true</setting>
|
||||||
<setting name="threshold" control="file-threshold">10 ms</setting>
|
<setting name="threshold">1 ms</setting>
|
||||||
|
<setting name="throttle">300/s</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="jdk.FileWrite">
|
<event name="jdk.FileWrite">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
<setting name="stackTrace">true</setting>
|
<setting name="stackTrace">true</setting>
|
||||||
<setting name="threshold" control="file-threshold">10 ms</setting>
|
<setting name="threshold">1 ms</setting>
|
||||||
|
<setting name="throttle">300/s</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="jdk.SocketRead">
|
<event name="jdk.SocketRead">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
<setting name="stackTrace">true</setting>
|
<setting name="stackTrace">true</setting>
|
||||||
<setting name="threshold" control="socket-threshold">10 ms</setting>
|
<setting name="threshold">1 ms</setting>
|
||||||
|
<setting name="throttle">300/s</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="jdk.SocketWrite">
|
<event name="jdk.SocketWrite">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
<setting name="stackTrace">true</setting>
|
<setting name="stackTrace">true</setting>
|
||||||
<setting name="threshold" control="socket-threshold">10 ms</setting>
|
<setting name="threshold">1 ms</setting>
|
||||||
|
<setting name="throttle">300/s</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="jdk.Deserialization">
|
<event name="jdk.Deserialization">
|
||||||
@ -836,8 +840,9 @@
|
|||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="jdk.JavaExceptionThrow">
|
<event name="jdk.JavaExceptionThrow">
|
||||||
<setting name="enabled" control="enable-exceptions">false</setting>
|
<setting name="enabled" control="enable-exceptions">true</setting>
|
||||||
<setting name="stackTrace">true</setting>
|
<setting name="stackTrace">true</setting>
|
||||||
|
<setting name="throttle" control="exceptions-throttle-rate">300/s</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
<event name="jdk.JavaErrorThrow">
|
<event name="jdk.JavaErrorThrow">
|
||||||
@ -1135,21 +1140,28 @@
|
|||||||
<test name="thread-dump" operator="equal" value="999 d"/>
|
<test name="thread-dump" operator="equal" value="999 d"/>
|
||||||
</condition>
|
</condition>
|
||||||
|
|
||||||
<selection name="exceptions" default="errors" label="Exceptions">
|
<selection name="exceptions" default="throttled" label="Exceptions">
|
||||||
<option label="Off" name="off">off</option>
|
<option label="Off" name="off">off</option>
|
||||||
<option label="Errors Only" name="errors">errors</option>
|
<option label="Errors and 300 Exceptions Per Second" name="throttled">throttled</option>
|
||||||
<option label="All Exceptions, including Errors" name="all">all</option>
|
<option label="Errors and All Exceptions" name="all">all</option>
|
||||||
</selection>
|
</selection>
|
||||||
|
|
||||||
<condition name="enable-errors" true="true" false="false">
|
<condition name="enable-errors" true="true" false="false">
|
||||||
<or>
|
<or>
|
||||||
<test name="exceptions" operator="equal" value="errors"/>
|
<test name="exceptions" operator="equal" value="throttled"/>
|
||||||
<test name="exceptions" operator="equal" value="all"/>
|
<test name="exceptions" operator="equal" value="all"/>
|
||||||
</or>
|
</or>
|
||||||
</condition>
|
</condition>
|
||||||
|
|
||||||
<condition name="enable-exceptions" true="true" false="false">
|
<condition name="enable-exceptions" true="true" false="false">
|
||||||
<test name="exceptions" operator="equal" value="all"/>
|
<or>
|
||||||
|
<test name="exceptions" operator="equal" value="throttled"/>
|
||||||
|
<test name="exceptions" operator="equal" value="all"/>
|
||||||
|
</or>
|
||||||
|
</condition>
|
||||||
|
|
||||||
|
<condition name="exceptions-throttle-rate" true="off" false="300/s">
|
||||||
|
<test name="exceptions" operator="equal" value="all"/>
|
||||||
</condition>
|
</condition>
|
||||||
|
|
||||||
<selection name="memory-leaks" default="stack-traces" label="Memory Leak Detection">
|
<selection name="memory-leaks" default="stack-traces" label="Memory Leak Detection">
|
||||||
@ -1176,10 +1188,6 @@
|
|||||||
|
|
||||||
<text name="locking-threshold" label="Locking Threshold" contentType="timespan" minimum="0 s">10 ms</text>
|
<text name="locking-threshold" label="Locking Threshold" contentType="timespan" minimum="0 s">10 ms</text>
|
||||||
|
|
||||||
<text name="file-threshold" label="File I/O Threshold" contentType="timespan" minimum="0 s">10 ms</text>
|
|
||||||
|
|
||||||
<text name="socket-threshold" label="Socket I/O Threshold" contentType="timespan" minimum="0 s">10 ms</text>
|
|
||||||
|
|
||||||
<text name="method-timing" label="Method Timing" contentType="text"></text>
|
<text name="method-timing" label="Method Timing" contentType="text"></text>
|
||||||
|
|
||||||
<text name="method-trace" label="Method Trace" contentType="text"></text>
|
<text name="method-trace" label="Method Trace" contentType="text"></text>
|
||||||
|
290
test/jdk/jdk/jfr/api/metadata/annotations/TestThrottle.java
Normal file
290
test/jdk/jdk/jfr/api/metadata/annotations/TestThrottle.java
Normal file
@ -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<String> 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<? extends Event> eventClass, boolean shouldCommit) throws Exception {
|
||||||
|
try (Recording r = new Recording()) {
|
||||||
|
r.start();
|
||||||
|
Constructor<Event> c = (Constructor<Event>) 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -66,7 +66,7 @@ public class TestSettingsAvailability {
|
|||||||
for (EventType parsedType : rf.readEventTypes()) {
|
for (EventType parsedType : rf.readEventTypes()) {
|
||||||
EventType inMem = inMemoryTypes.get(parsedType.getName());
|
EventType inMem = inMemoryTypes.get(parsedType.getName());
|
||||||
if (inMem == null) {
|
if (inMem == null) {
|
||||||
throw new Exception("Superflous event type " + parsedType.getName() + " in recording");
|
throw new Exception("Superfluous event type " + parsedType.getName() + " in recording");
|
||||||
}
|
}
|
||||||
Set<String> inMemsettings = new HashSet<>();
|
Set<String> inMemsettings = new HashSet<>();
|
||||||
for (SettingDescriptor sd : inMem.getSettingDescriptors()) {
|
for (SettingDescriptor sd : inMem.getSettingDescriptors()) {
|
||||||
@ -75,7 +75,7 @@ public class TestSettingsAvailability {
|
|||||||
|
|
||||||
for (SettingDescriptor parsedSetting : parsedType.getSettingDescriptors()) {
|
for (SettingDescriptor parsedSetting : parsedType.getSettingDescriptors()) {
|
||||||
if (!inMemsettings.contains(parsedSetting.getName())) {
|
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());
|
inMemsettings.remove(parsedSetting.getName());
|
||||||
}
|
}
|
||||||
@ -89,14 +89,14 @@ public class TestSettingsAvailability {
|
|||||||
|
|
||||||
private static void testKnownSettings() throws Exception {
|
private static void testKnownSettings() throws Exception {
|
||||||
testSetting(EventNames.JVMInformation, "enabled", "period");
|
testSetting(EventNames.JVMInformation, "enabled", "period");
|
||||||
testSetting(EventNames.FileRead, "enabled", "threshold", "stackTrace");
|
testSetting(EventNames.FileRead, "enabled", "threshold", "stackTrace", "throttle");
|
||||||
testSetting(EventNames.FileWrite, "enabled", "threshold","stackTrace");
|
testSetting(EventNames.FileWrite, "enabled", "threshold", "stackTrace", "throttle");
|
||||||
testSetting(EventNames.ExceptionStatistics, "enabled", "period");
|
testSetting(EventNames.ExceptionStatistics, "enabled", "period");
|
||||||
testSetting(EventNames.SocketRead, "enabled", "threshold", "stackTrace");
|
testSetting(EventNames.SocketRead, "enabled", "threshold", "stackTrace", "throttle");
|
||||||
testSetting(EventNames.SocketWrite, "enabled", "threshold", "stackTrace");
|
testSetting(EventNames.SocketWrite, "enabled", "threshold", "stackTrace", "throttle");
|
||||||
testSetting(EventNames.ActiveRecording, "enabled");
|
testSetting(EventNames.ActiveRecording, "enabled");
|
||||||
testSetting(EventNames.ActiveSetting, "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 {
|
private static void testSetting(String eventName, String... settingNames) throws Exception {
|
||||||
|
@ -51,7 +51,7 @@ import jdk.jfr.Recording;
|
|||||||
* jdk.jfr.startupargs.TestEventSettings multipleSettings
|
* jdk.jfr.startupargs.TestEventSettings multipleSettings
|
||||||
*
|
*
|
||||||
* @run main/othervm
|
* @run main/othervm
|
||||||
* -XX:StartFlightRecording:class-loading=true,socket-threshold=100ms
|
* -XX:StartFlightRecording:class-loading=true,locking-threshold=100ms
|
||||||
* jdk.jfr.startupargs.TestEventSettings jfcOptions
|
* jdk.jfr.startupargs.TestEventSettings jfcOptions
|
||||||
*/
|
*/
|
||||||
public class TestEventSettings {
|
public class TestEventSettings {
|
||||||
@ -70,7 +70,7 @@ public class TestEventSettings {
|
|||||||
}
|
}
|
||||||
case "jfcOptions" -> {
|
case "jfcOptions" -> {
|
||||||
assertSetting("jdk.ClassDefine#enabled","true");
|
assertSetting("jdk.ClassDefine#enabled","true");
|
||||||
assertSetting("jdk.SocketRead#threshold", "100 ms");
|
assertSetting("jdk.JavaMonitorEnter#threshold", "100 ms");
|
||||||
}
|
}
|
||||||
default -> throw new Exception("Uknown tes " + subTest);
|
default -> throw new Exception("Uknown tes " + subTest);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user