Skip to content

Commit

Permalink
Rename debugProfilePlatformChannels to a constant that works in rel…
Browse files Browse the repository at this point in the history
…ease mode (flutter#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 flutter#102189
  • Loading branch information
jiahaog authored and Mairramer committed Oct 10, 2023
1 parent 8b3eb36 commit fe8e40c
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 38 deletions.
14 changes: 1 addition & 13 deletions packages/flutter/lib/src/services/debug.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand All @@ -46,7 +34,7 @@ bool debugAssertAllServicesVarsUnset(String reason) {
if (debugKeyEventSimulatorTransitModeOverride != null) {
throw FlutterError(reason);
}
if (debugProfilePlatformChannels || debugPrintKeyboardEvents) {
if (debugPrintKeyboardEvents) {
throw FlutterError(reason);
}
return true;
Expand Down
56 changes: 31 additions & 25 deletions packages/flutter/lib/src/services/platform_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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));
Expand All @@ -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();
Expand All @@ -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();
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit fe8e40c

Please sign in to comment.