build_enable_perfetto.patch 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
  2. From: Shelley Vohr <[email protected]>
  3. Date: Wed, 17 Apr 2024 08:17:49 -0400
  4. Subject: build: enable perfetto
  5. Enable perfetto by default in Node.js. Node.js disables perfetto by
  6. default but is broken on build - they don't currently add guards for
  7. `V8_USE_PERFETTO` and upstream only defines certain functions
  8. on `v8::TracingController` if perfetto is disabled. Electron already
  9. had minimal to no support for Node.js trace events, so the impact of
  10. adding associated guards there should be relatively small.
  11. We should upstream this as it will eventually impact Node.js as well.
  12. diff --git a/lib/internal/constants.js b/lib/internal/constants.js
  13. index 8d7204f6cb48f783adc4d1c1eb2de0c83b7fffe2..a154559a56bf383d3c26af523c9bb07b564ef600 100644
  14. --- a/lib/internal/constants.js
  15. +++ b/lib/internal/constants.js
  16. @@ -5,12 +5,15 @@ const isWindows = process.platform === 'win32';
  17. module.exports = {
  18. // Alphabet chars.
  19. CHAR_UPPERCASE_A: 65, /* A */
  20. + CHAR_UPPERCASE_B: 66, /* B */
  21. CHAR_LOWERCASE_A: 97, /* a */
  22. CHAR_UPPERCASE_Z: 90, /* Z */
  23. CHAR_LOWERCASE_Z: 122, /* z */
  24. CHAR_UPPERCASE_C: 67, /* C */
  25. CHAR_LOWERCASE_B: 98, /* b */
  26. + CHAR_UPPERCASE_E: 69, /* E */
  27. CHAR_LOWERCASE_E: 101, /* e */
  28. +
  29. CHAR_LOWERCASE_N: 110, /* n */
  30. // Non-alphabetic chars.
  31. diff --git a/lib/internal/http.js b/lib/internal/http.js
  32. index 251f51ec454f9cba4023b8b6729241ee753aac13..1de8cac6e3953ce9cab9db03530da327199acfd5 100644
  33. --- a/lib/internal/http.js
  34. +++ b/lib/internal/http.js
  35. @@ -8,8 +8,8 @@ const {
  36. const { setUnrefTimeout } = require('internal/timers');
  37. const { getCategoryEnabledBuffer, trace } = internalBinding('trace_events');
  38. const {
  39. - CHAR_LOWERCASE_B,
  40. - CHAR_LOWERCASE_E,
  41. + CHAR_UPPERCASE_B,
  42. + CHAR_UPPERCASE_E,
  43. } = require('internal/constants');
  44. let utcCache;
  45. @@ -44,11 +44,13 @@ function isTraceHTTPEnabled() {
  46. const traceEventCategory = 'node,node.http';
  47. function traceBegin(...args) {
  48. - trace(CHAR_LOWERCASE_B, traceEventCategory, ...args);
  49. + // See v8/src/builtins/builtins-trace.cc - must be uppercase for perfetto
  50. + trace(CHAR_UPPERCASE_B, traceEventCategory, ...args);
  51. }
  52. function traceEnd(...args) {
  53. - trace(CHAR_LOWERCASE_E, traceEventCategory, ...args);
  54. + // See v8/src/builtins/builtins-trace.cc - must be uppercase for perfetto
  55. + trace(CHAR_UPPERCASE_E, traceEventCategory, ...args);
  56. }
  57. module.exports = {
  58. diff --git a/node.gyp b/node.gyp
  59. index b21cfbf2fad024445e8d1ef8a6781141f788eb1a..55c6e01d9e879ce63524ec1504f8a23e00a2aa29 100644
  60. --- a/node.gyp
  61. +++ b/node.gyp
  62. @@ -174,7 +174,6 @@
  63. 'src/timers.cc',
  64. 'src/timer_wrap.cc',
  65. 'src/tracing/agent.cc',
  66. - 'src/tracing/node_trace_buffer.cc',
  67. 'src/tracing/node_trace_writer.cc',
  68. 'src/tracing/trace_event.cc',
  69. 'src/tracing/traced_value.cc',
  70. @@ -302,7 +301,6 @@
  71. 'src/tcp_wrap.h',
  72. 'src/timers.h',
  73. 'src/tracing/agent.h',
  74. - 'src/tracing/node_trace_buffer.h',
  75. 'src/tracing/node_trace_writer.h',
  76. 'src/tracing/trace_event.h',
  77. 'src/tracing/trace_event_common.h',
  78. diff --git a/src/inspector/tracing_agent.cc b/src/inspector/tracing_agent.cc
  79. index e7b6d3b3ea63bdc80e569f56209e958b4fcde328..b52d5b1c7293539315626cd67f794cce4cfd1760 100644
  80. --- a/src/inspector/tracing_agent.cc
  81. +++ b/src/inspector/tracing_agent.cc
  82. @@ -84,14 +84,14 @@ class InspectorTraceWriter : public node::tracing::AsyncTraceWriter {
  83. explicit InspectorTraceWriter(int frontend_object_id,
  84. std::shared_ptr<MainThreadHandle> main_thread)
  85. : frontend_object_id_(frontend_object_id), main_thread_(main_thread) {}
  86. -
  87. +#ifndef V8_USE_PERFETTO
  88. void AppendTraceEvent(
  89. v8::platform::tracing::TraceObject* trace_event) override {
  90. if (!json_writer_)
  91. json_writer_.reset(TraceWriter::CreateJSONTraceWriter(stream_, "value"));
  92. json_writer_->AppendTraceEvent(trace_event);
  93. }
  94. -
  95. +#endif
  96. void Flush(bool) override {
  97. if (!json_writer_)
  98. return;
  99. diff --git a/src/tracing/agent.cc b/src/tracing/agent.cc
  100. index 7ce59674356f9743438350949be42fa7ead2afbe..30bff4272ed8eb5146e3b73a4849c187177fc3bd 100644
  101. --- a/src/tracing/agent.cc
  102. +++ b/src/tracing/agent.cc
  103. @@ -2,7 +2,9 @@
  104. #include <string>
  105. #include "trace_event.h"
  106. +#ifndef V8_USE_PERFETTO
  107. #include "tracing/node_trace_buffer.h"
  108. +#endif
  109. #include "debug_utils-inl.h"
  110. #include "env-inl.h"
  111. @@ -50,7 +52,9 @@ using v8::platform::tracing::TraceWriter;
  112. using std::string;
  113. Agent::Agent() : tracing_controller_(new TracingController()) {
  114. +#ifndef V8_USE_PERFETTO
  115. tracing_controller_->Initialize(nullptr);
  116. +#endif
  117. CHECK_EQ(uv_loop_init(&tracing_loop_), 0);
  118. CHECK_EQ(uv_async_init(&tracing_loop_,
  119. @@ -86,10 +90,14 @@ Agent::~Agent() {
  120. void Agent::Start() {
  121. if (started_)
  122. return;
  123. -
  124. +#ifdef V8_USE_PERFETTO
  125. + std::ostringstream perfetto_output;
  126. + tracing_controller_->InitializeForPerfetto(&perfetto_output);
  127. +#else
  128. NodeTraceBuffer* trace_buffer_ = new NodeTraceBuffer(
  129. NodeTraceBuffer::kBufferChunks, this, &tracing_loop_);
  130. tracing_controller_->Initialize(trace_buffer_);
  131. +#endif
  132. // This thread should be created *after* async handles are created
  133. // (within NodeTraceWriter and NodeTraceBuffer constructors).
  134. @@ -143,8 +151,10 @@ void Agent::StopTracing() {
  135. return;
  136. // Perform final Flush on TraceBuffer. We don't want the tracing controller
  137. // to flush the buffer again on destruction of the V8::Platform.
  138. - tracing_controller_->StopTracing();
  139. +#ifndef V8_USE_PERFETTO
  140. tracing_controller_->Initialize(nullptr);
  141. +#endif
  142. + tracing_controller_->StopTracing();
  143. started_ = false;
  144. // Thread should finish when the tracing loop is stopped.
  145. @@ -202,6 +212,7 @@ std::string Agent::GetEnabledCategories() const {
  146. return categories;
  147. }
  148. +#ifndef V8_USE_PERFETTO
  149. void Agent::AppendTraceEvent(TraceObject* trace_event) {
  150. for (const auto& id_writer : writers_)
  151. id_writer.second->AppendTraceEvent(trace_event);
  152. @@ -211,18 +222,21 @@ void Agent::AddMetadataEvent(std::unique_ptr<TraceObject> event) {
  153. Mutex::ScopedLock lock(metadata_events_mutex_);
  154. metadata_events_.push_back(std::move(event));
  155. }
  156. +#endif
  157. void Agent::Flush(bool blocking) {
  158. +#ifndef V8_USE_PERFETTO
  159. {
  160. Mutex::ScopedLock lock(metadata_events_mutex_);
  161. for (const auto& event : metadata_events_)
  162. AppendTraceEvent(event.get());
  163. }
  164. -
  165. +#endif
  166. for (const auto& id_writer : writers_)
  167. id_writer.second->Flush(blocking);
  168. }
  169. +#ifndef V8_USE_PERFETTO
  170. void TracingController::AddMetadataEvent(
  171. const unsigned char* category_group_enabled,
  172. const char* name,
  173. @@ -246,6 +260,6 @@ void TracingController::AddMetadataEvent(
  174. if (node_agent != nullptr)
  175. node_agent->AddMetadataEvent(std::move(trace_event));
  176. }
  177. -
  178. +#endif
  179. } // namespace tracing
  180. } // namespace node
  181. diff --git a/src/tracing/agent.h b/src/tracing/agent.h
  182. index b542a849fe8da7e8bbbcca7067b73dc32b18d6d3..059ce6f6ea17199ead09c6c13bcc680f18f8c4d0 100644
  183. --- a/src/tracing/agent.h
  184. +++ b/src/tracing/agent.h
  185. @@ -27,7 +27,9 @@ class Agent;
  186. class AsyncTraceWriter {
  187. public:
  188. virtual ~AsyncTraceWriter() = default;
  189. +#ifndef V8_USE_PERFETTO
  190. virtual void AppendTraceEvent(TraceObject* trace_event) = 0;
  191. +#endif
  192. virtual void Flush(bool blocking) = 0;
  193. virtual void InitializeOnThread(uv_loop_t* loop) {}
  194. };
  195. @@ -36,6 +38,7 @@ class TracingController : public v8::platform::tracing::TracingController {
  196. public:
  197. TracingController() : v8::platform::tracing::TracingController() {}
  198. +#ifndef V8_USE_PERFETTO
  199. int64_t CurrentTimestampMicroseconds() override {
  200. return uv_hrtime() / 1000;
  201. }
  202. @@ -48,6 +51,7 @@ class TracingController : public v8::platform::tracing::TracingController {
  203. const uint64_t* arg_values,
  204. std::unique_ptr<v8::ConvertableToTraceFormat>* convertable_values,
  205. unsigned int flags);
  206. +#endif
  207. };
  208. class AgentWriterHandle {
  209. @@ -108,11 +112,12 @@ class Agent {
  210. // Returns a comma-separated list of enabled categories.
  211. std::string GetEnabledCategories() const;
  212. -
  213. +#ifndef V8_USE_PERFETTO
  214. // Writes to all writers registered through AddClient().
  215. void AppendTraceEvent(TraceObject* trace_event);
  216. void AddMetadataEvent(std::unique_ptr<TraceObject> event);
  217. +#endif
  218. // Flushes all writers registered through AddClient().
  219. void Flush(bool blocking);
  220. @@ -152,7 +157,9 @@ class Agent {
  221. std::set<AsyncTraceWriter*> to_be_initialized_;
  222. Mutex metadata_events_mutex_;
  223. +#ifndef V8_USE_PERFETTO
  224. std::list<std::unique_ptr<TraceObject>> metadata_events_;
  225. +#endif
  226. };
  227. void AgentWriterHandle::reset() {
  228. diff --git a/src/tracing/node_trace_buffer.h b/src/tracing/node_trace_buffer.h
  229. index 18e4f43efaae3a60b924e697918867e604513194..7cbaf01235750138c680c8ec2ed5d206d638f8b6 100644
  230. --- a/src/tracing/node_trace_buffer.h
  231. +++ b/src/tracing/node_trace_buffer.h
  232. @@ -42,7 +42,9 @@ class InternalTraceBuffer {
  233. bool flushing_;
  234. size_t max_chunks_;
  235. Agent* agent_;
  236. +#ifndef V8_USE_PERFETTO
  237. std::vector<std::unique_ptr<TraceBufferChunk>> chunks_;
  238. +#endif
  239. size_t total_chunks_ = 0;
  240. uint32_t current_chunk_seq_ = 1;
  241. uint32_t id_;
  242. diff --git a/src/tracing/node_trace_writer.cc b/src/tracing/node_trace_writer.cc
  243. index 8f053efe93324b9acbb4e85f7b974b4f7712e200..1801594e727ec7a2ef3b89603975f507078b88a1 100644
  244. --- a/src/tracing/node_trace_writer.cc
  245. +++ b/src/tracing/node_trace_writer.cc
  246. @@ -96,6 +96,7 @@ void NodeTraceWriter::OpenNewFileForStreaming() {
  247. }
  248. }
  249. +#ifndef V8_USE_PERFETTO
  250. void NodeTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
  251. Mutex::ScopedLock scoped_lock(stream_mutex_);
  252. // If this is the first trace event, open a new file for streaming.
  253. @@ -112,6 +113,7 @@ void NodeTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
  254. ++total_traces_;
  255. json_trace_writer_->AppendTraceEvent(trace_event);
  256. }
  257. +#endif
  258. void NodeTraceWriter::FlushPrivate() {
  259. std::string str;
  260. diff --git a/src/tracing/node_trace_writer.h b/src/tracing/node_trace_writer.h
  261. index cd965d77b7859ff2edcf781a934594b5a9b6d251..fe1714ba77fddef693d37eeb8c7a196ddfd15c26 100644
  262. --- a/src/tracing/node_trace_writer.h
  263. +++ b/src/tracing/node_trace_writer.h
  264. @@ -20,7 +20,9 @@ class NodeTraceWriter : public AsyncTraceWriter {
  265. ~NodeTraceWriter() override;
  266. void InitializeOnThread(uv_loop_t* loop) override;
  267. +#ifndef V8_USE_PERFETTO
  268. void AppendTraceEvent(TraceObject* trace_event) override;
  269. +#endif
  270. void Flush(bool blocking) override;
  271. static const int kTracesPerFile = 1 << 19;
  272. diff --git a/src/tracing/trace_event.h b/src/tracing/trace_event.h
  273. index a662a081dc3bf356bf93e4063fcb043e4d8df07b..c89cdfe2b2681fbf9946200a03d7d1f7bad21226 100644
  274. --- a/src/tracing/trace_event.h
  275. +++ b/src/tracing/trace_event.h
  276. @@ -69,8 +69,16 @@ enum CategoryGroupEnabledFlags {
  277. // for best performance when tracing is disabled.
  278. // const uint8_t*
  279. // TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(const char* category_group)
  280. +#ifndef V8_USE_PERFETTO
  281. #define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED \
  282. node::tracing::TraceEventHelper::GetCategoryGroupEnabled
  283. +#else
  284. +#define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group) \
  285. + ([](const char*) -> const uint8_t* { \
  286. + static uint8_t no = 0; \
  287. + return &no; \
  288. + })(category_group)
  289. +#endif
  290. // Get the number of times traces have been recorded. This is used to implement
  291. // the TRACE_EVENT_IS_NEW_TRACE facility.
  292. @@ -114,10 +122,15 @@ enum CategoryGroupEnabledFlags {
  293. // const uint8_t* category_group_enabled,
  294. // const char* name,
  295. // uint64_t id)
  296. +#ifndef V8_USE_PERFETTO
  297. #define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION \
  298. if (auto controller = \
  299. node::tracing::TraceEventHelper::GetTracingController()) \
  300. controller->UpdateTraceEventDuration
  301. +#else
  302. +#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled, name, event_handle) \
  303. + (void)(category_group_enabled), (void)(name), (void)(event_handle)
  304. +#endif
  305. // Adds a metadata event to the trace log. The |AppendValueAsTraceFormat| method
  306. // on the convertable value will be called at flush time.
  307. @@ -319,12 +332,15 @@ class TraceEventHelper {
  308. static void SetAgent(Agent* agent);
  309. static inline const uint8_t* GetCategoryGroupEnabled(const char* group) {
  310. +#ifndef V8_USE_PERFETTO
  311. v8::TracingController* controller = GetTracingController();
  312. static const uint8_t disabled = 0;
  313. if (controller == nullptr) [[unlikely]] {
  314. return &disabled;
  315. }
  316. return controller->GetCategoryGroupEnabled(group);
  317. +#endif
  318. + return 0;
  319. }
  320. };
  321. @@ -462,6 +478,7 @@ static inline uint64_t AddTraceEventImpl(
  322. const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
  323. const char** arg_names, const uint8_t* arg_types,
  324. const uint64_t* arg_values, unsigned int flags) {
  325. +#ifndef V8_USE_PERFETTO
  326. std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertibles[2];
  327. if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
  328. arg_convertibles[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
  329. @@ -478,6 +495,8 @@ static inline uint64_t AddTraceEventImpl(
  330. return controller->AddTraceEvent(phase, category_group_enabled, name, scope, id,
  331. bind_id, num_args, arg_names, arg_types,
  332. arg_values, arg_convertibles, flags);
  333. +#endif
  334. + return 0;
  335. }
  336. static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
  337. @@ -485,6 +504,7 @@ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
  338. const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
  339. const char** arg_names, const uint8_t* arg_types,
  340. const uint64_t* arg_values, unsigned int flags, int64_t timestamp) {
  341. +#ifndef V8_USE_PERFETTO
  342. std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertibles[2];
  343. if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
  344. arg_convertibles[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
  345. @@ -501,12 +521,15 @@ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
  346. return controller->AddTraceEventWithTimestamp(
  347. phase, category_group_enabled, name, scope, id, bind_id, num_args,
  348. arg_names, arg_types, arg_values, arg_convertibles, flags, timestamp);
  349. +#endif
  350. + return 0;
  351. }
  352. static V8_INLINE void AddMetadataEventImpl(
  353. const uint8_t* category_group_enabled, const char* name, int32_t num_args,
  354. const char** arg_names, const uint8_t* arg_types,
  355. const uint64_t* arg_values, unsigned int flags) {
  356. +#ifndef V8_USE_PERFETTO
  357. std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertibles[2];
  358. if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
  359. arg_convertibles[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
  360. @@ -522,6 +545,7 @@ static V8_INLINE void AddMetadataEventImpl(
  361. return agent->GetTracingController()->AddMetadataEvent(
  362. category_group_enabled, name, num_args, arg_names, arg_types, arg_values,
  363. arg_convertibles, flags);
  364. +#endif
  365. }
  366. // Define SetTraceValue for each allowed type. It stores the type and