blob: 7e98bdd06e1ac73fee2324269d4b29585c3cffd6 [file] [log] [blame]
// Copyright 2013 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.
// @dart = 2.6
part of engine;
/// A function that receives a benchmark [value] labeleb by [name].
typedef OnBenchmark = void Function(String name, num value);
/// A function that computes a value of type [R].
///
/// Functions of this signature can be passed to [timeAction] for performance
/// profiling.
typedef Action<R> = R Function();
/// Uses the [Profiler] to time a synchronous [action] function and reports the
/// result under the give metric [name].
///
/// If profiling is disabled, simply calls [action] and returns the result.
///
/// Use this for situations when the cost of an extra closure is negligible.
/// This function reduces the boilerplate associated with checking if profiling
/// is enabled and exercising the stopwatch.
///
/// Example:
///
/// ```
/// final result = timeAction('expensive_operation', () {
/// ... expensive work ...
/// return someValue;
/// });
/// ```
R timeAction<R>(String name, Action<R> action) {
if (!Profiler.isBenchmarkMode) {
return action();
} else {
final Stopwatch stopwatch = Stopwatch()..start();
final R result = action();
stopwatch.stop();
Profiler.instance.benchmark(name, stopwatch.elapsedMicroseconds);
return result;
}
}
/// The purpose of this class is to facilitate communication of
/// profiling/benchmark data to the outside world (e.g. a macrobenchmark that's
/// running a flutter app).
///
/// To use the [Profiler]:
///
/// 1. Set the environment variable `FLUTTER_WEB_ENABLE_PROFILING` to true.
///
/// 2. Using JS interop, assign a listener function to
/// `window._flutter_internal_on_benchmark` in the browser.
///
/// The listener function will be called every time a new benchmark number is
/// calculated. The signature is `Function(String name, num value)`.
class Profiler {
Profiler._() {
_checkBenchmarkMode();
}
static bool isBenchmarkMode = const bool.fromEnvironment(
'FLUTTER_WEB_ENABLE_PROFILING',
defaultValue: false,
);
static Profiler ensureInitialized() {
_checkBenchmarkMode();
return Profiler._instance ??= Profiler._();
}
static Profiler get instance {
_checkBenchmarkMode();
if (_instance == null) {
throw Exception(
'Profiler has not been properly initialized. '
'Make sure Profiler.ensureInitialized() is being called before you '
'access Profiler.instance',
);
}
return _instance;
}
static Profiler _instance;
static void _checkBenchmarkMode() {
if (!isBenchmarkMode) {
throw Exception(
'Cannot use Profiler unless benchmark mode is enabled. '
'You can enable it by setting the `FLUTTER_WEB_ENABLE_PROFILING` '
'environment variable to true.',
);
}
}
/// Used to send benchmark data to whoever is listening to them.
void benchmark(String name, num value) {
_checkBenchmarkMode();
final OnBenchmark onBenchmark =
js_util.getProperty(html.window, '_flutter_internal_on_benchmark');
if (onBenchmark != null) {
onBenchmark(name, value);
}
}
}