/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/tracing/agent_legacy.cc
320 строк
10 KB
Chengzhong Wu
src: abstract tracing agent for both legacy and perfetto
29 июн 2026, 16:57
Не верифицирован
29 июн 2026, 16:57
d95cbc2
Код
Авторство
О чём код?
#include "tracing/agent_legacy.h" #include <ranges> #include <string> #include <string_view> #include "debug_utils-inl.h" #include "env-inl.h" #include "node_metadata.h" #include "node_options.h" #include "trace_event.h" #include "tracing/node_trace_buffer.h" #include "tracing/node_trace_writer.h" #include "tracing/traced_value.h" namespace node { namespace tracing { class LegacyTracingAgent::ScopedSuspendTracing { public: ScopedSuspendTracing(TracingController* controller, LegacyTracingAgent* agent, bool do_suspend = true) : controller_(controller), agent_(do_suspend ? agent : nullptr) { if (do_suspend) { CHECK(agent_->started_); controller->StopTracing(); } } ~ScopedSuspendTracing() { if (agent_ == nullptr) return; TraceConfig* config = agent_->CreateTraceConfig(); if (config != nullptr) { controller_->StartTracing(config); } } private: TracingController* controller_; LegacyTracingAgent* agent_; }; namespace { std::set<std::string> flatten( const std::unordered_map<int, std::multiset<std::string>>& map) { std::set<std::string> result; for (const auto& id_value : map) result.insert(id_value.second.begin(), id_value.second.end()); return result; } } // namespace using std::string; using v8::platform::tracing::TraceConfig; using v8::platform::tracing::TraceWriter; void NodeTraceStateObserver::OnTraceEnabled() { std::string title = GetProcessTitle(""); if (!title.empty()) { TRACE_EVENT_METADATA1( "__metadata", "process_name", "name", TRACE_STR_COPY(title.c_str())); } TRACE_EVENT_METADATA1("__metadata", "version", "node", per_process::metadata.versions.node.c_str()); TRACE_EVENT_METADATA1( "__metadata", "thread_name", "name", "JavaScriptMainThread"); ProcessMeta trace_process; TRACE_EVENT_METADATA1( "__metadata", "node", "process", CastTracedValue(trace_process)); // This only runs the first time tracing is enabled controller_->RemoveTraceStateObserver(this); } LegacyTracingAgent::LegacyTracingAgent() : tracing_controller_(new TracingController()) { tracing_controller_->Initialize(nullptr); trace_state_observer_ = std::make_unique<NodeTraceStateObserver>(tracing_controller_.get()); tracing_controller_->AddTraceStateObserver(trace_state_observer_.get()); tracing_file_writer_ = AgentWriterHandle(this, kDefaultHandleId); CHECK_EQ(uv_loop_init(&tracing_loop_), 0); CHECK_EQ(uv_async_init(&tracing_loop_, &initialize_writer_async_, [](uv_async_t* async) { LegacyTracingAgent* agent = ContainerOf( &LegacyTracingAgent::initialize_writer_async_, async); agent->InitializeWritersOnThread(); }), 0); uv_unref(reinterpret_cast<uv_handle_t*>(&initialize_writer_async_)); } void LegacyTracingAgent::InitializeWritersOnThread() { Mutex::ScopedLock lock(initialize_writer_mutex_); while (!to_be_initialized_.empty()) { AsyncTraceWriter* head = *to_be_initialized_.begin(); head->InitializeOnThread(&tracing_loop_); to_be_initialized_.erase(head); } initialize_writer_condvar_.Broadcast(lock); } LegacyTracingAgent::~LegacyTracingAgent() { StopTracing(); categories_.clear(); writers_.clear(); Stop(); uv_close(reinterpret_cast<uv_handle_t*>(&initialize_writer_async_), nullptr); uv_run(&tracing_loop_, UV_RUN_ONCE); CheckedUvLoopClose(&tracing_loop_); } void LegacyTracingAgent::Start() { if (started_) return; NodeTraceBuffer* trace_buffer_ = new NodeTraceBuffer(NodeTraceBuffer::kBufferChunks, this, &tracing_loop_); tracing_controller_->Initialize(trace_buffer_); // This thread should be created *after* async handles are created // (within NodeTraceWriter and NodeTraceBuffer constructors). // Otherwise the thread could shut down prematurely. CHECK_EQ(0, uv_thread_create( &thread_, [](void* arg) { uv_thread_setname("TraceEventWorker"); LegacyTracingAgent* agent = static_cast<LegacyTracingAgent*>(arg); uv_run(&agent->tracing_loop_, UV_RUN_DEFAULT); }, this)); started_ = true; } AgentWriterHandle LegacyTracingAgent::AddClient( const std::set<std::string>& categories, std::unique_ptr<AsyncTraceWriter> writer, enum UseDefaultCategoryMode mode) { Start(); const std::set<std::string>* use_categories = &categories; std::set<std::string> categories_with_default; if (mode == kUseDefaultCategories) { categories_with_default.insert(categories.begin(), categories.end()); categories_with_default.insert(categories_[kDefaultHandleId].begin(), categories_[kDefaultHandleId].end()); use_categories = &categories_with_default; } ScopedSuspendTracing suspend(tracing_controller_.get(), this); int id = next_writer_id_++; AsyncTraceWriter* raw = writer.get(); writers_[id] = std::move(writer); categories_[id] = {use_categories->begin(), use_categories->end()}; { Mutex::ScopedLock lock(initialize_writer_mutex_); to_be_initialized_.insert(raw); uv_async_send(&initialize_writer_async_); while (to_be_initialized_.count(raw) > 0) initialize_writer_condvar_.Wait(lock); } return AgentWriterHandle(this, id); } void LegacyTracingAgent::Stop() { if (!started_) return; // Perform final Flush on TraceBuffer. We don't want the tracing controller // to flush the buffer again on destruction of the V8::Platform. tracing_controller_->StopTracing(); tracing_controller_->Initialize(nullptr); started_ = false; // Thread should finish when the tracing loop is stopped. uv_thread_join(&thread_); } void LegacyTracingAgent::Disconnect(int client) { if (client == kDefaultHandleId) return; { Mutex::ScopedLock lock(initialize_writer_mutex_); to_be_initialized_.erase(writers_[client].get()); } ScopedSuspendTracing suspend(tracing_controller_.get(), this); writers_.erase(client); categories_.erase(client); } void LegacyTracingAgent::Enable(int id, const std::set<std::string>& categories) { if (categories.empty()) return; ScopedSuspendTracing suspend( tracing_controller_.get(), this, id != kDefaultHandleId); categories_[id].insert(categories.begin(), categories.end()); } void LegacyTracingAgent::Disable(int id, const std::set<std::string>& categories) { ScopedSuspendTracing suspend( tracing_controller_.get(), this, id != kDefaultHandleId); std::multiset<std::string>& writer_categories = categories_[id]; for (const std::string& category : categories) { auto it = writer_categories.find(category); if (it != writer_categories.end()) writer_categories.erase(it); } } TraceConfig* LegacyTracingAgent::CreateTraceConfig() const { if (categories_.empty()) return nullptr; TraceConfig* trace_config = new TraceConfig(); for (const auto& category : flatten(categories_)) { trace_config->AddIncludedCategory(category.c_str()); } return trace_config; } std::string LegacyTracingAgent::GetEnabledCategories() const { std::string categories; for (const std::string& category : flatten(categories_)) { if (!categories.empty()) categories += ','; categories += category; } return categories; } void LegacyTracingAgent::AppendTraceEvent(TraceObject* trace_event) { for (const auto& id_writer : writers_) id_writer.second->AppendTraceEvent(trace_event); } void LegacyTracingAgent::AddMetadataEvent(std::unique_ptr<TraceObject> event) { Mutex::ScopedLock lock(metadata_events_mutex_); metadata_events_.push_back(std::move(event)); } void LegacyTracingAgent::Flush(bool blocking) { { Mutex::ScopedLock lock(metadata_events_mutex_); for (const auto& event : metadata_events_) AppendTraceEvent(event.get()); } for (const auto& id_writer : writers_) id_writer.second->Flush(blocking); } void LegacyTracingAgent::StartTracing(const std::string& categories) { // Attach a new NodeTraceWriter only if this function hasn't been called // before. if (tracing_file_writer_.id_ != LegacyTracingAgent::kDefaultHandleId) return; using std::operator""sv; auto parts = std::views::split(categories, ","sv); std::set<std::string> categories_set; for (const auto& s : parts) { categories_set.emplace(std::string(s.data(), s.size())); } tracing_file_writer_ = AddClient(categories_set, std::unique_ptr<AsyncTraceWriter>(new NodeTraceWriter( per_process::cli_options->trace_event_file_pattern)), kUseDefaultCategories); } void LegacyTracingAgent::StopTracing() { tracing_file_writer_.reset(); tracing_file_writer_ = AgentWriterHandle(this, kDefaultHandleId); } AgentWriterHandle* LegacyTracingAgent::GetDefaultWriterHandle() { return &tracing_file_writer_; } void TracingController::AddMetadataEvent( const unsigned char* category_group_enabled, const char* name, int num_args, const char** arg_names, const unsigned char* arg_types, const uint64_t* arg_values, std::unique_ptr<v8::ConvertableToTraceFormat>* convertable_values, unsigned int flags) { std::unique_ptr<TraceObject> trace_event(new TraceObject); trace_event->Initialize(TRACE_EVENT_PHASE_METADATA, category_group_enabled, name, node::tracing::kGlobalScope, // scope node::tracing::kNoId, // id node::tracing::kNoId, // bind_id num_args, arg_names, arg_types, arg_values, convertable_values, TRACE_EVENT_FLAG_NONE, CurrentTimestampMicroseconds(), CurrentCpuTimestampMicroseconds()); LegacyTracingAgent* node_agent = static_cast<LegacyTracingAgent*>(Agent::GetInstance()); if (node_agent != nullptr) node_agent->AddMetadataEvent(std::move(trace_event)); } } // namespace tracing } // namespace node