/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/tracing/agent_perfetto.h
145 строк
5 KB
Chengzhong Wu
src: add perfetto trace agent
24 июл 2026, 17:00
24 июл 2026, 17:00
5bdc82d
Код
Авторство
О чём код?
#ifndef SRC_TRACING_AGENT_PERFETTO_H_ #define SRC_TRACING_AGENT_PERFETTO_H_ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "node_mutex.h" #include "tracing/agent.h" #include "tracing/trace_event_perfetto.h" #include "util.h" #include "uv.h" #include "v8-platform.h" #include <list> #include <set> #include <string> #include <unordered_map> namespace node::tracing { // Consumes trace data produced by a PerfettoSessionReader. All methods run on // the agent's dedicated background tracing thread (the loop passed to // InitializeOnThread), never on the application's main thread or Perfetto's // internal thread, so implementations may block (e.g. do synchronous I/O). class TraceWriter { public: virtual ~TraceWriter() = default; // 'chunk' is guaranteed to contain 1 or more full trace packets, which // can be decoded using trace.proto. No partial or truncated packets are // exposed. virtual void AppendTraceChunk(std::vector<char> chunk) = 0; virtual void Flush(bool blocking) = 0; virtual void InitializeOnThread(uv_loop_t* loop) {} }; // Owns one Perfetto tracing session and pumps its trace data out to a // TraceWriter using the consumer ReadTrace() API, reading on a fixed period. // // Threading: two threads are involved. // - Perfetto's internal thread invokes ReadTraceCallback. It only copies the // borrowed chunk into pending_chunks_ (under chunks_mutex_) and signals // read_async_; it never touches the writer or the file. // - The agent's dedicated tracing loop thread runs everything else. A // repeating timer (read_timer_) starts a read every kReadPeriodMs, and // OnReadAsync drains pending_chunks_ into the writer there. This is why the // writer can safely block on synchronous I/O (see TraceWriter). // read_in_progress_ prevents a timer tick from starting a new read while a // previous ReadTrace() cycle is still delivering chunks. class PerfettoSessionReader final { public: struct Deleter { void operator()(PerfettoSessionReader* ptr) const noexcept; }; using Ptr = std::unique_ptr<PerfettoSessionReader, Deleter>; static Ptr Create(perfetto::TraceConfig config, std::unique_ptr<TraceWriter> writer) { return Ptr(new PerfettoSessionReader(config, std::move(writer))); } void ChangeTraceConfig(perfetto::TraceConfig config); void InitializeOnThread(uv_loop_t* loop); private: explicit PerfettoSessionReader(perfetto::TraceConfig config, std::unique_ptr<TraceWriter> writer); ~PerfettoSessionReader(); void ReadTraceCallback(perfetto::TracingSession::ReadTraceCallbackArgs args); void SessionStopCallback(); void Read(); static void OnReadAsync(uv_async_t* async); static void OnReadTimer(uv_timer_t* timer); static void OnHandleClose(uv_handle_t* handle); uv_loop_t* tracing_loop_; uv_async_t read_async_; uv_timer_t read_timer_; int handles_pending_close_ = 0; std::atomic<bool> stop_requested_ = false; std::atomic<bool> read_in_progress_ = false; Mutex chunks_mutex_; std::list<std::vector<char>> pending_chunks_; std::unique_ptr<perfetto::TracingSession> tracing_session_ = nullptr; std::unique_ptr<TraceWriter> writer_; }; class PerfettoTracingAgent final : public Agent { public: enum UseDefaultCategoryMode { kUseDefaultCategories, kIgnoreDefaultCategories }; PerfettoTracingAgent(); ~PerfettoTracingAgent() override; v8::TracingController* GetTracingController() override { return nullptr; } AgentWriterHandle AddClient(const std::set<std::string>& categories, std::unique_ptr<TraceWriter> writer, enum UseDefaultCategoryMode mode); std::string GetEnabledCategories() const override; void StartTracing(const std::string& categories) override; void StopTracing() override; AgentWriterHandle* GetDefaultWriterHandle() override; private: static constexpr int kDefaultHandleId = -1; void Disconnect(int client) override; void Enable(int id, const std::set<std::string>& categories) override; void Disable(int id, const std::set<std::string>& categories) override; void InitializeWritersOnThread(); void Start(); perfetto::TraceConfig CreateTraceConfig( std::multiset<std::string> categories) const; uv_thread_t thread_; uv_loop_t tracing_loop_; bool started_ = false; int next_writer_id_ = 1; std::unordered_map<int, std::multiset<std::string>> categories_; std::unordered_map<int, PerfettoSessionReader::Ptr> writers_; Mutex initialize_writer_mutex_; ConditionVariable initialize_writer_condvar_; uv_async_t initialize_writer_async_; std::set<PerfettoSessionReader*> to_be_initialized_; std::optional<AgentWriterHandle> tracing_file_writer_; }; } // namespace node::tracing #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #endif // SRC_TRACING_AGENT_PERFETTO_H_