Skip to content

Commit d3bbacf

Browse files
jensjohaCommit Queue
authored andcommitted
[analyzer] Faster export scope calculation in bad cases
With the `big_chain_benchmark` for ImportExportCycle and ImportCycleExportChain it scales a lot better. The other ones (ImportCycle, ImportChain, ImportExportChain) doesn't change. For ImportExportCycle, in AOT mode, before we got: ``` +------+-----------+------------+------------+ | Size | Initial | Completion | Fully done | +------+-----------+------------+------------+ | 16 | 0.46673 | 0.169486 | 0.406448 | | 32 | 0.875871 | 0.242876 | 0.85543 | | 64 | 1.583077 | 0.465915 | 1.506953 | | 128 | 3.198071 | 0.903894 | 3.09165 | | 256 | 6.786677 | 2.149489 | 6.779569 | | 512 | 17.346131 | 8.92149 | 17.971033 | | 1024 | 63.358453 | 46.152089 | 65.401559 | +------+-----------+------------+------------+ ``` now instead we get: ``` +------+-----------+------------+------------+ | Size | Initial | Completion | Fully done | +------+-----------+------------+------------+ | 16 | 0.474942 | 0.166857 | 0.411457 | | 32 | 0.834925 | 0.243397 | 0.76843 | | 64 | 1.608813 | 0.439885 | 1.53438 | | 128 | 3.198453 | 0.805756 | 3.302559 | | 256 | 6.347211 | 1.712426 | 6.165624 | | 512 | 12.874747 | 3.551489 | 13.1461 | | 1024 | 27.14403 | 7.844261 | 27.32785 | +------+-----------+------------+------------+ ``` An almost 6x improvement for completion and 2x+ improvement for both initial analysis and analysing after the change. For ImportCycleExportChain, in AOT mode, before we got: ``` +------+-----------+------------+------------+ | Size | Initial | Completion | Fully done | +------+-----------+------------+------------+ | 16 | 0.454349 | 0.152505 | 0.400889 | | 32 | 0.892146 | 0.302407 | 0.81263 | | 64 | 1.67604 | 0.439954 | 1.517379 | | 128 | 3.335087 | 0.907002 | 3.262481 | | 256 | 6.378526 | 1.943725 | 6.292922 | | 512 | 15.477861 | 6.461358 | 15.560008 | | 1024 | 50.671197 | 33.14349 | 51.689455 | +------+-----------+------------+------------+ ``` now instead we get: ``` +------+-----------+------------+------------+ | Size | Initial | Completion | Fully done | +------+-----------+------------+------------+ | 16 | 0.548357 | 0.166257 | 0.415632 | | 32 | 0.906483 | 0.296618 | 0.910544 | | 64 | 1.623723 | 0.464061 | 1.527888 | | 128 | 3.067769 | 0.801507 | 2.927981 | | 256 | 6.224551 | 1.596711 | 6.098531 | | 512 | 12.941757 | 3.277487 | 12.345753 | | 1024 | 25.870713 | 7.020787 | 25.760605 | +------+-----------+------------+------------+ ``` A ~4.7x improvement on completion and ~2x improvement for both initial analysis and analysing after the change. Change-Id: I052879c1695ad5f0aa63c2d96013a1e3eae96428 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/413421 Reviewed-by: Lasse Nielsen <[email protected]> Commit-Queue: Jens Johansen <[email protected]>
1 parent 06d9380 commit d3bbacf

File tree

8 files changed

+155
-5
lines changed

8 files changed

+155
-5
lines changed

pkg/analyzer/lib/src/summary2/export.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class ExportedReferenceExported extends ExportedReference {
6161
});
6262

6363
void addLocation(ExportLocation location) {
64+
// This list is very small, contains on it is probably ok.
6465
if (!locations.contains(location)) {
6566
locations.add(location);
6667
}

pkg/analyzer/lib/src/summary2/link.dart

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'package:analyzer/src/dart/element/name_union.dart';
1515
import 'package:analyzer/src/fine/library_manifest.dart';
1616
import 'package:analyzer/src/summary2/bundle_writer.dart';
1717
import 'package:analyzer/src/summary2/detach_nodes.dart';
18+
import 'package:analyzer/src/summary2/export.dart';
1819
import 'package:analyzer/src/summary2/library_builder.dart';
1920
import 'package:analyzer/src/summary2/linked_element_factory.dart';
2021
import 'package:analyzer/src/summary2/reference.dart';
@@ -179,19 +180,47 @@ class Linker {
179180
}
180181
}
181182

182-
while (true) {
183-
var hasChanges = false;
183+
// We keep a queue of exports to propagate.
184+
// First we loop over every reference that both exports and is exported,
185+
// but then we only process the exports that should be propagated.
186+
var additionalExportData = <_AdditionalExport>[];
187+
188+
void addExport(Export export, String name, ExportedReference reference) {
189+
if (export.addToExportScope(name, reference)) {
190+
// We've added [name] to [export.exporter]s export scope.
191+
// We need to propagate that to anyone that exports that library.
192+
additionalExportData
193+
.add(_AdditionalExport(export.exporter, name, reference));
194+
}
195+
}
196+
197+
for (var exported in both) {
198+
for (var export in exported.exports) {
199+
exported.exportScope.forEach((name, reference) {
200+
addExport(export, name, reference);
201+
});
202+
}
203+
}
204+
205+
while (additionalExportData.isNotEmpty) {
206+
var data = additionalExportData.removeLast();
207+
for (var export in data.exported.exports) {
208+
addExport(export, data.name, data.reference);
209+
}
210+
}
211+
212+
assert(() {
184213
for (var exported in both) {
185214
for (var export in exported.exports) {
186215
exported.exportScope.forEach((name, reference) {
187216
if (export.addToExportScope(name, reference)) {
188-
hasChanges = true;
217+
throw "Error in export calculation: Assert failed.";
189218
}
190219
});
191220
}
192221
}
193-
if (!hasChanges) break;
194-
}
222+
return true;
223+
}(), true);
195224

196225
for (var library in builders.values) {
197226
library.storeExportScope();
@@ -362,3 +391,11 @@ class LinkResult {
362391
required this.resolutionBytes,
363392
});
364393
}
394+
395+
class _AdditionalExport {
396+
final LibraryBuilder exported;
397+
final String name;
398+
final ExportedReference reference;
399+
400+
_AdditionalExport(this.exported, this.name, this.reference);
401+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) 2025, 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 "bigger_cyclic_helper_2.dart";
6+
export "bigger_cyclic_helper_2.dart";
7+
8+
void get2(int i) {
9+
print("2: $i");
10+
if (i > 0) {
11+
get1(i - 1);
12+
get2(i - 1);
13+
get3(i - 1);
14+
get4(i - 1);
15+
get5(i - 1);
16+
get6(i - 1);
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) 2025, 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 "bigger_cyclic_helper_3.dart";
6+
export "bigger_cyclic_helper_3.dart";
7+
8+
void get3(int i) {
9+
print("3: $i");
10+
if (i > 0) {
11+
get1(i - 1);
12+
get2(i - 1);
13+
get3(i - 1);
14+
get4(i - 1);
15+
get5(i - 1);
16+
get6(i - 1);
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) 2025, 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 "bigger_cyclic_helper_4.dart";
6+
export "bigger_cyclic_helper_4.dart";
7+
8+
void get4(int i) {
9+
print("4: $i");
10+
if (i > 0) {
11+
get1(i - 1);
12+
get2(i - 1);
13+
get3(i - 1);
14+
get4(i - 1);
15+
get5(i - 1);
16+
get6(i - 1);
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) 2025, 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 "bigger_cyclic_helper_5.dart";
6+
export "bigger_cyclic_helper_5.dart";
7+
8+
void get5(int i) {
9+
print("5: $i");
10+
if (i > 0) {
11+
get1(i - 1);
12+
get2(i - 1);
13+
get3(i - 1);
14+
get4(i - 1);
15+
get5(i - 1);
16+
get6(i - 1);
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) 2025, 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 "bigger_cyclic_test.dart";
6+
export "bigger_cyclic_test.dart";
7+
8+
void get6(int i) {
9+
print("6: $i");
10+
if (i > 0) {
11+
get1(i - 1);
12+
get2(i - 1);
13+
get3(i - 1);
14+
get4(i - 1);
15+
get5(i - 1);
16+
get6(i - 1);
17+
}
18+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) 2025, 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 "bigger_cyclic_helper_1.dart";
6+
export "bigger_cyclic_helper_1.dart";
7+
8+
void main() {
9+
get1(1);
10+
}
11+
12+
void get1(int i) {
13+
print("1: $i");
14+
if (i > 0) {
15+
get1(i - 1);
16+
get2(i - 1);
17+
get3(i - 1);
18+
get4(i - 1);
19+
get5(i - 1);
20+
get6(i - 1);
21+
}
22+
}

0 commit comments

Comments
 (0)