Add suport for TAR files
Changes in this cl:
* Tar file reader
* Move all archive related importers to a common dir
* Tar files also need to sort trace files prior to sendind data to the
sorting stage (same as ZIP) so this cl extracts that logic to its own
class: CombinedTraceParser
* Simplified a bit the tracking of trace_files
* The TraceFileTable now tracks all files detected during parsing and
explicitly shows the order in which they were parsed.
* Add an efficient way of extracting multiple TraceBlobView spans from a
TraceBlobViewReader (avoiding the copy to a contiguous buffer).
Change-Id: I09f32c9304fcfec4853d0c3e8cb1d955df3a641a
diff --git a/Android.bp b/Android.bp
index 4db773b..d0729b4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2467,6 +2467,7 @@
":perfetto_src_trace_processor_export_json",
":perfetto_src_trace_processor_importers_android_bugreport_android_bugreport",
":perfetto_src_trace_processor_importers_android_bugreport_android_log_event",
+ ":perfetto_src_trace_processor_importers_archive_archive",
":perfetto_src_trace_processor_importers_art_method_art_method",
":perfetto_src_trace_processor_importers_art_method_art_method_event",
":perfetto_src_trace_processor_importers_common_common",
@@ -2481,7 +2482,6 @@
":perfetto_src_trace_processor_importers_fuchsia_full",
":perfetto_src_trace_processor_importers_fuchsia_minimal",
":perfetto_src_trace_processor_importers_gecko_gecko_event",
- ":perfetto_src_trace_processor_importers_gzip_full",
":perfetto_src_trace_processor_importers_i2c_full",
":perfetto_src_trace_processor_importers_instruments_instruments",
":perfetto_src_trace_processor_importers_instruments_row",
@@ -2504,7 +2504,6 @@
":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",
@@ -12399,6 +12398,17 @@
],
}
+// GN: //src/trace_processor/importers/archive:archive
+filegroup {
+ name: "perfetto_src_trace_processor_importers_archive_archive",
+ srcs: [
+ "src/trace_processor/importers/archive/archive_entry.cc",
+ "src/trace_processor/importers/archive/gzip_trace_parser.cc",
+ "src/trace_processor/importers/archive/tar_trace_reader.cc",
+ "src/trace_processor/importers/archive/zip_trace_reader.cc",
+ ],
+}
+
// GN: //src/trace_processor/importers/art_method:art_method
filegroup {
name: "perfetto_src_trace_processor_importers_art_method_art_method",
@@ -12435,7 +12445,6 @@
"src/trace_processor/importers/common/process_track_translation_table.cc",
"src/trace_processor/importers/common/process_tracker.cc",
"src/trace_processor/importers/common/sched_event_tracker.cc",
- "src/trace_processor/importers/common/scoped_active_trace_file.cc",
"src/trace_processor/importers/common/slice_tracker.cc",
"src/trace_processor/importers/common/slice_translation_table.cc",
"src/trace_processor/importers/common/stack_profile_tracker.cc",
@@ -12581,14 +12590,6 @@
name: "perfetto_src_trace_processor_importers_gecko_gecko_event",
}
-// GN: //src/trace_processor/importers/gzip:full
-filegroup {
- name: "perfetto_src_trace_processor_importers_gzip_full",
- srcs: [
- "src/trace_processor/importers/gzip/gzip_trace_parser.cc",
- ],
-}
-
// GN: //src/trace_processor/importers/i2c:full
filegroup {
name: "perfetto_src_trace_processor_importers_i2c_full",
@@ -12996,14 +12997,6 @@
],
}
-// 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",
@@ -15626,6 +15619,7 @@
":perfetto_src_trace_processor_importers_android_bugreport_android_bugreport",
":perfetto_src_trace_processor_importers_android_bugreport_android_log_event",
":perfetto_src_trace_processor_importers_android_bugreport_unittests",
+ ":perfetto_src_trace_processor_importers_archive_archive",
":perfetto_src_trace_processor_importers_art_method_art_method",
":perfetto_src_trace_processor_importers_art_method_art_method_event",
":perfetto_src_trace_processor_importers_common_common",
@@ -15643,7 +15637,6 @@
":perfetto_src_trace_processor_importers_fuchsia_minimal",
":perfetto_src_trace_processor_importers_fuchsia_unittests",
":perfetto_src_trace_processor_importers_gecko_gecko_event",
- ":perfetto_src_trace_processor_importers_gzip_full",
":perfetto_src_trace_processor_importers_i2c_full",
":perfetto_src_trace_processor_importers_instruments_instruments",
":perfetto_src_trace_processor_importers_instruments_row",
@@ -15671,7 +15664,6 @@
":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",
@@ -16701,6 +16693,7 @@
":perfetto_src_trace_processor_export_json",
":perfetto_src_trace_processor_importers_android_bugreport_android_bugreport",
":perfetto_src_trace_processor_importers_android_bugreport_android_log_event",
+ ":perfetto_src_trace_processor_importers_archive_archive",
":perfetto_src_trace_processor_importers_art_method_art_method",
":perfetto_src_trace_processor_importers_art_method_art_method_event",
":perfetto_src_trace_processor_importers_common_common",
@@ -16715,7 +16708,6 @@
":perfetto_src_trace_processor_importers_fuchsia_full",
":perfetto_src_trace_processor_importers_fuchsia_minimal",
":perfetto_src_trace_processor_importers_gecko_gecko_event",
- ":perfetto_src_trace_processor_importers_gzip_full",
":perfetto_src_trace_processor_importers_i2c_full",
":perfetto_src_trace_processor_importers_instruments_instruments",
":perfetto_src_trace_processor_importers_instruments_row",
@@ -16738,7 +16730,6 @@
":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",
@@ -17128,6 +17119,7 @@
":perfetto_src_trace_processor_export_json",
":perfetto_src_trace_processor_importers_android_bugreport_android_bugreport",
":perfetto_src_trace_processor_importers_android_bugreport_android_log_event",
+ ":perfetto_src_trace_processor_importers_archive_archive",
":perfetto_src_trace_processor_importers_art_method_art_method",
":perfetto_src_trace_processor_importers_art_method_art_method_event",
":perfetto_src_trace_processor_importers_common_common",
@@ -17142,7 +17134,6 @@
":perfetto_src_trace_processor_importers_fuchsia_full",
":perfetto_src_trace_processor_importers_fuchsia_minimal",
":perfetto_src_trace_processor_importers_gecko_gecko_event",
- ":perfetto_src_trace_processor_importers_gzip_full",
":perfetto_src_trace_processor_importers_i2c_full",
":perfetto_src_trace_processor_importers_instruments_instruments",
":perfetto_src_trace_processor_importers_instruments_row",
@@ -17165,7 +17156,6 @@
":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 e03af4f..9201633 100644
--- a/BUILD
+++ b/BUILD
@@ -223,6 +223,7 @@
":src_trace_processor_export_json",
":src_trace_processor_importers_android_bugreport_android_bugreport",
":src_trace_processor_importers_android_bugreport_android_log_event",
+ ":src_trace_processor_importers_archive_archive",
":src_trace_processor_importers_art_method_art_method",
":src_trace_processor_importers_art_method_art_method_event",
":src_trace_processor_importers_common_common",
@@ -238,7 +239,6 @@
":src_trace_processor_importers_fuchsia_minimal",
":src_trace_processor_importers_gecko_gecko",
":src_trace_processor_importers_gecko_gecko_event",
- ":src_trace_processor_importers_gzip_full",
":src_trace_processor_importers_i2c_full",
":src_trace_processor_importers_instruments_instruments",
":src_trace_processor_importers_instruments_row",
@@ -261,7 +261,6 @@
":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",
@@ -1520,6 +1519,21 @@
],
)
+# GN target: //src/trace_processor/importers/archive:archive
+perfetto_filegroup(
+ name = "src_trace_processor_importers_archive_archive",
+ srcs = [
+ "src/trace_processor/importers/archive/archive_entry.cc",
+ "src/trace_processor/importers/archive/archive_entry.h",
+ "src/trace_processor/importers/archive/gzip_trace_parser.cc",
+ "src/trace_processor/importers/archive/gzip_trace_parser.h",
+ "src/trace_processor/importers/archive/tar_trace_reader.cc",
+ "src/trace_processor/importers/archive/tar_trace_reader.h",
+ "src/trace_processor/importers/archive/zip_trace_reader.cc",
+ "src/trace_processor/importers/archive/zip_trace_reader.h",
+ ],
+)
+
# GN target: //src/trace_processor/importers/art_method:art_method
perfetto_filegroup(
name = "src_trace_processor_importers_art_method_art_method",
@@ -1583,8 +1597,6 @@
"src/trace_processor/importers/common/sched_event_state.h",
"src/trace_processor/importers/common/sched_event_tracker.cc",
"src/trace_processor/importers/common/sched_event_tracker.h",
- "src/trace_processor/importers/common/scoped_active_trace_file.cc",
- "src/trace_processor/importers/common/scoped_active_trace_file.h",
"src/trace_processor/importers/common/slice_tracker.cc",
"src/trace_processor/importers/common/slice_tracker.h",
"src/trace_processor/importers/common/slice_translation_table.cc",
@@ -1748,15 +1760,6 @@
],
)
-# GN target: //src/trace_processor/importers/gzip:full
-perfetto_filegroup(
- name = "src_trace_processor_importers_gzip_full",
- srcs = [
- "src/trace_processor/importers/gzip/gzip_trace_parser.cc",
- "src/trace_processor/importers/gzip/gzip_trace_parser.h",
- ],
-)
-
# GN target: //src/trace_processor/importers/i2c:full
perfetto_filegroup(
name = "src_trace_processor_importers_i2c_full",
@@ -2200,15 +2203,6 @@
],
)
-# 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",
@@ -6410,6 +6404,7 @@
":src_trace_processor_export_json",
":src_trace_processor_importers_android_bugreport_android_bugreport",
":src_trace_processor_importers_android_bugreport_android_log_event",
+ ":src_trace_processor_importers_archive_archive",
":src_trace_processor_importers_art_method_art_method",
":src_trace_processor_importers_art_method_art_method_event",
":src_trace_processor_importers_common_common",
@@ -6425,7 +6420,6 @@
":src_trace_processor_importers_fuchsia_minimal",
":src_trace_processor_importers_gecko_gecko",
":src_trace_processor_importers_gecko_gecko_event",
- ":src_trace_processor_importers_gzip_full",
":src_trace_processor_importers_i2c_full",
":src_trace_processor_importers_instruments_instruments",
":src_trace_processor_importers_instruments_row",
@@ -6448,7 +6442,6 @@
":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",
@@ -6614,6 +6607,7 @@
":src_trace_processor_export_json",
":src_trace_processor_importers_android_bugreport_android_bugreport",
":src_trace_processor_importers_android_bugreport_android_log_event",
+ ":src_trace_processor_importers_archive_archive",
":src_trace_processor_importers_art_method_art_method",
":src_trace_processor_importers_art_method_art_method_event",
":src_trace_processor_importers_common_common",
@@ -6629,7 +6623,6 @@
":src_trace_processor_importers_fuchsia_minimal",
":src_trace_processor_importers_gecko_gecko",
":src_trace_processor_importers_gecko_gecko_event",
- ":src_trace_processor_importers_gzip_full",
":src_trace_processor_importers_i2c_full",
":src_trace_processor_importers_instruments_instruments",
":src_trace_processor_importers_instruments_row",
@@ -6652,7 +6645,6 @@
":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",
@@ -6875,6 +6867,7 @@
":src_trace_processor_export_json",
":src_trace_processor_importers_android_bugreport_android_bugreport",
":src_trace_processor_importers_android_bugreport_android_log_event",
+ ":src_trace_processor_importers_archive_archive",
":src_trace_processor_importers_art_method_art_method",
":src_trace_processor_importers_art_method_art_method_event",
":src_trace_processor_importers_common_common",
@@ -6890,7 +6883,6 @@
":src_trace_processor_importers_fuchsia_minimal",
":src_trace_processor_importers_gecko_gecko",
":src_trace_processor_importers_gecko_gecko_event",
- ":src_trace_processor_importers_gzip_full",
":src_trace_processor_importers_i2c_full",
":src_trace_processor_importers_instruments_instruments",
":src_trace_processor_importers_instruments_row",
@@ -6913,7 +6905,6 @@
":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/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index a6bff20..0e99a43 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -168,12 +168,12 @@
"../protozero",
"db",
"importers/android_bugreport",
+ "importers/archive",
"importers/art_method",
"importers/common",
"importers/etw:full",
"importers/ftrace:full",
"importers/fuchsia:full",
- "importers/gzip:full",
"importers/json:full",
"importers/json:minimal",
"importers/ninja",
@@ -182,7 +182,6 @@
"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 bc9f044..23b32b1 100644
--- a/src/trace_processor/forwarding_trace_parser.cc
+++ b/src/trace_processor/forwarding_trace_parser.cc
@@ -26,9 +26,11 @@
#include "perfetto/trace_processor/basic_types.h"
#include "src/trace_processor/importers/common/chunked_trace_reader.h"
#include "src/trace_processor/importers/common/process_tracker.h"
+#include "src/trace_processor/importers/common/trace_file_tracker.h"
#include "src/trace_processor/importers/proto/proto_trace_reader.h"
#include "src/trace_processor/sorter/trace_sorter.h"
#include "src/trace_processor/storage/stats.h"
+#include "src/trace_processor/tables/metadata_tables_py.h"
#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"
@@ -65,6 +67,7 @@
case kJsonTraceType:
case kFuchsiaTraceType:
case kZipFile:
+ case kTarTraceType:
case kAndroidLogcatTraceType:
case kGeckoTraceType:
case kArtMethodTraceType:
@@ -85,8 +88,9 @@
} // namespace
-ForwardingTraceParser::ForwardingTraceParser(TraceProcessorContext* context)
- : context_(context) {}
+ForwardingTraceParser::ForwardingTraceParser(TraceProcessorContext* context,
+ tables::TraceFileTable::Id id)
+ : context_(context), file_id_(id) {}
ForwardingTraceParser::~ForwardingTraceParser() {}
@@ -104,6 +108,8 @@
return base::ErrStatus("Unknown trace type provided (ERR:fmt)");
}
+ context_->trace_file_tracker->StartParsing(file_id_, trace_type_);
+
base::StatusOr<std::unique_ptr<ChunkedTraceReader>> reader_or =
context_->reader_registry->CreateTraceReader(trace_type_);
if (!reader_or.ok()) {
@@ -151,11 +157,17 @@
if (!reader_) {
RETURN_IF_ERROR(Init(blob));
}
+ trace_size_ += blob.size();
return reader_->Parse(std::move(blob));
}
base::Status ForwardingTraceParser::NotifyEndOfFile() {
- return reader_ ? reader_->NotifyEndOfFile() : base::OkStatus();
+ base::Status status = base::OkStatus();
+ if (reader_) {
+ status = reader_->NotifyEndOfFile();
+ }
+ context_->trace_file_tracker->DoneParsing(file_id_, trace_size_);
+ return status;
}
} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/forwarding_trace_parser.h b/src/trace_processor/forwarding_trace_parser.h
index fa90279..1f4858a 100644
--- a/src/trace_processor/forwarding_trace_parser.h
+++ b/src/trace_processor/forwarding_trace_parser.h
@@ -22,6 +22,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/tables/metadata_tables_py.h"
#include "src/trace_processor/util/trace_type.h"
namespace perfetto::trace_processor {
@@ -30,7 +31,8 @@
class ForwardingTraceParser : public ChunkedTraceReader {
public:
- explicit ForwardingTraceParser(TraceProcessorContext*);
+ explicit ForwardingTraceParser(TraceProcessorContext*,
+ tables::TraceFileTable::Id);
~ForwardingTraceParser() override;
// ChunkedTraceReader implementation
@@ -43,6 +45,8 @@
base::Status Init(const TraceBlobView&);
void UpdateSorterForTraceType(TraceType trace_type);
TraceProcessorContext* const context_;
+ tables::TraceFileTable::Id file_id_;
+ size_t trace_size_ = 0;
std::unique_ptr<ChunkedTraceReader> reader_;
TraceType trace_type_ = kUnknownTraceType;
};
diff --git a/src/trace_processor/importers/android_bugreport/android_bugreport_reader.cc b/src/trace_processor/importers/android_bugreport/android_bugreport_reader.cc
index fee307f..07c8434 100644
--- a/src/trace_processor/importers/android_bugreport/android_bugreport_reader.cc
+++ b/src/trace_processor/importers/android_bugreport/android_bugreport_reader.cc
@@ -104,17 +104,21 @@
// Move the file to the end move it out of the list and pop the back.
std::swap(files[res->file_index], files.back());
- BugReportFile bug_report{res->year, std::move(files.back())};
+ auto id = context->trace_file_tracker->AddFile(files.back().name());
+ BugReportFile bug_report{id, res->year, std::move(files.back())};
files.pop_back();
std::set<LogFile> ordered_log_files;
for (size_t i = 0; i < files.size(); ++i) {
+ id = context->trace_file_tracker->AddFile(files[i].name());
+ // Set size in case we end up not parsing this file.
+ context->trace_file_tracker->SetSize(id, files[i].compressed_size());
if (!IsLogFile(files[i])) {
continue;
}
int64_t timestamp = files[i].GetDatetime();
- ordered_log_files.insert(LogFile{timestamp, std::move(files[i])});
+ ordered_log_files.insert(LogFile{id, timestamp, std::move(files[i])});
}
return AndroidBugreportReader(context, std::move(bug_report),
@@ -146,9 +150,8 @@
base::Status AndroidBugreportReader::ParseDumpstateTxt(
std::vector<TimestampedAndroidLogEvent> logcat_events) {
- ScopedActiveTraceFile trace_file = context_->trace_file_tracker->StartNewFile(
- bug_report_.file.name(), kAndroidDumpstateTraceType,
- bug_report_.file.uncompressed_size());
+ context_->trace_file_tracker->StartParsing(bug_report_.id,
+ kAndroidDumpstateTraceType);
AndroidDumpstateReader reader(context_, bug_report_.year,
std::move(logcat_events));
base::Status status = bug_report_.file.DecompressLines(
@@ -157,6 +160,8 @@
reader.ParseLine(line);
}
});
+ context_->trace_file_tracker->DoneParsing(
+ bug_report_.id, bug_report_.file.uncompressed_size());
return status;
}
@@ -167,16 +172,16 @@
// Push all events into the AndroidLogParser. It will take care of string
// interning into the pool. Appends entries into `log_events`.
for (const auto& log_file : ordered_log_files_) {
- ScopedActiveTraceFile trace_file =
- context_->trace_file_tracker->StartNewFile(
- log_file.file.name(), kAndroidLogcatTraceType,
- log_file.file.uncompressed_size());
+ context_->trace_file_tracker->StartParsing(log_file.id,
+ kAndroidLogcatTraceType);
RETURN_IF_ERROR(log_file.file.DecompressLines(
[&](const std::vector<base::StringView>& lines) {
for (const auto& line : lines) {
log_reader.ParseLine(line);
}
}));
+ context_->trace_file_tracker->DoneParsing(
+ log_file.id, log_file.file.uncompressed_size());
}
return std::move(log_reader).ConsumeBufferedEvents();
diff --git a/src/trace_processor/importers/android_bugreport/android_bugreport_reader.h b/src/trace_processor/importers/android_bugreport/android_bugreport_reader.h
index e0fe4fe..b36c45c 100644
--- a/src/trace_processor/importers/android_bugreport/android_bugreport_reader.h
+++ b/src/trace_processor/importers/android_bugreport/android_bugreport_reader.h
@@ -26,6 +26,7 @@
#include "perfetto/ext/base/status_or.h"
#include "perfetto/trace_processor/status.h"
#include "src/trace_processor/importers/android_bugreport/android_log_reader.h"
+#include "src/trace_processor/tables/metadata_tables_py.h"
#include "src/trace_processor/util/zip_reader.h"
namespace perfetto ::trace_processor {
@@ -46,10 +47,12 @@
private:
struct BugReportFile {
+ tables::TraceFileTable::Id id;
int32_t year;
util::ZipFile file;
};
struct LogFile {
+ tables::TraceFileTable::Id id;
int64_t timestamp;
util::ZipFile file;
// Sort files to ease the job of the line-based sort. Unfortunately
diff --git a/src/trace_processor/importers/zip/BUILD.gn b/src/trace_processor/importers/archive/BUILD.gn
similarity index 66%
rename from src/trace_processor/importers/zip/BUILD.gn
rename to src/trace_processor/importers/archive/BUILD.gn
index 0262e02..4f092ad 100644
--- a/src/trace_processor/importers/zip/BUILD.gn
+++ b/src/trace_processor/importers/archive/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright (C) 2022 The Android Open Source Project
+# 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.
@@ -12,18 +12,31 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-source_set("full") {
+source_set("archive") {
sources = [
+ "archive_entry.cc",
+ "archive_entry.h",
+ "gzip_trace_parser.cc",
+ "gzip_trace_parser.h",
+ "tar_trace_reader.cc",
+ "tar_trace_reader.h",
"zip_trace_reader.cc",
"zip_trace_reader.h",
]
deps = [
+ "../..:storage_minimal",
"../../../../gn:default_deps",
+ "../../../../include/perfetto/base:base",
"../../../../include/perfetto/ext/base:base",
+ "../../../base",
"../../../trace_processor:storage_minimal",
+ "../../storage",
+ "../../tables:tables_python",
"../../types",
+ "../../util",
+ "../../util:gzip",
+ "../../util:trace_blob_view_reader",
"../../util:trace_type",
- "../../util:util",
"../../util:zip_reader",
"../android_bugreport",
"../common",
diff --git a/src/trace_processor/importers/archive/archive_entry.cc b/src/trace_processor/importers/archive/archive_entry.cc
new file mode 100644
index 0000000..1d187df
--- /dev/null
+++ b/src/trace_processor/importers/archive/archive_entry.cc
@@ -0,0 +1,55 @@
+/*
+ * 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/archive/archive_entry.h"
+
+#include <tuple>
+
+namespace perfetto::trace_processor {
+
+bool ArchiveEntry::operator<(const ArchiveEntry& rhs) const {
+ // Traces with symbols should be the last ones to be read.
+ // 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.
+ if (trace_type == kSymbolsTraceType) {
+ return false;
+ }
+ if (rhs.trace_type == kSymbolsTraceType) {
+ return true;
+ }
+
+ // Proto traces should always parsed first as they might contains clock sync
+ // data needed to correctly parse other traces.
+ if (rhs.trace_type == TraceType::kProtoTraceType) {
+ return false;
+ }
+ if (trace_type == TraceType::kProtoTraceType) {
+ return true;
+ }
+
+ if (rhs.trace_type == TraceType::kGzipTraceType) {
+ return false;
+ }
+ if (trace_type == TraceType::kGzipTraceType) {
+ return true;
+ }
+
+ return std::tie(name, index) < std::tie(rhs.name, rhs.index);
+}
+
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/archive/archive_entry.h b/src/trace_processor/importers/archive/archive_entry.h
new file mode 100644
index 0000000..ae13cf7
--- /dev/null
+++ b/src/trace_processor/importers/archive/archive_entry.h
@@ -0,0 +1,44 @@
+/*
+ * 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_ARCHIVE_ARCHIVE_ENTRY_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_ARCHIVE_ARCHIVE_ENTRY_H_
+
+#include <string>
+
+#include "src/trace_processor/util/trace_type.h"
+
+namespace perfetto::trace_processor {
+
+// Helper class to determine a proper tokenization. This class can be used as
+// a key of a std::map to automatically sort files before sending them in proper
+// order for tokenization.
+struct ArchiveEntry {
+ // File name. Used to break ties.
+ std::string name;
+ // Position. 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;
+ // Comparator used to determine the order in which files in the ZIP will be
+ // read.
+ bool operator<(const ArchiveEntry& rhs) const;
+};
+} // namespace perfetto::trace_processor
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_ARCHIVE_ARCHIVE_ENTRY_H_
diff --git a/src/trace_processor/importers/gzip/gzip_trace_parser.cc b/src/trace_processor/importers/archive/gzip_trace_parser.cc
similarity index 93%
rename from src/trace_processor/importers/gzip/gzip_trace_parser.cc
rename to src/trace_processor/importers/archive/gzip_trace_parser.cc
index d133b2c..bc4074a 100644
--- a/src/trace_processor/importers/gzip/gzip_trace_parser.cc
+++ b/src/trace_processor/importers/archive/gzip_trace_parser.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "src/trace_processor/importers/gzip/gzip_trace_parser.h"
+#include "src/trace_processor/importers/archive/gzip_trace_parser.h"
#include <cstdint>
#include <cstring>
@@ -30,6 +30,8 @@
#include "perfetto/trace_processor/trace_blob_view.h"
#include "src/trace_processor/forwarding_trace_parser.h"
#include "src/trace_processor/importers/common/chunked_trace_reader.h"
+#include "src/trace_processor/importers/common/trace_file_tracker.h"
+#include "src/trace_processor/types/trace_processor_context.h"
#include "src/trace_processor/util/gzip_utils.h"
#include "src/trace_processor/util/status_macros.h"
@@ -59,7 +61,8 @@
if (!inner_) {
PERFETTO_CHECK(context_);
- inner_.reset(new ForwardingTraceParser(context_));
+ inner_.reset(new ForwardingTraceParser(
+ context_, context_->trace_file_tracker->AddFile("")));
}
if (!first_chunk_parsed_) {
diff --git a/src/trace_processor/importers/gzip/gzip_trace_parser.h b/src/trace_processor/importers/archive/gzip_trace_parser.h
similarity index 88%
rename from src/trace_processor/importers/gzip/gzip_trace_parser.h
rename to src/trace_processor/importers/archive/gzip_trace_parser.h
index 4a565e6..17fdc4c 100644
--- a/src/trace_processor/importers/gzip/gzip_trace_parser.h
+++ b/src/trace_processor/importers/archive/gzip_trace_parser.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_GZIP_GZIP_TRACE_PARSER_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_GZIP_GZIP_TRACE_PARSER_H_
+#ifndef SRC_TRACE_PROCESSOR_IMPORTERS_ARCHIVE_GZIP_TRACE_PARSER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_ARCHIVE_GZIP_TRACE_PARSER_H_
#include <cstddef>
#include <cstdint>
@@ -55,4 +55,4 @@
} // namespace perfetto::trace_processor
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_GZIP_GZIP_TRACE_PARSER_H_
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_ARCHIVE_GZIP_TRACE_PARSER_H_
diff --git a/src/trace_processor/importers/archive/tar_trace_reader.cc b/src/trace_processor/importers/archive/tar_trace_reader.cc
new file mode 100644
index 0000000..d0cf11f
--- /dev/null
+++ b/src/trace_processor/importers/archive/tar_trace_reader.cc
@@ -0,0 +1,285 @@
+/*
+ * 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/archive/tar_trace_reader.h"
+
+#include <algorithm>
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <optional>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/base/status.h"
+#include "perfetto/ext/base/status_or.h"
+#include "perfetto/ext/base/string_view.h"
+#include "perfetto/trace_processor/trace_blob_view.h"
+#include "src/trace_processor/forwarding_trace_parser.h"
+#include "src/trace_processor/importers/archive/archive_entry.h"
+#include "src/trace_processor/importers/common/trace_file_tracker.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::trace_processor {
+namespace {
+
+constexpr char kUstarMagic[] = {'u', 's', 't', 'a', 'r', '\0'};
+constexpr char kGnuMagic[] = {'u', 's', 't', 'a', 'r', ' ', ' ', '\0'};
+
+constexpr char TYPE_FLAG_REGULAR = '0';
+constexpr char TYPE_FLAG_AREGULAR = '\0';
+constexpr char TYPE_FLAG_GNU_LONG_NAME = 'L';
+
+template <size_t Size>
+std::optional<uint64_t> ExtractUint64(const char (&ptr)[Size]) {
+ static_assert(Size <= 64 / 3);
+ if (*ptr == 0) {
+ return std::nullopt;
+ }
+ uint64_t value = 0;
+ for (size_t i = 0; i < Size && ptr[i] != 0; ++i) {
+ if (ptr[i] > '7' || ptr[i] < '0') {
+ return std::nullopt;
+ }
+ value <<= 3;
+ value += static_cast<uint64_t>(ptr[i] - '0');
+ }
+ return value;
+}
+
+enum class TarType { kUnknown, kUstar, kGnu };
+
+struct alignas(1) Header {
+ char name[100];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char checksum[8];
+ char type_flag[1];
+ char link_name[100];
+ union {
+ struct UstarMagic {
+ char magic[6];
+ char version[2];
+ } ustar;
+ char gnu[8];
+ } magic;
+ char user_name[32];
+ char group_name[32];
+ char dev_major[8];
+ char dev_minor[8];
+ char prefix[155];
+ char padding[12];
+
+ TarType GetTarFileType() const {
+ if (memcmp(magic.gnu, kGnuMagic, sizeof(kGnuMagic)) == 0) {
+ return TarType::kGnu;
+ }
+ if (memcmp(magic.ustar.magic, kUstarMagic, sizeof(kUstarMagic)) == 0) {
+ return TarType::kUstar;
+ }
+ return TarType::kUnknown;
+ }
+};
+
+constexpr size_t kHeaderSize = 512;
+static_assert(sizeof(Header) == kHeaderSize);
+
+bool IsAllZeros(const TraceBlobView& data) {
+ const uint8_t* start = data.data();
+ const uint8_t* end = data.data() + data.size();
+ return std::find_if(start, end, [](uint8_t v) { return v != 0; }) == end;
+}
+
+template <size_t Size>
+std::string ExtractString(const char (&start)[Size]) {
+ const char* end = start + Size;
+ end = std::find(start, end, 0);
+ return std::string(start, end);
+}
+
+} // namespace
+
+TarTraceReader::TarTraceReader(TraceProcessorContext* context)
+ : context_(context) {}
+
+TarTraceReader::~TarTraceReader() = default;
+
+util::Status TarTraceReader::Parse(TraceBlobView blob) {
+ ParseResult result = ParseResult::kOk;
+ buffer_.PushBack(std::move(blob));
+ while (!buffer_.empty() && result == ParseResult::kOk) {
+ switch (state_) {
+ case State::kMetadata:
+ case State::kZeroMetadata: {
+ ASSIGN_OR_RETURN(result, ParseMetadata());
+ break;
+ }
+ case State::kContent: {
+ ASSIGN_OR_RETURN(result, ParseContent());
+ break;
+ }
+ case State::kDone:
+ // We are done, ignore any more data
+ buffer_.PopFrontUntil(buffer_.end_offset());
+ }
+ }
+ return base::OkStatus();
+}
+
+base::Status TarTraceReader::NotifyEndOfFile() {
+ if (state_ != State::kDone) {
+ return base::ErrStatus("Premature end of TAR file");
+ }
+
+ for (auto& file : ordered_files_) {
+ auto chunk_reader =
+ std::make_unique<ForwardingTraceParser>(context_, file.second.id);
+ auto& parser = *chunk_reader;
+ context_->chunk_readers.push_back(std::move(chunk_reader));
+
+ for (auto& data : file.second.data) {
+ RETURN_IF_ERROR(parser.Parse(std::move(data)));
+ }
+ RETURN_IF_ERROR(parser.NotifyEndOfFile());
+ // Make sure the ForwardingTraceParser determined the same trace type as we
+ // did.
+ PERFETTO_CHECK(parser.trace_type() == file.first.trace_type);
+ }
+
+ return base::OkStatus();
+}
+
+base::StatusOr<TarTraceReader::ParseResult> TarTraceReader::ParseMetadata() {
+ PERFETTO_CHECK(!metadata_.has_value());
+ auto blob = buffer_.SliceOff(buffer_.start_offset(), kHeaderSize);
+ if (!blob) {
+ return ParseResult::kNeedsMoreData;
+ }
+ buffer_.PopFrontBytes(kHeaderSize);
+ const Header& header = *reinterpret_cast<const Header*>(blob->data());
+
+ TarType type = header.GetTarFileType();
+
+ if (type == TarType::kUnknown) {
+ if (!IsAllZeros(*blob)) {
+ return base::ErrStatus("Invalid magic value");
+ }
+ // EOF is signaled by two consecutive zero headers.
+ if (state_ == State::kMetadata) {
+ // Fist time we see all zeros. NExt parser loop will enter ParseMetadata
+ // again and decide whether it is the real end or maybe a ral header
+ // comes.
+ state_ = State::kZeroMetadata;
+ } else {
+ // Previous header was zeros, thus we are done.
+ PERFETTO_CHECK(state_ == State::kZeroMetadata);
+ state_ = State::kDone;
+ }
+ return ParseResult::kOk;
+ }
+
+ if (type == TarType::kUstar && (header.magic.ustar.version[0] != '0' ||
+ header.magic.ustar.version[1] != '0')) {
+ return base::ErrStatus("Invalid version: %c%c",
+ header.magic.ustar.version[0],
+ header.magic.ustar.version[1]);
+ }
+
+ std::optional<uint64_t> size = ExtractUint64(header.size);
+ if (!size.has_value()) {
+ return base::ErrStatus("Failed to parse octal size field.");
+ }
+
+ metadata_.emplace();
+ metadata_->size = *size;
+ metadata_->type_flag = *header.type_flag;
+
+ if (long_name_) {
+ metadata_->name = std::move(*long_name_);
+ long_name_.reset();
+ } else {
+ metadata_->name =
+ ExtractString(header.prefix) + "/" + ExtractString(header.name);
+ }
+
+ switch (metadata_->type_flag) {
+ case TYPE_FLAG_REGULAR:
+ case TYPE_FLAG_AREGULAR:
+ case TYPE_FLAG_GNU_LONG_NAME:
+ state_ = State::kContent;
+ break;
+
+ default:
+ if (metadata_->size != 0) {
+ return base::ErrStatus("Unsupported file type: 0x%02x",
+ metadata_->type_flag);
+ }
+ state_ = State::kMetadata;
+ break;
+ }
+
+ return ParseResult::kOk;
+}
+
+base::StatusOr<TarTraceReader::ParseResult> TarTraceReader::ParseContent() {
+ PERFETTO_CHECK(metadata_.has_value());
+
+ size_t data_and_padding_size = base::AlignUp(metadata_->size, kHeaderSize);
+ if (buffer_.avail() < data_and_padding_size) {
+ return ParseResult::kNeedsMoreData;
+ }
+
+ if (metadata_->type_flag == TYPE_FLAG_GNU_LONG_NAME) {
+ TraceBlobView data =
+ *buffer_.SliceOff(buffer_.start_offset(), metadata_->size);
+ long_name_ = std::string(reinterpret_cast<const char*>(data.data()),
+ metadata_->size);
+ } else {
+ AddFile(*metadata_,
+ *buffer_.SliceOff(
+ buffer_.start_offset(),
+ std::min(static_cast<uint64_t>(512), metadata_->size)),
+ buffer_.MultiSliceOff(buffer_.start_offset(), metadata_->size));
+ }
+
+ buffer_.PopFrontBytes(data_and_padding_size);
+
+ metadata_.reset();
+ state_ = State::kMetadata;
+ return ParseResult::kOk;
+}
+
+void TarTraceReader::AddFile(const Metadata& metadata,
+ TraceBlobView header,
+ std::vector<TraceBlobView> data) {
+ auto file_id = context_->trace_file_tracker->AddFile(metadata.name);
+ context_->trace_file_tracker->SetSize(file_id, metadata.size);
+ ordered_files_.emplace(
+ ArchiveEntry{metadata.name, ordered_files_.size(),
+ GuessTraceType(header.data(), header.size())},
+ File{file_id, std::move(data)});
+}
+
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/archive/tar_trace_reader.h b/src/trace_processor/importers/archive/tar_trace_reader.h
new file mode 100644
index 0000000..6760774
--- /dev/null
+++ b/src/trace_processor/importers/archive/tar_trace_reader.h
@@ -0,0 +1,82 @@
+/*
+ * 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_ARCHIVE_TAR_TRACE_READER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_ARCHIVE_TAR_TRACE_READER_H_
+
+#include <cstddef>
+#include <cstdint>
+#include <map>
+
+#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/archive/archive_entry.h"
+#include "src/trace_processor/importers/common/chunked_trace_reader.h"
+#include "src/trace_processor/tables/metadata_tables_py.h"
+#include "src/trace_processor/util/trace_blob_view_reader.h"
+
+namespace perfetto::trace_processor {
+
+class TraceProcessorContext;
+
+class TarTraceReader : public ChunkedTraceReader {
+ public:
+ explicit TarTraceReader(TraceProcessorContext*);
+ ~TarTraceReader() override;
+
+ // ChunkedTraceReader implementation
+ base::Status Parse(TraceBlobView) override;
+ base::Status NotifyEndOfFile() override;
+
+ private:
+ struct Metadata {
+ std::string name;
+ uint64_t size;
+ char type_flag;
+ };
+ enum class ParseResult {
+ kOk,
+ kNeedsMoreData,
+ };
+
+ struct File {
+ tables::TraceFileTable::Id id;
+ std::vector<TraceBlobView> data;
+ };
+
+ enum class State { kMetadata, kContent, kZeroMetadata, kDone };
+
+ base::StatusOr<ParseResult> ParseMetadata();
+ base::StatusOr<ParseResult> ParseContent();
+ base::StatusOr<ParseResult> ParseLongName();
+ base::StatusOr<ParseResult> ParsePadding();
+
+ void AddFile(const Metadata& metadata,
+ TraceBlobView header,
+ std::vector<TraceBlobView> data);
+
+ TraceProcessorContext* const context_;
+ State state_{State::kMetadata};
+ util::TraceBlobViewReader buffer_;
+ std::optional<Metadata> metadata_;
+ std::optional<std::string> long_name_;
+ std::map<ArchiveEntry, File> ordered_files_;
+};
+
+} // namespace perfetto::trace_processor
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_ARCHIVE_TAR_TRACE_READER_H_
diff --git a/src/trace_processor/importers/archive/zip_trace_reader.cc b/src/trace_processor/importers/archive/zip_trace_reader.cc
new file mode 100644
index 0000000..6077d00
--- /dev/null
+++ b/src/trace_processor/importers/archive/zip_trace_reader.cc
@@ -0,0 +1,95 @@
+/*
+ * 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/archive/zip_trace_reader.h"
+
+#include <algorithm>
+#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/ext/base/string_view.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_reader.h"
+#include "src/trace_processor/importers/archive/archive_entry.h"
+#include "src/trace_processor/importers/common/trace_file_tracker.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"
+#include "src/trace_processor/util/zip_reader.h"
+
+namespace perfetto::trace_processor {
+
+ZipTraceReader::ZipTraceReader(TraceProcessorContext* context)
+ : context_(context) {}
+ZipTraceReader::~ZipTraceReader() = default;
+
+base::Status ZipTraceReader::Parse(TraceBlobView blob) {
+ return zip_reader_.Parse(std::move(blob));
+}
+
+base::Status ZipTraceReader::NotifyEndOfFile() {
+ std::vector<util::ZipFile> files = zip_reader_.TakeFiles();
+
+ // Android bug reports are ZIP files and its files do not get handled
+ // separately.
+ if (AndroidBugreportReader::IsAndroidBugReport(files)) {
+ return AndroidBugreportReader::Parse(context_, std::move(files));
+ }
+
+ // TODO(carlscab): 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<uint8_t> buffer;
+ std::map<ArchiveEntry, File> ordered_files;
+ for (size_t i = 0; i < files.size(); ++i) {
+ util::ZipFile& zip_file = files[i];
+ auto id = context_->trace_file_tracker->AddFile(zip_file.name());
+ context_->trace_file_tracker->SetSize(id, zip_file.compressed_size());
+ RETURN_IF_ERROR(files[i].Decompress(&buffer));
+ TraceBlobView data(TraceBlob::CopyFrom(buffer.data(), buffer.size()));
+ ArchiveEntry entry{zip_file.name(), i,
+ GuessTraceType(data.data(), data.size())};
+ ordered_files.emplace(entry, File{id, std::move(data)});
+ }
+
+ for (auto& file : ordered_files) {
+ auto chunk_reader =
+ std::make_unique<ForwardingTraceParser>(context_, file.second.id);
+ auto& parser = *chunk_reader;
+ context_->chunk_readers.push_back(std::move(chunk_reader));
+
+ RETURN_IF_ERROR(parser.Parse(std::move(file.second.data)));
+ RETURN_IF_ERROR(parser.NotifyEndOfFile());
+ // Make sure the ForwardingTraceParser determined the same trace type as we
+ // did.
+ PERFETTO_CHECK(parser.trace_type() == file.first.trace_type);
+ }
+
+ return base::OkStatus();
+}
+
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/archive/zip_trace_reader.h b/src/trace_processor/importers/archive/zip_trace_reader.h
new file mode 100644
index 0000000..d36fd5c
--- /dev/null
+++ b/src/trace_processor/importers/archive/zip_trace_reader.h
@@ -0,0 +1,57 @@
+/*
+ * 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_ARCHIVE_ZIP_TRACE_READER_H_
+#define SRC_TRACE_PROCESSOR_IMPORTERS_ARCHIVE_ZIP_TRACE_READER_H_
+
+#include <cstddef>
+#include <map>
+
+#include "perfetto/base/status.h"
+#include "perfetto/trace_processor/trace_blob_view.h"
+#include "src/trace_processor/importers/archive/archive_entry.h"
+#include "src/trace_processor/importers/common/chunked_trace_reader.h"
+#include "src/trace_processor/tables/metadata_tables_py.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
+ base::Status Parse(TraceBlobView) override;
+ base::Status NotifyEndOfFile() override;
+
+ private:
+ struct File {
+ tables::TraceFileTable::Id id;
+ TraceBlobView data;
+ };
+ TraceProcessorContext* const context_;
+ util::ZipReader zip_reader_;
+};
+
+} // namespace perfetto::trace_processor
+
+#endif // SRC_TRACE_PROCESSOR_IMPORTERS_ARCHIVE_ZIP_TRACE_READER_H_
diff --git a/src/trace_processor/importers/common/BUILD.gn b/src/trace_processor/importers/common/BUILD.gn
index a65d044..47c7521 100644
--- a/src/trace_processor/importers/common/BUILD.gn
+++ b/src/trace_processor/importers/common/BUILD.gn
@@ -56,8 +56,6 @@
"sched_event_state.h",
"sched_event_tracker.cc",
"sched_event_tracker.h",
- "scoped_active_trace_file.cc",
- "scoped_active_trace_file.h",
"slice_tracker.cc",
"slice_tracker.h",
"slice_translation_table.cc",
diff --git a/src/trace_processor/importers/common/scoped_active_trace_file.cc b/src/trace_processor/importers/common/scoped_active_trace_file.cc
deleted file mode 100644
index 7249261..0000000
--- a/src/trace_processor/importers/common/scoped_active_trace_file.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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/common/scoped_active_trace_file.h"
-
-#include <cstddef>
-#include <cstdint>
-#include <string>
-
-#include "perfetto/ext/base/string_view.h"
-#include "src/trace_processor/importers/common/trace_file_tracker.h"
-#include "src/trace_processor/storage/trace_storage.h"
-#include "src/trace_processor/tables/metadata_tables_py.h"
-#include "src/trace_processor/types/trace_processor_context.h"
-
-namespace perfetto::trace_processor {
-ScopedActiveTraceFile::~ScopedActiveTraceFile() {
- if (is_valid_) {
- context_->trace_file_tracker->EndFile(row_);
- }
-}
-
-void ScopedActiveTraceFile::SetName(const std::string& name) {
- row_.set_name(context_->storage->InternString(base::StringView(name)));
-}
-
-void ScopedActiveTraceFile::SetTraceType(TraceType type) {
- row_.set_trace_type(context_->storage->InternString(TraceTypeToString(type)));
-}
-
-void ScopedActiveTraceFile::SetSize(size_t size) {
- row_.set_size(static_cast<int64_t>(size));
-}
-
-void ScopedActiveTraceFile::AddSize(size_t size) {
- row_.set_size(static_cast<int64_t>(size) + row_.size());
-}
-
-} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/common/scoped_active_trace_file.h b/src/trace_processor/importers/common/scoped_active_trace_file.h
deleted file mode 100644
index 0006fcf..0000000
--- a/src/trace_processor/importers/common/scoped_active_trace_file.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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_COMMON_SCOPED_ACTIVE_TRACE_FILE_H_
-#define SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_SCOPED_ACTIVE_TRACE_FILE_H_
-
-#include <string>
-
-#include "src/trace_processor/tables/metadata_tables_py.h"
-#include "src/trace_processor/util/trace_type.h"
-
-namespace perfetto::trace_processor {
-
-class TraceProcessorContext;
-
-// RAII like object that represents a file currently being parsed. When
-// instances of this object go out of scope they will notify the
-// TraceFileTracker that we are done parsing the file.
-// This class also acts a handler for setting file related properties.
-class ScopedActiveTraceFile {
- public:
- ~ScopedActiveTraceFile();
-
- ScopedActiveTraceFile(const ScopedActiveTraceFile&) = delete;
- ScopedActiveTraceFile& operator=(const ScopedActiveTraceFile&) = delete;
-
- ScopedActiveTraceFile(ScopedActiveTraceFile&& o)
- : context_(o.context_), row_(o.row_), is_valid_(o.is_valid_) {
- o.is_valid_ = false;
- }
-
- ScopedActiveTraceFile& operator=(ScopedActiveTraceFile&& o) {
- context_ = o.context_;
- row_ = o.row_;
- is_valid_ = o.is_valid_;
- o.is_valid_ = false;
- return *this;
- }
-
- void SetTraceType(TraceType type);
-
- // For streamed files this method can be called for each chunk to update the
- // file size incrementally.
- void AddSize(size_t delta);
-
- private:
- friend class TraceFileTracker;
- ScopedActiveTraceFile(TraceProcessorContext* context,
- tables::TraceFileTable::RowReference row)
- : context_(context), row_(row), is_valid_(true) {}
-
- // Sets the file name. If this method is not called (sometimes we do not know
- // the file name, e.g. streaming data) the name is set to null.
- void SetName(const std::string& name);
- void SetSize(size_t size);
-
- TraceProcessorContext* context_;
- tables::TraceFileTable::RowReference row_;
- bool is_valid_;
-};
-
-} // namespace perfetto::trace_processor
-
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_COMMON_SCOPED_ACTIVE_TRACE_FILE_H_
diff --git a/src/trace_processor/importers/common/trace_file_tracker.cc b/src/trace_processor/importers/common/trace_file_tracker.cc
index e51371a..2bf02b7 100644
--- a/src/trace_processor/importers/common/trace_file_tracker.cc
+++ b/src/trace_processor/importers/common/trace_file_tracker.cc
@@ -17,11 +17,14 @@
#include "src/trace_processor/importers/common/trace_file_tracker.h"
#include <cstddef>
+#include <cstdint>
+#include <optional>
#include <string>
#include <vector>
+#include "perfetto/base/logging.h"
+#include "perfetto/ext/base/string_view.h"
#include "src/trace_processor/importers/common/metadata_tracker.h"
-#include "src/trace_processor/storage/metadata.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/tables/metadata_tables_py.h"
#include "src/trace_processor/types/trace_processor_context.h"
@@ -29,46 +32,49 @@
namespace perfetto::trace_processor {
-ScopedActiveTraceFile TraceFileTracker::StartNewFile() {
- tables::TraceFileTable::Row row;
- if (!ancestors_.empty()) {
- row.parent_id = ancestors_.back();
- }
-
- row.size = 0;
- row.trace_type =
- context_->storage->InternString(TraceTypeToString(kUnknownTraceType));
-
- auto ref =
- context_->storage->mutable_trace_file_table()->Insert(row).row_reference;
-
- ancestors_.push_back(ref.id());
- return ScopedActiveTraceFile(context_, std::move(ref));
+tables::TraceFileTable::Id TraceFileTracker::AddFile(const std::string& name) {
+ return AddFileImpl(context_->storage->InternString(base::StringView(name)));
}
-ScopedActiveTraceFile TraceFileTracker::StartNewFile(const std::string& name,
- TraceType type,
- size_t size) {
- auto file = StartNewFile();
- file.SetName(name);
- file.SetTraceType(type);
- file.SetSize(size);
- return file;
+tables::TraceFileTable::Id TraceFileTracker::AddFileImpl(StringId name) {
+ std::optional<tables::TraceFileTable::Id> parent =
+ parsing_stack_.empty() ? std::nullopt
+ : std::make_optional(parsing_stack_.back());
+ return context_->storage->mutable_trace_file_table()
+ ->Insert({parent, name, 0,
+ context_->storage->InternString(
+ TraceTypeToString(kUnknownTraceType)),
+ std::nullopt})
+ .id;
}
-void TraceFileTracker::EndFile(
- const tables::TraceFileTable::ConstRowReference& row) {
- PERFETTO_CHECK(!ancestors_.empty());
- PERFETTO_CHECK(ancestors_.back() == row.id());
+void TraceFileTracker::SetSize(tables::TraceFileTable::Id id, uint64_t size) {
+ auto row = *context_->storage->mutable_trace_file_table()->FindById(id);
+ row.set_size(static_cast<int64_t>(size));
+}
+
+void TraceFileTracker::StartParsing(tables::TraceFileTable::Id id,
+ TraceType trace_type) {
+ parsing_stack_.push_back(id);
+ auto row = *context_->storage->mutable_trace_file_table()->FindById(id);
+ row.set_trace_type(
+ context_->storage->InternString(TraceTypeToString(trace_type)));
+ row.set_processing_order(static_cast<int64_t>(processing_order_++));
+}
+
+void TraceFileTracker::DoneParsing(tables::TraceFileTable::Id id, size_t size) {
+ PERFETTO_CHECK(!parsing_stack_.empty() && parsing_stack_.back() == id);
+ parsing_stack_.pop_back();
+ auto row = *context_->storage->mutable_trace_file_table()->FindById(id);
+ row.set_size(static_cast<int64_t>(size));
// First file (root)
- if (row.id().value == 0) {
+ if (id.value == 0) {
context_->metadata_tracker->SetMetadata(metadata::trace_size_bytes,
Variadic::Integer(row.size()));
context_->metadata_tracker->SetMetadata(metadata::trace_type,
Variadic::String(row.trace_type()));
}
- ancestors_.pop_back();
}
} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/common/trace_file_tracker.h b/src/trace_processor/importers/common/trace_file_tracker.h
index 0e2f5f9..4c6be5f 100644
--- a/src/trace_processor/importers/common/trace_file_tracker.h
+++ b/src/trace_processor/importers/common/trace_file_tracker.h
@@ -20,7 +20,7 @@
#include <string>
#include <vector>
-#include "src/trace_processor/importers/common/scoped_active_trace_file.h"
+#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/tables/metadata_tables_py.h"
#include "src/trace_processor/util/trace_type.h"
@@ -36,24 +36,18 @@
explicit TraceFileTracker(TraceProcessorContext* context)
: context_(context) {}
- // Notifies the start of a new file that we are about to parse. It returns a
- // RAII like object that will notify the end of processing when it goes out of
- // scope.
- // NOTE: Files must be ended in reverse order of being started.
- ScopedActiveTraceFile StartNewFile();
-
- // Convenience version of the above that should be used when all the file
- // properties are known upfront.
- ScopedActiveTraceFile StartNewFile(const std::string& name,
- TraceType type,
- size_t size);
+ tables::TraceFileTable::Id AddFile(const std::string& name);
+ tables::TraceFileTable::Id AddFile() { return AddFileImpl(kNullStringId); }
+ void SetSize(tables::TraceFileTable::Id id, uint64_t size);
+ void StartParsing(tables::TraceFileTable::Id id, TraceType trace_type);
+ void DoneParsing(tables::TraceFileTable::Id id, size_t size);
private:
- void EndFile(const tables::TraceFileTable::ConstRowReference& row);
+ tables::TraceFileTable::Id AddFileImpl(StringId name);
- friend class ScopedActiveTraceFile;
TraceProcessorContext* const context_;
- std::vector<tables::TraceFileTable::Id> ancestors_;
+ size_t processing_order_ = 0;
+ std::vector<tables::TraceFileTable::Id> parsing_stack_;
};
} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/gzip/BUILD.gn b/src/trace_processor/importers/gzip/BUILD.gn
deleted file mode 100644
index d2fad21..0000000
--- a/src/trace_processor/importers/gzip/BUILD.gn
+++ /dev/null
@@ -1,28 +0,0 @@
-# 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 = [
- "gzip_trace_parser.cc",
- "gzip_trace_parser.h",
- ]
- deps = [
- "../..:storage_minimal",
- "../../../../gn:default_deps",
- "../../../base",
- "../../util",
- "../../util:gzip",
- "../common",
- ]
-}
diff --git a/src/trace_processor/importers/zip/zip_trace_reader.cc b/src/trace_processor/importers/zip/zip_trace_reader.cc
deleted file mode 100644
index 732559d..0000000
--- a/src/trace_processor/importers/zip/zip_trace_reader.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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 <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_reader.h"
-#include "src/trace_processor/importers/common/trace_file_tracker.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"
-#include "src/trace_processor/util/zip_reader.h"
-
-namespace perfetto::trace_processor {
-
-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.
- // 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.
- if (trace_type == kSymbolsTraceType) {
- return false;
- }
- if (rhs.trace_type == kSymbolsTraceType) {
- return true;
- }
-
- // Proto traces should always parsed first as they might contains clock sync
- // data needed to correctly parse other traces.
- if (rhs.trace_type == TraceType::kProtoTraceType) {
- return false;
- }
- if (trace_type == TraceType::kProtoTraceType) {
- return true;
- }
-
- if (rhs.trace_type == TraceType::kGzipTraceType) {
- return false;
- }
- if (trace_type == TraceType::kGzipTraceType) {
- return true;
- }
-
- return std::tie(name, index) < std::tie(rhs.name, rhs.index);
-}
-
-base::Status ZipTraceReader::Parse(TraceBlobView blob) {
- return zip_reader_.Parse(std::move(blob));
-}
-
-base::Status ZipTraceReader::NotifyEndOfFile() {
- std::vector<util::ZipFile> files = zip_reader_.TakeFiles();
-
- // Android bug reports are ZIP files and its files do not get handled
- // separately.
- if (AndroidBugreportReader::IsAndroidBugReport(files)) {
- return AndroidBugreportReader::Parse(context_, std::move(files));
- }
-
- ASSIGN_OR_RETURN(std::vector<Entry> entries,
- ExtractEntries(std::move(files)));
- std::sort(entries.begin(), entries.end());
-
- for (Entry& e : entries) {
- ScopedActiveTraceFile trace_file =
- context_->trace_file_tracker->StartNewFile(e.name, e.trace_type,
- e.uncompressed_data.size());
-
- auto chunk_reader = std::make_unique<ForwardingTraceParser>(context_);
- auto& parser = *chunk_reader;
- context_->chunk_readers.push_back(std::move(chunk_reader));
-
- RETURN_IF_ERROR(parser.Parse(std::move(e.uncompressed_data)));
- RETURN_IF_ERROR(parser.NotifyEndOfFile());
-
- // Make sure the ForwardingTraceParser determined the same trace type as we
- // did.
- PERFETTO_CHECK(parser.trace_type() == e.trace_type);
- }
- return base::OkStatus();
-}
-
-base::StatusOr<std::vector<ZipTraceReader::Entry>>
-ZipTraceReader::ExtractEntries(std::vector<util::ZipFile> files) {
- // 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());
- entries.push_back(std::move(entry));
- }
- return std::move(entries);
-}
-
-} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/importers/zip/zip_trace_reader.h b/src/trace_processor/importers/zip/zip_trace_reader.h
deleted file mode 100644
index b6620ae..0000000
--- a/src/trace_processor/importers/zip/zip_trace_reader.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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
- base::Status Parse(TraceBlobView) override;
- base::Status 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;
- // Comparator used to determine the order in which files in the ZIP will be
- // read.
- bool operator<(const Entry& rhs) const;
- };
-
- static base::StatusOr<std::vector<Entry>> ExtractEntries(
- std::vector<util::ZipFile> files);
- base::Status ParseEntry(Entry entry);
-
- TraceProcessorContext* const context_;
- util::ZipReader zip_reader_;
-};
-
-} // namespace perfetto::trace_processor
-
-#endif // SRC_TRACE_PROCESSOR_IMPORTERS_ZIP_ZIP_TRACE_READER_H_
diff --git a/src/trace_processor/read_trace.cc b/src/trace_processor/read_trace.cc
index 91e784a..e9f8f8c 100644
--- a/src/trace_processor/read_trace.cc
+++ b/src/trace_processor/read_trace.cc
@@ -26,8 +26,8 @@
#include "perfetto/protozero/proto_utils.h"
#include "perfetto/trace_processor/trace_blob_view.h"
#include "perfetto/trace_processor/trace_processor.h"
+#include "src/trace_processor/importers/archive/gzip_trace_parser.h"
#include "src/trace_processor/importers/common/chunked_trace_reader.h"
-#include "src/trace_processor/importers/gzip/gzip_trace_parser.h"
#include "src/trace_processor/importers/proto/proto_trace_tokenizer.h"
#include "src/trace_processor/read_trace_internal.h"
#include "src/trace_processor/util/gzip_utils.h"
diff --git a/src/trace_processor/read_trace_internal.cc b/src/trace_processor/read_trace_internal.cc
index 3b537cd..f2b1a67 100644
--- a/src/trace_processor/read_trace_internal.cc
+++ b/src/trace_processor/read_trace_internal.cc
@@ -27,7 +27,6 @@
#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/gzip/gzip_trace_parser.h"
#include "src/trace_processor/importers/proto/proto_trace_tokenizer.h"
#include "src/trace_processor/util/gzip_utils.h"
#include "src/trace_processor/util/status_macros.h"
diff --git a/src/trace_processor/tables/metadata_tables.py b/src/trace_processor/tables/metadata_tables.py
index cb70e2a..10da09b 100644
--- a/src/trace_processor/tables/metadata_tables.py
+++ b/src/trace_processor/tables/metadata_tables.py
@@ -460,6 +460,7 @@
C('name', CppOptional(CppString())),
C('size', CppInt64()),
C('trace_type', CppString()),
+ C('processing_order', CppOptional(CppInt64())),
],
wrapping_sql_view=WrappingSqlView('trace_file'),
tabledoc=TableDoc(
@@ -481,6 +482,8 @@
'''Size in bytes''',
'trace_type':
'''Trace type''',
+ 'processing_order':
+ '''In which order where the files were processed.''',
}))
# Keep this list sorted.
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index a8f1ffe..54436d3 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -46,6 +46,9 @@
#include "perfetto/trace_processor/trace_processor.h"
#include "src/trace_processor/importers/android_bugreport/android_log_event_parser_impl.h"
#include "src/trace_processor/importers/android_bugreport/android_log_reader.h"
+#include "src/trace_processor/importers/archive/gzip_trace_parser.h"
+#include "src/trace_processor/importers/archive/tar_trace_reader.h"
+#include "src/trace_processor/importers/archive/zip_trace_reader.h"
#include "src/trace_processor/importers/art_method/art_method_parser_impl.h"
#include "src/trace_processor/importers/art_method/art_method_tokenizer.h"
#include "src/trace_processor/importers/common/clock_tracker.h"
@@ -55,7 +58,6 @@
#include "src/trace_processor/importers/fuchsia/fuchsia_trace_tokenizer.h"
#include "src/trace_processor/importers/gecko/gecko_trace_parser_impl.h"
#include "src/trace_processor/importers/gecko/gecko_trace_tokenizer.h"
-#include "src/trace_processor/importers/gzip/gzip_trace_parser.h"
#include "src/trace_processor/importers/json/json_trace_parser_impl.h"
#include "src/trace_processor/importers/json/json_trace_tokenizer.h"
#include "src/trace_processor/importers/json/json_utils.h"
@@ -68,7 +70,6 @@
#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"
@@ -457,6 +458,8 @@
context_.perf_text_parser =
std::make_unique<perf_text_importer::PerfTextTraceParserImpl>(&context_);
+ context_.reader_registry->RegisterTraceReader<TarTraceReader>(kTarTraceType);
+
if (context_.config.analyze_trace_proto_content) {
context_.content_analyzer =
std::make_unique<ProtoContentAnalyzer>(&context_);
diff --git a/src/trace_processor/trace_processor_storage_impl.cc b/src/trace_processor/trace_processor_storage_impl.cc
index e93e0fe..1fe24c0 100644
--- a/src/trace_processor/trace_processor_storage_impl.cc
+++ b/src/trace_processor/trace_processor_storage_impl.cc
@@ -20,6 +20,7 @@
#include <cstddef>
#include <cstdint>
#include <memory>
+#include <optional>
#include <utility>
#include "perfetto/base/logging.h"
@@ -76,8 +77,8 @@
return base::ErrStatus(
"Failed unrecoverably while parsing in a previous Parse call");
if (!parser_) {
- active_file_ = context_.trace_file_tracker->StartNewFile();
- auto parser = std::make_unique<ForwardingTraceParser>(&context_);
+ auto parser = std::make_unique<ForwardingTraceParser>(
+ &context_, context_.trace_file_tracker->AddFile());
parser_ = parser.get();
context_.chunk_readers.push_back(std::move(parser));
}
@@ -97,7 +98,6 @@
Variadic::String(id_for_uuid));
}
- active_file_->AddSize(blob.size());
base::Status status = parser_->Parse(std::move(blob));
unrecoverable_parse_error_ |= !status.ok();
return status;
@@ -121,9 +121,6 @@
}
Flush();
RETURN_IF_ERROR(parser_->NotifyEndOfFile());
- PERFETTO_CHECK(active_file_.has_value());
- active_file_->SetTraceType(parser_->trace_type());
- active_file_.reset();
// NotifyEndOfFile might have pushed packets to the sorter.
Flush();
for (std::unique_ptr<ProtoImporterModule>& module : context_.modules) {
@@ -144,8 +141,6 @@
}
void TraceProcessorStorageImpl::DestroyContext() {
- // End any active files. Eg. when NotifyEndOfFile is not called.
- active_file_.reset();
TraceProcessorContext context;
context.storage = std::move(context_.storage);
diff --git a/src/trace_processor/trace_processor_storage_impl.h b/src/trace_processor/trace_processor_storage_impl.h
index bab8961..9198d2f 100644
--- a/src/trace_processor/trace_processor_storage_impl.h
+++ b/src/trace_processor/trace_processor_storage_impl.h
@@ -17,9 +17,6 @@
#ifndef SRC_TRACE_PROCESSOR_TRACE_PROCESSOR_STORAGE_IMPL_H_
#define SRC_TRACE_PROCESSOR_TRACE_PROCESSOR_STORAGE_IMPL_H_
-#include <memory>
-#include <optional>
-
#include "perfetto/ext/base/hash.h"
#include "perfetto/trace_processor/basic_types.h"
#include "perfetto/trace_processor/status.h"
@@ -51,7 +48,6 @@
bool unrecoverable_parse_error_ = false;
size_t hash_input_size_remaining_ = 4096;
ForwardingTraceParser* parser_ = nullptr;
- std::optional<ScopedActiveTraceFile> active_file_;
};
} // namespace trace_processor
diff --git a/src/trace_processor/trace_reader_registry.cc b/src/trace_processor/trace_reader_registry.cc
index 6301ced..fe108c8 100644
--- a/src/trace_processor/trace_reader_registry.cc
+++ b/src/trace_processor/trace_reader_registry.cc
@@ -54,6 +54,7 @@
case kGeckoTraceType:
case kArtMethodTraceType:
case kPerfTextTraceType:
+ case kTarTraceType:
return false;
}
PERFETTO_FATAL("For GCC");
diff --git a/src/trace_processor/util/trace_blob_view_reader.cc b/src/trace_processor/util/trace_blob_view_reader.cc
index 78a1e1f..acdc898 100644
--- a/src/trace_processor/util/trace_blob_view_reader.cc
+++ b/src/trace_processor/util/trace_blob_view_reader.cc
@@ -21,8 +21,10 @@
#include <cstddef>
#include <cstdint>
#include <cstring>
+#include <iterator>
#include <optional>
#include <utility>
+#include <vector>
#include "perfetto/base/logging.h"
#include "perfetto/public/compiler.h"
@@ -59,12 +61,13 @@
return target_offset == end_offset_;
}
-std::optional<TraceBlobView> TraceBlobViewReader::SliceOff(
- size_t offset,
- size_t length) const {
- // If the length is zero, then a zero-sized blob view is always approrpriate.
+template <typename Visitor>
+auto TraceBlobViewReader::SliceOffImpl(const size_t offset,
+ const size_t length,
+ Visitor& visitor) const {
+ // If the length is zero, then a zero-sized blob view is always appropiate.
if (PERFETTO_UNLIKELY(length == 0)) {
- return TraceBlobView();
+ return visitor.OneSlice(TraceBlobView());
}
PERFETTO_DCHECK(offset >= start_offset());
@@ -76,47 +79,105 @@
!data_.empty() &&
offset + length <= data_.front().start_offset + data_.front().data.size();
if (PERFETTO_LIKELY(is_fast_path)) {
- return data_.front().data.slice_off(offset - data_.front().start_offset,
- length);
+ return visitor.OneSlice(data_.front().data.slice_off(
+ offset - data_.front().start_offset, length));
}
// If we don't have any TBVs or the end of the slice does not fit, then we
// cannot possibly return a full slice.
if (PERFETTO_UNLIKELY(data_.empty() || offset + length > end_offset_)) {
- return std::nullopt;
+ return visitor.NoData();
}
// Find the first block finishes *after* start_offset i.e. there is at least
// one byte in that block which will end up in the slice. We know this *must*
// exist because of the above check.
- auto rit = std::upper_bound(
+ auto it = std::upper_bound(
data_.begin(), data_.end(), offset, [](size_t offset, const Entry& rhs) {
return offset < rhs.start_offset + rhs.data.size();
});
- PERFETTO_CHECK(rit != data_.end());
+ PERFETTO_CHECK(it != data_.end());
// If the slice fits entirely in the block we found, then just slice that
// block avoiding any copies.
- size_t rel_off = offset - rit->start_offset;
- if (rel_off + length <= rit->data.size()) {
- return rit->data.slice_off(rel_off, length);
+ size_t rel_off = offset - it->start_offset;
+ if (rel_off + length <= it->data.size()) {
+ return visitor.OneSlice(it->data.slice_off(rel_off, length));
}
- // Otherwise, allocate some memory and make a copy.
- auto buffer = TraceBlob::Allocate(length);
- uint8_t* ptr = buffer.data();
- uint8_t* end = buffer.data() + buffer.size();
+ auto res = visitor.StartMultiSlice(length);
- // Copy all bytes in this block which overlap with the slice.
- memcpy(ptr, rit->data.data() + rel_off, rit->data.length() - rel_off);
- ptr += rit->data.length() - rel_off;
+ size_t res_offset = 0;
+ size_t left = length;
- for (auto it = rit + 1; ptr != end; ++it) {
- auto len = std::min(static_cast<size_t>(end - ptr), it->data.size());
- memcpy(ptr, it->data.data(), len);
- ptr += len;
+ size_t size = it->data.length() - rel_off;
+ visitor.AddSlice(res, res_offset, it->data.slice_off(rel_off, size));
+ left -= size;
+ res_offset += size;
+
+ for (++it; left != 0; ++it) {
+ size = std::min(left, it->data.size());
+ visitor.AddSlice(res, res_offset, it->data.slice_off(0, size));
+ left -= size;
+ res_offset += size;
}
- return TraceBlobView(std::move(buffer));
+
+ return visitor.Finalize(std::move(res));
+}
+
+std::optional<TraceBlobView> TraceBlobViewReader::SliceOff(
+ size_t offset,
+ size_t length) const {
+ struct Visitor {
+ std::optional<TraceBlobView> NoData() { return std::nullopt; }
+
+ std::optional<TraceBlobView> OneSlice(TraceBlobView tbv) {
+ return std::move(tbv);
+ }
+
+ TraceBlob StartMultiSlice(size_t length) {
+ return TraceBlob::Allocate(length);
+ }
+
+ void AddSlice(TraceBlob& blob, size_t offset, TraceBlobView tbv) {
+ memcpy(blob.data() + offset, tbv.data(), tbv.size());
+ }
+
+ std::optional<TraceBlobView> Finalize(TraceBlob blob) {
+ return TraceBlobView(std::move(blob));
+ }
+
+ } visitor;
+
+ return SliceOffImpl(offset, length, visitor);
+}
+
+std::vector<TraceBlobView> TraceBlobViewReader::MultiSliceOff(
+ size_t offset,
+ size_t length) const {
+ struct Visitor {
+ std::vector<TraceBlobView> NoData() { return {}; }
+
+ std::vector<TraceBlobView> OneSlice(TraceBlobView tbv) {
+ std::vector<TraceBlobView> res;
+ res.reserve(1);
+ res.push_back(std::move(tbv));
+ return res;
+ }
+
+ std::vector<TraceBlobView> StartMultiSlice(size_t) { return {}; }
+
+ void AddSlice(std::vector<TraceBlobView>& vec, size_t, TraceBlobView tbv) {
+ vec.push_back(std::move(tbv));
+ }
+
+ std::vector<TraceBlobView> Finalize(std::vector<TraceBlobView> vec) {
+ return vec;
+ }
+
+ } visitor;
+
+ return SliceOffImpl(offset, length, visitor);
}
} // namespace perfetto::trace_processor::util
diff --git a/src/trace_processor/util/trace_blob_view_reader.h b/src/trace_processor/util/trace_blob_view_reader.h
index f076d04..dd9a562 100644
--- a/src/trace_processor/util/trace_blob_view_reader.h
+++ b/src/trace_processor/util/trace_blob_view_reader.h
@@ -180,6 +180,11 @@
// NOTE: If `offset` < 'file_offset()' this method will CHECK fail.
std::optional<TraceBlobView> SliceOff(size_t offset, size_t length) const;
+ // Similar to SliceOff but this method will not combine slices but instead
+ // potentially return multiple chunks. Useful if we are extracting slices to
+ // forward them to a `ChunkedTraceReader`.
+ std::vector<TraceBlobView> MultiSliceOff(size_t offset, size_t length) const;
+
// Returns the offset to the start of the available data.
size_t start_offset() const {
return data_.empty() ? end_offset_ : data_.front().start_offset;
@@ -194,6 +199,9 @@
bool empty() const { return data_.empty(); }
private:
+ template <typename Visitor>
+ auto SliceOffImpl(size_t offset, size_t length, Visitor& visitor) const;
+
// CircularQueue has no const_iterator, so mutable is needed to access it from
// const methods.
mutable base::CircularQueue<Entry> data_;
diff --git a/src/trace_processor/util/trace_type.cc b/src/trace_processor/util/trace_type.cc
index 7c8d9e6..bec7279 100644
--- a/src/trace_processor/util/trace_type.cc
+++ b/src/trace_processor/util/trace_type.cc
@@ -41,6 +41,9 @@
constexpr char kZipMagic[] = {'P', 'K', '\x03', '\x04'};
constexpr char kGzipMagic[] = {'\x1f', '\x8b'};
constexpr char kArtMethodStreamingMagic[] = {'S', 'L', 'O', 'W'};
+constexpr char kTarPosixMagic[] = {'u', 's', 't', 'a', 'r', '\0'};
+constexpr char kTarGnuMagic[] = {'u', 's', 't', 'a', 'r', ' ', ' ', '\0'};
+constexpr size_t kTarMagicOffset = 257;
constexpr uint8_t kTracePacketTag =
protozero::proto_utils::MakeTagLengthDelimited(
@@ -59,11 +62,15 @@
}
template <size_t N>
-bool MatchesMagic(const uint8_t* data, size_t size, const char (&magic)[N]) {
- if (size < N) {
+bool MatchesMagic(const uint8_t* data,
+ size_t size,
+ const char (&magic)[N],
+ size_t offset = 0) {
+ if (size < N + offset) {
return false;
}
- return memcmp(data, magic, N) == 0;
+
+ return memcmp(data + offset, magic, N) == 0;
}
bool IsProtoTraceWithSymbols(const uint8_t* ptr, size_t size) {
@@ -136,6 +143,8 @@
return "perf_text";
case kUnknownTraceType:
return "unknown";
+ case kTarTraceType:
+ return "tar";
}
PERFETTO_FATAL("For GCC");
}
@@ -145,6 +154,14 @@
return kUnknownTraceType;
}
+ if (MatchesMagic(data, size, kTarPosixMagic, kTarMagicOffset)) {
+ return kTarTraceType;
+ }
+
+ if (MatchesMagic(data, size, kTarGnuMagic, kTarMagicOffset)) {
+ return kTarTraceType;
+ }
+
if (MatchesMagic(data, size, kFuchsiaMagic)) {
return kFuchsiaTraceType;
}
diff --git a/src/trace_processor/util/trace_type.h b/src/trace_processor/util/trace_type.h
index 2e9d17d..80d8ff4 100644
--- a/src/trace_processor/util/trace_type.h
+++ b/src/trace_processor/util/trace_type.h
@@ -41,6 +41,7 @@
kGeckoTraceType,
kArtMethodTraceType,
kPerfTextTraceType,
+ kTarTraceType,
};
constexpr size_t kGuessTraceMaxLookahead = 64;
diff --git a/test/data/perf_track_sym.tar.gz.sha256 b/test/data/perf_track_sym.tar.gz.sha256
new file mode 100644
index 0000000..edccf35
--- /dev/null
+++ b/test/data/perf_track_sym.tar.gz.sha256
@@ -0,0 +1 @@
+358db7f9628a9bb79d2dffa274c73c2894c3c7108b67bfb9f513bf4bac34acd6
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/parser/android/tests_bugreport.py b/test/trace_processor/diff_tests/parser/android/tests_bugreport.py
index d67867d..b52f5f8 100644
--- a/test/trace_processor/diff_tests/parser/android/tests_bugreport.py
+++ b/test/trace_processor/diff_tests/parser/android/tests_bugreport.py
@@ -60,18 +60,36 @@
""",
out=Path('android_bugreport_dumpsys_test.out'))
- def test_android_bugreport_trace_types(self):
+ def test_android_bugreport_parse_order(self):
return DiffTestBlueprint(
trace=DataPath('bugreport-crosshatch-SPB5.zip'),
query="""
SELECT *
FROM __intrinsic_trace_file
- ORDER BY id
+ WHERE trace_type <> "unknown"
+ ORDER BY processing_order
""",
out=Csv("""
- "id","type","parent_id","name","size","trace_type"
- 0,"__intrinsic_trace_file","[NULL]","[NULL]",6220586,"zip"
- 1,"__intrinsic_trace_file",0,"FS/data/misc/logd/logcat.01",2169697,"android_logcat"
- 2,"__intrinsic_trace_file",0,"FS/data/misc/logd/logcat",2152073,"android_logcat"
- 3,"__intrinsic_trace_file",0,"bugreport-crosshatch-SPB5.210812.002-2021-08-24-23-35-40.txt",43132864,"android_dumpstate"
- """))
\ No newline at end of file
+ "id","type","parent_id","name","size","trace_type","processing_order"
+ 0,"__intrinsic_trace_file","[NULL]","[NULL]",6220586,"zip",0
+ 16,"__intrinsic_trace_file",0,"FS/data/misc/logd/logcat.01",2169697,"android_logcat",1
+ 15,"__intrinsic_trace_file",0,"FS/data/misc/logd/logcat",2152073,"android_logcat",2
+ 1,"__intrinsic_trace_file",0,"bugreport-crosshatch-SPB5.210812.002-2021-08-24-23-35-40.txt",43132864,"android_dumpstate",3
+ """))
+
+ def test_android_bugreport_trace_types(self):
+ return DiffTestBlueprint(
+ trace=DataPath('bugreport-crosshatch-SPB5.zip'),
+ query="""
+ SELECT trace_type, count(*) AS cnt, sum(size) AS total_size
+ FROM __intrinsic_trace_file
+ GROUP BY trace_type
+ ORDER BY trace_type
+ """,
+ out=Csv("""
+ "trace_type","cnt","total_size"
+ "android_dumpstate",1,43132864
+ "android_logcat",2,4321770
+ "unknown",2452,626115
+ "zip",1,6220586
+ """))
diff --git a/test/trace_processor/diff_tests/parser/zip/tests.py b/test/trace_processor/diff_tests/parser/zip/tests.py
index 660bdbe..4e46286 100644
--- a/test/trace_processor/diff_tests/parser/zip/tests.py
+++ b/test/trace_processor/diff_tests/parser/zip/tests.py
@@ -59,20 +59,37 @@
"main,E"
'''))
- def test_tokenization_order(self):
+ def test_zip_tokenization_order(self):
return DiffTestBlueprint(
trace=DataPath('zip/perf_track_sym.zip'),
query='''
SELECT *
FROM __intrinsic_trace_file
- ORDER BY id
+ ORDER BY processing_order
''',
out=Csv('''
- "id","type","parent_id","name","size","trace_type"
- 0,"__intrinsic_trace_file","[NULL]","[NULL]",94651,"zip"
- 1,"__intrinsic_trace_file",0,"c.trace.pb",379760,"proto"
- 2,"__intrinsic_trace_file",0,"b.simpleperf.data",554911,"perf"
- 3,"__intrinsic_trace_file",0,"a.symbols.pb",186149,"symbols"
+ "id","type","parent_id","name","size","trace_type","processing_order"
+ 0,"__intrinsic_trace_file","[NULL]","[NULL]",94651,"zip",0
+ 3,"__intrinsic_trace_file",0,"c.trace.pb",379760,"proto",1
+ 1,"__intrinsic_trace_file",0,"b.simpleperf.data",554911,"perf",2
+ 2,"__intrinsic_trace_file",0,"a.symbols.pb",186149,"symbols",3
+ '''))
+
+ def test_tar_gz_tokenization_order(self):
+ return DiffTestBlueprint(
+ trace=DataPath('perf_track_sym.tar.gz'),
+ query='''
+ SELECT *
+ FROM __intrinsic_trace_file
+ ORDER BY processing_order
+ ''',
+ out=Csv('''
+ "id","type","parent_id","name","size","trace_type","processing_order"
+ 0,"__intrinsic_trace_file","[NULL]","[NULL]",94091,"gzip",0
+ 1,"__intrinsic_trace_file",0,"",1126400,"tar",1
+ 4,"__intrinsic_trace_file",1,"/c.trace.pb",379760,"proto",2
+ 3,"__intrinsic_trace_file",1,"/b.simpleperf.data",554911,"perf",3
+ 2,"__intrinsic_trace_file",1,"/a.symbols.pb",186149,"symbols",4
'''))
# Make sure the logcat timestamps are correctly converted to trace ts. All