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();