From fddb0c272e2f3e9f9639e1c1dbfcbf2ff86a262c Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Mon, 16 Mar 2020 11:00:03 -0700 Subject: [PATCH] Made it so you can whitelist what events you want to listen to (#17108) --- ci/licenses_golden/licenses_flutter | 3 + common/settings.h | 1 + fml/BUILD.gn | 3 + fml/ascii_trie.cc | 48 ++++++ fml/ascii_trie.h | 39 +++++ fml/ascii_trie_unittests.cc | 36 +++++ fml/trace_event.cc | 222 +++++++++++++++------------- fml/trace_event.h | 2 + shell/common/shell.cc | 16 ++ shell/common/switches.cc | 3 + shell/common/switches.h | 5 + 11 files changed, 279 insertions(+), 99 deletions(-) create mode 100644 fml/ascii_trie.cc create mode 100644 fml/ascii_trie.h create mode 100644 fml/ascii_trie_unittests.cc diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index ef7478a6914..0dac1de978c 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -107,6 +107,9 @@ FILE: ../../../flutter/flow/view_holder.cc FILE: ../../../flutter/flow/view_holder.h FILE: ../../../flutter/flutter_frontend_server/bin/starter.dart FILE: ../../../flutter/flutter_frontend_server/lib/server.dart +FILE: ../../../flutter/fml/ascii_trie.cc +FILE: ../../../flutter/fml/ascii_trie.h +FILE: ../../../flutter/fml/ascii_trie_unittests.cc FILE: ../../../flutter/fml/backtrace.cc FILE: ../../../flutter/fml/backtrace.h FILE: ../../../flutter/fml/backtrace_stub.cc diff --git a/common/settings.h b/common/settings.h index 1eddf4c16fe..c0914ae9970 100644 --- a/common/settings.h +++ b/common/settings.h @@ -91,6 +91,7 @@ struct Settings { bool enable_checked_mode = false; bool start_paused = false; bool trace_skia = false; + std::string trace_whitelist; bool trace_startup = false; bool trace_systrace = false; bool dump_skp_on_shader_compilation = false; diff --git a/fml/BUILD.gn b/fml/BUILD.gn index 356b8e2baa7..3a0b77515c4 100644 --- a/fml/BUILD.gn +++ b/fml/BUILD.gn @@ -10,6 +10,8 @@ import("//flutter/testing/testing.gni") source_set("fml") { sources = [ + "ascii_trie.cc", + "ascii_trie.h", "backtrace.h", "base32.cc", "base32.h", @@ -236,6 +238,7 @@ executable("fml_unittests") { testonly = true sources = [ + "ascii_trie_unittests.cc", "backtrace_unittests.cc", "base32_unittest.cc", "command_line_unittest.cc", diff --git a/fml/ascii_trie.cc b/fml/ascii_trie.cc new file mode 100644 index 00000000000..57892591fca --- /dev/null +++ b/fml/ascii_trie.cc @@ -0,0 +1,48 @@ +// 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. +#include "flutter/fml/ascii_trie.h" +#include "flutter/fml/logging.h" + +namespace fml { +typedef AsciiTrie::TrieNode TrieNode; +typedef AsciiTrie::TrieNodePtr TrieNodePtr; + +namespace { +void Add(TrieNodePtr* trie, const char* entry) { + int ch = entry[0]; + FML_DCHECK(ch < AsciiTrie::kMaxAsciiValue); + if (ch != 0) { + if (!*trie) { + *trie = std::make_unique(); + } + Add(&(*trie)->children[ch], entry + 1); + } +} + +TrieNodePtr MakeTrie(const std::vector& entries) { + TrieNodePtr result; + for (const std::string& entry : entries) { + Add(&result, entry.c_str()); + } + return result; +} +} // namespace + +void AsciiTrie::Fill(const std::vector& entries) { + node_ = MakeTrie(entries); +} + +bool AsciiTrie::Query(TrieNode* trie, const char* query) { + FML_DCHECK(trie); + const char* char_position = query; + TrieNode* trie_position = trie; + TrieNode* child; + int ch; + while ((ch = *char_position) && (child = trie_position->children[ch].get())) { + char_position++; + trie_position = child; + } + return !child && trie_position != trie; +} +} // namespace fml diff --git a/fml/ascii_trie.h b/fml/ascii_trie.h new file mode 100644 index 00000000000..e6ff430a08e --- /dev/null +++ b/fml/ascii_trie.h @@ -0,0 +1,39 @@ +// 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. + +#ifndef FLUTTER_FML_ASCIITRIE_H_ +#define FLUTTER_FML_ASCIITRIE_H_ + +#include +#include + +namespace fml { + +/// A trie for looking for ASCII prefixes. +class AsciiTrie { + public: + struct TrieNode; + typedef std::unique_ptr TrieNodePtr; + /// The max Ascii value. + static const int kMaxAsciiValue = 128; + + /// Clear and insert all the entries into the trie. + void Fill(const std::vector& entries); + + /// Returns true if \p argument is prefixed by the contents of the trie. + inline bool Query(const char* argument) { + return !node_ || Query(node_.get(), argument); + } + + struct TrieNode { + TrieNodePtr children[kMaxAsciiValue]; + }; + + private: + static bool Query(TrieNode* trie, const char* query); + TrieNodePtr node_; +}; +} // namespace fml + +#endif diff --git a/fml/ascii_trie_unittests.cc b/fml/ascii_trie_unittests.cc new file mode 100644 index 00000000000..e11cb185d28 --- /dev/null +++ b/fml/ascii_trie_unittests.cc @@ -0,0 +1,36 @@ +// 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. + +#include "flutter/fml/ascii_trie.h" +#include "gtest/gtest.h" + +using fml::AsciiTrie; + +TEST(AsciiTableTest, Simple) { + AsciiTrie trie; + auto entries = std::vector{"foo"}; + trie.Fill(entries); + ASSERT_TRUE(trie.Query("foobar")); + ASSERT_FALSE(trie.Query("google")); +} + +TEST(AsciiTableTest, ExactMatch) { + AsciiTrie trie; + auto entries = std::vector{"foo"}; + trie.Fill(entries); + ASSERT_TRUE(trie.Query("foo")); +} + +TEST(AsciiTableTest, Empty) { + AsciiTrie trie; + ASSERT_TRUE(trie.Query("foo")); +} + +TEST(AsciiTableTest, MultipleEntries) { + AsciiTrie trie; + auto entries = std::vector{"foo", "bar"}; + trie.Fill(entries); + ASSERT_TRUE(trie.Query("foozzz")); + ASSERT_TRUE(trie.Query("barzzz")); +} diff --git a/fml/trace_event.cc b/fml/trace_event.cc index 8698a2b0f20..7e11b2c6f8e 100644 --- a/fml/trace_event.cc +++ b/fml/trace_event.cc @@ -8,6 +8,7 @@ #include #include +#include "flutter/fml/ascii_trie.h" #include "flutter/fml/build_config.h" #include "flutter/fml/logging.h" @@ -22,6 +23,27 @@ namespace tracing { #if TIMELINE_ENABLED +namespace { +AsciiTrie gWhitelist; + +inline void FlutterTimelineEvent(const char* label, + int64_t timestamp0, + int64_t timestamp1_or_async_id, + Dart_Timeline_Event_Type type, + intptr_t argument_count, + const char** argument_names, + const char** argument_values) { + if (gWhitelist.Query(label)) { + Dart_TimelineEvent(label, timestamp0, timestamp1_or_async_id, type, + argument_count, argument_names, argument_values); + } +} +} // namespace + +void TraceSetWhitelist(const std::vector& whitelist) { + gWhitelist.Fill(whitelist); +} + size_t TraceNonce() { static std::atomic_size_t gLastItem; return ++gLastItem; @@ -42,7 +64,7 @@ void TraceTimelineEvent(TraceArg category_group, c_values[i] = values[i].c_str(); } - Dart_TimelineEvent( + FlutterTimelineEvent( name, // label Dart_TimelineGetMicros(), // timestamp0 identifier, // timestamp1_or_async_id @@ -54,13 +76,13 @@ void TraceTimelineEvent(TraceArg category_group, } void TraceEvent0(TraceArg category_group, TraceArg name) { - Dart_TimelineEvent(name, // label - Dart_TimelineGetMicros(), // timestamp0 - 0, // timestamp1_or_async_id - Dart_Timeline_Event_Begin, // event type - 0, // argument_count - nullptr, // argument_names - nullptr // argument_values + FlutterTimelineEvent(name, // label + Dart_TimelineGetMicros(), // timestamp0 + 0, // timestamp1_or_async_id + Dart_Timeline_Event_Begin, // event type + 0, // argument_count + nullptr, // argument_names + nullptr // argument_values ); } @@ -70,13 +92,13 @@ void TraceEvent1(TraceArg category_group, TraceArg arg1_val) { const char* arg_names[] = {arg1_name}; const char* arg_values[] = {arg1_val}; - Dart_TimelineEvent(name, // label - Dart_TimelineGetMicros(), // timestamp0 - 0, // timestamp1_or_async_id - Dart_Timeline_Event_Begin, // event type - 1, // argument_count - arg_names, // argument_names - arg_values // argument_values + FlutterTimelineEvent(name, // label + Dart_TimelineGetMicros(), // timestamp0 + 0, // timestamp1_or_async_id + Dart_Timeline_Event_Begin, // event type + 1, // argument_count + arg_names, // argument_names + arg_values // argument_values ); } @@ -88,24 +110,24 @@ void TraceEvent2(TraceArg category_group, TraceArg arg2_val) { const char* arg_names[] = {arg1_name, arg2_name}; const char* arg_values[] = {arg1_val, arg2_val}; - Dart_TimelineEvent(name, // label - Dart_TimelineGetMicros(), // timestamp0 - 0, // timestamp1_or_async_id - Dart_Timeline_Event_Begin, // event type - 2, // argument_count - arg_names, // argument_names - arg_values // argument_values + FlutterTimelineEvent(name, // label + Dart_TimelineGetMicros(), // timestamp0 + 0, // timestamp1_or_async_id + Dart_Timeline_Event_Begin, // event type + 2, // argument_count + arg_names, // argument_names + arg_values // argument_values ); } void TraceEventEnd(TraceArg name) { - Dart_TimelineEvent(name, // label - Dart_TimelineGetMicros(), // timestamp0 - 0, // timestamp1_or_async_id - Dart_Timeline_Event_End, // event type - 0, // argument_count - nullptr, // argument_names - nullptr // argument_values + FlutterTimelineEvent(name, // label + Dart_TimelineGetMicros(), // timestamp0 + 0, // timestamp1_or_async_id + Dart_Timeline_Event_End, // event type + 0, // argument_count + nullptr, // argument_names + nullptr // argument_values ); } @@ -119,47 +141,47 @@ void TraceEventAsyncComplete(TraceArg category_group, std::swap(begin, end); } - Dart_TimelineEvent(name, // label - begin.ToEpochDelta().ToMicroseconds(), // timestamp0 - identifier, // timestamp1_or_async_id - Dart_Timeline_Event_Async_Begin, // event type - 0, // argument_count - nullptr, // argument_names - nullptr // argument_values + FlutterTimelineEvent(name, // label + begin.ToEpochDelta().ToMicroseconds(), // timestamp0 + identifier, // timestamp1_or_async_id + Dart_Timeline_Event_Async_Begin, // event type + 0, // argument_count + nullptr, // argument_names + nullptr // argument_values ); - Dart_TimelineEvent(name, // label - end.ToEpochDelta().ToMicroseconds(), // timestamp0 - identifier, // timestamp1_or_async_id - Dart_Timeline_Event_Async_End, // event type - 0, // argument_count - nullptr, // argument_names - nullptr // argument_values + FlutterTimelineEvent(name, // label + end.ToEpochDelta().ToMicroseconds(), // timestamp0 + identifier, // timestamp1_or_async_id + Dart_Timeline_Event_Async_End, // event type + 0, // argument_count + nullptr, // argument_names + nullptr // argument_values ); } void TraceEventAsyncBegin0(TraceArg category_group, TraceArg name, TraceIDArg id) { - Dart_TimelineEvent(name, // label - Dart_TimelineGetMicros(), // timestamp0 - id, // timestamp1_or_async_id - Dart_Timeline_Event_Async_Begin, // event type - 0, // argument_count - nullptr, // argument_names - nullptr // argument_values + FlutterTimelineEvent(name, // label + Dart_TimelineGetMicros(), // timestamp0 + id, // timestamp1_or_async_id + Dart_Timeline_Event_Async_Begin, // event type + 0, // argument_count + nullptr, // argument_names + nullptr // argument_values ); } void TraceEventAsyncEnd0(TraceArg category_group, TraceArg name, TraceIDArg id) { - Dart_TimelineEvent(name, // label - Dart_TimelineGetMicros(), // timestamp0 - id, // timestamp1_or_async_id - Dart_Timeline_Event_Async_End, // event type - 0, // argument_count - nullptr, // argument_names - nullptr // argument_values + FlutterTimelineEvent(name, // label + Dart_TimelineGetMicros(), // timestamp0 + id, // timestamp1_or_async_id + Dart_Timeline_Event_Async_End, // event type + 0, // argument_count + nullptr, // argument_names + nullptr // argument_values ); } @@ -170,13 +192,13 @@ void TraceEventAsyncBegin1(TraceArg category_group, TraceArg arg1_val) { const char* arg_names[] = {arg1_name}; const char* arg_values[] = {arg1_val}; - Dart_TimelineEvent(name, // label - Dart_TimelineGetMicros(), // timestamp0 - id, // timestamp1_or_async_id - Dart_Timeline_Event_Async_Begin, // event type - 1, // argument_count - arg_names, // argument_names - arg_values // argument_values + FlutterTimelineEvent(name, // label + Dart_TimelineGetMicros(), // timestamp0 + id, // timestamp1_or_async_id + Dart_Timeline_Event_Async_Begin, // event type + 1, // argument_count + arg_names, // argument_names + arg_values // argument_values ); } @@ -187,66 +209,68 @@ void TraceEventAsyncEnd1(TraceArg category_group, TraceArg arg1_val) { const char* arg_names[] = {arg1_name}; const char* arg_values[] = {arg1_val}; - Dart_TimelineEvent(name, // label - Dart_TimelineGetMicros(), // timestamp0 - id, // timestamp1_or_async_id - Dart_Timeline_Event_Async_End, // event type - 1, // argument_count - arg_names, // argument_names - arg_values // argument_values + FlutterTimelineEvent(name, // label + Dart_TimelineGetMicros(), // timestamp0 + id, // timestamp1_or_async_id + Dart_Timeline_Event_Async_End, // event type + 1, // argument_count + arg_names, // argument_names + arg_values // argument_values ); } void TraceEventInstant0(TraceArg category_group, TraceArg name) { - Dart_TimelineEvent(name, // label - Dart_TimelineGetMicros(), // timestamp0 - 0, // timestamp1_or_async_id - Dart_Timeline_Event_Instant, // event type - 0, // argument_count - nullptr, // argument_names - nullptr // argument_values + FlutterTimelineEvent(name, // label + Dart_TimelineGetMicros(), // timestamp0 + 0, // timestamp1_or_async_id + Dart_Timeline_Event_Instant, // event type + 0, // argument_count + nullptr, // argument_names + nullptr // argument_values ); } void TraceEventFlowBegin0(TraceArg category_group, TraceArg name, TraceIDArg id) { - Dart_TimelineEvent(name, // label - Dart_TimelineGetMicros(), // timestamp0 - id, // timestamp1_or_async_id - Dart_Timeline_Event_Flow_Begin, // event type - 0, // argument_count - nullptr, // argument_names - nullptr // argument_values + FlutterTimelineEvent(name, // label + Dart_TimelineGetMicros(), // timestamp0 + id, // timestamp1_or_async_id + Dart_Timeline_Event_Flow_Begin, // event type + 0, // argument_count + nullptr, // argument_names + nullptr // argument_values ); } void TraceEventFlowStep0(TraceArg category_group, TraceArg name, TraceIDArg id) { - Dart_TimelineEvent(name, // label - Dart_TimelineGetMicros(), // timestamp0 - id, // timestamp1_or_async_id - Dart_Timeline_Event_Flow_Step, // event type - 0, // argument_count - nullptr, // argument_names - nullptr // argument_values + FlutterTimelineEvent(name, // label + Dart_TimelineGetMicros(), // timestamp0 + id, // timestamp1_or_async_id + Dart_Timeline_Event_Flow_Step, // event type + 0, // argument_count + nullptr, // argument_names + nullptr // argument_values ); } void TraceEventFlowEnd0(TraceArg category_group, TraceArg name, TraceIDArg id) { - Dart_TimelineEvent(name, // label - Dart_TimelineGetMicros(), // timestamp0 - id, // timestamp1_or_async_id - Dart_Timeline_Event_Flow_End, // event type - 0, // argument_count - nullptr, // argument_names - nullptr // argument_values + FlutterTimelineEvent(name, // label + Dart_TimelineGetMicros(), // timestamp0 + id, // timestamp1_or_async_id + Dart_Timeline_Event_Flow_End, // event type + 0, // argument_count + nullptr, // argument_names + nullptr // argument_values ); } #else // TIMELINE_ENABLED +void TraceSetWhitelist(const std::vector& whitelist) {} + size_t TraceNonce() { return 0; } diff --git a/fml/trace_event.h b/fml/trace_event.h index a5b478ffc15..a90aed2ff64 100644 --- a/fml/trace_event.h +++ b/fml/trace_event.h @@ -112,6 +112,8 @@ namespace tracing { using TraceArg = const char*; using TraceIDArg = int64_t; +void TraceSetWhitelist(const std::vector& whitelist); + void TraceTimelineEvent(TraceArg category_group, TraceArg name, TraceIDArg id, diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 3a3f9cfa901..b115cb1bf60 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -180,6 +180,16 @@ static void RecordStartupTimestamp() { } } +static void Tokenize(const std::string& input, + std::vector* results, + char delimiter) { + std::istringstream ss(input); + std::string token; + while (std::getline(ss, token, delimiter)) { + results->push_back(token); + } +} + // Though there can be multiple shells, some settings apply to all components in // the process. These have to be setup before the shell or any of its // sub-components can be initialized. In a perfect world, this would be empty. @@ -205,6 +215,12 @@ static void PerformInitializationTasks(const Settings& settings) { InitSkiaEventTracer(settings.trace_skia); } + if (!settings.trace_whitelist.empty()) { + std::vector prefixes; + Tokenize(settings.trace_whitelist, &prefixes, ','); + fml::tracing::TraceSetWhitelist(prefixes); + } + if (!settings.skia_deterministic_rendering_on_cpu) { SkGraphics::Init(); } else { diff --git a/shell/common/switches.cc b/shell/common/switches.cc index a23e1156f5e..885763a1075 100644 --- a/shell/common/switches.cc +++ b/shell/common/switches.cc @@ -272,6 +272,9 @@ Settings SettingsFromCommandLine(const fml::CommandLine& command_line) { settings.trace_skia = command_line.HasOption(FlagForSwitch(Switch::TraceSkia)); + command_line.GetOptionValue(FlagForSwitch(Switch::TraceWhitelist), + &settings.trace_whitelist); + settings.trace_systrace = command_line.HasOption(FlagForSwitch(Switch::TraceSystrace)); diff --git a/shell/common/switches.h b/shell/common/switches.h index c0faac25d50..e509b5cfd61 100644 --- a/shell/common/switches.h +++ b/shell/common/switches.h @@ -129,6 +129,11 @@ DEF_SWITCH(TraceSkia, "Trace Skia calls. This is useful when debugging the GPU threed." "By default, Skia tracing is not enabled to reduce the number of " "traced events") +DEF_SWITCH( + TraceWhitelist, + "trace-whitelist", + "Filters out all trace events except those that are specified in this " + "comma separated list of whitelisted prefixes.") DEF_SWITCH(DumpSkpOnShaderCompilation, "dump-skp-on-shader-compilation", "Automatically dump the skp that triggers new shader compilations. "