Merge "trace_processor: implement first android mem metric!"
diff --git a/Android.bp b/Android.bp
index 0b5991d..515e736 100644
--- a/Android.bp
+++ b/Android.bp
@@ -14,6 +14,20 @@
//
// This file is automatically generated by tools/gen_android_bp. Do not edit.
+genrule {
+ name: "gen_merged_sql_metrics",
+ srcs: [
+ "src/trace_processor/metrics/android/android_mem.sql",
+ ],
+ cmd: "$(location tools/gen_merged_sql_metrics) --cpp_out=$(out) $(in)",
+ out: [
+ "src/trace_processor/metrics/sql_metrics.h",
+ ],
+ tool_files: [
+ "tools/gen_merged_sql_metrics",
+ ],
+}
+
// GN target: //:heapprofd
cc_binary {
name: "heapprofd",
@@ -1034,6 +1048,76 @@
],
}
+// GN target: //protos/perfetto/metrics/android:zero_gen
+genrule {
+ name: "perfetto_protos_perfetto_metrics_android_zero_gen",
+ srcs: [
+ "protos/perfetto/metrics/android/mem_metric.proto",
+ ],
+ tools: [
+ "aprotoc",
+ "perfetto_src_protozero_protoc_plugin_protoc_plugin___gn_standalone_toolchain_gcc_like_host_",
+ ],
+ cmd: "mkdir -p $(genDir)/external/perfetto/protos && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/protos --proto_path=external/perfetto/protos --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_protoc_plugin___gn_standalone_toolchain_gcc_like_host_) --plugin_out=wrapper_namespace=pbzero:$(genDir)/external/perfetto/protos $(in)",
+ out: [
+ "external/perfetto/protos/perfetto/metrics/android/mem_metric.pbzero.cc",
+ ],
+}
+
+// GN target: //protos/perfetto/metrics/android:zero_gen
+genrule {
+ name: "perfetto_protos_perfetto_metrics_android_zero_gen_headers",
+ srcs: [
+ "protos/perfetto/metrics/android/mem_metric.proto",
+ ],
+ tools: [
+ "aprotoc",
+ "perfetto_src_protozero_protoc_plugin_protoc_plugin___gn_standalone_toolchain_gcc_like_host_",
+ ],
+ cmd: "mkdir -p $(genDir)/external/perfetto/protos && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/protos --proto_path=external/perfetto/protos --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_protoc_plugin___gn_standalone_toolchain_gcc_like_host_) --plugin_out=wrapper_namespace=pbzero:$(genDir)/external/perfetto/protos $(in)",
+ out: [
+ "external/perfetto/protos/perfetto/metrics/android/mem_metric.pbzero.h",
+ ],
+ export_include_dirs: [
+ "protos",
+ ],
+}
+
+// GN target: //protos/perfetto/metrics:zero_gen
+genrule {
+ name: "perfetto_protos_perfetto_metrics_zero_gen",
+ srcs: [
+ "protos/perfetto/metrics/metrics.proto",
+ ],
+ tools: [
+ "aprotoc",
+ "perfetto_src_protozero_protoc_plugin_protoc_plugin___gn_standalone_toolchain_gcc_like_host_",
+ ],
+ cmd: "mkdir -p $(genDir)/external/perfetto/protos && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/protos --proto_path=external/perfetto/protos --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_protoc_plugin___gn_standalone_toolchain_gcc_like_host_) --plugin_out=wrapper_namespace=pbzero:$(genDir)/external/perfetto/protos $(in)",
+ out: [
+ "external/perfetto/protos/perfetto/metrics/metrics.pbzero.cc",
+ ],
+}
+
+// GN target: //protos/perfetto/metrics:zero_gen
+genrule {
+ name: "perfetto_protos_perfetto_metrics_zero_gen_headers",
+ srcs: [
+ "protos/perfetto/metrics/metrics.proto",
+ ],
+ tools: [
+ "aprotoc",
+ "perfetto_src_protozero_protoc_plugin_protoc_plugin___gn_standalone_toolchain_gcc_like_host_",
+ ],
+ cmd: "mkdir -p $(genDir)/external/perfetto/protos && $(location aprotoc) --cpp_out=$(genDir)/external/perfetto/protos --proto_path=external/perfetto/protos --plugin=protoc-gen-plugin=$(location perfetto_src_protozero_protoc_plugin_protoc_plugin___gn_standalone_toolchain_gcc_like_host_) --plugin_out=wrapper_namespace=pbzero:$(genDir)/external/perfetto/protos $(in)",
+ out: [
+ "external/perfetto/protos/perfetto/metrics/metrics.pbzero.h",
+ ],
+ export_include_dirs: [
+ "protos",
+ ],
+}
+
// GN target: //protos/perfetto/trace/android:lite_gen
genrule {
name: "perfetto_protos_perfetto_trace_android_lite_gen",
@@ -3069,6 +3153,8 @@
":perfetto_protos_perfetto_common_zero_gen",
":perfetto_protos_perfetto_config_lite_gen",
":perfetto_protos_perfetto_config_zero_gen",
+ ":perfetto_protos_perfetto_metrics_android_zero_gen",
+ ":perfetto_protos_perfetto_metrics_zero_gen",
":perfetto_protos_perfetto_trace_android_lite_gen",
":perfetto_protos_perfetto_trace_android_zero_gen",
":perfetto_protos_perfetto_trace_chrome_lite_gen",
@@ -3175,10 +3261,13 @@
"libsqlite",
],
generated_headers: [
+ "gen_merged_sql_metrics",
"perfetto_protos_perfetto_common_lite_gen_headers",
"perfetto_protos_perfetto_common_zero_gen_headers",
"perfetto_protos_perfetto_config_lite_gen_headers",
"perfetto_protos_perfetto_config_zero_gen_headers",
+ "perfetto_protos_perfetto_metrics_android_zero_gen_headers",
+ "perfetto_protos_perfetto_metrics_zero_gen_headers",
"perfetto_protos_perfetto_trace_android_lite_gen_headers",
"perfetto_protos_perfetto_trace_android_zero_gen_headers",
"perfetto_protos_perfetto_trace_chrome_lite_gen_headers",
diff --git a/BUILD b/BUILD
index 6d4775e..d54ab5e 100644
--- a/BUILD
+++ b/BUILD
@@ -20,6 +20,21 @@
exports_files(["LICENSE"])
+# GN target: //src/trace_processor/metrics:gen_merged_sql_metrics
+genrule(
+ name = "gen_merged_sql_metrics",
+ srcs = [
+ "src/trace_processor/metrics/android/android_mem.sql",
+ ],
+ cmd = "$(location gen_merged_sql_metrics_py) --cpp_out=$@ $SRCS",
+ outs = [
+ "src/trace_processor/metrics/sql_metrics.h",
+ ],
+ tools = [
+ "gen_merged_sql_metrics_py",
+ ],
+)
+
# GN target: //src/protozero:libprotozero
cc_library(
name = "libprotozero",
@@ -287,10 +302,13 @@
"include/perfetto/traced/sys_stats_counters.h",
],
deps = [
+ "//third_party/perfetto:gen_merged_sql_metrics",
"//third_party/perfetto/google:gtest_prod",
"//third_party/perfetto/google:jsoncpp",
"//third_party/perfetto/protos:common_zero_cc_proto",
"//third_party/perfetto/protos:config_zero_cc_proto",
+ "//third_party/perfetto/protos:metrics_android_zero_cc_proto",
+ "//third_party/perfetto/protos:metrics_zero_cc_proto",
"//third_party/perfetto/protos:trace_android_zero_cc_proto",
"//third_party/perfetto/protos:trace_chrome_zero_cc_proto",
"//third_party/perfetto/protos:trace_filesystem_zero_cc_proto",
@@ -484,12 +502,15 @@
"src/trace_processor/window_operator_table.h",
],
deps = [
+ "//third_party/perfetto:gen_merged_sql_metrics",
"//third_party/perfetto/google:gtest_prod",
"//third_party/perfetto/google:jsoncpp",
"//third_party/perfetto/google:linenoise",
"//third_party/perfetto/google:perfetto_version",
"//third_party/perfetto/protos:common_zero_cc_proto",
"//third_party/perfetto/protos:config_zero_cc_proto",
+ "//third_party/perfetto/protos:metrics_android_zero_cc_proto",
+ "//third_party/perfetto/protos:metrics_zero_cc_proto",
"//third_party/perfetto/protos:trace_android_zero_cc_proto",
"//third_party/perfetto/protos:trace_chrome_zero_cc_proto",
"//third_party/perfetto/protos:trace_filesystem_zero_cc_proto",
@@ -693,6 +714,7 @@
"tools/trace_to_text/utils.h",
],
deps = [
+ "//third_party/perfetto:gen_merged_sql_metrics",
"//third_party/perfetto/google:gtest_prod",
"//third_party/perfetto/google:jsoncpp",
"//third_party/perfetto/google:perfetto_version",
@@ -700,6 +722,8 @@
"//third_party/perfetto/protos:common_zero_cc_proto",
"//third_party/perfetto/protos:config_cc_proto",
"//third_party/perfetto/protos:config_zero_cc_proto",
+ "//third_party/perfetto/protos:metrics_android_zero_cc_proto",
+ "//third_party/perfetto/protos:metrics_zero_cc_proto",
"//third_party/perfetto/protos:protos_third_party_pprof_cc_proto",
"//third_party/perfetto/protos:trace_android_cc_proto",
"//third_party/perfetto/protos:trace_android_zero_cc_proto",
@@ -744,3 +768,10 @@
":trace_to_text",
],
)
+
+py_binary(
+ name = "gen_merged_sql_metrics_py"
+ srcs = [
+ "tools/gen_merged_sql_metrics"
+ ]
+)
diff --git a/BUILD.extras b/BUILD.extras
index a1ca2c3..1139c44 100644
--- a/BUILD.extras
+++ b/BUILD.extras
@@ -11,3 +11,10 @@
":trace_to_text",
],
)
+
+py_binary(
+ name = "gen_merged_sql_metrics_py"
+ srcs = [
+ "tools/gen_merged_sql_metrics"
+ ]
+)
diff --git a/include/perfetto/base/string_utils.h b/include/perfetto/base/string_utils.h
index 2df82f5..d2f9a36 100644
--- a/include/perfetto/base/string_utils.h
+++ b/include/perfetto/base/string_utils.h
@@ -28,6 +28,8 @@
bool Contains(const std::string& haystack, const std::string& needle);
std::string Join(const std::vector<std::string>& parts,
const std::string& delim);
+std::vector<std::string> SplitString(const std::string& text,
+ const std::string& delimiter);
} // namespace base
} // namespace perfetto
diff --git a/protos/BUILD b/protos/BUILD
index b41edf1..ed2ce1f 100644
--- a/protos/BUILD
+++ b/protos/BUILD
@@ -170,6 +170,45 @@
],
)
+# GN target: //protos/perfetto/metrics/android:zero_gen
+proto_library(
+ name = "metrics_android_zero",
+ srcs = [
+ "perfetto/metrics/android/mem_metric.proto",
+ ],
+)
+
+# GN target: //protos/perfetto/metrics/android:zero_gen
+pbzero_cc_proto_library(
+ name = "metrics_android_zero_cc_proto",
+ src_proto_library = "//third_party/perfetto/protos:metrics_android_zero",
+ deps = [
+ "//third_party/perfetto:libprotozero",
+ "//third_party/perfetto/google:gtest_prod",
+ ],
+)
+
+# GN target: //protos/perfetto/metrics:zero_gen
+proto_library(
+ name = "metrics_zero",
+ srcs = [
+ "perfetto/metrics/metrics.proto",
+ ],
+ deps = [
+ "//third_party/perfetto/protos:metrics_android_zero",
+ ],
+)
+
+# GN target: //protos/perfetto/metrics:zero_gen
+pbzero_cc_proto_library(
+ name = "metrics_zero_cc_proto",
+ src_proto_library = "//third_party/perfetto/protos:metrics_zero",
+ deps = [
+ "//third_party/perfetto:libprotozero",
+ "//third_party/perfetto/google:gtest_prod",
+ ],
+)
+
# GN target: //protos/third_party/pprof:lite_gen
proto_library(
name = "protos_third_party_pprof",
diff --git a/src/base/string_utils.cc b/src/base/string_utils.cc
index ad5c620..267952b 100644
--- a/src/base/string_utils.cc
+++ b/src/base/string_utils.cc
@@ -16,6 +16,8 @@
#include "perfetto/base/string_utils.h"
+#include "perfetto/base/logging.h"
+
namespace perfetto {
namespace base {
@@ -45,5 +47,22 @@
return acc;
}
+std::vector<std::string> SplitString(const std::string& text,
+ const std::string& delimiter) {
+ PERFETTO_CHECK(!delimiter.empty());
+
+ std::vector<std::string> output;
+ size_t start = 0;
+ size_t next;
+ for (;;) {
+ next = std::min(text.find(delimiter, start), text.size());
+ output.emplace_back(&text[start], next - start);
+ start = next + delimiter.size();
+ if (start >= text.size())
+ break;
+ }
+ return output;
+}
+
} // namespace base
} // namespace perfetto
diff --git a/src/base/string_utils_unittest.cc b/src/base/string_utils_unittest.cc
index c5737a4..bed511f 100644
--- a/src/base/string_utils_unittest.cc
+++ b/src/base/string_utils_unittest.cc
@@ -23,6 +23,8 @@
namespace base {
namespace {
+using testing::ElementsAre;
+
TEST(StringUtilsTest, StartsWith) {
EXPECT_TRUE(StartsWith("", ""));
EXPECT_TRUE(StartsWith("abc", ""));
@@ -45,6 +47,16 @@
EXPECT_FALSE(EndsWith("", "c"));
}
+TEST(StringUtilsTest, SplitString) {
+ EXPECT_THAT(SplitString("", ":"), ElementsAre(""));
+ EXPECT_THAT(SplitString("a:b:c", ":"), ElementsAre("a", "b", "c"));
+ EXPECT_THAT(SplitString("a::b::c", "::"), ElementsAre("a", "b", "c"));
+ EXPECT_THAT(SplitString("abc", ":"), ElementsAre("abc"));
+ EXPECT_THAT(SplitString("abc", "::"), ElementsAre("abc"));
+ EXPECT_THAT(SplitString("abc", ":"), ElementsAre("abc"));
+ EXPECT_THAT(SplitString("abc", "::"), ElementsAre("abc"));
+}
+
} // namespace
} // namespace base
} // namespace perfetto
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 44cd51b..8bfa043 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -148,6 +148,8 @@
"../../gn:default_deps",
"../../include/perfetto/traced:sys_stats_counters",
"../../protos/perfetto/common:zero",
+ "../../protos/perfetto/metrics:zero",
+ "../../protos/perfetto/metrics/android:zero",
"../../protos/perfetto/trace:zero",
"../../protos/perfetto/trace/android:zero",
"../../protos/perfetto/trace/ftrace:zero",
@@ -159,6 +161,7 @@
"../../protos/perfetto/trace/track_event:zero",
"../base",
"../protozero",
+ "metrics:gen_merged_sql_metrics",
]
public_deps = [
"../../include/perfetto/trace_processor",
diff --git a/src/trace_processor/metrics/BUILD.gn b/src/trace_processor/metrics/BUILD.gn
new file mode 100644
index 0000000..779cdf7
--- /dev/null
+++ b/src/trace_processor/metrics/BUILD.gn
@@ -0,0 +1,35 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("../../../gn/perfetto.gni")
+
+sql_files = [ "android/android_mem.sql" ]
+
+config("gen_config") {
+ include_dirs = [ "${root_gen_dir}/${perfetto_root_path}" ]
+}
+
+action("gen_merged_sql_metrics") {
+ script = "../../../tools/gen_merged_sql_metrics"
+ generated_header = "${target_gen_dir}/sql_metrics.h"
+ args = rebase_path(sql_files, root_build_dir) + [
+ "--cpp_out",
+ rebase_path(generated_header, root_build_dir),
+ ]
+ inputs = sql_files
+ outputs = [
+ generated_header,
+ ]
+ public_configs = [ ":gen_config" ]
+}
diff --git a/src/trace_processor/metrics/android/android_mem.sql b/src/trace_processor/metrics/android/android_mem.sql
new file mode 100644
index 0000000..80daf9c
--- /dev/null
+++ b/src/trace_processor/metrics/android/android_mem.sql
@@ -0,0 +1,42 @@
+--
+-- Copyright 2019 The Android Open Source Project
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- https://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+-- Create all the views used to generate the Android Memory metrics proto.
+CREATE TABLE last_oom_adj(upid BIG INT PRIMARY KEY, ts BIG INT, score INT);
+
+INSERT INTO last_oom_adj
+SELECT upid, ts, score
+FROM (
+ SELECT ref AS upid,
+ ts,
+ CAST(value AS INT) AS score,
+ row_number() OVER (PARTITION BY counter_id ORDER BY ts DESC) AS rank
+ FROM counter_definitions JOIN counter_values USING(counter_id)
+ WHERE name = 'oom_score_adj'
+ AND ref_type = 'upid')
+WHERE rank = 1;
+
+CREATE VIEW lmk_events AS
+SELECT ref AS upid
+FROM instants
+WHERE name = 'mem.lmk' AND ref_type = 'upid';
+
+CREATE VIEW lmk_by_score AS
+SELECT process.name, last_oom_adj.score
+FROM lmk_events
+LEFT JOIN process ON lmk_events.upid = process.upid
+LEFT JOIN last_oom_adj ON lmk_events.upid = last_oom_adj.upid
+ORDER BY lmk_events.upid;
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 0f1e3b8..04ddd16 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -21,7 +21,9 @@
#include <functional>
#include "perfetto/base/logging.h"
+#include "perfetto/base/string_utils.h"
#include "perfetto/base/time.h"
+#include "perfetto/protozero/scattered_heap_buffer.h"
#include "src/trace_processor/android_logs_table.h"
#include "src/trace_processor/args_table.h"
#include "src/trace_processor/args_tracker.h"
@@ -32,6 +34,7 @@
#include "src/trace_processor/fuchsia_trace_parser.h"
#include "src/trace_processor/fuchsia_trace_tokenizer.h"
#include "src/trace_processor/instants_table.h"
+#include "src/trace_processor/metrics/sql_metrics.h"
#include "src/trace_processor/process_table.h"
#include "src/trace_processor/process_tracker.h"
#include "src/trace_processor/proto_trace_parser.h"
@@ -52,6 +55,9 @@
#include "src/trace_processor/trace_sorter.h"
#include "src/trace_processor/window_operator_table.h"
+#include "perfetto/metrics/android/mem_metric.pbzero.h"
+#include "perfetto/metrics/metrics.pbzero.h"
+
// JSON parsing is only supported in the standalone build.
#if PERFETTO_BUILDFLAG(PERFETTO_STANDALONE_BUILD)
#include "src/trace_processor/json_trace_parser.h"
@@ -71,6 +77,12 @@
namespace trace_processor {
namespace {
+std::string RemoveWhitespace(const std::string& input) {
+ std::string str(input);
+ str.erase(std::remove_if(str.begin(), str.end(), ::isspace), str.end());
+ return str;
+}
+
void InitializeSqlite(sqlite3* db) {
char* error = nullptr;
sqlite3_exec(db, "PRAGMA temp_store=2", 0, 0, &error);
@@ -169,16 +181,6 @@
}
}
-bool IsPrefix(const std::string& a, const std::string& b) {
- return a.size() <= b.size() && b.substr(0, a.size()) == a;
-}
-
-std::string RemoveWhitespace(const std::string& input) {
- std::string str(input);
- str.erase(std::remove_if(str.begin(), str.end(), ::isspace), str.end());
- return str;
-}
-
// Fuchsia traces have a magic number as documented here:
// https://fuchsia.googlesource.com/fuchsia/+/HEAD/docs/development/tracing/trace-format/README.md#magic-number-record-trace-info-type-0
constexpr uint64_t kFuchsiaMagicNumber = 0x0016547846040010;
@@ -191,9 +193,9 @@
std::string start(reinterpret_cast<const char*>(data),
std::min<size_t>(size, 20));
std::string start_minus_white_space = RemoveWhitespace(start);
- if (IsPrefix("{\"traceEvents\":[", start_minus_white_space))
+ if (base::StartsWith(start_minus_white_space, "{\"traceEvents\":["))
return kJsonTraceType;
- if (IsPrefix("[{", start_minus_white_space))
+ if (base::StartsWith(start_minus_white_space, "[{"))
return kJsonTraceType;
if (size >= 8) {
uint64_t first_word = *reinterpret_cast<const uint64_t*>(data);
@@ -322,7 +324,53 @@
int TraceProcessorImpl::ComputeMetric(
const std::vector<std::string>& metric_names,
std::vector<uint8_t>* metrics_proto) {
- perfetto::base::ignore_result(metric_names, metrics_proto);
+ // TODO(lalitm): stop hardcoding android.mem metric and read the proto
+ // descriptor for this logic instead.
+ if (metric_names.size() != 1 || metric_names[0] != "android.mem") {
+ PERFETTO_ELOG("Only android.mem metric is currently supported");
+ return 1;
+ }
+
+ auto queries = base::SplitString(metrics::kAndroidMem, ";\n\n");
+ for (const auto& query : queries) {
+ PERFETTO_DLOG("Executing query: %s", query.c_str());
+ auto prep_it = ExecuteQuery(query);
+ auto prep_has_next = prep_it.Next();
+ if (auto opt_error = prep_it.GetLastError()) {
+ PERFETTO_ELOG("SQLite error: %s", opt_error->c_str());
+ return 1;
+ }
+ PERFETTO_DCHECK(!prep_has_next);
+ }
+
+ protozero::ScatteredHeapBuffer delegate;
+ protozero::ScatteredStreamWriter writer(&delegate);
+ delegate.set_writer(&writer);
+
+ protos::pbzero::TraceMetrics metrics;
+ metrics.Reset(&writer);
+
+ // TODO(lalitm): all the below is temporary hardcoded queries and proto
+ // filling to ensure that the code above works.
+ auto it = ExecuteQuery("SELECT COUNT(*) from lmk_by_score;");
+ auto has_next = it.Next();
+ if (auto opt_error = it.GetLastError()) {
+ PERFETTO_ELOG("SQLite error: %s", opt_error->c_str());
+ return 1;
+ }
+ PERFETTO_CHECK(has_next);
+ PERFETTO_CHECK(it.Get(0).type == SqlValue::Type::kLong);
+
+ auto* memory = metrics.set_android_mem();
+ memory->set_system_metrics()->set_lmks()->set_total_count(
+ static_cast<int32_t>(it.Get(0).long_value));
+ metrics.Finalize();
+
+ *metrics_proto = delegate.StitchSlices();
+
+ has_next = it.Next();
+ PERFETTO_DCHECK(!has_next);
+
return 0;
}
diff --git a/src/trace_processor/trace_processor_shell.cc b/src/trace_processor/trace_processor_shell.cc
index 05215e4..a75d934 100644
--- a/src/trace_processor/trace_processor_shell.cc
+++ b/src/trace_processor/trace_processor_shell.cc
@@ -17,6 +17,7 @@
#include <aio.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -248,6 +249,7 @@
PERFETTO_ELOG("Error when computing metrics");
return 1;
}
+ fwrite(metric_result.data(), sizeof(uint8_t), metric_result.size(), stdout);
return 0;
}
diff --git a/tools/gen_android_bp b/tools/gen_android_bp
index e9ca6ab..b6b5eda 100755
--- a/tools/gen_android_bp
+++ b/tools/gen_android_bp
@@ -213,6 +213,7 @@
self.include_dirs = []
self.required = []
self.user_debug_flag = False
+ self.tool_files = None
def to_string(self, output):
if self.comment:
@@ -235,6 +236,7 @@
self._output_field(output, 'local_include_dirs')
self._output_field(output, 'include_dirs')
self._output_field(output, 'required')
+ self._output_field(output, 'tool_files')
disable_pdk = any(name in library_not_in_pdk for name in self.shared_libs)
if self.user_debug_flag or disable_pdk:
@@ -365,12 +367,16 @@
type = target['type']
if type == 'action':
- create_modules_from_target(blueprint, desc, dep_name)
- # Depend both on the generated sources and headers -- see
- # make_genrules_for_action.
- module.srcs.append(':' + label_to_module_name(dep_name))
- module.generated_headers.append(
- label_to_module_name(dep_name) + '_headers')
+ if "gen_merged_sql_metrics" in dep_name:
+ dep_mod = create_merged_sql_metrics_target(blueprint, desc, dep_name)
+ module.generated_headers.append(dep_mod.name)
+ else:
+ create_modules_from_target(blueprint, desc, dep_name)
+ # Depend both on the generated sources and headers -- see
+ # make_genrules_for_action.
+ module.srcs.append(':' + label_to_module_name(dep_name))
+ module.generated_headers.append(
+ label_to_module_name(dep_name) + '_headers')
elif type == 'static_library' and label_to_module_name(
dep_name) != module.name:
create_modules_from_target(blueprint, desc, dep_name)
@@ -506,6 +512,26 @@
]
return source_module, header_module
+def create_merged_sql_metrics_target(blueprint, desc, gn_target_name):
+ target_desc = desc[gn_target_name]
+ module = Module(
+ 'genrule',
+ 'gen_merged_sql_metrics',
+ )
+ module.tool_files = [
+ 'tools/gen_merged_sql_metrics',
+ ]
+ module.cmd = '$(location tools/gen_merged_sql_metrics) --cpp_out=$(out) $(in)'
+ module.out = set(
+ src[src.index('gen/') + len('gen/'):]
+ for src in target_desc.get('outputs', [])
+ )
+ module.srcs.extend(
+ label_to_path(src)
+ for src in target_desc.get('inputs', [])
+ )
+ blueprint.add_module(module)
+ return module
def _get_cflags(target):
cflags = set(flag for flag in target.get('cflags', [])
diff --git a/tools/gen_build b/tools/gen_build
index 307d693..ade417f 100755
--- a/tools/gen_build
+++ b/tools/gen_build
@@ -314,7 +314,7 @@
def __init__(self, type, name, gn_name=None, **kwargs):
assert type in ('cc_binary', 'cc_library', 'cc_proto_library',
'proto_library', 'filegroup', 'alias',
- 'pbzero_cc_proto_library',)
+ 'pbzero_cc_proto_library', 'genrule', )
self.type = type
self.name = name
self.srcs = set()
@@ -459,13 +459,21 @@
self.apply_module_sources_to_target(target, dep_desc)
elif dep_desc['type'] == 'action':
- (proto_target, cc_target) = self.create_target(dep_name)
- if target.type == 'proto_library':
- dep_target_name = proto_target.name
+ args = dep_desc['args']
+ if "gen_merged_sql_metrics" in dep_name:
+ dep_target = self.create_merged_sql_metrics_target(dep_name)
+ target.deps.add(Label("//third_party/perfetto:" + dep_target.name))
+ elif args[0].endswith('/protoc'):
+ (proto_target, cc_target) = self.create_proto_target(dep_name)
+ if target.type == 'proto_library':
+ dep_target_name = proto_target.name
+ else:
+ dep_target_name = cc_target.name
+ target.deps.add(
+ Label("//third_party/perfetto/protos:" + dep_target_name))
else:
- dep_target_name = cc_target.name
- target.deps.add(
- Label("//third_party/perfetto/protos:" + dep_target_name))
+ raise Error('Unsupported action in target %s: %s' % (dep_target_name,
+ args))
elif dep_desc['type'] == 'static_library':
dep_target = self.create_target(dep_name)
target.deps.add(Label("//third_party/perfetto:" + dep_target.name))
@@ -480,13 +488,33 @@
raise Error('Unknown target name %s with type: %s' %
(dep_name, dep_desc['type']))
+ def create_merged_sql_metrics_target(self, gn_target_name):
+ target_desc = self.desc[gn_target_name]
+ gn_target_name_no_toolchain = label_without_toolchain(gn_target_name)
+ target = Target(
+ 'genrule',
+ 'gen_merged_sql_metrics',
+ gn_name=gn_target_name_no_toolchain,
+ outs=set(
+ Label(src[src.index('gen/') + len('gen/'):])
+ for src in target_desc.get('outputs', [])
+ ),
+ cmd = '$(location gen_merged_sql_metrics_py) --cpp_out=$@ $SRCS',
+ tools=[
+ 'gen_merged_sql_metrics_py',
+ ],
+ )
+ target.srcs.update(
+ Label(label_to_path(src))
+ for src in target_desc.get('inputs', [])
+ if src not in self.action_generated_files
+ )
+ self.build.add_target(target)
+ return target
- def create_action_target(self, gn_target_name):
+ def create_proto_target(self, gn_target_name):
target_desc = self.desc[gn_target_name]
args = target_desc['args']
- if not args[0].endswith('/protoc'):
- raise Error('Unsupported action in target %s: %s' % (gn_target_name,
- target_desc['args']))
is_pbzero = any("pbzero" in arg for arg in args)
gn_target_name_no_toolchain = label_without_toolchain(gn_target_name)
@@ -496,14 +524,14 @@
pretty_target_name = pretty_target_name.replace("_zero_gen", "_zero")
proto_target = Target(
- 'proto_library',
- pretty_target_name,
- gn_name=gn_target_name_no_toolchain,
- is_pbzero=is_pbzero
+ 'proto_library',
+ pretty_target_name,
+ gn_name=gn_target_name_no_toolchain,
+ is_pbzero=is_pbzero
)
proto_target.srcs.update([
- Label(label_to_path(src).replace('protos/', ''))
- for src in target_desc.get('sources', [])
+ Label(label_to_path(src).replace('protos/', ''))
+ for src in target_desc.get('sources', [])
])
if not is_pbzero:
proto_target.visibility.add("//visibility:public")
@@ -563,7 +591,12 @@
target_desc = self.desc[gn_target_name]
if target_desc['type'] == 'action':
- return self.create_action_target(gn_target_name)
+ args = target_desc['args']
+ if args[0].endswith('/protoc'):
+ return self.create_proto_target(gn_target_name)
+ else:
+ raise Error('Unsupported action in target %s: %s' % (gn_target_name,
+ args))
elif target_desc['type'] == 'executable':
target_type = 'cc_binary'
elif target_desc['type'] == 'static_library':
diff --git a/tools/gen_merged_sql_metrics b/tools/gen_merged_sql_metrics
new file mode 100755
index 0000000..6ad35ea
--- /dev/null
+++ b/tools/gen_merged_sql_metrics
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import argparse
+import os
+import sys
+
+# Converts the SQL metrics for trace processor into a C++ header with the SQL
+# as a string constant to allow trace processor to exectue the metrics.
+
+REPLACEMENT_HEADER = '''/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ *******************************************************************************
+ * AUTOGENERATED BY tools/gen_merged_sql_metrics - DO NOT EDIT
+ *******************************************************************************
+ */
+'''
+
+NAMESPACE_BEGIN = '''
+namespace perfetto {
+namespace trace_processor {
+namespace metrics {
+'''
+
+FILE_TO_SQL_STRUCT = '''
+struct FileToSql {
+ const char* filename;
+ const char* sql;
+};
+'''
+
+NAMESPACE_END = '''
+} // namespace metrics
+} // namespace trace_processor
+} // namsepace perfetto
+'''
+
+def filename_to_variable(filename):
+ return "k" + "".join([x.capitalize() for x in filename.split("_")])
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--cpp_out', required=True)
+ parser.add_argument('sql_files', action='append')
+ args = parser.parse_args()
+
+ # Extract the SQL output from each file.
+ escaped_sql_outputs = {}
+ for file_name in args.sql_files:
+ with open(file_name, 'r') as f:
+ basename = os.path.basename(file_name)
+
+ # Escape any quote characters.
+ escaped_sql_outputs[basename] = "".join(f.readlines())
+
+ with open(args.cpp_out, 'w+') as output:
+ output.write(REPLACEMENT_HEADER)
+ output.write(NAMESPACE_BEGIN)
+
+ # Create the C++ variable for each SQL file.
+ for name, sql in escaped_sql_outputs.items():
+ variable = filename_to_variable(os.path.splitext(name)[0])
+ output.write('\nconst char {}[] = R"gendelimiter(\n{})gendelimiter";\n'
+ .format(variable, sql))
+
+ output.write(FILE_TO_SQL_STRUCT)
+
+ # Create mapping of filename to variable name for each variable.
+ output.write("\nconst FileToSql kFileToSql[] = {")
+ for name in escaped_sql_outputs.keys():
+ variable = filename_to_variable(os.path.splitext(name)[0])
+ output.write('\n {{"{}", {}}},\n'.format(name, variable))
+ output.write("};\n")
+
+ output.write(NAMESPACE_END)
+
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())