#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <cctype>
#include <cinttypes>
#include <functional>
#include <iostream>
#include <optional>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <google/protobuf/compiler/parser.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/text_format.h>
#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
#include "perfetto/base/status.h"
#include "perfetto/base/time.h"
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/flat_hash_map.h"
#include "perfetto/ext/base/getopt.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/status_or.h"
#include "perfetto/ext/base/string_splitter.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/version.h"
#include "perfetto/trace_processor/metatrace_config.h"
#include "perfetto/trace_processor/read_trace.h"
#include "perfetto/trace_processor/trace_processor.h"
#include "src/trace_processor/metrics/all_chrome_metrics.descriptor.h"
#include "src/trace_processor/metrics/all_webview_metrics.descriptor.h"
#include "src/trace_processor/metrics/metrics.descriptor.h"
#include "src/trace_processor/read_trace_internal.h"
#include "src/trace_processor/rpc/stdiod.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
#include "src/trace_processor/util/sql_modules.h"
#include "src/trace_processor/util/status_macros.h"
#include "protos/perfetto/trace_processor/trace_processor.pbzero.h"
#if PERFETTO_BUILDFLAG(PERFETTO_TP_HTTPD)
#include "src/trace_processor/rpc/httpd.h"
#endif
#include "src/profiling/deobfuscator.h"
#include "src/profiling/symbolizer/local_symbolizer.h"
#include "src/profiling/symbolizer/symbolize_database.h"
#include "src/profiling/symbolizer/symbolizer.h"
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
#define PERFETTO_HAS_SIGNAL_H() …
#else
#define PERFETTO_HAS_SIGNAL_H …
#endif
#if PERFETTO_BUILDFLAG(PERFETTO_TP_LINENOISE)
#include <linenoise.h>
#include <pwd.h>
#include <sys/types.h>
#endif
#if PERFETTO_HAS_SIGNAL_H()
#include <signal.h>
#endif
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <io.h>
#define ftruncate …
#else
#include <dirent.h>
#endif
#if PERFETTO_BUILDFLAG(PERFETTO_TP_LINENOISE) && \
!PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <unistd.h>
#endif
namespace perfetto {
namespace trace_processor {
namespace {
TraceProcessor* g_tp;
#if PERFETTO_BUILDFLAG(PERFETTO_TP_LINENOISE)
bool EnsureDir(const std::string& path) {
return base::Mkdir(path) || errno == EEXIST;
}
bool EnsureFile(const std::string& path) {
return base::OpenFile(path, O_RDONLY | O_CREAT, 0644).get() != -1;
}
std::string GetConfigPath() {
const char* homedir = getenv("HOME");
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
if (homedir == nullptr)
homedir = getpwuid(getuid())->pw_dir;
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
if (homedir == nullptr)
homedir = getenv("USERPROFILE");
#endif
if (homedir == nullptr)
return "";
return std::string(homedir) + "/.config";
}
std::string GetPerfettoPath() {
std::string config = GetConfigPath();
if (config.empty())
return "";
return config + "/perfetto";
}
std::string GetHistoryPath() {
std::string perfetto = GetPerfettoPath();
if (perfetto.empty())
return "";
return perfetto + "/.trace_processor_shell_history";
}
void SetupLineEditor() {
linenoiseSetMultiLine(true);
linenoiseHistorySetMaxLen(1000);
bool success = !GetHistoryPath().empty();
success = success && EnsureDir(GetConfigPath());
success = success && EnsureDir(GetPerfettoPath());
success = success && EnsureFile(GetHistoryPath());
success = success && linenoiseHistoryLoad(GetHistoryPath().c_str()) != -1;
if (!success) {
PERFETTO_PLOG("Could not load history from %s", GetHistoryPath().c_str());
}
}
struct LineDeleter {
void operator()(char* p) const {
linenoiseHistoryAdd(p);
linenoiseHistorySave(GetHistoryPath().c_str());
linenoiseFree(p);
}
};
using ScopedLine = std::unique_ptr<char, LineDeleter>;
ScopedLine GetLine(const char* prompt) {
errno = 0;
auto line = ScopedLine(linenoise(prompt));
if (!line && errno == EAGAIN)
return ScopedLine(strdup(""));
return line;
}
#else
void SetupLineEditor() { … }
using ScopedLine = std::unique_ptr<char>;
ScopedLine GetLine(const char* prompt) { … }
#endif
base::Status PrintStats() { … }
base::Status ExportTraceToDatabase(const std::string& output_name) { … }
class ErrorPrinter : public google::protobuf::io::ErrorCollector { … };
std::string BaseName(std::string metric_path) { … }
base::Status RegisterMetric(const std::string& register_metric) { … }
base::Status ParseToFileDescriptorProto(
const std::string& filename,
google::protobuf::FileDescriptorProto* file_desc) { … }
base::Status ExtendMetricsProto(const std::string& extend_metrics_proto,
google::protobuf::DescriptorPool* pool) { … }
enum OutputFormat { … };
struct MetricNameAndPath { … };
base::Status RunMetrics(const std::vector<MetricNameAndPath>& metrics,
OutputFormat format) { … }
void PrintQueryResultInteractively(Iterator* it,
base::TimeNanos t_start,
uint32_t column_width) { … }
struct QueryResult { … };
base::StatusOr<QueryResult> ExtractQueryResult(Iterator* it, bool has_more) { … }
void PrintQueryResultAsCsv(const QueryResult& result, FILE* output) { … }
base::Status RunQueriesWithoutOutput(const std::string& sql_query) { … }
base::Status RunQueriesAndPrintResult(const std::string& sql_query,
FILE* output) { … }
base::Status PrintPerfFile(const std::string& perf_file_path,
base::TimeNanos t_load,
base::TimeNanos t_run) { … }
class MetricExtension { … };
metatrace::MetatraceCategories ParseMetatraceCategories(std::string s) { … }
struct CommandLineOptions { … };
void PrintUsage(char** argv) { … }
CommandLineOptions ParseCommandLineOptions(int argc, char** argv) { … }
void ExtendPoolWithBinaryDescriptor(
google::protobuf::DescriptorPool& pool,
const void* data,
int size,
const std::vector<std::string>& skip_prefixes) { … }
base::Status LoadTrace(const std::string& trace_file_path, double* size_mb) { … }
base::Status RunQueries(const std::string& queries, bool expect_output) { … }
base::Status RunQueriesFromFile(const std::string& query_file_path,
bool expect_output) { … }
base::Status ParseSingleMetricExtensionPath(bool dev,
const std::string& raw_extension,
MetricExtension& parsed_extension) { … }
base::Status CheckForDuplicateMetricExtension(
const std::vector<MetricExtension>& metric_extensions) { … }
base::Status ParseMetricExtensionPaths(
bool dev,
const std::vector<std::string>& raw_metric_extensions,
std::vector<MetricExtension>& metric_extensions) { … }
base::Status IncludeSqlModule(std::string root, bool allow_override) { … }
base::Status LoadOverridenStdlib(std::string root) { … }
base::Status LoadMetricExtensionProtos(const std::string& proto_root,
const std::string& mount_path,
google::protobuf::DescriptorPool& pool) { … }
base::Status LoadMetricExtensionSql(const std::string& sql_root,
const std::string& mount_path) { … }
base::Status LoadMetricExtension(const MetricExtension& extension,
google::protobuf::DescriptorPool& pool) { … }
base::Status PopulateDescriptorPool(
google::protobuf::DescriptorPool& pool,
const std::vector<MetricExtension>& metric_extensions) { … }
base::Status LoadMetrics(const std::string& raw_metric_names,
google::protobuf::DescriptorPool& pool,
std::vector<MetricNameAndPath>& name_and_path) { … }
OutputFormat ParseOutputFormat(const CommandLineOptions& options) { … }
base::Status LoadMetricsAndExtensionsSql(
const std::vector<MetricNameAndPath>& metrics,
const std::vector<MetricExtension>& extensions) { … }
void PrintShellUsage() { … }
struct InteractiveOptions { … };
base::Status StartInteractiveShell(const InteractiveOptions& options) { … }
base::Status MaybeWriteMetatrace(const std::string& metatrace_path) { … }
base::Status MaybeUpdateSqlModules(const CommandLineOptions& options) { … }
base::Status TraceProcessorMain(int argc, char** argv) { … }
}
}
}
int main(int argc, char** argv) { … }