Skip to content

Commit bd4ccc8

Browse files
misterpoeitaloacasas
authored andcommitted
src: add tracing controller
This commit adds support for trace-event tracing to Node.js. It provides a mechanism to centralize tracing information generated by V8, Node core, and userspace code. It includes: - A trace writer responsible for serializing traces and cycling the output files so that no individual file becomes to large. - A buffer for aggregating traces to allow for batched flushes. - An agent which initializes the tracing controller and ensures that trace serialization is done on a separate thread. - A set of macros for generating trace events. - Tests and documentation. Author: Raymond Kang <raymondksi@gmail.com> Author: Kelvin Jin <kelvinjin@google.com> Author: Matthew Loring <mattloring@google.com> Author: Jason Ginchereau <jasongin@microsoft.com> PR-URL: #11106 Reviewed-By: Josh Gavant <josh.gavant@outlook.com>
1 parent 1c7f221 commit bd4ccc8

15 files changed

+2458
-1
lines changed

doc/api/cli.md

+14
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,20 @@ added: v2.1.0
139139
Prints a stack trace whenever synchronous I/O is detected after the first turn
140140
of the event loop.
141141

142+
### `--trace-events-enabled`
143+
<!-- YAML
144+
added: REPLACEME
145+
-->
146+
147+
Enables the collection of trace event tracing information.
148+
149+
### `--trace-event-categories`
150+
<!-- YAML
151+
added: REPLACEME
152+
-->
153+
154+
A comma separated list of categories that should be traced when trace event
155+
tracing is enabled using `--trace-events-enabled`.
142156

143157
### `--zero-fill-buffers`
144158
<!-- YAML

doc/api/debugger.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -201,4 +201,4 @@ To start debugging, open the following URL in Chrome:
201201
chrome-devtools://devtools/remote/serve_file/@60cd6e859b9f557d2312f5bf532f6aec5f284980/inspector.html?experiments=true&v8only=true&ws=localhost:9229/node
202202
```
203203

204-
[TCP-based protocol]: https://github.com/v8/v8/wiki/Debugging-Protocol
204+
[TCP-based protocol]: https://github.com/v8/v8/wiki/Debugging-Protocol

doc/api/tracing.md

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Tracing
2+
3+
Trace Event provides a mechanism to centralize tracing information generated by
4+
V8, Node core, and userspace code.
5+
6+
Tracing can be enabled by passing the `--trace-events-enabled` flag when starting a
7+
Node.js application.
8+
9+
The set of categories for which traces are recorded can be specified using the
10+
`--trace-event-categories` flag followed by a list of comma separated category names.
11+
By default the `node` and `v8` categories are enabled.
12+
13+
```txt
14+
node --trace-events-enabled --trace-event-categories v8,node server.js
15+
```
16+
17+
Running Node.js with tracing enabled will produce log files that can be opened
18+
in the [`chrome://tracing`](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool)
19+
tab of Chrome.

node.gyp

+5
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@
152152
],
153153

154154
'sources': [
155+
'src/tracing/agent.cc',
156+
'src/tracing/node_trace_buffer.cc',
157+
'src/tracing/node_trace_writer.cc',
158+
'src/tracing/trace_event.cc',
155159
'src/async-wrap.cc',
156160
'src/cares_wrap.cc',
157161
'src/connection_wrap.cc',
@@ -230,6 +234,7 @@
230234
'src/stream_base.h',
231235
'src/stream_base-inl.h',
232236
'src/stream_wrap.h',
237+
'src/tracing/trace_event.h'
233238
'src/tree.h',
234239
'src/util.h',
235240
'src/util-inl.h',

src/node.cc

+28
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "req-wrap.h"
3939
#include "req-wrap-inl.h"
4040
#include "string_bytes.h"
41+
#include "tracing/agent.h"
4142
#include "util.h"
4243
#include "uv.h"
4344
#if NODE_USE_V8_PLATFORM
@@ -151,6 +152,8 @@ static node_module* modpending;
151152
static node_module* modlist_builtin;
152153
static node_module* modlist_linked;
153154
static node_module* modlist_addon;
155+
static bool trace_enabled = false;
156+
static const char* trace_enabled_categories = nullptr;
154157

155158
#if defined(NODE_HAVE_I18N_SUPPORT)
156159
// Path to ICU data (for i18n / Intl)
@@ -195,6 +198,7 @@ static uv_async_t dispatch_debug_messages_async;
195198

196199
static Mutex node_isolate_mutex;
197200
static v8::Isolate* node_isolate;
201+
static tracing::Agent* tracing_agent;
198202

199203
static node::DebugOptions debug_options;
200204

@@ -203,6 +207,7 @@ static struct {
203207
void Initialize(int thread_pool_size) {
204208
platform_ = v8::platform::CreateDefaultPlatform(thread_pool_size);
205209
V8::InitializePlatform(platform_);
210+
tracing::TraceEventHelper::SetCurrentPlatform(platform_);
206211
}
207212

208213
void PumpMessageLoop(Isolate* isolate) {
@@ -3369,6 +3374,9 @@ void SetupProcessObject(Environment* env,
33693374

33703375
void SignalExit(int signo) {
33713376
uv_tty_reset_mode();
3377+
if (trace_enabled) {
3378+
tracing_agent->Stop();
3379+
}
33723380
#ifdef __FreeBSD__
33733381
// FreeBSD has a nasty bug, see RegisterSignalHandler for details
33743382
struct sigaction sa;
@@ -3655,6 +3663,16 @@ static void ParseArgs(int* argc,
36553663
trace_deprecation = true;
36563664
} else if (strcmp(arg, "--trace-sync-io") == 0) {
36573665
trace_sync_io = true;
3666+
} else if (strcmp(arg, "--trace-events-enabled") == 0) {
3667+
trace_enabled = true;
3668+
} else if (strcmp(arg, "--trace-event-categories") == 0) {
3669+
const char* categories = argv[index + 1];
3670+
if (categories == nullptr) {
3671+
fprintf(stderr, "%s: %s requires an argument\n", argv[0], arg);
3672+
exit(9);
3673+
}
3674+
args_consumed += 1;
3675+
trace_enabled_categories = categories;
36583676
} else if (strcmp(arg, "--track-heap-objects") == 0) {
36593677
track_heap_objects = true;
36603678
} else if (strcmp(arg, "--throw-deprecation") == 0) {
@@ -4499,10 +4517,20 @@ int Start(int argc, char** argv) {
44994517
#endif // HAVE_OPENSSL
45004518

45014519
v8_platform.Initialize(v8_thread_pool_size);
4520+
// Enable tracing when argv has --trace-events-enabled.
4521+
if (trace_enabled) {
4522+
fprintf(stderr, "Warning: Trace event is an experimental feature "
4523+
"and could change at any time.\n");
4524+
tracing_agent = new tracing::Agent();
4525+
tracing_agent->Start(v8_platform.platform_, trace_enabled_categories);
4526+
}
45024527
V8::Initialize();
45034528
v8_initialized = true;
45044529
const int exit_code =
45054530
Start(uv_default_loop(), argc, argv, exec_argc, exec_argv);
4531+
if (trace_enabled) {
4532+
tracing_agent->Stop();
4533+
}
45064534
v8_initialized = false;
45074535
V8::Dispose();
45084536

src/node.h

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141

4242
#include "v8.h" // NOLINT(build/include_order)
4343
#include "node_version.h" // NODE_MODULE_VERSION
44+
#include "tracing/trace_event.h"
4445

4546
#define NODE_MAKE_VERSION(major, minor, patch) \
4647
((major) * 0x1000 + (minor) * 0x100 + (patch))

src/tracing/agent.cc

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#include "tracing/agent.h"
2+
3+
#include <sstream>
4+
#include <string>
5+
6+
#include "env-inl.h"
7+
#include "libplatform/libplatform.h"
8+
9+
namespace node {
10+
namespace tracing {
11+
12+
using v8::platform::tracing::TraceConfig;
13+
14+
Agent::Agent() {}
15+
16+
void Agent::Start(v8::Platform* platform, const char* enabled_categories) {
17+
platform_ = platform;
18+
19+
int err = uv_loop_init(&tracing_loop_);
20+
CHECK_EQ(err, 0);
21+
22+
NodeTraceWriter* trace_writer = new NodeTraceWriter(&tracing_loop_);
23+
TraceBuffer* trace_buffer = new NodeTraceBuffer(
24+
NodeTraceBuffer::kBufferChunks, trace_writer, &tracing_loop_);
25+
26+
tracing_controller_ = new TracingController();
27+
28+
TraceConfig* trace_config = new TraceConfig();
29+
if (enabled_categories) {
30+
std::stringstream category_list(enabled_categories);
31+
while (category_list.good()) {
32+
std::string category;
33+
getline(category_list, category, ',');
34+
trace_config->AddIncludedCategory(category.c_str());
35+
}
36+
} else {
37+
trace_config->AddIncludedCategory("v8");
38+
trace_config->AddIncludedCategory("node");
39+
}
40+
41+
// This thread should be created *after* async handles are created
42+
// (within NodeTraceWriter and NodeTraceBuffer constructors).
43+
// Otherwise the thread could shut down prematurely.
44+
err = uv_thread_create(&thread_, ThreadCb, this);
45+
CHECK_EQ(err, 0);
46+
47+
tracing_controller_->Initialize(trace_buffer);
48+
tracing_controller_->StartTracing(trace_config);
49+
v8::platform::SetTracingController(platform, tracing_controller_);
50+
}
51+
52+
void Agent::Stop() {
53+
if (!IsStarted()) {
54+
return;
55+
}
56+
// Perform final Flush on TraceBuffer. We don't want the tracing controller
57+
// to flush the buffer again on destruction of the V8::Platform.
58+
tracing_controller_->StopTracing();
59+
delete tracing_controller_;
60+
// Thread should finish when the tracing loop is stopped.
61+
uv_thread_join(&thread_);
62+
v8::platform::SetTracingController(platform_, nullptr);
63+
}
64+
65+
// static
66+
void Agent::ThreadCb(void* arg) {
67+
Agent* agent = static_cast<Agent*>(arg);
68+
uv_run(&agent->tracing_loop_, UV_RUN_DEFAULT);
69+
}
70+
71+
} // namespace tracing
72+
} // namespace node

src/tracing/agent.h

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#ifndef SRC_TRACING_AGENT_H_
2+
#define SRC_TRACING_AGENT_H_
3+
4+
#include "tracing/node_trace_buffer.h"
5+
#include "tracing/node_trace_writer.h"
6+
#include "uv.h"
7+
#include "v8.h"
8+
9+
namespace node {
10+
namespace tracing {
11+
12+
class Agent {
13+
public:
14+
explicit Agent();
15+
void Start(v8::Platform* platform, const char* enabled_categories);
16+
void Stop();
17+
18+
private:
19+
bool IsStarted() { return platform_ != nullptr; }
20+
static void ThreadCb(void* arg);
21+
22+
uv_thread_t thread_;
23+
uv_loop_t tracing_loop_;
24+
v8::Platform* platform_ = nullptr;
25+
TracingController* tracing_controller_;
26+
};
27+
28+
} // namespace tracing
29+
} // namespace node
30+
31+
#endif // SRC_TRACING_AGENT_H_

0 commit comments

Comments
 (0)