Skip to content

Commit 0686640

Browse files
authored
Fix timestamp intervals of PerformanceCollectionData in profiles (getsentry#2648)
* fixed timestamps of PerformanceCollectionData in profiles * updated ui test to cover all measurements cases
1 parent 18efe20 commit 0686640

File tree

4 files changed

+41
-27
lines changed

4 files changed

+41
-27
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
### Fixes
1212

13+
- Fix timestamp intervals of PerformanceCollectionData in profiles ([#2648](https://github.com/getsentry/sentry-java/pull/2648))
1314
- Fix timestamps of PerformanceCollectionData in profiles ([#2632](https://github.com/getsentry/sentry-java/pull/2632))
1415
- Fix missing propagateMinConstraints flag for SentryTraced ([#2637](https://github.com/getsentry/sentry-java/pull/2637))
1516

sentry-android-core/src/main/java/io/sentry/android/core/AndroidTransactionProfiler.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,9 @@ private void putPerformanceCollectionDataInMeasurements(
433433
// terms of System.currentTimeMillis() and measurements timestamps require the nanoseconds since
434434
// the beginning, expressed with SystemClock.elapsedRealtimeNanos()
435435
long timestampDiff =
436-
SystemClock.elapsedRealtimeNanos() - transactionStartNanos - System.currentTimeMillis();
436+
SystemClock.elapsedRealtimeNanos()
437+
- transactionStartNanos
438+
- TimeUnit.MILLISECONDS.toNanos(System.currentTimeMillis());
437439
if (performanceCollectionData != null) {
438440
final @NotNull ArrayDeque<ProfileMeasurementValue> memoryUsageMeasurements =
439441
new ArrayDeque<>(performanceCollectionData.size());
@@ -447,17 +449,19 @@ private void putPerformanceCollectionDataInMeasurements(
447449
if (cpuData != null) {
448450
cpuUsageMeasurements.add(
449451
new ProfileMeasurementValue(
450-
cpuData.getTimestampMillis() + timestampDiff, cpuData.getCpuUsagePercentage()));
452+
TimeUnit.MILLISECONDS.toNanos(cpuData.getTimestampMillis()) + timestampDiff,
453+
cpuData.getCpuUsagePercentage()));
451454
}
452455
if (memoryData != null && memoryData.getUsedHeapMemory() > -1) {
453456
memoryUsageMeasurements.add(
454457
new ProfileMeasurementValue(
455-
memoryData.getTimestampMillis() + timestampDiff, memoryData.getUsedHeapMemory()));
458+
TimeUnit.MILLISECONDS.toNanos(memoryData.getTimestampMillis()) + timestampDiff,
459+
memoryData.getUsedHeapMemory()));
456460
}
457461
if (memoryData != null && memoryData.getUsedNativeMemory() > -1) {
458462
nativeMemoryUsageMeasurements.add(
459463
new ProfileMeasurementValue(
460-
memoryData.getTimestampMillis() + timestampDiff,
464+
TimeUnit.MILLISECONDS.toNanos(memoryData.getTimestampMillis()) + timestampDiff,
461465
memoryData.getUsedNativeMemory()));
462466
}
463467
}

sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/EnvelopeTests.kt

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ class EnvelopeTests : BaseUiTest() {
8888
val slowFrames = profilingTraceData.measurementsMap[ProfileMeasurement.ID_SLOW_FRAME_RENDERS]
8989
val frozenFrames = profilingTraceData.measurementsMap[ProfileMeasurement.ID_FROZEN_FRAME_RENDERS]
9090
val frameRates = profilingTraceData.measurementsMap[ProfileMeasurement.ID_SCREEN_FRAME_RATES]!!
91-
val memoryStats = profilingTraceData.measurementsMap[ProfileMeasurement.ID_MEMORY_FOOTPRINT]!!
92-
val memoryNativeStats = profilingTraceData.measurementsMap[ProfileMeasurement.ID_MEMORY_NATIVE_FOOTPRINT]!!
93-
val cpuStats = profilingTraceData.measurementsMap[ProfileMeasurement.ID_CPU_USAGE]!!
91+
val memoryStats = profilingTraceData.measurementsMap[ProfileMeasurement.ID_MEMORY_FOOTPRINT]
92+
val memoryNativeStats = profilingTraceData.measurementsMap[ProfileMeasurement.ID_MEMORY_NATIVE_FOOTPRINT]
93+
val cpuStats = profilingTraceData.measurementsMap[ProfileMeasurement.ID_CPU_USAGE]
9494
// Slow and frozen frames can be null (in case there were none)
9595
if (slowFrames != null) {
9696
assertEquals(ProfileMeasurement.UNIT_NANOSECONDS, slowFrames.unit)
@@ -101,28 +101,35 @@ class EnvelopeTests : BaseUiTest() {
101101
// There could be no slow/frozen frames, but we expect at least one frame rate
102102
assertEquals(ProfileMeasurement.UNIT_HZ, frameRates.unit)
103103
assertTrue(frameRates.values.isNotEmpty())
104-
assertEquals(ProfileMeasurement.UNIT_BYTES, memoryStats.unit)
105-
assertTrue(memoryStats.values.isNotEmpty())
106-
assertEquals(ProfileMeasurement.UNIT_BYTES, memoryNativeStats.unit)
107-
assertTrue(memoryNativeStats.values.isNotEmpty())
108-
assertEquals(ProfileMeasurement.UNIT_PERCENT, cpuStats.unit)
109-
assertTrue(cpuStats.values.isNotEmpty())
104+
memoryStats?.let {
105+
assertEquals(ProfileMeasurement.UNIT_BYTES, it.unit)
106+
assertEquals(true, it.values.isNotEmpty())
107+
}
108+
memoryNativeStats?.let {
109+
assertEquals(ProfileMeasurement.UNIT_BYTES, it.unit)
110+
assertEquals(true, it.values.isNotEmpty())
111+
}
112+
cpuStats?.let {
113+
assertEquals(ProfileMeasurement.UNIT_PERCENT, it.unit)
114+
assertEquals(true, it.values.isNotEmpty())
115+
}
110116

111117
// We allow measurements to be added since the start up to the end of the profile, with a small tolerance due to threading
112-
val maxTimestampAllowed = profilingTraceData.durationNs.toLong() + TimeUnit.SECONDS.toNanos(1)
113-
114-
assertTrue((slowFrames?.values?.maxOf { it.relativeStartNs.toLong() } ?: 0) < maxTimestampAllowed)
115-
assertTrue((slowFrames?.values?.minOf { it.relativeStartNs.toLong() } ?: 0) >= 0)
116-
assertTrue((frozenFrames?.values?.maxOf { it.relativeStartNs.toLong() } ?: 0) < maxTimestampAllowed)
117-
assertTrue((frozenFrames?.values?.minOf { it.relativeStartNs.toLong() } ?: 0) >= 0)
118-
assertTrue(frameRates.values.maxOf { it.relativeStartNs.toLong() } < maxTimestampAllowed)
119-
assertTrue(frameRates.values.minOf { it.relativeStartNs.toLong() } > 0)
120-
assertTrue(memoryStats.values.maxOf { it.relativeStartNs.toLong() } < maxTimestampAllowed)
121-
assertTrue(memoryStats.values.minOf { it.relativeStartNs.toLong() } > 0)
122-
assertTrue(memoryNativeStats.values.maxOf { it.relativeStartNs.toLong() } < maxTimestampAllowed)
123-
assertTrue(memoryNativeStats.values.minOf { it.relativeStartNs.toLong() } > 0)
124-
assertTrue(cpuStats.values.maxOf { it.relativeStartNs.toLong() } < maxTimestampAllowed)
125-
assertTrue(cpuStats.values.minOf { it.relativeStartNs.toLong() } > 0)
118+
val maxTimestampAllowed = profilingTraceData.durationNs.toLong() + TimeUnit.SECONDS.toNanos(2)
119+
val allMeasurements = profilingTraceData.measurementsMap.values
120+
121+
allMeasurements.filter { it.values.isNotEmpty() }.forEach { measurement ->
122+
val values = measurement.values.sortedBy { it.relativeStartNs.toLong() }
123+
// There should be no measurement before the profile starts
124+
assertTrue(values.first().relativeStartNs.toLong() > 0)
125+
// There should be no measurement after the profile ends
126+
assertTrue(values.last().relativeStartNs.toLong() < maxTimestampAllowed)
127+
128+
// Timestamps of measurements should differ at least 10 milliseconds from each other
129+
(1 until values.size).forEach { i ->
130+
assertTrue(values[i].relativeStartNs.toLong() > values[i - 1].relativeStartNs.toLong() + TimeUnit.MILLISECONDS.toNanos(10))
131+
}
132+
}
126133

127134
// We should find the transaction id that started the profiling in the list of transactions
128135
val transactionData = profilingTraceData.transactions

sentry-samples/sentry-samples-android/src/main/AndroidManifest.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
<!-- Just some random permissions to showcase the permission context sent to Sentry -->
1313
<uses-permission android:name="android.permission.CAMERA"/>
1414
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
15+
<!-- Needed by leakcanary.NotificationEventListener -->
16+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
1517

1618
<!-- if your minSdkVersion < 16, this would make usable on minSdkVersion >= 14-->
1719
<uses-sdk

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy