Skip to content

Commit fb1c50c

Browse files
authored
Send cpu usage percentage in profile payload (#2469)
* Added cpu usage percentage to profile payload * Added a ui test to check memory and cpu usages being sent in profiles
1 parent b049670 commit fb1c50c

File tree

7 files changed

+63
-5
lines changed

7 files changed

+63
-5
lines changed

CHANGELOG.md

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

55
### Features
66

7+
- Send cpu usage percentage in profile payload ([#2469](https://github.com/getsentry/sentry-java/pull/2469))
78
- Send transaction memory stats in profile payload ([#2447](https://github.com/getsentry/sentry-java/pull/2447))
89
- Add cpu usage collection ([#2462](https://github.com/getsentry/sentry-java/pull/2462))
910
- Improve ANR implementation: ([#2475](https://github.com/getsentry/sentry-java/pull/2475))

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import android.os.Process;
1212
import android.os.SystemClock;
1313
import android.view.FrameMetrics;
14+
import io.sentry.CpuCollectionData;
1415
import io.sentry.HubAdapter;
1516
import io.sentry.IHub;
1617
import io.sentry.ITransaction;
@@ -417,12 +418,18 @@ public void onFrameMetricCollected(
417418
private void putPerformanceCollectionDataInMeasurements(
418419
final @Nullable PerformanceCollectionData performanceCollectionData) {
419420
if (performanceCollectionData != null) {
420-
List<MemoryCollectionData> memoryCollectionData = performanceCollectionData.getMemoryData();
421421
final @NotNull ArrayDeque<ProfileMeasurementValue> memoryUsageMeasurements =
422422
new ArrayDeque<>();
423423
final @NotNull ArrayDeque<ProfileMeasurementValue> nativeMemoryUsageMeasurements =
424424
new ArrayDeque<>();
425-
for (MemoryCollectionData memoryData : memoryCollectionData) {
425+
final @NotNull ArrayDeque<ProfileMeasurementValue> cpuUsageMeasurements = new ArrayDeque<>();
426+
for (CpuCollectionData cpuData : performanceCollectionData.getCpuData()) {
427+
cpuUsageMeasurements.add(
428+
new ProfileMeasurementValue(
429+
TimeUnit.MILLISECONDS.toNanos(cpuData.getTimestampMillis()) - transactionStartNanos,
430+
cpuData.getCpuUsagePercentage()));
431+
}
432+
for (MemoryCollectionData memoryData : performanceCollectionData.getMemoryData()) {
426433
if (memoryData.getUsedHeapMemory() > -1) {
427434
memoryUsageMeasurements.add(
428435
new ProfileMeasurementValue(
@@ -438,6 +445,11 @@ private void putPerformanceCollectionDataInMeasurements(
438445
memoryData.getUsedNativeMemory()));
439446
}
440447
}
448+
if (!cpuUsageMeasurements.isEmpty()) {
449+
measurementsMap.put(
450+
ProfileMeasurement.ID_CPU_USAGE,
451+
new ProfileMeasurement(ProfileMeasurement.UNIT_PERCENT, cpuUsageMeasurements));
452+
}
441453
if (!memoryUsageMeasurements.isEmpty()) {
442454
measurementsMap.put(
443455
ProfileMeasurement.ID_MEMORY_FOOTPRINT,

sentry-android-core/src/test/java/io/sentry/android/core/AndroidTransactionProfilerTest.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.content.Context
44
import android.os.Build
55
import androidx.test.core.app.ApplicationProvider
66
import androidx.test.ext.junit.runners.AndroidJUnit4
7+
import io.sentry.CpuCollectionData
78
import io.sentry.IHub
89
import io.sentry.ILogger
910
import io.sentry.ISentryExecutorService
@@ -363,27 +364,33 @@ class AndroidTransactionProfilerTest {
363364
}
364365

365366
@Test
366-
fun `profiler does not includes memory measurements when null is passed on transaction finish`() {
367+
fun `profiler does not includes performance measurements when null is passed on transaction finish`() {
367368
val profiler = fixture.getSut(context)
368369
profiler.onTransactionStart(fixture.transaction1)
369370
val data = profiler.onTransactionFinish(fixture.transaction1, null)
370371
assertFalse(data!!.measurementsMap.containsKey(ProfileMeasurement.ID_MEMORY_FOOTPRINT))
371372
assertFalse(data.measurementsMap.containsKey(ProfileMeasurement.ID_MEMORY_NATIVE_FOOTPRINT))
373+
assertFalse(data.measurementsMap.containsKey(ProfileMeasurement.ID_CPU_USAGE))
372374
}
373375

374376
@Test
375-
fun `profiler includes memory measurements when passed on transaction finish`() {
377+
fun `profiler includes performance measurements when passed on transaction finish`() {
376378
val profiler = fixture.getSut(context)
377379
val memoryCollectionData = PerformanceCollectionData()
378380
memoryCollectionData.addMemoryData(MemoryCollectionData(1, 2, 3))
381+
memoryCollectionData.addCpuData(CpuCollectionData(1, 1.4))
379382
memoryCollectionData.commitData()
380383
memoryCollectionData.addMemoryData(MemoryCollectionData(2, 3, 4))
381384
memoryCollectionData.commitData()
382385
profiler.onTransactionStart(fixture.transaction1)
383386
val data = profiler.onTransactionFinish(fixture.transaction1, memoryCollectionData)
387+
assertContentEquals(
388+
listOf(1.4),
389+
data!!.measurementsMap[ProfileMeasurement.ID_CPU_USAGE]!!.values.map { it.value }
390+
)
384391
assertContentEquals(
385392
listOf(2.0, 3.0),
386-
data!!.measurementsMap[ProfileMeasurement.ID_MEMORY_FOOTPRINT]!!.values.map { it.value }
393+
data.measurementsMap[ProfileMeasurement.ID_MEMORY_FOOTPRINT]!!.values.map { it.value }
387394
)
388395
assertContentEquals(
389396
listOf(3.0, 4.0),

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +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]!!
9194
// Slow and frozen frames can be null (in case there were none)
9295
if (slowFrames != null) {
9396
assertEquals(ProfileMeasurement.UNIT_NANOSECONDS, slowFrames.unit)
@@ -98,6 +101,12 @@ class EnvelopeTests : BaseUiTest() {
98101
// There could be no slow/frozen frames, but we expect at least one frame rate
99102
assertEquals(ProfileMeasurement.UNIT_HZ, frameRates.unit)
100103
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())
101110

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

sentry/api/sentry.api

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2429,6 +2429,7 @@ public final class io/sentry/internal/modules/ResourcesModulesLoader : io/sentry
24292429
}
24302430

24312431
public final class io/sentry/profilemeasurements/ProfileMeasurement : io/sentry/JsonSerializable, io/sentry/JsonUnknown {
2432+
public static final field ID_CPU_USAGE Ljava/lang/String;
24322433
public static final field ID_FROZEN_FRAME_RENDERS Ljava/lang/String;
24332434
public static final field ID_MEMORY_FOOTPRINT Ljava/lang/String;
24342435
public static final field ID_MEMORY_NATIVE_FOOTPRINT Ljava/lang/String;
@@ -2438,6 +2439,7 @@ public final class io/sentry/profilemeasurements/ProfileMeasurement : io/sentry/
24382439
public static final field UNIT_BYTES Ljava/lang/String;
24392440
public static final field UNIT_HZ Ljava/lang/String;
24402441
public static final field UNIT_NANOSECONDS Ljava/lang/String;
2442+
public static final field UNIT_PERCENT Ljava/lang/String;
24412443
public static final field UNIT_UNKNOWN Ljava/lang/String;
24422444
public fun <init> ()V
24432445
public fun <init> (Ljava/lang/String;Ljava/util/Collection;)V

sentry/src/main/java/io/sentry/profilemeasurements/ProfileMeasurement.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ public final class ProfileMeasurement implements JsonUnknown, JsonSerializable {
2424
public static final String ID_FROZEN_FRAME_RENDERS = "frozen_frame_renders";
2525
public static final String ID_SLOW_FRAME_RENDERS = "slow_frame_renders";
2626
public static final String ID_SCREEN_FRAME_RATES = "screen_frame_rates";
27+
public static final String ID_CPU_USAGE = "cpu_usage";
2728
public static final String ID_MEMORY_FOOTPRINT = "memory_footprint";
2829
public static final String ID_MEMORY_NATIVE_FOOTPRINT = "memory_native_footprint";
2930
public static final String ID_UNKNOWN = "unknown";
3031

3132
public static final String UNIT_HZ = "hz";
3233
public static final String UNIT_NANOSECONDS = "nanosecond";
3334
public static final String UNIT_BYTES = "byte";
35+
public static final String UNIT_PERCENT = "percent";
3436
public static final String UNIT_UNKNOWN = "unknown";
3537

3638
private @Nullable Map<String, Object> unknown;

sentry/src/test/java/io/sentry/JsonSerializerTest.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,11 @@ class JsonSerializerTest {
532532
ProfileMeasurement(
533533
ProfileMeasurement.UNIT_BYTES,
534534
listOf(ProfileMeasurementValue(3, 104.52))
535+
),
536+
ProfileMeasurement.ID_CPU_USAGE to
537+
ProfileMeasurement(
538+
ProfileMeasurement.UNIT_PERCENT,
539+
listOf(ProfileMeasurementValue(5, 10.52))
535540
)
536541
)
537542
)
@@ -609,6 +614,16 @@ class JsonSerializerTest {
609614
"elapsed_since_start_ns" to "3"
610615
)
611616
)
617+
),
618+
ProfileMeasurement.ID_CPU_USAGE to
619+
mapOf(
620+
"unit" to ProfileMeasurement.UNIT_PERCENT,
621+
"values" to listOf(
622+
mapOf(
623+
"value" to 10.52,
624+
"elapsed_since_start_ns" to "5"
625+
)
626+
)
612627
)
613628
),
614629
element["measurements"]
@@ -681,6 +696,12 @@ class JsonSerializerTest {
681696
"values":[
682697
{"value":"1100","elapsed_since_start_ns":"4"}
683698
]
699+
},
700+
"cpu_usage": {
701+
"unit":"percent",
702+
"values":[
703+
{"value":"17.04","elapsed_since_start_ns":"5"}
704+
]
684705
}
685706
},
686707
"transaction_name":"transactionName",
@@ -742,6 +763,10 @@ class JsonSerializerTest {
742763
ProfileMeasurement.ID_MEMORY_NATIVE_FOOTPRINT to ProfileMeasurement(
743764
ProfileMeasurement.UNIT_BYTES,
744765
listOf(ProfileMeasurementValue(4, 1100))
766+
),
767+
ProfileMeasurement.ID_CPU_USAGE to ProfileMeasurement(
768+
ProfileMeasurement.UNIT_PERCENT,
769+
listOf(ProfileMeasurementValue(5, 17.04))
745770
)
746771
)
747772
assertEquals(expectedMeasurements, profilingTraceData.measurementsMap)

0 commit comments

Comments
 (0)