Merge "Add ability to pivot on depth"
diff --git a/BUILD b/BUILD
index 1c67ffa..567b22c 100644
--- a/BUILD
+++ b/BUILD
@@ -591,6 +591,7 @@
name = "include_perfetto_trace_processor_trace_processor",
srcs = [
"include/perfetto/trace_processor/iterator.h",
+ "include/perfetto/trace_processor/metatrace_config.h",
"include/perfetto/trace_processor/read_trace.h",
"include/perfetto/trace_processor/ref_counted.h",
"include/perfetto/trace_processor/trace_processor.h",
diff --git a/OWNERS b/OWNERS
index 0da623c..dee7d70 100644
--- a/OWNERS
+++ b/OWNERS
@@ -21,6 +21,9 @@
nuskos@google.com
oysteine@google.com
+# UI, Chromium-related metrics and simpler trace processor changes.
+altimin@google.com
+
# Most Android-related metrics.
ilkos@google.com
diff --git a/include/perfetto/trace_processor/BUILD.gn b/include/perfetto/trace_processor/BUILD.gn
index e6e0131..d0dae7f 100644
--- a/include/perfetto/trace_processor/BUILD.gn
+++ b/include/perfetto/trace_processor/BUILD.gn
@@ -15,6 +15,7 @@
source_set("trace_processor") {
sources = [
"iterator.h",
+ "metatrace_config.h",
"read_trace.h",
"ref_counted.h",
"trace_processor.h",
diff --git a/include/perfetto/trace_processor/metatrace_config.h b/include/perfetto/trace_processor/metatrace_config.h
new file mode 100644
index 0000000..6ffe4f0
--- /dev/null
+++ b/include/perfetto/trace_processor/metatrace_config.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2022 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.
+
+#ifndef INCLUDE_PERFETTO_TRACE_PROCESSOR_METATRACE_CONFIG_H_
+#define INCLUDE_PERFETTO_TRACE_PROCESSOR_METATRACE_CONFIG_H_
+
+#include <cstddef>
+
+namespace perfetto {
+namespace trace_processor {
+namespace metatrace {
+
+enum MetatraceCategories {
+ TOPLEVEL = 1 << 0,
+ QUERY = 1 << 1,
+ FUNCTION = 1 << 2,
+
+ NONE = 0,
+ ALL = TOPLEVEL | QUERY | FUNCTION,
+};
+
+struct MetatraceConfig {
+ MetatraceConfig();
+
+ MetatraceCategories categories = MetatraceCategories::ALL;
+ // Requested buffer size. The implemenation may choose to allocate a larger
+ // buffer size for efficiency.
+ size_t override_buffer_size = 0;
+};
+
+} // namespace metatrace
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_TRACE_PROCESSOR_METATRACE_CONFIG_H_
diff --git a/include/perfetto/trace_processor/trace_processor.h b/include/perfetto/trace_processor/trace_processor.h
index adcbca1..ff87e36 100644
--- a/include/perfetto/trace_processor/trace_processor.h
+++ b/include/perfetto/trace_processor/trace_processor.h
@@ -24,6 +24,7 @@
#include "perfetto/base/export.h"
#include "perfetto/trace_processor/basic_types.h"
#include "perfetto/trace_processor/iterator.h"
+#include "perfetto/trace_processor/metatrace_config.h"
#include "perfetto/trace_processor/status.h"
#include "perfetto/trace_processor/trace_processor_storage.h"
@@ -111,19 +112,8 @@
// Metatracing involves tracing trace processor itself to root-cause
// performace issues in trace processor. See |DisableAndReadMetatrace| for
// more information on the format of the metatrace.
- enum MetatraceCategories {
- TOPLEVEL = 1 << 0,
- QUERY = 1 << 1,
- FUNCTION = 1 << 2,
-
- NONE = 0,
- ALL = TOPLEVEL | QUERY | FUNCTION,
- };
- struct MetatraceConfig {
- MetatraceConfig();
-
- MetatraceCategories categories = MetatraceCategories::ALL;
- };
+ using MetatraceConfig = metatrace::MetatraceConfig;
+ using MetatraceCategories = metatrace::MetatraceCategories;
virtual void EnableMetatrace(MetatraceConfig config = {}) = 0;
// Disables "meta-tracing" of trace processor and writes the trace as a
diff --git a/protos/perfetto/trace/perfetto/perfetto_metatrace.proto b/protos/perfetto/trace/perfetto/perfetto_metatrace.proto
index df33b13..56caf9f 100644
--- a/protos/perfetto/trace/perfetto/perfetto_metatrace.proto
+++ b/protos/perfetto/trace/perfetto/perfetto_metatrace.proto
@@ -27,11 +27,19 @@
// For trace processor metatracing.
string event_name = 8;
+ uint64 event_name_iid = 11;
+
string counter_name = 9;
}
message Arg {
- optional string key = 1;
- optional string value = 2;
+ oneof key_or_interned_key {
+ string key = 1;
+ uint64 key_iid = 3;
+ }
+ oneof value_or_interned_value {
+ string value = 2;
+ uint64 value_iid = 4;
+ }
}
// Only when using |event_id|.
@@ -49,4 +57,12 @@
// Args for the event.
repeated Arg args = 7;
+
+ // Interned strings corresponding to the |event_name_iid|, |key_iid| and
+ // |value_iid| above.
+ message InternedString {
+ optional uint64 iid = 1;
+ optional string value = 2;
+ };
+ repeated InternedString interned_strings = 10;
}
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 251c12b..4b7c2a5 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -9812,11 +9812,19 @@
// For trace processor metatracing.
string event_name = 8;
+ uint64 event_name_iid = 11;
+
string counter_name = 9;
}
message Arg {
- optional string key = 1;
- optional string value = 2;
+ oneof key_or_interned_key {
+ string key = 1;
+ uint64 key_iid = 3;
+ }
+ oneof value_or_interned_value {
+ string value = 2;
+ uint64 value_iid = 4;
+ }
}
// Only when using |event_id|.
@@ -9834,6 +9842,14 @@
// Args for the event.
repeated Arg args = 7;
+
+ // Interned strings corresponding to the |event_name_iid|, |key_iid| and
+ // |value_iid| above.
+ message InternedString {
+ optional uint64 iid = 1;
+ optional string value = 2;
+ };
+ repeated InternedString interned_strings = 10;
}
// End of protos/perfetto/trace/perfetto/perfetto_metatrace.proto
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index d815d04..ba96b2a 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -51,6 +51,7 @@
deps = [
"../../gn:default_deps",
"../../include/perfetto/ext/base",
+ "../../include/perfetto/trace_processor",
"../../protos/perfetto/trace_processor:zero",
]
}
diff --git a/src/trace_processor/importers/proto/proto_trace_parser.cc b/src/trace_processor/importers/proto/proto_trace_parser.cc
index 4a8b49e..f348af8 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser.cc
+++ b/src/trace_processor/importers/proto/proto_trace_parser.cc
@@ -63,7 +63,9 @@
raw_chrome_legacy_system_trace_event_id_(
context->storage->InternString("chrome_event.legacy_system_trace")),
raw_chrome_legacy_user_trace_event_id_(
- context->storage->InternString("chrome_event.legacy_user_trace")) {}
+ context->storage->InternString("chrome_event.legacy_user_trace")),
+ missing_metatrace_interned_string_id_(
+ context->storage->InternString("MISSING STRING")) {}
ProtoTraceParser::~ProtoTraceParser() = default;
@@ -317,6 +319,14 @@
StringId name_id = kNullStringId;
char fallback[64];
+ for (auto it = event.interned_strings(); it; ++it) {
+ protos::pbzero::PerfettoMetatrace::InternedString::Decoder interned_string(
+ it->data(), it->size());
+ metatrace_interned_strings_.Insert(
+ interned_string.iid(),
+ context_->storage->InternString(interned_string.value()));
+ }
+
// This function inserts the args from the proto into the args table.
// Args inserted with the same key multiple times are treated as an array:
// this function correctly creates the key and flat key for each arg array.
@@ -327,8 +337,18 @@
std::vector<Arg> interned;
for (auto it = event.args(); it; ++it) {
protos::pbzero::PerfettoMetatrace::Arg::Decoder arg_proto(*it);
- StringId key = context_->storage->InternString(arg_proto.key());
- StringId value = context_->storage->InternString(arg_proto.value());
+ StringId key;
+ if (arg_proto.has_key_iid()) {
+ key = GetMetatraceInternedString(arg_proto.key_iid());
+ } else {
+ key = context_->storage->InternString(arg_proto.key());
+ }
+ StringId value;
+ if (arg_proto.has_value_iid()) {
+ value = GetMetatraceInternedString(arg_proto.value_iid());
+ } else {
+ value = context_->storage->InternString(arg_proto.value());
+ }
interned.emplace_back(key, value);
}
@@ -373,7 +393,8 @@
}
};
- if (event.has_event_id() || event.has_event_name()) {
+ if (event.has_event_id() || event.has_event_name() ||
+ event.has_event_name_iid()) {
if (event.has_event_id()) {
auto eid = event.event_id();
if (eid < metatrace::EVENTS_MAX) {
@@ -382,6 +403,8 @@
sprintf(fallback, "Event %d", eid);
name_id = context_->storage->InternString(fallback);
}
+ } else if (event.has_event_name_iid()) {
+ name_id = GetMetatraceInternedString(event.event_name_iid());
} else {
name_id = context_->storage->InternString(event.event_name());
}
@@ -454,5 +477,12 @@
Variadic::String(id));
}
+StringId ProtoTraceParser::GetMetatraceInternedString(uint64_t iid) {
+ StringId* maybe_id = metatrace_interned_strings_.Find(iid);
+ if (!maybe_id)
+ return missing_metatrace_interned_string_id_;
+ return *maybe_id;
+}
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/importers/proto/proto_trace_parser.h b/src/trace_processor/importers/proto/proto_trace_parser.h
index c3b570b..00b3f48 100644
--- a/src/trace_processor/importers/proto/proto_trace_parser.h
+++ b/src/trace_processor/importers/proto/proto_trace_parser.h
@@ -67,6 +67,8 @@
void ParseTraceConfig(ConstBytes);
private:
+ StringId GetMetatraceInternedString(uint64_t iid);
+
TraceProcessorContext* context_;
const StringId metatrace_id_;
@@ -74,6 +76,9 @@
const StringId raw_chrome_metadata_event_id_;
const StringId raw_chrome_legacy_system_trace_event_id_;
const StringId raw_chrome_legacy_user_trace_event_id_;
+ const StringId missing_metatrace_interned_string_id_;
+
+ base::FlatHashMap<uint64_t, StringId> metatrace_interned_strings_;
};
} // namespace trace_processor
diff --git a/src/trace_processor/sqlite/sqlite_table.cc b/src/trace_processor/sqlite/sqlite_table.cc
index 2e63e59..7103442 100644
--- a/src/trace_processor/sqlite/sqlite_table.cc
+++ b/src/trace_processor/sqlite/sqlite_table.cc
@@ -258,6 +258,7 @@
r->AddArg("cache_hit", std::to_string(cache_hit));
r->AddArg("name", name_);
WriteQueryConstraintsToMetatrace(r, qc_cache_, schema_);
+ r->AddArg("raw_constraints", idxStr);
r->AddArg("argc", std::to_string(argc));
});
diff --git a/src/trace_processor/tp_metatrace.cc b/src/trace_processor/tp_metatrace.cc
index 1169a14..79e6dbc 100644
--- a/src/trace_processor/tp_metatrace.cc
+++ b/src/trace_processor/tp_metatrace.cc
@@ -20,10 +20,34 @@
namespace trace_processor {
namespace metatrace {
+namespace {
+
+using ProtoEnum = protos::pbzero::MetatraceCategories;
+ProtoEnum MetatraceCategoriesToProtoEnum(MetatraceCategories categories) {
+ switch (categories) {
+ case MetatraceCategories::TOPLEVEL:
+ return ProtoEnum::TOPLEVEL;
+ case MetatraceCategories::FUNCTION:
+ return ProtoEnum::FUNCTION;
+ case MetatraceCategories::QUERY:
+ return ProtoEnum::QUERY;
+ case MetatraceCategories::ALL:
+ return ProtoEnum::ALL;
+ case MetatraceCategories::NONE:
+ return ProtoEnum::NONE;
+ }
+ return ProtoEnum::NONE;
+}
+
+} // namespace
+
Category g_enabled_categories = Category::NONE;
-void Enable(Category categories) {
- g_enabled_categories = categories;
+void Enable(MetatraceConfig config) {
+ g_enabled_categories = MetatraceCategoriesToProtoEnum(config.categories);
+ if (config.override_buffer_size) {
+ RingBuffer::GetInstance()->Resize(config.override_buffer_size);
+ }
}
void DisableAndReadBuffer(std::function<void(Record*)> fn) {
@@ -33,19 +57,28 @@
RingBuffer::GetInstance()->ReadAll(fn);
}
-RingBuffer::RingBuffer() {
- static_assert((kCapacity & (kCapacity - 1)) == 0,
+RingBuffer::RingBuffer() : data_(kDefaultCapacity) {
+ static_assert((kDefaultCapacity & (kDefaultCapacity - 1)) == 0,
"Capacity should be a power of 2");
}
+void RingBuffer::Resize(size_t requested_capacity) {
+ size_t actual_capacity = 1;
+ while (actual_capacity < requested_capacity)
+ actual_capacity <<= 1;
+ data_.resize(actual_capacity);
+ start_idx_ = 0;
+ write_idx_ = 0;
+}
+
void RingBuffer::ReadAll(std::function<void(Record*)> fn) {
// Mark as reading so we don't get reentrancy in obtaining new
// trace events.
is_reading_ = true;
- uint64_t start = (write_idx_ - start_idx_) < kCapacity
+ uint64_t start = (write_idx_ - start_idx_) < data_.size()
? start_idx_
- : write_idx_ - kCapacity;
+ : write_idx_ - data_.size();
uint64_t end = write_idx_;
// Increment the write index by kCapacity + 1. This ensures that if
@@ -54,7 +87,7 @@
// This works because of the logic in ~ScopedEntry and
// RingBuffer::HasOverwritten which ensures that we don't overwrite entries
// more than kCapcity elements in the past.
- write_idx_ += kCapacity + 1;
+ write_idx_ += data_.size() + 1;
for (uint64_t i = start; i < end; ++i) {
Record* record = At(i);
diff --git a/src/trace_processor/tp_metatrace.h b/src/trace_processor/tp_metatrace.h
index 9c2cd90..473fff6 100644
--- a/src/trace_processor/tp_metatrace.h
+++ b/src/trace_processor/tp_metatrace.h
@@ -25,6 +25,7 @@
#include "perfetto/ext/base/metatrace_events.h"
#include "perfetto/ext/base/string_view.h"
#include "perfetto/ext/base/thread_checker.h"
+#include "perfetto/trace_processor/metatrace_config.h"
#include "protos/perfetto/trace_processor/metatrace_categories.pbzero.h"
// Trace processor maintains its own base implementation to avoid the
@@ -97,7 +98,7 @@
// is enabled and read one-shot at the end of execution.
class RingBuffer {
public:
- static constexpr uint32_t kCapacity = 256 * 1024;
+ static constexpr uint32_t kDefaultCapacity = 256 * 1024;
RingBuffer();
~RingBuffer() = default;
@@ -115,7 +116,7 @@
return std::make_pair(idx, record);
}
- Record* At(uint64_t idx) { return &data_[idx % kCapacity]; }
+ Record* At(uint64_t idx) { return &data_[idx % data_.size()]; }
void ReadAll(std::function<void(Record*)>);
@@ -130,14 +131,19 @@
// Returns whether the record at the |index| has been overwritten because
// of wraps of the ring buffer.
- bool HasOverwritten(uint64_t index) { return index + kCapacity < write_idx_; }
+ bool HasOverwritten(uint64_t index) {
+ return index + data_.size() < write_idx_;
+ }
+
+ // Request the ring buffer to be resized. Clears the existing buffer.
+ void Resize(size_t requested_capacity);
private:
bool is_reading_ = false;
uint64_t start_idx_ = 0;
uint64_t write_idx_ = 0;
- std::array<Record, kCapacity> data_;
+ std::vector<Record> data_;
PERFETTO_THREAD_CHECKER(thread_checker_)
};
@@ -187,7 +193,7 @@
};
// Enables meta-tracing of trace-processor.
-void Enable(Category categories = Category::ALL);
+void Enable(MetatraceConfig config = {});
// Disables meta-tracing of trace-processor and reads all records.
void DisableAndReadBuffer(std::function<void(Record*)>);
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index dee5e80..3b4ecc4 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -1125,32 +1125,44 @@
return pool_.SerializeAsDescriptorSet();
}
+void TraceProcessorImpl::EnableMetatrace(MetatraceConfig config) {
+ metatrace::Enable(config);
+}
+
namespace {
-using ProtoEnum = protos::pbzero::MetatraceCategories;
-ProtoEnum MetatraceCategoriesToProtoEnum(
- TraceProcessor::MetatraceCategories categories) {
- switch (categories) {
- case TraceProcessor::TOPLEVEL:
- return ProtoEnum::TOPLEVEL;
- case TraceProcessor::FUNCTION:
- return ProtoEnum::FUNCTION;
- case TraceProcessor::QUERY:
- return ProtoEnum::QUERY;
- case TraceProcessor::ALL:
- return ProtoEnum::ALL;
- case TraceProcessor::NONE:
- return ProtoEnum::NONE;
+class StringInterner {
+ public:
+ StringInterner(protos::pbzero::PerfettoMetatrace& event,
+ base::FlatHashMap<std::string, uint64_t>& interned_strings)
+ : event_(event), interned_strings_(interned_strings) {}
+
+ ~StringInterner() {
+ for (const auto& interned_string : new_interned_strings_) {
+ auto* interned_string_proto = event_.add_interned_strings();
+ interned_string_proto->set_iid(interned_string.first);
+ interned_string_proto->set_value(interned_string.second);
+ }
}
- return ProtoEnum::NONE;
-}
+
+ uint64_t InternString(const std::string& str) {
+ uint64_t new_iid = interned_strings_.size();
+ auto insert_result = interned_strings_.Insert(str, new_iid);
+ if (insert_result.second) {
+ new_interned_strings_.emplace_back(new_iid, str);
+ }
+ return *insert_result.first;
+ }
+
+ private:
+ protos::pbzero::PerfettoMetatrace& event_;
+ base::FlatHashMap<std::string, uint64_t>& interned_strings_;
+
+ base::SmallVector<std::pair<uint64_t, std::string>, 16> new_interned_strings_;
+};
} // namespace
-void TraceProcessorImpl::EnableMetatrace(MetatraceConfig config) {
- metatrace::Enable(MetatraceCategoriesToProtoEnum(config.categories));
-}
-
base::Status TraceProcessorImpl::DisableAndReadMetatrace(
std::vector<uint8_t>* trace_proto) {
protozero::HeapBuffered<protos::pbzero::Trace> trace;
@@ -1175,11 +1187,16 @@
}
}
- metatrace::DisableAndReadBuffer([&trace](metatrace::Record* record) {
+ base::FlatHashMap<std::string, uint64_t> interned_strings;
+ metatrace::DisableAndReadBuffer([&trace, &interned_strings](
+ metatrace::Record* record) {
auto packet = trace->add_packet();
packet->set_timestamp(record->timestamp_ns);
auto* evt = packet->set_perfetto_metatrace();
- evt->set_event_name(record->event_name);
+
+ StringInterner interner(*evt, interned_strings);
+
+ evt->set_event_name_iid(interner.InternString(record->event_name));
evt->set_event_duration_ns(record->duration_ns);
evt->set_thread_id(1); // Not really important, just required for the ui.
@@ -1191,11 +1208,11 @@
base::StringSplitter::EmptyTokenMode::ALLOW_EMPTY_TOKENS);
for (; s.Next();) {
auto* arg_proto = evt->add_args();
- arg_proto->set_key(s.cur_token());
+ arg_proto->set_key_iid(interner.InternString(s.cur_token()));
bool has_next = s.Next();
PERFETTO_CHECK(has_next);
- arg_proto->set_value(s.cur_token());
+ arg_proto->set_value_iid(interner.InternString(s.cur_token()));
}
});
*trace_proto = trace.SerializeAsArray();
diff --git a/src/trace_processor/trace_processor_shell.cc b/src/trace_processor/trace_processor_shell.cc
index caee3f7..3341279 100644
--- a/src/trace_processor/trace_processor_shell.cc
+++ b/src/trace_processor/trace_processor_shell.cc
@@ -652,6 +652,31 @@
}
};
+metatrace::MetatraceCategories ParseMetatraceCategories(std::string s) {
+ using Cat = metatrace::MetatraceCategories;
+ std::transform(s.begin(), s.end(), s.begin(),
+ [](unsigned char c) { return std::tolower(c); });
+ base::StringSplitter splitter(s, ',');
+
+ Cat result = Cat::NONE;
+ for (; splitter.Next();) {
+ std::string cur = splitter.cur_token();
+ if (cur == "all" || cur == "*") {
+ result = Cat::ALL;
+ } else if (cur == "toplevel") {
+ result = static_cast<Cat>(result | Cat::TOPLEVEL);
+ } else if (cur == "function") {
+ result = static_cast<Cat>(result | Cat::FUNCTION);
+ } else if (cur == "query") {
+ result = static_cast<Cat>(result | Cat::QUERY);
+ } else {
+ PERFETTO_ELOG("Unknown metatrace category %s", cur.data());
+ exit(1);
+ }
+ }
+ return result;
+}
+
struct CommandLineOptions {
std::string perf_file_path;
std::string query_file_path;
@@ -667,6 +692,9 @@
bool wide = false;
bool force_full_sort = false;
std::string metatrace_path;
+ size_t metatrace_buffer_capacity = 0;
+ metatrace::MetatraceCategories metatrace_categories =
+ metatrace::MetatraceCategories::ALL;
bool dev = false;
bool no_ftrace_raw = false;
};
@@ -713,6 +741,10 @@
text).
-m, --metatrace FILE Enables metatracing of trace processor
writing the resulting trace into FILE.
+ --metatrace-buffer-capacity N Sets metatrace event buffer to capture
+ last N events.
+ --metatrace-categories CATEGORIES A comma-separated list of metatrace
+ categories to enable.
--full-sort Forces the trace processor into performing
a full sort ignoring any windowing
logic.
@@ -745,6 +777,8 @@
OPT_METRIC_EXTENSION,
OPT_DEV,
OPT_NO_FTRACE_RAW,
+ OPT_METATRACE_BUFFER_CAPACITY,
+ OPT_METATRACE_CATEGORIES,
};
static const option long_options[] = {
@@ -758,6 +792,10 @@
{"query-file", required_argument, nullptr, 'q'},
{"export", required_argument, nullptr, 'e'},
{"metatrace", required_argument, nullptr, 'm'},
+ {"metatrace-buffer-capacity", required_argument, nullptr,
+ OPT_METATRACE_BUFFER_CAPACITY},
+ {"metatrace-categories", required_argument, nullptr,
+ OPT_METATRACE_CATEGORIES},
{"run-metrics", required_argument, nullptr, OPT_RUN_METRICS},
{"pre-metrics", required_argument, nullptr, OPT_PRE_METRICS},
{"metrics-output", required_argument, nullptr, OPT_METRICS_OUTPUT},
@@ -867,6 +905,18 @@
continue;
}
+ if (option == OPT_METATRACE_BUFFER_CAPACITY) {
+ command_line_options.metatrace_buffer_capacity =
+ static_cast<size_t>(atoi(optarg));
+ continue;
+ }
+
+ if (option == OPT_METATRACE_CATEGORIES) {
+ command_line_options.metatrace_categories =
+ ParseMetatraceCategories(optarg);
+ continue;
+ }
+
PrintUsage(argv);
exit(option == 'h' ? 0 : 1);
}
@@ -1294,6 +1344,25 @@
return base::OkStatus();
}
+base::Status MaybeWriteMetatrace(const std::string& metatrace_path) {
+ if (metatrace_path.empty()) {
+ return base::OkStatus();
+ }
+ std::vector<uint8_t> serialized;
+ base::Status status = g_tp->DisableAndReadMetatrace(&serialized);
+ if (!status.ok())
+ return status;
+
+ auto file = base::OpenFile(metatrace_path, O_CREAT | O_RDWR | O_TRUNC);
+ if (!file)
+ return base::ErrStatus("Unable to open metatrace file");
+
+ ssize_t res = base::WriteAll(*file, serialized.data(), serialized.size());
+ if (res < 0)
+ return base::ErrStatus("Error while writing metatrace file");
+ return base::OkStatus();
+}
+
base::Status TraceProcessorMain(int argc, char** argv) {
CommandLineOptions options = ParseCommandLineOptions(argc, argv);
@@ -1320,7 +1389,10 @@
// Enable metatracing as soon as possible.
if (!options.metatrace_path.empty()) {
- tp->EnableMetatrace();
+ metatrace::MetatraceConfig metatrace_config;
+ metatrace_config.override_buffer_size = options.metatrace_buffer_capacity;
+ metatrace_config.categories = options.metatrace_categories;
+ tp->EnableMetatrace(metatrace_config);
}
// We load all the metric extensions even when --run-metrics arg is not there,
@@ -1344,14 +1416,8 @@
RETURN_IF_ERROR(PrintStats());
}
-#if PERFETTO_BUILDFLAG(PERFETTO_TP_HTTPD)
- if (options.enable_httpd) {
- RunHttpRPCServer(std::move(tp), options.port_number);
- PERFETTO_FATAL("Should never return");
- }
-#endif
-
#if PERFETTO_HAS_SIGNAL_H()
+ // Set up interrupt signal to allow the user to abort query.
signal(SIGINT, [](int) { g_tp->InterruptQuery(); });
#endif
@@ -1380,7 +1446,12 @@
}
if (!options.query_file_path.empty()) {
- RETURN_IF_ERROR(RunQueries(options.query_file_path, true));
+ base::Status status = RunQueries(options.query_file_path, true);
+ if (!status.ok()) {
+ // Write metatrace if needed before exiting.
+ RETURN_IF_ERROR(MaybeWriteMetatrace(options.metatrace_path));
+ return status;
+ }
}
base::TimeNanos t_query = base::GetWallTimeNs() - t_query_start;
@@ -1388,6 +1459,19 @@
RETURN_IF_ERROR(ExportTraceToDatabase(options.sqlite_file_path));
}
+#if PERFETTO_BUILDFLAG(PERFETTO_TP_HTTPD)
+ if (options.enable_httpd) {
+#if PERFETTO_HAS_SIGNAL_H()
+ // Restore the default signal handler to allow the user to terminate
+ // httpd server via Ctrl-C.
+ signal(SIGINT, SIG_DFL);
+#endif
+
+ RunHttpRPCServer(std::move(tp), options.port_number);
+ PERFETTO_FATAL("Should never return");
+ }
+#endif
+
if (options.launch_shell) {
RETURN_IF_ERROR(StartInteractiveShell(
InteractiveOptions{options.wide ? 40u : 20u, metric_format,
@@ -1396,21 +1480,7 @@
RETURN_IF_ERROR(PrintPerfFile(options.perf_file_path, t_load, t_query));
}
- if (!options.metatrace_path.empty()) {
- std::vector<uint8_t> serialized;
- base::Status status = g_tp->DisableAndReadMetatrace(&serialized);
- if (!status.ok())
- return status;
-
- auto file =
- base::OpenFile(options.metatrace_path, O_CREAT | O_RDWR | O_TRUNC);
- if (!file)
- return base::ErrStatus("Unable to open metatrace file");
-
- ssize_t res = base::WriteAll(*file, serialized.data(), serialized.size());
- if (res < 0)
- return base::ErrStatus("Error while writing metatrace file");
- }
+ RETURN_IF_ERROR(MaybeWriteMetatrace(options.metatrace_path));
return base::OkStatus();
}