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 #include <string_view>
8
9 #include "env-inl.h"
10 #include "node.h"
11 #include "node_metadata.h"
12 #include "node_platform.h"
13 #include "node_options.h"
14 #include "tracing/node_trace_writer.h"
15 #include "tracing/trace_event.h"
16 #include "tracing/traced_value.h"
17 #include "util.h"
18
19 namespace node {
20
21 // Ensures that __metadata trace events are only emitted
22 // when tracing is enabled.
23 class NodeTraceStateObserver
24 : public v8::TracingController::TraceStateObserver {
25 public:
OnTraceEnabled()26 inline void OnTraceEnabled() override {
27 std::string title = GetProcessTitle("");
28 if (!title.empty()) {
29 // Only emit the metadata event if the title can be retrieved
30 // successfully. Ignore it otherwise.
31 TRACE_EVENT_METADATA1(
32 "__metadata", "process_name", "name", TRACE_STR_COPY(title.c_str()));
33 }
34 TRACE_EVENT_METADATA1("__metadata",
35 "version",
36 "node",
37 per_process::metadata.versions.node.c_str());
38 TRACE_EVENT_METADATA1(
39 "__metadata", "thread_name", "name", "JavaScriptMainThread");
40
41 auto trace_process = tracing::TracedValue::Create();
42 trace_process->BeginDictionary("versions");
43
44 #define V(key) \
45 trace_process->SetString(#key, per_process::metadata.versions.key.c_str());
46
47 NODE_VERSIONS_KEYS(V)
48 #undef V
49
50 trace_process->EndDictionary();
51
52 trace_process->SetString("arch", per_process::metadata.arch.c_str());
53 trace_process->SetString("platform",
54 per_process::metadata.platform.c_str());
55
56 trace_process->BeginDictionary("release");
57 trace_process->SetString("name",
58 per_process::metadata.release.name.c_str());
59 #if NODE_VERSION_IS_LTS
60 trace_process->SetString("lts", per_process::metadata.release.lts.c_str());
61 #endif
62 trace_process->EndDictionary();
63 TRACE_EVENT_METADATA1(
64 "__metadata", "node", "process", std::move(trace_process));
65
66 // This only runs the first time tracing is enabled
67 controller_->RemoveTraceStateObserver(this);
68 }
69
OnTraceDisabled()70 inline void OnTraceDisabled() override {
71 // Do nothing here. This should never be called because the
72 // observer removes itself when OnTraceEnabled() is called.
73 UNREACHABLE();
74 }
75
NodeTraceStateObserver(v8::TracingController * controller)76 explicit NodeTraceStateObserver(v8::TracingController* controller)
77 : controller_(controller) {}
78 ~NodeTraceStateObserver() override = default;
79
80 private:
81 v8::TracingController* controller_;
82 };
83
84 struct V8Platform {
85 bool initialized_ = false;
86
87 #if NODE_USE_V8_PLATFORM
InitializeV8Platform88 inline void Initialize(int thread_pool_size) {
89 CHECK(!initialized_);
90 initialized_ = true;
91 tracing_agent_ = std::make_unique<tracing::Agent>();
92 node::tracing::TraceEventHelper::SetAgent(tracing_agent_.get());
93 node::tracing::TracingController* controller =
94 tracing_agent_->GetTracingController();
95 trace_state_observer_ =
96 std::make_unique<NodeTraceStateObserver>(controller);
97 controller->AddTraceStateObserver(trace_state_observer_.get());
98 tracing_file_writer_ = tracing_agent_->DefaultHandle();
99 // Only start the tracing agent if we enabled any tracing categories.
100 if (!per_process::cli_options->trace_event_categories.empty()) {
101 StartTracingAgent();
102 }
103 // Tracing must be initialized before platform threads are created.
104 platform_ = new NodePlatform(thread_pool_size, controller);
105 v8::V8::InitializePlatform(platform_);
106 }
107 // Make sure V8Platform don not call into Libuv threadpool,
108 // see DefaultProcessExitHandlerInternal in environment.cc
DisposeV8Platform109 inline void Dispose() {
110 if (!initialized_)
111 return;
112 initialized_ = false;
113 node::tracing::TraceEventHelper::SetAgent(nullptr);
114 StopTracingAgent();
115 platform_->Shutdown();
116 delete platform_;
117 platform_ = nullptr;
118 // Destroy tracing after the platform (and platform threads) have been
119 // stopped.
120 tracing_agent_.reset(nullptr);
121 // The observer remove itself in OnTraceEnabled
122 trace_state_observer_.reset(nullptr);
123 }
124
DrainVMTasksV8Platform125 inline void DrainVMTasks(v8::Isolate* isolate) {
126 platform_->DrainTasks(isolate);
127 }
128
StartTracingAgentV8Platform129 inline void StartTracingAgent() {
130 constexpr auto convert_to_set =
131 [](std::vector<std::string_view> categories) -> std::set<std::string> {
132 std::set<std::string> out;
133 for (const auto& s : categories) {
134 out.emplace(s);
135 }
136 return out;
137 };
138 // Attach a new NodeTraceWriter only if this function hasn't been called
139 // before.
140 if (tracing_file_writer_.IsDefaultHandle()) {
141 using std::string_view_literals::operator""sv;
142 const std::vector<std::string_view> categories =
143 SplitString(per_process::cli_options->trace_event_categories, ","sv);
144
145 tracing_file_writer_ = tracing_agent_->AddClient(
146 convert_to_set(categories),
147 std::unique_ptr<tracing::AsyncTraceWriter>(
148 new tracing::NodeTraceWriter(
149 per_process::cli_options->trace_event_file_pattern)),
150 tracing::Agent::kUseDefaultCategories);
151 }
152 }
153
StopTracingAgentV8Platform154 inline void StopTracingAgent() { tracing_file_writer_.reset(); }
155
GetTracingAgentWriterV8Platform156 inline tracing::AgentWriterHandle* GetTracingAgentWriter() {
157 return &tracing_file_writer_;
158 }
159
PlatformV8Platform160 inline NodePlatform* Platform() { return platform_; }
161
162 std::unique_ptr<NodeTraceStateObserver> trace_state_observer_;
163 std::unique_ptr<tracing::Agent> tracing_agent_;
164 tracing::AgentWriterHandle tracing_file_writer_;
165 NodePlatform* platform_;
166 #else // !NODE_USE_V8_PLATFORM
InitializeV8Platform167 inline void Initialize(int thread_pool_size) {}
DisposeV8Platform168 inline void Dispose() {}
DrainVMTasksV8Platform169 inline void DrainVMTasks(v8::Isolate* isolate) {}
StartTracingAgentV8Platform170 inline void StartTracingAgent() {
171 if (!per_process::cli_options->trace_event_categories.empty()) {
172 fprintf(stderr,
173 "Node compiled with NODE_USE_V8_PLATFORM=0, "
174 "so event tracing is not available.\n");
175 }
176 }
StopTracingAgentV8Platform177 inline void StopTracingAgent() {}
178
GetTracingAgentWriterV8Platform179 inline tracing::AgentWriterHandle* GetTracingAgentWriter() { return nullptr; }
180
PlatformV8Platform181 inline NodePlatform* Platform() { return nullptr; }
182 #endif // !NODE_USE_V8_PLATFORM
183 };
184
185 namespace per_process {
186 extern struct V8Platform v8_platform;
187 }
188
StartTracingAgent()189 inline void StartTracingAgent() {
190 return per_process::v8_platform.StartTracingAgent();
191 }
192
GetTracingAgentWriter()193 inline tracing::AgentWriterHandle* GetTracingAgentWriter() {
194 return per_process::v8_platform.GetTracingAgentWriter();
195 }
196
DisposePlatform()197 inline void DisposePlatform() {
198 per_process::v8_platform.Dispose();
199 }
200
201 } // namespace node
202
203 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
204
205 #endif // SRC_NODE_V8_PLATFORM_INL_H_
206