From f393f92b00b9363bba24311dfa6b6100ddb8e1d7 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Tue, 11 Aug 2026 15:40:05 +0200 Subject: [PATCH 1/2] perf(core): Read the clock once per performance collection round While a transaction is running, performance data is collected every 100ms. CompositeData.addDataAndCheckTimeout read the clock to check for the 30 second collection timeout once per in-flight transaction, allocating a SentryNanotimeDate each time, even though the enclosing timer task had just read it for the sample it was distributing. Pass that reading in, so a collection round reads the clock once instead of once per transaction. --- .../io/sentry/DefaultCompositePerformanceCollector.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sentry/src/main/java/io/sentry/DefaultCompositePerformanceCollector.java b/sentry/src/main/java/io/sentry/DefaultCompositePerformanceCollector.java index 22b8bb839b..2b5a386300 100644 --- a/sentry/src/main/java/io/sentry/DefaultCompositePerformanceCollector.java +++ b/sentry/src/main/java/io/sentry/DefaultCompositePerformanceCollector.java @@ -124,7 +124,7 @@ public void run() { // Add the enriched tempData to all transactions/profiles/objects that collect data. // Then Check if that object timed out. for (CompositeData data : compositeDataMap.values()) { - if (data.addDataAndCheckTimeout(tempData)) { + if (data.addDataAndCheckTimeout(tempData, tempData.getNanoTimestamp())) { // timed out if (data.transaction != null) { timedOutTransactions.add(data.transaction); @@ -224,16 +224,19 @@ private CompositeData(final @Nullable ITransaction transaction) { * Adds the data to the internal list of PerformanceCollectionData. Then it checks if data * collection timed out (for transactions only). * + * @param nowNanos the timestamp of the current collection, passed in so a single clock reading + * is shared by every transaction in this collection round. * @return true if data collection timed out (for transactions only). */ - boolean addDataAndCheckTimeout(final @NotNull PerformanceCollectionData data) { + boolean addDataAndCheckTimeout( + final @NotNull PerformanceCollectionData data, final long nowNanos) { // stop() hands dataList out while this timer thread may still be writing to it, so consumers // synchronize on the list while iterating. We must hold the same monitor here. synchronized (dataList) { dataList.add(data); } return transaction != null - && options.getDateProvider().now().nanoTimestamp() + && nowNanos > startTimestamp + TimeUnit.MILLISECONDS.toNanos(TRANSACTION_COLLECTION_TIMEOUT_MILLIS); } From 22cbb55422a606f7b560f99877320d7f797a5a3f Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Tue, 11 Aug 2026 15:46:09 +0200 Subject: [PATCH 2/2] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6588c0a78f..7cf3268ee8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ ### Performance +- Read the clock once per performance collection round instead of once per in-flight transaction ([#5934](https://github.com/getsentry/sentry-java/pull/5934)) - Reduce allocations while collecting cpu usage during transactions by reading the process cpu time via `Process.getElapsedCpuTime()` instead of parsing `/proc/self/stat` (33.6kB to 16 bytes per sample on a Pixel 3) ([#5926](https://github.com/getsentry/sentry-java/pull/5926)) ### Dependencies