[dart2js] Include memory usage in dart2js's output.

This adds a small text on the output of dart2js to indicate how much memory
it consumed during compilation.

It's implemented via a service protocol API that collects the total heap
capacity at the time dart2js is practically done with compilation.
Once this is in place, we could change our benchmarks to start using this metric.

Change-Id: Iaf4425ef713ce0195474ef4e818149d46ab55e9b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/244802
Commit-Queue: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Ben Konyi <bkonyi@google.com>
Reviewed-by: Joshua Litt <joshualitt@google.com>
diff --git a/pkg/compiler/lib/src/common/ram_usage.dart b/pkg/compiler/lib/src/common/ram_usage.dart
new file mode 100644
index 0000000..76c5c2d
--- /dev/null
+++ b/pkg/compiler/lib/src/common/ram_usage.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2022, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This library contains logic to fetch RAM utilization information.
+/// It is implemented as an RPC that connects to the VM's vm_service isolate and
+/// all necessary details.
+///
+/// This is similar to the information that the VM prints when provided the
+/// `--print_metrics` flag. However, this API allows us to obtain the data
+/// directly while the process is running and embedded in the compiler output
+/// (and in the future in dump-info).
+///
+/// Note that one could alternatively use Process.maxRss instead, however that
+/// number may have a lot more variability depending on system conditions.
+/// Our goal with this number is not so much to be exact, but to have a good
+/// metric we can track overtime and use to detect improvements and regressions.
+import 'dart:developer';
+import 'package:vm_service/vm_service_io.dart' as vm_service_io;
+
+Future<int> _currentHeapCapacity() async {
+  final info =
+      await Service.controlWebServer(enable: true, silenceOutput: true);
+  final observatoryUri = info.serverUri!;
+  final wsUri = 'ws://${observatoryUri.authority}${observatoryUri.path}ws';
+  final vmService = await vm_service_io.vmServiceConnectUri(wsUri);
+  int sum = 0;
+  for (final group in (await vmService.getVM()).isolateGroups!) {
+    final usage = await vmService.getIsolateGroupMemoryUsage(group.id!);
+    sum += usage.heapCapacity!;
+  }
+  vmService.dispose();
+  return sum;
+}
+
+Future<String> currentHeapCapacityInMb() async {
+  final capacity = await _currentHeapCapacity();
+  return "${(capacity / (1024 * 1024)).toStringAsFixed(3)} MB";
+}
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 26b15e7..bb3680f 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -16,6 +16,7 @@
 import '../compiler_api.dart' as api;
 import '../compiler_api_unmigrated.dart' as api_unmigrated;
 import 'commandline_options.dart';
+import 'common/ram_usage.dart';
 import 'options.dart' show CompilerOptions, FeatureOptions;
 import 'source_file_provider.dart';
 import 'util/command_line.dart';
@@ -933,7 +934,8 @@
       RandomAccessFileOutputProvider(out, sourceMapOut,
           onInfo: diagnosticHandler.info, onFailure: fail);
 
-  api.CompilationResult compilationDone(api.CompilationResult result) {
+  Future<api.CompilationResult> compilationDone(
+      api.CompilationResult result) async {
     if (!result.isSuccess) {
       fail('Compilation failed.');
     }
@@ -1060,7 +1062,8 @@
     print('$processName '
         '${_formatCharacterCount(inputSize)} $inputName to '
         '${_formatCharacterCount(outputSize)} $outputName in '
-        '${_formatDurationAsSeconds(wallclock.elapsed)} seconds');
+        '${_formatDurationAsSeconds(wallclock.elapsed)} seconds using '
+        '${await currentHeapCapacityInMb()} of memory');
     if (primaryOutputSize != null) {
       diagnosticHandler
           .info('${_formatCharacterCount(primaryOutputSize)} $outputName '
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index f3dfd26..071e5e1 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -19,6 +19,7 @@
   js_runtime: any
   js_shared: any
   kernel: any
+  vm_service: any
 
 dev_dependencies:
   args: any