• 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 #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