Skip to content

Commit

Permalink
src: add trace events for env.cc
Browse files Browse the repository at this point in the history
PR-URL: nodejs#23674
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Denys Otrishko <shishugi@gmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Reviewed-By: Matheus Marchini <mat@mmarchini.me>
  • Loading branch information
jasnell authored and Trott committed Oct 18, 2018
1 parent 92d67fe commit 72a48a2
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 1 deletion.
1 change: 1 addition & 0 deletions doc/api/tracing.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ The available categories are:
The [`async_hooks`] events have a unique `asyncId` and a special `triggerId`
`triggerAsyncId` property.
* `node.bootstrap` - Enables capture of Node.js bootstrap milestones.
* `node.environment` - Enables capture of Node.js Environment milestones.
* `node.fs.sync` - Enables capture of trace data for file system sync methods.
* `node.perf` - Enables capture of [Performance API] measurements.
* `node.perf.usertiming` - Enables capture of only Performance API User Timing
Expand Down
55 changes: 54 additions & 1 deletion src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "node_context_data.h"
#include "node_worker.h"
#include "tracing/agent.h"
#include "tracing/traced_value.h"

#include <stdio.h>
#include <algorithm>
Expand All @@ -33,6 +34,25 @@ using worker::Worker;

#define kTraceCategoryCount 1

// TODO(@jasnell): Likely useful to move this to util or node_internal to
// allow reuse. But since we're not reusing it yet...
class TraceEventScope {
public:
TraceEventScope(const char* category,
const char* name,
void* id) : category_(category), name_(name), id_(id) {
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(category_, name_, id_);
}
~TraceEventScope() {
TRACE_EVENT_NESTABLE_ASYNC_END0(category_, name_, id_);
}

private:
const char* category_;
const char* name_;
void* id_;
};

int const Environment::kNodeContextTag = 0x6e6f64;
void* Environment::kNodeContextTagPtr = const_cast<void*>(
static_cast<const void*>(&Environment::kNodeContextTag));
Expand Down Expand Up @@ -224,6 +244,9 @@ Environment::~Environment() {
delete[] heap_statistics_buffer_;
delete[] heap_space_statistics_buffer_;
delete[] http_parser_buffer_;

TRACE_EVENT_NESTABLE_ASYNC_END0(
TRACING_CATEGORY_NODE1(environment), "Environment", this);
}

void Environment::Start(const std::vector<std::string>& args,
Expand All @@ -232,6 +255,23 @@ void Environment::Start(const std::vector<std::string>& args,
HandleScope handle_scope(isolate());
Context::Scope context_scope(context());

if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
TRACING_CATEGORY_NODE1(environment)) != 0) {
auto traced_value = tracing::TracedValue::Create();
traced_value->BeginArray("args");
for (const std::string& arg : args)
traced_value->AppendString(arg);
traced_value->EndArray();
traced_value->BeginArray("exec_args");
for (const std::string& arg : exec_args)
traced_value->AppendString(arg);
traced_value->EndArray();
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
TRACING_CATEGORY_NODE1(environment),
"Environment", this,
"args", std::move(traced_value));
}

CHECK_EQ(0, uv_timer_init(event_loop(), timer_handle()));
uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));

Expand Down Expand Up @@ -401,6 +441,8 @@ void Environment::PrintSyncTrace() const {
}

void Environment::RunCleanup() {
TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
"RunCleanup", this);
CleanupHandles();

while (!cleanup_hooks_.empty()) {
Expand Down Expand Up @@ -432,6 +474,8 @@ void Environment::RunCleanup() {
}

void Environment::RunBeforeExitCallbacks() {
TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
"BeforeExit", this);
for (ExitCallback before_exit : before_exit_functions_) {
before_exit.cb_(before_exit.arg_);
}
Expand All @@ -443,6 +487,8 @@ void Environment::BeforeExit(void (*cb)(void* arg), void* arg) {
}

void Environment::RunAtExitCallbacks() {
TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
"AtExit", this);
for (ExitCallback at_exit : at_exit_functions_) {
at_exit.cb_(at_exit.arg_);
}
Expand Down Expand Up @@ -496,13 +542,16 @@ void Environment::EnvPromiseHook(v8::PromiseHookType type,

Environment* env = Environment::GetCurrent(context);
if (env == nullptr) return;

TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
"EnvPromiseHook", env);
for (const PromiseHookCallback& hook : env->promise_hooks_) {
hook.cb_(type, promise, parent, hook.arg_);
}
}

void Environment::RunAndClearNativeImmediates() {
TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
"RunAndClearNativeImmediates", this);
size_t count = native_immediate_callbacks_.size();
if (count > 0) {
size_t ref_count = 0;
Expand Down Expand Up @@ -555,6 +604,8 @@ void Environment::ToggleTimerRef(bool ref) {

void Environment::RunTimers(uv_timer_t* handle) {
Environment* env = Environment::from_timer_handle(handle);
TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
"RunTimers", env);

if (!env->can_call_into_js())
return;
Expand Down Expand Up @@ -615,6 +666,8 @@ void Environment::RunTimers(uv_timer_t* handle) {

void Environment::CheckImmediate(uv_check_t* handle) {
Environment* env = Environment::from_immediate_check_handle(handle);
TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
"CheckImmediate", env);

if (env->immediate_info()->count() == 0)
return;
Expand Down
61 changes: 61 additions & 0 deletions test/parallel/test-trace-events-environment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Flags: --no-warnings

'use strict';
const common = require('../common');
const assert = require('assert');
const cp = require('child_process');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');

// This tests the emission of node.environment trace events

if (!common.isMainThread)
common.skip('process.chdir is not available in Workers');

const names = new Set([
'Environment',
'RunAndClearNativeImmediates',
'CheckImmediate',
'RunTimers',
'BeforeExit',
'RunCleanup',
'AtExit'
]);

if (process.argv[2] === 'child') {
// This is just so that the child has something to do.
1 + 1;
// These ensure that the RunTimers, CheckImmediate, and
// RunAndClearNativeImmediates appear in the list.
setImmediate(() => { 1 + 1; });
setTimeout(() => { 1 + 1; }, 1);
} else {
tmpdir.refresh();
process.chdir(tmpdir.path);

const proc = cp.fork(__filename,
[ 'child' ], {
execArgv: [
'--trace-event-categories',
'node.environment'
]
});

proc.once('exit', common.mustCall(async () => {
const file = path.join(tmpdir.path, 'node_trace.1.log');
const checkSet = new Set();

assert(fs.existsSync(file));
const data = await fs.promises.readFile(file);
JSON.parse(data.toString()).traceEvents
.filter((trace) => trace.cat !== '__metadata')
.forEach((trace) => {
assert.strictEqual(trace.pid, proc.pid);
assert(names.has(trace.name));
checkSet.add(trace.name);
});

assert.deepStrictEqual(names, checkSet);
}));
}

0 comments on commit 72a48a2

Please sign in to comment.