Skip to content

Commit 734e4a5

Browse files
authored
Update benchmark cpu approach (#2473)
* updated benchmark devices * added sustained performance mode on profiling benchmarks, but not on sdk init * changed cpu time reading from Process.getElapsedCpuTime() to reading /proc/self/stat file * reverted threshold from 5.5% to 5% * removed absolute time check in SdkBenchmarkTest * converted cpu time from milliseconds to nanoseconds
1 parent 68dfbfd commit 734e4a5

File tree

7 files changed

+56
-28
lines changed

7 files changed

+56
-28
lines changed

.sauce/sentry-uitest-android-benchmark.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,23 @@ suites:
2525
useTestOrchestrator: true
2626
devices:
2727
- id: Google_Pixel_6_Pro_real_us # Google Pixel 6 Pro - api 31 (12) - high end
28-
- id: Google_Pixel_6a_real_us # Google Pixel 6a - api 31 (12) - low end
28+
- id: Google_Pixel_5_12_real_us # Google Pixel 5 - api 31 (12) - low end
2929

3030
- name: "Android 11 (api 30)"
3131
testOptions:
3232
clearPackageData: true
3333
useTestOrchestrator: true
3434
devices:
3535
- id: OnePlus_9_Pro_real_us # OnePlus 9 Pro - api 30 (11) - high end
36-
- id: Google_Pixel_4_real_us # Google Pixel 4 - api 30 (11) - mid end
36+
- id: Samsung_Galaxy_A71_5G_real_us # Samsung Galaxy A71 5G - api 30 (11) - mid end
3737
- id: Google_Pixel_3a_real # Google Pixel 3a - api 30 (11) - low end
3838

3939
- name: "Android 10 (api 29)"
4040
testOptions:
4141
clearPackageData: true
4242
useTestOrchestrator: true
4343
devices:
44-
- id: Google_Pixel_4_XL_real_us1 # Google Pixel 4 XL - api 29 (10)
44+
- id: Google_Pixel_3a_XL_real # Google Pixel 3a XL - api 29 (10)
4545
- id: Nokia_7_1_real_us # Nokia 7.1 - api 29 (10)
4646

4747
# At the time of writing (July, 4, 2022), the market share per android version is:

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.sentry.uitest.android.benchmark
22

3+
import android.os.Bundle
34
import androidx.lifecycle.Lifecycle
45
import androidx.test.core.app.launchActivity
56
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -39,11 +40,8 @@ class SdkBenchmarkTest : BaseBenchmarkTest() {
3940
val perfProfilingSdkResult = perfProfilingSdkResults.getSummaryResult()
4041
perfProfilingSdkResult.printResults()
4142

42-
val maxDurationThreshold = TimeUnit.MILLISECONDS.toNanos(250)
43-
assertTrue(simpleSdkResult.durationIncreaseNanos in 0..maxDurationThreshold)
44-
assertTrue(simpleSdkResult.cpuTimeIncreaseMillis in 0..100)
45-
assertTrue(perfProfilingSdkResult.durationIncreaseNanos in 0..maxDurationThreshold)
46-
assertTrue(perfProfilingSdkResult.cpuTimeIncreaseMillis in 0..100)
43+
assertTrue(simpleSdkResult.cpuTimeIncreaseNanos in 0..TimeUnit.MILLISECONDS.toNanos(100))
44+
assertTrue(perfProfilingSdkResult.cpuTimeIncreaseNanos in 0..TimeUnit.MILLISECONDS.toNanos(100))
4745
}
4846

4947
private fun getOperation(init: (() -> Unit)? = null) = BenchmarkOperation(
@@ -52,7 +50,9 @@ class SdkBenchmarkTest : BaseBenchmarkTest() {
5250
runner.runOnMainSync {
5351
init?.invoke()
5452
}
55-
val benchmarkScenario = launchActivity<BenchmarkActivity>()
53+
val benchmarkScenario = launchActivity<BenchmarkActivity>(
54+
activityOptions = Bundle().apply { putBoolean(BenchmarkActivity.EXTRA_SUSTAINED_PERFORMANCE_MODE, false) }
55+
)
5656
benchmarkScenario.moveToState(Lifecycle.State.DESTROYED)
5757
},
5858
after = {

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.sentry.uitest.android.benchmark
22

3+
import android.os.Bundle
34
import androidx.lifecycle.Lifecycle
45
import androidx.test.core.app.launchActivity
56
import androidx.test.espresso.Espresso
@@ -89,7 +90,7 @@ class SentryBenchmarkTest : BaseBenchmarkTest() {
8990
comparisonResult.printResults()
9091

9192
// Currently we just want to assert the cpu overhead
92-
assertTrue(comparisonResult.cpuTimeIncreasePercentage in 0F..5.5F)
93+
assertTrue(comparisonResult.cpuTimeIncreasePercentage in 0F..5F)
9394
}
9495

9596
/**
@@ -99,7 +100,9 @@ class SentryBenchmarkTest : BaseBenchmarkTest() {
99100
private fun getOperation(runner: AndroidJUnitRunner, transactionBuilder: () -> ITransaction? = { null }): () -> Unit = {
100101
var transaction: ITransaction? = null
101102
// Launch the sentry-uitest-android-benchmark activity
102-
val benchmarkScenario = launchActivity<BenchmarkActivity>()
103+
val benchmarkScenario = launchActivity<BenchmarkActivity>(
104+
activityOptions = Bundle().apply { putBoolean(BenchmarkActivity.EXTRA_SUSTAINED_PERFORMANCE_MODE, true) }
105+
)
103106
// Starts a transaction (it can be null, but we still runOnMainSync to make operations as similar as possible)
104107
runner.runOnMainSync {
105108
transaction = transactionBuilder()

sentry-android-integration-tests/sentry-uitest-android-benchmark/src/androidTest/java/io/sentry/uitest/android/benchmark/util/BenchmarkComparisonResult.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ internal data class BenchmarkComparisonResult(
7070
println(
7171
"$prefix CPU time overhead, over $cores cores: %.2f%% (%d ms)".format(
7272
cpuTimeIncreasePercentages[index],
73-
cpuTimeIncreases[index]
73+
TimeUnit.NANOSECONDS.toMillis(cpuTimeIncreases[index])
7474
)
7575
)
7676

@@ -111,10 +111,10 @@ internal data class BenchmarkComparisonResult(
111111
/** Result of the [BenchmarkOperation] comparison. */
112112
internal data class BenchmarkSummaryResult(
113113
/**
114-
* Increase of cpu time in milliseconds.
114+
* Increase of cpu time in nanoseconds.
115115
* It has no direct impact on performance of the app, but it has on battery usage, as the cpu is 'awaken' longer.
116116
*/
117-
val cpuTimeIncreaseMillis: Long,
117+
val cpuTimeIncreaseNanos: Long,
118118
/** Increase of cpu time in percentage. */
119119
val cpuTimeIncreasePercentage: Double,
120120
/**
@@ -146,7 +146,7 @@ internal data class BenchmarkSummaryResult(
146146
TimeUnit.NANOSECONDS.toMillis(durationIncreaseNanos)
147147
)
148148
)
149-
println("CPU time overhead: %.2f%% (%d ms)".format(cpuTimeIncreasePercentage, cpuTimeIncreaseMillis))
149+
println("CPU time overhead: %.2f%% (%d ms)".format(cpuTimeIncreasePercentage, cpuTimeIncreaseNanos))
150150
println("FPS decrease: %.2f%% (%d fps)".format(fpsDecreasePercentage, fpsDecrease))
151151
println("Frame drop increase: %.2f%% (%.2f)".format(droppedFramesIncreasePercentage, droppedFramesIncrease))
152152
}

sentry-android-integration-tests/sentry-uitest-android-benchmark/src/androidTest/java/io/sentry/uitest/android/benchmark/util/BenchmarkOperation.kt

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package io.sentry.uitest.android.benchmark.util
22

3-
import android.os.Process
43
import android.os.SystemClock
4+
import android.system.Os
5+
import android.system.OsConstants
56
import android.view.Choreographer
7+
import java.io.File
68
import java.util.LinkedList
79
import java.util.concurrent.TimeUnit
810

@@ -79,7 +81,7 @@ internal class BenchmarkOperation(
7981
}
8082

8183
private var lastFrameTimeNanos: Long = 0
82-
private val cpuDurationMillisList: MutableList<Long> = LinkedList()
84+
private val cpuDurationNanosList: MutableList<Long> = LinkedList()
8385
private val droppedFramesList: MutableList<Double> = LinkedList()
8486
private val durationNanosList: MutableList<Long> = LinkedList()
8587
private val fpsList: MutableList<Int> = LinkedList()
@@ -99,15 +101,15 @@ internal class BenchmarkOperation(
99101
frameCallback.setup(refreshRate)
100102

101103
val startRealtimeNs = SystemClock.elapsedRealtimeNanos()
102-
val startCpuTimeMs = Process.getElapsedCpuTime()
104+
val startCpuTimeMs = readProcessorTimeNanos()
103105
lastFrameTimeNanos = startRealtimeNs
104106

105107
choreographer.postFrameCallback(frameCallback)
106108
op()
107109
choreographer.removeFrameCallback(frameCallback)
108110

109111
val durationNanos = SystemClock.elapsedRealtimeNanos() - startRealtimeNs
110-
cpuDurationMillisList.add(Process.getElapsedCpuTime() - startCpuTimeMs)
112+
cpuDurationNanosList.add(readProcessorTimeNanos() - startCpuTimeMs)
111113
durationNanosList.add(durationNanos)
112114
droppedFramesList.add(frameCallback.droppedFrames)
113115
// fps = counted frames per seconds converted into frames per nanoseconds, divided by duration in nanoseconds
@@ -118,10 +120,26 @@ internal class BenchmarkOperation(
118120
isolate()
119121
}
120122

123+
private fun readProcessorTimeNanos(): Long {
124+
val clockSpeedHz = Os.sysconf(OsConstants._SC_CLK_TCK)
125+
// val numCores = Os.sysconf(OsConstants._SC_NPROCESSORS_CONF)
126+
val nanosecondsPerClockTick = 1_000_000_000 / clockSpeedHz.toDouble()
127+
val selfStat = File("/proc/self/stat")
128+
val stats = selfStat.readText().trim().split("[\n\t\r ]".toRegex())
129+
if (stats.isNotEmpty()) {
130+
val uTime = stats[13].toLong()
131+
val sTime = stats[14].toLong()
132+
val cuTime = stats[15].toLong()
133+
val csTime = stats[16].toLong()
134+
return ((uTime + sTime + cuTime + csTime) * nanosecondsPerClockTick).toLong()
135+
}
136+
return 0
137+
}
138+
121139
/** Return the [BenchmarkOperationComparable] for the operation. */
122140
private fun getResult(operationName: String): BenchmarkOperationComparable {
123141
return BenchmarkOperationComparable(
124-
cpuDurationMillisList,
142+
cpuDurationNanosList,
125143
droppedFramesList,
126144
durationNanosList,
127145
fpsList,

sentry-android-integration-tests/sentry-uitest-android-benchmark/src/androidTest/java/io/sentry/uitest/android/benchmark/util/BenchmarkOperationComparable.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import java.util.concurrent.TimeUnit
44

55
/** Stores the results of a single run of [BenchmarkOperation]. */
66
internal data class BenchmarkOperationComparable(
7-
val cpuTimeMillis: List<Long>,
7+
val cpuTimeNanos: List<Long>,
88
val droppedFrames: List<Double>,
99
val durationNanos: List<Long>,
1010
val fps: List<Int>,
@@ -15,7 +15,7 @@ internal data class BenchmarkOperationComparable(
1515
val cores = Runtime.getRuntime().availableProcessors()
1616
val durationIncreaseNanos = ArrayList<Long>()
1717
val durationIncreasePercentage = ArrayList<Double>()
18-
val cpuTimeIncreaseMillis = ArrayList<Long>()
18+
val cpuTimeIncreaseNanos = ArrayList<Long>()
1919
val cpuTimeOverheadPercentage = ArrayList<Double>()
2020
val fpsDecrease = ArrayList<Int>()
2121
val fpsDecreasePercentage = ArrayList<Double>()
@@ -29,8 +29,8 @@ internal data class BenchmarkOperationComparable(
2929

3030
// Measure average cpu time
3131
// Cpu time spent profiling is weighted based on available threads, as profiling runs on 1 thread only.
32-
cpuTimeIncreaseMillis.add((cpuTimeMillis[index] - other.cpuTimeMillis[index]) / cores)
33-
cpuTimeOverheadPercentage.add(cpuTimeIncreaseMillis[index] * 100.0 / other.cpuTimeMillis[index])
32+
cpuTimeIncreaseNanos.add((cpuTimeNanos[index] - other.cpuTimeNanos[index]) / cores)
33+
cpuTimeOverheadPercentage.add(cpuTimeIncreaseNanos[index] * 100.0 / other.cpuTimeNanos[index])
3434

3535
// Measure average fps
3636
fpsDecrease.add(other.fps[index] - fps[index])
@@ -50,9 +50,9 @@ internal data class BenchmarkOperationComparable(
5050
cores,
5151
operationName,
5252
other.operationName,
53-
cpuTimeMillis,
54-
other.cpuTimeMillis,
55-
cpuTimeIncreaseMillis,
53+
cpuTimeNanos,
54+
other.cpuTimeNanos,
55+
cpuTimeIncreaseNanos,
5656
cpuTimeOverheadPercentage,
5757
droppedFrames,
5858
other.droppedFrames,

sentry-android-integration-tests/sentry-uitest-android-benchmark/src/main/java/io/sentry/uitest/android/benchmark/BenchmarkActivity.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ import java.util.concurrent.Executors
1212

1313
/** A simple activity with a list of bitmaps. */
1414
class BenchmarkActivity : AppCompatActivity() {
15-
1615
companion object {
1716

1817
/** The activity will set this when scrolling. */
1918
val scrollingIdlingResource = CountingIdlingResource("sentry-uitest-android-benchmark-activityScrolling")
2019

2120
/** The refresh rate of the device, set on activity create. */
2221
var refreshRate: Float? = null
22+
23+
internal const val EXTRA_SUSTAINED_PERFORMANCE_MODE = "EXTRA_SUSTAINED_PERFORMANCE_MODE"
2324
}
2425

2526
/**
@@ -35,6 +36,12 @@ class BenchmarkActivity : AppCompatActivity() {
3536
override fun onCreate(savedInstanceState: Bundle?) {
3637
super.onCreate(savedInstanceState)
3738

39+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&
40+
savedInstanceState?.getBoolean(EXTRA_SUSTAINED_PERFORMANCE_MODE) == true
41+
) {
42+
window.setSustainedPerformanceMode(true)
43+
}
44+
3845
refreshRate = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
3946
display?.refreshRate
4047
} else {

0 commit comments

Comments
 (0)