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: |
25 |
|
89 |
inline void OnTraceEnabled() override { |
26 |
|
178 |
std::string title = GetProcessTitle(""); |
27 |
✓✗ |
89 |
if (!title.empty()) { |
28 |
|
|
// Only emit the metadata event if the title can be retrieved |
29 |
|
|
// successfully. Ignore it otherwise. |
30 |
✓✗✓✗
|
267 |
TRACE_EVENT_METADATA1( |
31 |
|
|
"__metadata", "process_name", "name", TRACE_STR_COPY(title.c_str())); |
32 |
|
|
} |
33 |
✓✗✓✗
|
267 |
TRACE_EVENT_METADATA1("__metadata", |
34 |
|
|
"version", |
35 |
|
|
"node", |
36 |
|
|
per_process::metadata.versions.node.c_str()); |
37 |
✓✗✓✗
|
267 |
TRACE_EVENT_METADATA1( |
38 |
|
|
"__metadata", "thread_name", "name", "JavaScriptMainThread"); |
39 |
|
|
|
40 |
|
178 |
auto trace_process = tracing::TracedValue::Create(); |
41 |
|
89 |
trace_process->BeginDictionary("versions"); |
42 |
|
|
|
43 |
|
|
#define V(key) \ |
44 |
|
|
trace_process->SetString(#key, per_process::metadata.versions.key.c_str()); |
45 |
|
|
|
46 |
|
89 |
NODE_VERSIONS_KEYS(V) |
47 |
|
|
#undef V |
48 |
|
|
|
49 |
|
89 |
trace_process->EndDictionary(); |
50 |
|
|
|
51 |
|
89 |
trace_process->SetString("arch", per_process::metadata.arch.c_str()); |
52 |
|
89 |
trace_process->SetString("platform", |
53 |
|
|
per_process::metadata.platform.c_str()); |
54 |
|
|
|
55 |
|
89 |
trace_process->BeginDictionary("release"); |
56 |
|
89 |
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 |
|
89 |
trace_process->EndDictionary(); |
62 |
✓✗✓✗
|
267 |
TRACE_EVENT_METADATA1( |
63 |
|
|
"__metadata", "node", "process", std::move(trace_process)); |
64 |
|
|
|
65 |
|
|
// This only runs the first time tracing is enabled |
66 |
|
89 |
controller_->RemoveTraceStateObserver(this); |
67 |
|
89 |
} |
68 |
|
|
|
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 |
|
|
|
75 |
|
5534 |
explicit NodeTraceStateObserver(v8::TracingController* controller) |
76 |
|
5534 |
: controller_(controller) {} |
77 |
|
22136 |
~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 |
87 |
|
5534 |
inline void Initialize(int thread_pool_size) { |
88 |
✗✓ |
5534 |
CHECK(!initialized_); |
89 |
|
5534 |
initialized_ = true; |
90 |
|
5534 |
tracing_agent_ = std::make_unique<tracing::Agent>(); |
91 |
|
5534 |
node::tracing::TraceEventHelper::SetAgent(tracing_agent_.get()); |
92 |
|
|
node::tracing::TracingController* controller = |
93 |
|
5534 |
tracing_agent_->GetTracingController(); |
94 |
|
|
trace_state_observer_ = |
95 |
|
5534 |
std::make_unique<NodeTraceStateObserver>(controller); |
96 |
|
5534 |
controller->AddTraceStateObserver(trace_state_observer_.get()); |
97 |
|
5534 |
tracing_file_writer_ = tracing_agent_->DefaultHandle(); |
98 |
|
|
// Only start the tracing agent if we enabled any tracing categories. |
99 |
✓✓ |
5534 |
if (!per_process::cli_options->trace_event_categories.empty()) { |
100 |
|
85 |
StartTracingAgent(); |
101 |
|
|
} |
102 |
|
|
// Tracing must be initialized before platform threads are created. |
103 |
|
5534 |
platform_ = new NodePlatform(thread_pool_size, controller); |
104 |
|
5534 |
v8::V8::InitializePlatform(platform_); |
105 |
|
5534 |
} |
106 |
|
|
|
107 |
|
5529 |
inline void Dispose() { |
108 |
✓✓ |
5529 |
if (!initialized_) |
109 |
|
2 |
return; |
110 |
|
5527 |
initialized_ = false; |
111 |
|
|
|
112 |
|
5527 |
StopTracingAgent(); |
113 |
|
5527 |
platform_->Shutdown(); |
114 |
✓✗ |
5527 |
delete platform_; |
115 |
|
5527 |
platform_ = nullptr; |
116 |
|
|
// Destroy tracing after the platform (and platform threads) have been |
117 |
|
|
// stopped. |
118 |
|
5527 |
tracing_agent_.reset(nullptr); |
119 |
|
5527 |
trace_state_observer_.reset(nullptr); |
120 |
|
|
} |
121 |
|
|
|
122 |
|
|
inline void DrainVMTasks(v8::Isolate* isolate) { |
123 |
|
|
platform_->DrainTasks(isolate); |
124 |
|
|
} |
125 |
|
|
|
126 |
|
105 |
inline void StartTracingAgent() { |
127 |
|
|
// Attach a new NodeTraceWriter only if this function hasn't been called |
128 |
|
|
// before. |
129 |
✓✓ |
105 |
if (tracing_file_writer_.IsDefaultHandle()) { |
130 |
|
|
std::vector<std::string> categories = |
131 |
|
87 |
SplitString(per_process::cli_options->trace_event_categories, ','); |
132 |
|
|
|
133 |
|
261 |
tracing_file_writer_ = tracing_agent_->AddClient( |
134 |
|
174 |
std::set<std::string>(std::make_move_iterator(categories.begin()), |
135 |
|
|
std::make_move_iterator(categories.end())), |
136 |
|
174 |
std::unique_ptr<tracing::AsyncTraceWriter>( |
137 |
|
|
new tracing::NodeTraceWriter( |
138 |
|
87 |
per_process::cli_options->trace_event_file_pattern)), |
139 |
|
87 |
tracing::Agent::kUseDefaultCategories); |
140 |
|
|
} |
141 |
|
105 |
} |
142 |
|
|
|
143 |
|
5527 |
inline void StopTracingAgent() { tracing_file_writer_.reset(); } |
144 |
|
|
|
145 |
|
12002 |
inline tracing::AgentWriterHandle* GetTracingAgentWriter() { |
146 |
|
12002 |
return &tracing_file_writer_; |
147 |
|
|
} |
148 |
|
|
|
149 |
|
11078 |
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 |
156 |
|
|
inline void Initialize(int thread_pool_size) {} |
157 |
|
|
inline void Dispose() {} |
158 |
|
|
inline void DrainVMTasks(v8::Isolate* isolate) {} |
159 |
|
|
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 |
|
|
} |
166 |
|
|
inline void StopTracingAgent() {} |
167 |
|
|
|
168 |
|
|
inline tracing::AgentWriterHandle* GetTracingAgentWriter() { return nullptr; } |
169 |
|
|
|
170 |
|
|
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 |
|
|
|
178 |
|
20 |
inline void StartTracingAgent() { |
179 |
|
20 |
return per_process::v8_platform.StartTracingAgent(); |
180 |
|
|
} |
181 |
|
|
|
182 |
|
12002 |
inline tracing::AgentWriterHandle* GetTracingAgentWriter() { |
183 |
|
12002 |
return per_process::v8_platform.GetTracingAgentWriter(); |
184 |
|
|
} |
185 |
|
|
|
186 |
|
657 |
inline void DisposePlatform() { |
187 |
|
657 |
per_process::v8_platform.Dispose(); |
188 |
|
657 |
} |
189 |
|
|
|
190 |
|
|
} // namespace node |
191 |
|
|
|
192 |
|
|
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
193 |
|
|
|
194 |
|
|
#endif // SRC_NODE_V8_PLATFORM_INL_H_ |