diff options
author | Eugene Ostroukhov <eostroukhov@google.com> | 2018-04-27 17:20:37 -0700 |
---|---|---|
committer | Eugene Ostroukhov <eostroukhov@google.com> | 2018-05-17 13:14:26 -0700 |
commit | 47bdc716f83462b6ab938315d11de6c92be082ac (patch) | |
tree | 8bdfd8c487cdcfb4e5b573b24d7809d053c675a6 /src/tracing/agent.cc | |
parent | 5248401174ff1ec02f5e1a247a97594341bbfd89 (diff) | |
download | android-node-v8-47bdc716f83462b6ab938315d11de6c92be082ac.tar.gz android-node-v8-47bdc716f83462b6ab938315d11de6c92be082ac.tar.bz2 android-node-v8-47bdc716f83462b6ab938315d11de6c92be082ac.zip |
inspector: add a "NodeTracing" domain support
This change adds a new inspector domain for receiving Node tracing
data.
1. Node.js now can extend Inspector protocol with new domains with
the API defined in the src/inspector/node_protocol.pdl.
2. Plumbing code will be generated at the build time. /json/protocol
HTTP endpoint returns both V8 and Node.js inspector protocol.
3. "NodeTracing" domain was introduced. It is based on the Chrome
"Tracing" domain.
PR-URL: https://github.com/nodejs/node/pull/20608
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Diffstat (limited to 'src/tracing/agent.cc')
-rw-r--r-- | src/tracing/agent.cc | 153 |
1 files changed, 107 insertions, 46 deletions
diff --git a/src/tracing/agent.cc b/src/tracing/agent.cc index cd4c3c0df9..a3ddfb61a9 100644 --- a/src/tracing/agent.cc +++ b/src/tracing/agent.cc @@ -8,11 +8,43 @@ namespace node { namespace tracing { +namespace { + +class ScopedSuspendTracing { + public: + ScopedSuspendTracing(TracingController* controller, Agent* agent) + : controller_(controller), agent_(agent) { + controller->StopTracing(); + } + + ~ScopedSuspendTracing() { + TraceConfig* config = agent_->CreateTraceConfig(); + if (config != nullptr) { + controller_->StartTracing(config); + } + } + + private: + TracingController* controller_; + Agent* agent_; +}; + +std::set<std::string> flatten( + const std::unordered_map<int, std::set<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 v8::platform::tracing::TraceConfig; +using v8::platform::tracing::TraceWriter; using std::string; Agent::Agent(const std::string& log_file_pattern) - : log_file_pattern_(log_file_pattern) { + : log_file_pattern_(log_file_pattern), file_writer_(EmptyClientHandle()) { tracing_controller_ = new TracingController(); tracing_controller_->Initialize(nullptr); } @@ -23,11 +55,9 @@ void Agent::Start() { CHECK_EQ(uv_loop_init(&tracing_loop_), 0); - NodeTraceWriter* trace_writer = - new NodeTraceWriter(log_file_pattern_, &tracing_loop_); - TraceBuffer* trace_buffer = new NodeTraceBuffer( - NodeTraceBuffer::kBufferChunks, trace_writer, &tracing_loop_); - tracing_controller_->Initialize(trace_buffer); + 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). @@ -36,7 +66,23 @@ void Agent::Start() { started_ = true; } +Agent::ClientHandle Agent::AddClient(const std::set<std::string>& categories, + std::unique_ptr<AsyncTraceWriter> writer) { + Start(); + ScopedSuspendTracing suspend(tracing_controller_, this); + int id = next_writer_id_++; + writers_[id] = std::move(writer); + categories_[id] = categories; + + auto client_id = new std::pair<Agent*, int>(this, id); + return ClientHandle(client_id, &DisconnectClient); +} + void Agent::Stop() { + file_writer_.reset(); +} + +void Agent::StopTracing() { if (!started_) return; // Perform final Flush on TraceBuffer. We don't want the tracing controller @@ -49,6 +95,12 @@ void Agent::Stop() { uv_thread_join(&thread_); } +void Agent::Disconnect(int client) { + ScopedSuspendTracing suspend(tracing_controller_, this); + writers_.erase(client); + categories_.erase(client); +} + // static void Agent::ThreadCb(void* arg) { Agent* agent = static_cast<Agent*>(arg); @@ -56,72 +108,81 @@ void Agent::ThreadCb(void* arg) { } void Agent::Enable(const std::string& categories) { - if (!categories.empty()) { - std::stringstream category_list(categories); - while (category_list.good()) { - std::string category; - getline(category_list, category, ','); - categories_.insert(category.c_str()); - } - RestartTracing(); + if (categories.empty()) + return; + std::set<std::string> categories_set; + std::stringstream category_list(categories); + while (category_list.good()) { + std::string category; + getline(category_list, category, ','); + categories_set.insert(category); } + Enable(categories_set); } void Agent::Enable(const std::set<std::string>& categories) { - if (!categories.empty()) { - categories_.insert(categories.begin(), categories.end()); - RestartTracing(); - } -} + std::string cats; + for (const std::string cat : categories) + cats += cat + ", "; + if (categories.empty()) + return; -void Agent::Disable(const std::set<std::string>& categories) { - if (!categories.empty()) { - for (auto category : categories) { - auto pos = categories_.lower_bound(category); - if (pos != categories_.end()) - categories_.erase(pos); - } - RestartTracing(); + file_writer_categories_.insert(categories.begin(), categories.end()); + std::set<std::string> full_list(file_writer_categories_.begin(), + file_writer_categories_.end()); + if (!file_writer_) { + // Ensure background thread is running + Start(); + std::unique_ptr<NodeTraceWriter> writer( + new NodeTraceWriter(log_file_pattern_, &tracing_loop_)); + file_writer_ = AddClient(full_list, std::move(writer)); + } else { + ScopedSuspendTracing suspend(tracing_controller_, this); + categories_[file_writer_->second] = full_list; } } -void Agent::RestartTracing() { - static bool warned; - if (!warned) { - warned = true; - fprintf(stderr, "Warning: Trace event is an experimental feature " - "and could change at any time.\n"); +void Agent::Disable(const std::set<std::string>& categories) { + for (auto category : categories) { + auto it = file_writer_categories_.find(category); + if (it != file_writer_categories_.end()) + file_writer_categories_.erase(it); } - Start(); // Start the agent if it hasn't already been started - tracing_controller_->StopTracing(); - auto config = CreateTraceConfig(); - if (config != nullptr) - tracing_controller_->StartTracing(config); + if (!file_writer_) + return; + ScopedSuspendTracing suspend(tracing_controller_, this); + categories_[file_writer_->second] = { file_writer_categories_.begin(), + file_writer_categories_.end() }; } TraceConfig* Agent::CreateTraceConfig() { if (categories_.empty()) return nullptr; TraceConfig* trace_config = new TraceConfig(); - for (auto category = categories_.begin(); - category != categories_.end(); - category = categories_.upper_bound(*category)) { - trace_config->AddIncludedCategory(category->c_str()); + for (const auto& category : flatten(categories_)) { + trace_config->AddIncludedCategory(category.c_str()); } return trace_config; } std::string Agent::GetEnabledCategories() { std::string categories; - for (auto category = categories_.begin(); - category != categories_.end(); - category = categories_.upper_bound(*category)) { + for (const auto& category : flatten(categories_)) { if (!categories.empty()) categories += ','; - categories += *category; + categories += category; } return categories; } +void Agent::AppendTraceEvent(TraceObject* trace_event) { + for (const auto& id_writer : writers_) + id_writer.second->AppendTraceEvent(trace_event); +} + +void Agent::Flush(bool blocking) { + for (const auto& id_writer : writers_) + id_writer.second->Flush(blocking); +} } // namespace tracing } // namespace node |