I originally posted this at http://dtrace.org/blogs/brendan/2011/11/25/dtrace-variable-types.
When using DTrace it is important to understand variable types and when each should be used. Using the wrong type can increase the overhead of your DTrace script, leading to degraded performance and DTrace error messages ("dynamic variable drops").
When discussing this with someone recently, we hit upon a neat way to explain it: listing variable types in order of preference. Work through the list below and pick the first variable type that can do the job.
DTrace variable types, in order of preference:
type | prefix | scope | overhead | multi-CPU safe | example assignment |
---|---|---|---|---|---|
aggregation | @ | global | low | yes | @x = count(); |
clause local | this-> | clause instance[1] | very low | yes | this->x = 1; |
thread local | self-> | thread | medium | yes | self->x = 1; |
scalar | none | global | low-medium | no[2] | x = 1; |
associative array | none | global | medium-high | no[2] | x[y] = 1; |
[1] The clause is the DTrace action specified within "{" and "}", and the variables are valid only while that probe is firing (not between different firings of the same probe). This type of variable can be thought of as working registers for intermediate calculations. While uncommonly used, they can be set in one clause and then accessed in another that uses the same probe, since the probe actions are executed in order.
[2] Multiple CPUs writing to the same scalar at the same time can lead to a corrupt variable state. It's unlikely, but has happened, and has been noticed for string scalars (corrupted string).
- Use "@x = count()" instead of "x++".
- Use self-> variables to associate data to threads wherever possible, instead of associative arrays.
- For intermediate calculations, use clause local: eg "this->delta = timestamp - self->start".