Skip to content

Commit 218da8a

Browse files
authored
[macros] Add JSON macro benchmark. (#3892)
1 parent ad36fde commit 218da8a

File tree

5 files changed

+1012
-0
lines changed

5 files changed

+1012
-0
lines changed

working/macros/dart_model/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ of the specified size and codegen strategy.
3232
`HashCode()` and `ToString()`. These inspect the fields of a class and generate
3333
corresponding (shallow) `operator==`, `hashCode` and `toString()`.
3434

35+
`json_macro` is the `package:json` macro. There is no `dartModel` version yet.
36+
Generate it using `bin/main_json.dart` instead of `bin/main.dart`.
37+
3538
### Strategies
3639

3740
Four strategies are supported:
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (c) 2024, 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 'dart:io';
6+
7+
import 'package:benchmark/json_macro/input_generator.dart';
8+
import 'package:benchmark/workspace.dart';
9+
10+
Future<void> main(List<String> arguments) async {
11+
if (arguments.length != 3) {
12+
print('''
13+
Creates packages to benchmark macro performance. Usage:
14+
15+
dart bin/main_json.dart <workspace name> <macro|manual|none> <# libraries>
16+
''');
17+
exit(1);
18+
}
19+
20+
final workspaceName = arguments[0];
21+
final strategy = Strategy.values.where((e) => e.name == arguments[1]).single;
22+
final libraryCount = int.parse(arguments[2]);
23+
24+
print('Creating under: /tmp/dart_model_benchmark/$workspaceName');
25+
final workspace = Workspace(workspaceName);
26+
final inputGenerator = JsonMacroInputGenerator(
27+
fieldsPerClass: 100,
28+
classesPerLibrary: 10,
29+
librariesPerCycle: libraryCount,
30+
strategy: strategy);
31+
inputGenerator.generate(workspace);
32+
await workspace.pubGet();
33+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// Copyright (c) 2024, 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 'dart:io';
6+
7+
import 'package:benchmark/random.dart';
8+
import 'package:benchmark/workspace.dart';
9+
10+
enum Strategy {
11+
manual,
12+
macro,
13+
none;
14+
15+
String annotation(String name) {
16+
switch (this) {
17+
case Strategy.manual:
18+
case Strategy.none:
19+
return '';
20+
case Strategy.macro:
21+
return '@m.$name()';
22+
}
23+
}
24+
}
25+
26+
class JsonMacroInputGenerator {
27+
final int fieldsPerClass;
28+
final int classesPerLibrary;
29+
final int librariesPerCycle;
30+
final Strategy strategy;
31+
32+
JsonMacroInputGenerator(
33+
{required this.fieldsPerClass,
34+
required this.classesPerLibrary,
35+
required this.librariesPerCycle,
36+
required this.strategy});
37+
38+
void generate(Workspace workspace) {
39+
// All strategies except "manual" need augmentations, which is the "macros"
40+
// experiment.
41+
if (strategy == Strategy.macro) {
42+
workspace.write('analysis_options.yaml', source: '''
43+
analyzer:
44+
enable-experiment:
45+
- macros
46+
''');
47+
}
48+
49+
if (strategy == Strategy.macro) {
50+
workspace.write('lib/macros.dart',
51+
source: File('lib/json_macro/macros.dart').readAsStringSync());
52+
}
53+
54+
for (var i = 0; i != librariesPerCycle; ++i) {
55+
workspace.write('lib/a$i.dart', source: _generateLibrary(i));
56+
}
57+
}
58+
59+
String _generateLibrary(int index,
60+
{bool topLevelCacheBuster = false, bool fieldCacheBuster = false}) {
61+
final buffer = StringBuffer();
62+
63+
if (strategy == Strategy.macro) {
64+
buffer.writeln("import 'macros.dart';");
65+
}
66+
67+
if (librariesPerCycle != 1) {
68+
final nextLibrary = (index + 1) % librariesPerCycle;
69+
buffer.writeln('import "a$nextLibrary.dart" as next_in_cycle;');
70+
buffer.writeln('next_in_cycle.A0? referenceOther;');
71+
}
72+
73+
if (topLevelCacheBuster) {
74+
buffer.writeln('int? cacheBuster$largeRandom;');
75+
}
76+
77+
for (var j = 0; j != classesPerLibrary; ++j) {
78+
buffer.write(_generateClass(j, fieldCacheBuster: fieldCacheBuster));
79+
}
80+
81+
return buffer.toString();
82+
}
83+
84+
String _generateClass(int index, {required bool fieldCacheBuster}) {
85+
final className = 'A$index';
86+
String fieldName(int index) => 'a$index';
87+
88+
final result =
89+
StringBuffer(strategy == Strategy.macro ? '@JsonCodable()' : '');
90+
91+
result.writeln('class $className {');
92+
if (fieldCacheBuster) {
93+
result.writeln('int? b$largeRandom;');
94+
}
95+
for (var i = 0; i != fieldsPerClass; ++i) {
96+
result.writeln('int? ${fieldName(i)};');
97+
}
98+
99+
if (strategy == Strategy.manual) {
100+
result.writeln('$className._({');
101+
for (var i = 0; i != fieldsPerClass; ++i) {
102+
result.writeln('required this.${fieldName(i)},');
103+
}
104+
result.writeln('});');
105+
106+
result.writeln('Map<String, Object?> toJson() {');
107+
result.writeln(' final result = <String, Object?>{};');
108+
for (var i = 0; i != fieldsPerClass; ++i) {
109+
result.writeln(
110+
"if (${fieldName(i)} != null) result['${fieldName(i)}'] = ${fieldName(i)};");
111+
}
112+
result.writeln('return result;');
113+
result.writeln('}');
114+
result
115+
.writeln('factory $className.fromJson(Map<String, Object?> json) {');
116+
result.writeln('return $className._(');
117+
for (var i = 0; i != fieldsPerClass; ++i) {
118+
result.writeln("${fieldName(i)}: json['${fieldName(i)}'] as int,");
119+
}
120+
result.writeln(');');
121+
result.writeln('}');
122+
}
123+
124+
result.writeln('}');
125+
return result.toString();
126+
}
127+
128+
void changeIrrelevantInput(Workspace workspace) {
129+
workspace.write('lib/a0.dart',
130+
source: _generateLibrary(0, topLevelCacheBuster: true));
131+
}
132+
133+
void changeRevelantInput(Workspace workspace) {
134+
workspace.write('lib/a0.dart',
135+
source: _generateLibrary(0, fieldCacheBuster: true));
136+
}
137+
}

0 commit comments

Comments
 (0)