diff --git a/packages/flutter_driver/lib/src/driver/gpu_sumarizer.dart b/packages/flutter_driver/lib/src/driver/gpu_sumarizer.dart new file mode 100644 index 00000000000..6364195cb19 --- /dev/null +++ b/packages/flutter_driver/lib/src/driver/gpu_sumarizer.dart @@ -0,0 +1,62 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'percentile_utils.dart'; +import 'timeline.dart'; + +/// Summarizes [GpuSumarizer]s corresponding to GPU start and end events. +class GpuSumarizer { + /// Creates a RasterCacheSummarizer given the timeline events. + GpuSumarizer(List gpuEvents) { + for (final TimelineEvent event in gpuEvents) { + final Object? value = event.arguments!['FrameTimeMS']; + if (value is String) { + final double? parsedValue = double.tryParse(value); + if (parsedValue != null) { + _frameTimes.add(parsedValue); + } + } + } + } + + /// Whether or not this event is a GPU event. + static const Set kGpuEvents = {'GPUTracer'}; + + final List _frameTimes = []; + + /// Computes the average GPU time recorded. + double computeAverageGPUTime() => _computeAverage(_frameTimes); + + /// The [percentile]-th percentile GPU time recorded. + double computePercentileGPUTime(double percentile) { + if (_frameTimes.isEmpty) { + return 0; + } + return findPercentile(_frameTimes, percentile); + } + + /// Compute the worst GPU time recorded. + double computeWorstGPUTime() => _computeWorst(_frameTimes); + + static double _computeAverage(List values) { + if (values.isEmpty) { + return 0; + } + + double total = 0; + for (final double data in values) { + total += data; + } + return total / values.length; + } + + static double _computeWorst(List values) { + if (values.isEmpty) { + return 0; + } + + values.sort(); + return values.last; + } +} diff --git a/packages/flutter_driver/lib/src/driver/timeline_summary.dart b/packages/flutter_driver/lib/src/driver/timeline_summary.dart index d79caeffd06..c32ae53e999 100644 --- a/packages/flutter_driver/lib/src/driver/timeline_summary.dart +++ b/packages/flutter_driver/lib/src/driver/timeline_summary.dart @@ -11,6 +11,7 @@ import 'package:path/path.dart' as path; import 'common.dart'; import 'frame_request_pending_latency_summarizer.dart'; import 'gc_summarizer.dart'; +import 'gpu_sumarizer.dart'; import 'percentile_utils.dart'; import 'profiling_summarizer.dart'; import 'raster_cache_summarizer.dart'; @@ -275,6 +276,7 @@ class TimelineSummary { final GCSummarizer gcSummarizer = _gcSummarizer(); final RefreshRateSummary refreshRateSummary = RefreshRateSummary(vsyncEvents: _extractNamedEvents(kUIThreadVsyncProcessEvent)); final FrameRequestPendingLatencySummarizer frameRequestPendingLatencySummarizer = _frameRequestPendingLatencySummarizer(); + final GpuSumarizer gpuSummarizer = _gpuSumarizer(); final Map timelineSummary = { 'average_frame_build_time_millis': computeAverageFrameBuildTimeMillis(), @@ -336,6 +338,10 @@ class TimelineSummary { '90hz_frame_percentage': refreshRateSummary.percentageOf90HzFrames, '120hz_frame_percentage': refreshRateSummary.percentageOf120HzFrames, 'illegal_refresh_rate_frame_count': refreshRateSummary.framesWithIllegalRefreshRate.length, + 'average_gpu_frame_time': gpuSummarizer.computeAverageGPUTime(), + '90th_percentile_gpu_frame_time': gpuSummarizer.computePercentileGPUTime(90.0), + '99th_percentile_gpu_frame_time': gpuSummarizer.computePercentileGPUTime(99.0), + 'worst_gpu_frame_time': gpuSummarizer.computeWorstGPUTime(), }; timelineSummary.addAll(profilingSummary); @@ -507,4 +513,6 @@ class TimelineSummary { FrameRequestPendingLatencySummarizer _frameRequestPendingLatencySummarizer() => FrameRequestPendingLatencySummarizer(_extractNamedEvents(kFrameRequestPendingEvent)); GCSummarizer _gcSummarizer() => GCSummarizer.fromEvents(_extractEventsWithNames(kGCRootEvents)); + + GpuSumarizer _gpuSumarizer() => GpuSumarizer(_extractEventsWithNames(GpuSumarizer.kGpuEvents)); } diff --git a/packages/flutter_driver/test/src/gpu_summarizer_test.dart b/packages/flutter_driver/test/src/gpu_summarizer_test.dart new file mode 100644 index 00000000000..71fbb0f9357 --- /dev/null +++ b/packages/flutter_driver/test/src/gpu_summarizer_test.dart @@ -0,0 +1,31 @@ +// Copyright 2014 The Flutter Authors. 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:flutter_driver/flutter_driver.dart'; +import 'package:flutter_driver/src/driver/gpu_sumarizer.dart'; + +import '../common.dart'; + +TimelineEvent newGPUTraceEvent(double ms) => TimelineEvent({ + 'name': 'GPUStart', + 'ph': 'b', + 'args': { + 'FrameTimeMS': ms.toString() + }, +}); + +void main() { + test('Can process GPU frame times.', () { + final GpuSumarizer summarizer = GpuSumarizer([ + newGPUTraceEvent(4.233), + newGPUTraceEvent(7.22), + newGPUTraceEvent(9.1), + newGPUTraceEvent(40.23), + ]); + + expect(summarizer.computeAverageGPUTime(), closeTo(15.19, 0.1)); + expect(summarizer.computePercentileGPUTime(50.0), closeTo(9.1, 0.1)); + expect(summarizer.computeWorstGPUTime(), 40.23); + }); +} diff --git a/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart b/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart index 2e6c70a064f..dd94a46b46f 100644 --- a/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart +++ b/packages/flutter_driver/test/src/real_tests/timeline_summary_test.dart @@ -528,6 +528,10 @@ void main() { 'average_frame_request_pending_latency': 2000.0, '90th_percentile_frame_request_pending_latency': 3000.0, '99th_percentile_frame_request_pending_latency': 3000.0, + 'average_gpu_frame_time': 0, + '90th_percentile_gpu_frame_time': 0, + '99th_percentile_gpu_frame_time': 0, + 'worst_gpu_frame_time': 0, }, ); }); @@ -659,6 +663,10 @@ void main() { 'average_frame_request_pending_latency': 2000.0, '90th_percentile_frame_request_pending_latency': 3000.0, '99th_percentile_frame_request_pending_latency': 3000.0, + 'average_gpu_frame_time': 0, + '90th_percentile_gpu_frame_time': 0, + '99th_percentile_gpu_frame_time': 0, + 'worst_gpu_frame_time': 0, }); }); });