Merge "tp: rewrite OrderedIndexSearch to be truly O(logn)" into main
diff --git a/Android.bp b/Android.bp
index e3312bb..972f828 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2425,6 +2425,7 @@
":perfetto_src_trace_processor_importers_systrace_full",
":perfetto_src_trace_processor_importers_systrace_systrace_line",
":perfetto_src_trace_processor_importers_systrace_systrace_parser",
+ ":perfetto_src_trace_processor_importers_zip_full",
":perfetto_src_trace_processor_lib",
":perfetto_src_trace_processor_metatrace",
":perfetto_src_trace_processor_metrics_metrics",
@@ -12562,6 +12563,14 @@
],
}
+// GN: //src/trace_processor/importers/zip:full
+filegroup {
+ name: "perfetto_src_trace_processor_importers_zip_full",
+ srcs: [
+ "src/trace_processor/importers/zip/zip_trace_reader.cc",
+ ],
+}
+
// GN: //src/trace_processor:lib
filegroup {
name: "perfetto_src_trace_processor_lib",
@@ -13106,13 +13115,16 @@
"src/trace_processor/perfetto_sql/stdlib/deprecated/v42/common/slices.sql",
"src/trace_processor/perfetto_sql/stdlib/deprecated/v42/common/thread_states.sql",
"src/trace_processor/perfetto_sql/stdlib/deprecated/v42/common/timestamps.sql",
+ "src/trace_processor/perfetto_sql/stdlib/gpu/frequency.sql",
"src/trace_processor/perfetto_sql/stdlib/graphs/dominator_tree.sql",
"src/trace_processor/perfetto_sql/stdlib/graphs/partition.sql",
"src/trace_processor/perfetto_sql/stdlib/graphs/search.sql",
"src/trace_processor/perfetto_sql/stdlib/intervals/intersect.sql",
"src/trace_processor/perfetto_sql/stdlib/intervals/overlap.sql",
"src/trace_processor/perfetto_sql/stdlib/linux/cpu_idle.sql",
+ "src/trace_processor/perfetto_sql/stdlib/memory/android/gpu.sql",
"src/trace_processor/perfetto_sql/stdlib/memory/heap_graph_dominator_tree.sql",
+ "src/trace_processor/perfetto_sql/stdlib/memory/linux/general.sql",
"src/trace_processor/perfetto_sql/stdlib/memory/linux/high_watermark.sql",
"src/trace_processor/perfetto_sql/stdlib/memory/linux/process.sql",
"src/trace_processor/perfetto_sql/stdlib/pkvm/hypervisor.sql",
@@ -15086,6 +15098,7 @@
":perfetto_src_trace_processor_importers_systrace_systrace_line",
":perfetto_src_trace_processor_importers_systrace_systrace_parser",
":perfetto_src_trace_processor_importers_systrace_unittests",
+ ":perfetto_src_trace_processor_importers_zip_full",
":perfetto_src_trace_processor_lib",
":perfetto_src_trace_processor_metatrace",
":perfetto_src_trace_processor_metrics_metrics",
@@ -16083,6 +16096,7 @@
":perfetto_src_trace_processor_importers_systrace_full",
":perfetto_src_trace_processor_importers_systrace_systrace_line",
":perfetto_src_trace_processor_importers_systrace_systrace_parser",
+ ":perfetto_src_trace_processor_importers_zip_full",
":perfetto_src_trace_processor_lib",
":perfetto_src_trace_processor_metatrace",
":perfetto_src_trace_processor_metrics_metrics",
@@ -16480,6 +16494,7 @@
":perfetto_src_trace_processor_importers_systrace_full",
":perfetto_src_trace_processor_importers_systrace_systrace_line",
":perfetto_src_trace_processor_importers_systrace_systrace_parser",
+ ":perfetto_src_trace_processor_importers_zip_full",
":perfetto_src_trace_processor_lib",
":perfetto_src_trace_processor_metatrace",
":perfetto_src_trace_processor_metrics_metrics",
diff --git a/BUILD b/BUILD
index 02617c5..537ccc4 100644
--- a/BUILD
+++ b/BUILD
@@ -251,6 +251,7 @@
":src_trace_processor_importers_systrace_full",
":src_trace_processor_importers_systrace_systrace_line",
":src_trace_processor_importers_systrace_systrace_parser",
+ ":src_trace_processor_importers_zip_full",
":src_trace_processor_lib",
":src_trace_processor_metatrace",
":src_trace_processor_metrics_metrics",
@@ -2013,6 +2014,15 @@
],
)
+# GN target: //src/trace_processor/importers/zip:full
+perfetto_filegroup(
+ name = "src_trace_processor_importers_zip_full",
+ srcs = [
+ "src/trace_processor/importers/zip/zip_trace_reader.cc",
+ "src/trace_processor/importers/zip/zip_trace_reader.h",
+ ],
+)
+
# GN target: //src/trace_processor/metrics/sql/android:android
perfetto_filegroup(
name = "src_trace_processor_metrics_sql_android_android",
@@ -2598,6 +2608,14 @@
],
)
+# GN target: //src/trace_processor/perfetto_sql/stdlib/gpu:gpu
+perfetto_filegroup(
+ name = "src_trace_processor_perfetto_sql_stdlib_gpu_gpu",
+ srcs = [
+ "src/trace_processor/perfetto_sql/stdlib/gpu/frequency.sql",
+ ],
+)
+
# GN target: //src/trace_processor/perfetto_sql/stdlib/graphs:graphs
perfetto_filegroup(
name = "src_trace_processor_perfetto_sql_stdlib_graphs_graphs",
@@ -2625,10 +2643,19 @@
],
)
+# GN target: //src/trace_processor/perfetto_sql/stdlib/memory/android:android
+perfetto_filegroup(
+ name = "src_trace_processor_perfetto_sql_stdlib_memory_android_android",
+ srcs = [
+ "src/trace_processor/perfetto_sql/stdlib/memory/android/gpu.sql",
+ ],
+)
+
# GN target: //src/trace_processor/perfetto_sql/stdlib/memory/linux:linux
perfetto_filegroup(
name = "src_trace_processor_perfetto_sql_stdlib_memory_linux_linux",
srcs = [
+ "src/trace_processor/perfetto_sql/stdlib/memory/linux/general.sql",
"src/trace_processor/perfetto_sql/stdlib/memory/linux/high_watermark.sql",
"src/trace_processor/perfetto_sql/stdlib/memory/linux/process.sql",
],
@@ -2746,9 +2773,11 @@
":src_trace_processor_perfetto_sql_stdlib_cpu_cpu",
":src_trace_processor_perfetto_sql_stdlib_cpu_utilization_utilization",
":src_trace_processor_perfetto_sql_stdlib_deprecated_v42_common_common",
+ ":src_trace_processor_perfetto_sql_stdlib_gpu_gpu",
":src_trace_processor_perfetto_sql_stdlib_graphs_graphs",
":src_trace_processor_perfetto_sql_stdlib_intervals_intervals",
":src_trace_processor_perfetto_sql_stdlib_linux_linux",
+ ":src_trace_processor_perfetto_sql_stdlib_memory_android_android",
":src_trace_processor_perfetto_sql_stdlib_memory_linux_linux",
":src_trace_processor_perfetto_sql_stdlib_memory_memory",
":src_trace_processor_perfetto_sql_stdlib_pkvm_pkvm",
@@ -5993,6 +6022,7 @@
":src_trace_processor_importers_systrace_full",
":src_trace_processor_importers_systrace_systrace_line",
":src_trace_processor_importers_systrace_systrace_parser",
+ ":src_trace_processor_importers_zip_full",
":src_trace_processor_lib",
":src_trace_processor_metatrace",
":src_trace_processor_metrics_metrics",
@@ -6172,6 +6202,7 @@
":src_trace_processor_importers_systrace_full",
":src_trace_processor_importers_systrace_systrace_line",
":src_trace_processor_importers_systrace_systrace_parser",
+ ":src_trace_processor_importers_zip_full",
":src_trace_processor_lib",
":src_trace_processor_metatrace",
":src_trace_processor_metrics_metrics",
@@ -6411,6 +6442,7 @@
":src_trace_processor_importers_systrace_full",
":src_trace_processor_importers_systrace_systrace_line",
":src_trace_processor_importers_systrace_systrace_parser",
+ ":src_trace_processor_importers_zip_full",
":src_trace_processor_lib",
":src_trace_processor_metatrace",
":src_trace_processor_metrics_metrics",
diff --git a/CHANGELOG b/CHANGELOG
index 70cb79c..8aae7f5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,10 +1,13 @@
Unreleased:
Tracing service and probes:
- *
+ *
SQL Standard library:
* Added megacycles support to CPU package. Added tables:
`cpu_cycles_per_process`, `cpu_cycles_per_thread` and
`cpu_cycles_per_cpu`.
+ * Improved `memory` package. Added `memory.linux.process`,
+ `memory.linux.high_watermark` and `memory.android.gpu` modules.
+ * Created `gpu` package with `gpu.frequency` module.
* Migrated `sched.utilization` package to `cpu.utilization`.
Trace Processor:
* Added "time to initial display" and "time to full display" metrics to
diff --git a/include/perfetto/ext/base/getopt.h b/include/perfetto/ext/base/getopt.h
index bf993fc..abf8cca 100644
--- a/include/perfetto/ext/base/getopt.h
+++ b/include/perfetto/ext/base/getopt.h
@@ -45,7 +45,7 @@
::perfetto::base::getopt_compat::required_argument;
#else
-#include <getopt.h>
+#include <getopt.h> // IWYU pragma: export
#endif
#endif // INCLUDE_PERFETTO_EXT_BASE_GETOPT_H_
diff --git a/protos/perfetto/common/observable_events.proto b/protos/perfetto/common/observable_events.proto
index 85767a6..b841a0b 100644
--- a/protos/perfetto/common/observable_events.proto
+++ b/protos/perfetto/common/observable_events.proto
@@ -63,6 +63,9 @@
// consumer has no idea of what is the TSID of its own tracing session and
// there is no other good way to plumb it.
optional int64 tracing_session_id = 1;
+
+ // The trigger name of the CLONE_SNAPSHOT trigger which was hit.
+ optional string trigger_name = 2;
}
repeated DataSourceInstanceStateChange instance_state_changes = 1;
diff --git a/src/android_internal/statsd_logging.cc b/src/android_internal/statsd_logging.cc
index a164adf..09b55a2 100644
--- a/src/android_internal/statsd_logging.cc
+++ b/src/android_internal/statsd_logging.cc
@@ -16,12 +16,11 @@
#include "src/android_internal/statsd_logging.h"
-#include <string.h>
+#include <cstdint>
#include <statslog_perfetto.h>
-namespace perfetto {
-namespace android_internal {
+namespace perfetto::android_internal {
void StatsdLogUploadEvent(PerfettoStatsdAtom atom,
int64_t uuid_lsb,
@@ -35,5 +34,4 @@
stats_write(PERFETTO_TRIGGER, static_cast<int32_t>(atom), trigger_name);
}
-} // namespace android_internal
-} // namespace perfetto
+} // namespace perfetto::android_internal
diff --git a/src/android_stats/perfetto_atoms.h b/src/android_stats/perfetto_atoms.h
index 1981a77..6352042 100644
--- a/src/android_stats/perfetto_atoms.h
+++ b/src/android_stats/perfetto_atoms.h
@@ -27,6 +27,8 @@
// Checkpoints inside perfetto_cmd before tracing is finished.
kTraceBegin = 1,
kBackgroundTraceBegin = 2,
+ kCloneTraceBegin = 55,
+ kCloneTriggerTraceBegin = 56,
kOnConnect = 3,
// Guardrails inside perfetto_cmd before tracing is finished.
@@ -105,7 +107,7 @@
// longer supports uploading traces using Dropbox.
// reserved 5, 6, 7;
- // Contained status of guardrail state initalization and upload limit in
+ // Contained status of guardrail state initialization and upload limit in
// perfetto_cmd. Removed as perfetto no longer manages stateful guardrails
// reserved 44, 45, 46;
};
diff --git a/src/android_stats/statsd_logging_helper.cc b/src/android_stats/statsd_logging_helper.cc
index c943027..1f5011a 100644
--- a/src/android_stats/statsd_logging_helper.cc
+++ b/src/android_stats/statsd_logging_helper.cc
@@ -16,10 +16,12 @@
#include "src/android_stats/statsd_logging_helper.h"
+#include <cstdint>
#include <string>
+#include <vector>
#include "perfetto/base/build_config.h"
-#include "perfetto/base/compiler.h"
+#include "src/android_stats/perfetto_atoms.h"
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
@@ -27,8 +29,7 @@
#include "src/android_internal/statsd_logging.h" // nogncheck
#endif
-namespace perfetto {
-namespace android_stats {
+namespace perfetto::android_stats {
// Make sure we don't accidentally log on non-Android tree build. Note that even
// removing this ifdef still doesn't make uploads work on OS_ANDROID.
@@ -75,5 +76,4 @@
const std::vector<std::string>&) {}
#endif
-} // namespace android_stats
-} // namespace perfetto
+} // namespace perfetto::android_stats
diff --git a/src/android_stats/statsd_logging_helper.h b/src/android_stats/statsd_logging_helper.h
index 5f0911f..0ba2d65 100644
--- a/src/android_stats/statsd_logging_helper.h
+++ b/src/android_stats/statsd_logging_helper.h
@@ -18,6 +18,7 @@
#define SRC_ANDROID_STATS_STATSD_LOGGING_HELPER_H_
#include <stdint.h>
+#include <optional>
#include <string>
#include <vector>
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index 2ccd24e..e11a485 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -16,46 +16,47 @@
#include "src/perfetto_cmd/perfetto_cmd.h"
-#include "perfetto/base/build_config.h"
-#include "perfetto/base/proc_utils.h"
-#include "perfetto/ext/base/scoped_file.h"
-#include "perfetto/ext/base/string_splitter.h"
-
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
-// For dup() (and _setmode() on windows).
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
-#include <fcntl.h>
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-
+#include <algorithm>
+#include <array>
#include <atomic>
#include <chrono>
-#include <fstream>
+#include <cinttypes>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
#include <iostream>
#include <iterator>
+#include <memory>
#include <mutex>
+#include <optional>
#include <random>
-#include <sstream>
+#include <string>
#include <thread>
+#include <utility>
+#include <vector>
+#include "perfetto/base/build_config.h"
#include "perfetto/base/compiler.h"
#include "perfetto/base/logging.h"
-#include "perfetto/base/time.h"
-#include "perfetto/ext/base/android_utils.h"
+#include "perfetto/base/proc_utils.h" // IWYU pragma: keep
+#include "perfetto/ext/base/android_utils.h" // IWYU pragma: keep
#include "perfetto/ext/base/ctrl_c_handler.h"
#include "perfetto/ext/base/file_utils.h"
-#include "perfetto/ext/base/getopt.h"
+#include "perfetto/ext/base/getopt.h" // IWYU pragma: keep
#include "perfetto/ext/base/no_destructor.h"
#include "perfetto/ext/base/pipe.h"
+#include "perfetto/ext/base/scoped_file.h"
+#include "perfetto/ext/base/string_splitter.h"
+#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/string_view.h"
-#include "perfetto/ext/base/temp_file.h"
+#include "perfetto/ext/base/thread_task_runner.h"
#include "perfetto/ext/base/thread_utils.h"
#include "perfetto/ext/base/utils.h"
#include "perfetto/ext/base/uuid.h"
@@ -64,11 +65,14 @@
#include "perfetto/ext/traced/traced.h"
#include "perfetto/ext/tracing/core/basic_types.h"
#include "perfetto/ext/tracing/core/trace_packet.h"
-#include "perfetto/protozero/proto_utils.h"
-#include "perfetto/tracing/core/data_source_descriptor.h"
+#include "perfetto/ext/tracing/core/tracing_service.h"
+#include "perfetto/ext/tracing/ipc/consumer_ipc_client.h"
+#include "perfetto/tracing/core/flush_flags.h"
+#include "perfetto/tracing/core/forward_decls.h"
#include "perfetto/tracing/core/trace_config.h"
-#include "perfetto/tracing/core/tracing_service_state.h"
#include "perfetto/tracing/default_socket.h"
+#include "protos/perfetto/common/data_source_descriptor.gen.h"
+#include "src/android_stats/perfetto_atoms.h"
#include "src/android_stats/statsd_logging_helper.h"
#include "src/perfetto_cmd/bugreport_path.h"
#include "src/perfetto_cmd/config.h"
@@ -81,6 +85,14 @@
#include "protos/perfetto/common/tracing_service_state.gen.h"
#include "protos/perfetto/common/track_event_descriptor.gen.h"
+// For dup() (and _setmode() on windows).
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <fcntl.h>
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
namespace perfetto {
namespace {
@@ -92,7 +104,7 @@
class LoggingErrorReporter : public ErrorReporter {
public:
LoggingErrorReporter(std::string file_name, const char* config)
- : file_name_(file_name), config_(config) {}
+ : file_name_(std::move(file_name)), config_(config) {}
void AddError(size_t row,
size_t column,
@@ -1014,7 +1026,14 @@
std::this_thread::sleep_for(std::chrono::milliseconds(dist(minstd)));
}
- if (trace_config_->trigger_config().trigger_timeout_ms() == 0) {
+ if (clone_tsid_) {
+ if (snapshot_trigger_name_.empty()) {
+ LogUploadEvent(PerfettoStatsdAtom::kCloneTraceBegin);
+ } else {
+ LogUploadEvent(PerfettoStatsdAtom::kCloneTriggerTraceBegin,
+ snapshot_trigger_name_);
+ }
+ } else if (trace_config_->trigger_config().trigger_timeout_ms() == 0) {
LogUploadEvent(PerfettoStatsdAtom::kTraceBegin);
} else {
LogUploadEvent(PerfettoStatsdAtom::kBackgroundTraceBegin);
@@ -1533,11 +1552,15 @@
}
if (observable_events.has_clone_trigger_hit()) {
int64_t tsid = observable_events.clone_trigger_hit().tracing_session_id();
- OnCloneSnapshotTriggerReceived(static_cast<TracingSessionID>(tsid));
+ std::string trigger_name =
+ observable_events.clone_trigger_hit().trigger_name();
+ OnCloneSnapshotTriggerReceived(static_cast<TracingSessionID>(tsid),
+ std::move(trigger_name));
}
}
-void PerfettoCmd::OnCloneSnapshotTriggerReceived(TracingSessionID tsid) {
+void PerfettoCmd::OnCloneSnapshotTriggerReceived(TracingSessionID tsid,
+ std::string trigger_name) {
std::string cmdline;
cmdline.reserve(128);
ArgsAppend(&cmdline, "perfetto");
@@ -1555,13 +1578,15 @@
} else {
PERFETTO_FATAL("Cannot use CLONE_SNAPSHOT with the current cmdline args");
}
- CloneSessionOnThread(tsid, cmdline, kSingleExtraThread, nullptr);
+ CloneSessionOnThread(tsid, cmdline, kSingleExtraThread,
+ std::move(trigger_name), nullptr);
}
void PerfettoCmd::CloneSessionOnThread(
TracingSessionID tsid,
const std::string& cmdline,
CloneThreadMode thread_mode,
+ std::string trigger_name,
std::function<void()> on_clone_callback) {
PERFETTO_DLOG("Creating snapshot for tracing session %" PRIu64, tsid);
@@ -1583,7 +1608,7 @@
std::string trace_config_copy = trace_config_->SerializeAsString();
snapshot_threads_.back().PostTask(
- [tsid, cmdline, trace_config_copy, on_clone_callback] {
+ [tsid, cmdline, trace_config_copy, trigger_name, on_clone_callback] {
int argc = 0;
char* argv[32];
// `splitter` needs to live on the stack for the whole scope as it owns
@@ -1595,6 +1620,7 @@
}
perfetto::PerfettoCmd cmd;
cmd.snapshot_config_ = std::move(trace_config_copy);
+ cmd.snapshot_trigger_name_ = std::move(trigger_name);
cmd.on_session_cloned_ = on_clone_callback;
auto cmdline_res = cmd.ParseCmdlineAndMaybeDaemonize(argc, argv);
PERFETTO_CHECK(!cmdline_res.has_value()); // No daemonization expected.
@@ -1686,7 +1712,7 @@
ArgsAppend(&cmdline, "--clone-for-bugreport");
ArgsAppend(&cmdline, "--out");
ArgsAppend(&cmdline, out_path);
- CloneSessionOnThread(it->tsid, cmdline, kNewThreadPerRequest, sync_fn);
+ CloneSessionOnThread(it->tsid, cmdline, kNewThreadPerRequest, "", sync_fn);
} // for(sessions)
PERFETTO_DLOG("Issuing %zu CloneSession requests", num_sessions);
@@ -1720,6 +1746,15 @@
android_stats::MaybeLogUploadEvent(atom, uuid.lsb(), uuid.msb());
}
+void PerfettoCmd::LogUploadEvent(PerfettoStatsdAtom atom,
+ const std::string& trigger_name) {
+ if (!statsd_logging_)
+ return;
+ base::Uuid uuid(uuid_);
+ android_stats::MaybeLogUploadEvent(atom, uuid.lsb(), uuid.msb(),
+ trigger_name);
+}
+
void PerfettoCmd::LogTriggerEvents(
PerfettoTriggerAtom atom,
const std::vector<std::string>& trigger_names) {
diff --git a/src/perfetto_cmd/perfetto_cmd.h b/src/perfetto_cmd/perfetto_cmd.h
index 844afaf..160a701 100644
--- a/src/perfetto_cmd/perfetto_cmd.h
+++ b/src/perfetto_cmd/perfetto_cmd.h
@@ -17,8 +17,7 @@
#ifndef SRC_PERFETTO_CMD_PERFETTO_CMD_H_
#define SRC_PERFETTO_CMD_PERFETTO_CMD_H_
-#include <time.h>
-
+#include <cstdint>
#include <functional>
#include <list>
#include <memory>
@@ -32,9 +31,12 @@
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/thread_task_runner.h"
#include "perfetto/ext/base/unix_task_runner.h"
+#include "perfetto/ext/base/uuid.h"
#include "perfetto/ext/base/weak_ptr.h"
+#include "perfetto/ext/tracing/core/basic_types.h"
#include "perfetto/ext/tracing/core/consumer.h"
#include "perfetto/ext/tracing/ipc/consumer_ipc_client.h"
+#include "perfetto/tracing/core/forward_decls.h"
#include "src/android_stats/perfetto_atoms.h"
#include "src/perfetto_cmd/packet_writer.h"
@@ -86,6 +88,7 @@
void CloneSessionOnThread(TracingSessionID,
const std::string& cmdline, // \0 separated.
CloneThreadMode,
+ std::string clone_trigger_name,
std::function<void()> on_clone_callback);
void OnTimeout();
bool is_detach() const { return !detach_key_.empty(); }
@@ -126,7 +129,8 @@
// will have no effect.
void NotifyBgProcessPipe(BgProcessStatus status);
- void OnCloneSnapshotTriggerReceived(TracingSessionID);
+ void OnCloneSnapshotTriggerReceived(TracingSessionID,
+ std::string trigger_name);
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
static base::ScopedFile CreateUnlinkedTmpFile();
@@ -135,6 +139,7 @@
void ReportTraceToAndroidFrameworkOrCrash();
#endif
void LogUploadEvent(PerfettoStatsdAtom atom);
+ void LogUploadEvent(PerfettoStatsdAtom atom, const std::string& trigger_name);
void LogTriggerEvents(PerfettoTriggerAtom atom,
const std::vector<std::string>& trigger_names);
@@ -185,6 +190,7 @@
std::list<base::ThreadTaskRunner> snapshot_threads_;
int snapshot_count_ = 0;
std::string snapshot_config_;
+ std::string snapshot_trigger_name_;
base::WeakPtrFactory<PerfettoCmd> weak_factory_{this};
};
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 2a61ec6..802f9bc 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -177,6 +177,7 @@
"importers/proto:full",
"importers/proto:minimal",
"importers/systrace:full",
+ "importers/zip:full",
"metrics",
"perfetto_sql/engine",
"perfetto_sql/intrinsics/functions",
diff --git a/src/trace_processor/forwarding_trace_parser.cc b/src/trace_processor/forwarding_trace_parser.cc
index 369917d..a3b6a7f 100644
--- a/src/trace_processor/forwarding_trace_parser.cc
+++ b/src/trace_processor/forwarding_trace_parser.cc
@@ -29,6 +29,7 @@
#include "src/trace_processor/trace_reader_registry.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "src/trace_processor/util/status_macros.h"
+#include "src/trace_processor/util/trace_type.h"
namespace perfetto {
namespace trace_processor {
@@ -53,7 +54,7 @@
case kSystraceTraceType:
case kGzipTraceType:
case kCtraceTraceType:
- case kAndroidBugreportTraceType:
+ case kZipFile:
return std::nullopt;
case kPerfDataTraceType:
@@ -102,26 +103,11 @@
reader_ = std::move(*reader_or);
PERFETTO_DLOG("%s detected", ToString(trace_type));
- std::optional<TraceSorter::SortingMode> minimum_sorting_mode =
- GetMinimumSortingMode(trace_type, *context_);
+ UpdateSorterForTraceType(trace_type);
- if (minimum_sorting_mode.has_value()) {
- if (!context_->sorter) {
- context_->sorter.reset(new TraceSorter(context_, *minimum_sorting_mode));
- }
-
- switch (context_->sorter->sorting_mode()) {
- case TraceSorter::SortingMode::kDefault:
- PERFETTO_CHECK(minimum_sorting_mode ==
- TraceSorter::SortingMode::kDefault);
- break;
- case TraceSorter::SortingMode::kFullSort:
- break;
- }
- }
-
- // TODO(carlscab) Make sure kProtoTraceType and kSystraceTraceType are parsed
- // first so that we do not get issues with SetPidZeroIsUpidZeroIdleProcess()
+ // TODO(b/334978369) Make sure kProtoTraceType and kSystraceTraceType are
+ // parsed first so that we do not get issues with
+ // SetPidZeroIsUpidZeroIdleProcess()
if (trace_type == kProtoTraceType || trace_type == kSystraceTraceType) {
context_->process_tracker->SetPidZeroIsUpidZeroIdleProcess();
}
@@ -129,6 +115,27 @@
return base::OkStatus();
}
+void ForwardingTraceParser::UpdateSorterForTraceType(TraceType trace_type) {
+ std::optional<TraceSorter::SortingMode> minimum_sorting_mode =
+ GetMinimumSortingMode(trace_type, *context_);
+ if (!minimum_sorting_mode.has_value()) {
+ return;
+ }
+
+ if (!context_->sorter) {
+ context_->sorter.reset(new TraceSorter(context_, *minimum_sorting_mode));
+ }
+
+ switch (context_->sorter->sorting_mode()) {
+ case TraceSorter::SortingMode::kDefault:
+ PERFETTO_CHECK(minimum_sorting_mode ==
+ TraceSorter::SortingMode::kDefault);
+ break;
+ case TraceSorter::SortingMode::kFullSort:
+ break;
+ }
+}
+
base::Status ForwardingTraceParser::Parse(TraceBlobView blob) {
// If this is the first Parse() call, guess the trace type and create the
// appropriate parser.
diff --git a/src/trace_processor/forwarding_trace_parser.h b/src/trace_processor/forwarding_trace_parser.h
index 1f32938..12fe447 100644
--- a/src/trace_processor/forwarding_trace_parser.h
+++ b/src/trace_processor/forwarding_trace_parser.h
@@ -20,6 +20,7 @@
#include "perfetto/base/status.h"
#include "perfetto/trace_processor/trace_blob_view.h"
#include "src/trace_processor/importers/common/chunked_trace_reader.h"
+#include "src/trace_processor/util/trace_type.h"
namespace perfetto {
namespace trace_processor {
@@ -37,6 +38,7 @@
private:
base::Status Init(const TraceBlobView&);
+ void UpdateSorterForTraceType(TraceType trace_type);
TraceProcessorContext* const context_;
std::unique_ptr<ChunkedTraceReader> reader_;
};
diff --git a/src/trace_processor/importers/android_bugreport/android_bugreport_parser.cc b/src/trace_processor/importers/android_bugreport/android_bugreport_parser.cc
index 87aa0f5..1d46efc 100644
--- a/src/trace_processor/importers/android_bugreport/android_bugreport_parser.cc
+++ b/src/trace_processor/importers/android_bugreport/android_bugreport_parser.cc
@@ -17,54 +17,90 @@
#include "src/trace_processor/importers/android_bugreport/android_bugreport_parser.h"
#include <algorithm>
+#include <cstddef>
#include <optional>
+#include <string>
+#include <vector>
#include "perfetto/base/logging.h"
+#include "perfetto/base/status.h"
#include "perfetto/ext/base/string_utils.h"
-#include "perfetto/trace_processor/trace_blob.h"
-#include "perfetto/trace_processor/trace_blob_view.h"
+#include "protos/perfetto/common/builtin_clock.pbzero.h"
#include "src/trace_processor/importers/android_bugreport/android_log_parser.h"
#include "src/trace_processor/importers/common/clock_tracker.h"
#include "src/trace_processor/importers/common/process_tracker.h"
-#include "src/trace_processor/importers/common/track_tracker.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "src/trace_processor/util/zip_reader.h"
-#include "protos/perfetto/common/builtin_clock.pbzero.h"
-
namespace perfetto {
namespace trace_processor {
+namespace {
+const util::ZipFile* FindBugReportFile(
+ const std::vector<util::ZipFile>& zip_file_entries) {
+ for (const auto& zf : zip_file_entries) {
+ if (base::StartsWith(zf.name(), "bugreport-") &&
+ base::EndsWith(zf.name(), ".txt")) {
+ return &zf;
+ }
+ }
+ return nullptr;
+}
-AndroidBugreportParser::AndroidBugreportParser(TraceProcessorContext* ctx)
- : context_(ctx), zip_reader_(new util::ZipReader()) {}
+std::optional<int32_t> ExtractYearFromBugReportFilename(
+ const std::string& filename) {
+ // Typical name: "bugreport-product-TP1A.220623.001-2022-06-24-16-24-37.txt".
+ auto year_str =
+ filename.substr(filename.size() - strlen("2022-12-31-23-59-00.txt"), 4);
+ return base::StringToInt32(year_str);
+}
+
+} // namespace
+
+// static
+bool AndroidBugreportParser::IsAndroidBugReport(
+ const std::vector<util::ZipFile>& zip_file_entries) {
+ if (const util::ZipFile* file = FindBugReportFile(zip_file_entries);
+ file != nullptr) {
+ return ExtractYearFromBugReportFilename(file->name()).has_value();
+ }
+
+ return false;
+}
+
+// static
+util::Status AndroidBugreportParser::Parse(
+ TraceProcessorContext* context,
+ std::vector<util::ZipFile> zip_file_entries) {
+ return AndroidBugreportParser(context, std::move(zip_file_entries))
+ .ParseImpl();
+}
+
+AndroidBugreportParser::AndroidBugreportParser(
+ TraceProcessorContext* context,
+ std::vector<util::ZipFile> zip_file_entries)
+ : context_(context), zip_file_entries_(std::move(zip_file_entries)) {}
AndroidBugreportParser::~AndroidBugreportParser() = default;
-util::Status AndroidBugreportParser::Parse(TraceBlobView tbv) {
- if (!first_chunk_seen_) {
- first_chunk_seen_ = true;
- // All logs in Android bugreports use wall time (which creates problems
- // in case of early boot events before NTP kicks in, which get emitted as
- // 1970), but that is the state of affairs.
- context_->clock_tracker->SetTraceTimeClock(
- protos::pbzero::BUILTIN_CLOCK_REALTIME);
- }
-
- return zip_reader_->Parse(tbv.data(), tbv.size());
-}
-
-void AndroidBugreportParser::NotifyEndOfFile() {
+util::Status AndroidBugreportParser::ParseImpl() {
+ // All logs in Android bugreports use wall time (which creates problems
+ // in case of early boot events before NTP kicks in, which get emitted as
+ // 1970), but that is the state of affairs.
+ context_->clock_tracker->SetTraceTimeClock(
+ protos::pbzero::BUILTIN_CLOCK_REALTIME);
if (!DetectYearAndBrFilename()) {
context_->storage->IncrementStats(stats::android_br_parse_errors);
- return;
+ return base::ErrStatus("Zip file does not contain bugreport file.");
}
ParsePersistentLogcat();
ParseDumpstateTxt();
SortAndStoreLogcat();
+ return base::OkStatus();
}
void AndroidBugreportParser::ParseDumpstateTxt() {
+ PERFETTO_CHECK(dumpstate_file_);
// Dumpstate is organized in a two level hierarchy, beautifully flattened into
// one text file with load bearing ----- markers:
// 1. Various dumpstate sections, examples:
@@ -95,80 +131,81 @@
// Here we put each line in a dedicated table, android_dumpstate, keeping
// track of the dumpstate `section` and dumpsys `service`.
AndroidLogParser log_parser(br_year_, context_->storage.get());
- util::ZipFile* zf = zip_reader_->Find(dumpstate_fname_);
StringId section_id = StringId::Null(); // The current dumpstate section.
StringId service_id = StringId::Null(); // The current dumpsys service.
static constexpr size_t npos = base::StringView::npos;
enum { OTHER = 0, DUMPSYS, LOG } cur_sect = OTHER;
- zf->DecompressLines([&](const std::vector<base::StringView>& lines) {
- // Optimization for ParseLogLines() below. Avoids ctor/dtor-ing a new vector
- // on every line.
- std::vector<base::StringView> log_line(1);
- for (const base::StringView& line : lines) {
- if (line.StartsWith("------ ") && line.EndsWith(" ------")) {
- // These lines mark the beginning and end of dumpstate sections:
- // ------ DUMPSYS CRITICAL (/system/bin/dumpsys) ------
- // ------ 0.356s was the duration of 'DUMPSYS CRITICAL' ------
- base::StringView section = line.substr(7);
- section = section.substr(0, section.size() - 7);
- bool end_marker = section.find("was the duration of") != npos;
- service_id = StringId::Null();
- if (end_marker) {
- section_id = StringId::Null();
- } else {
- section_id = context_->storage->InternString(section);
- cur_sect = OTHER;
- if (section.StartsWith("DUMPSYS")) {
- cur_sect = DUMPSYS;
- } else if (section.StartsWith("SYSTEM LOG") ||
- section.StartsWith("EVENT LOG") ||
- section.StartsWith("RADIO LOG")) {
- // KERNEL LOG is deliberately omitted because SYSTEM LOG is a
- // superset. KERNEL LOG contains all dupes.
- cur_sect = LOG;
- } else if (section.StartsWith("BLOCK STAT")) {
- // Coalesce all the block stats into one section. Otherwise they
- // pollute the table with one section per block device.
- section_id = context_->storage->InternString("BLOCK STAT");
+ dumpstate_file_->DecompressLines(
+ [&](const std::vector<base::StringView>& lines) {
+ // Optimization for ParseLogLines() below. Avoids ctor/dtor-ing a new
+ // vector on every line.
+ std::vector<base::StringView> log_line(1);
+ for (const base::StringView& line : lines) {
+ if (line.StartsWith("------ ") && line.EndsWith(" ------")) {
+ // These lines mark the beginning and end of dumpstate sections:
+ // ------ DUMPSYS CRITICAL (/system/bin/dumpsys) ------
+ // ------ 0.356s was the duration of 'DUMPSYS CRITICAL' ------
+ base::StringView section = line.substr(7);
+ section = section.substr(0, section.size() - 7);
+ bool end_marker = section.find("was the duration of") != npos;
+ service_id = StringId::Null();
+ if (end_marker) {
+ section_id = StringId::Null();
+ } else {
+ section_id = context_->storage->InternString(section);
+ cur_sect = OTHER;
+ if (section.StartsWith("DUMPSYS")) {
+ cur_sect = DUMPSYS;
+ } else if (section.StartsWith("SYSTEM LOG") ||
+ section.StartsWith("EVENT LOG") ||
+ section.StartsWith("RADIO LOG")) {
+ // KERNEL LOG is deliberately omitted because SYSTEM LOG is a
+ // superset. KERNEL LOG contains all dupes.
+ cur_sect = LOG;
+ } else if (section.StartsWith("BLOCK STAT")) {
+ // Coalesce all the block stats into one section. Otherwise they
+ // pollute the table with one section per block device.
+ section_id = context_->storage->InternString("BLOCK STAT");
+ }
+ }
+ continue;
}
+ // Skip end marker lines for dumpsys sections.
+ if (cur_sect == DUMPSYS && line.StartsWith("--------- ") &&
+ line.find("was the duration of dumpsys") != npos) {
+ service_id = StringId::Null();
+ continue;
+ }
+ if (cur_sect == DUMPSYS && service_id.is_null() &&
+ line.StartsWith(
+ "----------------------------------------------")) {
+ continue;
+ }
+ if (cur_sect == DUMPSYS && line.StartsWith("DUMP OF SERVICE")) {
+ // DUMP OF SERVICE [CRITICAL|HIGH] ServiceName:
+ base::StringView svc = line.substr(line.rfind(' ') + 1);
+ svc = svc.substr(0, svc.size() - 1);
+ service_id = context_->storage->InternString(svc);
+ } else if (cur_sect == LOG) {
+ // Parse the non-persistent logcat and append to `log_events_`,
+ // together with the persistent one previously parsed by
+ // ParsePersistentLogcat(). Skips entries that are already seen in
+ // the persistent logcat, handling us vs ms truncation.
+ PERFETTO_DCHECK(log_line.size() == 1);
+ log_line[0] = line;
+ log_parser.ParseLogLines(log_line, &log_events_,
+ log_events_last_sorted_idx_);
+ }
+
+ if (build_fpr_.empty() && line.StartsWith("Build fingerprint:")) {
+ build_fpr_ = line.substr(20, line.size() - 20).ToStdString();
+ }
+
+ // Append the line to the android_dumpstate table.
+ context_->storage->mutable_android_dumpstate_table()->Insert(
+ {section_id, service_id, context_->storage->InternString(line)});
}
- continue;
- }
- // Skip end marker lines for dumpsys sections.
- if (cur_sect == DUMPSYS && line.StartsWith("--------- ") &&
- line.find("was the duration of dumpsys") != npos) {
- service_id = StringId::Null();
- continue;
- }
- if (cur_sect == DUMPSYS && service_id.is_null() &&
- line.StartsWith("----------------------------------------------")) {
- continue;
- }
- if (cur_sect == DUMPSYS && line.StartsWith("DUMP OF SERVICE")) {
- // DUMP OF SERVICE [CRITICAL|HIGH] ServiceName:
- base::StringView svc = line.substr(line.rfind(' ') + 1);
- svc = svc.substr(0, svc.size() - 1);
- service_id = context_->storage->InternString(svc);
- } else if (cur_sect == LOG) {
- // Parse the non-persistent logcat and append to `log_events_`, together
- // with the persistent one previously parsed by ParsePersistentLogcat().
- // Skips entries that are already seen in the persistent logcat,
- // handling us vs ms truncation.
- PERFETTO_DCHECK(log_line.size() == 1);
- log_line[0] = line;
- log_parser.ParseLogLines(log_line, &log_events_,
- log_events_last_sorted_idx_);
- }
-
- if (build_fpr_.empty() && line.StartsWith("Build fingerprint:")) {
- build_fpr_ = line.substr(20, line.size() - 20).ToStdString();
- }
-
- // Append the line to the android_dumpstate table.
- context_->storage->mutable_android_dumpstate_table()->Insert(
- {section_id, service_id, context_->storage->InternString(line)});
- }
- });
+ });
}
void AndroidBugreportParser::ParsePersistentLogcat() {
@@ -182,22 +219,23 @@
// Sort files to ease the job of the subsequent line-based sort. Unfortunately
// lines within each file are not 100% timestamp-ordered, due to things like
// kernel messages where log time != event time.
- std::vector<std::pair<uint64_t, std::string>> log_paths;
- for (const util::ZipFile& zf : zip_reader_->files()) {
+ std::vector<std::pair<uint64_t, const util::ZipFile*>> log_files;
+ for (const util::ZipFile& zf : zip_file_entries_) {
if (base::StartsWith(zf.name(), "FS/data/misc/logd/logcat") &&
!base::EndsWith(zf.name(), "logcat.id")) {
- log_paths.emplace_back(std::make_pair(zf.GetDatetime(), zf.name()));
+ log_files.push_back(std::make_pair(zf.GetDatetime(), &zf));
}
}
- std::sort(log_paths.begin(), log_paths.end());
+
+ std::sort(log_files.begin(), log_files.end());
// Push all events into the AndroidLogParser. It will take care of string
// interning into the pool. Appends entries into `log_events`.
- for (const auto& kv : log_paths) {
- util::ZipFile* zf = zip_reader_->Find(kv.second);
- zf->DecompressLines([&](const std::vector<base::StringView>& lines) {
- log_parser.ParseLogLines(lines, &log_events_);
- });
+ for (const auto& log_file : log_files) {
+ log_file.second->DecompressLines(
+ [&](const std::vector<base::StringView>& lines) {
+ log_parser.ParseLogLines(lines, &log_events_);
+ });
}
// Do an initial sorting pass. This is not the final sorting because we
@@ -230,30 +268,20 @@
// This is obviously bugged for cases of bugreports collected across new year
// but we'll live with that.
bool AndroidBugreportParser::DetectYearAndBrFilename() {
- const util::ZipFile* br_file = nullptr;
- for (const auto& zf : zip_reader_->files()) {
- if (base::StartsWith(zf.name(), "bugreport-") &&
- base::EndsWith(zf.name(), ".txt")) {
- br_file = &zf;
- break;
- }
- }
-
+ const util::ZipFile* br_file = FindBugReportFile(zip_file_entries_);
if (!br_file) {
PERFETTO_ELOG("Could not find bugreport-*.txt in the zip file");
return false;
}
- // Typical name: "bugreport-product-TP1A.220623.001-2022-06-24-16-24-37.txt".
- auto year_str = br_file->name().substr(
- br_file->name().size() - strlen("2022-12-31-23-59-00.txt"), 4);
- std::optional<int32_t> year = base::StringToInt32(year_str);
+ std::optional<int32_t> year =
+ ExtractYearFromBugReportFilename(br_file->name());
if (!year.has_value()) {
PERFETTO_ELOG("Could not parse the year from %s", br_file->name().c_str());
return false;
}
br_year_ = *year;
- dumpstate_fname_ = br_file->name();
+ dumpstate_file_ = br_file;
return true;
}
diff --git a/src/trace_processor/importers/android_bugreport/android_bugreport_parser.h b/src/trace_processor/importers/android_bugreport/android_bugreport_parser.h
index 9969159..a9ca322 100644
--- a/src/trace_processor/importers/android_bugreport/android_bugreport_parser.h
+++ b/src/trace_processor/importers/android_bugreport/android_bugreport_parser.h
@@ -17,8 +17,11 @@
#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_ANDROID_BUGREPORT_ANDROID_BUGREPORT_PARSER_H_
#define SRC_TRACE_PROCESSOR_IMPORTERS_ANDROID_BUGREPORT_ANDROID_BUGREPORT_PARSER_H_
-#include "src/trace_processor/importers/common/chunked_trace_reader.h"
-#include "src/trace_processor/storage/trace_storage.h"
+#include <cstddef>
+#include <vector>
+
+#include "perfetto/trace_processor/status.h"
+#include "src/trace_processor/util/zip_reader.h"
namespace perfetto {
namespace trace_processor {
@@ -31,16 +34,19 @@
class TraceProcessorContext;
// Trace importer for Android bugreport.zip archives.
-class AndroidBugreportParser : public ChunkedTraceReader {
+class AndroidBugreportParser {
public:
- explicit AndroidBugreportParser(TraceProcessorContext*);
- ~AndroidBugreportParser() override;
-
- // ChunkedTraceReader implementation.
- util::Status Parse(TraceBlobView) override;
- void NotifyEndOfFile() override;
+ static bool IsAndroidBugReport(
+ const std::vector<util::ZipFile>& zip_file_entries);
+ static util::Status Parse(TraceProcessorContext* context,
+ std::vector<util::ZipFile> zip_file_entries);
private:
+ AndroidBugreportParser(TraceProcessorContext* context,
+ std::vector<util::ZipFile> zip_file_entries);
+ ~AndroidBugreportParser();
+ util::Status ParseImpl();
+
bool DetectYearAndBrFilename();
void ParsePersistentLogcat();
void ParseDumpstateTxt();
@@ -48,11 +54,11 @@
void SortLogEvents();
TraceProcessorContext* const context_;
+ std::vector<util::ZipFile> zip_file_entries_;
int br_year_ = 0; // The year when the bugreport has been taken.
- std::string dumpstate_fname_; // The name of bugreport-xxx-2022-08-04....txt
+ const util::ZipFile* dumpstate_file_ =
+ nullptr; // The bugreport-xxx-2022-08-04....txt file
std::string build_fpr_;
- bool first_chunk_seen_ = false;
- std::unique_ptr<util::ZipReader> zip_reader_;
std::vector<AndroidLogEvent> log_events_;
size_t log_events_last_sorted_idx_ = 0;
};
diff --git a/src/trace_processor/importers/zip/BUILD.gn b/src/trace_processor/importers/zip/BUILD.gn
new file mode 100644
index 0000000..a938fdd
--- /dev/null
+++ b/src/trace_processor/importers/zip/BUILD.gn
@@ -0,0 +1,33 @@
+# 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.
+
+source_set("full") {
+ sources = [
+ "zip_trace_reader.cc",
+ "zip_trace_reader.h",
+ ]
+ deps = [
+ "../../../../gn:default_deps",
+ "../../../../gn:zlib",
+ "../../../../include/perfetto/ext/base:base",
+ "../../../trace_processor:storage_minimal",
+ "../../types",
+ "../../util:trace_type",
+ "../../util:util",
+ "../../util:zip_reader",
+ "../android_bugreport",
+ "../common",
+ "../proto:minimal",
+ ]
+}
diff --git a/src/trace_processor/importers/zip/zip_trace_reader.cc b/src/trace_processor/importers/zip/zip_trace_reader.cc
new file mode 100644
index 0000000..20f019f
--- /dev/null
+++ b/src/trace_processor/importers/zip/zip_trace_reader.cc
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include "src/trace_processor/importers/zip/zip_trace_reader.h"
+
+#include <algorithm>
+#include <cinttypes>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/base/status.h"
+#include "perfetto/ext/base/status_or.h"
+#include "perfetto/trace_processor/trace_blob.h"
+#include "perfetto/trace_processor/trace_blob_view.h"
+#include "src/trace_processor/forwarding_trace_parser.h"
+#include "src/trace_processor/importers/android_bugreport/android_bugreport_parser.h"
+#include "src/trace_processor/importers/proto/proto_trace_tokenizer.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+#include "src/trace_processor/util/status_macros.h"
+#include "src/trace_processor/util/trace_type.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace {
+
+// Proto traces should always parsed first as they might contains clock sync
+// data needed to correctly parse other traces.
+// The rest of the types are sorted by position in the enum but this is not
+// something users should rely on.
+// TODO(carlscab): Proto traces with just ModuleSymbols packets should be an
+// exception. We actually need those are the very end (once whe have all the
+// Frames). Alternatively we could build a map address -> symbol during
+// tokenization and use this during parsing to resolve symbols.
+bool CompareTraceType(TraceType lhs, TraceType rhs) {
+ if (rhs == TraceType::kProtoTraceType) {
+ return false;
+ }
+ if (lhs == TraceType::kProtoTraceType) {
+ return true;
+ }
+ return lhs < rhs;
+}
+
+bool HasSymbols(const TraceBlobView& blob) {
+ bool has_symbols = false;
+ ProtoTraceTokenizer().Tokenize(blob.copy(), [&](TraceBlobView raw) {
+ protos::pbzero::TracePacket::Decoder packet(raw.data(), raw.size());
+ has_symbols = packet.has_module_symbols();
+ return base::ErrStatus("break");
+ });
+ return has_symbols;
+}
+
+} // namespace
+
+ZipTraceReader::ZipTraceReader(TraceProcessorContext* context)
+ : context_(context) {}
+ZipTraceReader::~ZipTraceReader() = default;
+
+bool ZipTraceReader::Entry::operator<(const Entry& rhs) const {
+ // Traces with symbols should be the last ones to be read.
+ if (has_symbols) {
+ return false;
+ }
+ if (rhs.has_symbols) {
+ return true;
+ }
+ if (CompareTraceType(trace_type, rhs.trace_type)) {
+ return true;
+ }
+ if (CompareTraceType(rhs.trace_type, trace_type)) {
+ return false;
+ }
+ return std::tie(name, index) < std::tie(rhs.name, rhs.index);
+}
+
+util::Status ZipTraceReader::Parse(TraceBlobView blob) {
+ zip_reader_.Parse(blob.data(), blob.size());
+ return base::OkStatus();
+}
+
+void ZipTraceReader::NotifyEndOfFile() {
+ base::Status status = NotifyEndOfFileImpl();
+ if (!status.ok()) {
+ PERFETTO_ELOG("ZipTraceReader failed: %s", status.c_message());
+ }
+}
+
+base::Status ZipTraceReader::NotifyEndOfFileImpl() {
+ std::vector<util::ZipFile> files = zip_reader_.TakeFiles();
+
+ // Android bug reports are ZIP files and its files do not get handled
+ // separately.
+ if (AndroidBugreportParser::IsAndroidBugReport(files)) {
+ return AndroidBugreportParser::Parse(context_, std::move(files));
+ }
+
+ base::StatusOr<std::vector<Entry>> entries = ExtractEntries(std::move(files));
+ if (!entries.ok()) {
+ return entries.status();
+ }
+ std::sort(entries->begin(), entries->end());
+
+ for (Entry& e : *entries) {
+ parsers_.push_back(std::make_unique<ForwardingTraceParser>(context_));
+ auto& parser = *parsers_.back();
+ RETURN_IF_ERROR(parser.Parse(std::move(e.uncompressed_data)));
+ parser.NotifyEndOfFile();
+ }
+ return base::OkStatus();
+}
+
+base::StatusOr<std::vector<ZipTraceReader::Entry>>
+ZipTraceReader::ExtractEntries(std::vector<util::ZipFile> files) const {
+ // TODO(carlsacab): There is a lot of unnecessary copying going on here.
+ // ZipTraceReader can directly parse the ZIP file and given that we know the
+ // decompressed size we could directly decompress into TraceBlob chunks and
+ // send them to the tokenizer.
+ std::vector<Entry> entries;
+ std::vector<uint8_t> buffer;
+ for (size_t i = 0; i < files.size(); ++i) {
+ const util::ZipFile& zip_file = files[i];
+ Entry entry;
+ entry.name = zip_file.name();
+ entry.index = i;
+ RETURN_IF_ERROR(files[i].Decompress(&buffer));
+ entry.uncompressed_data =
+ TraceBlobView(TraceBlob::CopyFrom(buffer.data(), buffer.size()));
+ entry.trace_type = GuessTraceType(entry.uncompressed_data.data(),
+ entry.uncompressed_data.size());
+ entry.has_symbols = entry.trace_type == TraceType::kProtoTraceType &&
+ HasSymbols(entry.uncompressed_data);
+ entries.push_back(std::move(entry));
+ }
+ return std::move(entries);
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/importers/zip/zip_trace_reader.h b/src/trace_processor/importers/zip/zip_trace_reader.h
new file mode 100644
index 0000000..d4f3d88
--- /dev/null
+++ b/src/trace_processor/importers/zip/zip_trace_reader.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2024 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 SRC_TRACE_PROCESSOR_IMPORTERS_ZIP_ZIP_TRACE_READER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_ZIP_ZIP_TRACE_READER_H_
+
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "perfetto/base/status.h"
+#include "perfetto/ext/base/status_or.h"
+#include "perfetto/trace_processor/trace_blob_view.h"
+#include "src/trace_processor/importers/common/chunked_trace_reader.h"
+#include "src/trace_processor/util/trace_type.h"
+#include "src/trace_processor/util/zip_reader.h"
+
+namespace perfetto::trace_processor {
+
+class ForwardingTraceParser;
+class TraceProcessorContext;
+
+// Forwards files contained in a ZIP to the appropiate ChunkedTraceReader. It is
+// guaranteed that proto traces will be parsed first.
+class ZipTraceReader : public ChunkedTraceReader {
+ public:
+ explicit ZipTraceReader(TraceProcessorContext* context);
+ ~ZipTraceReader() override;
+
+ // ChunkedTraceReader implementation
+ util::Status Parse(TraceBlobView) override;
+ void NotifyEndOfFile() override;
+
+ private:
+ // Represents a file in the ZIP file. Used to sort them before sending the
+ // files one by one to a `ForwardingTraceParser` instance.
+ struct Entry {
+ // File name. Used to break ties.
+ std::string name;
+ // Position in the zip file. Used to break ties.
+ size_t index;
+ // Trace type. This is the main attribute traces are ordered by. Proto
+ // traces are always parsed first as they might contains clock sync
+ // data needed to correctly parse other traces.
+ TraceType trace_type;
+ TraceBlobView uncompressed_data;
+ // True for proto trace_types whose fist message is a ModuleSymbols packet
+ bool has_symbols = false;
+ // Comparator used to determine the order in which files in the ZIP will be
+ // read.
+ bool operator<(const Entry& rhs) const;
+ };
+
+ base::Status NotifyEndOfFileImpl();
+ base::StatusOr<std::vector<Entry>> ExtractEntries(
+ std::vector<util::ZipFile> files) const;
+ base::Status ParseEntry(Entry entry);
+
+ TraceProcessorContext* const context_;
+ util::ZipReader zip_reader_;
+ // For every file in the ZIP we will create a `ForwardingTraceParser`instance
+ // and send that file to it for tokenization. The instances are kept around
+ // here as some tokenizers might keep state that is later needed after
+ // sorting.
+ std::vector<std::unique_ptr<ForwardingTraceParser>> parsers_;
+};
+
+} // namespace perfetto::trace_processor
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_ZIP_ZIP_TRACE_READER_H_
diff --git a/src/trace_processor/metrics/sql/android/android_boot.sql b/src/trace_processor/metrics/sql/android/android_boot.sql
index 9140387..5738bff 100644
--- a/src/trace_processor/metrics/sql/android/android_boot.sql
+++ b/src/trace_processor/metrics/sql/android/android_boot.sql
@@ -19,6 +19,24 @@
INCLUDE PERFETTO MODULE android.garbage_collection;
INCLUDE PERFETTO MODULE android.oom_adjuster;
+DROP VIEW IF EXISTS android_oom_adj_intervals_with_detailed_bucket_name;
+CREATE PERFETTO VIEW android_oom_adj_intervals_with_detailed_bucket_name AS
+SELECT
+ ts,
+ dur,
+ score,
+ android_oom_adj_score_to_detailed_bucket_name(score, android_appid) AS bucket,
+ upid,
+ process_name,
+ oom_adj_id,
+ oom_adj_ts,
+ oom_adj_dur,
+ oom_adj_track_id,
+ oom_adj_thread_name,
+ oom_adj_reason,
+ oom_adj_trigger
+FROM _oom_adjuster_intervals;
+
CREATE OR REPLACE PERFETTO FUNCTION get_durations(process_name STRING)
RETURNS TABLE(uint_sleep_dur LONG, total_dur LONG) AS
SELECT
@@ -41,7 +59,7 @@
bucket,
process_name,
oom_adj_reason
-FROM android_oom_adj_intervals;
+FROM android_oom_adj_intervals_with_detailed_bucket_name;
DROP VIEW IF EXISTS oom_adj_events_by_process_name;
CREATE PERFETTO VIEW oom_adj_events_by_process_name AS
@@ -280,7 +298,7 @@
NULL as name,
bucket,
SUM(dur) as total_dur
- FROM android_oom_adj_intervals
+ FROM android_oom_adj_intervals_with_detailed_bucket_name
WHERE ts > first_user_unlocked()
GROUP BY bucket)
),
@@ -296,7 +314,7 @@
process_name as name,
bucket,
SUM(dur) as total_dur
- FROM android_oom_adj_intervals
+ FROM android_oom_adj_intervals_with_detailed_bucket_name
WHERE ts > first_user_unlocked()
AND process_name IS NOT NULL
GROUP BY process_name, bucket)
@@ -318,7 +336,7 @@
AVG(oom_adj_dur) as avg_oom_adj_dur,
COUNT(DISTINCT(oom_adj_id)) oom_adj_event_count,
oom_adj_reason
- FROM android_oom_adj_intervals
+ FROM android_oom_adj_intervals_with_detailed_bucket_name
WHERE ts > first_user_unlocked()
GROUP BY oom_adj_reason
)
diff --git a/src/trace_processor/metrics/sql/android/android_lmk_reason.sql b/src/trace_processor/metrics/sql/android/android_lmk_reason.sql
index 0ca2258..b7c7ca5 100644
--- a/src/trace_processor/metrics/sql/android/android_lmk_reason.sql
+++ b/src/trace_processor/metrics/sql/android/android_lmk_reason.sql
@@ -64,8 +64,8 @@
FROM lmk_events
JOIN rss_and_swap_span
WHERE lmk_events.ts
- BETWEEN rss_and_swap_span.ts
- AND rss_and_swap_span.ts + MAX(rss_and_swap_span.dur - 1, 0)
+ BETWEEN rss_and_swap_span.ts
+ AND rss_and_swap_span.ts + MAX(rss_and_swap_span.dur - 1, 0)
),
lmk_process_sizes_output AS (
SELECT ts, RepeatedField(AndroidLmkReasonMetric_Process(
diff --git a/src/trace_processor/metrics/sql/android/android_oom_adjuster.sql b/src/trace_processor/metrics/sql/android/android_oom_adjuster.sql
index 7b752a8..1564586 100644
--- a/src/trace_processor/metrics/sql/android/android_oom_adjuster.sql
+++ b/src/trace_processor/metrics/sql/android/android_oom_adjuster.sql
@@ -15,6 +15,51 @@
--
INCLUDE PERFETTO MODULE android.oom_adjuster;
+DROP VIEW IF EXISTS android_oom_adj_intervals_with_detailed_bucket_name;
+CREATE PERFETTO VIEW android_oom_adj_intervals_with_detailed_bucket_name (
+ -- Timestamp the oom_adj score of the process changed
+ ts INT,
+ -- Duration until the next oom_adj score change of the process.
+ dur INT,
+ -- oom_adj score of the process.
+ score INT,
+ -- oom_adj bucket of the process.
+ bucket STRING,
+ -- Upid of the process having an oom_adj update.
+ upid INT,
+ -- Name of the process having an oom_adj update.
+ process_name STRING,
+ -- Slice id of the latest oom_adj update in the system_server.
+ oom_adj_id INT,
+ -- Timestamp of the latest oom_adj update in the system_server.
+ oom_adj_ts INT,
+ -- Duration of the latest oom_adj update in the system_server.
+ oom_adj_dur INT,
+ -- Track id of the latest oom_adj update in the system_server
+ oom_adj_track_id INT,
+ -- Thread name of the latest oom_adj update in the system_server.
+ oom_adj_thread_name STRING,
+ -- Reason for the latest oom_adj update in the system_server.
+ oom_adj_reason STRING,
+ -- Trigger for the latest oom_adj update in the system_server.
+ oom_adj_trigger STRING
+ ) AS
+SELECT
+ ts,
+ dur,
+ score,
+ android_oom_adj_score_to_detailed_bucket_name(score, android_appid) AS bucket,
+ upid,
+ process_name,
+ oom_adj_id,
+ oom_adj_ts,
+ oom_adj_dur,
+ oom_adj_track_id,
+ oom_adj_thread_name,
+ oom_adj_reason,
+ oom_adj_trigger
+FROM _oom_adjuster_intervals;
+
DROP TABLE IF EXISTS _oom_adj_events_with_src_bucket;
CREATE PERFETTO TABLE _oom_adj_events_with_src_bucket
AS
@@ -24,7 +69,7 @@
bucket,
process_name,
oom_adj_reason
-FROM android_oom_adj_intervals;
+FROM android_oom_adj_intervals_with_detailed_bucket_name;
DROP VIEW IF EXISTS oom_adj_events_by_process_name;
CREATE PERFETTO VIEW oom_adj_events_by_process_name AS
@@ -100,7 +145,7 @@
)
FROM (
SELECT NULL as name, bucket, SUM(dur) as total_dur
- FROM android_oom_adj_intervals GROUP BY bucket
+ FROM android_oom_adj_intervals_with_detailed_bucket_name GROUP BY bucket
)
),
'oom_adj_bucket_duration_agg_by_process',(SELECT RepeatedField(
@@ -112,7 +157,7 @@
)
FROM (
SELECT process_name as name, bucket, SUM(dur) as total_dur
- FROM android_oom_adj_intervals
+ FROM android_oom_adj_intervals_with_detailed_bucket_name
WHERE process_name IS NOT NULL
GROUP BY process_name, bucket
)
@@ -133,7 +178,7 @@
AVG(oom_adj_dur) as avg_oom_adj_dur,
COUNT(DISTINCT(oom_adj_id)) oom_adj_event_count,
oom_adj_reason
- FROM android_oom_adj_intervals GROUP BY oom_adj_reason
+ FROM android_oom_adj_intervals_with_detailed_bucket_name GROUP BY oom_adj_reason
)
)
);
diff --git a/src/trace_processor/metrics/sql/android/process_mem.sql b/src/trace_processor/metrics/sql/android/process_mem.sql
index b26bf05..f3b1c88 100644
--- a/src/trace_processor/metrics/sql/android/process_mem.sql
+++ b/src/trace_processor/metrics/sql/android/process_mem.sql
@@ -47,7 +47,7 @@
ts,
dur,
upid,
- file_rss AS file_tss_val,
+ file_rss AS file_rss_val,
anon_rss AS anon_rss_val,
shmem_rss AS shmem_rss_val,
swap AS swap_val,
diff --git a/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.cc b/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.cc
index 8f163a0..3048e68 100644
--- a/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.cc
+++ b/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.cc
@@ -32,6 +32,7 @@
#include "perfetto/base/logging.h"
#include "perfetto/base/status.h"
+#include "perfetto/ext/base/flat_hash_map.h"
#include "perfetto/ext/base/status_or.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/string_view.h"
@@ -848,7 +849,18 @@
const std::vector<std::string>& column_names,
const std::vector<sql_argument::ArgumentDefinition>& schema,
const char* tag) {
- // If the user has not provided a schema, we have nothing to validate.
+ std::vector<std::string> duplicate_columns;
+ for (auto it = column_names.begin(); it != column_names.end(); ++it) {
+ if (std::count(it + 1, column_names.end(), *it) > 0) {
+ duplicate_columns.push_back(*it);
+ }
+ }
+ if (!duplicate_columns.empty()) {
+ return base::ErrStatus("%s: multiple columns are named: %s", tag,
+ base::Join(duplicate_columns, ", ").c_str());
+ }
+
+ // If the user has not provided a schema, we have nothing further to validate.
if (schema.empty()) {
return base::OkStatus();
}
diff --git a/src/trace_processor/perfetto_sql/stdlib/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/BUILD.gn
index 349e2f6..e746a1d 100644
--- a/src/trace_processor/perfetto_sql/stdlib/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/BUILD.gn
@@ -25,6 +25,7 @@
"counters",
"cpu",
"deprecated/v42/common",
+ "gpu",
"graphs",
"intervals",
"linux",
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/oom_adjuster.sql b/src/trace_processor/perfetto_sql/stdlib/android/oom_adjuster.sql
index 3ce017e..c09414e 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/oom_adjuster.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/oom_adjuster.sql
@@ -17,8 +17,30 @@
INCLUDE PERFETTO MODULE slices.with_context;
INCLUDE PERFETTO MODULE counters.intervals;
--- Converts an oom_adj score Integer to String bucket name.
+-- Converts an oom_adj score Integer to String sample name.
+-- One of: cached, background, job, foreground_service, bfgs, foreground and
+-- system.
CREATE PERFETTO FUNCTION android_oom_adj_score_to_bucket_name(
+ -- `oom_score` value
+ oom_score INT
+)
+-- Returns the sample bucket based on the oom score.
+RETURNS STRING
+AS
+SELECT
+ CASE
+ WHEN $oom_score >= 900 THEN 'cached'
+ WHEN $oom_score BETWEEN 250 AND 900 THEN 'background'
+ WHEN $oom_score BETWEEN 201 AND 250 THEN 'job'
+ WHEN $oom_score = 200 THEN 'foreground_service'
+ WHEN $oom_score BETWEEN 100 AND 200 THEN 'bfgs'
+ WHEN $oom_score BETWEEN 0 AND 100 THEN 'foreground'
+ WHEN $oom_score < 0 THEN 'system'
+END;
+
+-- Converts an oom_adj score Integer to String bucket name.
+-- Deprecated: use `android_oom_adj_score_to_bucket_name` instead.
+CREATE PERFETTO FUNCTION android_oom_adj_score_to_detailed_bucket_name(
-- oom_adj score.
value INT,
-- android_app id of the process.
@@ -52,8 +74,58 @@
ELSE 'unknown_app'
END;
+CREATE PERFETTO TABLE _oom_adjuster_intervals AS
+WITH reason AS (
+ SELECT
+ thread_slice.id AS oom_adj_id,
+ thread_slice.ts AS oom_adj_ts,
+ thread_slice.dur AS oom_adj_dur,
+ thread_slice.track_id AS oom_adj_track_id,
+ utid AS oom_adj_utid,
+ thread_name AS oom_adj_thread_name,
+ str_split(thread_slice.name, '_', 1) AS oom_adj_reason,
+ slice.name AS oom_adj_trigger,
+ LEAD(thread_slice.ts) OVER (ORDER BY thread_slice.ts) AS oom_adj_next_ts
+ FROM thread_slice
+ LEFT JOIN slice ON slice.id = thread_slice.parent_id AND slice.dur != -1
+ WHERE thread_slice.name GLOB 'updateOomAdj_*' AND process_name = 'system_server'
+)
+SELECT
+ ts,
+ dur,
+ cast_int!(value) AS score,
+ process.upid,
+ process.name AS process_name,
+ reason.oom_adj_id,
+ reason.oom_adj_ts,
+ reason.oom_adj_dur,
+ reason.oom_adj_track_id,
+ reason.oom_adj_thread_name,
+ reason.oom_adj_utid,
+ reason.oom_adj_reason,
+ reason.oom_adj_trigger,
+ android_appid
+FROM
+ counter_leading_intervals
+ !(
+ (
+ SELECT counter.*
+ FROM counter
+ JOIN counter_track track
+ ON track.id = counter.track_id AND track.name = 'oom_score_adj'
+ ))
+ counter
+JOIN process_counter_track track
+ ON counter.track_id = track.id
+JOIN process
+ USING (upid)
+LEFT JOIN reason
+ ON counter.ts BETWEEN oom_adj_ts AND COALESCE(oom_adj_next_ts, trace_end())
+WHERE track.name = 'oom_score_adj';
+
+
-- All oom adj state intervals across all processes along with the reason for the state update.
-CREATE PERFETTO TABLE android_oom_adj_intervals (
+CREATE PERFETTO VIEW android_oom_adj_intervals (
-- Timestamp the oom_adj score of the process changed
ts INT,
-- Duration until the next oom_adj score change of the process.
@@ -81,49 +153,18 @@
-- Trigger for the latest oom_adj update in the system_server.
oom_adj_trigger STRING
) AS
-WITH
- reason AS (
- SELECT
- thread_slice.id AS oom_adj_id,
- thread_slice.ts AS oom_adj_ts,
- thread_slice.dur AS oom_adj_dur,
- thread_slice.track_id AS oom_adj_track_id,
- thread_name AS oom_adj_thread_name,
- str_split(thread_slice.name, '_', 1) AS oom_adj_reason,
- slice.name AS oom_adj_trigger,
- LEAD(thread_slice.ts) OVER (ORDER BY thread_slice.ts) AS oom_adj_next_ts
- FROM thread_slice
- LEFT JOIN slice ON slice.id = thread_slice.parent_id AND slice.dur != -1
- WHERE thread_slice.name GLOB 'updateOomAdj_*' AND process_name = 'system_server'
- )
SELECT
ts,
dur,
- value AS score,
- android_oom_adj_score_to_bucket_name(value, android_appid) AS bucket,
- process.upid,
- process.name AS process_name,
- reason.oom_adj_id,
- reason.oom_adj_ts,
- reason.oom_adj_dur,
- reason.oom_adj_track_id,
- reason.oom_adj_thread_name,
- reason.oom_adj_reason,
- reason.oom_adj_trigger
-FROM
- counter_leading_intervals
- !(
- (
- SELECT counter.*
- FROM counter
- JOIN counter_track track
- ON track.id = counter.track_id AND track.name = 'oom_score_adj'
- ))
- counter
-JOIN process_counter_track track
- ON counter.track_id = track.id
-JOIN process
- USING (upid)
-LEFT JOIN reason
- ON counter.ts BETWEEN oom_adj_ts AND COALESCE(oom_adj_next_ts, trace_end())
-WHERE track.name = 'oom_score_adj';
+ score,
+ android_oom_adj_score_to_bucket_name(score) AS bucket,
+ upid,
+ process_name,
+ oom_adj_id,
+ oom_adj_ts,
+ oom_adj_dur,
+ oom_adj_track_id,
+ oom_adj_thread_name,
+ oom_adj_reason,
+ oom_adj_trigger
+FROM _oom_adjuster_intervals;
diff --git a/src/trace_processor/perfetto_sql/stdlib/counters/intervals.sql b/src/trace_processor/perfetto_sql/stdlib/counters/intervals.sql
index 82427f7..7bb0c96 100644
--- a/src/trace_processor/perfetto_sql/stdlib/counters/intervals.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/counters/intervals.sql
@@ -62,7 +62,7 @@
ts,
track_id,
LEAD(ts, 1, trace_end()) OVER(PARTITION BY track_id ORDER BY ts) - ts AS dur,
- CAST(value AS INT) AS value
+ value
FROM base
WHERE value != lag_value OR lag_value IS NULL
);
diff --git a/src/trace_processor/perfetto_sql/stdlib/cpu/freq.sql b/src/trace_processor/perfetto_sql/stdlib/cpu/freq.sql
index c0226bf..5dd2a48 100644
--- a/src/trace_processor/perfetto_sql/stdlib/cpu/freq.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/cpu/freq.sql
@@ -37,7 +37,7 @@
count_w_dur.track_id,
count_w_dur.ts,
count_w_dur.dur,
- count_w_dur.value as freq,
+ cast_int!(count_w_dur.value) as freq,
cct.cpu
FROM
counter_leading_intervals!((
diff --git a/src/trace_processor/perfetto_sql/stdlib/cpu/idle.sql b/src/trace_processor/perfetto_sql/stdlib/cpu/idle.sql
index 7f837a2..703a913 100644
--- a/src/trace_processor/perfetto_sql/stdlib/cpu/idle.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/cpu/idle.sql
@@ -39,7 +39,7 @@
count_w_dur.track_id,
count_w_dur.ts,
count_w_dur.dur,
- IIF(count_w_dur.value = 4294967295, -1, count_w_dur.value) AS idle,
+ cast_int!(IIF(count_w_dur.value = 4294967295, -1, count_w_dur.value)) AS idle,
cct.cpu
FROM
counter_leading_intervals!((
diff --git a/src/trace_processor/perfetto_sql/stdlib/gpu/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/gpu/BUILD.gn
new file mode 100644
index 0000000..a5f431d
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/gpu/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright (C) 2024 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_sql.gni")
+
+perfetto_sql_source_set("gpu") {
+ sources = [ "frequency.sql" ]
+}
diff --git a/src/trace_processor/perfetto_sql/stdlib/gpu/frequency.sql b/src/trace_processor/perfetto_sql/stdlib/gpu/frequency.sql
new file mode 100644
index 0000000..2bd87b2
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/gpu/frequency.sql
@@ -0,0 +1,42 @@
+--
+-- Copyright 2024 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.
+--
+
+INCLUDE PERFETTO MODULE counters.intervals;
+
+-- GPU frequency counter per GPU.
+CREATE PERFETTO TABLE gpu_frequency(
+ -- Timestamp
+ ts INT,
+ -- Duration
+ dur INT,
+ -- GPU id. Joinable with `gpu_counter_track.gpu_id`.
+ gpu_id INT,
+ -- GPU frequency
+ gpu_freq INT
+) AS
+SELECT
+ ts,
+ dur,
+ gpu_id,
+ cast_int!(value) AS gpu_freq
+FROM counter_leading_intervals!((
+ SELECT c.*
+ FROM counter c
+ JOIN gpu_counter_track t
+ ON t.id = c.track_id AND t.name = 'gpufreq'
+ WHERE gpu_id IS NOT NULL
+))
+JOIN gpu_counter_track t ON t.id = track_id;
\ No newline at end of file
diff --git a/src/trace_processor/perfetto_sql/stdlib/memory/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/memory/BUILD.gn
index da9685e..ddc6419 100644
--- a/src/trace_processor/perfetto_sql/stdlib/memory/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/memory/BUILD.gn
@@ -15,6 +15,9 @@
import("../../../../../gn/perfetto_sql.gni")
perfetto_sql_source_set("memory") {
- deps = ["linux"]
+ deps = [
+ "android",
+ "linux",
+ ]
sources = [ "heap_graph_dominator_tree.sql" ]
}
diff --git a/src/trace_processor/perfetto_sql/stdlib/memory/android/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/memory/android/BUILD.gn
new file mode 100644
index 0000000..55123b6
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/memory/android/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright (C) 2024 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_sql.gni")
+
+perfetto_sql_source_set("android") {
+ sources = [ "gpu.sql" ]
+}
diff --git a/src/trace_processor/perfetto_sql/stdlib/memory/android/gpu.sql b/src/trace_processor/perfetto_sql/stdlib/memory/android/gpu.sql
new file mode 100644
index 0000000..39abaec
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/memory/android/gpu.sql
@@ -0,0 +1,35 @@
+--
+-- Copyright 2024 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.
+
+INCLUDE PERFETTO MODULE memory.linux.general;
+
+-- Counter for GPU memory per process with duration.
+CREATE PERFETTO TABLE memory_gpu_per_process(
+ -- Timestamp
+ ts INT,
+ -- Duration
+ dur INT,
+ -- Upid of the process
+ upid INT,
+ -- GPU memory
+ gpu_memory INT
+) AS
+SELECT
+ ts,
+ dur,
+ upid,
+ cast_int!(value) AS gpu_memory
+FROM _all_counters_per_process
+WHERE name = 'GPU Memory';
\ No newline at end of file
diff --git a/src/trace_processor/perfetto_sql/stdlib/memory/linux/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/memory/linux/BUILD.gn
index e436ca6..0711197 100644
--- a/src/trace_processor/perfetto_sql/stdlib/memory/linux/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/memory/linux/BUILD.gn
@@ -16,6 +16,7 @@
perfetto_sql_source_set("linux") {
sources = [
+ "general.sql",
"high_watermark.sql",
"process.sql",
]
diff --git a/src/trace_processor/perfetto_sql/stdlib/memory/linux/general.sql b/src/trace_processor/perfetto_sql/stdlib/memory/linux/general.sql
new file mode 100644
index 0000000..372cbf9
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/memory/linux/general.sql
@@ -0,0 +1,30 @@
+--
+-- Copyright 2024 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 PERFETTO VIEW _all_counters_per_process AS
+SELECT
+ ts,
+ LEAD(
+ ts, 1,
+ (SELECT COALESCE(end_ts, trace_end())
+ FROM process p WHERE p.upid = t.upid) + 1)
+ OVER (PARTITION BY track_id ORDER BY ts) - ts AS dur,
+ upid,
+ value,
+ track_id,
+ name
+FROM counter c JOIN process_counter_track t
+ON t.id = c.track_id
+WHERE upid IS NOT NULL;
\ No newline at end of file
diff --git a/src/trace_processor/perfetto_sql/stdlib/memory/linux/high_watermark.sql b/src/trace_processor/perfetto_sql/stdlib/memory/linux/high_watermark.sql
index bc5ca67..b01f2df 100644
--- a/src/trace_processor/perfetto_sql/stdlib/memory/linux/high_watermark.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/memory/linux/high_watermark.sql
@@ -36,7 +36,7 @@
0 AS id
FROM with_rss
)
-SELECT ts, dur, track_id AS upid, value AS rss_high_watermark
+SELECT ts, dur, track_id AS upid, cast_int!(value) AS rss_high_watermark
FROM counter_leading_intervals!(high_watermark_as_counter);
-- For each process fetches the memory high watermark until or during
diff --git a/src/trace_processor/perfetto_sql/stdlib/memory/linux/process.sql b/src/trace_processor/perfetto_sql/stdlib/memory/linux/process.sql
index 8a81f43..4601c21 100644
--- a/src/trace_processor/perfetto_sql/stdlib/memory/linux/process.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/memory/linux/process.sql
@@ -13,20 +13,8 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
-CREATE PERFETTO VIEW _all_counters_for_with_upid AS
-SELECT
- ts,
- LEAD(
- ts, 1,
- (SELECT COALESCE(end_ts, trace_end())
- FROM process p WHERE p.upid = t.upid) + 1)
- OVER (PARTITION BY track_id ORDER BY ts) - ts AS dur,
- upid,
- value,
- name
-FROM counter c JOIN process_counter_track t
-ON t.id = c.track_id
-WHERE upid IS NOT NULL;
+INCLUDE PERFETTO MODULE android.oom_adjuster;
+INCLUDE PERFETTO MODULE memory.linux.general;
-- All memory counters tables.
@@ -36,7 +24,7 @@
dur,
upid,
value AS anon_rss_val
-FROM _all_counters_for_with_upid
+FROM _all_counters_per_process
WHERE name = 'mem.rss.anon';
CREATE PERFETTO VIEW _file_rss AS
@@ -45,7 +33,7 @@
dur,
upid,
value AS file_rss_val
-FROM _all_counters_for_with_upid
+FROM _all_counters_per_process
WHERE name = 'mem.rss.file';
CREATE PERFETTO VIEW _shmem_rss AS
@@ -54,7 +42,7 @@
dur,
upid,
value AS shmem_rss_val
-FROM _all_counters_for_with_upid
+FROM _all_counters_per_process
WHERE name = 'mem.rss.shmem';
CREATE PERFETTO VIEW _swap AS
@@ -63,7 +51,7 @@
dur,
upid,
value AS swap_val
-FROM _all_counters_for_with_upid
+FROM _all_counters_per_process
WHERE name = 'mem.swap';
-- Span joins
@@ -145,3 +133,85 @@
anon_rss + file_rss + COALESCE(shmem_rss, 0) + COALESCE(swap, 0) AS rss_and_swap
FROM _memory_rss_and_swap_per_process_table
JOIN process USING (upid);
+
+-- OOM score tables
+
+CREATE VIRTUAL TABLE _mem_ooms_sj
+USING SPAN_OUTER_JOIN(
+ android_oom_adj_intervals PARTITIONED upid,
+ _memory_rss_and_swap_per_process_table PARTITIONED upid);
+
+-- Process memory and it's OOM adjuster scores. Detects transitions, each new
+-- interval means that either the memory or OOM adjuster score of the process changed.
+CREATE PERFETTO TABLE memory_oom_score_with_rss_and_swap_per_process(
+ -- Timestamp the oom_adj score or memory of the process changed
+ ts INT,
+ -- Duration until the next oom_adj score or memory change of the process.
+ dur INT,
+ -- oom adjuster score of the process.
+ score INT,
+ -- oom adjuster bucket of the process.
+ bucket STRING,
+ -- Upid of the process having an oom_adj update.
+ upid INT,
+ -- Name of the process having an oom_adj update.
+ process_name STRING,
+ -- Pid of the process having an oom_adj update.
+ pid INT,
+ -- Slice of the latest oom_adj update in the system_server. Alias of
+ -- `slice.id`.
+ oom_adj_id INT,
+ -- Timestamp of the latest oom_adj update in the system_server.
+ oom_adj_ts INT,
+ -- Duration of the latest oom_adj update in the system_server.
+ oom_adj_dur INT,
+ -- Track of the latest oom_adj update in the system_server. Alias of
+ -- `track.id`.
+ oom_adj_track_id INT,
+ -- Thread name of the latest oom_adj update in the system_server.
+ oom_adj_thread_name STRING,
+ -- Reason for the latest oom_adj update in the system_server.
+ oom_adj_reason STRING,
+ -- Trigger for the latest oom_adj update in the system_server.
+ oom_adj_trigger STRING,
+ -- Anon RSS counter value
+ anon_rss INT,
+ -- File RSS counter value
+ file_rss INT,
+ -- Shared memory RSS counter value
+ shmem_rss INT,
+ -- Total RSS value. Sum of `anon_rss`, `file_rss` and `shmem_rss`. Returns
+ -- value even if one of the values is NULL.
+ rss INT,
+ -- Swap counter value
+ swap INT,
+ -- Sum or `anon_rss` and `swap`. Returns value even if one of the values is
+ -- NULL.
+ anon_rss_and_swap INT,
+ -- Sum or `rss` and `swap`. Returns value even if one of the values is NULL.
+ rss_and_swap INT
+) AS
+SELECT
+ ts,
+ dur,
+ score,
+ bucket,
+ upid,
+ process_name,
+ pid,
+ oom_adj_id,
+ oom_adj_ts,
+ oom_adj_dur,
+ oom_adj_track_id,
+ oom_adj_thread_name,
+ oom_adj_reason,
+ oom_adj_trigger,
+ anon_rss,
+ file_rss,
+ shmem_rss,
+ file_rss + anon_rss + COALESCE(shmem_rss, 0) AS rss,
+ swap,
+ anon_rss + COALESCE(swap, 0) AS anon_rss_and_swap,
+ anon_rss + file_rss + COALESCE(shmem_rss, 0) + COALESCE(swap, 0) AS rss_and_swap
+FROM _mem_ooms_sj
+JOIN process USING (upid);
diff --git a/src/trace_processor/perfetto_sql/stdlib/sched/thread_executing_span_with_slice.sql b/src/trace_processor/perfetto_sql/stdlib/sched/thread_executing_span_with_slice.sql
index 89085f3..74f73a5 100644
--- a/src/trace_processor/perfetto_sql/stdlib/sched/thread_executing_span_with_slice.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/sched/thread_executing_span_with_slice.sql
@@ -213,7 +213,7 @@
self_thread_state_id AS id,
ts,
dur,
- utid,
+ critical_path_utid AS utid,
0 AS stack_depth,
'thread_state: ' || self_state AS name,
'thread_state' AS table_name,
@@ -225,7 +225,7 @@
self_thread_state_id AS id,
ts,
dur,
- utid,
+ critical_path_utid AS utid,
1 AS stack_depth,
IIF(self_state GLOB 'R*', NULL, 'kernel function: ' || self_function) AS name,
'thread_state' AS table_name,
@@ -237,7 +237,7 @@
self_thread_state_id AS id,
ts,
dur,
- utid,
+ critical_path_utid AS utid,
2 AS stack_depth,
IIF(self_state GLOB 'R*', NULL, 'io_wait: ' || self_io_wait) AS name,
'thread_state' AS table_name,
@@ -281,7 +281,7 @@
anc.id,
slice.ts,
slice.dur,
- slice.utid,
+ critical_path_utid AS utid,
anc.depth + 5 AS stack_depth,
IIF($enable_self_slice, anc.name, NULL) AS name,
'slice' AS table_name,
@@ -294,7 +294,7 @@
self_slice_id AS id,
ts,
dur,
- utid,
+ critical_path_utid AS utid,
self_slice_depth + 5 AS stack_depth,
IIF($enable_self_slice, self_slice_name, NULL) AS name,
'slice' AS table_name,
diff --git a/src/trace_processor/rpc/wasm_bridge.cc b/src/trace_processor/rpc/wasm_bridge.cc
index ca27abc..2473e4c 100644
--- a/src/trace_processor/rpc/wasm_bridge.cc
+++ b/src/trace_processor/rpc/wasm_bridge.cc
@@ -15,8 +15,13 @@
*/
#include <emscripten/emscripten.h>
-#include <cstdint>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <new>
+
+#include "perfetto/base/compiler.h"
#include "src/trace_processor/rpc/rpc.h"
namespace perfetto::trace_processor {
@@ -29,6 +34,12 @@
// The buffer used to pass the request arguments. The caller (JS) decides how
// big this buffer should be in the Initialize() call.
uint8_t* g_req_buf;
+
+PERFETTO_NO_INLINE void OutOfMemoryHandler() {
+ fprintf(stderr, "\nCannot enlarge memory\n");
+ abort();
+}
+
} // namespace
// +---------------------------------------------------------------------------+
@@ -41,6 +52,13 @@
trace_processor_rpc_init(RpcResponseFn* RpcResponseFn, uint32_t);
uint8_t* trace_processor_rpc_init(RpcResponseFn* resp_function,
uint32_t req_buffer_size) {
+ // Usually OOMs manifest as a failure in dlmalloc() -> sbrk() ->
+ //_emscripten_resize_heap() which aborts itself. However in some rare cases
+ // sbrk() can fail outside of _emscripten_resize_heap and just return null.
+ // When that happens, just abort with the same message that
+ // _emscripten_resize_heap uses, so error_dialog.ts shows a OOM message.
+ std::set_new_handler(&OutOfMemoryHandler);
+
g_trace_processor_rpc = new Rpc();
// |resp_function| is a JS-bound function passed by wasm_bridge.ts. It will
diff --git a/src/trace_processor/trace_database_integrationtest.cc b/src/trace_processor/trace_database_integrationtest.cc
index d09c8a7..731f4e3 100644
--- a/src/trace_processor/trace_database_integrationtest.cc
+++ b/src/trace_processor/trace_database_integrationtest.cc
@@ -14,17 +14,23 @@
* limitations under the License.
*/
-#include <algorithm>
+#include <cstdint>
#include <cstdio>
-#include <map>
-#include <optional>
+#include <cstring>
+#include <memory>
#include <random>
#include <string>
+#include <utility>
+#include <vector>
+#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
+#include "perfetto/base/status.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/trace_processor/basic_types.h"
+#include "perfetto/trace_processor/iterator.h"
+#include "perfetto/trace_processor/status.h"
#include "perfetto/trace_processor/trace_processor.h"
#include "protos/perfetto/common/descriptor.pbzero.h"
#include "protos/perfetto/trace_processor/trace_processor.pbzero.h"
@@ -32,11 +38,12 @@
#include "src/base/test/utils.h"
#include "test/gtest_and_gmock.h"
-namespace perfetto {
-namespace trace_processor {
+namespace perfetto::trace_processor {
namespace {
-constexpr size_t kMaxChunkSize = 4 * 1024 * 1024;
+using testing::HasSubstr;
+
+constexpr size_t kMaxChunkSize = 4ul * 1024 * 1024;
TEST(TraceProcessorCustomConfigTest, SkipInternalMetricsMatchingMountPath) {
auto config = Config();
@@ -97,12 +104,13 @@
: processor_(TraceProcessor::CreateInstance(Config())) {}
protected:
- util::Status LoadTrace(const char* name,
+ base::Status LoadTrace(const char* name,
size_t min_chunk_size = 512,
size_t max_chunk_size = kMaxChunkSize) {
EXPECT_LE(min_chunk_size, max_chunk_size);
- base::ScopedFstream f(fopen(
- base::GetTestDataPath(std::string("test/data/") + name).c_str(), "rb"));
+ base::ScopedFstream f(
+ fopen(base::GetTestDataPath(std::string("test/data/") + name).c_str(),
+ "rbe"));
std::minstd_rand0 rnd_engine(0);
std::uniform_int_distribution<size_t> dist(min_chunk_size, max_chunk_size);
while (!feof(*f)) {
@@ -118,7 +126,7 @@
}
Iterator Query(const std::string& query) {
- return processor_->ExecuteQuery(query.c_str());
+ return processor_->ExecuteQuery(query);
}
TraceProcessor* Processor() { return processor_.get(); }
@@ -280,7 +288,7 @@
TEST_F(TraceProcessorIntegrationTest, ComputeMetricsFormattedExtension) {
std::string metric_output;
- util::Status status = Processor()->ComputeMetricText(
+ base::Status status = Processor()->ComputeMetricText(
std::vector<std::string>{"test_chrome_metric"},
TraceProcessor::MetricResultFormat::kProtoText, &metric_output);
ASSERT_TRUE(status.ok());
@@ -293,7 +301,7 @@
TEST_F(TraceProcessorIntegrationTest, ComputeMetricsFormattedNoExtension) {
std::string metric_output;
- util::Status status = Processor()->ComputeMetricText(
+ base::Status status = Processor()->ComputeMetricText(
std::vector<std::string>{"trace_metadata"},
TraceProcessor::MetricResultFormat::kProtoText, &metric_output);
ASSERT_TRUE(status.ok());
@@ -321,21 +329,21 @@
}
TEST_F(TraceProcessorIntegrationTest, Clusterfuzz14762) {
- ASSERT_TRUE(LoadTrace("clusterfuzz_14762", 4096 * 1024).ok());
+ ASSERT_TRUE(LoadTrace("clusterfuzz_14762", 4096ul * 1024).ok());
auto it = Query("select sum(value) from stats where severity = 'error';");
ASSERT_TRUE(it.Next());
ASSERT_GT(it.Get(0).long_value, 0);
}
TEST_F(TraceProcessorIntegrationTest, Clusterfuzz14767) {
- ASSERT_TRUE(LoadTrace("clusterfuzz_14767", 4096 * 1024).ok());
+ ASSERT_TRUE(LoadTrace("clusterfuzz_14767", 4096ul * 1024).ok());
auto it = Query("select sum(value) from stats where severity = 'error';");
ASSERT_TRUE(it.Next());
ASSERT_GT(it.Get(0).long_value, 0);
}
TEST_F(TraceProcessorIntegrationTest, Clusterfuzz14799) {
- ASSERT_TRUE(LoadTrace("clusterfuzz_14799", 4096 * 1024).ok());
+ ASSERT_TRUE(LoadTrace("clusterfuzz_14799", 4096ul * 1024).ok());
auto it = Query("select sum(value) from stats where severity = 'error';");
ASSERT_TRUE(it.Next());
ASSERT_GT(it.Get(0).long_value, 0);
@@ -793,6 +801,15 @@
ASSERT_TRUE(it.Status().ok());
}
+TEST_F(TraceProcessorIntegrationTest, CreateTableDuplicateNames) {
+ auto it = Query(
+ "create perfetto table foo select 1 as duplicate_a, 2 as duplicate_a, 3 "
+ "as duplicate_b, 4 as duplicate_b");
+ ASSERT_FALSE(it.Next());
+ ASSERT_FALSE(it.Status().ok());
+ ASSERT_THAT(it.Status().message(), HasSubstr("duplicate_a"));
+ ASSERT_THAT(it.Status().message(), HasSubstr("duplicate_b"));
+}
+
} // namespace
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index fb9b294..117a737 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -59,6 +59,7 @@
#include "src/trace_processor/importers/proto/additional_modules.h"
#include "src/trace_processor/importers/proto/content_analyzer.h"
#include "src/trace_processor/importers/systrace/systrace_trace_parser.h"
+#include "src/trace_processor/importers/zip/zip_trace_reader.h"
#include "src/trace_processor/iterator_impl.h"
#include "src/trace_processor/metrics/all_chrome_metrics.descriptor.h"
#include "src/trace_processor/metrics/all_webview_metrics.descriptor.h"
@@ -121,6 +122,7 @@
#include "src/trace_processor/util/regex.h"
#include "src/trace_processor/util/sql_modules.h"
#include "src/trace_processor/util/status_macros.h"
+#include "src/trace_processor/util/trace_type.h"
#include "protos/perfetto/common/builtin_clock.pbzero.h"
#include "protos/perfetto/trace/clock_snapshot.pbzero.h"
@@ -308,8 +310,8 @@
return "ctrace";
case kNinjaLogTraceType:
return "ninja_log";
- case kAndroidBugreportTraceType:
- return "android_bugreport";
+ case kZipFile:
+ return "zip";
case kPerfDataTraceType:
return "perf_data";
}
@@ -362,8 +364,7 @@
kGzipTraceType);
context_.reader_registry->RegisterTraceReader<GzipTraceParser>(
kCtraceTraceType);
- context_.reader_registry->RegisterTraceReader<AndroidBugreportParser>(
- kAndroidBugreportTraceType);
+ context_.reader_registry->RegisterTraceReader<ZipTraceReader>(kZipFile);
}
if (json::IsJsonSupported()) {
diff --git a/src/trace_processor/trace_processor_storage_impl.cc b/src/trace_processor/trace_processor_storage_impl.cc
index 32f2452..09d5386 100644
--- a/src/trace_processor/trace_processor_storage_impl.cc
+++ b/src/trace_processor/trace_processor_storage_impl.cc
@@ -107,6 +107,8 @@
return;
Flush();
context_.chunk_reader->NotifyEndOfFile();
+ // NotifyEndOfFile might have pushed packets to the sorter.
+ Flush();
for (std::unique_ptr<ProtoImporterModule>& module : context_.modules) {
module->NotifyEndOfFile();
}
diff --git a/src/trace_processor/trace_reader_registry.cc b/src/trace_processor/trace_reader_registry.cc
index 09c5c7b..065f6f6 100644
--- a/src/trace_processor/trace_reader_registry.cc
+++ b/src/trace_processor/trace_reader_registry.cc
@@ -30,7 +30,7 @@
switch (type) {
case kGzipTraceType:
case kCtraceTraceType:
- case kAndroidBugreportTraceType:
+ case kZipFile:
return true;
case kNinjaLogTraceType:
diff --git a/src/trace_processor/util/trace_type.cc b/src/trace_processor/util/trace_type.cc
index d265b90..ee5a56a 100644
--- a/src/trace_processor/util/trace_type.cc
+++ b/src/trace_processor/util/trace_type.cc
@@ -58,8 +58,8 @@
return "gzip trace";
case kCtraceTraceType:
return "ctrace trace";
- case kAndroidBugreportTraceType:
- return "Android Bugreport";
+ case kZipFile:
+ return "ZIP file";
case kPerfDataTraceType:
return "perf data";
case kUnknownTraceType:
@@ -124,12 +124,8 @@
if (base::StartsWith(start, "\x0a"))
return kProtoTraceType;
- // Android bugreport.zip
- // TODO(primiano). For now we assume any .zip file is a bugreport. In future,
- // if we want to support different trace formats based on a .zip arachive we
- // will need an extra layer similar to what we did kGzipTraceType.
if (base::StartsWith(start, "PK\x03\x04"))
- return kAndroidBugreportTraceType;
+ return kZipFile;
return kUnknownTraceType;
}
diff --git a/src/trace_processor/util/trace_type.h b/src/trace_processor/util/trace_type.h
index fec7a74..2d40d83 100644
--- a/src/trace_processor/util/trace_type.h
+++ b/src/trace_processor/util/trace_type.h
@@ -31,7 +31,7 @@
kGzipTraceType,
kCtraceTraceType,
kNinjaLogTraceType,
- kAndroidBugreportTraceType,
+ kZipFile,
kPerfDataTraceType,
};
diff --git a/src/traceconv/symbolize_profile.cc b/src/traceconv/symbolize_profile.cc
index 00cc7b9..4efaa10 100644
--- a/src/traceconv/symbolize_profile.cc
+++ b/src/traceconv/symbolize_profile.cc
@@ -55,12 +55,12 @@
PERFETTO_FATAL("Failed to read trace.");
tp->Flush();
+ tp->NotifyEndOfFile();
SymbolizeDatabase(
tp.get(), symbolizer.get(),
[output](const std::string& trace_proto) { *output << trace_proto; });
- tp->NotifyEndOfFile();
return 0;
}
diff --git a/src/tracing/service/tracing_service_impl.cc b/src/tracing/service/tracing_service_impl.cc
index d667767..6631d68 100644
--- a/src/tracing/service/tracing_service_impl.cc
+++ b/src/tracing/service/tracing_service_impl.cc
@@ -24,6 +24,7 @@
#include <limits>
#include <optional>
#include <regex>
+#include <string>
#include <unordered_set>
#include "perfetto/base/time.h"
#include "perfetto/ext/tracing/core/client_identity.h"
@@ -1689,13 +1690,14 @@
tracing_session.config, tracing_session.trace_uuid,
PerfettoStatsdAtom::kTracedTriggerCloneSnapshot, iter->name());
task_runner_->PostDelayedTask(
- [weak_this, tsid] {
+ [weak_this, tsid, trigger_name = iter->name()] {
if (!weak_this)
return;
auto* tsess = weak_this->GetTracingSession(tsid);
if (!tsess || !tsess->consumer_maybe_null)
return;
- tsess->consumer_maybe_null->NotifyCloneSnapshotTrigger();
+ tsess->consumer_maybe_null->NotifyCloneSnapshotTrigger(
+ trigger_name);
},
iter->stop_delay_ms());
break;
@@ -4265,13 +4267,15 @@
observable_events->set_all_data_sources_started(true);
}
-void TracingServiceImpl::ConsumerEndpointImpl::NotifyCloneSnapshotTrigger() {
+void TracingServiceImpl::ConsumerEndpointImpl::NotifyCloneSnapshotTrigger(
+ const std::string& trigger_name) {
if (!(observable_events_mask_ & ObservableEvents::TYPE_CLONE_TRIGGER_HIT)) {
return;
}
auto* observable_events = AddObservableEvents();
auto* clone_trig = observable_events->mutable_clone_trigger_hit();
clone_trig->set_tracing_session_id(static_cast<int64_t>(tracing_session_id_));
+ clone_trig->set_trigger_name(trigger_name);
}
ObservableEvents*
diff --git a/src/tracing/service/tracing_service_impl.h b/src/tracing/service/tracing_service_impl.h
index 9fa84fe..1dbcbe6 100644
--- a/src/tracing/service/tracing_service_impl.h
+++ b/src/tracing/service/tracing_service_impl.h
@@ -32,6 +32,7 @@
#include "perfetto/base/time.h"
#include "perfetto/ext/base/circular_queue.h"
#include "perfetto/ext/base/periodic_task.h"
+#include "perfetto/ext/base/string_view.h"
#include "perfetto/ext/base/uuid.h"
#include "perfetto/ext/base/weak_ptr.h"
#include "perfetto/ext/tracing/core/basic_types.h"
@@ -211,7 +212,7 @@
~ConsumerEndpointImpl() override;
void NotifyOnTracingDisabled(const std::string& error);
- void NotifyCloneSnapshotTrigger();
+ void NotifyCloneSnapshotTrigger(const std::string& trigger_name);
// TracingService::ConsumerEndpoint implementation.
void EnableTracing(const TraceConfig&, base::ScopedFile) override;
diff --git a/test/.gitignore b/test/.gitignore
index 369c917..47a77bd 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -22,3 +22,7 @@
!/data/simpleperf
/data/simpleperf/*
!/data/simpleperf/*.sha256
+
+!/data/zip
+/data/zip/*
+!/data/zip/*.sha256
\ No newline at end of file
diff --git a/test/data/zip/perf_track_sym.zip.sha256 b/test/data/zip/perf_track_sym.zip.sha256
new file mode 100644
index 0000000..53dfcb3
--- /dev/null
+++ b/test/data/zip/perf_track_sym.zip.sha256
@@ -0,0 +1 @@
+146b1d8f48743323e91fd63d6ab5a1f6d8fcca8c5ea8455ebe8f087667a23c3f
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/include_index.py b/test/trace_processor/diff_tests/include_index.py
index 871abaf..e70dfa3 100644
--- a/test/trace_processor/diff_tests/include_index.py
+++ b/test/trace_processor/diff_tests/include_index.py
@@ -96,6 +96,7 @@
from diff_tests.parser.track_event.tests import TrackEvent
from diff_tests.parser.translated_args.tests import TranslatedArgs
from diff_tests.parser.ufs.tests import Ufs
+from diff_tests.parser.zip.tests import Zip
from diff_tests.stdlib.android.frames_tests import Frames
from diff_tests.stdlib.android.startups_tests import Startups
from diff_tests.stdlib.android.tests import AndroidStdlib
@@ -105,6 +106,7 @@
from diff_tests.stdlib.counters.tests import StdlibCounterIntervals
from diff_tests.stdlib.cpu.tests import Cpu
from diff_tests.stdlib.dynamic_tables.tests import DynamicTables
+from diff_tests.stdlib.gpu.tests import Gpu
from diff_tests.stdlib.graphs.dominator_tree_tests import DominatorTree
from diff_tests.stdlib.graphs.partition_tests import GraphPartitionTests
from diff_tests.stdlib.graphs.search_tests import GraphSearchTests
@@ -219,6 +221,7 @@
*FtraceCrop(index_path, 'parser/ftrace', 'FtraceCrop').fetch(),
*ParsingTracedStats(index_path, 'parser/parsing',
'ParsingTracedStats').fetch(),
+ *Zip(index_path, 'parser/zip', 'Zip').fetch(),
]
metrics_tests = [
@@ -265,6 +268,7 @@
*Cpu(index_path, 'stdlib/cpu', 'Cpu').fetch(),
*DominatorTree(index_path, 'stdlib/graphs', 'DominatorTree').fetch(),
*Frames(index_path, 'stdlib/android', 'Frames').fetch(),
+ *Gpu(index_path, 'stdlib/gpu', 'Gpu').fetch(),
*GraphSearchTests(index_path, 'stdlib/graphs',
'GraphSearchTests').fetch(),
*GraphPartitionTests(index_path, 'stdlib/graphs',
diff --git a/test/trace_processor/diff_tests/metrics/memory/tests.py b/test/trace_processor/diff_tests/metrics/memory/tests.py
index 7ea5fda..a5a5cec 100644
--- a/test/trace_processor/diff_tests/metrics/memory/tests.py
+++ b/test/trace_processor/diff_tests/metrics/memory/tests.py
@@ -248,6 +248,17 @@
}
"""))
+ def test_android_lmk_reason(self):
+ return DiffTestBlueprint(
+ trace=DataPath('lmk_userspace.pb'),
+ query=Metric('android_lmk_reason'),
+ # TODO(mayzner): Find a trace that returns results. This is still
+ # beneficial though, as at least this metric is run.
+ out=TextProto(r"""
+ android_lmk_reason {
+ }
+ """))
+
def test_android_mem_delta(self):
return DiffTestBlueprint(
trace=Path('android_mem_delta.py'),
diff --git a/test/trace_processor/diff_tests/parser/simpleperf/clocks_align_test.sql b/test/trace_processor/diff_tests/parser/simpleperf/clocks_align_test.sql
new file mode 100644
index 0000000..f5a65ee
--- /dev/null
+++ b/test/trace_processor/diff_tests/parser/simpleperf/clocks_align_test.sql
@@ -0,0 +1,99 @@
+--
+-- Copyright 2024 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 PERFETTO VIEW perf_sample_in(ts INT, dur INT)
+AS
+SELECT ts, 0 AS dur FROM perf_sample;
+
+CREATE VIRTUAL TABLE span
+USING
+ SPAN_JOIN(perf_sample_in, slice PARTITIONED depth);
+
+CREATE PERFETTO TABLE slice_stack
+AS
+WITH
+ tmp AS (
+ SELECT
+ ts,
+ parent_stack_id,
+ string_AGG(IIF(name = 'Main loop', 'main', name), ',')
+ OVER (
+ PARTITION BY ts
+ ORDER BY depth ASC
+ RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
+ ) AS stack
+ FROM span
+ )
+SELECT ts, stack FROM tmp WHERE parent_stack_id = 0 ORDER BY TS ASC;
+
+CREATE PERFETTO TABLE perf_stack
+AS
+WITH
+ symbol AS (
+ SELECT
+ id,
+ symbol_set_id,
+ replace(replace(name, '(anonymous namespace)::', ''), '()', '') AS name
+ FROM stack_profile_symbol
+ ),
+ symbol_agg AS (
+ SELECT
+ id,
+ symbol_set_id,
+ string_agg(name, ',')
+ OVER (
+ PARTITION BY symbol_set_id
+ ORDER BY id DESC
+ RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
+ ) AS name
+ FROM symbol
+ WHERE name IN ('main', 'A', 'B', 'C', 'D', 'E')
+ ),
+ inline AS (
+ SELECT symbol_set_id, name FROM symbol_agg WHERE id = symbol_set_id
+ ),
+ frame AS (
+ SELECT f.id AS frame_id, i.name
+ FROM STACK_PROFILE_FRAME f, inline i
+ USING (symbol_set_id)
+ ),
+ child AS (
+ SELECT
+ s.ts,
+ spc.id,
+ spc.parent_id,
+ name
+ FROM perf_sample s, stack_profile_callsite spc
+ ON (s.callsite_id = spc.id),
+ frame USING (frame_id)
+ UNION ALL
+ SELECT
+ child.ts,
+ parent.id,
+ parent.parent_id,
+ COALESCE(f.name || ',', '') || child.name AS name
+ FROM child, stack_profile_callsite parent
+ ON (child.parent_id = parent.id)
+ LEFT JOIN frame f
+ USING (frame_id)
+ )
+SELECT ts, name AS stack FROM child WHERE parent_id IS NULL ORDER BY ts ASC;
+
+SELECT COUNT(*) AS misaligned_count
+FROM slice_stack s
+FULL JOIN perf_stack p
+ USING (ts)
+WHERE s.stack <> p.stack;
diff --git a/test/trace_processor/diff_tests/parser/simpleperf/tests.py b/test/trace_processor/diff_tests/parser/simpleperf/tests.py
index c98239d..4f5a22b 100644
--- a/test/trace_processor/diff_tests/parser/simpleperf/tests.py
+++ b/test/trace_processor/diff_tests/parser/simpleperf/tests.py
@@ -142,3 +142,12 @@
"0b12a384a9f4a3f3659b7171ca615dbec3a81f71","/t1"
"0b12a384a9f4a3f3659b7171ca615dbec3a81f71","/t2"
'''))
+
+ def test_clocks_align(self):
+ return DiffTestBlueprint(
+ trace=DataPath('zip/perf_track_sym.zip'),
+ query=Path('clocks_align_test.sql'),
+ out=Csv('''
+ "misaligned_count"
+ 0
+ '''))
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/parser/zip/stacks_test.sql b/test/trace_processor/diff_tests/parser/zip/stacks_test.sql
new file mode 100644
index 0000000..68543f1
--- /dev/null
+++ b/test/trace_processor/diff_tests/parser/zip/stacks_test.sql
@@ -0,0 +1,48 @@
+WITH
+ symbol AS (
+ SELECT
+ id,
+ symbol_set_id,
+ replace(replace(name, '(anonymous namespace)::', ''), '()', '') AS name
+ FROM stack_profile_symbol
+ ),
+ symbol_agg AS (
+ SELECT
+ id,
+ symbol_set_id,
+ string_agg(name, ',')
+ OVER (
+ PARTITION BY symbol_set_id
+ ORDER BY id DESC
+ RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
+ ) AS name
+ FROM symbol
+ WHERE name IN ('main', 'A', 'B', 'C', 'D', 'E')
+ ),
+ inline AS (
+ SELECT symbol_set_id, name FROM symbol_agg WHERE id = symbol_set_id
+ ),
+ frame AS (
+ SELECT f.id AS frame_id, i.name
+ FROM STACK_PROFILE_FRAME f, inline i
+ USING (symbol_set_id)
+ ),
+ child AS (
+ SELECT
+ spc.id,
+ spc.parent_id,
+ name
+ FROM perf_sample s, stack_profile_callsite spc
+ ON (s.callsite_id = spc.id),
+ frame USING (frame_id)
+ UNION ALL
+ SELECT
+ parent.id,
+ parent.parent_id,
+ COALESCE(f.name || ',', '') || child.name AS name
+ FROM child, stack_profile_callsite parent
+ ON (child.parent_id = parent.id)
+ LEFT JOIN frame f
+ USING (frame_id)
+ )
+SELECT DISTINCT name FROM child WHERE parent_id IS NULL ORDER BY name
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/parser/zip/tests.py b/test/trace_processor/diff_tests/parser/zip/tests.py
new file mode 100644
index 0000000..9827072
--- /dev/null
+++ b/test/trace_processor/diff_tests/parser/zip/tests.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+# Copyright (C) 2023 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 a
+#
+# 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.
+
+from python.generators.diff_tests.testing import Csv, Path, DataPath
+from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import TestSuite
+
+
+class Zip(TestSuite):
+
+ def test_perf_proto_sym(self):
+ return DiffTestBlueprint(
+ trace=DataPath('zip/perf_track_sym.zip'),
+ query=Path('stacks_test.sql'),
+ out=Csv('''
+ "name"
+ "main,A"
+ "main,A,B"
+ "main,A,B,C"
+ "main,A,B,C,D"
+ "main,A,B,C,D,E"
+ "main,A,B,C,E"
+ "main,A,B,D"
+ "main,A,B,D,E"
+ "main,A,B,E"
+ "main,A,C"
+ "main,A,C,D"
+ "main,A,C,D,E"
+ "main,A,C,E"
+ "main,A,D"
+ "main,A,D,E"
+ "main,A,E"
+ "main,B"
+ "main,B,C"
+ "main,B,C,D"
+ "main,B,C,D,E"
+ "main,B,C,E"
+ "main,B,D"
+ "main,B,D,E"
+ "main,B,E"
+ "main,C"
+ "main,C,D"
+ "main,C,D,E"
+ "main,C,E"
+ "main,D"
+ "main,D,E"
+ "main,E"
+ '''))
diff --git a/test/trace_processor/diff_tests/stdlib/android/tests.py b/test/trace_processor/diff_tests/stdlib/android/tests.py
index 59a8877..6781e3e 100644
--- a/test/trace_processor/diff_tests/stdlib/android/tests.py
+++ b/test/trace_processor/diff_tests/stdlib/android/tests.py
@@ -1244,16 +1244,16 @@
""",
out=Csv("""
"ts","dur","score","bucket","process_name","oom_adj_ts","oom_adj_dur","oom_adj_thread_name","oom_adj_reason","oom_adj_trigger"
- 1737065264829,701108081,925,"cached_app","com.android.providers.calendar",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
- 1737066678827,3470211742,935,"cached_app","com.android.imsserviceentitlement",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
- 1737066873002,3470017567,945,"cached_app","com.android.carrierconfig",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
- 1737067058812,3469831757,955,"cached_app_lmk_first","com.android.messaging",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
- 1737067246975,699224817,955,"cached_app_lmk_first","android.process.acore",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
- 1737068421919,3468468650,965,"cached_app_lmk_first","com.android.shell",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
- 1737068599673,697908135,965,"cached_app_lmk_first","android.process.media",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
- 1737068933602,3467956967,975,"cached_app_lmk_first","com.android.gallery3d",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
- 1737069091010,3467799559,975,"cached_app_lmk_first","com.android.packageinstaller",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
- 1737069240534,3467650035,985,"cached_app_lmk_first","com.android.managedprovisioning",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+1737065264829,701108081,925,"cached","com.android.providers.calendar",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+1737066678827,3470211742,935,"cached","com.android.imsserviceentitlement",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+1737066873002,3470017567,945,"cached","com.android.carrierconfig",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+1737067058812,3469831757,955,"cached","com.android.messaging",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+1737067246975,699224817,955,"cached","android.process.acore",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+1737068421919,3468468650,965,"cached","com.android.shell",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+1737068599673,697908135,965,"cached","android.process.media",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+1737068933602,3467956967,975,"cached","com.android.gallery3d",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+1737069091010,3467799559,975,"cached","com.android.packageinstaller",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
+1737069240534,3467650035,985,"cached","com.android.managedprovisioning",1737064421516,29484835,"binder:642_1","processEnd","IActivityManager#1598246212"
"""))
def test_broadcast_minsdk_u(self):
diff --git a/test/trace_processor/diff_tests/stdlib/gpu/tests.py b/test/trace_processor/diff_tests/stdlib/gpu/tests.py
new file mode 100644
index 0000000..2c23e80
--- /dev/null
+++ b/test/trace_processor/diff_tests/stdlib/gpu/tests.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python3
+# Copyright (C) 2023 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 a
+#
+# 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.
+
+from python.generators.diff_tests.testing import Path, DataPath, Metric, Systrace
+from python.generators.diff_tests.testing import Csv, Json, TextProto, BinaryProto
+from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import TestSuite
+from python.generators.diff_tests.testing import PrintProfileProto
+
+
+class Gpu(TestSuite):
+
+ def test_gpu_frequency(self):
+ return DiffTestBlueprint(
+ trace=Path('../../metrics/graphics/gpu_frequency_metric.textproto'),
+ query="""
+ INCLUDE PERFETTO MODULE gpu.frequency;
+ SELECT *
+ FROM gpu_frequency;
+ """,
+ out=Csv("""
+ "ts","dur","gpu_id","gpu_freq"
+ 200001000000,2000000,0,585000
+ 200003000000,1000000,0,0
+ 200004000000,2000000,0,603000
+ 200002000000,3000000,1,400000
+ 200005000000,1000000,1,758000
+ """))
diff --git a/test/trace_processor/diff_tests/stdlib/memory/tests.py b/test/trace_processor/diff_tests/stdlib/memory/tests.py
index bc8f16d..d781b54 100644
--- a/test/trace_processor/diff_tests/stdlib/memory/tests.py
+++ b/test/trace_processor/diff_tests/stdlib/memory/tests.py
@@ -67,3 +67,45 @@
38090817604,11930827,1,1982,"com.android.systemui",373714944
"""))
+ def test_memory_oom_score_with_rss_and_swap_per_process(self):
+ return DiffTestBlueprint(
+ trace=DataPath('sched_wakeup_trace.atr'),
+ query="""
+ INCLUDE PERFETTO MODULE memory.linux.process;
+ SELECT *
+ FROM memory_oom_score_with_rss_and_swap_per_process
+ WHERE oom_adj_reason IS NOT NULL
+ ORDER BY ts
+ LIMIT 10;
+ """,
+ out=Csv("""
+ "ts","dur","score","bucket","upid","process_name","pid","oom_adj_id","oom_adj_ts","oom_adj_dur","oom_adj_track_id","oom_adj_thread_name","oom_adj_reason","oom_adj_trigger","anon_rss","file_rss","shmem_rss","rss","swap","anon_rss_and_swap","rss_and_swap"
+ 1737065264829,701108081,925,"cached",269,"com.android.providers.calendar",1937,332,1737064421516,29484835,1217,"binder:642_1","processEnd","IActivityManager#1598246212",49229824,57495552,835584,107560960,0,49229824,107560960
+ 1737066678827,2934486383,935,"cached",287,"com.android.imsserviceentitlement",2397,332,1737064421516,29484835,1217,"binder:642_1","processEnd","IActivityManager#1598246212",48881664,57081856,831488,106795008,0,48881664,106795008
+ 1737066873002,2934292208,945,"cached",292,"com.android.carrierconfig",2593,332,1737064421516,29484835,1217,"binder:642_1","processEnd","IActivityManager#1598246212",48586752,49872896,823296,99282944,0,48586752,99282944
+ 1737067058812,2934106398,955,"cached",288,"com.android.messaging",2416,332,1737064421516,29484835,1217,"binder:642_1","processEnd","IActivityManager#1598246212",54956032,71417856,843776,127217664,0,54956032,127217664
+ 1737067246975,699224817,955,"cached",267,"android.process.acore",1866,332,1737064421516,29484835,1217,"binder:642_1","processEnd","IActivityManager#1598246212",52498432,72048640,856064,125403136,0,52498432,125403136
+ 1737068421919,2932743291,965,"cached",273,"com.android.shell",2079,332,1737064421516,29484835,1217,"binder:642_1","processEnd","IActivityManager#1598246212",48738304,52056064,823296,101617664,0,48738304,101617664
+ 1737068599673,970398,965,"cached",271,"android.process.media",2003,332,1737064421516,29484835,1217,"binder:642_1","processEnd","IActivityManager#1598246212",49917952,60444672,839680,111202304,0,49917952,111202304
+ 1737068933602,2932231608,975,"cached",286,"com.android.gallery3d",2371,332,1737064421516,29484835,1217,"binder:642_1","processEnd","IActivityManager#1598246212",49561600,54521856,831488,104914944,0,49561600,104914944
+ 1737069091010,682459310,975,"cached",289,"com.android.packageinstaller",2480,332,1737064421516,29484835,1217,"binder:642_1","processEnd","IActivityManager#1598246212",49364992,52539392,827392,102731776,0,49364992,102731776
+ 1737069240534,489635,985,"cached",268,"com.android.managedprovisioning",1868,332,1737064421516,29484835,1217,"binder:642_1","processEnd","IActivityManager#1598246212",50683904,53985280,815104,105484288,0,50683904,105484288
+ """))
+
+ def test_memory_gpu_per_process(self):
+ return DiffTestBlueprint(
+ trace=Path('../../metrics/graphics/gpu_metric.py'),
+ query="""
+ INCLUDE PERFETTO MODULE memory.android.gpu;
+ SELECT *
+ FROM memory_gpu_per_process;
+ """,
+ out=Csv("""
+ "ts","dur","upid","gpu_memory"
+ 2,2,2,6
+ 4,6,2,8
+ 4,5,1,2
+ 9,1,1,8
+ 6,1,3,7
+ 7,3,3,10
+ """))
diff --git a/test/trace_processor/diff_tests/tables/tests_sched.py b/test/trace_processor/diff_tests/tables/tests_sched.py
index ad23a5d..f13d42c 100644
--- a/test/trace_processor/diff_tests/tables/tests_sched.py
+++ b/test/trace_processor/diff_tests/tables/tests_sched.py
@@ -487,22 +487,24 @@
table_name,
critical_path_utid
FROM _thread_executing_span_critical_path_stack((select utid from thread where tid = 3487), start_ts, end_ts), trace_bounds
- ORDER BY ts
- LIMIT 11
+ WHERE ts = 1737500355691
+ ORDER BY utid, id
""",
out=Csv("""
"id","ts","dur","utid","stack_depth","name","table_name","critical_path_utid"
- 11889,1737349401439,57188,1477,0,"thread_state: R","thread_state",1477
- 11889,1737349401439,57188,1477,1,"[NULL]","thread_state",1477
- 11889,1737349401439,57188,1477,2,"[NULL]","thread_state",1477
- 11889,1737349401439,57188,1477,3,"process_name: com.android.providers.media.module","thread_state",1477
- 11889,1737349401439,57188,1477,4,"thread_name: rs.media.module","thread_state",1477
- 11891,1737349458627,1884896,1477,0,"thread_state: Running","thread_state",1477
- 11891,1737349458627,1884896,1477,1,"[NULL]","thread_state",1477
- 11891,1737349458627,1884896,1477,2,"[NULL]","thread_state",1477
- 11891,1737349458627,1884896,1477,3,"process_name: com.android.providers.media.module","thread_state",1477
- 11891,1737349458627,1884896,1477,4,"thread_name: rs.media.module","thread_state",1477
- 11891,1737349458627,1884896,1477,5,"cpu: 0","thread_state",1477
+ 4271,1737500355691,1456753,1477,5,"bindApplication","slice",1477
+ 13120,1737500355691,1456753,1477,0,"thread_state: S","thread_state",1477
+ 13120,1737500355691,1456753,1477,1,"[NULL]","thread_state",1477
+ 13120,1737500355691,1456753,1477,2,"[NULL]","thread_state",1477
+ 13120,1737500355691,1456753,1477,3,"process_name: com.android.providers.media.module","thread_state",1477
+ 13120,1737500355691,1456753,1477,4,"thread_name: rs.media.module","thread_state",1477
+ 4800,1737500355691,1456753,1498,11,"HIDL::IComponentStore::getStructDescriptors::client","slice",1477
+ 4801,1737500355691,1456753,1498,12,"binder transaction","slice",1477
+ 13648,1737500355691,1456753,1498,6,"blocking thread_state: R+","thread_state",1477
+ 13648,1737500355691,1456753,1498,7,"blocking process_name: com.android.providers.media.module","thread_state",1477
+ 13648,1737500355691,1456753,1498,8,"blocking thread_name: CodecLooper","thread_state",1477
+ 13648,1737500355691,1456753,1498,9,"[NULL]","thread_state",1477
+ 13648,1737500355691,1456753,1498,10,"[NULL]","thread_state",1477
"""))
def test_thread_executing_span_critical_path_graph(self):
diff --git a/ui/src/core/default_plugins.ts b/ui/src/core/default_plugins.ts
index 4f5460e..44b4e21 100644
--- a/ui/src/core/default_plugins.ts
+++ b/ui/src/core/default_plugins.ts
@@ -58,4 +58,5 @@
'perfetto.VisualisedArgs',
'org.kernel.LinuxKernelDevices',
'perfetto.TrackUtils',
+ 'com.google.PixelMemory',
];
diff --git a/ui/src/frontend/error_dialog.ts b/ui/src/frontend/error_dialog.ts
index f2cea37..835292e 100644
--- a/ui/src/frontend/error_dialog.ts
+++ b/ui/src/frontend/error_dialog.ts
@@ -36,6 +36,7 @@
// Here we rely on the exception message from onCannotGrowMemory function
if (
err.message.includes('Cannot enlarge memory') ||
+ err.stack.some((entry) => entry.name.includes('OutOfMemoryHandler')) ||
err.stack.some((entry) => entry.name.includes('_emscripten_resize_heap')) ||
err.stack.some((entry) => entry.name.includes('sbrk')) ||
/^out of memory$/m.exec(err.message)
diff --git a/ui/src/plugins/com.google.PixelMemory/OWNERS b/ui/src/plugins/com.google.PixelMemory/OWNERS
new file mode 100644
index 0000000..249152a
--- /dev/null
+++ b/ui/src/plugins/com.google.PixelMemory/OWNERS
@@ -0,0 +1 @@
+liumartin@google.com
diff --git a/ui/src/plugins/com.google.PixelMemory/index.ts b/ui/src/plugins/com.google.PixelMemory/index.ts
new file mode 100644
index 0000000..c79faf2
--- /dev/null
+++ b/ui/src/plugins/com.google.PixelMemory/index.ts
@@ -0,0 +1,63 @@
+// Copyright (C) 2024 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 {Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
+
+import {addDebugCounterTrack} from '../../frontend/debug_tracks';
+
+class PixelMemory implements Plugin {
+ async onTraceLoad(ctx: PluginContextTrace): Promise<void> {
+ ctx.registerCommand({
+ id: 'dev.perfetto.PixelMemory#ShowTotalMemory',
+ name: 'Add tracks: show a process total memory',
+ callback: async (pid) => {
+ if (pid === undefined) {
+ pid = prompt('Enter a process pid', '');
+ if (pid === null) return;
+ }
+ const RSS_ALL = `
+ INCLUDE PERFETTO MODULE memory.linux.process;
+ INCLUDE PERFETTO MODULE memory.android.gpu;
+
+ DROP TABLE IF EXISTS process_mem_rss_anon_file_shmem_swap_gpu;
+
+ CREATE VIRTUAL TABLE process_mem_rss_anon_file_shmem_swap_gpu
+ USING
+ SPAN_OUTER_JOIN(
+ memory_gpu_per_process PARTITIONED upid, memory_rss_and_swap_per_process PARTITIONED upid);
+ `;
+ await ctx.engine.query(RSS_ALL);
+ await addDebugCounterTrack(
+ {
+ sqlSource: `
+ SELECT
+ ts,
+ COALESCE(rss_and_swap, 0) + COALESCE(gpu_memory, 0) AS value
+ FROM process_mem_rss_anon_file_shmem_swap_gpu
+ WHERE pid = ${pid}
+ `,
+ columns: ['ts', 'value'],
+ },
+ pid + '_rss_anon_file_swap_shmem_gpu',
+ {ts: 'ts', value: 'value'},
+ );
+ },
+ });
+ }
+}
+
+export const plugin: PluginDescriptor = {
+ pluginId: 'com.google.PixelMemory',
+ plugin: PixelMemory,
+};