1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.benchmark
18 
19 import androidx.benchmark.json.BenchmarkData
20 import androidx.test.ext.junit.runners.AndroidJUnit4
21 import androidx.test.filters.SmallTest
22 import com.google.common.truth.Truth.assertThat
23 import java.io.File
24 import kotlin.test.assertFailsWith
25 import org.junit.Before
26 import org.junit.Test
27 import org.junit.runner.RunWith
28 
29 @SmallTest
30 @RunWith(AndroidJUnit4::class)
31 class InstrumentationResultsTest {
32     @Before
setupnull33     fun setup() {
34         // flush any scheduled ide warnings so that tests below aren't affected
35         InstrumentationResults.ideSummary(
36             testName = "foo",
37             measurements =
38                 Measurements(
39                     singleMetrics = listOf(MetricResult("Metric", listOf(0.0))),
40                     sampledMetrics = emptyList()
41                 )
42         )
43     }
44 
45     @Test
ideSummaryBasicMicro_alignmentnull46     fun ideSummaryBasicMicro_alignment() {
47         val summary1 =
48             InstrumentationResults.ideSummaryBasicMicro(
49                 benchmarkName = "foo",
50                 nanos = 1000.0,
51                 allocations = 100.0,
52                 profilerResults = emptyList()
53             )
54         val summary2 =
55             InstrumentationResults.ideSummaryBasicMicro(
56                 benchmarkName = "fooBarLongerKey",
57                 nanos = 10000.0,
58                 allocations = 0.0,
59                 profilerResults = emptyList()
60             )
61         assertEquals(summary1.indexOf("foo"), summary2.indexOf("foo"))
62     }
63 
64     @Test
ideSummaryBasicMicro_allocsnull65     fun ideSummaryBasicMicro_allocs() {
66         assertEquals(
67             "        1,000   ns    foo",
68             InstrumentationResults.ideSummaryBasicMicro("foo", 1000.0, null, emptyList())
69         )
70         assertEquals(
71             "        1,000   ns          10 allocs    foo",
72             InstrumentationResults.ideSummaryBasicMicro("foo", 1000.0, 10.0, emptyList())
73         )
74     }
75 
76     @Test
ideSummaryBasicMicro_decimalnull77     fun ideSummaryBasicMicro_decimal() {
78         assertEquals(
79             "        1,000   ns    foo",
80             InstrumentationResults.ideSummaryBasicMicro("foo", 1000.0, null, emptyList())
81         )
82         assertEquals(
83             "          100   ns    foo", // 10ths not shown ...
84             InstrumentationResults.ideSummaryBasicMicro("foo", 100.4, null, emptyList())
85         )
86         assertEquals(
87             "           99.9 ns    foo", // ... until value is < 100
88             InstrumentationResults.ideSummaryBasicMicro("foo", 99.9, null, emptyList())
89         )
90         assertEquals(
91             "            1.0 ns    foo",
92             InstrumentationResults.ideSummaryBasicMicro("foo", 1.0, null, emptyList())
93         )
94     }
95 
96     @Test
ideSummaryBasicMicro_profilerResultnull97     fun ideSummaryBasicMicro_profilerResult() {
98         assertEquals(
99             "        1,000   ns    [Trace Label](file://tracePath.trace)    foo",
100             InstrumentationResults.ideSummaryBasicMicro(
101                 benchmarkName = "foo",
102                 nanos = 1000.0,
103                 allocations = null,
104                 listOf(
105                     Profiler.ResultFile.of(
106                         label = "Trace Label",
107                         outputRelativePath = "tracePath.trace",
108                         type = BenchmarkData.TestResult.ProfilerOutput.Type.MethodTrace,
109                         source = MethodTracing
110                     )
111                 )
112             )
113         )
114     }
115 
createAbsoluteTracePathsnull116     private fun createAbsoluteTracePaths(@Suppress("SameParameterValue") count: Int) =
117         List(count) { File(Outputs.dirUsableByAppAndShell, "iter$it.trace").absolutePath }
118 
119     @Test
ideSummary_singleMinimalnull120     fun ideSummary_singleMinimal() {
121         val metricResult = MetricResult("Metric", listOf(0.0, 1.1, 2.2))
122 
123         assertEquals(0, metricResult.minIndex)
124         assertEquals(1, metricResult.medianIndex)
125         assertEquals(2, metricResult.maxIndex)
126         val absoluteTracePaths = createAbsoluteTracePaths(3)
127         val summary =
128             InstrumentationResults.ideSummary(
129                 testName = "foo",
130                 measurements =
131                     Measurements(
132                         singleMetrics = listOf(metricResult),
133                         sampledMetrics = emptyList()
134                     ),
135                 iterationTracePaths = absoluteTracePaths
136             )
137         assertEquals(
138             """
139                 |foo
140                 |  Metric   [min 0.0](file://iter0.trace),   [median 1.1](file://iter1.trace),   [max 2.2](file://iter2.trace)
141                 |    Traces: Iteration [0](file://iter0.trace) [1](file://iter1.trace) [2](file://iter2.trace)
142                 |
143             """
144                 .trimMargin(),
145             summary.summaryV2
146         )
147         // v1 is deprecated and should be the same as v2
148         assertEquals(summary.summaryV1, summary.summaryV2)
149     }
150 
151     @Test
ideSummary_singleComplexnull152     fun ideSummary_singleComplex() {
153         val metric1 = MetricResult("Metric1", listOf(0.0, 1.0, 2.0))
154         val metric2 = MetricResult("Metric2", listOf(222.0, 111.0, 0.0))
155         val summary =
156             InstrumentationResults.ideSummary(
157                 testName = "foo",
158                 measurements =
159                     Measurements(
160                         singleMetrics = listOf(metric1, metric2),
161                         sampledMetrics = emptyList()
162                     ),
163                 iterationTracePaths = createAbsoluteTracePaths(3)
164             )
165         assertEquals(
166             """
167                 |foo
168                 |  Metric1   [min   0.0](file://iter0.trace),   [median   1.0](file://iter1.trace),   [max   2.0](file://iter2.trace)
169                 |  Metric2   [min   0.0](file://iter2.trace),   [median 111.0](file://iter1.trace),   [max 222.0](file://iter0.trace)
170                 |    Traces: Iteration [0](file://iter0.trace) [1](file://iter1.trace) [2](file://iter2.trace)
171                 |
172             """
173                 .trimMargin(),
174             summary.summaryV2
175         )
176         // v1 is deprecated and should be the same as v2
177         assertEquals(summary.summaryV1, summary.summaryV2)
178     }
179 
180     @Test
ideSummary_sampledMinimalnull181     fun ideSummary_sampledMinimal() {
182         val metricResult = MetricResult("Metric1", List(101) { it.toDouble() })
183         val summary =
184             InstrumentationResults.ideSummary(
185                 testName = "foo",
186                 measurements =
187                     Measurements(
188                         singleMetrics = emptyList(),
189                         sampledMetrics = listOf(metricResult)
190                     ),
191                 iterationTracePaths = createAbsoluteTracePaths(3)
192             )
193         assertEquals(
194             """
195                 |foo
196                 |  Metric1   P50   50.0,   P90   90.0,   P95   95.0,   P99   99.0
197                 |    Traces: Iteration [0](file://iter0.trace) [1](file://iter1.trace) [2](file://iter2.trace)
198                 |
199             """
200                 .trimMargin(),
201             summary.summaryV2
202         )
203         // v1 is deprecated and should be the same as v2
204         assertEquals(summary.summaryV1, summary.summaryV2)
205     }
206 
207     @Test
ideSummary_complexnull208     public fun ideSummary_complex() {
209         val single = MetricResult("Metric1", listOf(0.0, 1.0, 2.0))
210         val sampled = MetricResult("Metric2", List(101) { it.toDouble() })
211         val absoluteTracePaths = createAbsoluteTracePaths(3)
212         val summary =
213             InstrumentationResults.ideSummary(
214                 testName = "foo",
215                 measurements =
216                     Measurements(singleMetrics = listOf(single), sampledMetrics = listOf(sampled)),
217                 iterationTracePaths = absoluteTracePaths
218             )
219         assertEquals(
220             """
221                 |foo
222                 |  Metric1   [min   0.0](file://iter0.trace),   [median   1.0](file://iter1.trace),   [max   2.0](file://iter2.trace)
223                 |  Metric2   P50   50.0,   P90   90.0,   P95   95.0,   P99   99.0
224                 |    Traces: Iteration [0](file://iter0.trace) [1](file://iter1.trace) [2](file://iter2.trace)
225                 |
226             """
227                 .trimMargin(),
228             summary.summaryV2
229         )
230         // v1 is deprecated and should be the same as v2
231         assertEquals(summary.summaryV1, summary.summaryV2)
232     }
233 
234     @Test
ideSummary_warning_singleLinenull235     fun ideSummary_warning_singleLine() {
236         val metricResult = MetricResult("timeNs", listOf(0.0, 1.0, 2.0))
237 
238         InstrumentationResults.scheduleIdeWarningOnNextReport("warning\nstring")
239         val summary =
240             InstrumentationResults.ideSummary(
241                 testName = "foo",
242                 measurements =
243                     Measurements(
244                         singleMetrics = listOf(metricResult),
245                         sampledMetrics = emptyList()
246                     ),
247             )
248         assertEquals(
249             """
250                 |warning
251                 |string
252                 |            0.0 ns    foo
253             """
254                 .trimMargin(),
255             summary.summaryV2
256         )
257         // v1 is deprecated and should be the same as v2
258         assertEquals(summary.summaryV1, summary.summaryV2)
259     }
260 
261     @Test
ideSummary_warningnull262     fun ideSummary_warning() {
263         val metricResult = MetricResult("Metric", listOf(0.0, 1.0, 2.0))
264         val absoluteTracePaths = createAbsoluteTracePaths(3)
265 
266         InstrumentationResults.scheduleIdeWarningOnNextReport("warning\nstring")
267         val summary =
268             InstrumentationResults.ideSummary(
269                 testName = "foo",
270                 measurements =
271                     Measurements(
272                         singleMetrics = listOf(metricResult),
273                         sampledMetrics = emptyList()
274                     ),
275                 iterationTracePaths = absoluteTracePaths
276             )
277         assertEquals(
278             """
279                 |warning
280                 |string
281                 |foo
282                 |  Metric   [min 0.0](file://iter0.trace),   [median 1.0](file://iter1.trace),   [max 2.0](file://iter2.trace)
283                 |    Traces: Iteration [0](file://iter0.trace) [1](file://iter1.trace) [2](file://iter2.trace)
284                 |
285             """
286                 .trimMargin(),
287             summary.summaryV2
288         )
289         // v1 is deprecated and should be the same as v2
290         assertEquals(summary.summaryV1, summary.summaryV2)
291     }
292 
293     @Test
ideSummary_requireMeasurementsNotEmptynull294     fun ideSummary_requireMeasurementsNotEmpty() {
295         assertFailsWith<IllegalArgumentException> {
296             InstrumentationResults.ideSummary(
297                 measurements =
298                     Measurements(singleMetrics = emptyList(), sampledMetrics = emptyList()),
299             )
300         }
301     }
302 }
303 
assertEqualsnull304 private fun <T> assertEquals(expected: T, actual: T) = assertThat(actual).isEqualTo(expected)
305