Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v7.x backport: src: add tracing controller #11106

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,20 @@ added: v2.1.0
Prints a stack trace whenever synchronous I/O is detected after the first turn
of the event loop.

### `--trace-events-enabled`
<!-- YAML
added: REPLACEME
-->

Enables the collection of trace event tracing information.

### `--trace-event-categories`
<!-- YAML
added: REPLACEME
-->

A comma separated list of categories that should be traced when trace event
tracing is enabled using `--trace-events-enabled`.

### `--zero-fill-buffers`
<!-- YAML
Expand Down
2 changes: 1 addition & 1 deletion doc/api/debugger.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,4 @@ To start debugging, open the following URL in Chrome:
chrome-devtools://devtools/remote/serve_file/@60cd6e859b9f557d2312f5bf532f6aec5f284980/inspector.html?experiments=true&v8only=true&ws=localhost:9229/node
```

[TCP-based protocol]: https://github.com/v8/v8/wiki/Debugging-Protocol
[TCP-based protocol]: https://github.com/v8/v8/wiki/Debugging-Protocol
19 changes: 19 additions & 0 deletions doc/api/tracing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Tracing

Trace Event provides a mechanism to centralize tracing information generated by
V8, Node core, and userspace code.

Tracing can be enabled by passing the `--trace-events-enabled` flag when starting a
Node.js application.

The set of categories for which traces are recorded can be specified using the
`--trace-event-categories` flag followed by a list of comma separated category names.
By default the `node` and `v8` categories are enabled.

```txt
node --trace-events-enabled --trace-event-categories v8,node server.js
```

Running Node.js with tracing enabled will produce log files that can be opened
in the [`chrome://tracing`](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool)
tab of Chrome.
5 changes: 5 additions & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@
],

'sources': [
'src/tracing/agent.cc',
'src/tracing/node_trace_buffer.cc',
'src/tracing/node_trace_writer.cc',
'src/tracing/trace_event.cc',
'src/async-wrap.cc',
'src/cares_wrap.cc',
'src/connection_wrap.cc',
Expand Down Expand Up @@ -230,6 +234,7 @@
'src/stream_base.h',
'src/stream_base-inl.h',
'src/stream_wrap.h',
'src/tracing/trace_event.h'
'src/tree.h',
'src/util.h',
'src/util-inl.h',
Expand Down
28 changes: 28 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "req-wrap.h"
#include "req-wrap-inl.h"
#include "string_bytes.h"
#include "tracing/agent.h"
#include "util.h"
#include "uv.h"
#if NODE_USE_V8_PLATFORM
Expand Down Expand Up @@ -151,6 +152,8 @@ static node_module* modpending;
static node_module* modlist_builtin;
static node_module* modlist_linked;
static node_module* modlist_addon;
static bool trace_enabled = false;
static const char* trace_enabled_categories = nullptr;

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

static Mutex node_isolate_mutex;
static v8::Isolate* node_isolate;
static tracing::Agent* tracing_agent;

static node::DebugOptions debug_options;

Expand All @@ -203,6 +207,7 @@ static struct {
void Initialize(int thread_pool_size) {
platform_ = v8::platform::CreateDefaultPlatform(thread_pool_size);
V8::InitializePlatform(platform_);
tracing::TraceEventHelper::SetCurrentPlatform(platform_);
}

void PumpMessageLoop(Isolate* isolate) {
Expand Down Expand Up @@ -3369,6 +3374,9 @@ void SetupProcessObject(Environment* env,

void SignalExit(int signo) {
uv_tty_reset_mode();
if (trace_enabled) {
tracing_agent->Stop();
}
#ifdef __FreeBSD__
// FreeBSD has a nasty bug, see RegisterSignalHandler for details
struct sigaction sa;
Expand Down Expand Up @@ -3655,6 +3663,16 @@ static void ParseArgs(int* argc,
trace_deprecation = true;
} else if (strcmp(arg, "--trace-sync-io") == 0) {
trace_sync_io = true;
} else if (strcmp(arg, "--trace-events-enabled") == 0) {
trace_enabled = true;
} else if (strcmp(arg, "--trace-event-categories") == 0) {
const char* categories = argv[index + 1];
if (categories == nullptr) {
fprintf(stderr, "%s: %s requires an argument\n", argv[0], arg);
exit(9);
}
args_consumed += 1;
trace_enabled_categories = categories;
} else if (strcmp(arg, "--track-heap-objects") == 0) {
track_heap_objects = true;
} else if (strcmp(arg, "--throw-deprecation") == 0) {
Expand Down Expand Up @@ -4499,10 +4517,20 @@ int Start(int argc, char** argv) {
#endif // HAVE_OPENSSL

v8_platform.Initialize(v8_thread_pool_size);
// Enable tracing when argv has --trace-events-enabled.
if (trace_enabled) {
fprintf(stderr, "Warning: Trace event is an experimental feature "
"and could change at any time.\n");
tracing_agent = new tracing::Agent();
tracing_agent->Start(v8_platform.platform_, trace_enabled_categories);
}
V8::Initialize();
v8_initialized = true;
const int exit_code =
Start(uv_default_loop(), argc, argv, exec_argc, exec_argv);
if (trace_enabled) {
tracing_agent->Stop();
}
v8_initialized = false;
V8::Dispose();

Expand Down
1 change: 1 addition & 0 deletions src/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@

#include "v8.h" // NOLINT(build/include_order)
#include "node_version.h" // NODE_MODULE_VERSION
#include "tracing/trace_event.h"

#define NODE_MAKE_VERSION(major, minor, patch) \
((major) * 0x1000 + (minor) * 0x100 + (patch))
Expand Down
72 changes: 72 additions & 0 deletions src/tracing/agent.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "tracing/agent.h"

#include <sstream>
#include <string>

#include "env-inl.h"
#include "libplatform/libplatform.h"

namespace node {
namespace tracing {

using v8::platform::tracing::TraceConfig;

Agent::Agent() {}

void Agent::Start(v8::Platform* platform, const char* enabled_categories) {
platform_ = platform;

int err = uv_loop_init(&tracing_loop_);
CHECK_EQ(err, 0);

NodeTraceWriter* trace_writer = new NodeTraceWriter(&tracing_loop_);
TraceBuffer* trace_buffer = new NodeTraceBuffer(
NodeTraceBuffer::kBufferChunks, trace_writer, &tracing_loop_);

tracing_controller_ = new TracingController();

TraceConfig* trace_config = new TraceConfig();
if (enabled_categories) {
std::stringstream category_list(enabled_categories);
while (category_list.good()) {
std::string category;
getline(category_list, category, ',');
trace_config->AddIncludedCategory(category.c_str());
}
} else {
trace_config->AddIncludedCategory("v8");
trace_config->AddIncludedCategory("node");
}

// This thread should be created *after* async handles are created
// (within NodeTraceWriter and NodeTraceBuffer constructors).
// Otherwise the thread could shut down prematurely.
err = uv_thread_create(&thread_, ThreadCb, this);
CHECK_EQ(err, 0);

tracing_controller_->Initialize(trace_buffer);
tracing_controller_->StartTracing(trace_config);
v8::platform::SetTracingController(platform, tracing_controller_);
}

void Agent::Stop() {
if (!IsStarted()) {
return;
}
// Perform final Flush on TraceBuffer. We don't want the tracing controller
// to flush the buffer again on destruction of the V8::Platform.
tracing_controller_->StopTracing();
delete tracing_controller_;
// Thread should finish when the tracing loop is stopped.
uv_thread_join(&thread_);
v8::platform::SetTracingController(platform_, nullptr);
}

// static
void Agent::ThreadCb(void* arg) {
Agent* agent = static_cast<Agent*>(arg);
uv_run(&agent->tracing_loop_, UV_RUN_DEFAULT);
}

} // namespace tracing
} // namespace node
31 changes: 31 additions & 0 deletions src/tracing/agent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#ifndef SRC_TRACING_AGENT_H_
#define SRC_TRACING_AGENT_H_

#include "tracing/node_trace_buffer.h"
#include "tracing/node_trace_writer.h"
#include "uv.h"
#include "v8.h"

namespace node {
namespace tracing {

class Agent {
public:
explicit Agent();
void Start(v8::Platform* platform, const char* enabled_categories);
void Stop();

private:
bool IsStarted() { return platform_ != nullptr; }
static void ThreadCb(void* arg);

uv_thread_t thread_;
uv_loop_t tracing_loop_;
v8::Platform* platform_ = nullptr;
TracingController* tracing_controller_;
};

} // namespace tracing
} // namespace node

#endif // SRC_TRACING_AGENT_H_
Loading