timeline_summary_test.dart 10.8 KB
Newer Older
1 2 3 4
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'dart:convert' show json;
6

7
import 'package:file/file.dart';
8 9
import 'package:flutter_driver/flutter_driver.dart';
import 'package:flutter_driver/src/driver/common.dart';
10
import 'package:path/path.dart' as path;
11 12

import '../common.dart';
13 14 15 16 17

void main() {
  group('TimelineSummary', () {

    TimelineSummary summarize(List<Map<String, dynamic>> testEvents) {
18
      return TimelineSummary.summarize(Timeline.fromJson(<String, dynamic>{
19
        'traceEvents': testEvents,
20
      }));
21 22
    }

23
    Map<String, dynamic> build(int timeStamp, int duration) => <String, dynamic>{
24 25 26 27
      'name': 'Frame',
      'ph': 'X',
      'ts': timeStamp,
      'dur': duration,
28 29
    };

30
    Map<String, dynamic> begin(int timeStamp) => <String, dynamic>{
31 32 33
      'name': 'GPURasterizer::Draw',
      'ph': 'B',
      'ts': timeStamp,
34 35 36
    };

    Map<String, dynamic> end(int timeStamp) => <String, dynamic>{
37 38 39
      'name': 'GPURasterizer::Draw',
      'ph': 'E',
      'ts': timeStamp,
40 41
    };

42 43 44
    List<Map<String, dynamic>> rasterizeTimeSequenceInMillis(List<int> sequence) {
      final List<Map<String, dynamic>> result = <Map<String, dynamic>>[];
      int t = 0;
45
      for (int duration in sequence) {
46 47 48 49 50 51 52
        result.add(begin(t));
        t += duration * 1000;
        result.add(end(t));
      }
      return result;
    }

53 54 55
    group('frame_count', () {
      test('counts frames', () {
        expect(
pq's avatar
pq committed
56
          summarize(<Map<String, dynamic>>[
57 58
            build(1000, 1000),
            build(3000, 2000),
59
          ]).countFrames(),
60
          2,
61 62 63 64 65
        );
      });
    });

    group('average_frame_build_time_millis', () {
66 67 68
      test('throws when there is no data', () {
        expect(
          () => summarize(<Map<String, dynamic>>[]).computeAverageFrameBuildTimeMillis(),
69
          throwsA(predicate<ArgumentError>((ArgumentError e) => e.message == 'durations is empty!')),
70
        );
71 72 73 74
      });

      test('computes average frame build time in milliseconds', () {
        expect(
pq's avatar
pq committed
75
          summarize(<Map<String, dynamic>>[
76 77
            build(1000, 1000),
            build(3000, 2000),
78
          ]).computeAverageFrameBuildTimeMillis(),
79
          1.5,
80 81
        );
      });
82 83 84
    });

    group('worst_frame_build_time_millis', () {
85 86 87
      test('throws when there is no data', () {
        expect(
          () => summarize(<Map<String, dynamic>>[]).computeWorstFrameBuildTimeMillis(),
88
          throwsA(predicate<ArgumentError>((ArgumentError e) => e.message == 'durations is empty!')),
89
        );
90 91 92 93
      });

      test('computes worst frame build time in milliseconds', () {
        expect(
pq's avatar
pq committed
94
          summarize(<Map<String, dynamic>>[
95 96
            build(1000, 1000),
            build(3000, 2000),
97
          ]).computeWorstFrameBuildTimeMillis(),
98
          2.0,
99 100
        );
        expect(
pq's avatar
pq committed
101
          summarize(<Map<String, dynamic>>[
102 103
            build(3000, 2000),
            build(1000, 1000),
104
          ]).computeWorstFrameBuildTimeMillis(),
105
          2.0,
106 107 108 109 110 111
        );
      });
    });

    group('computeMissedFrameBuildBudgetCount', () {
      test('computes the number of missed build budgets', () {
112
        final TimelineSummary summary = summarize(<Map<String, dynamic>>[
113 114 115
          build(1000, 17000),
          build(19000, 9000),
          build(29000, 18000),
116 117 118 119 120 121 122
        ]);

        expect(summary.countFrames(), 3);
        expect(summary.computeMissedFrameBuildBudgetCount(), 2);
      });
    });

123
    group('average_frame_rasterizer_time_millis', () {
124 125 126
      test('throws when there is no data', () {
        expect(
          () => summarize(<Map<String, dynamic>>[]).computeAverageFrameRasterizerTimeMillis(),
127
          throwsA(predicate<ArgumentError>((ArgumentError e) => e.message == 'durations is empty!')),
128
        );
129 130 131 132 133 134 135 136
      });

      test('computes average frame rasterizer time in milliseconds', () {
        expect(
            summarize(<Map<String, dynamic>>[
              begin(1000), end(2000),
              begin(3000), end(5000),
            ]).computeAverageFrameRasterizerTimeMillis(),
137
            1.5,
138 139 140 141 142 143 144 145 146
        );
      });

      test('skips leading "end" events', () {
        expect(
            summarize(<Map<String, dynamic>>[
              end(1000),
              begin(2000), end(4000),
            ]).computeAverageFrameRasterizerTimeMillis(),
147
            2.0,
148 149 150 151 152 153 154 155 156
        );
      });

      test('skips trailing "begin" events', () {
        expect(
            summarize(<Map<String, dynamic>>[
              begin(2000), end(4000),
              begin(5000),
            ]).computeAverageFrameRasterizerTimeMillis(),
157
            2.0,
158 159 160 161 162
        );
      });
    });

    group('worst_frame_rasterizer_time_millis', () {
163 164 165
      test('throws when there is no data', () {
        expect(
          () => summarize(<Map<String, dynamic>>[]).computeWorstFrameRasterizerTimeMillis(),
166
          throwsA(predicate<ArgumentError>((ArgumentError e) => e.message == 'durations is empty!')),
167
        );
168 169
      });

170

171 172 173 174 175 176
      test('computes worst frame rasterizer time in milliseconds', () {
        expect(
            summarize(<Map<String, dynamic>>[
              begin(1000), end(2000),
              begin(3000), end(5000),
            ]).computeWorstFrameRasterizerTimeMillis(),
177
            2.0,
178 179 180 181 182 183
        );
        expect(
            summarize(<Map<String, dynamic>>[
              begin(3000), end(5000),
              begin(1000), end(2000),
            ]).computeWorstFrameRasterizerTimeMillis(),
184
            2.0,
185 186 187 188 189 190 191 192 193
        );
      });

      test('skips leading "end" events', () {
        expect(
            summarize(<Map<String, dynamic>>[
              end(1000),
              begin(2000), end(4000),
            ]).computeWorstFrameRasterizerTimeMillis(),
194
            2.0,
195 196 197 198 199 200 201 202 203
        );
      });

      test('skips trailing "begin" events', () {
        expect(
            summarize(<Map<String, dynamic>>[
              begin(2000), end(4000),
              begin(5000),
            ]).computeWorstFrameRasterizerTimeMillis(),
204
            2.0,
205 206 207 208
        );
      });
    });

209
    group('percentile_frame_rasterizer_time_millis', () {
210 211 212
      test('throws when there is no data', () {
        expect(
          () => summarize(<Map<String, dynamic>>[]).computePercentileFrameRasterizerTimeMillis(90.0),
213
          throwsA(predicate<ArgumentError>((ArgumentError e) => e.message == 'durations is empty!')),
214
        );
215 216
      });

217

218 219 220
      const List<List<int>> sequences = <List<int>>[
        <int>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
        <int>[1, 2, 3, 4, 5],
221
        <int>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20],
222 223 224 225 226
      ];

      const List<int> p90s = <int>[
        9,
        5,
227
        18,
228 229 230
      ];

      test('computes 90th frame rasterizer time in milliseconds', () {
231
        for (int i = 0; i < sequences.length; ++i) {
232 233
          expect(
            summarize(rasterizeTimeSequenceInMillis(sequences[i])).computePercentileFrameRasterizerTimeMillis(90.0),
234
            p90s[i],
235 236 237 238 239 240
          );
        }
      });

      test('compute 99th frame rasterizer time in milliseconds', () {
        final List<int> sequence = <int>[];
241
        for (int i = 1; i <= 100; ++i) {
242 243 244 245
          sequence.add(i);
        }
        expect(
          summarize(rasterizeTimeSequenceInMillis(sequence)).computePercentileFrameRasterizerTimeMillis(99.0),
246
          99,
247 248 249 250
        );
      });
    });

251 252
    group('computeMissedFrameRasterizerBudgetCount', () {
      test('computes the number of missed rasterizer budgets', () {
253
        final TimelineSummary summary = summarize(<Map<String, dynamic>>[
254 255 256
          begin(1000), end(18000),
          begin(19000), end(28000),
          begin(29000), end(47000),
257 258 259 260 261 262
        ]);

        expect(summary.computeMissedFrameRasterizerBudgetCount(), 2);
      });
    });

263 264 265
    group('summaryJson', () {
      test('computes and returns summary as JSON', () {
        expect(
pq's avatar
pq committed
266
          summarize(<Map<String, dynamic>>[
267 268 269 270 271 272
            begin(1000), end(19000),
            begin(19000), end(29000),
            begin(29000), end(49000),
            build(1000, 17000),
            build(19000, 9000),
            build(29000, 19000),
273
          ]).summaryJson,
pq's avatar
pq committed
274
          <String, dynamic>{
275 276 277 278
            'average_frame_build_time_millis': 15.0,
            '90th_percentile_frame_build_time_millis': 19.0,
            '99th_percentile_frame_build_time_millis': 19.0,
            'worst_frame_build_time_millis': 19.0,
279
            'missed_frame_build_budget_count': 2,
280 281 282 283
            'average_frame_rasterizer_time_millis': 16.0,
            '90th_percentile_frame_rasterizer_time_millis': 20.0,
            '99th_percentile_frame_rasterizer_time_millis': 20.0,
            'worst_frame_rasterizer_time_millis': 20.0,
284
            'missed_frame_rasterizer_budget_count': 2,
285
            'frame_count': 3,
286 287
            'frame_build_times': <int>[17000, 9000, 19000],
            'frame_rasterizer_times': <int>[18000, 10000, 20000],
288
          },
289 290 291 292 293
        );
      });
    });

    group('writeTimelineToFile', () {
294 295 296

      Directory tempDir;

297 298
      setUp(() {
        useMemoryFileSystemForTesting();
299
        tempDir = fs.systemTempDirectory.createTempSync('flutter_driver_test.');
300 301 302
      });

      tearDown(() {
303
        tryToDelete(tempDir);
304 305 306 307
        restoreFileSystem();
      });

      test('writes timeline to JSON file', () async {
pq's avatar
pq committed
308
        await summarize(<Map<String, String>>[<String, String>{'foo': 'bar'}])
309
          .writeTimelineToFile('test', destinationDirectory: tempDir.path);
310
        final String written =
311
            await fs.file(path.join(tempDir.path, 'test.timeline.json')).readAsString();
312 313 314 315
        expect(written, '{"traceEvents":[{"foo":"bar"}]}');
      });

      test('writes summary to JSON file', () async {
pq's avatar
pq committed
316
        await summarize(<Map<String, dynamic>>[
317 318 319 320 321 322
          begin(1000), end(19000),
          begin(19000), end(29000),
          begin(29000), end(49000),
          build(1000, 17000),
          build(19000, 9000),
          build(29000, 19000),
323
        ]).writeSummaryToFile('test', destinationDirectory: tempDir.path);
324
        final String written =
325
            await fs.file(path.join(tempDir.path, 'test.timeline_summary.json')).readAsString();
326
        expect(json.decode(written), <String, dynamic>{
327 328 329 330
          'average_frame_build_time_millis': 15.0,
          'worst_frame_build_time_millis': 19.0,
          '90th_percentile_frame_build_time_millis': 19.0,
          '99th_percentile_frame_build_time_millis': 19.0,
331
          'missed_frame_build_budget_count': 2,
332 333 334 335
          'average_frame_rasterizer_time_millis': 16.0,
          '90th_percentile_frame_rasterizer_time_millis': 20.0,
          '99th_percentile_frame_rasterizer_time_millis': 20.0,
          'worst_frame_rasterizer_time_millis': 20.0,
336
          'missed_frame_rasterizer_budget_count': 2,
337
          'frame_count': 3,
338 339
          'frame_build_times': <int>[17000, 9000, 19000],
          'frame_rasterizer_times': <int>[18000, 10000, 20000],
340 341 342 343 344
        });
      });
    });
  });
}