From 50ef2efdb45de0c7361074bbcc577add129b7973 Mon Sep 17 00:00:00 2001 From: Bryce Anderson Date: Thu, 29 Aug 2024 13:05:20 -0600 Subject: [PATCH 1/2] concurent-api: save the timestamp of the SingleToFuture.get() calls Motivation: It can be very difficult to know if a thread is slow or completely stuck without taking multiple thread dumps and comparing them. Modifications: Try to mitigate this by saving the time stamp of the last blocking `.get()` call. This should then show up in heap dumps and we can at least compare them to see if they've all started blocking at about the same time or if there is a big spread. The latter would suggest they are truly stuck. --- .../io/servicetalk/concurrent/api/SourceToFuture.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/servicetalk-concurrent-api/src/main/java/io/servicetalk/concurrent/api/SourceToFuture.java b/servicetalk-concurrent-api/src/main/java/io/servicetalk/concurrent/api/SourceToFuture.java index f09fe4aa9a..ed751bb31c 100644 --- a/servicetalk-concurrent-api/src/main/java/io/servicetalk/concurrent/api/SourceToFuture.java +++ b/servicetalk-concurrent-api/src/main/java/io/servicetalk/concurrent/api/SourceToFuture.java @@ -45,6 +45,9 @@ abstract class SourceToFuture implements Future { @Nullable private volatile Object value; + // The timestamp of the last `.get()` call. This is intended to help with debugging stuck threads via heap dumps. + private long lastGetTimestamp; + private SourceToFuture() { } @@ -91,7 +94,12 @@ public final boolean isDone() { public final T get() throws InterruptedException, ExecutionException { final Object value = this.value; if (value == null) { - latch.await(); + lastGetTimestamp = System.currentTimeMillis(); + try { + latch.await(); + } finally { + lastGetTimestamp = 0; + } return reportGet(this.value); } else { return reportGet(value); From 6bfbba2e2f8dc86bba6b76f559fac5ab51a8c381 Mon Sep 17 00:00:00 2001 From: Bryce Anderson Date: Thu, 29 Aug 2024 15:05:44 -0600 Subject: [PATCH 2/2] Add ms suffix --- .../java/io/servicetalk/concurrent/api/SourceToFuture.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/servicetalk-concurrent-api/src/main/java/io/servicetalk/concurrent/api/SourceToFuture.java b/servicetalk-concurrent-api/src/main/java/io/servicetalk/concurrent/api/SourceToFuture.java index ed751bb31c..412dcdf79b 100644 --- a/servicetalk-concurrent-api/src/main/java/io/servicetalk/concurrent/api/SourceToFuture.java +++ b/servicetalk-concurrent-api/src/main/java/io/servicetalk/concurrent/api/SourceToFuture.java @@ -46,7 +46,7 @@ abstract class SourceToFuture implements Future { private volatile Object value; // The timestamp of the last `.get()` call. This is intended to help with debugging stuck threads via heap dumps. - private long lastGetTimestamp; + private long lastGetTimestampMs; private SourceToFuture() { } @@ -94,11 +94,11 @@ public final boolean isDone() { public final T get() throws InterruptedException, ExecutionException { final Object value = this.value; if (value == null) { - lastGetTimestamp = System.currentTimeMillis(); + lastGetTimestampMs = System.currentTimeMillis(); try { latch.await(); } finally { - lastGetTimestamp = 0; + lastGetTimestampMs = 0; } return reportGet(this.value); } else {