• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef SRC_NODE_V8_PLATFORM_INL_H_
2 #define SRC_NODE_V8_PLATFORM_INL_H_
3 
4 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5 
6 #include <memory>
7 
8 #include "env-inl.h"
9 #include "node.h"
10 #include "node_metadata.h"
11 #include "node_platform.h"
12 #include "node_options.h"
13 #include "tracing/node_trace_writer.h"
14 #include "tracing/trace_event.h"
15 #include "tracing/traced_value.h"
16 #include "util.h"
17 
18 namespace node {
19 
20 // Ensures that __metadata trace events are only emitted
21 // when tracing is enabled.
22 class NodeTraceStateObserver
23     : public v8::TracingController::TraceStateObserver {
24  public:
OnTraceEnabled()25   inline void OnTraceEnabled() override {
26     std::string title = GetProcessTitle("");
27     if (!title.empty()) {
28       // Only emit the metadata event if the title can be retrieved
29       // successfully. Ignore it otherwise.
30       TRACE_EVENT_METADATA1(
31           "__metadata", "process_name", "name", TRACE_STR_COPY(title.c_str()));
32     }
33     TRACE_EVENT_METADATA1("__metadata",
34                           "version",
35                           "node",
36                           per_process::metadata.versions.node.c_str());
37     TRACE_EVENT_METADATA1(
38         "__metadata", "thread_name", "name", "JavaScriptMainThread");
39 
40     auto trace_process = tracing::TracedValue::Create();
41     trace_process->BeginDictionary("versions");
42 
43 #define V(key)                                                                 \
44   trace_process->SetString(#key, per_process::metadata.versions.key.c_str());
45 
46     NODE_VERSIONS_KEYS(V)
47 #undef V
48 
49     trace_process->EndDictionary();
50 
51     trace_process->SetString("arch", per_process::metadata.arch.c_str());
52     trace_process->SetString("platform",
53                              per_process::metadata.platform.c_str());
54 
55     trace_process->BeginDictionary("release");
56     trace_process->SetString("name",
57                              per_process::metadata.release.name.c_str());
58 #if NODE_VERSION_IS_LTS
59     trace_process->SetString("lts", per_process::metadata.release.lts.c_str());
60 #endif
61     trace_process->EndDictionary();
62     TRACE_EVENT_METADATA1(
63         "__metadata", "node", "process", std::move(trace_process));
64 
65     // This only runs the first time tracing is enabled
66     controller_->RemoveTraceStateObserver(this);
67   }
68 
OnTraceDisabled()69   inline void OnTraceDisabled() override {
70     // Do nothing here. This should never be called because the
71     // observer removes itself when OnTraceEnabled() is called.
72     UNREACHABLE();
73   }
74 
NodeTraceStateObserver(v8::TracingController * controller)75   explicit NodeTraceStateObserver(v8::TracingController* controller)
76       : controller_(controller) {}
77   ~NodeTraceStateObserver() override = default;
78 
79  private:
80   v8::TracingController* controller_;
81 };
82 
83 struct V8Platform {
84   bool initialized_ = false;
85 
86 #if NODE_USE_V8_PLATFORM
InitializeV8Platform87   inline void Initialize(int thread_pool_size) {
88     CHECK(!initialized_);
89     initialized_ = true;
90     tracing_agent_ = std::make_unique<tracing::Agent>();
91     node::tracing::TraceEventHelper::SetAgent(tracing_agent_.get());
92     node::tracing::TracingController* controller =
93         tracing_agent_->GetTracingController();
94     trace_state_observer_ =
95         std::make_unique<NodeTraceStateObserver>(controller);
96     controller->AddTraceStateObserver(trace_state_observer_.get());
97     tracing_file_writer_ = tracing_agent_->DefaultHandle();
98     // Only start the tracing agent if we enabled any tracing categories.
99     if (!per_process::cli_options->trace_event_categories.empty()) {
100       StartTracingAgent();
101     }
102     // Tracing must be initialized before platform threads are created.
103     platform_ = new NodePlatform(thread_pool_size, controller);
104     v8::V8::InitializePlatform(platform_);
105   }
106 
DisposeV8Platform107   inline void Dispose() {
108     if (!initialized_)
109       return;
110     initialized_ = false;
111 
112     StopTracingAgent();
113     platform_->Shutdown();
114     delete platform_;
115     platform_ = nullptr;
116     // Destroy tracing after the platform (and platform threads) have been
117     // stopped.
118     tracing_agent_.reset(nullptr);
119     trace_state_observer_.reset(nullptr);
120   }
121 
DrainVMTasksV8Platform122   inline void DrainVMTasks(v8::Isolate* isolate) {
123     platform_->DrainTasks(isolate);
124   }
125 
StartTracingAgentV8Platform126   inline void StartTracingAgent() {
127     // Attach a new NodeTraceWriter only if this function hasn't been called
128     // before.
129     if (tracing_file_writer_.IsDefaultHandle()) {
130       std::vector<std::string> categories =
131           SplitString(per_process::cli_options->trace_event_categories, ',');
132 
133       tracing_file_writer_ = tracing_agent_->AddClient(
134           std::set<std::string>(std::make_move_iterator(categories.begin()),
135                                 std::make_move_iterator(categories.end())),
136           std::unique_ptr<tracing::AsyncTraceWriter>(
137               new tracing::NodeTraceWriter(
138                   per_process::cli_options->trace_event_file_pattern)),
139           tracing::Agent::kUseDefaultCategories);
140     }
141   }
142 
StopTracingAgentV8Platform143   inline void StopTracingAgent() { tracing_file_writer_.reset(); }
144 
GetTracingAgentWriterV8Platform145   inline tracing::AgentWriterHandle* GetTracingAgentWriter() {
146     return &tracing_file_writer_;
147   }
148 
PlatformV8Platform149   inline NodePlatform* Platform() { return platform_; }
150 
151   std::unique_ptr<NodeTraceStateObserver> trace_state_observer_;
152   std::unique_ptr<tracing::Agent> tracing_agent_;
153   tracing::AgentWriterHandle tracing_file_writer_;
154   NodePlatform* platform_;
155 #else   // !NODE_USE_V8_PLATFORM
InitializeV8Platform156   inline void Initialize(int thread_pool_size) {}
DisposeV8Platform157   inline void Dispose() {}
DrainVMTasksV8Platform158   inline void DrainVMTasks(v8::Isolate* isolate) {}
StartTracingAgentV8Platform159   inline void StartTracingAgent() {
160     if (!per_process::cli_options->trace_event_categories.empty()) {
161       fprintf(stderr,
162               "Node compiled with NODE_USE_V8_PLATFORM=0, "
163               "so event tracing is not available.\n");
164     }
165   }
StopTracingAgentV8Platform166   inline void StopTracingAgent() {}
167 
GetTracingAgentWriterV8Platform168   inline tracing::AgentWriterHandle* GetTracingAgentWriter() { return nullptr; }
169 
PlatformV8Platform170   inline NodePlatform* Platform() { return nullptr; }
171 #endif  // !NODE_USE_V8_PLATFORM
172 };
173 
174 namespace per_process {
175 extern struct V8Platform v8_platform;
176 }
177 
StartTracingAgent()178 inline void StartTracingAgent() {
179   return per_process::v8_platform.StartTracingAgent();
180 }
181 
GetTracingAgentWriter()182 inline tracing::AgentWriterHandle* GetTracingAgentWriter() {
183   return per_process::v8_platform.GetTracingAgentWriter();
184 }
185 
DisposePlatform()186 inline void DisposePlatform() {
187   per_process::v8_platform.Dispose();
188 }
189 
190 }  // namespace node
191 
192 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
193 
194 #endif  // SRC_NODE_V8_PLATFORM_INL_H_
195