Unverified Commit f92884c7 authored by Jia Hao's avatar Jia Hao Committed by GitHub

Rename `debugProfilePlatformChannels` to a constant that works in release mode (#134922)

When it comes to startup profiling, it is very helpful to look at platform channels. `debugProfilePlatformChannels` today only works in debug and profile mode. Unfortunately, using profile mode is less accurate for startup profiling, because of the service isolate introducing additional overhead.

This PR allows this toggle to work in release mode. Note that there are two parts to `debugProfilePlatformChannels`:

- Adding timeline events
- Logging statistics about platform channels

I also considered adding a separate toggle to limit the scope of this change to the former, but that seems like complexity that we might not need at this time.

Towards #102189
parent a0406ccc
...@@ -15,18 +15,6 @@ export 'hardware_keyboard.dart' show KeyDataTransitMode; ...@@ -15,18 +15,6 @@ export 'hardware_keyboard.dart' show KeyDataTransitMode;
/// of their extent of support for keyboard API. /// of their extent of support for keyboard API.
KeyDataTransitMode? debugKeyEventSimulatorTransitModeOverride; KeyDataTransitMode? debugKeyEventSimulatorTransitModeOverride;
/// Profile and print statistics on Platform Channel usage.
///
/// When this is true statistics about the usage of Platform Channels will be
/// printed out periodically to the console and Timeline events will show the
/// time between sending and receiving a message (encoding and decoding time
/// excluded).
///
/// The statistics include the total bytes transmitted and the average number of
/// bytes per invocation in the last quantum. "Up" means in the direction of
/// Flutter to the host platform, "down" is the host platform to flutter.
bool debugProfilePlatformChannels = false;
/// Setting to true will cause extensive logging to occur when key events are /// Setting to true will cause extensive logging to occur when key events are
/// received. /// received.
/// ///
...@@ -46,7 +34,7 @@ bool debugAssertAllServicesVarsUnset(String reason) { ...@@ -46,7 +34,7 @@ bool debugAssertAllServicesVarsUnset(String reason) {
if (debugKeyEventSimulatorTransitModeOverride != null) { if (debugKeyEventSimulatorTransitModeOverride != null) {
throw FlutterError(reason); throw FlutterError(reason);
} }
if (debugProfilePlatformChannels || debugPrintKeyboardEvents) { if (debugPrintKeyboardEvents) {
throw FlutterError(reason); throw FlutterError(reason);
} }
return true; return true;
......
...@@ -12,7 +12,6 @@ import '_background_isolate_binary_messenger_io.dart' ...@@ -12,7 +12,6 @@ import '_background_isolate_binary_messenger_io.dart'
import 'binary_messenger.dart'; import 'binary_messenger.dart';
import 'binding.dart'; import 'binding.dart';
import 'debug.dart' show debugProfilePlatformChannels;
import 'message_codec.dart'; import 'message_codec.dart';
import 'message_codecs.dart'; import 'message_codecs.dart';
...@@ -23,9 +22,21 @@ export 'binary_messenger.dart' show BinaryMessenger; ...@@ -23,9 +22,21 @@ export 'binary_messenger.dart' show BinaryMessenger;
export 'binding.dart' show RootIsolateToken; export 'binding.dart' show RootIsolateToken;
export 'message_codec.dart' show MessageCodec, MethodCall, MethodCodec; export 'message_codec.dart' show MessageCodec, MethodCall, MethodCodec;
bool _debugProfilePlatformChannelsIsRunning = false; /// Profile and print statistics on Platform Channel usage.
const Duration _debugProfilePlatformChannelsRate = Duration(seconds: 1); ///
final Expando<BinaryMessenger> _debugBinaryMessengers = Expando<BinaryMessenger>(); /// When this is true statistics about the usage of Platform Channels will be
/// printed out periodically to the console and Timeline events will show the
/// time between sending and receiving a message (encoding and decoding time
/// excluded).
///
/// The statistics include the total bytes transmitted and the average number of
/// bytes per invocation in the last quantum. "Up" means in the direction of
/// Flutter to the host platform, "down" is the host platform to flutter.
const bool kProfilePlatformChannels = false;
bool _profilePlatformChannelsIsRunning = false;
const Duration _profilePlatformChannelsRate = Duration(seconds: 1);
final Expando<BinaryMessenger> _profiledBinaryMessengers = Expando<BinaryMessenger>();
class _ProfiledBinaryMessenger implements BinaryMessenger { class _ProfiledBinaryMessenger implements BinaryMessenger {
const _ProfiledBinaryMessenger(this.proxy, this.channelTypeName, this.codecTypeName); const _ProfiledBinaryMessenger(this.proxy, this.channelTypeName, this.codecTypeName);
...@@ -40,17 +51,12 @@ class _ProfiledBinaryMessenger implements BinaryMessenger { ...@@ -40,17 +51,12 @@ class _ProfiledBinaryMessenger implements BinaryMessenger {
Future<ByteData?>? sendWithPostfix(String channel, String postfix, ByteData? message) async { Future<ByteData?>? sendWithPostfix(String channel, String postfix, ByteData? message) async {
_debugRecordUpStream(channelTypeName, '$channel$postfix', codecTypeName, message); _debugRecordUpStream(channelTypeName, '$channel$postfix', codecTypeName, message);
TimelineTask? debugTimelineTask; final TimelineTask timelineTask = TimelineTask()..start('Platform Channel send $channel$postfix');
if (!kReleaseMode) {
debugTimelineTask = TimelineTask()..start('Platform Channel send $channel$postfix');
}
final ByteData? result; final ByteData? result;
try { try {
result = await proxy.send(channel, message); result = await proxy.send(channel, message);
} finally { } finally {
if (!kReleaseMode) { timelineTask.finish();
debugTimelineTask!.finish();
}
} }
_debugRecordDownStream(channelTypeName, '$channel$postfix', codecTypeName, result); _debugRecordDownStream(channelTypeName, '$channel$postfix', codecTypeName, result);
return result; return result;
...@@ -93,17 +99,17 @@ class _PlatformChannelStats { ...@@ -93,17 +99,17 @@ class _PlatformChannelStats {
double get averageDownPayload => _downBytes / _downCount; double get averageDownPayload => _downBytes / _downCount;
} }
final Map<String, _PlatformChannelStats> _debugProfilePlatformChannelsStats = <String, _PlatformChannelStats>{}; final Map<String, _PlatformChannelStats> _profilePlatformChannelsStats = <String, _PlatformChannelStats>{};
Future<void> _debugLaunchProfilePlatformChannels() async { Future<void> _debugLaunchProfilePlatformChannels() async {
if (!_debugProfilePlatformChannelsIsRunning) { if (!_profilePlatformChannelsIsRunning) {
_debugProfilePlatformChannelsIsRunning = true; _profilePlatformChannelsIsRunning = true;
await Future<dynamic>.delayed(_debugProfilePlatformChannelsRate); await Future<dynamic>.delayed(_profilePlatformChannelsRate);
_debugProfilePlatformChannelsIsRunning = false; _profilePlatformChannelsIsRunning = false;
final StringBuffer log = StringBuffer(); final StringBuffer log = StringBuffer();
log.writeln('Platform Channel Stats:'); log.writeln('Platform Channel Stats:');
final List<_PlatformChannelStats> allStats = final List<_PlatformChannelStats> allStats =
_debugProfilePlatformChannelsStats.values.toList(); _profilePlatformChannelsStats.values.toList();
// Sort highest combined bandwidth first. // Sort highest combined bandwidth first.
allStats.sort((_PlatformChannelStats x, _PlatformChannelStats y) => allStats.sort((_PlatformChannelStats x, _PlatformChannelStats y) =>
(y.upBytes + y.downBytes) - (x.upBytes + x.downBytes)); (y.upBytes + y.downBytes) - (x.upBytes + x.downBytes));
...@@ -112,14 +118,14 @@ Future<void> _debugLaunchProfilePlatformChannels() async { ...@@ -112,14 +118,14 @@ Future<void> _debugLaunchProfilePlatformChannels() async {
' (name:"${stats.channel}" type:"${stats.type}" codec:"${stats.codec}" upBytes:${stats.upBytes} upBytes_avg:${stats.averageUpPayload.toStringAsFixed(1)} downBytes:${stats.downBytes} downBytes_avg:${stats.averageDownPayload.toStringAsFixed(1)})'); ' (name:"${stats.channel}" type:"${stats.type}" codec:"${stats.codec}" upBytes:${stats.upBytes} upBytes_avg:${stats.averageUpPayload.toStringAsFixed(1)} downBytes:${stats.downBytes} downBytes_avg:${stats.averageDownPayload.toStringAsFixed(1)})');
} }
debugPrint(log.toString()); debugPrint(log.toString());
_debugProfilePlatformChannelsStats.clear(); _profilePlatformChannelsStats.clear();
} }
} }
void _debugRecordUpStream(String channelTypeName, String name, void _debugRecordUpStream(String channelTypeName, String name,
String codecTypeName, ByteData? bytes) { String codecTypeName, ByteData? bytes) {
final _PlatformChannelStats stats = final _PlatformChannelStats stats =
_debugProfilePlatformChannelsStats[name] ??= _profilePlatformChannelsStats[name] ??=
_PlatformChannelStats(name, codecTypeName, channelTypeName); _PlatformChannelStats(name, codecTypeName, channelTypeName);
stats.addUpStream(bytes?.lengthInBytes ?? 0); stats.addUpStream(bytes?.lengthInBytes ?? 0);
_debugLaunchProfilePlatformChannels(); _debugLaunchProfilePlatformChannels();
...@@ -128,7 +134,7 @@ void _debugRecordUpStream(String channelTypeName, String name, ...@@ -128,7 +134,7 @@ void _debugRecordUpStream(String channelTypeName, String name,
void _debugRecordDownStream(String channelTypeName, String name, void _debugRecordDownStream(String channelTypeName, String name,
String codecTypeName, ByteData? bytes) { String codecTypeName, ByteData? bytes) {
final _PlatformChannelStats stats = final _PlatformChannelStats stats =
_debugProfilePlatformChannelsStats[name] ??= _profilePlatformChannelsStats[name] ??=
_PlatformChannelStats(name, codecTypeName, channelTypeName); _PlatformChannelStats(name, codecTypeName, channelTypeName);
stats.addDownStream(bytes?.lengthInBytes ?? 0); stats.addDownStream(bytes?.lengthInBytes ?? 0);
_debugLaunchProfilePlatformChannels(); _debugLaunchProfilePlatformChannels();
...@@ -184,8 +190,8 @@ class BasicMessageChannel<T> { ...@@ -184,8 +190,8 @@ class BasicMessageChannel<T> {
/// [BackgroundIsolateBinaryMessenger.ensureInitialized]. /// [BackgroundIsolateBinaryMessenger.ensureInitialized].
BinaryMessenger get binaryMessenger { BinaryMessenger get binaryMessenger {
final BinaryMessenger result = _binaryMessenger ?? _findBinaryMessenger(); final BinaryMessenger result = _binaryMessenger ?? _findBinaryMessenger();
return !kReleaseMode && debugProfilePlatformChannels return kProfilePlatformChannels
? _debugBinaryMessengers[this] ??= _ProfiledBinaryMessenger( ? _profiledBinaryMessengers[this] ??= _ProfiledBinaryMessenger(
// ignore: no_runtimetype_tostring // ignore: no_runtimetype_tostring
result, runtimeType.toString(), codec.runtimeType.toString()) result, runtimeType.toString(), codec.runtimeType.toString())
: result; : result;
...@@ -273,8 +279,8 @@ class MethodChannel { ...@@ -273,8 +279,8 @@ class MethodChannel {
/// [BackgroundIsolateBinaryMessenger.ensureInitialized]. /// [BackgroundIsolateBinaryMessenger.ensureInitialized].
BinaryMessenger get binaryMessenger { BinaryMessenger get binaryMessenger {
final BinaryMessenger result = _binaryMessenger ?? _findBinaryMessenger(); final BinaryMessenger result = _binaryMessenger ?? _findBinaryMessenger();
return !kReleaseMode && debugProfilePlatformChannels return kProfilePlatformChannels
? _debugBinaryMessengers[this] ??= _ProfiledBinaryMessenger( ? _profiledBinaryMessengers[this] ??= _ProfiledBinaryMessenger(
// ignore: no_runtimetype_tostring // ignore: no_runtimetype_tostring
result, runtimeType.toString(), codec.runtimeType.toString()) result, runtimeType.toString(), codec.runtimeType.toString())
: result; : result;
...@@ -304,7 +310,7 @@ class MethodChannel { ...@@ -304,7 +310,7 @@ class MethodChannel {
Future<T?> _invokeMethod<T>(String method, { required bool missingOk, dynamic arguments }) async { Future<T?> _invokeMethod<T>(String method, { required bool missingOk, dynamic arguments }) async {
final ByteData input = codec.encodeMethodCall(MethodCall(method, arguments)); final ByteData input = codec.encodeMethodCall(MethodCall(method, arguments));
final ByteData? result = final ByteData? result =
!kReleaseMode && debugProfilePlatformChannels ? kProfilePlatformChannels ?
await (binaryMessenger as _ProfiledBinaryMessenger).sendWithPostfix(name, '#$method', input) : await (binaryMessenger as _ProfiledBinaryMessenger).sendWithPostfix(name, '#$method', input) :
await binaryMessenger.send(name, input); await binaryMessenger.send(name, input);
if (result == null) { if (result == null) {
......
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