tp: improve plugin interface (#5368)
Learnings from trying to port various users to use the plugin API.
diff --git a/src/trace_processor/core/plugin/BUILD.gn b/src/trace_processor/core/plugin/BUILD.gn
index 6c7d24c..0f35661 100644
--- a/src/trace_processor/core/plugin/BUILD.gn
+++ b/src/trace_processor/core/plugin/BUILD.gn
@@ -22,5 +22,6 @@
"../../../base",
"../../containers",
"../../types",
+ "../util",
]
}
diff --git a/src/trace_processor/core/plugin/plugin.cc b/src/trace_processor/core/plugin/plugin.cc
index fbb7af5..39d8a88 100644
--- a/src/trace_processor/core/plugin/plugin.cc
+++ b/src/trace_processor/core/plugin/plugin.cc
@@ -17,8 +17,9 @@
#include "src/trace_processor/core/plugin/plugin.h"
#include <cstddef>
+#include <cstdint>
+#include <limits>
#include <memory>
-#include <string>
#include <utility>
#include <vector>
@@ -28,61 +29,21 @@
namespace perfetto::trace_processor {
-// Global linked list head for plugin registrations.
-static PluginRegistration* g_plugin_head = nullptr;
-
-PluginRegistration::PluginRegistration(Factory f,
- const void* id,
- const void* const* deps,
- size_t n_deps)
- : next(g_plugin_head),
- factory(f),
- plugin_id(id),
- dep_ids(deps),
- dep_count(n_deps) {
- g_plugin_head = this;
-}
-
-PluginRegistration* GetPluginRegistrations() {
- return g_plugin_head;
-}
-
-// Default no-op implementations.
-PluginBase::~PluginBase() = default;
-std::unique_ptr<Destructible> PluginBase::CreateStorage(
- TraceProcessorContext*) {
- return nullptr;
-}
-void PluginBase::RegisterImporters(TraceProcessorContext*, Destructible*) {}
-void PluginBase::RegisterDataframes(TraceProcessorContext*,
- Destructible*,
- std::vector<PluginDataframe>&) {}
-void PluginBase::RegisterStaticTableFunctions(
- TraceProcessorContext*,
- Destructible*,
- std::vector<std::unique_ptr<StaticTableFunction>>&) {}
-void PluginBase::RegisterSqliteModules(TraceProcessorContext*,
- Destructible*,
- std::vector<SqliteModuleRegistration>&) {
-}
-void PluginBase::RegisterSqlModules(
- TraceProcessorContext*,
- Destructible*,
- std::vector<std::pair<std::string, std::string>>&) {}
-
namespace {
-// Returns the topologically sorted order of plugin registrations.
-// The result is cached in a static local since the global linked list
-// is fixed after static initialization.
-std::vector<PluginRegistration*> TopologicalSort() {
+// Global linked list head for plugin registrations.
+PluginRegistration* g_plugin_head = nullptr;
+
+// Topologically sorts registrations and pre-resolves dependency indices.
+// Called once and cached.
+PluginSet BuildPluginSet() {
// Collect all registrations.
std::vector<PluginRegistration*> regs;
- for (auto* r = GetPluginRegistrations(); r; r = r->next) {
+ for (auto* r = g_plugin_head; r; r = r->next) {
regs.push_back(r);
}
- // Build a map from plugin_id -> index for dependency resolution.
+ // Build a map from plugin_id -> index in |regs|.
base::FlatHashMap<const void*, size_t> id_to_idx;
for (size_t i = 0; i < regs.size(); ++i) {
id_to_idx[regs[i]->plugin_id] = i;
@@ -98,8 +59,6 @@
// Kahn's algorithm for topological sort.
size_t n = regs.size();
std::vector<size_t> in_degree(n, 0);
-
- // Build adjacency: for each plugin, which plugins depend on it.
std::vector<std::vector<size_t>> dependents(n);
for (size_t i = 0; i < n; ++i) {
for (size_t d = 0; d < regs[i]->dep_count; ++d) {
@@ -109,7 +68,6 @@
}
}
- // Start with plugins that have no dependencies.
std::vector<size_t> queue;
for (size_t i = 0; i < n; ++i) {
if (in_degree[i] == 0) {
@@ -129,34 +87,64 @@
}
}
}
-
- // If we didn't process all plugins, there's a cycle.
PERFETTO_CHECK(sorted_order.size() == n);
- std::vector<PluginRegistration*> result;
- result.reserve(n);
- for (size_t idx : sorted_order) {
- result.push_back(regs[idx]);
+ // Build a map from original reg index -> position in sorted output,
+ // so we can resolve dep indices into the final array.
+ base::FlatHashMap<const void*, size_t> id_to_sorted_idx;
+ for (size_t i = 0; i < sorted_order.size(); ++i) {
+ id_to_sorted_idx[regs[sorted_order[i]]->plugin_id] = i;
+ }
+
+ // Build PluginSet with pre-resolved dep indices.
+ PluginSet result;
+ result.entries.reserve(n);
+ for (size_t orig_idx : sorted_order) {
+ PluginSet::Entry entry;
+ entry.factory = regs[orig_idx]->factory;
+ for (size_t d = 0; d < regs[orig_idx]->dep_count; ++d) {
+ size_t* dep_sorted = id_to_sorted_idx.Find(regs[orig_idx]->dep_ids[d]);
+ PERFETTO_CHECK(dep_sorted != nullptr);
+ entry.dep_indices.push_back(*dep_sorted);
+ }
+ result.entries.push_back(std::move(entry));
}
return result;
}
-const std::vector<PluginRegistration*>& GetSortedPluginRegistrations() {
- static base::NoDestructor<std::vector<PluginRegistration*>> sorted(
- TopologicalSort());
- return sorted.ref();
-}
-
} // namespace
-std::vector<std::unique_ptr<PluginBase>> CreatePlugins() {
- const auto& sorted = GetSortedPluginRegistrations();
- std::vector<std::unique_ptr<PluginBase>> plugins;
- plugins.reserve(sorted.size());
- for (auto* reg : sorted) {
- plugins.push_back(reg->factory());
- }
- return plugins;
+PluginRegistration::PluginRegistration(Factory f,
+ const void* id,
+ const void* const* deps,
+ size_t n_deps)
+ : next(g_plugin_head),
+ factory(f),
+ plugin_id(id),
+ dep_ids(deps),
+ dep_count(n_deps) {
+ g_plugin_head = this;
+}
+
+// Default no-op implementations.
+PluginBase::~PluginBase() = default;
+void PluginBase::RegisterImporters(TraceReaderRegistry&) {}
+void PluginBase::RegisterProtoImporterModules(ProtoImporterModuleContext*) {}
+void PluginBase::RegisterDataframes(std::vector<PluginDataframe>&) {}
+void PluginBase::RegisterStaticTableFunctions(
+ std::vector<std::unique_ptr<StaticTableFunction>>&) {}
+void PluginBase::RegisterSqliteModules(std::vector<SqliteModuleRegistration>&) {
+}
+uint64_t PluginBase::GetBoundsMutationCount() {
+ return 0;
+}
+std::pair<int64_t, int64_t> PluginBase::GetTimestampBounds() {
+ return {std::numeric_limits<int64_t>::max(), 0};
+}
+
+const PluginSet& GetPluginSet() {
+ static base::NoDestructor<PluginSet> set(BuildPluginSet());
+ return set.ref();
}
} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/core/plugin/plugin.h b/src/trace_processor/core/plugin/plugin.h
index 7079f2d..114d91e 100644
--- a/src/trace_processor/core/plugin/plugin.h
+++ b/src/trace_processor/core/plugin/plugin.h
@@ -19,13 +19,14 @@
#include <array>
#include <cstddef>
+#include <cstdint>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
-#include "src/trace_processor/types/destructible.h"
+#include "src/trace_processor/core/util/type_set.h"
struct sqlite3_module;
@@ -37,7 +38,9 @@
class StaticTableFunction;
class TraceProcessorContext;
+class TraceReaderRegistry;
class TraceStorage;
+struct ProtoImporterModuleContext;
// Lightweight struct for plugin dataframe registration.
struct PluginDataframe {
@@ -94,173 +97,73 @@
// runtime ID via the address of a per-instantiation static member.
template <typename T>
struct PluginTag {
- static inline constexpr char kTag = 0;
+ static constexpr char kTag = 0;
static constexpr const void* Id() { return &kTag; }
};
-// Non-templated base class for type-erased storage and virtual dispatch.
+// Non-templated base class for plugins.
//
-// Plugins must NOT store mutable state on the plugin object itself. State
-// should either live in the Storage object (for data that persists beyond
-// parsing) or inside the parser/importer that the plugin creates.
+// The plugin IS the context: it carries its resolved dependency pointers and
+// a back-pointer to TraceProcessorContext. The framework sets these fields
+// after construction; lifecycle methods access them via `this`.
//
-// TraceProcessorImpl calls these methods, passing both the context and the
-// type-erased storage pointer. Subclasses should not override these directly;
-// instead, override the typed methods on Plugin<>.
+// How the plugin organizes its internal state is an implementation detail.
+// Subclasses should not override the PluginBase virtuals directly; instead,
+// inherit from Plugin<> which provides identity and typed dep access.
class PluginBase {
public:
virtual ~PluginBase();
- // Creates the plugin's opaque storage. Called once by TraceProcessorImpl;
- // the returned pointer is owned by TraceStorage and passed back into
- // all subsequent lifecycle methods.
- virtual std::unique_ptr<Destructible> CreateStorage(
- TraceProcessorContext* context);
+ // Identity and dependency accessors for the framework.
+ virtual const void* GetPluginId() const = 0;
+ virtual const void* const* GetDepIds() const = 0;
+ virtual size_t GetDepCount() const = 0;
- virtual void RegisterImporters(TraceProcessorContext* context,
- Destructible* storage);
- virtual void RegisterDataframes(TraceProcessorContext* context,
- Destructible* storage,
- std::vector<PluginDataframe>& tables);
+ virtual void RegisterImporters(TraceReaderRegistry& registry);
+ virtual void RegisterProtoImporterModules(
+ ProtoImporterModuleContext* module_context);
+ virtual void RegisterDataframes(std::vector<PluginDataframe>& tables);
virtual void RegisterStaticTableFunctions(
- TraceProcessorContext* context,
- Destructible* storage,
std::vector<std::unique_ptr<StaticTableFunction>>& fns);
virtual void RegisterSqliteModules(
- TraceProcessorContext* context,
- Destructible* storage,
std::vector<SqliteModuleRegistration>& modules);
- // Allows plugins to contribute SQL modules to the stdlib. Each entry is a
- // pair of (module_key, sql_content) where module_key follows the stdlib
- // naming convention (e.g., "etm.decode").
- virtual void RegisterSqlModules(
- TraceProcessorContext* context,
- Destructible* storage,
- std::vector<std::pair<std::string, std::string>>& modules);
+
+ virtual uint64_t GetBoundsMutationCount();
+ virtual std::pair<int64_t, int64_t> GetTimestampBounds();
+
+ // --- Framework-managed fields. Set by TraceProcessorImpl after creation. ---
+ TraceProcessorContext* trace_context_ = nullptr;
+ std::vector<PluginBase*> resolved_deps_;
};
-// Templated subclass that provides identity, dependency tracking, and typed
-// storage dispatch.
+// Templated subclass that provides identity, dependency tracking, typed
+// dependency access, and typed factory wrappers for lifecycle methods.
//
// Self: CRTP parameter (the concrete plugin class).
-// Storage: plugin-owned state type, must inherit from Destructible.
-// Use void (or omit) if no storage is needed.
-// Deps: prerequisite plugin classes.
+// Deps: prerequisite plugin classes. Declares the dependency graph for
+// topological sorting. Access deps at runtime via dependency<T>().
//
// The template parameters serve three purposes:
// 1. Compile-time: forces #include of dep headers -> forces GN dep
// 2. Link-time: if dep's .cc isn't compiled, GN dep missing -> build fails
// 3. Runtime: topological sort verifies all deps are registered
-template <typename Self, typename Storage = void, typename... Deps>
+template <typename Self, typename... Deps>
class Plugin : public PluginBase {
public:
static constexpr const void* kPluginId = PluginTag<Self>::Id();
static constexpr std::array<const void*, sizeof...(Deps)> kDepIds = {
PluginTag<Deps>::Id()...};
- // Override these in the concrete plugin class.
- virtual std::unique_ptr<Storage> CreatePluginStorage(TraceProcessorContext*) {
- return nullptr;
- }
- virtual void RegisterImporters(TraceProcessorContext*, Storage*) {}
- virtual void RegisterDataframes(TraceProcessorContext*,
- Storage*,
- std::vector<PluginDataframe>&) {}
- virtual void RegisterStaticTableFunctions(
- TraceProcessorContext*,
- Storage*,
- std::vector<std::unique_ptr<StaticTableFunction>>&) {}
- virtual void RegisterSqliteModules(TraceProcessorContext*,
- Storage*,
- std::vector<SqliteModuleRegistration>&) {}
- virtual void RegisterSqlModules(
- TraceProcessorContext*,
- Storage*,
- std::vector<std::pair<std::string, std::string>>&) {}
+ const void* GetPluginId() const final { return kPluginId; }
+ const void* const* GetDepIds() const final { return kDepIds.data(); }
+ size_t GetDepCount() const final { return kDepIds.size(); }
- private:
- std::unique_ptr<Destructible> CreateStorage(
- TraceProcessorContext* ctx) final {
- return static_cast<Self*>(this)->CreatePluginStorage(ctx);
- }
- void RegisterImporters(TraceProcessorContext* ctx, Destructible* s) final {
- static_cast<Self*>(this)->RegisterImporters(ctx, static_cast<Storage*>(s));
- }
- void RegisterDataframes(TraceProcessorContext* ctx,
- Destructible* s,
- std::vector<PluginDataframe>& tables) final {
- static_cast<Self*>(this)->RegisterDataframes(ctx, static_cast<Storage*>(s),
- tables);
- }
- void RegisterStaticTableFunctions(
- TraceProcessorContext* ctx,
- Destructible* s,
- std::vector<std::unique_ptr<StaticTableFunction>>& fns) final {
- static_cast<Self*>(this)->RegisterStaticTableFunctions(
- ctx, static_cast<Storage*>(s), fns);
- }
- void RegisterSqliteModules(
- TraceProcessorContext* ctx,
- Destructible* s,
- std::vector<SqliteModuleRegistration>& modules) final {
- static_cast<Self*>(this)->RegisterSqliteModules(
- ctx, static_cast<Storage*>(s), modules);
- }
- void RegisterSqlModules(
- TraceProcessorContext* ctx,
- Destructible* s,
- std::vector<std::pair<std::string, std::string>>& modules) final {
- static_cast<Self*>(this)->RegisterSqlModules(ctx, static_cast<Storage*>(s),
- modules);
- }
-};
-
-// Specialization for plugins with no storage.
-template <typename Self, typename... Deps>
-class Plugin<Self, void, Deps...> : public PluginBase {
- public:
- static constexpr const void* kPluginId = PluginTag<Self>::Id();
- static constexpr std::array<const void*, sizeof...(Deps)> kDepIds = {
- PluginTag<Deps>::Id()...};
-
- virtual void RegisterImporters(TraceProcessorContext*) {}
- virtual void RegisterDataframes(TraceProcessorContext*,
- std::vector<PluginDataframe>&) {}
- virtual void RegisterStaticTableFunctions(
- TraceProcessorContext*,
- std::vector<std::unique_ptr<StaticTableFunction>>&) {}
- virtual void RegisterSqliteModules(TraceProcessorContext*,
- std::vector<SqliteModuleRegistration>&) {}
- virtual void RegisterSqlModules(
- TraceProcessorContext*,
- std::vector<std::pair<std::string, std::string>>&) {}
-
- private:
- void RegisterImporters(TraceProcessorContext* ctx, Destructible*) final {
- static_cast<Self*>(this)->RegisterImporters(ctx);
- }
- void RegisterDataframes(TraceProcessorContext* ctx,
- Destructible*,
- std::vector<PluginDataframe>& tables) final {
- static_cast<Self*>(this)->RegisterDataframes(ctx, tables);
- }
- void RegisterStaticTableFunctions(
- TraceProcessorContext* ctx,
- Destructible*,
- std::vector<std::unique_ptr<StaticTableFunction>>& fns) final {
- static_cast<Self*>(this)->RegisterStaticTableFunctions(ctx, fns);
- }
- void RegisterSqliteModules(
- TraceProcessorContext* ctx,
- Destructible*,
- std::vector<SqliteModuleRegistration>& modules) final {
- static_cast<Self*>(this)->RegisterSqliteModules(ctx, modules);
- }
- void RegisterSqlModules(
- TraceProcessorContext* ctx,
- Destructible*,
- std::vector<std::pair<std::string, std::string>>& modules) final {
- static_cast<Self*>(this)->RegisterSqlModules(ctx, modules);
+ // Returns a dependency plugin by type. T must be one of the Deps.
+ // The index is resolved at compile time from the parameter pack position.
+ template <typename T>
+ T* dependency() {
+ return static_cast<T*>(
+ resolved_deps_[core::TypeSet<Deps...>::template GetTypeIndex<T>()]);
}
};
@@ -280,11 +183,21 @@
size_t n_deps);
};
-PluginRegistration* GetPluginRegistrations();
+// The result of topological sorting: plugin factories in dependency order
+// with pre-resolved dep indices. Computed once (statically) and shared by
+// all TraceProcessorImpl instances.
+struct PluginSet {
+ struct Entry {
+ PluginRegistration::Factory factory;
+ // Indices into the PluginSet::entries vector for this plugin's deps.
+ std::vector<size_t> dep_indices;
+ };
+ std::vector<Entry> entries;
+};
-// Collects all registered plugins, topologically sorts them by dependencies,
-// and instantiates them in order.
-std::vector<std::unique_ptr<PluginBase>> CreatePlugins();
+// Returns the singleton PluginSet. The topological sort and dep resolution
+// happen once on first call; subsequent calls return the cached result.
+const PluginSet& GetPluginSet();
// Suppresses -Wglobal-constructors which is Clang-specific. GCC and MSVC
// do not have this warning so the macros are no-ops on those compilers.
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index d7359c2..7383b82 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -510,13 +510,26 @@
TraceProcessorImpl::TraceProcessorImpl(const Config& cfg)
: TraceProcessorStorageImpl(cfg), config_(cfg) {
- // Initialize plugins: create instances, allocate storage, register importers.
- for (auto& p : CreatePlugins()) {
- PluginEntry entry;
- entry.storage = p->CreateStorage(context());
- entry.plugin = std::move(p);
- entry.plugin->RegisterImporters(context(), entry.storage.get());
- plugins_.push_back(std::move(entry));
+ // Initialize plugins using the statically pre-computed PluginSet.
+ // Dep indices are resolved once at static init time; here we just
+ // instantiate, resolve dep pointers, and register importers.
+ {
+ const PluginSet& pset = GetPluginSet();
+ plugins_.reserve(pset.entries.size());
+ for (const auto& pse : pset.entries) {
+ plugins_.push_back(pse.factory());
+ }
+ for (size_t i = 0; i < pset.entries.size(); ++i) {
+ auto& p = *plugins_[i];
+ p.trace_context_ = context();
+ for (size_t dep_idx : pset.entries[i].dep_indices) {
+ p.resolved_deps_.push_back(plugins_[dep_idx].get());
+ }
+ }
+ // Let plugins register trace readers and proto importer modules.
+ for (auto& p : plugins_) {
+ p->RegisterImporters(*context()->reader_registry);
+ }
}
context()->register_additional_proto_modules = &RegisterAdditionalModules;
@@ -722,16 +735,16 @@
// Also finalize plugin-owned tables.
{
std::vector<PluginDataframe> plugin_tables;
- for (const auto& e : plugins_) {
- e.plugin->RegisterDataframes(context(), e.storage.get(), plugin_tables);
+ for (auto& p : plugins_) {
+ p->RegisterDataframes(plugin_tables);
}
for (const auto& table : plugin_tables) {
table.dataframe->Finalize();
}
}
- // Stage 4: register plugin SQL modules and prepare the engine for queries.
- IncludeAfterEofPrelude(context(), engine_.get(), plugins_);
+ // Stage 4: prepare the engine for queries.
+ IncludeAfterEofPrelude(engine_.get());
sqlite_objects_post_prelude_ = engine_->SqliteRegisteredObjectCount();
return base::OkStatus();
@@ -1277,10 +1290,10 @@
std::vector<PerfettoSqlEngine::StaticTable> tables = GetStaticTables(storage);
std::vector<PluginDataframe> plugin_dataframes;
std::vector<SqliteModuleRegistration> sqlite_modules;
- for (const auto& e : plugins) {
- e.plugin->RegisterDataframes(context, e.storage.get(), plugin_dataframes);
- e.plugin->RegisterStaticTableFunctions(context, e.storage.get(), functions);
- e.plugin->RegisterSqliteModules(context, e.storage.get(), sqlite_modules);
+ for (auto& p : plugins) {
+ p->RegisterDataframes(plugin_dataframes);
+ p->RegisterStaticTableFunctions(functions);
+ p->RegisterSqliteModules(sqlite_modules);
}
for (auto& df : plugin_dataframes) {
tables.push_back({df.dataframe, std::move(df.name)});
@@ -1510,7 +1523,7 @@
}
if (notify_eof_called) {
- IncludeAfterEofPrelude(context, engine.get(), plugins);
+ IncludeAfterEofPrelude(engine.get());
}
for (const auto& metric : sql_metrics) {
@@ -1522,30 +1535,7 @@
return engine;
}
-void TraceProcessorImpl::IncludeAfterEofPrelude(
- TraceProcessorContext* context,
- PerfettoSqlEngine* engine,
- const std::vector<PluginEntry>& plugins) {
- // Collect SQL modules from plugins and merge them into existing packages
- // (or create new ones).
- std::vector<std::pair<std::string, std::string>> plugin_modules;
- for (const auto& e : plugins) {
- e.plugin->RegisterSqlModules(context, e.storage.get(), plugin_modules);
- }
- for (auto& mod : plugin_modules) {
- std::string pkg_name = sql_modules::GetPackageName(mod.first);
- auto* existing = engine->FindPackage(pkg_name);
- if (existing) {
- existing->modules.Insert(mod.first,
- {std::move(mod.second), /*included=*/false});
- } else {
- sql_modules::RegisteredPackage new_pkg;
- new_pkg.modules.Insert(mod.first,
- {std::move(mod.second), /*included=*/false});
- engine->RegisterPackage(pkg_name, std::move(new_pkg));
- }
- }
-
+void TraceProcessorImpl::IncludeAfterEofPrelude(PerfettoSqlEngine* engine) {
auto result = engine->Execute(SqlSource::FromTraceProcessorImplementation(
"INCLUDE PERFETTO MODULE prelude.after_eof.*"));
if (!result.status().ok()) {
diff --git a/src/trace_processor/trace_processor_impl.h b/src/trace_processor/trace_processor_impl.h
index e178c44..2b61a93 100644
--- a/src/trace_processor/trace_processor_impl.h
+++ b/src/trace_processor/trace_processor_impl.h
@@ -43,7 +43,6 @@
#include "src/trace_processor/perfetto_sql/intrinsics/table_functions/static_table_function.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/trace_processor_storage_impl.h"
-#include "src/trace_processor/types/destructible.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "src/trace_processor/util/descriptors.h"
@@ -143,11 +142,6 @@
// Needed for iterators to be able to access the context.
friend class IteratorImpl;
- struct PluginEntry {
- std::unique_ptr<PluginBase> plugin;
- std::unique_ptr<Destructible> storage;
- };
-
bool IsRootMetricField(const std::string& metric_name);
void CacheBoundsAndBuildTable();
@@ -163,7 +157,7 @@
TraceProcessor* trace_processor;
bool notify_eof_called;
std::pair<int64_t, int64_t> cached_trace_bounds;
- const std::vector<PluginEntry>& plugins;
+ std::vector<std::unique_ptr<PluginBase>>& plugins;
};
static std::unique_ptr<PerfettoSqlEngine> InitPerfettoSqlEngine(
@@ -178,14 +172,12 @@
const Config& config,
PerfettoSqlEngine* engine);
- static void IncludeAfterEofPrelude(TraceProcessorContext*,
- PerfettoSqlEngine*,
- const std::vector<PluginEntry>& plugins);
+ static void IncludeAfterEofPrelude(PerfettoSqlEngine*);
const Config config_;
// Registered plugins, topologically sorted by dependency order.
- std::vector<PluginEntry> plugins_;
+ std::vector<std::unique_ptr<PluginBase>> plugins_;
std::unique_ptr<PerfettoSqlEngine> engine_;
diff --git a/src/trace_processor/trace_reader_registry.h b/src/trace_processor/trace_reader_registry.h
index 34039df..9a61713 100644
--- a/src/trace_processor/trace_reader_registry.h
+++ b/src/trace_processor/trace_reader_registry.h
@@ -19,6 +19,7 @@
#include <functional>
#include <memory>
+#include <utility>
#include "perfetto/ext/base/flat_hash_map.h"
#include "perfetto/ext/base/status_or.h"
@@ -45,6 +46,16 @@
});
}
+ // Registers a trace reader factory that captures its own state (e.g. a
+ // plugin's `this` pointer). The TraceProcessorContext* passed at creation
+ // time is ignored by the wrapper.
+ void RegisterPluginTraceReader(
+ TraceType trace_type,
+ std::function<std::unique_ptr<ChunkedTraceReader>()> factory) {
+ RegisterFactory(trace_type, [f = std::move(factory)](
+ TraceProcessorContext*) { return f(); });
+ }
+
// Creates a new `ChunkedTraceReader` instance for the given `type`. Returns
// an error if no mapping has been previously registered.
base::StatusOr<std::unique_ptr<ChunkedTraceReader>> CreateTraceReader(