From 3cb87bff7297a997fb28f05f9b4c4e64972da5c7 Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Fri, 6 Sep 2019 14:50:53 -0700 Subject: [PATCH] [flutter_runner] Generate symbols for the Dart VM profiler Ported from the original implementation in the Topaz tree. --- ci/licenses_golden/licenses_flutter | 1 + shell/platform/fuchsia/flutter/BUILD.gn | 26 +++- shell/platform/fuchsia/flutter/runner.cc | 24 +++ .../runtime/dart/profiler_symbols/BUILD.gn | 56 +++++++ .../profiler_symbols/analysis_options.yaml | 3 + .../dart_profiler_symbols.dart | 143 ++++++++++++++++++ .../dart/profiler_symbols/pubspec.yaml | 8 + 7 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 shell/platform/fuchsia/runtime/dart/profiler_symbols/BUILD.gn create mode 100644 shell/platform/fuchsia/runtime/dart/profiler_symbols/analysis_options.yaml create mode 100644 shell/platform/fuchsia/runtime/dart/profiler_symbols/dart_profiler_symbols.dart create mode 100644 shell/platform/fuchsia/runtime/dart/profiler_symbols/pubspec.yaml diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index ed833508ba90d..de796faef7b5f 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -971,6 +971,7 @@ FILE: ../../../flutter/shell/platform/fuchsia/flutter/vulkan_surface_pool.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/vulkan_surface_pool.h FILE: ../../../flutter/shell/platform/fuchsia/flutter/vulkan_surface_producer.cc FILE: ../../../flutter/shell/platform/fuchsia/flutter/vulkan_surface_producer.h +FILE: ../../../flutter/shell/platform/fuchsia/runtime/dart/profiler_symbols/dart_profiler_symbols.dart FILE: ../../../flutter/shell/platform/fuchsia/runtime/dart/utils/files.cc FILE: ../../../flutter/shell/platform/fuchsia/runtime/dart/utils/files.h FILE: ../../../flutter/shell/platform/fuchsia/runtime/dart/utils/handle_exception.cc diff --git a/shell/platform/fuchsia/flutter/BUILD.gn b/shell/platform/fuchsia/flutter/BUILD.gn index 07df29dfb4414..b5aaa5c999804 100644 --- a/shell/platform/fuchsia/flutter/BUILD.gn +++ b/shell/platform/fuchsia/flutter/BUILD.gn @@ -99,7 +99,10 @@ template("jit_runner") { ] if (!product) { - deps += [ engine_observatory_target ] + deps += [ + "$flutter_root/shell/platform/fuchsia/runtime/dart/profiler_symbols:flutter_jit_runner", + engine_observatory_target, + ] } binary = "flutter_jit${product_suffix}_runner" @@ -119,6 +122,14 @@ template("jit_runner") { path = rebase_path(engine_observatory_archive_file) dest = "observatory.tar" }, + { + path = rebase_path( + get_label_info( + "$flutter_root/shell/platform/fuchsia/runtime/dart/profiler_symbols:flutter_jit_runner", + "target_gen_dir") + + "/flutter_jit_runner.dartprofilersymbols") + dest = "flutter_jit_runner.dartprofilersymbols" + }, ] } @@ -169,7 +180,10 @@ template("aot_runner") { ] if (!product) { - deps += [ engine_observatory_target ] + deps += [ + "$flutter_root/shell/platform/fuchsia/runtime/dart/profiler_symbols:flutter_aot_runner", + engine_observatory_target, + ] } meta_dir = "$flutter_root/shell/platform/fuchsia/flutter/meta" @@ -189,6 +203,14 @@ template("aot_runner") { path = rebase_path(engine_observatory_archive_file) dest = "observatory.tar" }, + { + path = rebase_path( + get_label_info( + "$flutter_root/shell/platform/fuchsia/runtime/dart/profiler_symbols:flutter_aot_runner", + "target_gen_dir") + + "/flutter_aot_runner.dartprofilersymbols") + dest = "flutter_aot_runner.dartprofilersymbols" + }, ] } diff --git a/shell/platform/fuchsia/flutter/runner.cc b/shell/platform/fuchsia/flutter/runner.cc index f860b7988234d..22c70d5a8532f 100644 --- a/shell/platform/fuchsia/flutter/runner.cc +++ b/shell/platform/fuchsia/flutter/runner.cc @@ -16,6 +16,7 @@ #include "flutter/fml/make_copyable.h" #include "flutter/lib/ui/text/font_collection.h" #include "flutter/runtime/dart_vm.h" +#include "runtime/dart/utils/files.h" #include "runtime/dart/utils/vmo.h" #include "runtime/dart/utils/vmservice_object.h" #include "third_party/icu/source/common/unicode/udata.h" @@ -87,6 +88,19 @@ static void SetThreadName(const std::string& thread_name) { thread_name.size()); } +#if !defined(DART_PRODUCT) +// Register native symbol information for the Dart VM's profiler. +static void RegisterProfilerSymbols(const char* symbols_path, + const char* dso_name) { + std::string* symbols = new std::string(); + if (dart_utils::ReadFileToString(symbols_path, symbols)) { + Dart_AddSymbols(dso_name, symbols->data(), symbols->size()); + } else { + FML_LOG(ERROR) << "Failed to load " << symbols_path; + } +} +#endif // !defined(DART_PRODUCT) + Runner::Runner(async::Loop* loop) : loop_(loop), runner_context_(RunnerContext::CreateFromStartupInfo()) { #if !defined(DART_PRODUCT) @@ -110,6 +124,16 @@ Runner::Runner(async::Loop* loop) runner_context_->AddPublicService( std::bind(&Runner::RegisterApplication, this, std::placeholders::_1)); + +#if !defined(DART_PRODUCT) + if (Dart_IsPrecompiledRuntime()) { + RegisterProfilerSymbols("pkg/data/flutter_aot_runner.dartprofilersymbols", + ""); + } else { + RegisterProfilerSymbols("pkg/data/flutter_jit_runner.dartprofilersymbols", + ""); + } +#endif // !defined(DART_PRODUCT) } Runner::~Runner() { diff --git a/shell/platform/fuchsia/runtime/dart/profiler_symbols/BUILD.gn b/shell/platform/fuchsia/runtime/dart/profiler_symbols/BUILD.gn new file mode 100644 index 0000000000000..beea567141b11 --- /dev/null +++ b/shell/platform/fuchsia/runtime/dart/profiler_symbols/BUILD.gn @@ -0,0 +1,56 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//third_party/dart/build/dart/dart_action.gni") +import("$flutter_root/tools/fuchsia/clang.gni") + +template("generate_dart_profiler_symbols") { + assert(defined(invoker.library_label), "Must define 'library_label'") + assert(defined(invoker.library_path), "Must define 'library_path'") + assert(defined(invoker.output), "Must define 'output'") + + prebuilt_dart_action(target_name) { + deps = [ + invoker.library_label, + ] + inputs = [ + invoker.library_path, + ] + outputs = [ + invoker.output, + ] + + script = "dart_profiler_symbols.dart" + + packages = rebase_path("//third_party/dart/.packages") + + args = [ + "--nm", + rebase_path("//fuchsia/toolchain/$host_os/bin/llvm-nm"), + "--binary", + rebase_path(invoker.library_path), + "--output", + rebase_path(invoker.output), + ] + } +} + +generate_dart_profiler_symbols("dart_jit_runner") { + library_label = + "$flutter_root/shell/platform/fuchsia/dart_runner:dart_jit_runner_bin" + library_path = "${root_out_dir}/exe.unstripped/dart_jit_runner" + output = "${target_gen_dir}/dart_jit_runner.dartprofilersymbols" +} + +generate_dart_profiler_symbols("flutter_jit_runner") { + library_label = "$flutter_root/shell/platform/fuchsia/flutter:jit" + library_path = "${root_out_dir}/exe.unstripped/flutter_jit_runner" + output = "${target_gen_dir}/flutter_jit_runner.dartprofilersymbols" +} + +generate_dart_profiler_symbols("flutter_aot_runner") { + library_label = "$flutter_root/shell/platform/fuchsia/flutter:aot" + library_path = "${root_out_dir}/exe.unstripped/flutter_aot_runner" + output = "${target_gen_dir}/flutter_aot_runner.dartprofilersymbols" +} diff --git a/shell/platform/fuchsia/runtime/dart/profiler_symbols/analysis_options.yaml b/shell/platform/fuchsia/runtime/dart/profiler_symbols/analysis_options.yaml new file mode 100644 index 0000000000000..5e8ae01a4e1f8 --- /dev/null +++ b/shell/platform/fuchsia/runtime/dart/profiler_symbols/analysis_options.yaml @@ -0,0 +1,3 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. diff --git a/shell/platform/fuchsia/runtime/dart/profiler_symbols/dart_profiler_symbols.dart b/shell/platform/fuchsia/runtime/dart/profiler_symbols/dart_profiler_symbols.dart new file mode 100644 index 0000000000000..0e6af0f48e93f --- /dev/null +++ b/shell/platform/fuchsia/runtime/dart/profiler_symbols/dart_profiler_symbols.dart @@ -0,0 +1,143 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// On Fuchsia, in lieu of the ELF dynamic symbol table consumed through dladdr, +// the Dart VM profiler consumes symbols produced by this tool, which have the +// format +// +// struct { +// uint32_t num_entries; +// struct { +// uint32_t offset; +// uint32_t size; +// uint32_t string_table_offset; +// } entries[num_entries]; +// const char* string_table; +// } +// +// Entries are sorted by offset. String table entries are NUL-terminated. +// +// See also //third_party/dart/runtime/vm/native_symbol_fuchsia.cc + +import "dart:convert"; +import "dart:io"; +import "dart:typed_data"; + +import "package:args/args.dart"; +import "package:path/path.dart" as path; + +Future main(List args) async { + final parser = new ArgParser(); + parser.addOption("nm", help: "Path to `nm` tool"); + parser.addOption("binary", + help: "Path to the ELF file to extract symbols from"); + parser.addOption("output", help: "Path to output symbol table"); + final usage = """ +Usage: dart_profiler_symbols.dart [options] + +Options: +${parser.usage}; +"""; + + String buildIdDir; + String buildIdScript; + String nm; + String binary; + String output; + + try { + final options = parser.parse(args); + nm = options["nm"]; + if (nm == null) { + throw "Must specify --nm"; + } + if (!FileSystemEntity.isFileSync(nm)) { + throw "Cannot find $nm"; + } + binary = options["binary"]; + if (binary == null) { + throw "Must specify --binary"; + } + if (!FileSystemEntity.isFileSync(binary)) { + throw "Cannot find $binary"; + } + output = options["output"]; + if (output == null) { + throw "Must specify --output"; + } + } catch (e) { + print("ERROR: $e\n"); + print(usage); + exitCode = 1; + return; + } + + await run(buildIdDir, buildIdScript, nm, binary, output); +} + +class Symbol { + int offset; + int size; + String name; +} + +Future run(String buildIdDir, String buildIdScript, String nm, + String binary, String output) async { + final unstrippedFile = binary; + final args = ["--demangle", "--numeric-sort", "--print-size", unstrippedFile]; + final result = await Process.run(nm, args); + if (result.exitCode != 0) { + print(result.stdout); + print(result.stderr); + throw "Command failed: $nm $args"; + } + + var symbols = new List(); + + var regex = new RegExp("([0-9A-Za-z]+) ([0-9A-Za-z]+) (t|T|w|W) (.*)"); + for (final line in result.stdout.split("\n")) { + var match = regex.firstMatch(line); + if (match == null) { + continue; // Ignore non-text symbols. + } + + final symbol = new Symbol(); + + // Note that capture groups start at 1. + symbol.offset = int.parse(match[1], radix: 16); + symbol.size = int.parse(match[2], radix: 16); + symbol.name = match[4].split("(")[0]; + + if (symbol.name.startsWith("\$")) { + continue; // Ignore compiler/assembler temps. + } + + symbols.add(symbol); + } + + if (symbols.isEmpty) { + throw "$unstrippedFile has no symbols"; + } + + var nameTable = new BytesBuilder(); + var binarySearchTable = new Uint32List(symbols.length * 3 + 1); + var binarySearchTableIndex = 0; + binarySearchTable[binarySearchTableIndex++] = symbols.length; + // Symbols are sorted by offset because of --numeric-sort. + for (var symbol in symbols) { + var nameOffset = nameTable.length; + nameTable.add(utf8.encode(symbol.name)); + nameTable.addByte(0); + binarySearchTable[binarySearchTableIndex++] = symbol.offset; + binarySearchTable[binarySearchTableIndex++] = symbol.size; + binarySearchTable[binarySearchTableIndex++] = nameOffset; + } + + var file = new File(output); + await file.parent.create(recursive: true); + var sink = file.openWrite(); + sink.add(binarySearchTable.buffer.asUint8List()); + sink.add(nameTable.takeBytes()); + await sink.close(); +} diff --git a/shell/platform/fuchsia/runtime/dart/profiler_symbols/pubspec.yaml b/shell/platform/fuchsia/runtime/dart/profiler_symbols/pubspec.yaml new file mode 100644 index 0000000000000..8939a55d12c39 --- /dev/null +++ b/shell/platform/fuchsia/runtime/dart/profiler_symbols/pubspec.yaml @@ -0,0 +1,8 @@ +# Copyright 2013 The Flutter Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +name: profiler_symbols +version: 0 +description: Extracts a minimal symbols table for the Dart VM profiler +author: Dart Team