dtrace-provider
Advanced tools
Comparing version 0.0.9 to 0.2.0
@@ -6,28 +6,40 @@ dtrace-provider - Changes | ||
* 0.0.1: | ||
First working version: OSX x86_64 only. | ||
* 0.2.0: | ||
Update libusdt, and attempt to build it correctly for various platforms. | ||
Add support for disabling providers and removing probes. | ||
* 0.0.2: | ||
Solaris i386 support. | ||
Fixes memory leaks | ||
Improved performance, enabled- and disabled-probe. | ||
* 0.1.1: | ||
Replace Node-specific implementation with wrappers for libusdt. | ||
Extend argument support to 32 primitives. | ||
Adds Solaris x86_64 support. | ||
* 0.0.3: | ||
Builds to a stubbed-out version on non-DTrace platforms (Mark Cavage <mcavage@gmail.com>) | ||
* 0.0.9: | ||
Force the build architecture to x86_64 for OS X. | ||
* 0.0.4: | ||
Remove unused "sys" import (Alex Whitman) | ||
No longer builds an empty extension on non-DTrace platforms | ||
Probe objects are made available to Javascript. | ||
* 0.0.8: | ||
Removed overridden "scripts" section from package.json, breaking Windows installs | ||
* 0.0.7: | ||
Fix for multiple enable() calls breaking providers. | ||
* 0.0.6: | ||
Fix for segfault trying to use non-enabled probes (Mark Cavage mcavage@gmail.com) | ||
* 0.0.5: | ||
Revert changes to make probe objects available. | ||
* 0.0.6: | ||
Fix for segfault trying to use non-enabled probes (Mark Cavage <mcavage@gmail.com>) | ||
* 0.0.4: | ||
Remove unused "sys" import (Alex Whitman) | ||
No longer builds an empty extension on non-DTrace platforms | ||
Probe objects are made available to Javascript. | ||
* 0.0.7: | ||
Fix for multiple enable() calls breaking providers. | ||
* 0.0.3: | ||
Builds to a stubbed-out version on non-DTrace platforms (Mark Cavage <mcavage@gmail.com>) | ||
* 0.0.8: | ||
Removed overridden "scripts" section from package.json, breaking Windows installs | ||
* 0.0.2: | ||
Solaris i386 support. | ||
Fixes memory leaks | ||
Improved performance, enabled- and disabled-probe. | ||
* 0.0.1: | ||
First working version: OSX x86_64 only. |
var DTraceProvider; | ||
function DTraceProviderStub() {} | ||
DTraceProviderStub.prototype.addProbe = function() {}; | ||
DTraceProviderStub.prototype.addProbe = function() { | ||
return { | ||
'fire': function() { } | ||
}; | ||
}; | ||
DTraceProviderStub.prototype.enable = function() {}; | ||
DTraceProviderStub.prototype.fire = function() {}; | ||
try { | ||
var binding = require('./DTraceProviderBindings'); | ||
DTraceProvider = binding.DTraceProvider; | ||
} catch (e) { | ||
var builds = ['Release', 'default', 'Debug']; | ||
for (var i in builds) { | ||
try { | ||
var binding = require('./build/' + builds[i] + '/DTraceProviderBindings'); | ||
DTraceProvider = binding.DTraceProvider; | ||
break; | ||
} catch (e) { | ||
// if the platform looks like it _should_ have DTrace | ||
// available, log a failure to load the bindings. | ||
if (process.platform == 'darwin' || | ||
process.platform == 'solaris' || | ||
process.platform == 'freebsd') { | ||
console.log(e); | ||
} | ||
} | ||
} | ||
if (!DTraceProvider) { | ||
DTraceProvider = DTraceProviderStub; | ||
console.log(e); | ||
} | ||
exports.DTraceProvider = DTraceProvider; | ||
@@ -18,0 +35,0 @@ exports.createDTraceProvider = function(name) { |
{ | ||
"name" : "dtrace-provider", | ||
"version" : "0.0.9", | ||
"version" : "0.2.0", | ||
"description" : "Native DTrace providers for node.js applications", | ||
@@ -5,0 +5,0 @@ "keywords" : ["dtrace"], |
@@ -29,8 +29,24 @@ # dtrace-provider - Native DTrace providers for Node.js apps. | ||
var dtp = d.createDTraceProvider("nodeapp"); | ||
dtp.addProbe("probe1", "int", "int"); | ||
dtp.addProbe("probe2", "char *"); | ||
var p1 = dtp.addProbe("probe1", "int", "int"); | ||
var p2 = dtp.addProbe("probe2", "char *"); | ||
dtp.enable(); | ||
dtp.fire("probe1", function() { return [1, 2]; }); | ||
dtp.fire("probe2", function() { return ["hello, dtrace"]; }); | ||
Probes may be fired via the provider object: | ||
dtp.fire("probe1", function(p) { | ||
return [1, 2]; | ||
}); | ||
dtp.fire("probe2", function(p) { | ||
return ["hello, dtrace via provider", "foo"]; | ||
}); | ||
or via the probe objects themselves: | ||
p1.fire(function(p) { | ||
return [1, 2, 3, 4, 5, 6]; | ||
}); | ||
p2.fire(function(p) { | ||
return ["hello, dtrace via probe", "foo"]; | ||
}); | ||
This example creates a provider called "nodeapp", and adds two | ||
@@ -53,33 +69,35 @@ probes. It then enables the provider, at which point the provider | ||
The maximum number of arguments supported is 32. | ||
## PLATFORM SUPPORT | ||
The nature of this extension means that support must be added for each | ||
platform. Right now that support is only in place for OS X, 64 bit and | ||
Solaris, 32 bit. | ||
This libusdt-based Node.JS module supports 64 and 32 bit processes on | ||
Mac OS X and Solaris-like systems such as Illumos or SmartOS. As more | ||
platform support is added to libusdt, those platforms will be | ||
supported by this module. See libusdt's status at: | ||
https://github.com/chrisa/libusdt#readme | ||
FreeBSD is supported in principle but is restricted to only 4 working | ||
arguments per probe. | ||
Platforms not supporting DTrace (notably, Linux and Windows) may | ||
install this module without building libusdt, with a stub no-op | ||
implementation provided for compatibility. This allows cross-platform | ||
npm modules to embed probes and include a dependency on this module. | ||
## LIMITATIONS | ||
The maximum number of probe arguments is 6. There's scope to increase | ||
this, with some extra complexity in the platform-specific code. | ||
The data types supported are "int" and "char *". There's definitely | ||
scope to improve this, with more elaborate argument handling - see | ||
TODO.md | ||
The data types supported are "int" and "char *". Support for | ||
structured types is planned, depending on support from the host DTrace | ||
implementation for the necessary translators. | ||
You can only create a provider once - although you don't have to do it | ||
immediately, once you've set up a provider you can't change its | ||
definition. It should be possible to enable updates - again, see | ||
TODO.md. | ||
## CAVEATS | ||
Performance is not where it should be, most especially the | ||
disabled-probe effect. Probes are already using the "is-enabled" | ||
feature of DTrace to control execution of the arguments-gathering | ||
callback, but too much work needs to be done before that's | ||
checked. That being said, unless your (disabled) probes are | ||
insanely hot, this shouldn't be a problem. | ||
There is some overhead to probes, even when disabled. Probes are | ||
already using the "is-enabled" feature of DTrace to control execution | ||
of the arguments-gathering callback, but some work still needs to be | ||
done before that's checked. This overhead should not be a problem | ||
unless probes are placed in particularly hot code paths. | ||
Please see TODO.md for the details. | ||
## CONTRIBUTING | ||
@@ -86,0 +104,0 @@ |
@@ -1,21 +0,30 @@ | ||
// expected output: | ||
// | ||
// $ sudo dtrace -Z -n 'nodeapp*:::probe1{ printf("%i %i %i %i %i %i", arg0, arg1, arg2, arg3, arg4, arg5); }' \ | ||
// -n 'nodeapp*:::probe2{ printf("%s %s %s %s %s %s", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3), copyinstr(arg4), copyinstr(arg5)) }' \ | ||
// -c 'node test/dtp.js' | ||
// | ||
// dtrace: description 'nodeapp*:::probe1' matched 0 probes | ||
// dtrace: description 'nodeapp*:::probe2' matched 0 probes | ||
// CPU ID FUNCTION:NAME | ||
// 1 3421 func:probe1 1 2 3 4 5 6 | ||
// 1 3422 func:probe2 a b c d e f | ||
var util = require('util'); | ||
var d = require('../dtrace-provider'); | ||
var d = require('../dtrace-provider'); | ||
var dtp = d.createDTraceProvider("nodeapp"); | ||
dtp.addProbe("probe1", "int", "int", "int", "int", "int", "int"); | ||
dtp.addProbe("probe2", "char *", "char *", "char *", "char *", "char *", "char *"); | ||
var dtp = d.createDTraceProvider("testlibusdt"); | ||
var p = dtp.addProbe("32probe", "int", "int", "int", "int", "int", "int", "int", "int", | ||
"int", "int", "int", "int", "int", "int", "int", "int", | ||
"int", "int", "int", "int", "int", "int", "int", "int", | ||
"int", "int", "int", "int", "int", "int", "int", "int"); | ||
dtp.enable(); | ||
dtp.fire("probe1", function(p) { return [1, 2, 3, 4, 5, 6]; }); | ||
dtp.fire("probe2", function(p) { return ["a", "b", "c", "d", "e", "f"]; }); | ||
setTimeout(function() { }, 1000); | ||
util.debug("run: sudo dtrace -n 'testlibusdt*:::32probe{ printf(\"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\", args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], args[23], args[24], args[25], args[26], args[27], args[28], args[29], args[30], args[31]) }'") | ||
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, | ||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]; | ||
setTimeout(function() { | ||
var args = []; | ||
numbers.forEach(function(n) { | ||
args.push(n); | ||
dtp.fire("32probe", function(p) { | ||
return args; | ||
}); | ||
p.fire(function(p) { | ||
return args; | ||
}); | ||
}); | ||
}, 10000); |
59
TODO.md
@@ -5,55 +5,10 @@ # dtrace-provider - TODO | ||
### Complex Arguments | ||
### Structured Arguments | ||
Right now the argument types are just 'int' and 'char *'. There's no | ||
possibility of passing, say, javascript objects through DTrace. | ||
The current support for argument types is limited to "char *" and | ||
"int", i.e. strings and integer types. Native string types in | ||
Javascript are converted to raw C strings for use with DTrace. | ||
It seems like there's two things that need to be done here: | ||
* Find the right format for taking complex argument values through DTrace | ||
* Find a way to teach DTrace about what we're emitting | ||
### Dynamic Updates | ||
These providers are already pretty dynamic in that you get to create | ||
them based on runtime data - but you only get to do that once, for | ||
each provider. | ||
It'd be nice to be able to modify providers that already exist, | ||
updating or adding to their probe definitions. This opens up the | ||
possibility of providers which dynamically add probes based on data, | ||
and given a high level of collusion between a JIT and the provider | ||
management, much lower overhead dynamic-language tracing by having the | ||
JIT output tracepoints directly. | ||
## PERFORMANCE | ||
### Disabled Probe Effect | ||
The main problem here is how much work needs to be done to get to the | ||
point we can use the is-enabled check. | ||
While the is-enabled check allows us to avoid invoking the probe-args | ||
callback with its potentially expensive args-gathering work, we still | ||
do the following when a disabled probe is fired: | ||
* Dispatch Fire method from JS | ||
* Obtain DTraceProvider instance from V8 context | ||
* Args checking (must get a probe name and a callback) | ||
* Linear search through provider's probes for probe name | ||
* Invoke the is-enabled stub | ||
The fix I'd like to make here is to allow probes to exist as JS | ||
functions themselves, so that the calling code can directly invoke the | ||
function to fire the probe, avoiding the search by name. In this | ||
situation we could also defer checking the arguments until the probe | ||
is actually fired. | ||
With these changes, the disabled-probe overhead should be reduced to a | ||
JS method call, and then the invocation of the is-enabled stub. | ||
The API change to support this would be to return these probe | ||
functions from provider.addProbe(), rather than calling through | ||
provider.fire(), though that could easily remain for backwards | ||
compatibility. | ||
With support for dynamic types and translators from the host DTrace | ||
implementation, it'd be possible to provide a mapping from Javascript | ||
objects to C structs, which could then be inspected in D scripts. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
38
153
115
80008
2
1