processor: extract a public ReadTrace() function from shell
Clients are asking for this :)
Bug: 142310140
Change-Id: Id035f857d779b4a5d2b854079d2fdb3f650073a9
diff --git a/Android.bp b/Android.bp
index dc329a6..58fc8ca 100644
--- a/Android.bp
+++ b/Android.bp
@@ -4017,6 +4017,7 @@
"src/trace_processor/proto_trace_parser.cc",
"src/trace_processor/proto_trace_tokenizer.cc",
"src/trace_processor/raw_table.cc",
+ "src/trace_processor/read_trace.cc",
"src/trace_processor/row_iterators.cc",
"src/trace_processor/sched_slice_table.cc",
"src/trace_processor/slice_table.cc",
diff --git a/BUILD b/BUILD
index e560b11..56233f3 100644
--- a/BUILD
+++ b/BUILD
@@ -339,6 +339,7 @@
name = "include_perfetto_trace_processor_trace_processor",
srcs = [
"include/perfetto/trace_processor/basic_types.h",
+ "include/perfetto/trace_processor/read_trace.h",
"include/perfetto/trace_processor/status.h",
"include/perfetto/trace_processor/trace_processor.h",
],
@@ -660,6 +661,7 @@
"src/trace_processor/proto_trace_tokenizer.h",
"src/trace_processor/raw_table.cc",
"src/trace_processor/raw_table.h",
+ "src/trace_processor/read_trace.cc",
"src/trace_processor/row_iterators.cc",
"src/trace_processor/row_iterators.h",
"src/trace_processor/sched_slice_table.cc",
diff --git a/include/perfetto/trace_processor/BUILD.gn b/include/perfetto/trace_processor/BUILD.gn
index 90200fa..215be02 100644
--- a/include/perfetto/trace_processor/BUILD.gn
+++ b/include/perfetto/trace_processor/BUILD.gn
@@ -15,6 +15,7 @@
source_set("trace_processor") {
sources = [
"basic_types.h",
+ "read_trace.h",
"status.h",
"trace_processor.h",
]
diff --git a/include/perfetto/trace_processor/read_trace.h b/include/perfetto/trace_processor/read_trace.h
new file mode 100644
index 0000000..ac2053d
--- /dev/null
+++ b/include/perfetto/trace_processor/read_trace.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INCLUDE_PERFETTO_TRACE_PROCESSOR_READ_TRACE_H_
+#define INCLUDE_PERFETTO_TRACE_PROCESSOR_READ_TRACE_H_
+
+#include <functional>
+
+#include "perfetto/base/export.h"
+#include "perfetto/trace_processor/status.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class TraceProcessor;
+
+util::Status PERFETTO_EXPORT ReadTrace(
+ TraceProcessor* tp,
+ const char* filename,
+ const std::function<void(uint64_t parsed_size)>& progress_callback = {});
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // INCLUDE_PERFETTO_TRACE_PROCESSOR_READ_TRACE_H_
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index 6f20e97..fe3ce2a 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -95,8 +95,6 @@
"heap_profile_tracker.h",
"instants_table.cc",
"instants_table.h",
- "vulkan_memory_tracker.cc",
- "vulkan_memory_tracker.h",
"metadata.h",
"metadata_table.cc",
"metadata_table.h",
@@ -111,6 +109,7 @@
"proto_trace_tokenizer.h",
"raw_table.cc",
"raw_table.h",
+ "read_trace.cc",
"row_iterators.cc",
"row_iterators.h",
"sched_slice_table.cc",
@@ -167,6 +166,8 @@
"track_tracker.h",
"variadic.h",
"virtual_destructors.cc",
+ "vulkan_memory_tracker.cc",
+ "vulkan_memory_tracker.h",
"window_operator_table.cc",
"window_operator_table.h",
]
diff --git a/src/trace_processor/read_trace.cc b/src/trace_processor/read_trace.cc
new file mode 100644
index 0000000..8ba8f16
--- /dev/null
+++ b/src/trace_processor/read_trace.cc
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2019 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 "perfetto/trace_processor/read_trace.h"
+
+#include "perfetto/ext/base/scoped_file.h"
+#include "perfetto/trace_processor/trace_processor.h"
+
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
+#define PERFETTO_HAS_AIO_H() 1
+#else
+#define PERFETTO_HAS_AIO_H() 0
+#endif
+
+#if PERFETTO_HAS_AIO_H()
+#include <aio.h>
+#endif
+
+namespace perfetto {
+namespace trace_processor {
+
+util::Status ReadTrace(
+ TraceProcessor* tp,
+ const char* filename,
+ const std::function<void(uint64_t parsed_size)>& progress_callback) {
+ base::ScopedFile fd(base::OpenFile(filename, O_RDONLY));
+ if (!fd)
+ return util::ErrStatus("Could not open trace file (path: %s)", filename);
+
+ // 1MB chunk size seems the best tradeoff on a MacBook Pro 2013 - i7 2.8 GHz.
+ constexpr size_t kChunkSize = 1024 * 1024;
+ uint64_t file_size = 0;
+
+#if PERFETTO_HAS_AIO_H()
+ // Load the trace in chunks using async IO. We create a simple pipeline where,
+ // at each iteration, we parse the current chunk and asynchronously start
+ // reading the next chunk.
+ struct aiocb cb {};
+ cb.aio_nbytes = kChunkSize;
+ cb.aio_fildes = *fd;
+
+ std::unique_ptr<uint8_t[]> aio_buf(new uint8_t[kChunkSize]);
+#if defined(MEMORY_SANITIZER)
+ // Just initialize the memory to make the memory sanitizer happy as it
+ // cannot track aio calls below.
+ memset(aio_buf.get(), 0, kChunkSize);
+#endif // defined(MEMORY_SANITIZER)
+ cb.aio_buf = aio_buf.get();
+
+ PERFETTO_CHECK(aio_read(&cb) == 0);
+ struct aiocb* aio_list[1] = {&cb};
+
+ for (int i = 0;; i++) {
+ if (progress_callback && i % 128 == 0)
+ progress_callback(file_size);
+
+ // Block waiting for the pending read to complete.
+ PERFETTO_CHECK(aio_suspend(aio_list, 1, nullptr) == 0);
+ auto rsize = aio_return(&cb);
+ if (rsize <= 0)
+ break;
+ file_size += static_cast<uint64_t>(rsize);
+
+ // Take ownership of the completed buffer and enqueue a new async read
+ // with a fresh buffer.
+ std::unique_ptr<uint8_t[]> buf(std::move(aio_buf));
+ aio_buf.reset(new uint8_t[kChunkSize]);
+#if defined(MEMORY_SANITIZER)
+ // Just initialize the memory to make the memory sanitizer happy as it
+ // cannot track aio calls below.
+ memset(aio_buf.get(), 0, kChunkSize);
+#endif // defined(MEMORY_SANITIZER)
+ cb.aio_buf = aio_buf.get();
+ cb.aio_offset += rsize;
+ PERFETTO_CHECK(aio_read(&cb) == 0);
+
+ // Parse the completed buffer while the async read is in-flight.
+ util::Status status = tp->Parse(std::move(buf), static_cast<size_t>(rsize));
+ if (PERFETTO_UNLIKELY(!status.ok()))
+ return status;
+ }
+#else // PERFETTO_HAS_AIO_H()
+ // Load the trace in chunks using ordinary read().
+ // This version is used on Windows, since there's no aio library.
+ for (int i = 0;; i++) {
+ if (progress_callback && i % 128 == 0)
+ progress_callback(file_size);
+
+ std::unique_ptr<uint8_t[]> buf(new uint8_t[kChunkSize]);
+ auto rsize = read(*fd, buf.get(), kChunkSize);
+ if (rsize <= 0)
+ break;
+ file_size += static_cast<uint64_t>(rsize);
+
+ util::Status status = tp->Parse(std::move(buf), static_cast<size_t>(rsize));
+ if (PERFETTO_UNLIKELY(!status.ok()))
+ return status;
+ }
+#endif // PERFETTO_HAS_AIO_H()
+
+ tp->NotifyEndOfFile();
+
+ if (progress_callback)
+ progress_callback(file_size);
+ return util::OkStatus();
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/trace_processor_shell.cc b/src/trace_processor/trace_processor_shell.cc
index f37b5ab..e86f220 100644
--- a/src/trace_processor/trace_processor_shell.cc
+++ b/src/trace_processor/trace_processor_shell.cc
@@ -34,6 +34,7 @@
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/string_splitter.h"
+#include "perfetto/trace_processor/read_trace.h"
#include "perfetto/trace_processor/trace_processor.h"
#include "src/trace_processor/metrics/metrics.descriptor.h"
#include "src/trace_processor/proto_to_json.h"
@@ -46,13 +47,6 @@
#define PERFETTO_HAS_SIGNAL_H() 0
#endif
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
-#define PERFETTO_HAS_AIO_H() 1
-#else
-#define PERFETTO_HAS_AIO_H() 0
-#endif
-
#if PERFETTO_BUILDFLAG(PERFETTO_TP_LINENOISE)
#include <linenoise.h>
#include <pwd.h>
@@ -69,10 +63,6 @@
#include <signal.h>
#endif
-#if PERFETTO_HAS_AIO_H()
-#include <aio.h>
-#endif
-
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#define ftruncate _chsize
#else
@@ -643,94 +633,6 @@
bool wide = false;
};
-#if PERFETTO_HAS_AIO_H()
-uint64_t ReadTrace(TraceProcessor* tp, int file_descriptor) {
- // Load the trace in chunks using async IO. We create a simple pipeline where,
- // at each iteration, we parse the current chunk and asynchronously start
- // reading the next chunk.
-
- // 1MB chunk size seems the best tradeoff on a MacBook Pro 2013 - i7 2.8 GHz.
- constexpr size_t kChunkSize = 1024 * 1024;
- uint64_t file_size = 0;
-
- struct aiocb cb {};
- cb.aio_nbytes = kChunkSize;
- cb.aio_fildes = file_descriptor;
-
- std::unique_ptr<uint8_t[]> aio_buf(new uint8_t[kChunkSize]);
-#if defined(MEMORY_SANITIZER)
- // Just initialize the memory to make the memory sanitizer happy as it
- // cannot track aio calls below.
- memset(aio_buf.get(), 0, kChunkSize);
-#endif // defined(MEMORY_SANITIZER)
- cb.aio_buf = aio_buf.get();
-
- PERFETTO_CHECK(aio_read(&cb) == 0);
- struct aiocb* aio_list[1] = {&cb};
-
- for (int i = 0;; i++) {
- if (i % 128 == 0)
- fprintf(stderr, "\rLoading trace: %.2f MB\r", file_size / 1E6);
-
- // Block waiting for the pending read to complete.
- PERFETTO_CHECK(aio_suspend(aio_list, 1, nullptr) == 0);
- auto rsize = aio_return(&cb);
- if (rsize <= 0)
- break;
- file_size += static_cast<uint64_t>(rsize);
-
- // Take ownership of the completed buffer and enqueue a new async read
- // with a fresh buffer.
- std::unique_ptr<uint8_t[]> buf(std::move(aio_buf));
- aio_buf.reset(new uint8_t[kChunkSize]);
-#if defined(MEMORY_SANITIZER)
- // Just initialize the memory to make the memory sanitizer happy as it
- // cannot track aio calls below.
- memset(aio_buf.get(), 0, kChunkSize);
-#endif // defined(MEMORY_SANITIZER)
- cb.aio_buf = aio_buf.get();
- cb.aio_offset += rsize;
- PERFETTO_CHECK(aio_read(&cb) == 0);
-
- // Parse the completed buffer while the async read is in-flight.
- util::Status status = tp->Parse(std::move(buf), static_cast<size_t>(rsize));
- if (PERFETTO_UNLIKELY(!status.ok())) {
- PERFETTO_ELOG("Fatal error while parsing trace: %s", status.c_message());
- exit(1);
- }
- }
- tp->NotifyEndOfFile();
- return file_size;
-}
-#else // PERFETTO_HAS_AIO_H()
-uint64_t ReadTrace(TraceProcessor* tp, int file_descriptor) {
- // Load the trace in chunks using ordinary read().
- // This version is used on Windows, since there's no aio library.
-
- constexpr size_t kChunkSize = 1024 * 1024;
- uint64_t file_size = 0;
-
- for (int i = 0;; i++) {
- if (i % 128 == 0)
- fprintf(stderr, "\rLoading trace: %.2f MB\r", file_size / 1E6);
-
- std::unique_ptr<uint8_t[]> buf(new uint8_t[kChunkSize]);
- auto rsize = read(file_descriptor, buf.get(), kChunkSize);
- if (rsize <= 0)
- break;
- file_size += static_cast<uint64_t>(rsize);
-
- util::Status status = tp->Parse(std::move(buf), static_cast<size_t>(rsize));
- if (PERFETTO_UNLIKELY(!status.ok())) {
- PERFETTO_ELOG("Fatal error while parsing trace: %s", status.c_message());
- exit(1);
- }
- }
- tp->NotifyEndOfFile();
- return file_size;
-}
-#endif // PERFETTO_HAS_AIO_H()
-
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
void PrintUsage(char** argv) {
PERFETTO_ELOG(
@@ -955,18 +857,22 @@
// Load the trace file into the trace processor.
Config config;
std::unique_ptr<TraceProcessor> tp = TraceProcessor::CreateInstance(config);
- base::ScopedFile fd(base::OpenFile(options.trace_file_path, O_RDONLY));
- if (!fd) {
- PERFETTO_ELOG("Could not open trace file (path: %s)",
- options.trace_file_path.c_str());
- return 1;
- }
auto t_load_start = base::GetWallTimeNs();
- uint64_t file_size = ReadTrace(tp.get(), *fd);
+ double size_mb = 0;
+ util::Status read_status =
+ ReadTrace(tp.get(), options.trace_file_path.c_str(),
+ [&size_mb](size_t parsed_size) {
+ size_mb = parsed_size / 1E6;
+ fprintf(stderr, "\rLoading trace: %.2f MB\r", size_mb);
+ });
+ if (!read_status.ok()) {
+ PERFETTO_ELOG("Could not read trace file (path: %s): %s",
+ options.trace_file_path.c_str(), read_status.c_message());
+ return 1;
+ }
auto t_load = base::GetWallTimeNs() - t_load_start;
double t_load_s = t_load.count() / 1E9;
- double size_mb = file_size / 1E6;
PERFETTO_ILOG("Trace loaded: %.2f MB (%.1f MB/s)", size_mb,
size_mb / t_load_s);
g_tp = tp.get();