Skip to content

Commit 0df870d

Browse files
committed
Add some profiling instrumentation to the exhaustiveness checker.
1 parent 7c0ec27 commit 0df870d

File tree

5 files changed

+69
-14
lines changed

5 files changed

+69
-14
lines changed

working/0546-patterns/exhaustiveness_prototype/lib/equal.dart

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
4+
import 'profile.dart' as profile;
45
import 'space.dart';
56

67
/// Returns `true` if [left] and [right] are equivalent spaces.
78
///
89
/// Equality is defined purely structurally/syntactically.
9-
bool equal(Space left, Space right) {
10-
if (left == right) return true;
10+
bool equal(Space left, Space right, String reason) {
11+
profile.count('equal', reason);
12+
13+
if (identical(left, right)) return true;
1114

1215
// Empty is only equal to itself (and will get caught by the previous check).
1316
if (left == Space.empty) return false;
@@ -35,7 +38,7 @@ bool _equalUnions(UnionSpace left, UnionSpace right) {
3538
for (var leftArm in left.arms) {
3639
var found = false;
3740
for (var rightArm in right.arms) {
38-
if (equal(leftArm, rightArm)) {
41+
if (equal(leftArm, rightArm, 'recurse union')) {
3942
found = true;
4043
break;
4144
}
@@ -58,7 +61,9 @@ bool _equalExtracts(ExtractSpace left, ExtractSpace right) {
5861
if (right.fields.length != fields.length) return false;
5962

6063
for (var field in fields) {
61-
if (!equal(left.fields[field]!, right.fields[field]!)) return false;
64+
if (!equal(left.fields[field]!, right.fields[field]!, 'recurse extract')) {
65+
return false;
66+
}
6267
}
6368

6469
return true;

working/0546-patterns/exhaustiveness_prototype/lib/intersect.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
4-
import 'package:exhaustiveness_prototype/static_type.dart';
5-
4+
import 'profile.dart' as profile;
65
import 'space.dart';
6+
import 'static_type.dart';
77

88
/// Calculates the intersection of [left] and [right].
99
///
1010
/// This is used to tell if two field spaces on a pair of spaces being
1111
/// subtracted have no common values.
1212
Space intersect(Space left, Space right) {
13+
profile.count('intersect');
14+
1315
// The intersection with an empty space is always empty.
1416
if (left == Space.empty) return Space.empty;
1517
if (right == Space.empty) return Space.empty;
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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 'dart:math';
6+
7+
var enabled = false;
8+
9+
final _counts = <String, int>{};
10+
11+
void count(String name, [String? subname]) {
12+
if (!enabled) return;
13+
_counts.putIfAbsent(name, () => 0);
14+
_counts[name] = _counts[name]! + 1;
15+
16+
if (subname != null) {
17+
count('$name/$subname');
18+
}
19+
}
20+
21+
void run(void Function() callback) {
22+
reset();
23+
try {
24+
callback();
25+
} finally {
26+
log();
27+
reset();
28+
}
29+
}
30+
31+
void reset() {
32+
_counts.clear();
33+
}
34+
35+
void log() {
36+
var names = _counts.keys.toList();
37+
names.sort();
38+
var nameLength =
39+
names.fold<int>(0, (length, name) => max(length, name.length));
40+
var countLength = _counts.values
41+
.fold<int>(0, (length, count) => max(length, count.toString().length));
42+
43+
for (var name in names) {
44+
print('${name.padRight(nameLength)} = '
45+
'${_counts[name].toString().padLeft(countLength)}');
46+
}
47+
}

working/0546-patterns/exhaustiveness_prototype/lib/space.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ abstract class Space {
2828
// implementation would likely define hash code too and then simply
2929
// create a hash set to merge duplicates in O(n) time.
3030
for (var existing in allArms) {
31-
if (equal(existing, space)) return;
31+
if (equal(existing, space, 'dedupe union')) return;
3232
}
3333

3434
allArms.add(space);

working/0546-patterns/exhaustiveness_prototype/lib/subtract.dart

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
4-
import 'package:exhaustiveness_prototype/intersect_empty.dart';
5-
import 'package:exhaustiveness_prototype/static_type.dart';
4+
import 'intersect_empty.dart';
5+
import 'profile.dart' as profile;
6+
import 'static_type.dart';
67

78
import 'space.dart';
89

910
/// Returns a new [Space] that contains all of the values of [left] that are
1011
/// not also in [right].
1112
Space subtract(Space left, Space right) {
13+
profile.count('subtract');
14+
1215
// Subtracting from empty is still empty.
1316
if (left == Space.empty) return Space.empty;
1417

@@ -96,7 +99,6 @@ List<Space> _subtractExtractAtType(StaticType type, ExtractSpace left,
9699

97100
// Walk the fields and see which ones are modified by the right-hand fields.
98101
var fixed = <String, Space>{};
99-
var changedLeft = <String, Space>{};
100102
var changedDifference = <String, Space>{};
101103
for (var name in fieldNames) {
102104
var difference = subtract(leftFields[name]!, rightFields[name]!);
@@ -108,18 +110,17 @@ List<Space> _subtractExtractAtType(StaticType type, ExtractSpace left,
108110
// If the resulting field matches everything, simply discard it since
109111
// it's equivalent to omitting the field.
110112
} else {
111-
changedLeft[name] = leftFields[name]!;
112113
changedDifference[name] = difference;
113114
}
114115
}
115116

116117
// If no fields are affected by the subtraction, just return a single arm
117118
// with all of the fields.
118-
if (changedLeft.isEmpty) return [Space(type, fixed)];
119+
if (changedDifference.isEmpty) return [Space(type, fixed)];
119120

120121
// For each field whose `left - right` is different, include an arm that
121122
// includes that one difference.
122-
var changedFields = changedLeft.keys.toList();
123+
var changedFields = changedDifference.keys.toList();
123124
var spaces = <Space>[];
124125
for (var i = 0; i < changedFields.length; i++) {
125126
var fields = {...fixed};
@@ -129,7 +130,7 @@ List<Space> _subtractExtractAtType(StaticType type, ExtractSpace left,
129130
if (i == j) {
130131
fields[name] = changedDifference[name]!;
131132
} else {
132-
fields[name] = changedLeft[name]!;
133+
fields[name] = leftFields[name]!;
133134
}
134135
}
135136

0 commit comments

Comments
 (0)