Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 895 lines (720 sloc) 23.55 kB
cdea01b @bcantrill add support for sym()/func()/mod()/uaddr()/usym()/umod()/ufunc()
authored
1 /*
2 * For whatever reason, g++ on Solaris defines _XOPEN_SOURCE -- which in
3 * turn will prevent us from pulling in our desired definition for boolean_t.
4 * We don't need it, so explicitly undefine it.
5 */
6 #ifdef _XOPEN_SOURCE
7 #undef _XOPEN_SOURCE
8 #endif
9
20e9d9e @bcantrill primordial support for libdtrace
authored
10 #include <v8.h>
11 #include <node.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <node_object_wrap.h>
15 #include <errno.h>
16 #include <string>
17 #include <vector>
d5bd50b @bcantrill Add aggregation support
authored
18
19 /*
20 * Sadly, libelf refuses to compile if _FILE_OFFSET_BITS has been manually
21 * jacked to 64 on a 32-bit compile. In this case, we just manually set it
22 * back to 32.
23 */
24 #if defined(_ILP32) && (_FILE_OFFSET_BITS != 32)
25 #undef _FILE_OFFSET_BITS
26 #define _FILE_OFFSET_BITS 32
27 #endif
28
20e9d9e @bcantrill primordial support for libdtrace
authored
29 #include <dtrace.h>
30
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
31 /*
32 * This is a tad unsightly: if we didn't find the definition of the
33 * llquantize() aggregating action, we're going to redefine it here (along
34 * with its support cast of macros). This allows node-libdtrace to operate
35 * on a machine that has llquantize(), even if it was compiled on a machine
36 * without the support.
37 */
38 #ifndef DTRACEAGG_LLQUANTIZE
39
40 #define DTRACEAGG_LLQUANTIZE (DTRACEACT_AGGREGATION + 9)
41
42 #define DTRACE_LLQUANTIZE_FACTORSHIFT 48
43 #define DTRACE_LLQUANTIZE_FACTORMASK ((uint64_t)UINT16_MAX << 48)
44 #define DTRACE_LLQUANTIZE_LOWSHIFT 32
45 #define DTRACE_LLQUANTIZE_LOWMASK ((uint64_t)UINT16_MAX << 32)
46 #define DTRACE_LLQUANTIZE_HIGHSHIFT 16
47 #define DTRACE_LLQUANTIZE_HIGHMASK ((uint64_t)UINT16_MAX << 16)
48 #define DTRACE_LLQUANTIZE_NSTEPSHIFT 0
49 #define DTRACE_LLQUANTIZE_NSTEPMASK UINT16_MAX
50
51 #define DTRACE_LLQUANTIZE_FACTOR(x) \
52 (uint16_t)(((x) & DTRACE_LLQUANTIZE_FACTORMASK) >> \
53 DTRACE_LLQUANTIZE_FACTORSHIFT)
54
55 #define DTRACE_LLQUANTIZE_LOW(x) \
56 (uint16_t)(((x) & DTRACE_LLQUANTIZE_LOWMASK) >> \
57 DTRACE_LLQUANTIZE_LOWSHIFT)
58
59 #define DTRACE_LLQUANTIZE_HIGH(x) \
60 (uint16_t)(((x) & DTRACE_LLQUANTIZE_HIGHMASK) >> \
61 DTRACE_LLQUANTIZE_HIGHSHIFT)
62
63 #define DTRACE_LLQUANTIZE_NSTEP(x) \
64 (uint16_t)(((x) & DTRACE_LLQUANTIZE_NSTEPMASK) >> \
65 DTRACE_LLQUANTIZE_NSTEPSHIFT)
66 #endif
67
20e9d9e @bcantrill primordial support for libdtrace
authored
68 using namespace v8;
69 using std::string;
70 using std::vector;
71
72 class DTraceConsumer : node::ObjectWrap {
73 public:
74 static void Initialize(Handle<Object> target);
75
76 protected:
77 DTraceConsumer();
78 ~DTraceConsumer();
79
80 Handle<Value> error(const char *fmt, ...);
81 Handle<Value> badarg(const char *msg);
cdea01b @bcantrill add support for sym()/func()/mod()/uaddr()/usym()/umod()/ufunc()
authored
82 boolean_t valid(const dtrace_recdesc_t *);
d5bd50b @bcantrill Add aggregation support
authored
83 const char *action(const dtrace_recdesc_t *, char *, int);
cdea01b @bcantrill add support for sym()/func()/mod()/uaddr()/usym()/umod()/ufunc()
authored
84 Local<Value> record(const dtrace_recdesc_t *, caddr_t);
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
85 Local<Object> probedesc(const dtrace_probedesc_t *);
d5bd50b @bcantrill Add aggregation support
authored
86
87 Local<Array> *ranges_cached(dtrace_aggvarid_t);
88 Local<Array> *ranges_cache(dtrace_aggvarid_t, Local<Array> *);
89 Local<Array> *ranges_quantize(dtrace_aggvarid_t);
90 Local<Array> *ranges_lquantize(dtrace_aggvarid_t, uint64_t);
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
91 Local<Array> *ranges_llquantize(dtrace_aggvarid_t, uint64_t, int);
20e9d9e @bcantrill primordial support for libdtrace
authored
92
93 static int consume(const dtrace_probedata_t *data,
94 const dtrace_recdesc_t *rec, void *arg);
d5bd50b @bcantrill Add aggregation support
authored
95 static int aggwalk(const dtrace_aggdata_t *agg, void *arg);
20e9d9e @bcantrill primordial support for libdtrace
authored
96 static int bufhandler(const dtrace_bufdata_t *bufdata, void *arg);
97
98 static Handle<Value> New(const Arguments& args);
99 static Handle<Value> Consume(const Arguments& args);
d5bd50b @bcantrill Add aggregation support
authored
100 static Handle<Value> Aggwalk(const Arguments& args);
101 static Handle<Value> Aggmin(const Arguments& args);
102 static Handle<Value> Aggmax(const Arguments& args);
20e9d9e @bcantrill primordial support for libdtrace
authored
103 static Handle<Value> Strcompile(const Arguments& args);
104 static Handle<Value> Setopt(const Arguments& args);
105 static Handle<Value> Go(const Arguments& args);
106 static Handle<Value> Stop(const Arguments& args);
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
107 static Handle<Value> Version(const Arguments& args);
20e9d9e @bcantrill primordial support for libdtrace
authored
108
109 private:
110 dtrace_hdl_t *dtc_handle;
111 static Persistent<FunctionTemplate> dtc_templ;
112 const Arguments *dtc_args;
d5bd50b @bcantrill Add aggregation support
authored
113 Local<Function> dtc_callback;
20e9d9e @bcantrill primordial support for libdtrace
authored
114 Handle<Value> dtc_error;
d5bd50b @bcantrill Add aggregation support
authored
115 Local<Array> *dtc_ranges;
116 dtrace_aggvarid_t dtc_ranges_varid;
20e9d9e @bcantrill primordial support for libdtrace
authored
117 };
118
119 Persistent<FunctionTemplate> DTraceConsumer::dtc_templ;
120
121 DTraceConsumer::DTraceConsumer() : node::ObjectWrap()
122 {
123 int err;
124 dtrace_hdl_t *dtp;
125
126 if ((dtc_handle = dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL)
127 throw (dtrace_errmsg(NULL, err));
128
129 /*
130 * Set our buffer size and aggregation buffer size to the de facto
131 * standard of 4M.
132 */
133 (void) dtrace_setopt(dtp, "bufsize", "4m");
134 (void) dtrace_setopt(dtp, "aggsize", "4m");
135
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
136 if (dtrace_handle_buffered(dtp, DTraceConsumer::bufhandler, this) == -1)
20e9d9e @bcantrill primordial support for libdtrace
authored
137 throw (dtrace_errmsg(dtp, dtrace_errno(dtp)));
d5bd50b @bcantrill Add aggregation support
authored
138
139 dtc_ranges = NULL;
20e9d9e @bcantrill primordial support for libdtrace
authored
140 };
141
142 DTraceConsumer::~DTraceConsumer()
143 {
d5bd50b @bcantrill Add aggregation support
authored
144 if (dtc_ranges != NULL)
145 delete [] dtc_ranges;
146
20e9d9e @bcantrill primordial support for libdtrace
authored
147 dtrace_close(dtc_handle);
148 }
149
150 void
151 DTraceConsumer::Initialize(Handle<Object> target)
152 {
153 HandleScope scope;
154 Local<FunctionTemplate> dtc =
155 FunctionTemplate::New(DTraceConsumer::New);
156
157 dtc_templ = Persistent<FunctionTemplate>::New(dtc);
158 dtc_templ->InstanceTemplate()->SetInternalFieldCount(1);
159 dtc_templ->SetClassName(String::NewSymbol("Consumer"));
160
161 NODE_SET_PROTOTYPE_METHOD(dtc_templ, "strcompile",
162 DTraceConsumer::Strcompile);
163 NODE_SET_PROTOTYPE_METHOD(dtc_templ, "setopt", DTraceConsumer::Setopt);
164 NODE_SET_PROTOTYPE_METHOD(dtc_templ, "go", DTraceConsumer::Go);
165 NODE_SET_PROTOTYPE_METHOD(dtc_templ, "consume",
166 DTraceConsumer::Consume);
d5bd50b @bcantrill Add aggregation support
authored
167 NODE_SET_PROTOTYPE_METHOD(dtc_templ, "aggwalk",
168 DTraceConsumer::Aggwalk);
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
169 NODE_SET_PROTOTYPE_METHOD(dtc_templ, "aggmin", DTraceConsumer::Aggmin);
170 NODE_SET_PROTOTYPE_METHOD(dtc_templ, "aggmax", DTraceConsumer::Aggmax);
20e9d9e @bcantrill primordial support for libdtrace
authored
171 NODE_SET_PROTOTYPE_METHOD(dtc_templ, "stop", DTraceConsumer::Stop);
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
172 NODE_SET_PROTOTYPE_METHOD(dtc_templ, "version",
173 DTraceConsumer::Version);
20e9d9e @bcantrill primordial support for libdtrace
authored
174
175 target->Set(String::NewSymbol("Consumer"), dtc_templ->GetFunction());
176 }
177
178 Handle<Value>
179 DTraceConsumer::New(const Arguments& args)
180 {
181 HandleScope scope;
182 DTraceConsumer *dtc;
183
184 try {
185 dtc = new DTraceConsumer();
186 } catch (char const *msg) {
187 return (ThrowException(Exception::Error(String::New(msg))));
188 }
189
190 dtc->Wrap(args.Holder());
191
192 return (args.This());
193 }
194
d5bd50b @bcantrill Add aggregation support
authored
195 const char *
196 DTraceConsumer::action(const dtrace_recdesc_t *rec, char *buf, int size)
197 {
198 static struct {
199 dtrace_actkind_t action;
200 const char *name;
201 } act[] = {
202 { DTRACEACT_NONE, "<none>" },
203 { DTRACEACT_DIFEXPR, "<DIF expression>" },
204 { DTRACEACT_EXIT, "exit()" },
205 { DTRACEACT_PRINTF, "printf()" },
206 { DTRACEACT_PRINTA, "printa()" },
207 { DTRACEACT_LIBACT, "<library action>" },
208 { DTRACEACT_USTACK, "ustack()" },
209 { DTRACEACT_JSTACK, "jstack()" },
cdea01b @bcantrill add support for sym()/func()/mod()/uaddr()/usym()/umod()/ufunc()
authored
210 { DTRACEACT_USYM, "usym()" },
d5bd50b @bcantrill Add aggregation support
authored
211 { DTRACEACT_UMOD, "umod()" },
212 { DTRACEACT_UADDR, "uaddr()" },
213 { DTRACEACT_STOP, "stop()" },
214 { DTRACEACT_RAISE, "raise()" },
215 { DTRACEACT_SYSTEM, "system()" },
216 { DTRACEACT_FREOPEN, "freopen()" },
217 { DTRACEACT_STACK, "stack()" },
218 { DTRACEACT_SYM, "sym()" },
219 { DTRACEACT_MOD, "mod()" },
220 { DTRACEAGG_COUNT, "count()" },
221 { DTRACEAGG_MIN, "min()" },
222 { DTRACEAGG_MAX, "max()" },
223 { DTRACEAGG_AVG, "avg()" },
224 { DTRACEAGG_SUM, "sum()" },
225 { DTRACEAGG_STDDEV, "stddev()" },
226 { DTRACEAGG_QUANTIZE, "quantize()" },
227 { DTRACEAGG_LQUANTIZE, "lquantize()" },
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
228 { DTRACEAGG_LLQUANTIZE, "llquantize()" },
d5bd50b @bcantrill Add aggregation support
authored
229 { DTRACEACT_NONE, NULL },
230 };
231
232 dtrace_actkind_t action = rec->dtrd_action;
233 int i;
234
235 for (i = 0; act[i].name != NULL; i++) {
236 if (act[i].action == action)
237 return (act[i].name);
238 }
239
240 (void) snprintf(buf, size, "<unknown action 0x%x>", action);
241
242 return (buf);
243 }
244
20e9d9e @bcantrill primordial support for libdtrace
authored
245 Handle<Value>
246 DTraceConsumer::error(const char *fmt, ...)
247 {
248 char buf[1024], buf2[1024];
249 char *err = buf;
250 va_list ap;
251
252 va_start(ap, fmt);
253 (void) vsnprintf(buf, sizeof (buf), fmt, ap);
254
255 if (buf[strlen(buf) - 1] != '\n') {
256 /*
257 * If our error doesn't end in a new-line, we'll append the
258 * strerror of errno.
259 */
260 (void) snprintf(err = buf2, sizeof (buf2),
261 "%s: %s", buf, strerror(errno));
262 } else {
263 buf[strlen(buf) - 1] = '\0';
264 }
265
266 return (ThrowException(Exception::Error(String::New(err))));
267 }
268
269 Handle<Value>
270 DTraceConsumer::badarg(const char *msg)
271 {
272 return (ThrowException(Exception::TypeError(String::New(msg))));
273 }
274
cdea01b @bcantrill add support for sym()/func()/mod()/uaddr()/usym()/umod()/ufunc()
authored
275 boolean_t
276 DTraceConsumer::valid(const dtrace_recdesc_t *rec)
277 {
278 dtrace_actkind_t action = rec->dtrd_action;
279
280 switch (action) {
281 case DTRACEACT_DIFEXPR:
282 case DTRACEACT_SYM:
283 case DTRACEACT_MOD:
284 case DTRACEACT_USYM:
285 case DTRACEACT_UMOD:
286 case DTRACEACT_UADDR:
287 return (B_TRUE);
288
289 default:
290 return (B_FALSE);
291 }
292 }
293
294 Local<Value>
295 DTraceConsumer::record(const dtrace_recdesc_t *rec, caddr_t addr)
296 {
297 switch (rec->dtrd_action) {
298 case DTRACEACT_DIFEXPR:
299 switch (rec->dtrd_size) {
300 case sizeof (uint64_t):
301 return (Number::New(*((int64_t *)addr)));
302
303 case sizeof (uint32_t):
304 return (Integer::New(*((int32_t *)addr)));
305
306 case sizeof (uint16_t):
307 return (Integer::New(*((uint16_t *)addr)));
308
309 case sizeof (uint8_t):
310 return (Integer::New(*((uint8_t *)addr)));
311
312 default:
313 return (String::New((const char *)addr));
314 }
315
316 case DTRACEACT_SYM:
317 case DTRACEACT_MOD:
318 case DTRACEACT_USYM:
319 case DTRACEACT_UMOD:
320 case DTRACEACT_UADDR:
321 dtrace_hdl_t *dtp = dtc_handle;
322 char buf[2048], *tick, *plus;
323
324 buf[0] = '\0';
325
326 if (DTRACEACT_CLASS(rec->dtrd_action) == DTRACEACT_KERNEL) {
327 uint64_t pc = ((uint64_t *)addr)[0];
328 dtrace_addr2str(dtp, pc, buf, sizeof (buf) - 1);
329 } else {
330 uint64_t pid = ((uint64_t *)addr)[0];
331 uint64_t pc = ((uint64_t *)addr)[1];
332 dtrace_uaddr2str(dtp, pid, pc, buf, sizeof (buf) - 1);
333 }
334
335 if (rec->dtrd_action == DTRACEACT_MOD ||
336 rec->dtrd_action == DTRACEACT_UMOD) {
337 /*
338 * If we're looking for the module name, we'll
339 * return everything to the left of the left-most
340 * tick -- or "<undefined>" if there is none.
341 */
342 if ((tick = strchr(buf, '`')) == NULL)
343 return (String::New("<unknown>"));
344
345 *tick = '\0';
346 } else if (rec->dtrd_action == DTRACEACT_SYM ||
347 rec->dtrd_action == DTRACEACT_USYM) {
348 /*
349 * If we're looking for the symbol name, we'll
350 * return everything to the left of the right-most
351 * plus sign (if there is one).
352 */
353 if ((plus = strrchr(buf, '+')) != NULL)
354 *plus = '\0';
355 }
356
357 return (String::New(buf));
358 }
359
360 assert(B_FALSE);
361 return (Integer::New(-1));
362 }
363
20e9d9e @bcantrill primordial support for libdtrace
authored
364 Handle<Value>
365 DTraceConsumer::Strcompile(const Arguments& args)
366 {
367 DTraceConsumer *dtc = ObjectWrap::Unwrap<DTraceConsumer>(args.Holder());
368 dtrace_hdl_t *dtp = dtc->dtc_handle;
369 dtrace_prog_t *dp;
370 dtrace_proginfo_t info;
371
372 if (args.Length() < 1 || !args[0]->IsString())
373 return (dtc->badarg("expected program"));
374
375 String::Utf8Value program(args[0]->ToString());
376
377 if ((dp = dtrace_program_strcompile(dtp, *program,
378 DTRACE_PROBESPEC_NAME, 0, 0, NULL)) == NULL) {
379 return (dtc->error("couldn't compile '%s': %s\n", *program,
380 dtrace_errmsg(dtp, dtrace_errno(dtp))));
381 }
382
383 if (dtrace_program_exec(dtp, dp, &info) == -1) {
384 return (dtc->error("couldn't execute '%s': %s\n", *program,
385 dtrace_errmsg(dtp, dtrace_errno(dtp))));
386 }
387
388 return (Undefined());
389 }
390
391 Handle<Value>
392 DTraceConsumer::Setopt(const Arguments& args)
393 {
394 DTraceConsumer *dtc = ObjectWrap::Unwrap<DTraceConsumer>(args.Holder());
395 dtrace_hdl_t *dtp = dtc->dtc_handle;
396 dtrace_prog_t *dp;
397 dtrace_proginfo_t info;
398 int rval;
399
400 if (args.Length() < 1 || !args[0]->IsString())
401 return (dtc->badarg("expected an option to set"));
402
403 String::Utf8Value option(args[0]->ToString());
404
405 if (args.Length() >= 2) {
0cc7500 @bcantrill Fixed avg(); fixed setopt() values; added more tests
authored
406 if (args[1]->IsArray())
407 return (dtc->badarg("option value can't be an array"));
408
409 if (args[1]->IsObject())
410 return (dtc->badarg("option value can't be an object"));
20e9d9e @bcantrill primordial support for libdtrace
authored
411
412 String::Utf8Value optval(args[1]->ToString());
413 rval = dtrace_setopt(dtp, *option, *optval);
414 } else {
415 rval = dtrace_setopt(dtp, *option, NULL);
416 }
417
418 if (rval != 0) {
419 return (dtc->error("couldn't set option '%s': %s\n", *option,
420 dtrace_errmsg(dtp, dtrace_errno(dtp))));
421 }
422
423 return (Undefined());
424 }
425
426 Handle<Value>
427 DTraceConsumer::Go(const Arguments& args)
428 {
429 DTraceConsumer *dtc = ObjectWrap::Unwrap<DTraceConsumer>(args.Holder());
430 dtrace_hdl_t *dtp = dtc->dtc_handle;
431
432 if (dtrace_go(dtp) == -1) {
433 return (dtc->error("couldn't enable tracing: %s\n",
434 dtrace_errmsg(dtp, dtrace_errno(dtp))));
435 }
436
437 return (Undefined());
438 }
439
440 Handle<Value>
441 DTraceConsumer::Stop(const Arguments& args)
442 {
443 DTraceConsumer *dtc = ObjectWrap::Unwrap<DTraceConsumer>(args.Holder());
444 dtrace_hdl_t *dtp = dtc->dtc_handle;
445
446 if (dtrace_stop(dtp) == -1) {
447 return (dtc->error("couldn't disable tracing: %s\n",
448 dtrace_errmsg(dtp, dtrace_errno(dtp))));
449 }
450
451 return (Undefined());
452 }
453
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
454 Local<Object>
455 DTraceConsumer::probedesc(const dtrace_probedesc_t *pd)
456 {
457 Local<Object> probe = Object::New();
458 probe->Set(String::New("provider"), String::New(pd->dtpd_provider));
459 probe->Set(String::New("module"), String::New(pd->dtpd_mod));
460 probe->Set(String::New("function"), String::New(pd->dtpd_func));
461 probe->Set(String::New("name"), String::New(pd->dtpd_name));
462
463 return (probe);
464 }
465
20e9d9e @bcantrill primordial support for libdtrace
authored
466 int
467 DTraceConsumer::bufhandler(const dtrace_bufdata_t *bufdata, void *arg)
468 {
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
469 dtrace_probedata_t *data = bufdata->dtbda_probe;
470 const dtrace_recdesc_t *rec = bufdata->dtbda_recdesc;
471 DTraceConsumer *dtc = (DTraceConsumer *)arg;
472
473 if (rec == NULL || rec->dtrd_action != DTRACEACT_PRINTF)
474 return (DTRACE_HANDLE_OK);
475
476 Local<Object> probe = dtc->probedesc(data->dtpda_pdesc);
477 Local<Object> record = Object::New();
478 record->Set(String::New("data"), String::New(bufdata->dtbda_buffered));
479 Local<Value> argv[2] = { probe, record };
480
481 dtc->dtc_callback->Call(dtc->dtc_args->This(), 2, argv);
482
20e9d9e @bcantrill primordial support for libdtrace
authored
483 return (DTRACE_HANDLE_OK);
484 }
485
486 int
487 DTraceConsumer::consume(const dtrace_probedata_t *data,
488 const dtrace_recdesc_t *rec, void *arg)
489 {
490 DTraceConsumer *dtc = (DTraceConsumer *)arg;
491 dtrace_probedesc_t *pd = data->dtpda_pdesc;
492 Local<Value> datum;
493
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
494 Local<Object> probe = dtc->probedesc(data->dtpda_pdesc);
20e9d9e @bcantrill primordial support for libdtrace
authored
495
496 if (rec == NULL) {
497 Local<Value> argv[1] = { probe };
d5bd50b @bcantrill Add aggregation support
authored
498 dtc->dtc_callback->Call(dtc->dtc_args->This(), 1, argv);
20e9d9e @bcantrill primordial support for libdtrace
authored
499 return (DTRACE_CONSUME_NEXT);
500 }
501
cdea01b @bcantrill add support for sym()/func()/mod()/uaddr()/usym()/umod()/ufunc()
authored
502 if (!dtc->valid(rec)) {
d5bd50b @bcantrill Add aggregation support
authored
503 char errbuf[256];
504
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
505 /*
506 * If this is a printf(), we'll defer to the bufhandler.
507 */
508 if (rec->dtrd_action == DTRACEACT_PRINTF)
509 return (DTRACE_CONSUME_THIS);
510
d5bd50b @bcantrill Add aggregation support
authored
511 dtc->dtc_error = dtc->error("unsupported action %s "
512 "in record for %s:%s:%s:%s\n",
513 dtc->action(rec, errbuf, sizeof (errbuf)),
20e9d9e @bcantrill primordial support for libdtrace
authored
514 pd->dtpd_provider, pd->dtpd_mod,
515 pd->dtpd_func, pd->dtpd_name);
516 return (DTRACE_CONSUME_ABORT);
517 }
518
519 Local<Object> record = Object::New();
cdea01b @bcantrill add support for sym()/func()/mod()/uaddr()/usym()/umod()/ufunc()
authored
520 record->Set(String::New("data"), dtc->record(rec, data->dtpda_data));
20e9d9e @bcantrill primordial support for libdtrace
authored
521 Local<Value> argv[2] = { probe, record };
522
d5bd50b @bcantrill Add aggregation support
authored
523 dtc->dtc_callback->Call(dtc->dtc_args->This(), 2, argv);
20e9d9e @bcantrill primordial support for libdtrace
authored
524
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
525 return (DTRACE_CONSUME_THIS);
20e9d9e @bcantrill primordial support for libdtrace
authored
526 }
527
528 Handle<Value>
529 DTraceConsumer::Consume(const Arguments& args)
530 {
531 DTraceConsumer *dtc = ObjectWrap::Unwrap<DTraceConsumer>(args.Holder());
532 dtrace_hdl_t *dtp = dtc->dtc_handle;
533 dtrace_workstatus_t status;
534
535 if (!args[0]->IsFunction())
536 return (dtc->badarg("expected function as argument"));
537
d5bd50b @bcantrill Add aggregation support
authored
538 dtc->dtc_callback = Local<Function>::Cast(args[0]);
20e9d9e @bcantrill primordial support for libdtrace
authored
539 dtc->dtc_args = &args;
d5bd50b @bcantrill Add aggregation support
authored
540 dtc->dtc_error = Null();
20e9d9e @bcantrill primordial support for libdtrace
authored
541
542 status = dtrace_work(dtp, NULL, NULL, DTraceConsumer::consume, dtc);
543
d5bd50b @bcantrill Add aggregation support
authored
544 if (status == -1 && !dtc->dtc_error->IsNull())
20e9d9e @bcantrill primordial support for libdtrace
authored
545 return (dtc->dtc_error);
546
547 return (Undefined());
548 }
549
d5bd50b @bcantrill Add aggregation support
authored
550 /*
551 * Caching the quantized ranges improves performance substantially if the
552 * aggregations have many disjoing keys. Note that we only cache a single
553 * aggregation variable; programs that have more than one aggregation variable
554 * may see significant degradations in performance. (If this is a common
555 * case, this cache should clearly be expanded.)
556 */
557 Local<Array> *
558 DTraceConsumer::ranges_cached(dtrace_aggvarid_t varid)
559 {
560 if (varid == dtc_ranges_varid)
561 return (dtc_ranges);
562
563 return (NULL);
564 }
565
566 Local<Array> *
567 DTraceConsumer::ranges_cache(dtrace_aggvarid_t varid, Local<Array> *ranges)
568 {
569 if (dtc_ranges != NULL)
570 delete [] dtc_ranges;
571
572 dtc_ranges = ranges;
573 dtc_ranges_varid = varid;
574
575 return (ranges);
576 }
577
578 Local<Array> *
579 DTraceConsumer::ranges_quantize(dtrace_aggvarid_t varid)
580 {
581 int64_t min, max;
582 Local<Array> *ranges;
583 int i;
584
585 if ((ranges = ranges_cached(varid)) != NULL)
586 return (ranges);
587
588 ranges = new Local<Array>[DTRACE_QUANTIZE_NBUCKETS];
589
590 for (i = 0; i < DTRACE_QUANTIZE_NBUCKETS; i++) {
591 ranges[i] = Array::New(2);
592
593 if (i < DTRACE_QUANTIZE_ZEROBUCKET) {
594 /*
595 * If we're less than the zero bucket, our range
0cc7500 @bcantrill Fixed avg(); fixed setopt() values; added more tests
authored
596 * extends from negative infinity through to the
597 * beginning of our zeroth bucket.
d5bd50b @bcantrill Add aggregation support
authored
598 */
599 min = i > 0 ? DTRACE_QUANTIZE_BUCKETVAL(i - 1) + 1 :
600 INT64_MIN;
601 max = DTRACE_QUANTIZE_BUCKETVAL(i);
602 } else if (i == DTRACE_QUANTIZE_ZEROBUCKET) {
603 min = max = 0;
604 } else {
605 min = DTRACE_QUANTIZE_BUCKETVAL(i);
606 max = i < DTRACE_QUANTIZE_NBUCKETS - 1 ?
607 DTRACE_QUANTIZE_BUCKETVAL(i + 1) - 1 :
608 INT64_MAX;
609 }
610
611 ranges[i]->Set(0, Number::New(min));
612 ranges[i]->Set(1, Number::New(max));
613 }
614
615 return (ranges_cache(varid, ranges));
616 }
617
618 Local<Array> *
619 DTraceConsumer::ranges_lquantize(dtrace_aggvarid_t varid,
620 const uint64_t arg)
621 {
622 int64_t min, max;
623 Local<Array> *ranges;
624 int32_t base;
625 uint16_t step, levels;
626 int i;
627
628 if ((ranges = ranges_cached(varid)) != NULL)
629 return (ranges);
630
631 base = DTRACE_LQUANTIZE_BASE(arg);
632 step = DTRACE_LQUANTIZE_STEP(arg);
633 levels = DTRACE_LQUANTIZE_LEVELS(arg);
634
635 ranges = new Local<Array>[levels + 2];
636
637 for (i = 0; i <= levels + 1; i++) {
638 ranges[i] = Array::New(2);
639
640 min = i == 0 ? INT64_MIN : base + ((i - 1) * step);
641 max = i > levels ? INT64_MAX : base + (i * step) - 1;
642
643 ranges[i]->Set(0, Number::New(min));
644 ranges[i]->Set(1, Number::New(max));
645 }
646
647 return (ranges_cache(varid, ranges));
648 }
649
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
650 Local<Array> *
651 DTraceConsumer::ranges_llquantize(dtrace_aggvarid_t varid,
652 const uint64_t arg, int nbuckets)
653 {
654 int64_t value = 1, next, step;
655 Local<Array> *ranges;
656 int bucket = 0, order;
657 uint16_t factor, low, high, nsteps;
658
659 if ((ranges = ranges_cached(varid)) != NULL)
660 return (ranges);
661
662 factor = DTRACE_LLQUANTIZE_FACTOR(arg);
663 low = DTRACE_LLQUANTIZE_LOW(arg);
664 high = DTRACE_LLQUANTIZE_HIGH(arg);
665 nsteps = DTRACE_LLQUANTIZE_NSTEP(arg);
666
667 ranges = new Local<Array>[nbuckets];
668
669 for (order = 0; order < low; order++)
670 value *= factor;
671
672 ranges[bucket] = Array::New(2);
673 ranges[bucket]->Set(0, Number::New(0));
674 ranges[bucket]->Set(1, Number::New(value - 1));
675 bucket++;
676
677 next = value * factor;
678 step = next > nsteps ? next / nsteps : 1;
679
680 while (order <= high) {
681 ranges[bucket] = Array::New(2);
682 ranges[bucket]->Set(0, Number::New(value));
683 ranges[bucket]->Set(1, Number::New(value + step - 1));
684 bucket++;
685
686 if ((value += step) != next)
687 continue;
688
689 next = value * factor;
690 step = next > nsteps ? next / nsteps : 1;
691 order++;
692 }
693
694 ranges[bucket] = Array::New(2);
695 ranges[bucket]->Set(0, Number::New(value));
696 ranges[bucket]->Set(1, Number::New(INT64_MAX));
697
698 assert(bucket + 1 == nbuckets);
699
700 return (ranges_cache(varid, ranges));
701 }
702
d5bd50b @bcantrill Add aggregation support
authored
703 int
704 DTraceConsumer::aggwalk(const dtrace_aggdata_t *agg, void *arg)
705 {
706 DTraceConsumer *dtc = (DTraceConsumer *)arg;
707 const dtrace_aggdesc_t *aggdesc = agg->dtada_desc;
708 const dtrace_recdesc_t *aggrec;
709 Local<Value> id = Integer::New(aggdesc->dtagd_varid), val;
710 Local<Array> key;
711 char errbuf[256];
712 int i;
713
714 /*
715 * We expect to have both a variable ID and an aggregation value here;
716 * if we have fewer than two records, something is deeply wrong.
717 */
718 assert(aggdesc->dtagd_nrecs >= 2);
719 key = Array::New(aggdesc->dtagd_nrecs - 2);
720
721 for (i = 1; i < aggdesc->dtagd_nrecs - 1; i++) {
722 const dtrace_recdesc_t *rec = &aggdesc->dtagd_rec[i];
723 caddr_t addr = agg->dtada_data + rec->dtrd_offset;
724 Local<Value> datum;
725
cdea01b @bcantrill add support for sym()/func()/mod()/uaddr()/usym()/umod()/ufunc()
authored
726 if (!dtc->valid(rec)) {
d5bd50b @bcantrill Add aggregation support
authored
727 dtc->dtc_error = dtc->error("unsupported action %s "
728 "as key #%d in aggregation \"%s\"\n",
729 dtc->action(rec, errbuf, sizeof (errbuf)), i,
730 aggdesc->dtagd_name);
731 return (DTRACE_AGGWALK_ERROR);
732 }
733
cdea01b @bcantrill add support for sym()/func()/mod()/uaddr()/usym()/umod()/ufunc()
authored
734 key->Set(i - 1, dtc->record(rec, addr));
d5bd50b @bcantrill Add aggregation support
authored
735 }
736
737 aggrec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1];
738
739 switch (aggrec->dtrd_action) {
740 case DTRACEAGG_COUNT:
741 case DTRACEAGG_MIN:
742 case DTRACEAGG_MAX:
743 case DTRACEAGG_SUM: {
744 caddr_t addr = agg->dtada_data + aggrec->dtrd_offset;
745
746 assert(aggrec->dtrd_size == sizeof (uint64_t));
747 val = Number::New(*((int64_t *)addr));
748 break;
749 }
750
0cc7500 @bcantrill Fixed avg(); fixed setopt() values; added more tests
authored
751 case DTRACEAGG_AVG: {
752 const int64_t *data = (int64_t *)(agg->dtada_data +
753 aggrec->dtrd_offset);
754
755 assert(aggrec->dtrd_size == sizeof (uint64_t) * 2);
756 val = Number::New(data[1] / (double)data[0]);
757 break;
758 }
759
d5bd50b @bcantrill Add aggregation support
authored
760 case DTRACEAGG_QUANTIZE: {
761 Local<Array> quantize = Array::New();
762 const int64_t *data = (int64_t *)(agg->dtada_data +
763 aggrec->dtrd_offset);
764 Local<Array> *ranges, datum;
765 int i, j = 0;
766
767 ranges = dtc->ranges_quantize(aggdesc->dtagd_varid);
768
769 for (i = 0; i < DTRACE_QUANTIZE_NBUCKETS; i++) {
770 if (!data[i])
771 continue;
772
773 datum = Array::New(2);
774 datum->Set(0, ranges[i]);
775 datum->Set(1, Number::New(data[i]));
776
777 quantize->Set(j++, datum);
778 }
779
780 val = quantize;
781 break;
782 }
783
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
784 case DTRACEAGG_LQUANTIZE:
785 case DTRACEAGG_LLQUANTIZE: {
d5bd50b @bcantrill Add aggregation support
authored
786 Local<Array> lquantize = Array::New();
787 const int64_t *data = (int64_t *)(agg->dtada_data +
788 aggrec->dtrd_offset);
789 Local<Array> *ranges, datum;
790 int i, j = 0;
791
792 uint64_t arg = *data++;
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
793 int levels = (aggrec->dtrd_size / sizeof (uint64_t)) - 1;
d5bd50b @bcantrill Add aggregation support
authored
794
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
795 ranges = (aggrec->dtrd_action == DTRACEAGG_LQUANTIZE ?
796 dtc->ranges_lquantize(aggdesc->dtagd_varid, arg) :
797 dtc->ranges_llquantize(aggdesc->dtagd_varid, arg, levels));
d5bd50b @bcantrill Add aggregation support
authored
798
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
799 for (i = 0; i < levels; i++) {
d5bd50b @bcantrill Add aggregation support
authored
800 if (!data[i])
801 continue;
802
803 datum = Array::New(2);
804 datum->Set(0, ranges[i]);
805 datum->Set(1, Number::New(data[i]));
806
807 lquantize->Set(j++, datum);
808 }
809
810 val = lquantize;
811 break;
812 }
813
814 default:
815 dtc->dtc_error = dtc->error("unsupported aggregating action "
816 " %s in aggregation \"%s\"\n", dtc->action(aggrec, errbuf,
817 sizeof (errbuf)), aggdesc->dtagd_name);
818 return (DTRACE_AGGWALK_ERROR);
819 }
820
821 Local<Value> argv[3] = { id, key, val };
822 dtc->dtc_callback->Call(dtc->dtc_args->This(), 3, argv);
823
824 return (DTRACE_AGGWALK_REMOVE);
825 }
826
827 Handle<Value>
828 DTraceConsumer::Aggwalk(const Arguments& args)
829 {
830 HandleScope scope;
831 DTraceConsumer *dtc = ObjectWrap::Unwrap<DTraceConsumer>(args.Holder());
832 dtrace_hdl_t *dtp = dtc->dtc_handle;
658b724 @bcantrill Range cache must be invalidated before going out of scope
authored
833 int rval;
d5bd50b @bcantrill Add aggregation support
authored
834
835 if (!args[0]->IsFunction())
836 return (dtc->badarg("expected function as argument"));
837
838 dtc->dtc_callback = Local<Function>::Cast(args[0]);
839 dtc->dtc_args = &args;
840 dtc->dtc_error = Null();
841
842 if (dtrace_status(dtp) == -1) {
843 return (dtc->error("couldn't get status: %s\n",
844 dtrace_errmsg(dtp, dtrace_errno(dtp))));
845 }
846
847 if (dtrace_aggregate_snap(dtp) == -1) {
848 return (dtc->error("couldn't snap aggregate: %s\n",
849 dtrace_errmsg(dtp, dtrace_errno(dtp))));
850 }
851
658b724 @bcantrill Range cache must be invalidated before going out of scope
authored
852 rval = dtrace_aggregate_walk(dtp, DTraceConsumer::aggwalk, dtc);
853
854 /*
855 * Flush the ranges cache; the ranges will go out of scope when the
856 * destructor for our HandleScope is called, and we cannot be left
857 * holding references.
858 */
859 dtc->ranges_cache(DTRACE_AGGVARIDNONE, NULL);
860
861 if (rval == -1) {
d5bd50b @bcantrill Add aggregation support
authored
862 if (!dtc->dtc_error->IsNull())
863 return (dtc->dtc_error);
864
865 return (dtc->error("couldn't walk aggregate: %s\n",
866 dtrace_errmsg(dtp, dtrace_errno(dtp))));
867 }
868
869 return (Undefined());
870 }
871
872 Handle<Value>
873 DTraceConsumer::Aggmin(const Arguments& args)
874 {
875 return (Number::New(INT64_MIN));
876 }
877
878 Handle<Value>
879 DTraceConsumer::Aggmax(const Arguments& args)
880 {
881 return (Number::New(INT64_MAX));
882 }
883
83e6c53 @bcantrill llquantize() support; version() support; primordial printf() support
authored
884 Handle<Value>
885 DTraceConsumer::Version(const Arguments& args)
886 {
887 return (String::New(_dtrace_version));
888 }
889
20e9d9e @bcantrill primordial support for libdtrace
authored
890 extern "C" void
891 init (Handle<Object> target)
892 {
893 DTraceConsumer::Initialize(target);
894 }
Something went wrong with that request. Please try again.