Add interactive trace_processor_shell + fix mac build
Adds an interactive shell (ninja target: trace_processor_shell)
to test the trace processor on the host.
Also this CL fixes a small build issue on mac (unix_socket.cc)
Change-Id: I4923f51a706818bd5cf689b035a2075fa6c595a8
diff --git a/BUILD.gn b/BUILD.gn
index 3133792..31f6c70 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -50,7 +50,10 @@
"tools/proto_to_cpp",
]
if (!build_with_android) {
- deps += [ "tools/trace_to_text" ]
+ deps += [
+ ":trace_processor",
+ "tools/trace_to_text",
+ ]
}
if (is_linux || is_android) {
deps += [ "tools/skippy" ]
@@ -80,6 +83,14 @@
"ui",
]
}
+
+ # The trace processor shell executable. An interactive shell that allows to
+ # make queries on the trace using the terminal.
+ group("trace_processor") {
+ deps = [
+ "src/trace_processor:trace_processor_shell",
+ ]
+ }
}
executable("perfetto_unittests") {
@@ -215,14 +226,6 @@
"protos/perfetto/trace:lite",
]
}
- } else {
- # The library which eases processing of Perfetto traces by exposing reading
- # friendly APIs.
- static_library("trace_processor") {
- deps = [
- "src/trace_processor:lib",
- ]
- }
}
}
diff --git a/gn/wasm.gni b/gn/wasm.gni
index c47439e..32dd089 100644
--- a/gn/wasm.gni
+++ b/gn/wasm.gni
@@ -19,4 +19,11 @@
import("//gn/standalone/wasm.gni")
} else {
is_wasm = false # The WASM toolchain is supported only in standalone builds.
+
+ # Create a dummy template to avoid GN warnings in non-standalone builds.
+ template("wasm_lib") {
+ source_set("${target_name}_unused") {
+ forward_variables_from(invoker, "*")
+ }
+ }
}
diff --git a/protos/perfetto/trace_processor/raw_query.proto b/protos/perfetto/trace_processor/raw_query.proto
index 9c5eaf0..673994f 100644
--- a/protos/perfetto/trace_processor/raw_query.proto
+++ b/protos/perfetto/trace_processor/raw_query.proto
@@ -44,4 +44,5 @@
repeated ColumnDesc column_descriptors = 1;
optional uint64 num_records = 2;
repeated ColumnValues columns = 3;
+ optional string error = 4;
}
diff --git a/src/ipc/unix_socket.cc b/src/ipc/unix_socket.cc
index d8dad3b..b53bbde 100644
--- a/src/ipc/unix_socket.cc
+++ b/src/ipc/unix_socket.cc
@@ -343,7 +343,7 @@
struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg_hdr);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(num_fds * sizeof(int));
+ cmsg->cmsg_len = static_cast<CBufLenType>(CMSG_LEN(num_fds * sizeof(int)));
memcpy(CMSG_DATA(cmsg), send_fds, num_fds * sizeof(int));
msg_hdr.msg_controllen = cmsg->cmsg_len;
}
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index f560a99..c0e0aca 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -36,6 +36,8 @@
source_set("lib") {
sources = [
"blob_reader.h",
+ "file_reader.cc",
+ "file_reader.h",
"process_table.cc",
"process_table.h",
"process_tracker.cc",
@@ -72,6 +74,18 @@
]
}
+executable("trace_processor_shell") {
+ deps = [
+ ":lib",
+ "../../gn:default_deps",
+ "../../protos/perfetto/trace_processor:lite",
+ "../base",
+ ]
+ sources = [
+ "trace_processor_shell.cc",
+ ]
+}
+
source_set("unittests") {
testonly = true
sources = [
diff --git a/src/trace_processor/file_reader.cc b/src/trace_processor/file_reader.cc
new file mode 100644
index 0000000..d140dc3
--- /dev/null
+++ b/src/trace_processor/file_reader.cc
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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/file_reader.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+namespace perfetto {
+namespace trace_processor {
+
+FileReader::FileReader(const char* path) {
+ fd_.reset(open(path, O_RDONLY));
+ if (!fd_)
+ PERFETTO_FATAL("Could not open %s", path);
+ struct stat stat_buf {};
+ PERFETTO_CHECK(fstat(*fd_, &stat_buf) == 0);
+ file_size_ = static_cast<uint64_t>(stat_buf.st_size);
+}
+
+FileReader::~FileReader() = default;
+
+uint32_t FileReader::Read(uint64_t offset, uint32_t len, uint8_t* dst) {
+ ssize_t res = pread(*fd_, dst, len, static_cast<off_t>(offset));
+ return res > 0 ? static_cast<uint32_t>(res) : 0;
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/file_reader.h b/src/trace_processor/file_reader.h
new file mode 100644
index 0000000..e3970e0
--- /dev/null
+++ b/src/trace_processor/file_reader.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 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_FILE_READER_H_
+#define SRC_TRACE_PROCESSOR_FILE_READER_H_
+
+#include <stdint.h>
+
+#include "perfetto/base/scoped_file.h"
+#include "src/trace_processor/blob_reader.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class FileReader : public BlobReader {
+ public:
+ explicit FileReader(const char* path);
+ ~FileReader() override;
+
+ uint32_t Read(uint64_t offset, uint32_t len, uint8_t* dst) override;
+ uint64_t file_size() const { return file_size_; }
+
+ private:
+ FileReader(const FileReader&) = delete;
+ FileReader& operator=(const FileReader&) = delete;
+
+ base::ScopedFile fd_;
+ uint64_t file_size_ = 0;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_FILE_READER_H_
diff --git a/src/trace_processor/process_tracker_unittest.cc b/src/trace_processor/process_tracker_unittest.cc
index 24c4777..29f77dd 100644
--- a/src/trace_processor/process_tracker_unittest.cc
+++ b/src/trace_processor/process_tracker_unittest.cc
@@ -14,10 +14,12 @@
* limitations under the License.
*/
-#include "src/trace_processor/trace_processor.h"
-
+#include "src/trace_processor/process_tracker.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "src/trace_processor/sched_tracker.h"
+#include "src/trace_processor/trace_parser.h"
+#include "src/trace_processor/trace_processor.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/sched_tracker_unittest.cc b/src/trace_processor/sched_tracker_unittest.cc
index 3a115df..cf930b0 100644
--- a/src/trace_processor/sched_tracker_unittest.cc
+++ b/src/trace_processor/sched_tracker_unittest.cc
@@ -14,10 +14,12 @@
* limitations under the License.
*/
-#include "src/trace_processor/trace_processor.h"
-
+#include "src/trace_processor/sched_tracker.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "src/trace_processor/process_tracker.h"
+#include "src/trace_processor/trace_parser.h"
+#include "src/trace_processor/trace_processor.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/scoped_db.h b/src/trace_processor/scoped_db.h
index 372c771..75c156a 100644
--- a/src/trace_processor/scoped_db.h
+++ b/src/trace_processor/scoped_db.h
@@ -17,10 +17,15 @@
#ifndef SRC_TRACE_PROCESSOR_SCOPED_DB_H_
#define SRC_TRACE_PROCESSOR_SCOPED_DB_H_
-#include <sqlite3.h>
-
#include "perfetto/base/scoped_file.h"
+extern "C" {
+struct sqlite3;
+struct sqlite3_stmt;
+extern int sqlite3_close(sqlite3*);
+extern int sqlite3_finalize(sqlite3_stmt* pStmt);
+}
+
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/trace_processor.cc b/src/trace_processor/trace_processor.cc
index d1f3220..04977d8 100644
--- a/src/trace_processor/trace_processor.cc
+++ b/src/trace_processor/trace_processor.cc
@@ -16,8 +16,19 @@
#include "src/trace_processor/trace_processor.h"
+#include <sqlite3.h>
#include <functional>
+#include "perfetto/base/task_runner.h"
+#include "src/trace_processor/process_table.h"
+#include "src/trace_processor/process_tracker.h"
+#include "src/trace_processor/sched_slice_table.h"
+#include "src/trace_processor/sched_tracker.h"
+#include "src/trace_processor/thread_table.h"
+#include "src/trace_processor/trace_parser.h"
+
+#include "perfetto/trace_processor/raw_query.pb.h"
+
namespace perfetto {
namespace trace_processor {
namespace {
@@ -39,6 +50,8 @@
ThreadTable::RegisterTable(*db_, context_.storage.get());
}
+TraceProcessor::~TraceProcessor() = default;
+
void TraceProcessor::LoadTrace(BlobReader* reader,
std::function<void()> callback) {
// Reset storage.
@@ -50,7 +63,7 @@
void TraceProcessor::ExecuteQuery(
const protos::RawQueryArgs& args,
- std::function<void(protos::RawQueryResult)> callback) {
+ std::function<void(const protos::RawQueryResult&)> callback) {
protos::RawQueryResult proto;
const auto& sql = args.sql_query();
@@ -59,6 +72,7 @@
&raw_stmt, nullptr);
ScopedStmt stmt(std::move(raw_stmt));
if (err) {
+ proto.set_error(sqlite3_errmsg(*db_));
callback(std::move(proto));
return;
}
@@ -109,7 +123,7 @@
}
proto.set_num_records(static_cast<uint64_t>(row_count));
- callback(std::move(proto));
+ callback(proto);
}
void TraceProcessor::LoadTraceChunk(std::function<void()> callback) {
diff --git a/src/trace_processor/trace_processor.h b/src/trace_processor/trace_processor.h
index ffe26b9..c0ec406 100644
--- a/src/trace_processor/trace_processor.h
+++ b/src/trace_processor/trace_processor.h
@@ -17,26 +17,28 @@
#ifndef SRC_TRACE_PROCESSOR_TRACE_PROCESSOR_H_
#define SRC_TRACE_PROCESSOR_TRACE_PROCESSOR_H_
-#include <sqlite3.h>
+#include <functional>
#include <memory>
-#include "perfetto/base/task_runner.h"
#include "perfetto/base/weak_ptr.h"
-#include "perfetto/trace_processor/raw_query.pb.h"
-#include "src/trace_processor/blob_reader.h"
-#include "src/trace_processor/process_table.h"
-#include "src/trace_processor/process_tracker.h"
-#include "src/trace_processor/sched_slice_table.h"
-#include "src/trace_processor/sched_tracker.h"
#include "src/trace_processor/scoped_db.h"
-#include "src/trace_processor/thread_table.h"
-#include "src/trace_processor/trace_parser.h"
#include "src/trace_processor/trace_processor_context.h"
-#include "src/trace_processor/trace_storage.h"
namespace perfetto {
+
+namespace base {
+class TaskRunner;
+}
+
+namespace protos {
+class RawQueryArgs;
+class RawQueryResult;
+} // namespace protos
+
namespace trace_processor {
+class BlobReader;
+
// Coordinates the loading of traces from an arbitary source and allows
// execution of SQL queries on the events in these traces.
class TraceProcessor {
@@ -51,7 +53,7 @@
// Executes a SQLite query on the loaded portion of the trace. |result| will
// be invoked once after the result of the query is available.
void ExecuteQuery(const protos::RawQueryArgs&,
- std::function<void(protos::RawQueryResult)>);
+ std::function<void(const protos::RawQueryResult&)>);
private:
void LoadTraceChunk(std::function<void()> callback);
diff --git a/src/trace_processor/trace_processor_shell.cc b/src/trace_processor/trace_processor_shell.cc
new file mode 100644
index 0000000..eda0116
--- /dev/null
+++ b/src/trace_processor/trace_processor_shell.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2018 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 <unistd.h>
+
+#include <functional>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/base/time.h"
+#include "perfetto/base/unix_task_runner.h"
+#include "src/trace_processor/file_reader.h"
+#include "src/trace_processor/trace_processor.h"
+
+#include "perfetto/trace_processor/raw_query.pb.h"
+
+using namespace perfetto;
+using namespace perfetto::trace_processor;
+
+namespace {
+void PrintPrompt() {
+ printf("\r%80s\r> ", "");
+ fflush(stdout);
+}
+
+void OnQueryResult(base::TimeNanos t_start, const protos::RawQueryResult& res) {
+ PERFETTO_CHECK(res.columns_size() == res.column_descriptors_size());
+ if (res.has_error()) {
+ PERFETTO_ELOG("SQLite error: %s", res.error().c_str());
+ return;
+ }
+
+ base::TimeNanos t_end = base::GetWallTimeNs();
+
+ for (int r = 0; r < static_cast<int>(res.num_records()); r++) {
+ if (r % 32 == 0) {
+ if (r > 0) {
+ fprintf(stderr, "...\nType 'q' to stop, Enter for more records: ");
+ fflush(stderr);
+ char input[32];
+ if (!fgets(input, sizeof(input) - 1, stdin))
+ exit(0);
+ if (input[0] == 'q')
+ break;
+ }
+ for (const auto& col : res.column_descriptors())
+ printf("%20s ", col.name().c_str());
+ printf("\n");
+
+ for (int i = 0; i < res.columns_size(); i++)
+ printf("%20s ", "--------------------");
+ printf("\n");
+ }
+
+ for (int c = 0; c < res.columns_size(); c++) {
+ switch (res.column_descriptors(c).type()) {
+ case protos::RawQueryResult_ColumnDesc_Type_STRING:
+ printf("%20s ", res.columns(c).string_values(r).c_str());
+ break;
+ case protos::RawQueryResult_ColumnDesc_Type_DOUBLE:
+ printf("%20f ", res.columns(c).double_values(r));
+ break;
+ case protos::RawQueryResult_ColumnDesc_Type_LONG:
+ printf("%20lld ", res.columns(c).long_values(r));
+ break;
+ }
+ }
+ printf("\n");
+ }
+ printf("\nQuery executed in %.3f ms\n\n", (t_end - t_start).count() / 1E6);
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ PERFETTO_ELOG("Usage: %s trace_file.proto", argv[0]);
+ return 1;
+ }
+
+ base::UnixTaskRunner task_runner;
+ FileReader reader(argv[1]);
+ TraceProcessor tp(&task_runner);
+
+ task_runner.PostTask([&tp, &reader]() {
+ auto t_start = base::GetWallTimeMs();
+ auto on_trace_loaded = [t_start, &reader] {
+ double s = (base::GetWallTimeMs() - t_start).count() / 1000.0;
+ double size_mb = reader.file_size() / 1000000.0;
+ PERFETTO_ILOG("Trace loaded: %.2f MB (%.1f MB/s)", size_mb, size_mb / s);
+ PrintPrompt();
+ };
+ tp.LoadTrace(&reader, on_trace_loaded);
+ });
+
+ task_runner.AddFileDescriptorWatch(STDIN_FILENO, [&tp, &task_runner] {
+ char line[1024];
+ if (!fgets(line, sizeof(line) - 1, stdin)) {
+ task_runner.Quit();
+ return;
+ }
+ protos::RawQueryArgs query;
+ query.set_sql_query(line);
+ base::TimeNanos t_start = base::GetWallTimeNs();
+ tp.ExecuteQuery(query, [t_start](const protos::RawQueryResult& res) {
+ OnQueryResult(t_start, res);
+ });
+ PrintPrompt();
+ });
+
+ task_runner.Run();
+ return 0;
+}
diff --git a/src/trace_processor/wasm_bridge.cc b/src/trace_processor/wasm_bridge.cc
index 3cb997d..f85cb69 100644
--- a/src/trace_processor/wasm_bridge.cc
+++ b/src/trace_processor/wasm_bridge.cc
@@ -19,11 +19,13 @@
#include <string>
#include "perfetto/base/logging.h"
-#include "perfetto/trace_processor/raw_query.pb.h"
-#include "perfetto/trace_processor/sched.pb.h"
+#include "src/trace_processor/blob_reader.h"
#include "src/trace_processor/emscripten_task_runner.h"
#include "src/trace_processor/trace_processor.h"
+#include "perfetto/trace_processor/raw_query.pb.h"
+#include "perfetto/trace_processor/sched.pb.h"
+
namespace perfetto {
namespace trace_processor {