tp: perfetto_table_info
Bug:317966255
Change-Id: If1b5b4cd54e5c5963970bdb102111183dc2ae4bc
diff --git a/Android.bp b/Android.bp
index c9ef938..b81feff 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11721,6 +11721,7 @@
"src/trace_processor/perfetto_sql/intrinsics/table_functions/experimental_sched_upid.cc",
"src/trace_processor/perfetto_sql/intrinsics/table_functions/experimental_slice_layout.cc",
"src/trace_processor/perfetto_sql/intrinsics/table_functions/flamegraph_construction_algorithms.cc",
+ "src/trace_processor/perfetto_sql/intrinsics/table_functions/table_info.cc",
"src/trace_processor/perfetto_sql/intrinsics/table_functions/view.cc",
],
}
diff --git a/BUILD b/BUILD
index 2c2dbbe..5cebd65 100644
--- a/BUILD
+++ b/BUILD
@@ -2180,6 +2180,8 @@
"src/trace_processor/perfetto_sql/intrinsics/table_functions/experimental_slice_layout.h",
"src/trace_processor/perfetto_sql/intrinsics/table_functions/flamegraph_construction_algorithms.cc",
"src/trace_processor/perfetto_sql/intrinsics/table_functions/flamegraph_construction_algorithms.h",
+ "src/trace_processor/perfetto_sql/intrinsics/table_functions/table_info.cc",
+ "src/trace_processor/perfetto_sql/intrinsics/table_functions/table_info.h",
"src/trace_processor/perfetto_sql/intrinsics/table_functions/view.cc",
"src/trace_processor/perfetto_sql/intrinsics/table_functions/view.h",
],
diff --git a/src/trace_processor/db/column.h b/src/trace_processor/db/column.h
index 54e66a1..e660046 100644
--- a/src/trace_processor/db/column.h
+++ b/src/trace_processor/db/column.h
@@ -355,6 +355,9 @@
// Public for testing.
bool IsDummy() const { return type_ == ColumnType::kDummy; }
+ // Returns true if this column is a hidden column.
+ bool IsHidden() const { return (flags_ & Flag::kHidden) != 0; }
+
// Returns the index of the RowMap in the containing table.
uint32_t overlay_index() const { return overlay_index_; }
@@ -435,9 +438,6 @@
return static_cast<ColumnStorage<stored_type<T>>*>(storage_);
}
- // Returns true if this column is a hidden column.
- bool IsHidden() const { return (flags_ & Flag::kHidden) != 0; }
-
const StringPool& string_pool() const { return *string_pool_; }
// Returns the type of this Column in terms of SqlValue::Type.
diff --git a/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.cc b/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.cc
index 4337b56..c236a2f 100644
--- a/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.cc
+++ b/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.cc
@@ -184,6 +184,7 @@
const std::string& table_name) {
auto context =
std::make_unique<DbSqliteTable::Context>(query_cache_.get(), &table);
+ static_tables_.Insert(table_name, &table);
engine_->RegisterVirtualTableModule<DbSqliteTable>(
table_name, std::move(context), SqliteTable::kEponymousOnly, false);
@@ -833,5 +834,23 @@
base::Join(columns_missing_from_schema, ", ").c_str());
}
+const RuntimeTable* PerfettoSqlEngine::GetRuntimeTableOrNull(
+ std::string_view name) const {
+ auto table_ptr = runtime_tables_.Find(name.data());
+ if (!table_ptr) {
+ return nullptr;
+ }
+ return table_ptr->get();
+}
+
+const Table* PerfettoSqlEngine::GetStaticTableOrNull(
+ std::string_view name) const {
+ auto table_ptr = static_tables_.Find(name.data());
+ if (!table_ptr) {
+ return nullptr;
+ }
+ return *table_ptr;
+}
+
} // namespace trace_processor
} // namespace perfetto
diff --git a/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h b/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h
index 404d1c0..5d47e50 100644
--- a/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h
+++ b/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h
@@ -19,7 +19,9 @@
#include <cstdint>
#include <memory>
+#include <optional>
+#include "perfetto/base/logging.h"
#include "perfetto/base/status.h"
#include "perfetto/ext/base/flat_hash_map.h"
#include "perfetto/ext/base/status_or.h"
@@ -116,7 +118,7 @@
// Registers a trace processor C++ table with SQLite with an SQL name of
// |name|.
- void RegisterStaticTable(const Table& table, const std::string& name);
+ void RegisterStaticTable(const Table&, const std::string& name);
// Registers a trace processor C++ table function with SQLite.
void RegisterStaticTableFunction(std::unique_ptr<StaticTableFunction> fn);
@@ -164,6 +166,12 @@
macros_.size();
}
+ // Find RuntimeTable registered with engine with provided name.
+ const RuntimeTable* GetRuntimeTableOrNull(std::string_view) const;
+
+ // Find static table registered with engine with provided name.
+ const Table* GetStaticTableOrNull(std::string_view) const;
+
private:
base::StatusOr<SqlSource> ExecuteCreateFunction(
const PerfettoSqlParser::CreateFunction&,
@@ -221,6 +229,7 @@
base::FlatHashMap<std::string, std::unique_ptr<RuntimeTableFunction::State>>
runtime_table_fn_states_;
+ base::FlatHashMap<std::string, const Table*> static_tables_;
base::FlatHashMap<std::string, std::unique_ptr<RuntimeTable>> runtime_tables_;
base::FlatHashMap<std::string, sql_modules::RegisteredModule> modules_;
base::FlatHashMap<std::string, PerfettoSqlPreprocessor::Macro> macros_;
diff --git a/src/trace_processor/perfetto_sql/intrinsics/table_functions/BUILD.gn b/src/trace_processor/perfetto_sql/intrinsics/table_functions/BUILD.gn
index 1375d9e..cbe3513 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/table_functions/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/intrinsics/table_functions/BUILD.gn
@@ -39,6 +39,8 @@
"experimental_slice_layout.h",
"flamegraph_construction_algorithms.cc",
"flamegraph_construction_algorithms.h",
+ "table_info.cc",
+ "table_info.h",
"view.cc",
"view.h",
]
@@ -56,6 +58,7 @@
"../../../tables",
"../../../types",
"../../../util",
+ "../../engine",
]
public_deps = [ ":interface" ]
}
diff --git a/src/trace_processor/perfetto_sql/intrinsics/table_functions/table_info.cc b/src/trace_processor/perfetto_sql/intrinsics/table_functions/table_info.cc
new file mode 100644
index 0000000..fe17ac7
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/intrinsics/table_functions/table_info.cc
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2023 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/perfetto_sql/intrinsics/table_functions/table_info.h"
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/base/status.h"
+#include "src/trace_processor/containers/string_pool.h"
+#include "src/trace_processor/db/runtime_table.h"
+#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
+#include "src/trace_processor/perfetto_sql/intrinsics/table_functions/tables_py.h"
+#include "src/trace_processor/sqlite/sqlite_utils.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace tables {
+
+PerfettoTableInfoTable::~PerfettoTableInfoTable() = default;
+
+} // namespace tables
+
+namespace {
+
+using TableInfoTable = tables::PerfettoTableInfoTable;
+
+std::vector<TableInfoTable::Row> GetColInfoRows(const std::vector<Column>& cols,
+ StringPool* pool) {
+ std::vector<TableInfoTable::Row> rows;
+ for (const Column& col : cols) {
+ if (col.IsHidden()) {
+ continue;
+ }
+ TableInfoTable::Row row;
+ row.name = pool->InternString(col.name());
+ switch (col.col_type()) {
+ case ColumnType::kString:
+ row.col_type = pool->InternString("string");
+ break;
+ case ColumnType::kInt64:
+ row.col_type = pool->InternString("int64");
+ break;
+ case ColumnType::kInt32:
+ row.col_type = pool->InternString("int32");
+ break;
+ case ColumnType::kUint32:
+ row.col_type = pool->InternString("uint32");
+ break;
+ case ColumnType::kDouble:
+ row.col_type = pool->InternString("double");
+ break;
+ case ColumnType::kId:
+ row.col_type = pool->InternString("id");
+ break;
+ case ColumnType::kDummy:
+ row.col_type = pool->InternString("dummy");
+ break;
+ }
+ if (col.IsSetId()) {
+ row.col_type = pool->InternString("set id");
+ }
+ row.nullable = col.IsNullable();
+ row.sorted = col.IsSorted();
+ rows.push_back(row);
+ }
+ return rows;
+}
+
+} // namespace
+
+TableInfo::TableInfo(StringPool* string_pool, const PerfettoSqlEngine* engine)
+ : string_pool_(string_pool), engine_(engine) {}
+
+base::Status TableInfo::ValidateConstraints(const QueryConstraints& qc) {
+ const auto& cs = qc.constraints();
+
+ int column = static_cast<int>(TableInfoTable::ColumnIndex::table_name);
+ auto id_fn = [column](const QueryConstraints::Constraint& c) {
+ return c.column == column && sqlite_utils::IsOpEq(c.op);
+ };
+ bool has_id_cs = std::find_if(cs.begin(), cs.end(), id_fn) != cs.end();
+ return has_id_cs ? base::OkStatus()
+ : base::ErrStatus("Failed to find required constraints");
+}
+
+base::Status TableInfo::ComputeTable(const std::vector<Constraint>& cs,
+ const std::vector<Order>&,
+ const BitVector&,
+ std::unique_ptr<Table>& table_return) {
+ uint32_t column = TableInfoTable::ColumnIndex::table_name;
+ auto constraint_it =
+ std::find_if(cs.begin(), cs.end(), [column](const Constraint& c) {
+ return c.col_idx == column && c.op == FilterOp::kEq;
+ });
+ if (constraint_it == cs.end()) {
+ return base::ErrStatus("Failed to find required constraints");
+ }
+
+ if (constraint_it->value.type != SqlValue::kString) {
+ return base::ErrStatus("perfetto_table_info takes table name as a string.");
+ }
+
+ std::string table_name = constraint_it->value.AsString();
+ auto table = std::make_unique<TableInfoTable>(string_pool_);
+ auto table_name_id = string_pool_->InternString(table_name.c_str());
+
+ // Find static table
+ const Table* static_table = engine_->GetStaticTableOrNull(table_name);
+ if (static_table) {
+ for (auto& row : GetColInfoRows(static_table->columns(), string_pool_)) {
+ row.table_name = table_name_id;
+ table->Insert(row);
+ }
+ table_return = std::move(table);
+ return base::OkStatus();
+ }
+
+ // Find runtime table
+ const RuntimeTable* runtime_table =
+ engine_->GetRuntimeTableOrNull(table_name);
+ if (runtime_table) {
+ for (auto& row : GetColInfoRows(runtime_table->columns(), string_pool_)) {
+ row.table_name = table_name_id;
+ table->Insert(row);
+ }
+ table_return = std::move(table);
+ return base::OkStatus();
+ }
+
+ return base::ErrStatus("Perfetto table '%s' not found.", table_name.c_str());
+}
+
+Table::Schema TableInfo::CreateSchema() {
+ return TableInfoTable::ComputeStaticSchema();
+}
+
+std::string TableInfo::TableName() {
+ return TableInfoTable::Name();
+}
+
+uint32_t TableInfo::EstimateRowCount() {
+ return 1;
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/perfetto_sql/intrinsics/table_functions/table_info.h b/src/trace_processor/perfetto_sql/intrinsics/table_functions/table_info.h
new file mode 100644
index 0000000..bec9897
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/intrinsics/table_functions/table_info.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 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_PERFETTO_SQL_INTRINSICS_TABLE_FUNCTIONS_TABLE_INFO_H_
+#define SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_TABLE_FUNCTIONS_TABLE_INFO_H_
+
+#include <optional>
+
+#include "src/trace_processor/containers/string_pool.h"
+#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
+#include "src/trace_processor/perfetto_sql/intrinsics/table_functions/static_table_function.h"
+#include "src/trace_processor/storage/trace_storage.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class TraceProcessorContext;
+
+class TableInfo : public StaticTableFunction {
+ public:
+ explicit TableInfo(StringPool*, const PerfettoSqlEngine*);
+
+ Table::Schema CreateSchema() override;
+ std::string TableName() override;
+ uint32_t EstimateRowCount() override;
+ base::Status ValidateConstraints(const QueryConstraints&) override;
+ base::Status ComputeTable(const std::vector<Constraint>&,
+ const std::vector<Order>&,
+ const BitVector& cols_used,
+ std::unique_ptr<Table>& table_return) override;
+
+ private:
+ StringPool* string_pool_ = nullptr;
+ const PerfettoSqlEngine* engine_ = nullptr;
+};
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_TABLE_FUNCTIONS_TABLE_INFO_H_
diff --git a/src/trace_processor/perfetto_sql/intrinsics/table_functions/tables.py b/src/trace_processor/perfetto_sql/intrinsics/table_functions/tables.py
index 32e4550..b022676 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/table_functions/tables.py
+++ b/src/trace_processor/perfetto_sql/intrinsics/table_functions/tables.py
@@ -30,6 +30,18 @@
from src.trace_processor.tables.slice_tables import SLICE_TABLE
from src.trace_processor.tables.sched_tables import SCHED_SLICE_TABLE
+TABLE_INFO_TABLE = Table(
+ python_module=__file__,
+ class_name="PerfettoTableInfoTable",
+ sql_name="perfetto_table_info",
+ columns=[
+ C("table_name", CppString(), flags=ColumnFlag.HIDDEN),
+ C('name', CppString()),
+ C('col_type', CppString()),
+ C('nullable', CppInt64()),
+ C('sorted', CppInt64()),
+ ])
+
ANCESTOR_SLICE_TABLE = Table(
python_module=__file__,
class_name="AncestorSliceTable",
@@ -98,30 +110,6 @@
],
parent=STACK_PROFILE_CALLSITE_TABLE)
-EXPERIMENTAL_ANNOTATED_CALLSTACK_TABLE = Table(
- python_module=__file__,
- class_name="ExperimentalAnnotatedCallstackTable",
- sql_name="experimental_annotated_callstack",
- columns=[
- C("annotation", CppString()),
- C("start_id",
- CppTableId(STACK_PROFILE_CALLSITE_TABLE),
- flags=ColumnFlag.HIDDEN),
- ],
- parent=STACK_PROFILE_CALLSITE_TABLE)
-
-EXPERIMENTAL_ANNOTATED_CALLSTACK_TABLE = Table(
- python_module=__file__,
- class_name="ExperimentalAnnotatedCallstackTable",
- sql_name="experimental_annotated_callstack",
- columns=[
- C("annotation", CppString()),
- C("start_id",
- CppTableId(STACK_PROFILE_CALLSITE_TABLE),
- flags=ColumnFlag.HIDDEN),
- ],
- parent=STACK_PROFILE_CALLSITE_TABLE)
-
EXPERIMENTAL_COUNTER_DUR_TABLE = Table(
python_module=__file__,
class_name="ExperimentalCounterDurTable",
@@ -163,4 +151,5 @@
EXPERIMENTAL_COUNTER_DUR_TABLE,
EXPERIMENTAL_SCHED_UPID_TABLE,
EXPERIMENTAL_SLICE_LAYOUT_TABLE,
+ TABLE_INFO_TABLE,
]
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 514b92f..e777d6e 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -78,6 +78,7 @@
#include "src/trace_processor/perfetto_sql/intrinsics/table_functions/experimental_sched_upid.h"
#include "src/trace_processor/perfetto_sql/intrinsics/table_functions/experimental_slice_layout.h"
#include "src/trace_processor/perfetto_sql/intrinsics/table_functions/static_table_function.h"
+#include "src/trace_processor/perfetto_sql/intrinsics/table_functions/table_info.h"
#include "src/trace_processor/perfetto_sql/intrinsics/table_functions/view.h"
#include "src/trace_processor/perfetto_sql/prelude/tables_views.h"
#include "src/trace_processor/perfetto_sql/stdlib/stdlib.h"
@@ -862,6 +863,8 @@
engine_->RegisterStaticTableFunction(std::unique_ptr<ExperimentalSliceLayout>(
new ExperimentalSliceLayout(context_.storage.get()->mutable_string_pool(),
&storage->slice_table())));
+ engine_->RegisterStaticTableFunction(std::unique_ptr<TableInfo>(new TableInfo(
+ context_.storage.get()->mutable_string_pool(), engine_.get())));
engine_->RegisterStaticTableFunction(std::unique_ptr<Ancestor>(
new Ancestor(Ancestor::Type::kSlice, context_.storage.get())));
engine_->RegisterStaticTableFunction(std::unique_ptr<Ancestor>(new Ancestor(
diff --git a/test/trace_processor/diff_tests/syntax/table_tests.py b/test/trace_processor/diff_tests/syntax/table_tests.py
index f675760..1833f59 100644
--- a/test/trace_processor/diff_tests/syntax/table_tests.py
+++ b/test/trace_processor/diff_tests/syntax/table_tests.py
@@ -63,3 +63,37 @@
1,"big"
2,"bigger"
"""))
+
+ def test_perfetto_table_info_static_table(self):
+ return DiffTestBlueprint(
+ trace=DataPath('android_boot.pftrace'),
+ query="""
+ SELECT * FROM perfetto_table_info('counter');
+ """,
+ out=Csv("""
+ "id","type","name","col_type","nullable","sorted"
+ 0,"perfetto_table_info","id","id",0,1
+ 1,"perfetto_table_info","type","string",0,0
+ 2,"perfetto_table_info","ts","int64",0,1
+ 3,"perfetto_table_info","track_id","uint32",0,0
+ 4,"perfetto_table_info","value","double",0,0
+ 5,"perfetto_table_info","arg_set_id","uint32",1,0
+ """))
+
+ def test_perfetto_table_info_runtime_table(self):
+ return DiffTestBlueprint(
+ trace=DataPath('android_boot.pftrace'),
+ query="""
+ CREATE PERFETTO TABLE foo AS
+ SELECT 2 AS col
+ UNION
+ SELECT 1 AS col
+ UNION
+ SELECT 0 AS col;
+
+ SELECT * FROM perfetto_table_info('foo');
+ """,
+ out=Csv("""
+ "id","type","name","col_type","nullable","sorted"
+ 0,"perfetto_table_info","col","int64",1,0
+ """))