Deprecate profile() (#29054)

diff --git a/packages/flutter/lib/src/foundation/isolates.dart b/packages/flutter/lib/src/foundation/isolates.dart
index fd6ee57..a7bd1a3 100644
--- a/packages/flutter/lib/src/foundation/isolates.dart
+++ b/packages/flutter/lib/src/foundation/isolates.dart
@@ -8,7 +8,7 @@
 
 import 'package:meta/meta.dart';
 
-import 'profile.dart';
+import 'constants.dart';
 
 /// Signature for the callback passed to [compute].
 ///
@@ -45,7 +45,9 @@
 /// The `debugLabel` argument can be specified to provide a name to add to the
 /// [Timeline]. This is useful when profiling an application.
 Future<R> compute<Q, R>(ComputeCallback<Q, R> callback, Q message, { String debugLabel }) async {
-  profile(() { debugLabel ??= callback.toString(); });
+  if (!kReleaseMode) {
+    debugLabel ??= callback.toString();
+  }
   final Flow flow = Flow.begin();
   Timeline.startSync('$debugLabel: start', flow: flow);
   final ReceivePort resultPort = ReceivePort();
diff --git a/packages/flutter/lib/src/foundation/profile.dart b/packages/flutter/lib/src/foundation/profile.dart
index 21b5571..d1d5ff2 100644
--- a/packages/flutter/lib/src/foundation/profile.dart
+++ b/packages/flutter/lib/src/foundation/profile.dart
@@ -6,10 +6,16 @@
 
 import 'constants.dart';
 
-/// When running in profile mode (or debug mode), invoke the given function.
+/// DEPRECATED. `function` cannot be treeshaken out of release builds.
 ///
-/// In release mode, the function is not invoked.
-// TODO(devoncarew): Going forward, we'll want the call to profile() to be tree-shaken out.
+/// Instead use:
+///
+/// ```dart
+/// if (!kReleaseMode) {
+///   function();
+/// }
+/// ```
+@Deprecated('Use `if (!kReleaseMode) { function(); }` instead')
 void profile(VoidCallback function) {
   if (kReleaseMode)
     return;
diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart
index d4a8655..b490143 100644
--- a/packages/flutter/lib/src/rendering/object.dart
+++ b/packages/flutter/lib/src/rendering/object.dart
@@ -749,9 +749,9 @@
   ///
   /// See [RendererBinding] for an example of how this function is used.
   void flushLayout() {
-    profile(() {
+    if (!kReleaseMode) {
       Timeline.startSync('Layout', arguments: timelineWhitelistArguments);
-    });
+    }
     assert(() {
       _debugDoingLayout = true;
       return true;
@@ -771,9 +771,9 @@
         _debugDoingLayout = false;
         return true;
       }());
-      profile(() {
+      if (!kReleaseMode) {
         Timeline.finishSync();
-      });
+      }
     }
   }
 
@@ -809,14 +809,18 @@
   /// Called as part of the rendering pipeline after [flushLayout] and before
   /// [flushPaint].
   void flushCompositingBits() {
-    profile(() { Timeline.startSync('Compositing bits'); });
+    if (!kReleaseMode) {
+      Timeline.startSync('Compositing bits');
+    }
     _nodesNeedingCompositingBitsUpdate.sort((RenderObject a, RenderObject b) => a.depth - b.depth);
     for (RenderObject node in _nodesNeedingCompositingBitsUpdate) {
       if (node._needsCompositingBitsUpdate && node.owner == this)
         node._updateCompositingBits();
     }
     _nodesNeedingCompositingBitsUpdate.clear();
-    profile(() { Timeline.finishSync(); });
+    if (!kReleaseMode) {
+      Timeline.finishSync();
+    }
   }
 
   List<RenderObject> _nodesNeedingPaint = <RenderObject>[];
@@ -837,7 +841,9 @@
   ///
   /// See [RendererBinding] for an example of how this function is used.
   void flushPaint() {
-    profile(() { Timeline.startSync('Paint', arguments: timelineWhitelistArguments); });
+    if (!kReleaseMode) {
+      Timeline.startSync('Paint', arguments: timelineWhitelistArguments);
+    }
     assert(() {
       _debugDoingPaint = true;
       return true;
@@ -862,7 +868,9 @@
         _debugDoingPaint = false;
         return true;
       }());
-      profile(() { Timeline.finishSync(); });
+      if (!kReleaseMode) {
+        Timeline.finishSync();
+      }
     }
   }
 
@@ -937,7 +945,9 @@
   void flushSemantics() {
     if (_semanticsOwner == null)
       return;
-    profile(() { Timeline.startSync('Semantics'); });
+    if (!kReleaseMode) {
+      Timeline.startSync('Semantics');
+    }
     assert(_semanticsOwner != null);
     assert(() { _debugDoingSemantics = true; return true; }());
     try {
@@ -952,7 +962,9 @@
     } finally {
       assert(_nodesNeedingSemantics.isEmpty);
       assert(() { _debugDoingSemantics = false; return true; }());
-      profile(() { Timeline.finishSync(); });
+      if (!kReleaseMode) {
+        Timeline.finishSync();
+      }
     }
   }
 }
diff --git a/packages/flutter/lib/src/scheduler/binding.dart b/packages/flutter/lib/src/scheduler/binding.dart
index f33ba86..bee7c34 100644
--- a/packages/flutter/lib/src/scheduler/binding.dart
+++ b/packages/flutter/lib/src/scheduler/binding.dart
@@ -890,11 +890,11 @@
     if (rawTimeStamp != null)
       _lastRawTimeStamp = rawTimeStamp;
 
-    profile(() {
+    if (!kReleaseMode) {
       _profileFrameNumber += 1;
       _profileFrameStopwatch.reset();
       _profileFrameStopwatch.start();
-    });
+    }
 
     assert(() {
       if (debugPrintBeginFrameBanner || debugPrintEndFrameBanner) {
@@ -957,10 +957,10 @@
     } finally {
       _schedulerPhase = SchedulerPhase.idle;
       Timeline.finishSync(); // end the Frame
-      profile(() {
+      if (!kReleaseMode) {
         _profileFrameStopwatch.stop();
         _profileFramePostEvent();
-      });
+      }
       assert(() {
         if (debugPrintEndFrameBanner)
           debugPrint('▀' * _debugBanner.length);
diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart
index 128733f..70f25ff 100644
--- a/packages/flutter/lib/src/widgets/binding.dart
+++ b/packages/flutter/lib/src/widgets/binding.dart
@@ -270,7 +270,7 @@
   void initServiceExtensions() {
     super.initServiceExtensions();
 
-    profile(() {
+    if (!kReleaseMode) {
       registerSignalServiceExtension(
         name: 'debugDumpApp',
         callback: () {
@@ -302,7 +302,7 @@
           };
         },
       );
-    });
+    }
 
     assert(() {
       registerBoolServiceExtension(
@@ -566,10 +566,10 @@
   /// This is used by [WidgetsApp] to avoid reporting frames that aren't useful
   /// during startup as the "first frame".
   void deferFirstFrameReport() {
-    profile(() {
+    if (!kReleaseMode) {
       assert(_deferFirstFrameReportCount >= 0);
       _deferFirstFrameReportCount += 1;
-    });
+    }
   }
 
   /// When called after [deferFirstFrameReport]: tell the framework to report
@@ -581,10 +581,10 @@
   /// This is used by [WidgetsApp] to report when the first useful frame is
   /// painted.
   void allowFirstFrameReport() {
-    profile(() {
+    if (!kReleaseMode) {
       assert(_deferFirstFrameReportCount >= 1);
       _deferFirstFrameReportCount -= 1;
-    });
+    }
   }
 
   void _handleBuildScheduled() {
@@ -706,13 +706,13 @@
         return true;
       }());
     }
-    profile(() {
+    if (!kReleaseMode) {
       if (_needToReportFirstFrame && _reportFirstFrame) {
         developer.Timeline.instantSync('Widgets completed first useful frame');
         developer.postEvent('Flutter.FirstFrame', <String, dynamic>{});
         _needToReportFirstFrame = false;
       }
-    });
+    }
   }
 
   /// The [Element] that is at the root of the hierarchy (and which wraps the
diff --git a/packages/flutter/test/foundation/profile_test.dart b/packages/flutter/test/foundation/profile_test.dart
index c76dfdd..3b57f13 100644
--- a/packages/flutter/test/foundation/profile_test.dart
+++ b/packages/flutter/test/foundation/profile_test.dart
@@ -10,7 +10,7 @@
   // that the code in the `profile` closure is omitted in release mode.
   test('profile invokes its closure in debug or profile mode', () {
     int count = 0;
-    profile(() {
+    profile(() { // ignore: deprecated_member_use_from_same_package
       count++;
     });
     // We run our tests in debug mode, so kReleaseMode will always evaluate to