Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
7b9a647
tp: add SubcommandContext to Subcommand interface
LalitMaganti Mar 13, 2026
cd56e92
tp: add common_flags, query subcommand, and dispatcher
LalitMaganti Mar 13, 2026
80f8ca0
tp: regenerate Android.bp and BUILD
LalitMaganti Mar 14, 2026
7c89f91
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-s…
LalitMaganti Mar 16, 2026
e06580d
Merge branch 'dev/lalitm/tp-shell-subcommands' into dev/lalitm/tp-she…
LalitMaganti Mar 16, 2026
59ac55d
tp: add declarative flags, classic-to-modern translation, query subco…
LalitMaganti Mar 16, 2026
886b78e
Revert to clean slate
LalitMaganti Mar 16, 2026
7066a0f
Revert to clean slate
LalitMaganti Mar 16, 2026
5e690d4
Merge branch 'main' of github.com:google/perfetto into dev/lalitm/tp-…
LalitMaganti Mar 16, 2026
3ec2190
tp: add query subcommand with declarative flag system
LalitMaganti Mar 16, 2026
ed6cb89
tp: add interactive and server subcommands
LalitMaganti Mar 16, 2026
9f507aa
tp: add protobuf_full dep to :subcommand target
LalitMaganti Mar 16, 2026
bc7f80c
tp: add summarize and export subcommands
LalitMaganti Mar 16, 2026
dfca0b2
tp: add metrics subcommand
LalitMaganti Mar 16, 2026
3dd395f
tp: add help system, file collision detection, classic tests
LalitMaganti Mar 16, 2026
443b362
tp: fix unused chdir return value warning on gcc8
LalitMaganti Mar 16, 2026
efd76fd
tp: consolidate shell BUILD.gn into single source_set
LalitMaganti Mar 16, 2026
8077852
tp: implement -i (interactive after query) in query subcommand
LalitMaganti Mar 16, 2026
c0b9d77
tp: replace classic Run path with subcommand translation
LalitMaganti Mar 16, 2026
0b548e4
tp: add integration tests for classic-to-subcommand translation
LalitMaganti Mar 16, 2026
c7d97b8
tp: add --perf-file to metrics/summarize subcommands, fix -p flag
LalitMaganti Mar 16, 2026
db75f65
tp: forward --metatrace-categories in classic-to-subcommand translation
LalitMaganti Mar 16, 2026
76f1785
tp: error on -Q with --summary/--run-metrics in classic translation
LalitMaganti Mar 16, 2026
3182a76
tp: add content-sniffing for summary spec format detection
LalitMaganti Mar 16, 2026
2136b2e
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-q…
LalitMaganti Mar 16, 2026
f05092d
Merge branch 'dev/lalitm/tp-shell-query' into dev/lalitm/tp-shell-rep…
LalitMaganti Mar 16, 2026
ab9eaab
Merge branch 'dev/lalitm/tp-shell-repl-serve' into dev/lalitm/tp-shel…
LalitMaganti Mar 16, 2026
fd1fd3e
Merge branch 'dev/lalitm/tp-shell-summarize-export' into dev/lalitm/t…
LalitMaganti Mar 16, 2026
f9f8593
Merge branch 'dev/lalitm/tp-shell-metrics' into dev/lalitm/tp-shell-h…
LalitMaganti Mar 16, 2026
448fd06
Merge branch 'dev/lalitm/tp-shell-help-refactor' into dev/lalitm/tp-s…
LalitMaganti Mar 16, 2026
405729c
Merge branch 'dev/lalitm/tp-shell-build-consolidate' into dev/lalitm/…
LalitMaganti Mar 16, 2026
cbbbfdf
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-q…
LalitMaganti Mar 18, 2026
a6c290a
Merge branch 'dev/lalitm/tp-shell-query' into dev/lalitm/tp-shell-rep…
LalitMaganti Mar 18, 2026
e0a99ff
Merge branch 'dev/lalitm/tp-shell-repl-serve' into dev/lalitm/tp-shel…
LalitMaganti Mar 18, 2026
019330a
Merge branch 'dev/lalitm/tp-shell-summarize-export' into dev/lalitm/t…
LalitMaganti Mar 18, 2026
6cec173
Merge branch 'dev/lalitm/tp-shell-metrics' into dev/lalitm/tp-shell-h…
LalitMaganti Mar 18, 2026
ddc4162
Merge branch 'dev/lalitm/tp-shell-help-refactor' into dev/lalitm/tp-s…
LalitMaganti Mar 18, 2026
8b98bfb
Merge branch 'dev/lalitm/tp-shell-build-consolidate' into dev/lalitm/…
LalitMaganti Mar 18, 2026
0c67950
tp: Disallow copy/move on Subcommand base class
LalitMaganti Mar 18, 2026
ad6394a
Merge branch 'dev/lalitm/tp-shell-query' into dev/lalitm/tp-shell-rep…
LalitMaganti Mar 18, 2026
1bbaccc
Merge branch 'dev/lalitm/tp-shell-repl-serve' into dev/lalitm/tp-shel…
LalitMaganti Mar 18, 2026
186418d
Merge branch 'dev/lalitm/tp-shell-summarize-export' into dev/lalitm/t…
LalitMaganti Mar 18, 2026
b927267
Merge branch 'dev/lalitm/tp-shell-metrics' into dev/lalitm/tp-shell-h…
LalitMaganti Mar 18, 2026
2034162
Merge branch 'dev/lalitm/tp-shell-help-refactor' into dev/lalitm/tp-s…
LalitMaganti Mar 18, 2026
f2bc95a
Merge branch 'dev/lalitm/tp-shell-build-consolidate' into dev/lalitm/…
LalitMaganti Mar 18, 2026
fdd9bbf
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-q…
LalitMaganti Mar 18, 2026
dadfa31
Merge branch 'dev/lalitm/tp-shell-query' into dev/lalitm/tp-shell-rep…
LalitMaganti Mar 18, 2026
580d83f
Merge branch 'dev/lalitm/tp-shell-repl-serve' into dev/lalitm/tp-shel…
LalitMaganti Mar 18, 2026
f8789cc
Merge branch 'dev/lalitm/tp-shell-summarize-export' into dev/lalitm/t…
LalitMaganti Mar 18, 2026
0855280
Merge branch 'dev/lalitm/tp-shell-metrics' into dev/lalitm/tp-shell-h…
LalitMaganti Mar 18, 2026
f5bfc31
Merge branch 'dev/lalitm/tp-shell-help-refactor' into dev/lalitm/tp-s…
LalitMaganti Mar 18, 2026
e143ef5
Merge branch 'dev/lalitm/tp-shell-build-consolidate' into dev/lalitm/…
LalitMaganti Mar 18, 2026
5b52636
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-r…
LalitMaganti Mar 18, 2026
d58f4df
Merge branch 'dev/lalitm/tp-shell-repl-serve' into dev/lalitm/tp-shel…
LalitMaganti Mar 18, 2026
93c1883
Merge branch 'dev/lalitm/tp-shell-summarize-export' into dev/lalitm/t…
LalitMaganti Mar 18, 2026
0a77cff
Merge branch 'dev/lalitm/tp-shell-metrics' into dev/lalitm/tp-shell-h…
LalitMaganti Mar 18, 2026
439303d
Merge branch 'dev/lalitm/tp-shell-help-refactor' into dev/lalitm/tp-s…
LalitMaganti Mar 18, 2026
791c38e
Merge branch 'dev/lalitm/tp-shell-build-consolidate' into dev/lalitm/…
LalitMaganti Mar 18, 2026
24c8690
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-s…
LalitMaganti Mar 18, 2026
c2fc983
Merge branch 'dev/lalitm/tp-shell-summarize-export' into dev/lalitm/t…
LalitMaganti Mar 18, 2026
f6b22f6
Merge branch 'dev/lalitm/tp-shell-metrics' into dev/lalitm/tp-shell-h…
LalitMaganti Mar 18, 2026
0dee54c
Merge branch 'dev/lalitm/tp-shell-help-refactor' into dev/lalitm/tp-s…
LalitMaganti Mar 18, 2026
a933f63
Merge branch 'dev/lalitm/tp-shell-build-consolidate' into dev/lalitm/…
LalitMaganti Mar 18, 2026
b39f7b8
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-s…
LalitMaganti Mar 18, 2026
dbfac73
Merge branch 'dev/lalitm/tp-shell-summarize-export' into dev/lalitm/t…
LalitMaganti Mar 18, 2026
14a2672
Merge branch 'dev/lalitm/tp-shell-metrics' into dev/lalitm/tp-shell-h…
LalitMaganti Mar 18, 2026
f5fb038
Merge branch 'dev/lalitm/tp-shell-help-refactor' into dev/lalitm/tp-s…
LalitMaganti Mar 18, 2026
344c593
Merge branch 'dev/lalitm/tp-shell-build-consolidate' into dev/lalitm/…
LalitMaganti Mar 18, 2026
fc16c83
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-m…
LalitMaganti Mar 18, 2026
020c610
Merge branch 'dev/lalitm/tp-shell-metrics' into dev/lalitm/tp-shell-h…
LalitMaganti Mar 18, 2026
e21132c
Merge branch 'dev/lalitm/tp-shell-help-refactor' into dev/lalitm/tp-s…
LalitMaganti Mar 18, 2026
ba7df75
Merge branch 'dev/lalitm/tp-shell-build-consolidate' into dev/lalitm/…
LalitMaganti Mar 18, 2026
75a5f0a
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-h…
LalitMaganti Mar 18, 2026
edac364
Merge branch 'dev/lalitm/tp-shell-help-refactor' into dev/lalitm/tp-s…
LalitMaganti Mar 18, 2026
9db5b61
Merge branch 'dev/lalitm/tp-shell-build-consolidate' into dev/lalitm/…
LalitMaganti Mar 18, 2026
08bc389
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-b…
LalitMaganti Mar 18, 2026
6ad6113
Merge branch 'dev/lalitm/tp-shell-build-consolidate' into dev/lalitm/…
LalitMaganti Mar 18, 2026
b5a66ab
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-c…
LalitMaganti Mar 18, 2026
599e38c
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-c…
LalitMaganti Mar 18, 2026
c0f8959
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-c…
LalitMaganti Mar 19, 2026
caa0ca0
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-c…
LalitMaganti Mar 19, 2026
453fc8f
Merge remote-tracking branch 'origin/main' into dev/lalitm/tp-shell-c…
LalitMaganti Mar 19, 2026
924b225
tp: add structured query mode to query subcommand
LalitMaganti Mar 19, 2026
a489aad
Merge branch 'dev/lalitm/tp-shell-structured-query-mode' into dev/lal…
LalitMaganti Mar 19, 2026
9abe1ee
tp: fix conflict markers and add structured query translation
LalitMaganti Mar 19, 2026
85119f1
tp: remove legacy structured query codepath, rename flag
LalitMaganti Mar 19, 2026
8ef575e
Merge dev/lalitm/tp-shell-structured-query-mode
LalitMaganti Mar 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion python/generators/diff_tests/test_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,11 @@ def run(self, test: TestCase, trace_path: str) -> TestResult:
try:
cmd = [
self.trace_processor_path,
'query',
'--analyze-trace-proto-content',
'--crop-track-events',
'--extra-checks',
'--structured-query-spec',
'--summary-spec',
spec_file_path,
'--structured-query-id',
test.blueprint.query.query_id,
Expand Down
2 changes: 2 additions & 0 deletions src/trace_processor/shell/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ source_set("shell") {
"../../../protos/perfetto/trace_processor:zero",
"../../base",
"../../base:version",
"../../protozero/text_to_proto:text_to_proto",
"../metrics",
"../rpc",
"../rpc:stdiod",
"../trace_summary",
"../trace_summary:gen_cc_trace_summary_descriptor",
"../util:stdlib",
"../util/deobfuscation:deobfuscator",
"../util/symbolizer",
Expand Down
12 changes: 11 additions & 1 deletion src/trace_processor/shell/metrics_subcommand.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <vector>

#include "perfetto/base/status.h"
#include "perfetto/base/time.h"
#include "perfetto/ext/base/status_macros.h"
#include "src/trace_processor/shell/common_flags.h"
#include "src/trace_processor/shell/interactive.h"
Expand Down Expand Up @@ -65,6 +66,8 @@ std::vector<FlagSpec> MetricsSubcommand::GetFlags() {
[this](const char* v) { raw_extensions_.emplace_back(v); }},
StringFlag("post-query", '\0', "FILE", "SQL file after metrics.",
&post_query_path_),
StringFlag("perf-file", '\0', "FILE", "Write perf timing data to FILE.",
&perf_file_),
BoolFlag("interactive", 'i', "Start interactive shell after metrics.",
&interactive_),
};
Expand Down Expand Up @@ -97,7 +100,8 @@ base::Status MetricsSubcommand::Run(const SubcommandContext& ctx) {
RETURN_IF_ERROR(LoadMetricExtension(tp.get(), extension, pool));
}

RETURN_IF_ERROR(LoadTraceFile(tp.get(), ctx.platform, trace_file).status());
ASSIGN_OR_RETURN(auto t_load,
LoadTraceFile(tp.get(), ctx.platform, trace_file));

// Pre-metrics query.
if (!pre_path_.empty()) {
Expand All @@ -115,12 +119,18 @@ base::Status MetricsSubcommand::Run(const SubcommandContext& ctx) {
format = MetricV1OutputFormat::kJson;
}

base::TimeNanos t_query_start = base::GetWallTimeNs();
RETURN_IF_ERROR(RunMetrics(tp.get(), metrics, format));

// Post-query.
if (!post_query_path_.empty()) {
RETURN_IF_ERROR(RunQueriesFromFile(tp.get(), post_query_path_, true));
}
base::TimeNanos t_query = base::GetWallTimeNs() - t_query_start;

if (!perf_file_.empty()) {
RETURN_IF_ERROR(PrintPerfFile(perf_file_, t_load, t_query));
}

if (interactive_) {
RETURN_IF_ERROR(StartInteractiveShell(
Expand Down
1 change: 1 addition & 0 deletions src/trace_processor/shell/metrics_subcommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class MetricsSubcommand : public Subcommand {
std::string metric_output_;
std::vector<std::string> raw_extensions_;
std::string post_query_path_;
std::string perf_file_;
bool interactive_ = false;
};

Expand Down
140 changes: 134 additions & 6 deletions src/trace_processor/shell/query_subcommand.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@

#include "src/trace_processor/shell/query_subcommand.h"

#include <algorithm>
#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
#include <vector>

#include "perfetto/base/build_config.h"
Expand All @@ -25,10 +29,15 @@
#include "perfetto/base/time.h"
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/status_macros.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/trace_processor/summarizer.h"
#include "src/protozero/text_to_proto/text_to_proto.h"
#include "src/trace_processor/shell/common_flags.h"
#include "src/trace_processor/shell/interactive.h"
#include "src/trace_processor/shell/metatrace.h"
#include "src/trace_processor/shell/query.h"
#include "src/trace_processor/shell/subcommand.h"
#include "src/trace_processor/trace_summary/trace_summary.descriptor.h"

#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <io.h>
Expand All @@ -41,6 +50,63 @@
#endif

namespace perfetto::trace_processor::shell {
namespace {

// Returns true if the file at |path| with |content| should be treated as
// textproto rather than binary proto. Uses the same heuristic as the
// classic codepath: .pb → binary, .textproto → text, otherwise
// content-sniff the first 128 bytes (all printable/whitespace → text).
bool IsTextproto(const std::string& path, const std::string& content) {
if (base::EndsWith(path, ".pb")) {
return false;
}
if (base::EndsWith(path, ".textproto")) {
return true;
}
std::string_view prefix(content.c_str(),
std::min<size_t>(content.size(), 128));
return std::all_of(prefix.begin(), prefix.end(),
[](char c) { return std::isspace(c) || std::isprint(c); });
}

// Reads a TraceSummarySpec file and passes it to |summarizer|, converting
// textproto to binary proto when necessary.
base::Status LoadSpecIntoSummarizer(Summarizer* summarizer,
const std::string& path) {
std::string content;
if (!base::ReadFile(path, &content)) {
return base::ErrStatus("Unable to read spec file %s", path.c_str());
}

const uint8_t* spec_data;
size_t spec_size;
std::vector<uint8_t> binary_proto;
if (IsTextproto(path, content)) {
ASSIGN_OR_RETURN(binary_proto,
protozero::TextToProto(kTraceSummaryDescriptor.data(),
kTraceSummaryDescriptor.size(),
".perfetto.protos.TraceSummarySpec",
"-", std::string_view(content)));
spec_data = binary_proto.data();
spec_size = binary_proto.size();
} else {
spec_data = reinterpret_cast<const uint8_t*>(content.data());
spec_size = content.size();
}

SummarizerUpdateSpecResult update_result;
RETURN_IF_ERROR(summarizer->UpdateSpec(spec_data, spec_size, &update_result));
for (const auto& q : update_result.queries) {
if (q.error.has_value()) {
return base::ErrStatus("Error in query '%s' from spec '%s': %s",
q.query_id.c_str(), path.c_str(),
q.error->c_str());
}
}
return base::OkStatus();
}

} // namespace

const char* QuerySubcommand::name() const {
return "query";
Expand All @@ -63,17 +129,29 @@ SQL can be provided in three ways:
3. From stdin: cat q.sql | tp query trace.pb

Multiple semicolon-separated statements are supported. Use -i to drop into
an interactive shell after the queries complete.)";
an interactive shell after the queries complete.

Advanced (for debugging/testing structured queries):
--structured-query-id ID --summary-spec FILE [...]
Executes a single structured query by ID from the given summary spec
files. The spec files replace -f/stdin/positional SQL. Output is the
query result table.)";
}

std::vector<FlagSpec> QuerySubcommand::GetFlags() {
return {
StringFlag("query-file", 'f', "FILE",
"Read SQL from FILE (use '-' for stdin).", &query_file_),
StringFlag("structured-query-id", '\0', "ID",
"[Advanced] Run a single structured query by ID.",
&structured_query_id_),
{"summary-spec", '\0', true, "FILE",
"[Advanced] Summary spec file for structured queries (repeatable).",
[this](const char* v) { structured_query_specs_.emplace_back(v); }},
BoolFlag("interactive", 'i', "Start interactive shell after query.",
&interactive_),
BoolFlag("wide", 'W', "Double column width for output.", &wide_),
StringFlag("perf-file", 'p', "FILE", "Write perf timing data to FILE.",
StringFlag("perf-file", '\0', "FILE", "Write perf timing data to FILE.",
&perf_file_),
};
}
Expand All @@ -84,6 +162,11 @@ base::Status QuerySubcommand::Run(const SubcommandContext& ctx) {
}
std::string trace_file = ctx.positional_args[0];

// Advanced: structured query mode.
if (!structured_query_id_.empty()) {
return RunStructuredQuery(ctx, trace_file);
}

// Determine SQL source:
// 1. Positional: query trace.pb "SELECT ..."
// 2. File: query -f file.sql trace.pb
Expand Down Expand Up @@ -112,8 +195,6 @@ base::Status QuerySubcommand::Run(const SubcommandContext& ctx) {
ASSIGN_OR_RETURN(auto t_load,
LoadTraceFile(tp.get(), ctx.platform, trace_file));

// If we have a file, read it into sql. After this point, sql always has
// the SQL to execute.
if (!query_file_.empty()) {
if (!base::ReadFile(query_file_, &sql)) {
return base::ErrStatus("query: unable to read file '%s'",
Expand All @@ -128,12 +209,59 @@ base::Status QuerySubcommand::Run(const SubcommandContext& ctx) {
MaybeWriteMetatrace(tp.get(), ctx.global->metatrace_path);
return status;
}

base::TimeNanos t_query = base::GetWallTimeNs() - t_query_start;

if (!perf_file_.empty())
if (!perf_file_.empty()) {
RETURN_IF_ERROR(PrintPerfFile(perf_file_, t_load, t_query));
}

if (interactive_) {
RETURN_IF_ERROR(StartInteractiveShell(
tp.get(),
InteractiveOptions{
wide_ ? 40u : 20u, MetricV1OutputFormat::kNone, {}, {}, nullptr}));
}

RETURN_IF_ERROR(MaybeWriteMetatrace(tp.get(), ctx.global->metatrace_path));
return base::OkStatus();
}

base::Status QuerySubcommand::RunStructuredQuery(
const SubcommandContext& ctx,
const std::string& trace_file) {
if (structured_query_specs_.empty()) {
return base::ErrStatus(
"query: --structured-query-id requires at least one --summary-spec");
}

auto config = BuildConfig(*ctx.global, ctx.platform);
ASSIGN_OR_RETURN(auto tp,
SetupTraceProcessor(*ctx.global, config, ctx.platform));
ASSIGN_OR_RETURN(auto t_load,
LoadTraceFile(tp.get(), ctx.platform, trace_file));

std::unique_ptr<Summarizer> summarizer;
RETURN_IF_ERROR(tp->CreateSummarizer(&summarizer));
for (const auto& path : structured_query_specs_) {
RETURN_IF_ERROR(LoadSpecIntoSummarizer(summarizer.get(), path));
}

base::TimeNanos t_query_start = base::GetWallTimeNs();
SummarizerQueryResult query_result;
RETURN_IF_ERROR(summarizer->Query(structured_query_id_, &query_result));
if (!query_result.exists) {
return base::ErrStatus(
"Structured query ID '%s' not found in the provided spec files",
structured_query_id_.c_str());
}

RETURN_IF_ERROR(
RunQueries(tp.get(), "SELECT * FROM " + query_result.table_name, true));
base::TimeNanos t_query = base::GetWallTimeNs() - t_query_start;

if (!perf_file_.empty()) {
RETURN_IF_ERROR(PrintPerfFile(perf_file_, t_load, t_query));
}
RETURN_IF_ERROR(MaybeWriteMetatrace(tp.get(), ctx.global->metatrace_path));
return base::OkStatus();
}
Expand Down
5 changes: 5 additions & 0 deletions src/trace_processor/shell/query_subcommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@ class QuerySubcommand : public Subcommand {
base::Status Run(const SubcommandContext& ctx) override;

private:
base::Status RunStructuredQuery(const SubcommandContext& ctx,
const std::string& trace_file);

std::string query_file_;
std::string structured_query_id_;
std::vector<std::string> structured_query_specs_;
bool interactive_ = false;
bool wide_ = false;
std::string perf_file_;
Expand Down
41 changes: 36 additions & 5 deletions src/trace_processor/shell/summarize_subcommand.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@

#include "src/trace_processor/shell/summarize_subcommand.h"

#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <optional>
#include <string>
#include <vector>

#include "perfetto/base/status.h"
#include "perfetto/base/time.h"
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/status_macros.h"
#include "perfetto/ext/base/string_utils.h"
Expand All @@ -34,6 +36,29 @@
#include "src/trace_processor/trace_summary/summary.h"

namespace perfetto::trace_processor::shell {
namespace {

TraceSummarySpecBytes::Format GuessSummarySpecFormat(
const std::string& path,
const std::string& content) {
if (base::EndsWith(path, ".pb")) {
return TraceSummarySpecBytes::Format::kBinaryProto;
}
if (base::EndsWith(path, ".textproto")) {
return TraceSummarySpecBytes::Format::kTextProto;
}
// Content-sniffing fallback: if the first 128 bytes are all printable or
// whitespace, assume text proto; otherwise binary.
std::string_view prefix(content.c_str(),
std::min<size_t>(content.size(), 128));
if (std::all_of(prefix.begin(), prefix.end(),
[](char c) { return std::isspace(c) || std::isprint(c); })) {
return TraceSummarySpecBytes::Format::kTextProto;
}
return TraceSummarySpecBytes::Format::kBinaryProto;
}

} // namespace

const char* SummarizeSubcommand::name() const {
return "summarize";
Expand Down Expand Up @@ -70,6 +95,8 @@ std::vector<FlagSpec> SummarizeSubcommand::GetFlags() {
&output_format_),
StringFlag("post-query", '\0', "FILE",
"SQL file to run after summarization.", &post_query_path_),
StringFlag("perf-file", '\0', "FILE", "Write perf timing data to FILE.",
&perf_file_),
BoolFlag("interactive", 'i',
"Start interactive shell after summarization.", &interactive_),
};
Expand All @@ -90,7 +117,8 @@ base::Status SummarizeSubcommand::Run(const SubcommandContext& ctx) {
auto config = BuildConfig(*ctx.global, ctx.platform);
ASSIGN_OR_RETURN(auto tp,
SetupTraceProcessor(*ctx.global, config, ctx.platform));
RETURN_IF_ERROR(LoadTraceFile(tp.get(), ctx.platform, trace_file).status());
ASSIGN_OR_RETURN(auto t_load,
LoadTraceFile(tp.get(), ctx.platform, trace_file));

// Load spec files.
std::vector<std::string> spec_content;
Expand All @@ -105,10 +133,7 @@ base::Status SummarizeSubcommand::Run(const SubcommandContext& ctx) {
std::vector<TraceSummarySpecBytes> specs;
specs.reserve(spec_paths.size());
for (uint32_t i = 0; i < spec_paths.size(); ++i) {
auto format = TraceSummarySpecBytes::Format::kTextProto;
if (base::EndsWith(spec_paths[i], ".pb")) {
format = TraceSummarySpecBytes::Format::kBinaryProto;
}
auto format = GuessSummarySpecFormat(spec_paths[i], spec_content[i]);
specs.emplace_back(TraceSummarySpecBytes{
reinterpret_cast<const uint8_t*>(spec_content[i].data()),
spec_content[i].size(),
Expand All @@ -135,6 +160,7 @@ base::Status SummarizeSubcommand::Run(const SubcommandContext& ctx) {
output_spec.format = TraceSummaryOutputSpec::Format::kTextProto;
}

base::TimeNanos t_query_start = base::GetWallTimeNs();
std::vector<uint8_t> output;
RETURN_IF_ERROR(
tp->Summarize(computation_config, specs, &output, output_spec));
Expand All @@ -146,6 +172,11 @@ base::Status SummarizeSubcommand::Run(const SubcommandContext& ctx) {
if (!post_query_path_.empty()) {
RETURN_IF_ERROR(RunQueriesFromFile(tp.get(), post_query_path_, true));
}
base::TimeNanos t_query = base::GetWallTimeNs() - t_query_start;

if (!perf_file_.empty()) {
RETURN_IF_ERROR(PrintPerfFile(perf_file_, t_load, t_query));
}

if (interactive_) {
RETURN_IF_ERROR(StartInteractiveShell(
Expand Down
Loading
Loading