chrisa / node-dtrace-provider

Native DTrace probes for node.js apps
Other
319 stars 70 forks source link

Probes should hold a reference to their providers #90

Closed melloc closed 7 years ago

melloc commented 7 years ago

If a provider object passes out of scope but its probes do not, then the provider get garbage collected, and unregisters all USDT probes. The following program can recreate this:

var d = require('dtrace-provider');

var dtp = d.createDTraceProvider('gctest');

var p1 = dtp.addProbe('probe1', 'int', 'int');
var p2 = dtp.addProbe('probe2', 'char *', 'int');

dtp.enable();

module.exports = {
    p1: p1,
    p2: p2
};

And:

var dtrace = require('./dtrace');

global.gc();

setTimeout(function () {
    dtrace.p1.fire(function () {
        return [ 5, 2 ];
    });
    dtrace.p2.fire(function () {
        return [ "hello", 2 ];
    });
}, 60000);

If you run the program:

% node --expose-gc foo.js

You can't find the probes:

% sudo dtrace -Zln 'gctest$target:::' -p `pgrep node`

   ID   PROVIDER            MODULE                          FUNCTION NAME
dtrace: failed to match gctest8494:::: No probe matches description

We can see that it gets removed by the GC by tracing the program:

% sudo dtrace -F -Zn 'pid$target::usdt*:entry, pid$target::usdt*:return { ustack(); }' -c 'node foo.js'
...
  0  -> usdt_provider_free                    
              DTraceProviderBindings.node`usdt_provider_free
              DTraceProviderBindings.node`node::DTraceProvider::~DTraceProvider()+0x25
              DTraceProviderBindings.node`node::DTraceProvider::~DTraceProvider()+0xe
              node`v8::internal::GlobalHandles::Node::PostGarbageCollectionProcessing(v8::internal::Isolate*, v8::internal::GlobalHandles*)+0x8b
              node`v8::internal::GlobalHandles::PostGarbageCollectionProcessing(v8::internal::GarbageCollector)+0xcd
              node`v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::internal::GCTracer*)+0x6b3
              node`v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollector, char const*, char const*)+0x21f
              node`v8::internal::Runtime::PerformGC(v8::internal::Object*)+0x7f
              0x268b0b0063da
              0x268b0b07508d
              0x268b0b074d4e
              0x268b0b07310b
              0x268b0b00d507
              0x268b0b006116
              node`v8::internal::Invoke(bool, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*, bool*)+0x1aa
              node`v8::internal::Object::GetPropertyWithDefinedGetter(v8::internal::Object*, v8::internal::JSReceiver*)+0x142
              node`v8::internal::JSObject::GetPropertyWithCallback(v8::internal::Object*, v8::internal::Object*, v8::internal::String*)+0x2d5
              node`v8::internal::KeyedLoadIC::Load(v8::internal::InlineCacheState, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, bool)+0x6c0
              node`v8::internal::KeyedLoadIC_Miss(v8::internal::Arguments, v8::internal::Isolate*)+0x1aa
              0x268b0b006362

  0  <- usdt_provider_free                    
              DTraceProviderBindings.node`usdt_provider_free+0x4c
              DTraceProviderBindings.node`DYLD-STUB$$free
              DTraceProviderBindings.node`node::DTraceProvider::~DTraceProvider()+0xe
              node`v8::internal::GlobalHandles::Node::PostGarbageCollectionProcessing(v8::internal::Isolate*, v8::internal::GlobalHandles*)+0x8b
              node`v8::internal::GlobalHandles::PostGarbageCollectionProcessing(v8::internal::GarbageCollector)+0xcd
              node`v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::internal::GCTracer*)+0x6b3
              node`v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollector, char const*, char const*)+0x21f
              node`v8::internal::Runtime::PerformGC(v8::internal::Object*)+0x7f
              0x268b0b0063da
              0x268b0b07508d
              0x268b0b074d4e
              0x268b0b07310b
              0x268b0b00d507
              0x268b0b006116
              node`v8::internal::Invoke(bool, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*, bool*)+0x1aa
              node`v8::internal::Object::GetPropertyWithDefinedGetter(v8::internal::Object*, v8::internal::JSReceiver*)+0x142
              node`v8::internal::JSObject::GetPropertyWithCallback(v8::internal::Object*, v8::internal::Object*, v8::internal::String*)+0x2d5
              node`v8::internal::KeyedLoadIC::Load(v8::internal::InlineCacheState, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, bool)+0x6c0
              node`v8::internal::KeyedLoadIC_Miss(v8::internal::Arguments, v8::internal::Isolate*)+0x1aa
              0x268b0b006362