Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strip out debug fields to reduce memory footprint #22915

Closed
goderbauer opened this issue Oct 10, 2018 · 11 comments
Closed

Strip out debug fields to reduce memory footprint #22915

goderbauer opened this issue Oct 10, 2018 · 11 comments
Labels
c: performance Relates to speed or footprint issues (see "perf:" labels) c: proposal A detailed proposal for a change to Flutter dependency: dart Dart team may need to help us framework flutter/packages/flutter repository. See also f: labels. P3 Issues that are less important to the Flutter project perf: memory Performance issues related to memory platform-android Android applications specifically platform-ios iOS applications specifically

Comments

@goderbauer
Copy link
Member

The Flutter framework defines many debug* fields that are only used during debug builds. They are still present in release builds, but mostly unused there. While they don't take up any significant space in the snapshot (8B for hello_world, 6.4KB for flutter_gallery) they may significantly increase our memory footprint when the app runs on device.

We should measure what the impact on memory usage is and if it is significant strip those fields out in debug mode - either with a kernel transformer or by extending Dart's treeshakeing-algorithm to remove those unused fields.

/cc @jacob314

@goderbauer goderbauer added platform-android Android applications specifically platform-ios iOS applications specifically framework flutter/packages/flutter repository. See also f: labels. dependency: dart Dart team may need to help us labels Oct 10, 2018
@jmagman jmagman added this to Awaiting triage in Mobile Platforms - Android publication/release review via automation Mar 5, 2020
@jmagman jmagman added this to Awaiting triage in Mobile - app publication/release review via automation Mar 5, 2020
@jmagman jmagman moved this from Awaiting triage to Engineer reviewed in Mobile - app publication/release review Mar 13, 2020
@liyuqian liyuqian added perf: memory Performance issues related to memory c: performance Relates to speed or footprint issues (see "perf:" labels) labels Mar 28, 2020
@iapicca iapicca added passed first triage c: proposal A detailed proposal for a change to Flutter labels Jul 27, 2020
@kf6gpe kf6gpe added the P3 Issues that are less important to the Flutter project label Nov 9, 2020
@xster

This comment has been minimized.

@xster xster closed this as completed Dec 16, 2020
@mraleph
Copy link
Member

mraleph commented Dec 17, 2020

@xster split-debug-info is for splitting debug information like information used to format stack traces. This bug was about shaking away debug only fields. FWIW @alexmarkov has implemented an optimization that shakes fields which are never read (even if they are written to) - and we know that it shakes away debug only fields in widget hierarchy.

@xster xster reopened this Dec 17, 2020
Mobile - app publication/release review automation moved this from Engineer reviewed to Awaiting triage Dec 17, 2020
@xster
Copy link
Member

xster commented Dec 17, 2020

ah I misunderstood. These are for the actual Dart functions in the framework implementation like debugFillProperties, debugPaintSize etc.

Sorry, I totally misunderstood the OP.

@a-siva
Copy link
Contributor

a-siva commented Jun 15, 2021

/cc @alexmarkov

@alexmarkov
Copy link
Contributor

Indeed, Dart AOT compiler can tree shake fields if they are never read.

In order to verify how well this optimization works for Flutter debug fields, I looked at debug fields retained on Flutter Gallery (https://github.com/flutter/gallery @ flutter/gallery@c858388), flutter @ 6cb4357.

The following simple program dumps all fields which start with debug or _debug in the kernel file:

import 'dart:io';

import 'package:kernel/ast.dart';
import 'package:kernel/binary/ast_from_binary.dart' show BinaryBuilder;

class ListDebugFields extends RecursiveVisitor {
  @override
  visitField(Field node) {
    if (node.name.text.startsWith('debug') ||
        node.name.text.startsWith('_debug')) {
      final cls = node.enclosingClass;
      if (cls != null) {
        print('${cls.name}.${node.name.text}');
      } else {
        print('${node.enclosingLibrary.importUri} :: ${node.name.text}');
      }
    }
  }
}

main(List<String> args) async {
  final component = new Component();
  final List<int> bytes = new File(args[0]).readAsBytesSync();
  new BinaryBuilder(bytes).readComponent(component);

  ListDebugFields().visitComponent(component);
}

In debug mode, Flutter Gallery app.dill contains 230 debug fields.
In release mode, tree-shaken Flutter Gallery app.dill contains only 35 debug fields. So most of the debug fields are actually removed.

I grepped retained debug fields and found that 32 of those fields are actually used in release mode:

_Channel.debugEnableDiscardWarnings
  // Used in _Channel.push

AnimationController.debugLabel
  // Used in AnimationController.toStringDetails

CupertinoDynamicColor._debugLabel
  // Used in CupertinoDynamicColor.resolveFrom

CupertinoDynamicColor._debugResolveContext
  // Used in CupertinoDynamicColor.toString

_IsolateConfiguration.debugLabel
  // Used in _IsolateConfiguration._spawn

MaterialApp.debugShowCheckedModeBanner
  // Used in _MaterialAppState._buildWidgetApp

ImageInfo.debugLabel
  // Used in ImageInfo.clone

ImageStreamCompleter.debugLabel
  // Used in MultiFrameImageStreamCompleter._handleAppFrame

TextStyle.debugLabel
  // Used in StrutStyle.fromTextStyle

RenderImage.debugImageLabel
  // Used in RenderImage.paint

RenderObject._debugDisposed
  // Used in RenderObject.toStringShort

RenderObject.debugCreator
  // Used in RenderObject._debugReportException

_FrameCallbackEntry.debugStack
  // Used in SchedulerBinding.handleBeginFrame

RestorationBucket._debugOwner
  // Used in RestorationBucket.debugOwner

RawImage.debugImageLabel
  // Used in RawImage.createRenderObject

RenderObjectToWidgetAdapter.debugShortDescription
  // Used in RenderObjectToWidgetAdapter.toStringShort

EditableText.debugDeterministicCursor
  // Used in EditableTextState._startCursorTimer

FocusNode._debugLabel
  // Used in FocusNode.debugLabel

Focus.debugLabel
  // Used in _FocusState._createNode

LabeledGlobalKey._debugLabel
  // Used in LabeledGlobalKey.toString

ScrollController.debugLabel
  // Used in ScrollController.createScrollPosition

ScrollPosition.debugLabel
  // Used in ScrollPosition.debugFillDescription

TextSelectionOverlay.debugRequiredFor
  // Used in TextSelectionOverlay.showHandles

HighlightFocus.debugLabel
  // Used in _HighlightFocusState.build

package:flutter/src/foundation/debug.dart :: debugDoublePrecision
  // Used in debugFormatDouble

package:flutter/src/foundation/platform.dart :: debugDefaultTargetPlatformOverride
  // Used in defaultTargetPlatform

package:flutter/src/foundation/print.dart :: debugPrint
  // Used in debugPrintStack

package:flutter/src/foundation/print.dart :: _debugPrintedCharacters
  // Used in _debugPrintTask

package:flutter/src/foundation/print.dart :: _debugPrintBuffer
  // Used in debugPrintThrottled

package:flutter/src/foundation/print.dart :: _debugPrintStopwatch
  // Used in _debugPrintTask

package:flutter/src/foundation/print.dart :: _debugPrintCompleter
  // Used in _debugPrintTask

package:flutter/src/foundation/print.dart :: _debugPrintScheduled
  // Used in debugPrintThrottled

It is possible to change Flutter code to avoid these uses (for example, their uses can be guarded with kDebugMode flag).

The following 3 retained debug fields don't have uses in release mode:

BuildOwner._debugIllFatedElements
BuildOwner._debugGlobalKeyReservations
Element._debugForgottenChildrenWithGlobalKey

These fields are retained because they have initializers and constructors of their classes are retained.
Filed dart-lang/sdk#46402 to improve tree shaking to be able to remove these fields.

@alexmarkov
Copy link
Contributor

AOT tree shaker was improved to handle instance fields with initializers at dart-lang/sdk@9c190c5, and tree shaker now removes 3 debug fields which are not used in release mode.

The remaining 32 debug fields are not eliminated because they are still used in release mode.

@jacob314
Copy link
Contributor

jacob314 commented Jun 28, 2021

Fyi @kenzieschmoll. This would be a good use case for the code size tooling. None of the remaining 32 debug fields should be included in release mode but likely there are bugs in Flutter that result in the fields surviving in release mode.

@mraleph
Copy link
Member

mraleph commented Jun 29, 2021

Fyi @kenzieschmoll. This would be a good use case for the code size tooling.

FWIW we don't really write enough information into either snapshot profile or precompiler trace to connect a retained field back to its uses.

@mraleph
Copy link
Member

mraleph commented Dec 3, 2022

@gintominto5329 anything specific you are asking about?

@mraleph
Copy link
Member

mraleph commented Dec 12, 2022

Based on @alexmarkov comments above I think there is nothing planned on the Dart side and all treeshakable fields are now actually treeshaken.

@mraleph mraleph closed this as completed Dec 12, 2022
Mobile - app publication/release review automation moved this from Awaiting triage to Engineer reviewed Dec 12, 2022
@github-actions
Copy link

github-actions bot commented Mar 5, 2023

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 5, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
c: performance Relates to speed or footprint issues (see "perf:" labels) c: proposal A detailed proposal for a change to Flutter dependency: dart Dart team may need to help us framework flutter/packages/flutter repository. See also f: labels. P3 Issues that are less important to the Flutter project perf: memory Performance issues related to memory platform-android Android applications specifically platform-ios iOS applications specifically
Projects
Development

No branches or pull requests

9 participants