From 2ebd7f0d55225ba79f145470f03e86069a7dfb00 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 6 Mar 2024 12:17:31 -0800 Subject: [PATCH] [Impeller] measure GPU memory usage. (#144575) Framework side to https://github.com/flutter/engine/pull/51187 Part of https://github.com/flutter/flutter/issues/144617 --- dev/devicelab/lib/tasks/perf_tests.dart | 6 ++ .../lib/src/driver/memory_summarizer.dart | 62 +++++++++++++++++++ .../lib/src/driver/timeline_summary.dart | 8 +++ .../test/src/gpu_memory_summarizer_test.dart | 31 ++++++++++ .../src/real_tests/timeline_summary_test.dart | 8 +++ 5 files changed, 115 insertions(+) create mode 100644 packages/flutter_driver/lib/src/driver/memory_summarizer.dart create mode 100644 packages/flutter_driver/test/src/gpu_memory_summarizer_test.dart diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 96b90ef0936..3257a006647 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -1451,10 +1451,16 @@ class PerfTest { if (data['120hz_frame_percentage'] != null) '120hz_frame_percentage', if (data['illegal_refresh_rate_frame_count'] != null) 'illegal_refresh_rate_frame_count', if (recordGPU) ...[ + // GPU Frame Time. if (data['average_gpu_frame_time'] != null) 'average_gpu_frame_time', if (data['90th_percentile_gpu_frame_time'] != null) '90th_percentile_gpu_frame_time', if (data['99th_percentile_gpu_frame_time'] != null) '99th_percentile_gpu_frame_time', if (data['worst_gpu_frame_time'] != null) 'worst_gpu_frame_time', + // GPU Memory. + if (data['average_gpu_memory_mb'] != null) 'average_gpu_memory_mb', + if (data['90th_percentile_gpu_memory_mb'] != null) '90th_percentile_gpu_memory_mb', + if (data['99th_percentile_gpu_memory_mb'] != null) '99th_percentile_gpu_memory_mb', + if (data['worst_gpu_memory_mb'] != null) 'worst_gpu_memory_mb', ] ], ); diff --git a/packages/flutter_driver/lib/src/driver/memory_summarizer.dart b/packages/flutter_driver/lib/src/driver/memory_summarizer.dart new file mode 100644 index 00000000000..20fb9e40baa --- /dev/null +++ b/packages/flutter_driver/lib/src/driver/memory_summarizer.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 GPU/Device Memory allocations performed by Impeller. +class GPUMemorySumarizer { + /// Creates a RasterCacheSummarizer given the timeline events. + GPUMemorySumarizer(List gpuEvents) { + for (final TimelineEvent event in gpuEvents) { + final Object? value = event.arguments!['MemoryBudgetUsageMB']; + if (value is String) { + final double? parsedValue = double.tryParse(value); + if (parsedValue != null) { + _memoryMB.add(parsedValue); + } + } + } + } + + /// Whether or not this event is a GPU allocation event. + static const Set kMemoryEvents = {'AllocatorVK'}; + + final List _memoryMB = []; + + /// Computes the average GPU memory allocated. + double computeAverageMemoryUsage() => _computeAverage(_memoryMB); + + /// The [percentile]-th percentile GPU memory allocated. + double computePercentileMemoryUsage(double percentile) { + if (_memoryMB.isEmpty) { + return 0; + } + return findPercentile(_memoryMB, percentile); + } + + /// Compute the worst allocation quantity recorded. + double computeWorstMemoryUsage() => _computeWorst(_memoryMB); + + 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 53883c740d8..dc8220b5df5 100644 --- a/packages/flutter_driver/lib/src/driver/timeline_summary.dart +++ b/packages/flutter_driver/lib/src/driver/timeline_summary.dart @@ -12,6 +12,7 @@ import 'common.dart'; import 'frame_request_pending_latency_summarizer.dart'; import 'gc_summarizer.dart'; import 'gpu_sumarizer.dart'; +import 'memory_summarizer.dart'; import 'percentile_utils.dart'; import 'profiling_summarizer.dart'; import 'raster_cache_summarizer.dart'; @@ -277,6 +278,7 @@ class TimelineSummary { final RefreshRateSummary refreshRateSummary = RefreshRateSummary(vsyncEvents: _extractNamedEvents(kUIThreadVsyncProcessEvent)); final FrameRequestPendingLatencySummarizer frameRequestPendingLatencySummarizer = _frameRequestPendingLatencySummarizer(); final GpuSumarizer gpuSummarizer = _gpuSumarizer(); + final GPUMemorySumarizer memorySumarizer = _memorySummarizer(); final Map timelineSummary = { 'average_frame_build_time_millis': computeAverageFrameBuildTimeMillis(), @@ -342,6 +344,10 @@ class TimelineSummary { '90th_percentile_gpu_frame_time': gpuSummarizer.computePercentileGPUTime(90.0), '99th_percentile_gpu_frame_time': gpuSummarizer.computePercentileGPUTime(99.0), 'worst_gpu_frame_time': gpuSummarizer.computeWorstGPUTime(), + 'average_gpu_memory_mb': memorySumarizer.computeAverageMemoryUsage(), + '90th_percentile_gpu_memory_mb': memorySumarizer.computePercentileMemoryUsage(90.0), + '99th_percentile_gpu_memory_mb': memorySumarizer.computePercentileMemoryUsage(99.0), + 'worst_gpu_memory_mb': memorySumarizer.computeWorstMemoryUsage(), }; timelineSummary.addAll(profilingSummary); @@ -501,4 +507,6 @@ class TimelineSummary { GCSummarizer _gcSummarizer() => GCSummarizer.fromEvents(_extractEventsWithNames(kGCRootEvents)); GpuSumarizer _gpuSumarizer() => GpuSumarizer(_extractEventsWithNames(GpuSumarizer.kGpuEvents)); + + GPUMemorySumarizer _memorySummarizer() => GPUMemorySumarizer(_extractEventsWithNames(GPUMemorySumarizer.kMemoryEvents)); } diff --git a/packages/flutter_driver/test/src/gpu_memory_summarizer_test.dart b/packages/flutter_driver/test/src/gpu_memory_summarizer_test.dart new file mode 100644 index 00000000000..0dc4220bdee --- /dev/null +++ b/packages/flutter_driver/test/src/gpu_memory_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/memory_summarizer.dart'; + +import '../common.dart'; + +TimelineEvent newGPUTraceEvent(double ms) => TimelineEvent({ + 'name': 'AllocatorVK', + 'ph': 'b', + 'args': { + 'MemoryBudgetUsageMB': ms.toString() + }, +}); + +void main() { + test('Can process GPU memory usage times.', () { + final GPUMemorySumarizer summarizer = GPUMemorySumarizer([ + newGPUTraceEvent(1024), + newGPUTraceEvent(1024), + newGPUTraceEvent(512), + newGPUTraceEvent(2048), + ]); + + expect(summarizer.computeAverageMemoryUsage(), closeTo(1152, 0.1)); + expect(summarizer.computePercentileMemoryUsage(50.0), closeTo(1024, 0.1)); + expect(summarizer.computeWorstMemoryUsage(), 2048); + }); +} 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 dd94a46b46f..8b3151bc42f 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 @@ -532,6 +532,10 @@ void main() { '90th_percentile_gpu_frame_time': 0, '99th_percentile_gpu_frame_time': 0, 'worst_gpu_frame_time': 0, + 'average_gpu_memory_mb': 0, + '90th_percentile_gpu_memory_mb': 0, + '99th_percentile_gpu_memory_mb': 0, + 'worst_gpu_memory_mb': 0, }, ); }); @@ -667,6 +671,10 @@ void main() { '90th_percentile_gpu_frame_time': 0, '99th_percentile_gpu_frame_time': 0, 'worst_gpu_frame_time': 0, + 'average_gpu_memory_mb': 0, + '90th_percentile_gpu_memory_mb': 0, + '99th_percentile_gpu_memory_mb': 0, + 'worst_gpu_memory_mb': 0, }); }); });