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