Skip to content

Commit

Permalink
Add some profiling instrumentation to the exhaustiveness checker.
Browse files Browse the repository at this point in the history
  • Loading branch information
munificent committed Apr 20, 2022
1 parent 7c0ec27 commit 0df870d
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 14 deletions.
13 changes: 9 additions & 4 deletions working/0546-patterns/exhaustiveness_prototype/lib/equal.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
// Copyright (c) 2022, 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 file.
import 'profile.dart' as profile;
import 'space.dart';

/// Returns `true` if [left] and [right] are equivalent spaces.
///
/// Equality is defined purely structurally/syntactically.
bool equal(Space left, Space right) {
if (left == right) return true;
bool equal(Space left, Space right, String reason) {
profile.count('equal', reason);

if (identical(left, right)) return true;

// Empty is only equal to itself (and will get caught by the previous check).
if (left == Space.empty) return false;
Expand Down Expand Up @@ -35,7 +38,7 @@ bool _equalUnions(UnionSpace left, UnionSpace right) {
for (var leftArm in left.arms) {
var found = false;
for (var rightArm in right.arms) {
if (equal(leftArm, rightArm)) {
if (equal(leftArm, rightArm, 'recurse union')) {
found = true;
break;
}
Expand All @@ -58,7 +61,9 @@ bool _equalExtracts(ExtractSpace left, ExtractSpace right) {
if (right.fields.length != fields.length) return false;

for (var field in fields) {
if (!equal(left.fields[field]!, right.fields[field]!)) return false;
if (!equal(left.fields[field]!, right.fields[field]!, 'recurse extract')) {
return false;
}
}

return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
// Copyright (c) 2022, 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 file.
import 'package:exhaustiveness_prototype/static_type.dart';

import 'profile.dart' as profile;
import 'space.dart';
import 'static_type.dart';

/// Calculates the intersection of [left] and [right].
///
/// This is used to tell if two field spaces on a pair of spaces being
/// subtracted have no common values.
Space intersect(Space left, Space right) {
profile.count('intersect');

// The intersection with an empty space is always empty.
if (left == Space.empty) return Space.empty;
if (right == Space.empty) return Space.empty;
Expand Down
47 changes: 47 additions & 0 deletions working/0546-patterns/exhaustiveness_prototype/lib/profile.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2022, 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 file.

import 'dart:math';

var enabled = false;

final _counts = <String, int>{};

void count(String name, [String? subname]) {
if (!enabled) return;
_counts.putIfAbsent(name, () => 0);
_counts[name] = _counts[name]! + 1;

if (subname != null) {
count('$name/$subname');
}
}

void run(void Function() callback) {
reset();
try {
callback();
} finally {
log();
reset();
}
}

void reset() {
_counts.clear();
}

void log() {
var names = _counts.keys.toList();
names.sort();
var nameLength =
names.fold<int>(0, (length, name) => max(length, name.length));
var countLength = _counts.values
.fold<int>(0, (length, count) => max(length, count.toString().length));

for (var name in names) {
print('${name.padRight(nameLength)} = '
'${_counts[name].toString().padLeft(countLength)}');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ abstract class Space {
// implementation would likely define hash code too and then simply
// create a hash set to merge duplicates in O(n) time.
for (var existing in allArms) {
if (equal(existing, space)) return;
if (equal(existing, space, 'dedupe union')) return;
}

allArms.add(space);
Expand Down
15 changes: 8 additions & 7 deletions working/0546-patterns/exhaustiveness_prototype/lib/subtract.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
// Copyright (c) 2022, 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 file.
import 'package:exhaustiveness_prototype/intersect_empty.dart';
import 'package:exhaustiveness_prototype/static_type.dart';
import 'intersect_empty.dart';
import 'profile.dart' as profile;
import 'static_type.dart';

import 'space.dart';

/// Returns a new [Space] that contains all of the values of [left] that are
/// not also in [right].
Space subtract(Space left, Space right) {
profile.count('subtract');

// Subtracting from empty is still empty.
if (left == Space.empty) return Space.empty;

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

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

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

// For each field whose `left - right` is different, include an arm that
// includes that one difference.
var changedFields = changedLeft.keys.toList();
var changedFields = changedDifference.keys.toList();
var spaces = <Space>[];
for (var i = 0; i < changedFields.length; i++) {
var fields = {...fixed};
Expand All @@ -129,7 +130,7 @@ List<Space> _subtractExtractAtType(StaticType type, ExtractSpace left,
if (i == j) {
fields[name] = changedDifference[name]!;
} else {
fields[name] = changedLeft[name]!;
fields[name] = leftFields[name]!;
}
}

Expand Down

0 comments on commit 0df870d

Please sign in to comment.