| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "test_trace_processor_impl.h" |
| |
| #include <sstream> |
| |
| #include "third_party/perfetto/include/perfetto/trace_processor/trace_processor.h" |
| |
| namespace base::test { |
| |
| QueryResultOrError::QueryResultOrError(const QueryResult& result) |
| : result_(result) {} |
| QueryResultOrError::QueryResultOrError(const std::string& error) |
| : error_(error) {} |
| QueryResultOrError::~QueryResultOrError() = default; |
| |
| TestTraceProcessorImpl::TestTraceProcessorImpl() { |
| config_ = std::make_unique<perfetto::trace_processor::Config>(); |
| trace_processor_ = |
| perfetto::trace_processor::TraceProcessor::CreateInstance(*config_); |
| } |
| |
| TestTraceProcessorImpl::~TestTraceProcessorImpl() = default; |
| |
| TestTraceProcessorImpl::TestTraceProcessorImpl(TestTraceProcessorImpl&& other) = |
| default; |
| TestTraceProcessorImpl& TestTraceProcessorImpl::operator=( |
| TestTraceProcessorImpl&& other) = default; |
| |
| QueryResultOrError TestTraceProcessorImpl::ExecuteQuery( |
| const std::string& sql) const { |
| QueryResultOrError::QueryResult result; |
| auto it = trace_processor_->ExecuteQuery(sql); |
| // Write column names. |
| std::vector<std::string> column_names; |
| for (uint32_t c = 0; c < it.ColumnCount(); ++c) { |
| column_names.push_back(it.GetColumnName(c)); |
| } |
| result.push_back(column_names); |
| // Write rows. |
| while (it.Next()) { |
| std::vector<std::string> row; |
| for (uint32_t c = 0; c < it.ColumnCount(); ++c) { |
| perfetto::trace_processor::SqlValue sql_value = it.Get(c); |
| std::ostringstream ss; |
| switch (sql_value.type) { |
| case perfetto::trace_processor::SqlValue::Type::kLong: |
| ss << sql_value.AsLong(); |
| row.push_back(ss.str()); |
| break; |
| case perfetto::trace_processor::SqlValue::Type::kDouble: |
| ss << sql_value.AsDouble(); |
| row.push_back(ss.str()); |
| break; |
| case perfetto::trace_processor::SqlValue::Type::kString: |
| row.push_back(sql_value.AsString()); |
| break; |
| case perfetto::trace_processor::SqlValue::Type::kBytes: |
| row.push_back("<raw bytes>"); |
| break; |
| case perfetto::trace_processor::SqlValue::Type::kNull: |
| row.push_back("[NULL]"); |
| break; |
| default: |
| row.push_back("unknown"); |
| } |
| } |
| result.push_back(row); |
| } |
| if (!it.Status().ok()) { |
| return QueryResultOrError(it.Status().message()); |
| } |
| return QueryResultOrError(result); |
| } |
| |
| absl::Status TestTraceProcessorImpl::ParseTrace( |
| const std::vector<char>& raw_trace) { |
| auto status = |
| trace_processor_->Parse(perfetto::trace_processor::TraceBlobView( |
| perfetto::trace_processor::TraceBlob::CopyFrom(raw_trace.data(), |
| raw_trace.size()))); |
| // TODO(rasikan): Add DCHECK that the trace is well-formed and parsing doesn't |
| // have any errors (e.g. to catch the cases when someone emits overlapping |
| // trace events on the same track). |
| if (!status.ok()) { |
| return absl::UnknownError(status.message()); |
| } |
| |
| status = trace_processor_->NotifyEndOfFile(); |
| return status.ok() ? absl::OkStatus() : absl::UnknownError(status.message()); |
| } |
| |
| absl::Status TestTraceProcessorImpl::OverrideSqlModule( |
| const std::string& module_name, |
| const TestTraceProcessorImpl::PerfettoSQLModule& module) { |
| auto status = |
| trace_processor_->RegisterSqlModule({module_name, module, true}); |
| return status.ok() ? absl::OkStatus() : absl::UnknownError(status.message()); |
| } |
| |
| } // namespace base::test |