summaryrefslogtreecommitdiff
path: root/src/tracing/agent.cc
diff options
context:
space:
mode:
authorEugene Ostroukhov <eostroukhov@google.com>2018-04-27 17:20:37 -0700
committerEugene Ostroukhov <eostroukhov@google.com>2018-05-17 13:14:26 -0700
commit47bdc716f83462b6ab938315d11de6c92be082ac (patch)
tree8bdfd8c487cdcfb4e5b573b24d7809d053c675a6 /src/tracing/agent.cc
parent5248401174ff1ec02f5e1a247a97594341bbfd89 (diff)
downloadandroid-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.cc153
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