Skip to content

Commit

Permalink
src,lib: expose getCategoryEnabledBuffer to use on node.http
Browse files Browse the repository at this point in the history
Instead call the C++ code every time we need to check for a
trace category, now we get the C++ pointer to the flag that
holds the info if the trace is enabled and return this pointer
inside a buffer that we can use to call/check if the value is
enabled. With this change, no C++ call is made and the access
to the info happens in JS side, which has no perf penalty.

PR-URL: #53602
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
  • Loading branch information
H4ad authored and marco-ippolito committed Aug 19, 2024
1 parent 977af25 commit 31fdb88
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 2 deletions.
6 changes: 4 additions & 2 deletions lib/internal/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const {
} = primordials;

const { setUnrefTimeout } = require('internal/timers');
const { trace, isTraceCategoryEnabled } = internalBinding('trace_events');
const { getCategoryEnabledBuffer, trace } = internalBinding('trace_events');
const {
CHAR_LOWERCASE_B,
CHAR_LOWERCASE_E,
Expand Down Expand Up @@ -37,8 +37,10 @@ function getNextTraceEventId() {
return ++traceEventId;
}

const httpEnabled = getCategoryEnabledBuffer('node.http');

function isTraceHTTPEnabled() {
return isTraceCategoryEnabled('node.http');
return httpEnabled[0] > 0;
}

const traceEventCategory = 'node,node.http';
Expand Down
27 changes: 27 additions & 0 deletions src/node_trace_events.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace node {
class ExternalReferenceRegistry;

using v8::Array;
using v8::ArrayBuffer;
using v8::BackingStore;
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
Expand All @@ -25,6 +27,7 @@ using v8::Local;
using v8::NewStringType;
using v8::Object;
using v8::String;
using v8::Uint8Array;
using v8::Value;

class NodeCategorySet : public BaseObject {
Expand Down Expand Up @@ -120,6 +123,27 @@ static void SetTraceCategoryStateUpdateHandler(
env->set_trace_category_state_function(args[0].As<Function>());
}

static void GetCategoryEnabledBuffer(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsString());

Isolate* isolate = args.GetIsolate();
node::Utf8Value category_name(isolate, args[0]);

const uint8_t* enabled_pointer =
TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_name.out());
uint8_t* enabled_pointer_cast = const_cast<uint8_t*>(enabled_pointer);

std::unique_ptr<BackingStore> bs = ArrayBuffer::NewBackingStore(
enabled_pointer_cast,
sizeof(*enabled_pointer_cast),
[](void*, size_t, void*) {},
nullptr);
auto ab = ArrayBuffer::New(isolate, std::move(bs));
v8::Local<Uint8Array> u8 = v8::Uint8Array::New(ab, 0, 1);

args.GetReturnValue().Set(u8);
}

void NodeCategorySet::Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context,
Expand All @@ -132,6 +156,8 @@ void NodeCategorySet::Initialize(Local<Object> target,
target,
"setTraceCategoryStateUpdateHandler",
SetTraceCategoryStateUpdateHandler);
SetMethod(
context, target, "getCategoryEnabledBuffer", GetCategoryEnabledBuffer);

Local<FunctionTemplate> category_set =
NewFunctionTemplate(isolate, NodeCategorySet::New);
Expand Down Expand Up @@ -160,6 +186,7 @@ void NodeCategorySet::RegisterExternalReferences(
ExternalReferenceRegistry* registry) {
registry->Register(GetEnabledCategories);
registry->Register(SetTraceCategoryStateUpdateHandler);
registry->Register(GetCategoryEnabledBuffer);
registry->Register(NodeCategorySet::New);
registry->Register(NodeCategorySet::Enable);
registry->Register(NodeCategorySet::Disable);
Expand Down
43 changes: 43 additions & 0 deletions test/parallel/test-trace-events-get-category-enabled-buffer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use strict';
// Flags: --expose-internals

const common = require('../common');
const { it } = require('node:test');

try {
require('trace_events');
} catch {
common.skip('missing trace events');
}

const { createTracing, getEnabledCategories } = require('trace_events');
const assert = require('assert');

const binding = require('internal/test/binding');
const getCategoryEnabledBuffer = binding.internalBinding('trace_events').getCategoryEnabledBuffer;

it('should track enabled/disabled categories', () => {
const random = Math.random().toString().slice(2);
const category = `node.${random}`;

const buffer = getCategoryEnabledBuffer(category);

const tracing = createTracing({
categories: [category],
});

assert.ok(buffer[0] === 0, `the buffer[0] should start with value 0, got: ${buffer[0]}`);

tracing.enable();

let currentCategories = getEnabledCategories();

assert.ok(currentCategories.includes(category), `the getEnabledCategories should include ${category}, got: ${currentCategories}`);
assert.ok(buffer[0] > 0, `the buffer[0] should be greater than 0, got: ${buffer[0]}`);

tracing.disable();

currentCategories = getEnabledCategories();
assert.ok(currentCategories === undefined, `the getEnabledCategories should return undefined, got: ${currentCategories}`);
assert.ok(buffer[0] === 0, `the buffer[0] should be 0, got: ${buffer[0]}`);
});

0 comments on commit 31fdb88

Please sign in to comment.