Skip to content

Commit 6897b9e

Browse files
alexmarkovCommit Queue
authored and
Commit Queue
committed
[benchmarks] Micro-benchmark for multiple returns
The new micro-benchmark measures performance of returning 2 values via list, dedicated class, record and a record with named fields. Requires '--enable-experiment=records' flag to run. Issue: #49719 Change-Id: I895d955efb2fc4f1c04b31b113cd8e01db47132a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/265121 Reviewed-by: Slava Egorov <[email protected]> Commit-Queue: Alexander Markov <[email protected]>
1 parent 5caa8da commit 6897b9e

File tree

1 file changed

+287
-0
lines changed

1 file changed

+287
-0
lines changed
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:benchmark_harness/benchmark_harness.dart';
6+
7+
// Micro-benchmark for multiple returns.
8+
//
9+
// The goal of this benchmark is to compare and track performance of
10+
// various ways to return multiple values from a method.
11+
12+
int input1 = int.parse('42');
13+
String input2 = input1.toString();
14+
15+
const int N = 1000000;
16+
final int expectedSum = (input1 + input2.length) * N;
17+
18+
class ResultClass {
19+
final int result0;
20+
final String result1;
21+
const ResultClass(this.result0, this.result1);
22+
}
23+
24+
@pragma('vm:prefer-inline')
25+
@pragma('dart2js:prefer-inline')
26+
List<Object> inlinedList() => [input1, input2];
27+
28+
@pragma('vm:never-inline')
29+
@pragma('dart2js:never-inline')
30+
List<Object> notInlinedList() => [input1, input2];
31+
32+
@pragma('vm:never-inline')
33+
@pragma('dart2js:never-inline')
34+
List<Object> forwardedList() => notInlinedList();
35+
36+
@pragma('vm:prefer-inline')
37+
@pragma('dart2js:prefer-inline')
38+
ResultClass inlinedClass() => ResultClass(input1, input2);
39+
40+
@pragma('vm:never-inline')
41+
@pragma('dart2js:never-inline')
42+
ResultClass notInlinedClass() => ResultClass(input1, input2);
43+
44+
@pragma('vm:never-inline')
45+
@pragma('dart2js:never-inline')
46+
ResultClass forwardedClass() => notInlinedClass();
47+
48+
@pragma('vm:prefer-inline')
49+
@pragma('dart2js:prefer-inline')
50+
(int, String) inlinedRecord() => (input1, input2);
51+
52+
@pragma('vm:never-inline')
53+
@pragma('dart2js:never-inline')
54+
(int, String) notInlinedRecord() => (input1, input2);
55+
56+
@pragma('vm:never-inline')
57+
@pragma('dart2js:never-inline')
58+
(int, String) forwardedRecord() => notInlinedRecord();
59+
60+
@pragma('vm:prefer-inline')
61+
@pragma('dart2js:prefer-inline')
62+
({int result0, String result1}) inlinedRecordNamed() => (result0: input1, result1: input2);
63+
64+
@pragma('vm:never-inline')
65+
@pragma('dart2js:never-inline')
66+
({int result0, String result1}) notInlinedRecordNamed() => (result0: input1, result1: input2);
67+
68+
@pragma('vm:never-inline')
69+
@pragma('dart2js:never-inline')
70+
({int result0, String result1}) forwardedRecordNamed() => notInlinedRecordNamed();
71+
72+
class BenchInlinedList extends BenchmarkBase {
73+
BenchInlinedList() : super('MultipleReturns.Inlined.List');
74+
75+
@override
76+
void run() {
77+
int sum = 0;
78+
for (int i = 0; i < N; ++i) {
79+
final result = inlinedList();
80+
final int r0 = result[0] as int;
81+
final String r1 = result[1] as String;
82+
sum += r0 + r1.length;
83+
}
84+
if (sum != expectedSum) throw 'Bad result: $sum';
85+
}
86+
}
87+
88+
class BenchNotInlinedList extends BenchmarkBase {
89+
BenchNotInlinedList() : super('MultipleReturns.NotInlined.List');
90+
91+
@override
92+
void run() {
93+
int sum = 0;
94+
for (int i = 0; i < N; ++i) {
95+
final result = notInlinedList();
96+
final int r0 = result[0] as int;
97+
final String r1 = result[1] as String;
98+
sum += r0 + r1.length;
99+
}
100+
if (sum != expectedSum) throw 'Bad result: $sum';
101+
}
102+
}
103+
104+
class BenchForwardedList extends BenchmarkBase {
105+
BenchForwardedList() : super('MultipleReturns.Forwarded.List');
106+
107+
@override
108+
void run() {
109+
int sum = 0;
110+
for (int i = 0; i < N; ++i) {
111+
final result = forwardedList();
112+
final int r0 = result[0] as int;
113+
final String r1 = result[1] as String;
114+
sum += r0 + r1.length;
115+
}
116+
if (sum != expectedSum) throw 'Bad result: $sum';
117+
}
118+
}
119+
120+
class BenchInlinedClass extends BenchmarkBase {
121+
BenchInlinedClass() : super('MultipleReturns.Inlined.Class');
122+
123+
@override
124+
void run() {
125+
int sum = 0;
126+
for (int i = 0; i < N; ++i) {
127+
final result = inlinedClass();
128+
final int r0 = result.result0;
129+
final String r1 = result.result1;
130+
sum += r0 + r1.length;
131+
}
132+
if (sum != expectedSum) throw 'Bad result: $sum';
133+
}
134+
}
135+
136+
class BenchNotInlinedClass extends BenchmarkBase {
137+
BenchNotInlinedClass() : super('MultipleReturns.NotInlined.Class');
138+
139+
@override
140+
void run() {
141+
int sum = 0;
142+
for (int i = 0; i < N; ++i) {
143+
final result = notInlinedClass();
144+
final int r0 = result.result0;
145+
final String r1 = result.result1;
146+
sum += r0 + r1.length;
147+
}
148+
if (sum != expectedSum) throw 'Bad result: $sum';
149+
}
150+
}
151+
152+
class BenchForwardedClass extends BenchmarkBase {
153+
BenchForwardedClass() : super('MultipleReturns.Forwarded.Class');
154+
155+
@override
156+
void run() {
157+
int sum = 0;
158+
for (int i = 0; i < N; ++i) {
159+
final result = forwardedClass();
160+
final int r0 = result.result0;
161+
final String r1 = result.result1;
162+
sum += r0 + r1.length;
163+
}
164+
if (sum != expectedSum) throw 'Bad result: $sum';
165+
}
166+
}
167+
168+
169+
class BenchInlinedRecord extends BenchmarkBase {
170+
BenchInlinedRecord() : super('MultipleReturns.Inlined.Record');
171+
172+
@override
173+
void run() {
174+
int sum = 0;
175+
for (int i = 0; i < N; ++i) {
176+
final result = inlinedRecord();
177+
final int r0 = result.$0;
178+
final String r1 = result.$1;
179+
sum += r0 + r1.length;
180+
}
181+
if (sum != expectedSum) throw 'Bad result: $sum';
182+
}
183+
}
184+
185+
class BenchNotInlinedRecord extends BenchmarkBase {
186+
BenchNotInlinedRecord() : super('MultipleReturns.NotInlined.Record');
187+
188+
@override
189+
void run() {
190+
int sum = 0;
191+
for (int i = 0; i < N; ++i) {
192+
final result = notInlinedRecord();
193+
final int r0 = result.$0;
194+
final String r1 = result.$1;
195+
sum += r0 + r1.length;
196+
}
197+
if (sum != expectedSum) throw 'Bad result: $sum';
198+
}
199+
}
200+
201+
class BenchForwardedRecord extends BenchmarkBase {
202+
BenchForwardedRecord() : super('MultipleReturns.Forwarded.Record');
203+
204+
@override
205+
void run() {
206+
int sum = 0;
207+
for (int i = 0; i < N; ++i) {
208+
final result = forwardedRecord();
209+
final int r0 = result.$0;
210+
final String r1 = result.$1;
211+
sum += r0 + r1.length;
212+
}
213+
if (sum != expectedSum) throw 'Bad result: $sum';
214+
}
215+
}
216+
217+
class BenchInlinedRecordNamed extends BenchmarkBase {
218+
BenchInlinedRecordNamed() : super('MultipleReturns.Inlined.RecordNamed');
219+
220+
@override
221+
void run() {
222+
int sum = 0;
223+
for (int i = 0; i < N; ++i) {
224+
final result = inlinedRecordNamed();
225+
final int r0 = result.result0;
226+
final String r1 = result.result1;
227+
sum += r0 + r1.length;
228+
}
229+
if (sum != expectedSum) throw 'Bad result: $sum';
230+
}
231+
}
232+
233+
class BenchNotInlinedRecordNamed extends BenchmarkBase {
234+
BenchNotInlinedRecordNamed() : super('MultipleReturns.NotInlined.RecordNamed');
235+
236+
@override
237+
void run() {
238+
int sum = 0;
239+
for (int i = 0; i < N; ++i) {
240+
final result = notInlinedRecordNamed();
241+
final int r0 = result.result0;
242+
final String r1 = result.result1;
243+
sum += r0 + r1.length;
244+
}
245+
if (sum != expectedSum) throw 'Bad result: $sum';
246+
}
247+
}
248+
249+
class BenchForwardedRecordNamed extends BenchmarkBase {
250+
BenchForwardedRecordNamed() : super('MultipleReturns.Forwarded.RecordNamed');
251+
252+
@override
253+
void run() {
254+
int sum = 0;
255+
for (int i = 0; i < N; ++i) {
256+
final result = forwardedRecordNamed();
257+
final int r0 = result.result0;
258+
final String r1 = result.result1;
259+
sum += r0 + r1.length;
260+
}
261+
if (sum != expectedSum) throw 'Bad result: $sum';
262+
}
263+
}
264+
265+
void main() {
266+
final benchmarks = [
267+
BenchInlinedList(),
268+
BenchInlinedClass(),
269+
BenchInlinedRecord(),
270+
BenchInlinedRecordNamed(),
271+
BenchNotInlinedList(),
272+
BenchNotInlinedClass(),
273+
BenchNotInlinedRecord(),
274+
BenchNotInlinedRecordNamed(),
275+
BenchForwardedList(),
276+
BenchForwardedClass(),
277+
BenchForwardedRecord(),
278+
BenchForwardedRecordNamed(),
279+
];
280+
281+
for (final benchmark in benchmarks) {
282+
benchmark.warmup();
283+
}
284+
for (final benchmark in benchmarks) {
285+
benchmark.report();
286+
}
287+
}

0 commit comments

Comments
 (0)