2. D is a (safe) power tool
● Some D concepts (predicates) are unfamiliar
to procedural programmers
● Some simple ideas require many steps
● These steps are (for the most part)
fundamentally necessary but tedious
● Solution: syntactic sugar
3. if/else in XD
vdev_queue_pending_remove:entry
{
if (stringof(args[1]->io_spa->spa_name) == $$1) {
if (args[1]->io_type == ZIO_TYPE_READ) {
@bytes_read = sum(args[1]->io_size);
} else if (args[1]->io_type == ZIO_TYPE_WRITE &&
args[1]->io_bookmark.zb_level != 2) {
@bytes_written = sum(args[1]->io_size);
}
}
}
6. entry-> variables in XD
spa_sync:return
{
printf("%s(%s, %u) took %ums",
probefunc,
entry->args[0]->spa_name, entry->args[1],
entry->elapsed_ms);
}
7. callers[] in XD
zrl_add:entry / callers["resolvepath,traverse"] / {@[stack()] = count()}
● The value of callers[] is a count, not just a toggle
○ Useful for examining recursive functions.
● callers["resolvepath,traverse"]
○ Either function must be in the stack
● callers["resolvepath"] && callers["traverse"]
○ Both functions must be in the stack
● Possible performance considerations
○ Each element means two more probes, be cognizant of enabled probe
effect.
8. How does it do that?
Changes are primarily in libdtrace
● Create parse tree
○ new nodes for "if", "while"
● Transform parse tree to remove XD
○ create new clauses
○ swap out entry->*, callers[]
● Finish compiling the (now strictly D) parse tree
● No kernel changes
9. How can I use it?
● https://github.com/ahrens/illumos/tree/dpp
○ fork of illumos
○ 100% libdtrace, should be easy to port
● To see the D generated from your XD
○ dtrace -xd -x tree=8 …
● Examples: https://github.com/ahrens/dtrace
● Bugs?
○ email matt@delphix.com your XD script
10. Field use
● In production at Delphix since April 2014
● if/else: increases legibility of larger scripts
○ ~50% of scripts use “if”
● while: rarely used
● entry->arg[], entry->elapsed
○ Extremely helpful for one-liners
○ ~75% of scripts use “entry->”
● callers[]
○ Helpful for one-liners
○ ~33% of scripts use “callers[]”
11. Field use (one-liner example)
● Histograms of time in foo(), broken down by
request size, when called from bar()
dtrace -xd -n ‘
foo:return
/callers[“bar”]/
{
@[entry->args[2]->b_size] =
quantize(entry->elapsed_us);
}’
12. Integration status
● Pollutes namespace with “_XD_*” variables
○ Should be possible to fix
● if/else: agreement that this is a good idea
○ “if” and “else” are already reserved keywords
● while: not that useful, let’s not bother
● entry->arg[], entry->elapsed
○ Concern about FBT concepts leaking into language
○ Concern about “entry” polluting namespace
○ But sooooo useful! Needs more discussion.
13. Integration status
● callers[]
○ Concern about dependence on FBT
○ Concern about hiding perf cost
○ Idea: implement by examining stack instead?
■ Pro: linear performance impact
■ Downside: reliance on backtrace accuracy
■ Downside: requires kernel changes
● “Is there an address in the range [x,y] in the backtrace”
14. What next?
1. Integrate if/else to illumos
2. Figure out entry-> concerns
3. Integrate entry-> to illumos
4. Figure out callers[] FBT vs stack()
5. Integrate callers[]
15. What next?
● "for" and "do" loops; "break", "continue"(?)
● #pragma D option defaultscope=local
○ bare variables will have probe-local scope
■ i.e. implicit "this->"
○ use "global->" for global variables
○ use "thread->" for thread-local variables
● "inline" functions to replace preprocessor?
● better error diagnosability?
○ dtrace: error on enabled probe ID 463 (ID 33804:
fbt:zfs:put_nvlist:entry): invalid address (0x0) in
action #1 at DIF offset 36
16. What next? (continued)
● Predicate Scoping
○ Applying a predicate to multiple clauses specified in a block:
/callers["spa_sync"]/
{
zio_read:entry {
stack();
}
metaslab_sync:return {
trace(entry->elapsed_ms);
}
}
30. callers[] in XD
Now a one-liner:
zrl_add:entry / callers["resolvepath,traverse"] / {@[stack()] = count()}
● The value of callers[] is a count, not just a toggle
○ Useful for examining recursive functions.
● callers["resolvepath,traverse"]
○ Either function must be in the stack
● callers["resolvepath"] && callers["traverse"]
○ Both functions must be in the stack
● Possible performance considerations
○ Each element means two more probes, be cognizant of enabled probe
effect.