blob: 0ba1365aa25fe1bf7287ad058f0bb1ea58c55dbc [file] [log] [blame]
// Copyright (c) 2017, 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.
// @dart=2.9
/// Shared code used by fasta_perf and incremental_perf.
library front_end.tool.perf_common;
import 'dart:io' show exitCode, stderr;
import 'package:_fe_analyzer_shared/src/messages/diagnostic_message.dart'
show DiagnosticMessage, DiagnosticMessageHandler, getMessageCodeObject;
import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
import 'package:kernel/target/targets.dart' show Target, TargetFlags;
import 'package:vm/target/flutter.dart' show FlutterTarget;
import 'package:vm/target/vm.dart' show VmTarget;
import 'package:front_end/src/api_prototype/terminal_color_support.dart'
show printDiagnosticMessage;
import 'package:front_end/src/fasta/fasta_codes.dart' as fastaCodes;
/// Error messages that we temporarily allow when compiling benchmarks in strong
/// mode.
/// This allowlist lets us run the compiler benchmarks while those errors get
/// fixed. We don't blindly allow any error message because we would then miss
/// situations where the benchmarks are actually broken.
/// Note: the performance bots compile both dart2js and the flutter-gallery app
/// as benchmarks, so they both need to be checked before we remove a message
/// from this set.
final allowlistMessageCode = new Set<fastaCodes.Code>.from(<fastaCodes.Code>[
// Code names in this list should match the key used in messages.yaml
// The following errors are not covered by unit tests in the SDK repo because
// they are only seen today in the flutter-gallery benchmark (external to
// this repo).
DiagnosticMessageHandler onDiagnosticMessageHandler() {
bool messageReported = false;
return (DiagnosticMessage m) {
if (m.severity == Severity.internalProblem ||
m.severity == Severity.error) {
if (!allowlistMessageCode.contains(getMessageCodeObject(m))) {
printDiagnosticMessage(m, stderr.writeln);
exitCode = 1;
} else if (!messageReported) {
messageReported = true;
stderr.writeln('Allowlisted error messages omitted');
/// Creates a [VmTarget] or [FlutterTarget] with legacy mode enabled or
/// disabled.
// TODO(sigmund): delete as soon as the disableTypeInference flag and the
// legacyMode flag get merged, and we have a single way of specifying the
// legacy-mode flag to the FE.
Target createTarget({bool isFlutter: false}) {
TargetFlags flags = new TargetFlags();
if (isFlutter) {
return new FlutterTarget(flags);
} else {
return new VmTarget(flags);
class TimingsCollector {
final Stopwatch stopwatch = new Stopwatch();
final Map<String, List<double>> timings = <String, List<double>>{};
final bool verbose;
String currentKey;
void start(String key) {
if (currentKey != null) {
throw "Attempt to time '$key' while '$currentKey' is running.";
currentKey = key;
void stop(String key) {
if (currentKey == null) {
throw "Need to call 'start' before calling 'stop'.";
if (currentKey != key) {
throw "Can't stop timing '$key' because '$currentKey' is running.";
currentKey = null;
double duration =
stopwatch.elapsedMicroseconds / Duration.microsecondsPerMillisecond;
List<double> durations = (timings[key] ??= <double>[]);
if (verbose) {
print("$key took: ${duration}ms");
void printTimings() {
timings.forEach((String key, List<double> durations) {
double total = 0.0;
int length = durations.length;
if (length == 1) {
total += durations.single;
} else {
length -= 3;
for (double duration in durations.skip(3)) {
total += duration;
print("$key took: ${total / length}ms");