| // Copyright (C) 2026 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/plugins/metadata/metadata.h" |
| |
| #include <cstdint> |
| #include <memory> |
| #include <optional> |
| #include <vector> |
| |
| #include "perfetto/base/compiler.h" |
| #include "src/trace_processor/core/plugin/plugin.h" |
| #include "src/trace_processor/perfetto_sql/engine/perfetto_sql_connection.h" |
| #include "src/trace_processor/sqlite/bindings/sqlite_function.h" |
| #include "src/trace_processor/sqlite/bindings/sqlite_result.h" |
| #include "src/trace_processor/sqlite/bindings/sqlite_type.h" |
| #include "src/trace_processor/sqlite/bindings/sqlite_value.h" |
| #include "src/trace_processor/storage/trace_storage.h" |
| #include "src/trace_processor/tables/metadata_tables_py.h" |
| #include "src/trace_processor/types/trace_processor_context.h" |
| |
| namespace perfetto::trace_processor { |
| namespace { |
| |
| void ReportValue(sqlite3_context* ctx, |
| const TraceStorage* storage, |
| const tables::MetadataTable::ConstRowReference& rr) { |
| if (rr.str_value().has_value()) { |
| sqlite::result::StaticString(ctx, |
| storage->GetString(*rr.str_value()).c_str()); |
| } else if (rr.int_value().has_value()) { |
| sqlite::result::Long(ctx, *rr.int_value()); |
| } else { |
| sqlite::result::Null(ctx); |
| } |
| } |
| |
| } // namespace |
| |
| // static |
| void ExtractMetadata::Step(sqlite3_context* ctx, int, sqlite3_value** argv) { |
| if (sqlite::value::Type(argv[0]) == sqlite::Type::kNull) { |
| return; |
| } |
| const char* name = sqlite::value::Text(argv[0]); |
| auto* user_data = GetUserData(ctx); |
| |
| auto& cursor = user_data->cursor; |
| cursor.SetFilterValueUnchecked(0, name); |
| cursor.Execute(); |
| if (!cursor.Eof()) { |
| ReportValue(ctx, user_data->storage, |
| user_data->storage |
| ->metadata_table()[cursor.ToRowNumber().row_number()]); |
| } |
| } |
| |
| // static |
| void ExtractMetadataForMachine::Step(sqlite3_context* ctx, |
| int, |
| sqlite3_value** argv) { |
| if (sqlite::value::Type(argv[0]) == sqlite::Type::kNull || |
| sqlite::value::Type(argv[1]) == sqlite::Type::kNull) { |
| return; |
| } |
| auto machine_id = static_cast<uint32_t>(sqlite::value::Int64(argv[0])); |
| const char* name = sqlite::value::Text(argv[1]); |
| |
| auto* user_data = GetUserData(ctx); |
| auto& cursor = user_data->cursor; |
| cursor.SetFilterValueUnchecked(0, name); |
| cursor.SetFilterValueUnchecked(1, machine_id); |
| cursor.Execute(); |
| if (!cursor.Eof()) { |
| ReportValue(ctx, user_data->storage, |
| user_data->storage |
| ->metadata_table()[cursor.ToRowNumber().row_number()]); |
| } |
| } |
| |
| // static |
| void ExtractMetadataForTrace::Step(sqlite3_context* ctx, |
| int, |
| sqlite3_value** argv) { |
| if (sqlite::value::Type(argv[0]) == sqlite::Type::kNull || |
| sqlite::value::Type(argv[1]) == sqlite::Type::kNull) { |
| return; |
| } |
| auto trace_id = static_cast<uint32_t>(sqlite::value::Int64(argv[0])); |
| const char* name = sqlite::value::Text(argv[1]); |
| |
| auto* user_data = GetUserData(ctx); |
| auto& cursor = user_data->cursor; |
| cursor.SetFilterValueUnchecked(0, name); |
| cursor.SetFilterValueUnchecked(1, trace_id); |
| cursor.Execute(); |
| if (!cursor.Eof()) { |
| ReportValue(ctx, user_data->storage, |
| user_data->storage |
| ->metadata_table()[cursor.ToRowNumber().row_number()]); |
| } |
| } |
| |
| // static |
| void ExtractExactMetadata::Step(sqlite3_context* ctx, |
| int, |
| sqlite3_value** argv) { |
| if (sqlite::value::Type(argv[0]) == sqlite::Type::kNull || |
| sqlite::value::Type(argv[1]) == sqlite::Type::kNull || |
| sqlite::value::Type(argv[2]) == sqlite::Type::kNull) { |
| return; |
| } |
| auto machine_id = static_cast<uint32_t>(sqlite::value::Int64(argv[0])); |
| auto trace_id = static_cast<uint32_t>(sqlite::value::Int64(argv[1])); |
| const char* name = sqlite::value::Text(argv[2]); |
| |
| auto* user_data = GetUserData(ctx); |
| auto& cursor = user_data->cursor; |
| cursor.SetFilterValueUnchecked(0, name); |
| cursor.SetFilterValueUnchecked(1, machine_id); |
| cursor.SetFilterValueUnchecked(2, trace_id); |
| cursor.Execute(); |
| if (!cursor.Eof()) { |
| ReportValue(ctx, user_data->storage, |
| user_data->storage |
| ->metadata_table()[cursor.ToRowNumber().row_number()]); |
| } |
| } |
| |
| namespace metadata { |
| namespace { |
| |
| class MetadataPlugin : public Plugin<MetadataPlugin> { |
| public: |
| ~MetadataPlugin() override; |
| void RegisterFunctions(PerfettoSqlConnection*, |
| std::vector<FunctionRegistration>& out) override { |
| auto* s = trace_context_->storage.get(); |
| out.push_back(MakeFunctionRegistration<ExtractMetadata>( |
| std::make_unique<ExtractMetadata::Context>(s))); |
| out.push_back(MakeFunctionRegistration<ExtractMetadataForMachine>( |
| std::make_unique<ExtractMetadataForMachine::Context>(s))); |
| out.push_back(MakeFunctionRegistration<ExtractMetadataForTrace>( |
| std::make_unique<ExtractMetadataForTrace::Context>(s))); |
| out.push_back(MakeFunctionRegistration<ExtractExactMetadata>( |
| std::make_unique<ExtractExactMetadata::Context>(s))); |
| } |
| }; |
| MetadataPlugin::~MetadataPlugin() = default; |
| |
| } // namespace |
| |
| void RegisterPlugin() { |
| static PluginRegistration reg( |
| []() -> std::unique_ptr<PluginBase> { |
| return std::make_unique<MetadataPlugin>(); |
| }, |
| MetadataPlugin::kPluginId, MetadataPlugin::kDepIds.data(), |
| MetadataPlugin::kDepIds.size()); |
| base::ignore_result(reg); |
| } |
| |
| } // namespace metadata |
| } // namespace perfetto::trace_processor |