Coverage Report

Created: 2025-08-28 09:57

/src/node/src/node_v8_platform-inl.h
Line
Count
Source (jump to first uncovered line)
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:
26
0
  inline void OnTraceEnabled() override {
27
0
    std::string title = GetProcessTitle("");
28
0
    if (!title.empty()) {
29
      // Only emit the metadata event if the title can be retrieved
30
      // successfully. Ignore it otherwise.
31
0
      TRACE_EVENT_METADATA1(
32
0
          "__metadata", "process_name", "name", TRACE_STR_COPY(title.c_str()));
33
0
    }
34
0
    TRACE_EVENT_METADATA1("__metadata",
35
0
                          "version",
36
0
                          "node",
37
0
                          per_process::metadata.versions.node.c_str());
38
0
    TRACE_EVENT_METADATA1(
39
0
        "__metadata", "thread_name", "name", "JavaScriptMainThread");
40
41
0
    auto trace_process = tracing::TracedValue::Create();
42
0
    trace_process->BeginDictionary("versions");
43
44
0
#define V(key)                                                                 \
45
0
  trace_process->SetString(#key, per_process::metadata.versions.key.c_str());
46
47
0
    NODE_VERSIONS_KEYS(V)
48
0
#undef V
49
50
0
    trace_process->EndDictionary();
51
52
0
    trace_process->SetString("arch", per_process::metadata.arch.c_str());
53
0
    trace_process->SetString("platform",
54
0
                             per_process::metadata.platform.c_str());
55
56
0
    trace_process->BeginDictionary("release");
57
0
    trace_process->SetString("name",
58
0
                             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
0
    trace_process->EndDictionary();
63
0
    TRACE_EVENT_METADATA1(
64
0
        "__metadata", "node", "process", std::move(trace_process));
65
66
    // This only runs the first time tracing is enabled
67
0
    controller_->RemoveTraceStateObserver(this);
68
0
  }
69
70
0
  inline void OnTraceDisabled() override {
71
    // Do nothing here. This should never be called because the
72
    // observer removes itself when OnTraceEnabled() is called.
73
0
    UNREACHABLE();
74
0
  }
75
76
  explicit NodeTraceStateObserver(v8::TracingController* controller)
77
0
      : 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
88
0
  inline void Initialize(int thread_pool_size) {
89
0
    CHECK(!initialized_);
90
0
    initialized_ = true;
91
0
    tracing_agent_ = std::make_unique<tracing::Agent>();
92
0
    node::tracing::TraceEventHelper::SetAgent(tracing_agent_.get());
93
0
    node::tracing::TracingController* controller =
94
0
        tracing_agent_->GetTracingController();
95
0
    trace_state_observer_ =
96
0
        std::make_unique<NodeTraceStateObserver>(controller);
97
0
    controller->AddTraceStateObserver(trace_state_observer_.get());
98
0
    tracing_file_writer_ = tracing_agent_->DefaultHandle();
99
    // Only start the tracing agent if we enabled any tracing categories.
100
0
    if (!per_process::cli_options->trace_event_categories.empty()) {
101
0
      StartTracingAgent();
102
0
    }
103
    // Tracing must be initialized before platform threads are created.
104
0
    platform_ = new NodePlatform(thread_pool_size, controller);
105
0
    v8::V8::InitializePlatform(platform_);
106
0
  }
107
  // Make sure V8Platform don not call into Libuv threadpool,
108
  // see DefaultProcessExitHandlerInternal in environment.cc
109
0
  inline void Dispose() {
110
0
    if (!initialized_)
111
0
      return;
112
0
    initialized_ = false;
113
0
    node::tracing::TraceEventHelper::SetAgent(nullptr);
114
0
    StopTracingAgent();
115
0
    platform_->Shutdown();
116
0
    delete platform_;
117
0
    platform_ = nullptr;
118
    // Destroy tracing after the platform (and platform threads) have been
119
    // stopped.
120
0
    tracing_agent_.reset(nullptr);
121
    // The observer remove itself in OnTraceEnabled
122
0
    trace_state_observer_.reset(nullptr);
123
0
  }
124
125
0
  inline void DrainVMTasks(v8::Isolate* isolate) {
126
0
    platform_->DrainTasks(isolate);
127
0
  }
128
129
0
  inline void StartTracingAgent() {
130
0
    constexpr auto convert_to_set =
131
0
        [](std::vector<std::string_view> categories) -> std::set<std::string> {
132
0
      std::set<std::string> out;
133
0
      for (const auto& s : categories) {
134
0
        out.emplace(s);
135
0
      }
136
0
      return out;
137
0
    };
138
    // Attach a new NodeTraceWriter only if this function hasn't been called
139
    // before.
140
0
    if (tracing_file_writer_.IsDefaultHandle()) {
141
0
      using std::string_view_literals::operator""sv;
142
0
      const std::vector<std::string_view> categories =
143
0
          SplitString(per_process::cli_options->trace_event_categories, ","sv);
144
145
0
      tracing_file_writer_ = tracing_agent_->AddClient(
146
0
          convert_to_set(categories),
147
0
          std::unique_ptr<tracing::AsyncTraceWriter>(
148
0
              new tracing::NodeTraceWriter(
149
0
                  per_process::cli_options->trace_event_file_pattern)),
150
0
          tracing::Agent::kUseDefaultCategories);
151
0
    }
152
0
  }
153
154
0
  inline void StopTracingAgent() { tracing_file_writer_.reset(); }
155
156
244k
  inline tracing::AgentWriterHandle* GetTracingAgentWriter() {
157
244k
    return &tracing_file_writer_;
158
244k
  }
159
160
0
  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
167
  inline void Initialize(int thread_pool_size) {}
168
  inline void Dispose() {}
169
  inline void DrainVMTasks(v8::Isolate* isolate) {}
170
  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
  }
177
  inline void StopTracingAgent() {}
178
179
  inline tracing::AgentWriterHandle* GetTracingAgentWriter() { return nullptr; }
180
181
  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
189
0
inline void StartTracingAgent() {
190
0
  return per_process::v8_platform.StartTracingAgent();
191
0
}
192
193
244k
inline tracing::AgentWriterHandle* GetTracingAgentWriter() {
194
244k
  return per_process::v8_platform.GetTracingAgentWriter();
195
244k
}
196
197
0
inline void DisposePlatform() {
198
0
  per_process::v8_platform.Dispose();
199
0
}
200
201
}  // namespace node
202
203
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
204
205
#endif  // SRC_NODE_V8_PLATFORM_INL_H_