analysis.dart 3.95 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6
// @dart = 2.8

7 8 9 10
import 'dart:io';

import 'package:path/path.dart' as path;

11
import '../framework/task_result.dart';
12 13
import '../framework/utils.dart';

14 15 16 17 18 19
/// Run each benchmark this many times and compute average, min, max.
///
/// This must be small enough that we can do all the work in 15 minutes, the
/// devicelab deadline. Since there's four different analysis tasks, on average,
/// each can have 4 minutes. The tasks currently average a little more than a
/// minute, so that allows three runs per task.
20
const int _kRunsPerBenchmark = 3;
21

22 23
/// Path to the generated "mega gallery" app.
Directory get _megaGalleryDirectory => dir(path.join(Directory.systemTemp.path, 'mega_gallery'));
24

25
Future<TaskResult> analyzerBenchmarkTask() async {
26
  await inDirectory<void>(flutterDirectory, () async {
27 28
    rmTree(_megaGalleryDirectory);
    mkdirs(_megaGalleryDirectory);
29
    await flutter('update-packages');
30 31
    await dart(<String>['dev/tools/mega_gallery.dart', '--out=${_megaGalleryDirectory.path}']);
  });
32

33 34 35 36 37 38
  final Map<String, dynamic> data = <String, dynamic>{
    ...(await _run(_FlutterRepoBenchmark())).asMap('flutter_repo', 'batch'),
    ...(await _run(_FlutterRepoBenchmark(watch: true))).asMap('flutter_repo', 'watch'),
    ...(await _run(_MegaGalleryBenchmark())).asMap('mega_gallery', 'batch'),
    ...(await _run(_MegaGalleryBenchmark(watch: true))).asMap('mega_gallery', 'watch'),
  };
39

40
  return TaskResult.success(data, benchmarkScoreKeys: data.keys.toList());
41 42
}

43 44
class _BenchmarkResult {
  const _BenchmarkResult(this.mean, this.min, this.max);
45

46
  final double mean; // seconds
47

48
  final double min; // seconds
49

50
  final double max; // seconds
51

52 53 54 55 56 57
  Map<String, dynamic> asMap(String benchmark, String mode) {
    return <String, dynamic>{
      '${benchmark}_$mode': mean,
      '${benchmark}_${mode}_minimum': min,
      '${benchmark}_${mode}_maximum': max,
    };
58 59 60
  }
}

61
abstract class _Benchmark {
62
  _Benchmark({this.watch = false});
63

64
  final bool watch;
65

66
  String get title;
67

68
  Directory get directory;
69

70
  List<String> get options => <String>[
71 72 73
        '--benchmark',
        if (watch) '--watch',
      ];
74 75 76

  Future<double> execute(int iteration, int targetIterations) async {
    section('Analyze $title ${watch ? 'with watcher' : ''} - ${iteration + 1} / $targetIterations');
77
    final Stopwatch stopwatch = Stopwatch();
78
    await inDirectory<void>(directory, () async {
79 80 81
      stopwatch.start();
      await flutter('analyze', options: options);
      stopwatch.stop();
82
    });
83
    return stopwatch.elapsedMicroseconds / (1000.0 * 1000.0);
84
  }
85
}
86

87 88
/// Times how long it takes to analyze the Flutter repository.
class _FlutterRepoBenchmark extends _Benchmark {
89
  _FlutterRepoBenchmark({bool watch = false}) : super(watch: watch);
90 91 92 93 94 95 96 97 98

  @override
  String get title => 'Flutter repo';

  @override
  Directory get directory => flutterDirectory;

  @override
  List<String> get options {
99
    return super.options..add('--flutter-repo');
100 101 102 103 104
  }
}

/// Times how long it takes to analyze the generated "mega_gallery" app.
class _MegaGalleryBenchmark extends _Benchmark {
105
  _MegaGalleryBenchmark({bool watch = false}) : super(watch: watch);
106 107 108 109 110 111 112 113 114 115 116 117

  @override
  String get title => 'mega gallery';

  @override
  Directory get directory => _megaGalleryDirectory;
}

/// Runs `benchmark` several times and reports the results.
Future<_BenchmarkResult> _run(_Benchmark benchmark) async {
  final List<double> results = <double>[];
  for (int i = 0; i < _kRunsPerBenchmark; i += 1) {
118 119
    // Delete cached analysis results.
    rmTree(dir('${Platform.environment['HOME']}/.dartServer'));
120
    results.add(await benchmark.execute(i, _kRunsPerBenchmark));
121
  }
122 123 124 125 126
  results.sort();
  final double sum = results.fold<double>(
    0.0,
    (double previousValue, double element) => previousValue + element,
  );
127
  return _BenchmarkResult(sum / results.length, results.first, results.last);
128
}