ae593598f8
This CL does two things: * "Reenable" the skipping of the dart:ffi transformation entirely when the application does not use dart:ffi. This was originally added inad596359a6but was logically disabled in4558112105when dart:core started depending on it. Here we now ignore (real) dart:* libraries when looking for dependencies of dart:ffi. * Find the subset of the just compiled libraries that transitively depend on dart:ffi and just run the dart:ffi transformation on those libraries. For dart2js that doesn't use dart:ffi at all we go from: ``` $ out/ReleaseX64/dart pkg/front_end/tool/_fasta/compile.dart -v pkg/compiler/bin/dart2js.dart | grep -i "ffi" 0:00:09.003428: Transformed ffi natives in 51ms. 0:00:09.203442: Transformed ffi annotations in 199ms. $ out/ReleaseX64/dart pkg/front_end/tool/_fasta/compile.dart -v pkg/compiler/bin/dart2js.dart | grep -i "ffi" 0:00:09.098175: Transformed ffi natives in 52ms. 0:00:09.296847: Transformed ffi annotations in 198ms. $ out/ReleaseX64/dart pkg/front_end/tool/_fasta/compile.dart -v pkg/compiler/bin/dart2js.dart | grep -i "ffi" 0:00:08.854341: Transformed ffi natives in 57ms. 0:00:09.061804: Transformed ffi annotations in 207ms. ``` to ``` $ out/ReleaseX64/dart pkg/front_end/tool/_fasta/compile.dart -v pkg/compiler/bin/dart2js.dart | grep -i "ffi" 0:00:09.138651: Skipped ffi transformation in 1ms. $ out/ReleaseX64/dart pkg/front_end/tool/_fasta/compile.dart -v pkg/compiler/bin/dart2js.dart | grep -i "ffi" 0:00:09.242590: Skipped ffi transformation in 1ms. $ out/ReleaseX64/dart pkg/front_end/tool/_fasta/compile.dart -v pkg/compiler/bin/dart2js.dart | grep -i "ffi" 0:00:09.163885: Skipped ffi transformation in 1ms. ``` When compiling the flutter gallery app that does depend on dart:ffi we go from: ``` $ out/ReleaseX64/dart pkg/front_end/tool/_fasta/compile.dart -v --target=flutter --platform=/tmp/tmp.6KV5psVGIG/flutter_patched_sdk/platform_strong.dill /tmp/tmp.6KV5psVGIG/gallery/lib/main.dart | grep -i "ffi" 0:00:16.344955: Transformed ffi natives in 78ms. 0:00:16.777218: Transformed ffi annotations in 432ms. $ out/ReleaseX64/dart pkg/front_end/tool/_fasta/compile.dart -v --target=flutter --platform=/tmp/tmp.6KV5psVGIG/flutter_patched_sdk/platform_strong.dill /tmp/tmp.6KV5psVGIG/gallery/lib/main.dart | grep -i "ffi" 0:00:15.994674: Transformed ffi natives in 80ms. 0:00:16.472779: Transformed ffi annotations in 478ms. $ out/ReleaseX64/dart pkg/front_end/tool/_fasta/compile.dart -v --target=flutter --platform=/tmp/tmp.6KV5psVGIG/flutter_patched_sdk/platform_strong.dill /tmp/tmp.6KV5psVGIG/gallery/lib/main.dart | grep -i "ffi" 0:00:16.027488: Transformed ffi natives in 81ms. 0:00:16.491362: Transformed ffi annotations in 463ms. ``` to ``` $ out/ReleaseX64/dart pkg/front_end/tool/_fasta/compile.dart -v --target=flutter --platform=/tmp/tmp.6KV5psVGIG/flutter_patched_sdk/platform_strong.dill /tmp/tmp.6KV5psVGIG/gallery/lib/main.dart | grep -i "ffi" 0:00:15.991628: Transformed ffi natives in 30ms. 0:00:16.226564: Transformed ffi annotations in 234ms. $ out/ReleaseX64/dart pkg/front_end/tool/_fasta/compile.dart -v --target=flutter --platform=/tmp/tmp.6KV5psVGIG/flutter_patched_sdk/platform_strong.dill /tmp/tmp.6KV5psVGIG/gallery/lib/main.dart | grep -i "ffi" 0:00:16.184984: Transformed ffi natives in 29ms. 0:00:16.404439: Transformed ffi annotations in 219ms. $ out/ReleaseX64/dart pkg/front_end/tool/_fasta/compile.dart -v --target=flutter --platform=/tmp/tmp.6KV5psVGIG/flutter_patched_sdk/platform_strong.dill /tmp/tmp.6KV5psVGIG/gallery/lib/main.dart | grep -i "ffi" 0:00:15.933513: Transformed ffi natives in 27ms. 0:00:16.145640: Transformed ffi annotations in 212ms. ``` TEST=Assuming tests already exists. Change-Id: Ie13be1924d3439cb710c782af81e1e42cda2a838 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/228001 Reviewed-by: Johnni Winther <johnniwinther@google.com> Reviewed-by: Daco Harkes <dacoharkes@google.com> Commit-Queue: Jens Johansen <jensj@google.com>
659 lines
12 KiB
Dart
659 lines
12 KiB
Dart
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE.md file.
|
|
|
|
library kernel.test.graph_test;
|
|
|
|
import 'package:expect/expect.dart' show Expect;
|
|
|
|
import 'package:kernel/util/graph.dart';
|
|
|
|
const String A = 'A';
|
|
const String B = 'B';
|
|
const String C = 'C';
|
|
const String D = 'D';
|
|
const String E = 'E';
|
|
const String F = 'F';
|
|
|
|
class TestGraph implements Graph<String> {
|
|
final Map<String, List<String>> graph;
|
|
|
|
TestGraph(this.graph);
|
|
|
|
@override
|
|
Iterable<String> get vertices => graph.keys;
|
|
|
|
@override
|
|
Iterable<String> neighborsOf(String vertex) => graph[vertex]!;
|
|
}
|
|
|
|
void test(
|
|
{required List<List<String>> expectedStrongComponents,
|
|
List<String> expectedSortedVertices = const [],
|
|
List<String> expectedCyclicVertices = const [],
|
|
List<List<String>> expectedLayers = const [],
|
|
List<List<List<String>>> expectedStrongLayers = const [],
|
|
required Map<String, List<String>> graphData}) {
|
|
Graph<String> graph = new TestGraph(graphData);
|
|
|
|
List<List<String>> strongComponentResult = computeStrongComponents(graph);
|
|
Expect.equals(
|
|
expectedStrongComponents.length,
|
|
strongComponentResult.length,
|
|
"Unexpected strongly connected components count. "
|
|
"Expected ${expectedStrongComponents}, "
|
|
"actual ${strongComponentResult}");
|
|
for (int index = 0; index < expectedStrongComponents.length; index++) {
|
|
Expect.listEquals(
|
|
expectedStrongComponents[index],
|
|
strongComponentResult[index],
|
|
"Unexpected strongly connected components. "
|
|
"Expected $expectedStrongComponents, actual $strongComponentResult.");
|
|
}
|
|
|
|
TopologicalSortResult<String> topologicalResult = topologicalSort(graph);
|
|
Set<String> sortedAndCyclicVertices = topologicalResult.sortedVertices
|
|
.toSet()
|
|
.intersection(topologicalResult.cyclicVertices.toSet());
|
|
Expect.isTrue(sortedAndCyclicVertices.isEmpty,
|
|
"Found vertices both sorted and cyclic: $sortedAndCyclicVertices");
|
|
List<String> sortedOrCyclicVertices = [
|
|
...topologicalResult.sortedVertices,
|
|
...topologicalResult.cyclicVertices
|
|
];
|
|
Expect.equals(
|
|
graphData.length,
|
|
sortedOrCyclicVertices.length,
|
|
"Unexpected vertex count. Expected ${graphData.length}, "
|
|
"found ${sortedOrCyclicVertices.length}.");
|
|
Expect.listEquals(
|
|
expectedSortedVertices,
|
|
topologicalResult.sortedVertices,
|
|
"Unexpected sorted vertices. "
|
|
"Expected $expectedSortedVertices, "
|
|
"actual ${topologicalResult.sortedVertices}.");
|
|
Expect.listEquals(
|
|
expectedCyclicVertices,
|
|
topologicalResult.cyclicVertices,
|
|
"Unexpected cyclic vertices. "
|
|
"Expected $expectedCyclicVertices, "
|
|
"actual ${topologicalResult.cyclicVertices}.");
|
|
Expect.equals(
|
|
expectedLayers.length,
|
|
topologicalResult.layers.length,
|
|
"Unexpected topological layer count. "
|
|
"Expected ${expectedLayers}, "
|
|
"actual ${topologicalResult.layers}");
|
|
for (int index = 0; index < expectedLayers.length; index++) {
|
|
Expect.listEquals(
|
|
expectedLayers[index],
|
|
topologicalResult.layers[index],
|
|
"Unexpected topological layers. "
|
|
"Expected $expectedLayers, "
|
|
"actual ${topologicalResult.layers}.");
|
|
for (String vertex in topologicalResult.layers[index]) {
|
|
int actualIndex = topologicalResult.indexMap[vertex]!;
|
|
Expect.equals(
|
|
index,
|
|
actualIndex,
|
|
"Unexpected topological index for $vertex. "
|
|
"Expected $index, found $actualIndex.");
|
|
}
|
|
}
|
|
|
|
StrongComponentGraph<String> strongComponentGraph =
|
|
new StrongComponentGraph(graph, strongComponentResult);
|
|
TopologicalSortResult<List<String>> strongTopologicalResult =
|
|
topologicalSort(strongComponentGraph);
|
|
Expect.equals(
|
|
expectedStrongLayers.length,
|
|
strongTopologicalResult.layers.length,
|
|
"Unexpected strong topological layer count. "
|
|
"Expected ${expectedStrongLayers}, "
|
|
"actual ${strongTopologicalResult.layers}");
|
|
for (int index = 0; index < expectedStrongLayers.length; index++) {
|
|
List<List<String>> expectedStrongLayer = expectedStrongLayers[index];
|
|
List<List<String>> strongLayer = strongTopologicalResult.layers[index];
|
|
Expect.equals(
|
|
expectedStrongLayer.length,
|
|
strongLayer.length,
|
|
"Unexpected strong topological layer $index count. "
|
|
"Expected ${expectedStrongLayers}, "
|
|
"actual ${strongTopologicalResult.layers}");
|
|
|
|
for (int subIndex = 0; subIndex < expectedStrongLayer.length; subIndex++) {
|
|
Expect.listEquals(
|
|
expectedStrongLayer[subIndex],
|
|
strongLayer[subIndex],
|
|
"Unexpected strong topological layer $index. "
|
|
"Expected $expectedStrongLayer, "
|
|
"actual $strongLayer.");
|
|
}
|
|
for (List<String> vertex in strongTopologicalResult.layers[index]) {
|
|
int actualIndex = strongTopologicalResult.indexMap[vertex]!;
|
|
Expect.equals(
|
|
index,
|
|
actualIndex,
|
|
"Unexpected strong topological index for $vertex. "
|
|
"Expected $index, found $actualIndex.");
|
|
}
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
test(graphData: {
|
|
A: [B],
|
|
B: [A],
|
|
C: [A],
|
|
D: [C],
|
|
}, expectedStrongComponents: [
|
|
[B, A],
|
|
[C],
|
|
[D]
|
|
], expectedCyclicVertices: [
|
|
B,
|
|
A,
|
|
C,
|
|
D
|
|
], expectedStrongLayers: [
|
|
[
|
|
[B, A]
|
|
],
|
|
[
|
|
[C]
|
|
],
|
|
[
|
|
[D]
|
|
]
|
|
]);
|
|
|
|
test(graphData: {}, expectedStrongComponents: []);
|
|
|
|
test(graphData: {
|
|
A: [],
|
|
B: [],
|
|
C: [],
|
|
D: [],
|
|
}, expectedStrongComponents: [
|
|
[A],
|
|
[B],
|
|
[C],
|
|
[D]
|
|
], expectedSortedVertices: [
|
|
A,
|
|
B,
|
|
C,
|
|
D
|
|
], expectedLayers: [
|
|
[A, B, C, D]
|
|
], expectedStrongLayers: [
|
|
[
|
|
[A],
|
|
[B],
|
|
[C],
|
|
[D]
|
|
]
|
|
]);
|
|
|
|
test(graphData: {
|
|
D: [C],
|
|
C: [A],
|
|
B: [A],
|
|
A: [B],
|
|
}, expectedStrongComponents: [
|
|
[B, A],
|
|
[C],
|
|
[D]
|
|
], expectedCyclicVertices: [
|
|
B,
|
|
A,
|
|
C,
|
|
D
|
|
], expectedStrongLayers: [
|
|
[
|
|
[B, A]
|
|
],
|
|
[
|
|
[C]
|
|
],
|
|
[
|
|
[D]
|
|
]
|
|
]);
|
|
|
|
test(graphData: {
|
|
A: [B],
|
|
B: [C],
|
|
C: [D],
|
|
D: [],
|
|
}, expectedStrongComponents: [
|
|
[D],
|
|
[C],
|
|
[B],
|
|
[A]
|
|
], expectedSortedVertices: [
|
|
D,
|
|
C,
|
|
B,
|
|
A
|
|
], expectedLayers: [
|
|
[D],
|
|
[C],
|
|
[B],
|
|
[A]
|
|
], expectedStrongLayers: [
|
|
[
|
|
[D]
|
|
],
|
|
[
|
|
[C]
|
|
],
|
|
[
|
|
[B]
|
|
],
|
|
[
|
|
[A]
|
|
]
|
|
]);
|
|
|
|
test(graphData: {
|
|
D: [],
|
|
C: [D],
|
|
B: [C],
|
|
A: [B],
|
|
}, expectedStrongComponents: [
|
|
[D],
|
|
[C],
|
|
[B],
|
|
[A]
|
|
], expectedSortedVertices: [
|
|
D,
|
|
C,
|
|
B,
|
|
A
|
|
], expectedLayers: [
|
|
[D],
|
|
[C],
|
|
[B],
|
|
[A]
|
|
], expectedStrongLayers: [
|
|
[
|
|
[D]
|
|
],
|
|
[
|
|
[C]
|
|
],
|
|
[
|
|
[B]
|
|
],
|
|
[
|
|
[A]
|
|
]
|
|
]);
|
|
|
|
test(graphData: {
|
|
A: [],
|
|
B: [A],
|
|
C: [A],
|
|
D: [B, C],
|
|
}, expectedStrongComponents: [
|
|
[A],
|
|
[B],
|
|
[C],
|
|
[D]
|
|
], expectedSortedVertices: [
|
|
A,
|
|
B,
|
|
C,
|
|
D
|
|
], expectedLayers: [
|
|
[A],
|
|
[B, C],
|
|
[D]
|
|
], expectedStrongLayers: [
|
|
[
|
|
[A]
|
|
],
|
|
[
|
|
[B],
|
|
[C]
|
|
],
|
|
[
|
|
[D]
|
|
]
|
|
]);
|
|
|
|
// Test a complex graph.
|
|
test(graphData: {
|
|
A: [B, C],
|
|
B: [C, D],
|
|
C: [],
|
|
D: [C, E],
|
|
E: [B, F],
|
|
F: [C, D]
|
|
}, expectedStrongComponents: [
|
|
[C],
|
|
[F, E, D, B],
|
|
[A],
|
|
], expectedSortedVertices: [
|
|
C
|
|
], expectedCyclicVertices: [
|
|
E,
|
|
D,
|
|
B,
|
|
A,
|
|
F
|
|
], expectedLayers: [
|
|
[C]
|
|
], expectedStrongLayers: [
|
|
[
|
|
[C]
|
|
],
|
|
[
|
|
[F, E, D, B]
|
|
],
|
|
[
|
|
[A]
|
|
]
|
|
]);
|
|
|
|
// Test a diamond-shaped graph.
|
|
test(graphData: {
|
|
A: [B, C],
|
|
B: [D],
|
|
C: [D],
|
|
D: []
|
|
}, expectedStrongComponents: [
|
|
[D],
|
|
[B],
|
|
[C],
|
|
[A],
|
|
], expectedSortedVertices: [
|
|
D,
|
|
B,
|
|
C,
|
|
A
|
|
], expectedLayers: [
|
|
[D],
|
|
[B, C],
|
|
[A]
|
|
], expectedStrongLayers: [
|
|
[
|
|
[D]
|
|
],
|
|
[
|
|
[B],
|
|
[C]
|
|
],
|
|
[
|
|
[A]
|
|
]
|
|
]);
|
|
|
|
// Test a graph with a single node.
|
|
test(graphData: {
|
|
A: []
|
|
}, expectedStrongComponents: [
|
|
[A]
|
|
], expectedSortedVertices: [
|
|
A
|
|
], expectedLayers: [
|
|
[A]
|
|
], expectedStrongLayers: [
|
|
[
|
|
[A]
|
|
]
|
|
]);
|
|
|
|
// Test a graph with a single node and a trivial cycle.
|
|
test(graphData: {
|
|
A: [A]
|
|
}, expectedStrongComponents: [
|
|
[A]
|
|
], expectedCyclicVertices: [
|
|
A
|
|
], expectedStrongLayers: [
|
|
[
|
|
[A]
|
|
]
|
|
]);
|
|
|
|
// Test a graph with three nodes with circular dependencies.
|
|
test(graphData: {
|
|
A: [B],
|
|
B: [C],
|
|
C: [A],
|
|
}, expectedStrongComponents: [
|
|
[C, B, A]
|
|
], expectedCyclicVertices: [
|
|
C,
|
|
B,
|
|
A
|
|
], expectedStrongLayers: [
|
|
[
|
|
[C, B, A]
|
|
]
|
|
]);
|
|
|
|
// Test a graph A->B->C->D, where D points back to B and then C.
|
|
test(graphData: {
|
|
A: [B],
|
|
B: [C],
|
|
C: [D],
|
|
D: [B, C]
|
|
}, expectedStrongComponents: [
|
|
[D, C, B],
|
|
[A]
|
|
], expectedCyclicVertices: [
|
|
D,
|
|
C,
|
|
B,
|
|
A
|
|
], expectedStrongLayers: [
|
|
[
|
|
[D, C, B]
|
|
],
|
|
[
|
|
[A]
|
|
]
|
|
]);
|
|
|
|
// Test a graph A->B->C->D, where D points back to C and then B.
|
|
test(graphData: {
|
|
A: [B],
|
|
B: [C],
|
|
C: [D],
|
|
D: [C, B]
|
|
}, expectedStrongComponents: [
|
|
[D, C, B],
|
|
[A]
|
|
], expectedCyclicVertices: [
|
|
D,
|
|
C,
|
|
B,
|
|
A
|
|
], expectedStrongLayers: [
|
|
[
|
|
[D, C, B]
|
|
],
|
|
[
|
|
[A]
|
|
]
|
|
]);
|
|
|
|
// Test a graph with two nodes with circular dependencies.
|
|
test(graphData: {
|
|
A: [B],
|
|
B: [A]
|
|
}, expectedStrongComponents: [
|
|
[B, A]
|
|
], expectedCyclicVertices: [
|
|
B,
|
|
A
|
|
], expectedStrongLayers: [
|
|
[
|
|
[B, A]
|
|
]
|
|
]);
|
|
|
|
// Test a graph with two nodes and a single dependency.
|
|
test(graphData: {
|
|
A: [B],
|
|
B: []
|
|
}, expectedStrongComponents: [
|
|
[B],
|
|
[A]
|
|
], expectedSortedVertices: [
|
|
B,
|
|
A
|
|
], expectedLayers: [
|
|
[B],
|
|
[A]
|
|
], expectedStrongLayers: [
|
|
[
|
|
[B]
|
|
],
|
|
[
|
|
[A]
|
|
]
|
|
]);
|
|
|
|
test(graphData: {
|
|
A: [],
|
|
B: [A],
|
|
C: [B, D],
|
|
D: [C],
|
|
E: [A],
|
|
F: [B],
|
|
}, expectedStrongComponents: [
|
|
[A],
|
|
[B],
|
|
[D, C],
|
|
[E],
|
|
[F],
|
|
], expectedSortedVertices: [
|
|
A,
|
|
B,
|
|
E,
|
|
F,
|
|
], expectedCyclicVertices: [
|
|
D,
|
|
C,
|
|
], expectedLayers: [
|
|
[A],
|
|
[B, E],
|
|
[F],
|
|
], expectedStrongLayers: [
|
|
[
|
|
[A]
|
|
],
|
|
[
|
|
[B],
|
|
[E]
|
|
],
|
|
[
|
|
[D, C],
|
|
[F]
|
|
]
|
|
]);
|
|
|
|
testTransitiveDependencies(graphData: {
|
|
A: [B],
|
|
B: [A],
|
|
}, of: {
|
|
A
|
|
}, expected: {
|
|
A,
|
|
B,
|
|
});
|
|
|
|
testTransitiveDependencies(graphData: {}, of: {
|
|
A,
|
|
B,
|
|
C,
|
|
D,
|
|
E,
|
|
F,
|
|
}, expected: {});
|
|
|
|
{
|
|
String MAIN = "MAIN";
|
|
String DARTFFI = "DARTFFI";
|
|
testTransitiveDependencies(graphData: {
|
|
MAIN: [DARTFFI],
|
|
}, of: {
|
|
DARTFFI
|
|
}, expected: {
|
|
MAIN,
|
|
});
|
|
}
|
|
|
|
testTransitiveDependencies(graphData: {
|
|
A: [B],
|
|
B: [C],
|
|
C: [B, D],
|
|
D: [C],
|
|
E: [A],
|
|
F: [B],
|
|
}, of: {
|
|
A
|
|
}, expected: {
|
|
A,
|
|
E
|
|
});
|
|
|
|
{
|
|
String MAIN = "MAIN";
|
|
String TARGET = "TARGET";
|
|
|
|
testTransitiveDependencies(graphData: {
|
|
MAIN: [A, E],
|
|
A: [B],
|
|
B: [A, C],
|
|
C: [TARGET],
|
|
D: [],
|
|
E: [D],
|
|
}, of: {
|
|
TARGET,
|
|
}, expected: {
|
|
C,
|
|
B,
|
|
A,
|
|
MAIN,
|
|
});
|
|
|
|
testTransitiveDependencies(graphData: {
|
|
MAIN: [A, E],
|
|
A: [B],
|
|
B: [A, C],
|
|
C: [],
|
|
D: [],
|
|
E: [D],
|
|
}, of: {
|
|
TARGET,
|
|
}, expected: {});
|
|
|
|
testTransitiveDependencies(graphData: {
|
|
MAIN: [A, C, E, TARGET],
|
|
A: [B],
|
|
B: [A, C],
|
|
C: [],
|
|
D: [],
|
|
E: [D],
|
|
}, of: {
|
|
TARGET,
|
|
}, expected: {
|
|
MAIN,
|
|
});
|
|
}
|
|
}
|
|
|
|
void testTransitiveDependencies(
|
|
{required Set<String> of,
|
|
required Set<String> expected,
|
|
required Map<String, List<String>> graphData}) {
|
|
Graph<String> graph = new TestGraph(graphData);
|
|
Set<String> actual = calculateTransitiveDependenciesOf(graph, of);
|
|
Expect.setEquals(expected, actual);
|
|
}
|