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
This commit is contained in:
Jia Hao 2023-09-21 00:20:09 +00:00 committed by GitHub
parent a0406cccb1
commit f92884c7b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 38 deletions

View file

@ -15,18 +15,6 @@ export 'hardware_keyboard.dart' show KeyDataTransitMode;
/// of their extent of support for keyboard API.
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
/// received.
///
@ -46,7 +34,7 @@ bool debugAssertAllServicesVarsUnset(String reason) {
if (debugKeyEventSimulatorTransitModeOverride != null) {
throw FlutterError(reason);
}
if (debugProfilePlatformChannels || debugPrintKeyboardEvents) {
if (debugPrintKeyboardEvents) {
throw FlutterError(reason);
}
return true;

View file

@ -12,7 +12,6 @@ import '_background_isolate_binary_messenger_io.dart'
import 'binary_messenger.dart';
import 'binding.dart';
import 'debug.dart' show debugProfilePlatformChannels;
import 'message_codec.dart';
import 'message_codecs.dart';
@ -23,9 +22,21 @@ export 'binary_messenger.dart' show BinaryMessenger;
export 'binding.dart' show RootIsolateToken;
export 'message_codec.dart' show MessageCodec, MethodCall, MethodCodec;
bool _debugProfilePlatformChannelsIsRunning = false;
const Duration _debugProfilePlatformChannelsRate = Duration(seconds: 1);
final Expando<BinaryMessenger> _debugBinaryMessengers = Expando<BinaryMessenger>();
/// 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.
const bool kProfilePlatformChannels = false;
bool _profilePlatformChannelsIsRunning = false;
const Duration _profilePlatformChannelsRate = Duration(seconds: 1);
final Expando<BinaryMessenger> _profiledBinaryMessengers = Expando<BinaryMessenger>();
class _ProfiledBinaryMessenger implements BinaryMessenger {
const _ProfiledBinaryMessenger(this.proxy, this.channelTypeName, this.codecTypeName);
@ -40,17 +51,12 @@ class _ProfiledBinaryMessenger implements BinaryMessenger {
Future<ByteData?>? sendWithPostfix(String channel, String postfix, ByteData? message) async {
_debugRecordUpStream(channelTypeName, '$channel$postfix', codecTypeName, message);
TimelineTask? debugTimelineTask;
if (!kReleaseMode) {
debugTimelineTask = TimelineTask()..start('Platform Channel send $channel$postfix');
}
final TimelineTask timelineTask = TimelineTask()..start('Platform Channel send $channel$postfix');
final ByteData? result;
try {
result = await proxy.send(channel, message);
} finally {
if (!kReleaseMode) {
debugTimelineTask!.finish();
}
timelineTask.finish();
}
_debugRecordDownStream(channelTypeName, '$channel$postfix', codecTypeName, result);
return result;
@ -93,17 +99,17 @@ class _PlatformChannelStats {
double get averageDownPayload => _downBytes / _downCount;
}
final Map<String, _PlatformChannelStats> _debugProfilePlatformChannelsStats = <String, _PlatformChannelStats>{};
final Map<String, _PlatformChannelStats> _profilePlatformChannelsStats = <String, _PlatformChannelStats>{};
Future<void> _debugLaunchProfilePlatformChannels() async {
if (!_debugProfilePlatformChannelsIsRunning) {
_debugProfilePlatformChannelsIsRunning = true;
await Future<dynamic>.delayed(_debugProfilePlatformChannelsRate);
_debugProfilePlatformChannelsIsRunning = false;
if (!_profilePlatformChannelsIsRunning) {
_profilePlatformChannelsIsRunning = true;
await Future<dynamic>.delayed(_profilePlatformChannelsRate);
_profilePlatformChannelsIsRunning = false;
final StringBuffer log = StringBuffer();
log.writeln('Platform Channel Stats:');
final List<_PlatformChannelStats> allStats =
_debugProfilePlatformChannelsStats.values.toList();
_profilePlatformChannelsStats.values.toList();
// Sort highest combined bandwidth first.
allStats.sort((_PlatformChannelStats x, _PlatformChannelStats y) =>
(y.upBytes + y.downBytes) - (x.upBytes + x.downBytes));
@ -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)})');
}
debugPrint(log.toString());
_debugProfilePlatformChannelsStats.clear();
_profilePlatformChannelsStats.clear();
}
}
void _debugRecordUpStream(String channelTypeName, String name,
String codecTypeName, ByteData? bytes) {
final _PlatformChannelStats stats =
_debugProfilePlatformChannelsStats[name] ??=
_profilePlatformChannelsStats[name] ??=
_PlatformChannelStats(name, codecTypeName, channelTypeName);
stats.addUpStream(bytes?.lengthInBytes ?? 0);
_debugLaunchProfilePlatformChannels();
@ -128,7 +134,7 @@ void _debugRecordUpStream(String channelTypeName, String name,
void _debugRecordDownStream(String channelTypeName, String name,
String codecTypeName, ByteData? bytes) {
final _PlatformChannelStats stats =
_debugProfilePlatformChannelsStats[name] ??=
_profilePlatformChannelsStats[name] ??=
_PlatformChannelStats(name, codecTypeName, channelTypeName);
stats.addDownStream(bytes?.lengthInBytes ?? 0);
_debugLaunchProfilePlatformChannels();
@ -184,8 +190,8 @@ class BasicMessageChannel<T> {
/// [BackgroundIsolateBinaryMessenger.ensureInitialized].
BinaryMessenger get binaryMessenger {
final BinaryMessenger result = _binaryMessenger ?? _findBinaryMessenger();
return !kReleaseMode && debugProfilePlatformChannels
? _debugBinaryMessengers[this] ??= _ProfiledBinaryMessenger(
return kProfilePlatformChannels
? _profiledBinaryMessengers[this] ??= _ProfiledBinaryMessenger(
// ignore: no_runtimetype_tostring
result, runtimeType.toString(), codec.runtimeType.toString())
: result;
@ -273,8 +279,8 @@ class MethodChannel {
/// [BackgroundIsolateBinaryMessenger.ensureInitialized].
BinaryMessenger get binaryMessenger {
final BinaryMessenger result = _binaryMessenger ?? _findBinaryMessenger();
return !kReleaseMode && debugProfilePlatformChannels
? _debugBinaryMessengers[this] ??= _ProfiledBinaryMessenger(
return kProfilePlatformChannels
? _profiledBinaryMessengers[this] ??= _ProfiledBinaryMessenger(
// ignore: no_runtimetype_tostring
result, runtimeType.toString(), codec.runtimeType.toString())
: result;
@ -304,7 +310,7 @@ class MethodChannel {
Future<T?> _invokeMethod<T>(String method, { required bool missingOk, dynamic arguments }) async {
final ByteData input = codec.encodeMethodCall(MethodCall(method, arguments));
final ByteData? result =
!kReleaseMode && debugProfilePlatformChannels ?
kProfilePlatformChannels ?
await (binaryMessenger as _ProfiledBinaryMessenger).sendWithPostfix(name, '#$method', input) :
await binaryMessenger.send(name, input);
if (result == null) {