Unverified Commit 4dd56df4 authored by Yegor's avatar Yegor Committed by GitHub

[web] add image decoder benchmark (#93174)

parent 0125b032
......@@ -36,7 +36,7 @@ class BenchDynamicClipOnStaticPicture extends SceneBuilderRecorder {
// If the scrollable extent is too small, the benchmark may end up
// scrolling the picture out of the clip area entirely, resulting in
// bogus metric values.
const double maxScrollExtent = kTotalSampleCount * kScrollDelta;
const double maxScrollExtent = kDefaultTotalSampleCount * kScrollDelta;
const double pictureHeight = kRows * kRowHeight;
if (maxScrollExtent > pictureHeight) {
throw Exception(
......
// 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 'dart:html' as html;
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'recorder.dart';
/// Measures the performance of image decoding.
///
/// The benchmark measures the decoding latency and not impact on jank. It
/// cannot distinguish between blocking and non-blocking decoding. It simply
/// measures the total time it takes to decode image frames. For example, the
/// WASM codecs execute on the main thread and block the UI, leading to jank,
/// but the browser's WebCodecs API is asynchronous running on a separate thread
/// and does not jank. However, the benchmark result may be the same.
///
/// This benchmark does not support the HTML renderer because the HTML renderer
/// cannot decode image frames (it always returns 1 dummy frame, even for
/// animated images).
class BenchImageDecoding extends RawRecorder {
BenchImageDecoding() : super(
name: benchmarkName,
useCustomWarmUp: true,
);
static const String benchmarkName = 'bench_image_decoding';
// These test images are taken from https://github.com/flutter/flutter_gallery_assets/tree/master/lib/splash_effects
static const List<String> _imageUrls = <String>[
'assets/packages/flutter_gallery_assets/splash_effects/splash_effect_1.gif',
'assets/packages/flutter_gallery_assets/splash_effects/splash_effect_2.gif',
'assets/packages/flutter_gallery_assets/splash_effects/splash_effect_3.gif',
];
final List<Uint8List> _imageData = <Uint8List>[];
@override
Future<void> setUpAll() async {
if (_imageData.isNotEmpty) {
return;
}
for (final String imageUrl in _imageUrls) {
final html.Body image = await html.window.fetch(imageUrl) as html.Body;
_imageData.add((await image.arrayBuffer() as ByteBuffer).asUint8List());
}
}
// The number of samples recorded so far.
int _sampleCount = 0;
// The number of samples used for warm-up.
static const int _warmUpSampleCount = 5;
// The number of samples used to measure performance after the warm-up.
static const int _measuredSampleCount = 20;
@override
Future<void> body(Profile profile) async {
await profile.recordAsync('recordImageDecode', () async {
final List<Future<void>> allDecodes = <Future<void>>[
for (final Uint8List data in _imageData)
_decodeImage(data),
];
await Future.wait(allDecodes);
}, reported: true);
_sampleCount += 1;
if (_sampleCount == _warmUpSampleCount) {
profile.stopWarmingUp();
}
if (_sampleCount >= _warmUpSampleCount + _measuredSampleCount) {
profile.stopBenchmark();
}
}
}
Future<void> _decodeImage(Uint8List data) async {
final ui.Codec codec = await ui.instantiateImageCodec(data);
const int decodeFrameCount = 5;
if (codec.frameCount < decodeFrameCount) {
throw Exception(
'Test image contains too few frames for this benchmark (${codec.frameCount}). '
'Choose a test image with at least $decodeFrameCount frames.'
);
}
for (int i = 0; i < decodeFrameCount; i++) {
(await codec.getNextFrame()).image.dispose();
}
codec.dispose();
}
......@@ -15,6 +15,7 @@ import 'src/web/bench_clipped_out_pictures.dart';
import 'src/web/bench_default_target_platform.dart';
import 'src/web/bench_draw_rect.dart';
import 'src/web/bench_dynamic_clip_on_static_picture.dart';
import 'src/web/bench_image_decoding.dart';
import 'src/web/bench_mouse_region_grid_hover.dart';
import 'src/web/bench_mouse_region_grid_scroll.dart';
import 'src/web/bench_mouse_region_mixed_grid_hover.dart';
......@@ -62,6 +63,11 @@ final Map<String, RecorderFactory> benchmarks = <String, RecorderFactory>{
BenchTextLayout.canvasKitBenchmarkName: () => BenchTextLayout.canvasKit(),
BenchBuildColorsGrid.canvasKitBenchmarkName: () => BenchBuildColorsGrid.canvasKit(),
BenchTextCachedLayout.canvasKitBenchmarkName: () => BenchTextCachedLayout.canvasKit(),
// The HTML renderer does not decode frame-by-frame. It just drops an <img>
// element and lets it animate automatically with no feedback to the
// framework. So this benchmark only makes sense in CanvasKit.
BenchImageDecoding.benchmarkName: () => BenchImageDecoding(),
},
// HTML-only benchmarks
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment