[dart2js] Fix work queue bucketing.

I'm reverting the work queue change for the main inferrer branch. After some instrumenting I've found that it's rather sensitive to the max refinement limit which is very low for the non-experimental branch. In the linearized algorithm the refinement limit is increased so I will keep it in that fork.

Change-Id: I3407ae4d895c9910b6588dea5782ba4b6208ec7a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/290420
Reviewed-by: Mayank Patke <fishythefish@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
This commit is contained in:
Nate Biggs 2023-03-23 03:18:57 +00:00 committed by Commit Queue
parent f72782ce9b
commit 5ac0a50d43
2 changed files with 31 additions and 45 deletions

View file

@ -5,40 +5,18 @@
import 'dart:collection' show Queue;
import 'type_graph_nodes.dart';
const _numBuckets = 2;
/// This function applies a bucket index to each type information.
///
/// Current strategy:
/// Process call sites together effectively splitting intraprocedural type
/// refinement and local type refinement.
int _bucketForInfo(TypeInformation info) {
if (info is! CallSiteTypeInformation) return 0;
return 1;
}
/// A work queue for the inferrer. It filters out nodes that are tagged as
/// [TypeInformation.doNotEnqueue], as well as ensures through
/// [TypeInformation.inQueue] that a node is in the queue only once at
/// a time.
///
/// The queue uses a bucketed approach to allow the inferrer to make progress
/// on certain categories of types while also ensuring no category is starved
/// of resources. The queue draws work items from a bucket until it is empty
/// and then proceeds onto the next bucket with work remaining. This allows
/// related work items to be processed closer to each other.
class WorkQueue {
final List<Queue<TypeInformation>> buckets =
List.generate(_numBuckets, (_) => Queue());
int _length = 0;
int _activeBucket = 0;
final Queue<TypeInformation> queue = Queue<TypeInformation>();
void add(TypeInformation element) {
if (element.doNotEnqueue) return;
if (element.inQueue) return;
buckets[_bucketForInfo(element)].addLast(element);
queue.addLast(element);
element.inQueue = true;
_length++;
}
void addAll(Iterable<TypeInformation> all) {
@ -46,18 +24,12 @@ class WorkQueue {
}
TypeInformation remove() {
var bucket = buckets[_activeBucket];
while (bucket.isEmpty) {
if (++_activeBucket == buckets.length) _activeBucket = 0;
bucket = buckets[_activeBucket];
}
TypeInformation element = bucket.removeFirst();
TypeInformation element = queue.removeFirst();
element.inQueue = false;
_length--;
return element;
}
bool get isEmpty => _length == 0;
bool get isEmpty => queue.isEmpty;
int get length => _length;
int get length => queue.length;
}

View file

@ -24,19 +24,23 @@ int _bucketForInfo(TypeInformation info) {
///
/// The queue uses a bucketed approach to allow the inferrer to make progress
/// on certain categories of types while also ensuring no category is starved
/// of resources. The queue draws work items from a bucket until it is empty
/// and then proceeds onto the next bucket with work remaining. This allows
/// related work items to be processed closer to each other.
/// of resources. We grab a "snapshot" of the active bucket and process elements
/// from it until it is empty. Anything added to the bucket after we have
/// grabbed the snapshot is not processed immediately. Instead once the snapshot
/// is empty we move on to the next bucket. By ignoring elements after the
/// snapshot we prevent the queue from getting stuck on loops within the same
/// bucket.
class WorkQueue {
final List<Queue<TypeInformation>> buckets =
List.generate(_numBuckets, (_) => Queue());
List.generate(_numBuckets, (_) => Queue(), growable: false);
int _length = 0;
int _activeBucket = 0;
Queue<TypeInformation> _activeQueue = Queue();
int _activeBucketIndex = 0;
void add(TypeInformation element) {
if (element.doNotEnqueue) return;
if (element.inQueue) return;
buckets[_bucketForInfo(element)].addLast(element);
buckets[_bucketForInfo(element)].add(element);
element.inQueue = true;
_length++;
}
@ -46,17 +50,27 @@ class WorkQueue {
}
TypeInformation remove() {
var bucket = buckets[_activeBucket];
while (bucket.isEmpty) {
if (++_activeBucket == buckets.length) _activeBucket = 0;
bucket = buckets[_activeBucket];
while (_activeQueue.isEmpty) {
assert(_length != 0);
final bucket = buckets[_activeBucketIndex];
if (bucket.isNotEmpty) {
final tmp = _activeQueue;
_activeQueue = buckets[_activeBucketIndex];
buckets[_activeBucketIndex] = tmp;
}
_incrementBucketIndex();
}
TypeInformation element = bucket.removeFirst();
element.inQueue = false;
final element = _activeQueue.removeFirst();
_length--;
element.inQueue = false;
return element;
}
void _incrementBucketIndex() {
_activeBucketIndex =
_activeBucketIndex == buckets.length - 1 ? 0 : _activeBucketIndex + 1;
}
bool get isEmpty => _length == 0;
int get length => _length;