[DTrace-devel] [PATCH] examples: Add "language features" demo scripts
eugene.loh at oracle.com
eugene.loh at oracle.com
Tue Sep 2 20:02:46 UTC 2025
From: Eugene Loh <eugene.loh at oracle.com>
The idea is to have lots of short scripts, each illustrating a
D language feature.
The numbering scheme serves two purposes:
*) the scripts are more or less in ascending order
of difficulty, although that's admittedly a tricky
concept in such a multi-dimensional space
*) there is some grouping of themes -- e.g.,
"introduction", "providers", "built-in variables", etc.
The combination of comments and code is intended to help either
a human user or an AI bot to learn how to use the D language.
Other examples have been based on functional objectives (doing
simple but useful tasks). These new examples are based on language
features. A future set of examples could be based on errors! That
is, the scripts generate errors of different sorts that we would
illustrate (and explain how to fix).
Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
examples/README.md | 13 +++
.../language_features/000intro-hello-world.d | 63 ++++++++++++
.../language_features/001intro-ERROR-probe.d | 30 ++++++
.../002intro-global-variables.d | 31 ++++++
examples/language_features/003intro-C-like.d | 75 +++++++++++++++
examples/language_features/004intro-ternary.d | 32 +++++++
examples/language_features/005intro-strings.d | 65 +++++++++++++
.../language_features/006intro-associative.d | 34 +++++++
.../007intro-this-variables.d | 49 ++++++++++
.../008intro-self-variables.d | 57 +++++++++++
examples/language_features/009intro-pragmas.d | 38 ++++++++
.../010intro-external-variables.d | 53 +++++++++++
.../language_features/011intro-preprocessor.d | 25 +++++
.../language_features/012intro-predicates.d | 52 ++++++++++
examples/language_features/100list_probes.sh | 11 +++
.../101count_probes_by_provider.sh | 12 +++
.../102list_probe_arguments.sh | 11 +++
.../language_features/110provider_profile.d | 29 ++++++
examples/language_features/120provider_proc.d | 37 ++++++++
.../130provider_sched_on_off_cpu.d | 28 ++++++
.../131provider_sched_enqueue_dequeue.d | 24 +++++
.../language_features/140provider_syscall.d | 20 ++++
examples/language_features/150provider_fbt.d | 48 ++++++++++
.../160provider_sdt_rawtp.sh | 36 +++++++
.../language_features/170provider_lockstat.sh | 17 ++++
examples/language_features/171provider_io.d | 31 ++++++
examples/language_features/172provider_ip.d | 26 +++++
examples/language_features/180provider_cpc.d | 52 ++++++++++
.../200built-in-variables-probe.d | 18 ++++
.../201built-in-variables-timestamps.d | 31 ++++++
.../202built-in-variables-args.d | 28 ++++++
.../203built-in-variables-process-info.d | 31 ++++++
.../204built-in-variables-uregs.d | 31 ++++++
examples/language_features/300actions-exit.sh | 18 ++++
examples/language_features/301actions-print.d | 32 +++++++
.../language_features/302actions-strings.d | 45 +++++++++
.../303actions-strings-paths.d | 25 +++++
.../language_features/304actions-system.d | 22 +++++
.../language_features/305actions-progenyof.d | 20 ++++
.../306actions-speculations.d | 57 +++++++++++
.../language_features/307actions-callstack.d | 54 +++++++++++
.../310actions-alloca-copy.d | 95 +++++++++++++++++++
examples/language_features/311actions-rand.d | 25 +++++
.../language_features/500aggregations-intro.d | 24 +++++
.../501aggregations-names-keys.d | 19 ++++
.../502aggregations-basic-funcs.d | 26 +++++
.../language_features/503aggregations-stack.d | 24 +++++
.../504aggregations-printa.d | 29 ++++++
.../505aggregations-quantize.d | 65 +++++++++++++
.../506aggregations-clear-trunc.d | 63 ++++++++++++
.../507aggregations-trunc5.d | 50 ++++++++++
.../508aggregations-normalize.d | 49 ++++++++++
52 files changed, 1880 insertions(+)
create mode 100755 examples/language_features/000intro-hello-world.d
create mode 100755 examples/language_features/001intro-ERROR-probe.d
create mode 100755 examples/language_features/002intro-global-variables.d
create mode 100755 examples/language_features/003intro-C-like.d
create mode 100755 examples/language_features/004intro-ternary.d
create mode 100755 examples/language_features/005intro-strings.d
create mode 100755 examples/language_features/006intro-associative.d
create mode 100755 examples/language_features/007intro-this-variables.d
create mode 100755 examples/language_features/008intro-self-variables.d
create mode 100755 examples/language_features/009intro-pragmas.d
create mode 100755 examples/language_features/010intro-external-variables.d
create mode 100755 examples/language_features/011intro-preprocessor.d
create mode 100755 examples/language_features/012intro-predicates.d
create mode 100755 examples/language_features/100list_probes.sh
create mode 100755 examples/language_features/101count_probes_by_provider.sh
create mode 100755 examples/language_features/102list_probe_arguments.sh
create mode 100755 examples/language_features/110provider_profile.d
create mode 100755 examples/language_features/120provider_proc.d
create mode 100755 examples/language_features/130provider_sched_on_off_cpu.d
create mode 100755 examples/language_features/131provider_sched_enqueue_dequeue.d
create mode 100755 examples/language_features/140provider_syscall.d
create mode 100755 examples/language_features/150provider_fbt.d
create mode 100755 examples/language_features/160provider_sdt_rawtp.sh
create mode 100755 examples/language_features/170provider_lockstat.sh
create mode 100755 examples/language_features/171provider_io.d
create mode 100755 examples/language_features/172provider_ip.d
create mode 100755 examples/language_features/180provider_cpc.d
create mode 100755 examples/language_features/200built-in-variables-probe.d
create mode 100755 examples/language_features/201built-in-variables-timestamps.d
create mode 100755 examples/language_features/202built-in-variables-args.d
create mode 100755 examples/language_features/203built-in-variables-process-info.d
create mode 100755 examples/language_features/204built-in-variables-uregs.d
create mode 100755 examples/language_features/300actions-exit.sh
create mode 100755 examples/language_features/301actions-print.d
create mode 100755 examples/language_features/302actions-strings.d
create mode 100755 examples/language_features/303actions-strings-paths.d
create mode 100755 examples/language_features/304actions-system.d
create mode 100755 examples/language_features/305actions-progenyof.d
create mode 100755 examples/language_features/306actions-speculations.d
create mode 100755 examples/language_features/307actions-callstack.d
create mode 100755 examples/language_features/310actions-alloca-copy.d
create mode 100755 examples/language_features/311actions-rand.d
create mode 100755 examples/language_features/500aggregations-intro.d
create mode 100755 examples/language_features/501aggregations-names-keys.d
create mode 100755 examples/language_features/502aggregations-basic-funcs.d
create mode 100755 examples/language_features/503aggregations-stack.d
create mode 100755 examples/language_features/504aggregations-printa.d
create mode 100755 examples/language_features/505aggregations-quantize.d
create mode 100755 examples/language_features/506aggregations-clear-trunc.d
create mode 100755 examples/language_features/507aggregations-trunc5.d
create mode 100755 examples/language_features/508aggregations-normalize.d
diff --git a/examples/README.md b/examples/README.md
index de4ba090b..b84a34031 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -86,3 +86,16 @@ These are the scripts included, plus a brief description.
| | thread ID as returned in the DTrace tid variable. |
| var-scope.d | Demonstrate some of the scoping rules for global and |B|
| | clause-local variables. |
+
+## Language-feature examples
+
+In the language_features/ subdirectory are short scripts,
+each illustrating a D language feature.
+
+The numbering scheme serves two purposes:
+
+* The scripts are more or less in ascending order of difficulty, although that's admittedly a tricky concept in such a multi-dimensional space
+
+* There is some grouping of themes -- e.g., "introduction", "providers", "built-in variables", etc.
+
+The scripts start at Beginner, and they arguably do not get much more complicated than that.
diff --git a/examples/language_features/000intro-hello-world.d b/examples/language_features/000intro-hello-world.d
new file mode 100755
index 000000000..a38f7cacc
--- /dev/null
+++ b/examples/language_features/000intro-hello-world.d
@@ -0,0 +1,63 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./000intro-hello-world.d
+ *
+ * or
+ *
+ * sudo /usr/sbin/dtrace -s 000intro-hello-world.d
+ *
+ * or
+ *
+ * sudo /usr/sbin/dtrace -n 'dtrace:::BEGIN
+ * {
+ * printf("hello world\n");
+ * exit(0);
+ * }
+ * dtrace:::END
+ * {
+ * trace("goodbye world");
+ * }'
+ *
+ * DESCRIPTION
+ * This is a simple "hello world" program in D. It
+ * illustrates a variety of very simple features of D.
+ */
+
+/*
+ * The BEGIN probe fires when the script is launched. It can
+ * be called by simply asking for BEGIN. Or, its provider can
+ * also be named: dtrace:::BEGIN. The other probe description
+ * fields, the module and function, are blank for this probe.
+ */
+dtrace:::BEGIN
+{
+ /*
+ * A C-like printf() function can be used to print
+ * data. Alternatively, the trace() function can be
+ * used, and it will discern the appropriate data type.
+ */
+ printf("hello world\n");
+
+ /*
+ * Variables can be assigned. They maybe typed implicitly.
+ */
+ x = 123;
+
+ exit(0);
+}
+
+dtrace:::BEGIN
+/x == 456/ /* A predicate can indicate whether to execute a clause. */
+{
+ trace("YOU SHOULD NOT SEE THIS MESSAGE!!!\n");
+}
+
+/*
+ * We can also gives actions to list at the end.
+ */
+dtrace:::END
+{
+ trace("goodbye world");
+}
diff --git a/examples/language_features/001intro-ERROR-probe.d b/examples/language_features/001intro-ERROR-probe.d
new file mode 100755
index 000000000..3c3a50eee
--- /dev/null
+++ b/examples/language_features/001intro-ERROR-probe.d
@@ -0,0 +1,30 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./001intro-ERROR-probe.d
+ *
+ * DESCRIPTION
+ * The ERROR probe can be used to handle run-time errors.
+ * If a clause encounters an error, its output is not seen
+ * and the ERROR probe is triggered. Other clauses associated
+ * with the guilty probe, however, do execute.
+ */
+
+dtrace:::ERROR
+{
+ printf("An error occurred.\n");
+}
+
+dtrace:::BEGIN
+{
+ printf("WE SHOULD NOT SEE THIS!\n");
+ printf("Dereference an illegal address: %d\n", *((int *)0x1234));
+ printf("WE SHOULD NOT GET HERE!\n");
+}
+
+dtrace:::BEGIN
+{
+ printf("This is a different clause.\n");
+ exit(0);
+}
diff --git a/examples/language_features/002intro-global-variables.d b/examples/language_features/002intro-global-variables.d
new file mode 100755
index 000000000..9b9ec6533
--- /dev/null
+++ b/examples/language_features/002intro-global-variables.d
@@ -0,0 +1,31 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./002intro-global-variables.d
+ *
+ * DESCRIPTION
+ * Rules for variable names are similar to those in C. By
+ * default, they are "global" -- that is, seen by every thread
+ * and every probe. So be careful that no thread overwrites any
+ * other thread's write. Variables may be typed implicitly.
+ */
+
+int explicitly_typed_variable;
+
+dtrace:::BEGIN
+{
+ explicitly_typed_variable = 1234;
+ implicitly_typed_variable = 5678;
+
+ printf("%d %d\n", explicitly_typed_variable,
+ implicitly_typed_variable);
+
+ my_char = 'a';
+ my_string = "hello world";
+ my_pointer = (int *) 0x123456;
+
+ printf("%c '%s' %p\n", my_char, my_string, my_pointer);
+
+ exit(0);
+}
diff --git a/examples/language_features/003intro-C-like.d b/examples/language_features/003intro-C-like.d
new file mode 100755
index 000000000..2e3ea8bde
--- /dev/null
+++ b/examples/language_features/003intro-C-like.d
@@ -0,0 +1,75 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./003intro-C-like.d
+ *
+ * DESCRIPTION
+ * Much of D syntax is very C-like. Examples are shown here.
+ * Check the documentation for more complete information.
+ *
+ * Differences include:
+ * - D variables can be typed implicitly
+ * - D has no "if" "switch" "case" "for"
+ * - D has no function definitions
+ */
+
+/*
+ * As you have already seen, one can use multi-line comments in D
+ * similarly to C.
+ */
+
+/*
+ * Variables can be declared explicitly. Data types like short, int, long,
+ * long long, char, struct, and union are familiar from C.
+ */
+int x, y, arr[5];
+
+dtrace:::BEGIN
+{
+ /* Assignments are similar to C. */
+ x = 1;
+ y = 2;
+ x += 3;
+
+ /* There are familiar operators. E.g., arithmetic operators. */
+ x = x + y;
+ y = 3 * x - 2 * y;
+
+ /* Relational operators. */
+ x = 2 > 3;
+ y = 2 >= 3;
+
+ /* Logical operators. */
+ x = (2 > 3) && (2 >= 3);
+
+ /* Bitwise operators. */
+ x = x & y;
+
+ /* Various unary operators. */
+ x = x++ + --y;
+
+ /* Types and casting. */
+ x = (long long) (sizeof(int) + ((int) 0xfedcba9876543210ull));
+
+ /*
+ * In contrast with C, D has a printf() whose %d, %x, and %i format
+ * conversions use type information about the corresponding argument
+ * to interpret that argument with its actual word size.
+ */
+ printf("%x\n", x);
+
+ /* Arrays can also be associative. More on that later. */
+ arr[0] = 10000;
+ arr[1] = 11111;
+ arr[2] = 12222;
+ arr[3] = 13333;
+ arr[4] = 14444;
+
+ /* One can get addresses and dereference addresses. */
+ /* (In this case, `nr_cpu_ids is a kernel variable.) */
+ ptr = &`nr_cpu_ids;
+ printf("nr_cpu_ids: %d should equal %d\n", *ptr, `nr_cpu_ids);
+
+ exit(0);
+}
diff --git a/examples/language_features/004intro-ternary.d b/examples/language_features/004intro-ternary.d
new file mode 100755
index 000000000..e6404f8b6
--- /dev/null
+++ b/examples/language_features/004intro-ternary.d
@@ -0,0 +1,32 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./004intro-ternary.d
+ *
+ * DESCRIPTION
+ * Much of D syntax is very C-like. Another example is
+ * ternary operations: ($condition ? $if_yes : $if_no).
+ * In D, however, ternary operations are argubly more
+ * useful than they are in C. The D language does not
+ * have conditional constructs like "if" statements.
+ * Therefore, other constructs, like predicates and
+ * speculations, must be used. Or, ternary operations.
+ */
+
+dtrace:::BEGIN
+{
+ x = 123;
+ y = 456;
+
+ /* basic ternary operation to implement z = MIN(x, y) */
+ z = (x < y) ? x : y;
+
+ /* a more novel use to conditionalize an assignment */
+ (x < y) ? (y = x) : 1;
+
+ /* all three variables should have the same value */
+ printf("x = %d; y = %d; z = %d\n", x, y, z);
+
+ exit(0);
+}
diff --git a/examples/language_features/005intro-strings.d b/examples/language_features/005intro-strings.d
new file mode 100755
index 000000000..5a758fcc3
--- /dev/null
+++ b/examples/language_features/005intro-strings.d
@@ -0,0 +1,65 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./005intro-strings.d
+ *
+ * DESCRIPTION
+ * But D does differ from C when it comes to strings.
+ * The D language has a built-in string data type.
+ */
+
+/*
+ * Strings are stored in arrays of fixed length. The
+ * default length 256 can be overridden with a D option.
+ */
+#pragma D option strsize=12
+
+/* string variables can be declared explicitly */
+string exp;
+string s1, s2, s3, s4;
+
+char carray[32];
+
+BEGIN
+{
+ /* strings are truncated, if necessary, per strsize */
+ printf("%s\n", "abcdefghijklmnopqrstuvwxyz");
+
+ /* string variables can be declared implicitly */
+ imp = "abcdefghijklmnopqrstuvwxyz";
+ printf("%d chars, string %s\n", sizeof(imp), imp);
+
+ /* operators can be used to order strings lexically (akin to strcmp) */
+ exp = "zyxwvutsrqponmlkjihgfedcba";
+ printf("%s is %s than %s\n", imp, imp < exp ? "less" : "greater", exp);
+
+ /* set up NULL-terminated char array for some illustration purposes */
+ carray[ 0] = 'A'; carray[ 1] = 'B'; carray[ 2] = 'C'; carray[ 3] = 'D';
+ carray[ 4] = 'E'; carray[ 5] = 'F'; carray[ 6] = 'G'; carray[ 7] = 'H';
+ carray[ 8] = 'I'; carray[ 9] = 'J'; carray[10] = 'K'; carray[11] = 'L';
+ carray[12] = 'M'; carray[13] = 'N'; carray[14] = 'O'; carray[15] = 'P';
+ carray[16] = 'Q'; carray[17] = 'R'; carray[18] = 'S'; carray[19] = 'T';
+ carray[20] = 'U'; carray[21] = 'V'; carray[22] = 'W'; carray[23] = 'X';
+ carray[24] = 'Y'; carray[25] = 'Z'; carray[26] = '\0';
+
+ /* char pointers can be turned into strings */
+ s1 = (string) carray; /* type casting */
+ s2 = stringof carray; /* stringof operator */
+
+ /* char pointers can be promoted automatically to strings */
+ s3 = carray;
+ s4 = strchr(carray, 'B');
+
+ /*
+ * Note that in the above assignments, we did not simply set
+ * a char* to some existing string buffer. Rather, contents
+ * are copied "by-value" to the destination string buffer.
+ * E.g., if the source buffer is modified, the output strings
+ * nevertheless all stay the same.
+ */
+ carray[2] = '\0';
+ printf("%s %s %s %s %s\n", s1, s2, s3, s4, carray);
+
+ exit(0);
+}
diff --git a/examples/language_features/006intro-associative.d b/examples/language_features/006intro-associative.d
new file mode 100755
index 000000000..b811c6028
--- /dev/null
+++ b/examples/language_features/006intro-associative.d
@@ -0,0 +1,34 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./006intro-associative.d
+ *
+ * DESCRIPTION
+ * The D language also supports associative arrays.
+ */
+
+/* associative arrays can be declared explicitly by key (if any) and value types */
+int exp[string, int];
+
+BEGIN
+{
+ /* associative arrays can also be declared implicitly */
+ imp["hello", 5] = 1234;
+
+ /* values not set are assumed to be 0 */
+ printf("set value is %d; unset value is %d\n",
+ imp["hello", 5],
+ exp["hello", 5]);
+
+ /* when you are done, set a value back to 0 to free the memory */
+ imp["hello", 5] = 0;
+
+ /*
+ * By the way, you cannot promote a char associative array
+ * to a string -- whether with stringof or (string) -- since
+ * it is not a consecutive block of memory holding chars in sequence.
+ */
+
+ exit(0);
+}
diff --git a/examples/language_features/007intro-this-variables.d b/examples/language_features/007intro-this-variables.d
new file mode 100755
index 000000000..4d9ba5390
--- /dev/null
+++ b/examples/language_features/007intro-this-variables.d
@@ -0,0 +1,49 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./007intro-this-variables.d
+ *
+ * DESCRIPTION
+ * We saw earlier that D supports global variables, allowing
+ * convenient access from every probe and every thread. In
+ * the same way, however, this causes the danger of different
+ * probes and threads overwriting one another's values.
+ *
+ * For variables that are to used only within a set of clauses
+ * for a specific probe, specify "this->". Such variables have
+ * undefined values at the start of the set of clauses.
+ */
+
+/* "this" variables can be declared explicitly */
+this int exp;
+
+dtrace:::BEGIN
+{
+ /* the value is undefined by default, define its value */
+ this->exp = 1234;
+
+ /* variables can also be typed implicitly */
+ this->imp = 5678;
+}
+
+dtrace:::BEGIN
+/ 1 == 1 /
+{
+ /* the variables are available in this later clause for the same probe */
+ printf("%d %d\n", this->exp, this->imp);
+
+ /*
+ * There is no need to zero out this-> variables at the end of a
+ * set of clauses: they will no longer exist anyhow and their
+ * values when they are used in a different set of clauses, for
+ * some other probe firing, will be undefined at first.
+ */
+
+ exit(0);
+}
+
+END
+{
+ /* the variables are not available here, for a different probe */
+}
diff --git a/examples/language_features/008intro-self-variables.d b/examples/language_features/008intro-self-variables.d
new file mode 100755
index 000000000..68a5dcf59
--- /dev/null
+++ b/examples/language_features/008intro-self-variables.d
@@ -0,0 +1,57 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./008intro-self-variables.d
+ *
+ * DESCRIPTION
+ * In D, we can also have variables that are local to a thread.
+ * We preface them with "self->".
+ */
+
+/* Thread-local "self" variables can be declared explicitly */
+self int exp, dummy;
+
+syscall::write:entry
+{
+ /* we initialize one variable to the fd of the write() call */
+ self->exp = arg0;
+
+ /* we can declare a self->variable implicitly, setting it to the requested number of bytes */
+ self->imp = arg2;
+}
+
+fbt::ksys_write:entry
+/ self->exp /
+{
+ self->kernel_value = arg2;
+}
+
+/*
+ * We look for a write() return probe on the same thread where
+ * self->exp has been set. Using thread-local variables allows
+ * us to connect two probes for the same thread, without interference
+ * from other threads.
+ */
+syscall::write:return
+/ self->exp /
+{
+ printf("on fd %d\n", self->exp);
+ printf("bytes (requested): %d\n", self->imp);
+ printf("bytes (requested in kernel function): %d\n", self->kernel_value);
+ printf("bytes (actual): %d\n", arg1);
+
+ /* uninitialized self-> variables are 0 */
+ printf("uninitialized is zero: %d\n", self->dummy);
+
+ /*
+ * It is good practice to zero out variables when you are
+ * done with them to free up the associated memory.
+ */
+ self->exp = 0;
+ self->imp = 0;
+ self->kernel_value = 0;
+
+ /* but for this example, we are finished */
+ exit(0);
+}
diff --git a/examples/language_features/009intro-pragmas.d b/examples/language_features/009intro-pragmas.d
new file mode 100755
index 000000000..a4e359976
--- /dev/null
+++ b/examples/language_features/009intro-pragmas.d
@@ -0,0 +1,38 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./009intro-pragmas.d
+ *
+ * DESCRIPTION
+ * D options can be set on the command line. E.g.,
+ *
+ * sudo /usr/sbin/dtrace -xq ...
+ * sudo /usr/sbin/dtrace -xw ...
+ * sudo /usr/sbin/dtrace -xstrsize=12 ...
+ *
+ * They can also be set via pragmas inside a script.
+ * Respectively,
+ */
+
+/* -q */
+#pragma D option quiet
+
+/* -w, e.g., for the system() call */
+#pragma D option destructive
+
+/* -xstrsize=12 */
+#pragma D option strsize=12
+
+/*
+ * Simple options could alternatively be set on the first
+ * "shebang" line. E.g., "#!/usr/sbin/dtrace -qws".
+ */
+
+dtrace:::BEGIN
+{
+ /* string truncated to strsize */
+ system("echo abcdefghijklmnopqrstuvwxyz");
+
+ exit(0);
+}
diff --git a/examples/language_features/010intro-external-variables.d b/examples/language_features/010intro-external-variables.d
new file mode 100755
index 000000000..a763a36f6
--- /dev/null
+++ b/examples/language_features/010intro-external-variables.d
@@ -0,0 +1,53 @@
+#!/usr/sbin/dtrace -s
+
+#pragma D option quiet
+#pragma D option strsize=64
+
+/*
+ * SYNOPSIS
+ * sudo ./010intro-external-variables.d
+ *
+ * DESCRIPTION
+ * We can examine external variables -- that is, variables from outside
+ * the D program, such as kernel variables. They are distinguished by
+ * a back quote ` and constitute a different name space from that of
+ * the D variables. When such a variables is named, the kernel and all
+ * loaded modules are searched for the name. Or, you can specify a
+ * module before the back quote. The kernel itself is module "vmlinux".
+ * D scripts cannot modify values of kernel variables.
+ *
+ * Such external variables are not part of D and are subject to change.
+ */
+
+dtrace:::BEGIN
+{
+
+ printf("\n==== print some kernel variables ====\n\n");
+
+ printf("cad_pid->level: %d\n", ((struct pid *)`cad_pid)->level);
+ printf("crashing_cpu: %d\n", `crashing_cpu);
+ printf("linux_banner: %s\n", (string)`linux_banner);
+ printf("linux_proc_banner: %s\n", (string)`linux_proc_banner);
+ printf("load averages: %d.%02d, %d.%02d, %d.%02d\n",
+ `avenrun[0] / 2048, ((`avenrun[0] % 2048) * 100) / 2048,
+ `avenrun[1] / 2048, ((`avenrun[1] % 2048) * 100) / 2048,
+ `avenrun[2] / 2048, ((`avenrun[2] % 2048) * 100) / 2048);
+ printf("max_pvn: %d\n", `max_pfn);
+ printf("nr_cpu_ids: %d\n", `nr_cpu_ids);
+ printf("saved_command_line: %s\n", (string)`saved_command_line);
+
+ printf("\n==== reprint some of them, explicitly naming vmlinux ====\n\n");
+
+ printf("crashing_cpu: %d\n", vmlinux`crashing_cpu);
+ printf("linux_banner: %s\n", (string)vmlinux`linux_banner);
+ printf("linux_proc_banner: %s\n", (string)vmlinux`linux_proc_banner);
+ printf("max_pvn: %d\n", vmlinux`max_pfn);
+ printf("nr_cpu_ids: %d\n", vmlinux`nr_cpu_ids);
+
+ printf("\n==== refer to a data type in a module ====\n\n");
+
+ printf("offset of atomic in struct rds_message: %d\n",
+ offsetof(struct rds`rds_message, atomic));
+
+ exit(0);
+}
diff --git a/examples/language_features/011intro-preprocessor.d b/examples/language_features/011intro-preprocessor.d
new file mode 100755
index 000000000..1ece9d2d6
--- /dev/null
+++ b/examples/language_features/011intro-preprocessor.d
@@ -0,0 +1,25 @@
+#!/usr/sbin/dtrace -Cqs
+
+/*
+ * SYNOPSIS
+ * sudo ./011intro-preprocessor.d
+ *
+ * DESCRIPTION
+ * D scripts can also use the C preprocessor. This requires using
+ * the "dtrace -C" option, or by adding 'C' to the first, shebang
+ * line, as illustrated above.
+ */
+
+#define KEYS "abcde", 12
+#define DEBUG
+
+dtrace:::BEGIN
+{
+#ifdef DEBUG
+ printf("\nabcde, 12 should get a count of 1\n");
+#endif
+
+ @[KEYS] = count();
+
+ exit(0);
+}
diff --git a/examples/language_features/012intro-predicates.d b/examples/language_features/012intro-predicates.d
new file mode 100755
index 000000000..3e4f7894d
--- /dev/null
+++ b/examples/language_features/012intro-predicates.d
@@ -0,0 +1,52 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * SYNOPSIS
+ * sudo ./012intro-predicates.d
+ *
+ * DESCRIPTION
+ * We have already seen that predicates can be used to
+ * conditionalize execution in a D scripts. (Other
+ * mechanisms include speculation and ternary operators.)
+ */
+
+BEGIN
+{
+ ntimes = 0;
+}
+
+/*
+ * The write() system call has a file descriptor in arg0 and a
+ * requested number of bytes in arg2. If a nonzero number of
+ * bytes is requested, take note of the fd.
+ */
+syscall::write:entry
+/ (self->nbytes_requested = arg2) != 0 /
+{
+ ntimes++;
+ self->fd = arg0;
+}
+
+/*
+ * When the write() system call returns, we know the actual
+ * number of bytes written. Report it.
+ */
+syscall::write:return
+/ self->nbytes_requested != 0 /
+{
+ printf("fd %d: bytes requested %d, actual %d\n",
+ self->fd, self->nbytes_requested, arg1);
+
+ /* free memory associated with self-> variables */
+ self->nbytes_requested = 0;
+ self->fd = 0;
+}
+
+/*
+ * Only report a limited number of times.
+ */
+syscall::write:return
+/ ntimes >= 5 /
+{
+ exit(0);
+}
diff --git a/examples/language_features/100list_probes.sh b/examples/language_features/100list_probes.sh
new file mode 100755
index 000000000..23bfd0525
--- /dev/null
+++ b/examples/language_features/100list_probes.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+# SYNOPSIS
+# ./100list_probes.sh
+#
+# DESCRIPTION
+# List all probes. There are many.
+
+sudo /usr/sbin/dtrace -l | head -10
+echo "[...]"
+sudo /usr/sbin/dtrace -l | tail -10
diff --git a/examples/language_features/101count_probes_by_provider.sh b/examples/language_features/101count_probes_by_provider.sh
new file mode 100755
index 000000000..e897a1062
--- /dev/null
+++ b/examples/language_features/101count_probes_by_provider.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# SYNOPSIS
+# ./101count_probes_by_provider.sh
+#
+# DESCRIPTION
+# The second column lists probes' providers. Count how
+# many probes there are for each provider. Use "tail" to
+# start at the second line of output, since the first line
+# has the column headers, which we want to ignore.
+
+sudo /usr/sbin/dtrace -l | tail -n +2 | awk '{print $2}' | sort | uniq -c
diff --git a/examples/language_features/102list_probe_arguments.sh b/examples/language_features/102list_probe_arguments.sh
new file mode 100755
index 000000000..3d6eff537
--- /dev/null
+++ b/examples/language_features/102list_probe_arguments.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+# SYNOPSIS
+# ./102list_probe_arguments.sh
+#
+# DESCRIPTION
+# Some providers provide typed arguments for (some of) their
+# probes. Use "dtrace -lv" for a verbose listing to see the
+# arguments and their types, if any.
+
+sudo /usr/sbin/dtrace -lv -n 'syscall::open:entry'
diff --git a/examples/language_features/110provider_profile.d b/examples/language_features/110provider_profile.d
new file mode 100755
index 000000000..7f9e75b7d
--- /dev/null
+++ b/examples/language_features/110provider_profile.d
@@ -0,0 +1,29 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./110provider_profile.d
+ *
+ * DESCRIPTION
+ * The profile provider has basically two kinds of probes:
+ * - profile probes fire on all CPUs each time period
+ * - tick probes fire only once each time period
+ * One can specify either a frequency or a time period.
+ */
+
+/*
+ * A profile probe is used with higher frequency to sample
+ * what is executing on the system.
+ */
+profile:::profile-10hz
+{
+ printf("CPU %d: running %s\n", cpu, execname);
+}
+
+/*
+ * A tick probe is used to fire once to stop data collection.
+ */
+profile:::tick-2sec
+{
+ exit(0);
+}
diff --git a/examples/language_features/120provider_proc.d b/examples/language_features/120provider_proc.d
new file mode 100755
index 000000000..7c442f39f
--- /dev/null
+++ b/examples/language_features/120provider_proc.d
@@ -0,0 +1,37 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./120provider_proc.d
+ *
+ * DESCRIPTION
+ * We can track when processes throughout their life cycle.
+ */
+
+proc:::create
+{
+ printf("%s %s\n", probename, args[0]->pr_fname);
+}
+
+proc:::exec
+{
+ printf("%s %s\n", probename, args[0]);
+}
+
+proc:::start
+{
+ printf("%s %s\n", probename, execname);
+}
+
+proc:::exit
+{
+ printf("%s %s\n", probename, execname);
+}
+
+/*
+ * A tick probe is used to fire once to stop data collection.
+ */
+profile:::tick-10sec
+{
+ exit(0);
+}
diff --git a/examples/language_features/130provider_sched_on_off_cpu.d b/examples/language_features/130provider_sched_on_off_cpu.d
new file mode 100755
index 000000000..0d927bc3d
--- /dev/null
+++ b/examples/language_features/130provider_sched_on_off_cpu.d
@@ -0,0 +1,28 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./130provider_sched_on_off_cpu.d
+ *
+ * DESCRIPTION
+ * We can track when processes start and end execution
+ * on a CPU.
+ */
+
+sched:::on-cpu
+{
+ printf("on CPU %d is %s\n", curcpu->cpu_id, curlwpsinfo->pr_name);
+}
+
+sched:::off-cpu
+{
+ printf("off CPU %d is %s\n", curcpu->cpu_id, args[0]->pr_name);
+}
+
+/*
+ * A tick probe is used to fire once to stop data collection.
+ */
+profile:::tick-2sec
+{
+ exit(0);
+}
diff --git a/examples/language_features/131provider_sched_enqueue_dequeue.d b/examples/language_features/131provider_sched_enqueue_dequeue.d
new file mode 100755
index 000000000..c773dc908
--- /dev/null
+++ b/examples/language_features/131provider_sched_enqueue_dequeue.d
@@ -0,0 +1,24 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./131provider_sched_enqueue_dequeue.d
+ *
+ * DESCRIPTION
+ * We can track when processes are enqueued and
+ * dequeued on CPUs.
+ */
+
+sched:::dequeue,
+sched:::enqueue
+{
+ printf(" %s %s\n", probename, args[0]->pr_name);
+}
+
+/*
+ * A tick probe is used to fire once to stop data collection.
+ */
+profile:::tick-2sec
+{
+ exit(0);
+}
diff --git a/examples/language_features/140provider_syscall.d b/examples/language_features/140provider_syscall.d
new file mode 100755
index 000000000..370e7063d
--- /dev/null
+++ b/examples/language_features/140provider_syscall.d
@@ -0,0 +1,20 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * SYNOPSIS
+ * sudo ./140provider_syscall.d
+ *
+ * DESCRIPTION
+ * With the syscall provider, you can probe the entry to
+ * and return from any system call, which is useful for
+ * watching how a program moves between user space and the
+ * kernel.
+ */
+
+/* probe on entry to system call write() */
+syscall::write:entry
+{
+ printf("write %d bytes to fd %d\n", args[2], args[0]);
+
+ exit(0);
+}
diff --git a/examples/language_features/150provider_fbt.d b/examples/language_features/150provider_fbt.d
new file mode 100755
index 000000000..6dd30e264
--- /dev/null
+++ b/examples/language_features/150provider_fbt.d
@@ -0,0 +1,48 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * SYNOPSIS
+ * sudo ./150provider_fbt.d
+ *
+ * DESCRIPTION
+ * Function boundary tracing (fbt) can be used to trace the
+ * beginning and end of just about any function in the kernel.
+ * As such, it is very powerful.
+ *
+ * That said, there are some challenges:
+ *
+ * - One must know the kernel fairly well. There may
+ * be tens of thousands of functions available to trace.
+ *
+ * - Functions that can be traced will vary from one
+ * kernel build to another. For example, a function
+ * might be inlined in a kernel build, making that
+ * function not traceable in that build.
+ *
+ * Also, there are both:
+ *
+ * - an fbt provider, which supports typed probe arguments
+ * (seen with "dtrace -lvP fbt")
+ *
+ * - a rawfbt provider, whose probe arguments are not typed
+ * nor specially ordered; traceable functions include
+ * compiler-generated optimized variants of functions,
+ * named <func>.<suffix>.
+ */
+
+/* probe on entry to kernel function ksys_write() */
+fbt::ksys_write:entry
+{
+ printf("write %d bytes to fd %d\n", args[2], args[0]);
+}
+
+/* do the same thing with a rawfbt probe, so the args are not typed */
+rawfbt::ksys_write:entry
+{
+ printf("write %d bytes to fd %d\n", arg2, arg0);
+}
+
+fbt::ksys_write:return
+{
+ exit(0);
+}
diff --git a/examples/language_features/160provider_sdt_rawtp.sh b/examples/language_features/160provider_sdt_rawtp.sh
new file mode 100755
index 000000000..92ac621eb
--- /dev/null
+++ b/examples/language_features/160provider_sdt_rawtp.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+# SYNOPSIS
+# ./160provider_sdt_rawtp.sh
+#
+# DESCRIPTION
+# Statically Defined Tracing (SDT) refers to probes placed
+# in the kernel source code by kernel developers to support
+# tracing in stable, semantically meaningful terms. In the
+# case of Linux, this means tracepoints.
+
+# You can see these tracepoints via the sdt provider.
+sudo /usr/sbin/dtrace -lP sdt
+
+# You can see the exact same probes via the rawtp provider.
+sudo /usr/sbin/dtrace -lP rawtp
+
+# The difference is that the rawtp provider gives DTrace users
+# access to the raw tracepoints exposed by the kernel tracing
+# system, including access to the untranslated arguments of the
+# associated tracepoint events. Regular tracepoints often expose
+# translated arguments based on the raw arguments that were passed
+# in the tracepoint call.
+
+# For example, the DTrace sched provider implements the "off-cpu"
+# probe by using "rawtp:sched::sched_switch" and the "wakeup" probe
+# by using "rawtp:sched::sched_wakeup". We can see how the typed
+# arguments for these probes depend on whether we are using the
+# sdt or the rawtp provider:
+
+sudo /usr/sbin/dtrace -lvn :sched::sched_switch | grep args
+sudo /usr/sbin/dtrace -lvn :sched::sched_wakeup | grep args
+
+# Here, the module "sched" is named, but the provider name,
+# expected before the first colon ":", is left blank as a
+# wildcard to pick up both providers with these probes.
diff --git a/examples/language_features/170provider_lockstat.sh b/examples/language_features/170provider_lockstat.sh
new file mode 100755
index 000000000..de7913a82
--- /dev/null
+++ b/examples/language_features/170provider_lockstat.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# SYNOPSIS
+# ./170provider_lockstat.sh
+#
+# DESCRIPTION
+# The lockstat provider can be used to study lock usage.
+# For example, here we count how many times spin locks
+# and adaptive locks are acquired by the command "date".
+
+sudo /usr/sbin/dtrace -qn '
+lockstat:::spin-acquire,
+lockstat:::adaptive-acquire
+/pid == $target/
+{
+ @locks[probename] = count();
+}' -c date
diff --git a/examples/language_features/171provider_io.d b/examples/language_features/171provider_io.d
new file mode 100755
index 000000000..b91ba6cf5
--- /dev/null
+++ b/examples/language_features/171provider_io.d
@@ -0,0 +1,31 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * SYNOPSIS
+ * sudo ./171provider_io.d
+ *
+ * DESCRIPTION
+ * The io provider can be used to study I/O operations.
+ * For example, here we print whenever an I/O operation
+ * is started over the course of ten seconds, reporting
+ * the device name and whether it is a read or write
+ * operation. Consult the documentation for more
+ * information on the probes and their arguments.
+ */
+
+BEGIN
+{
+ printf("%10s %2s\n", "DEVICE", "RW");
+}
+
+io:::start
+{
+ printf("%10s %2s\n",
+ args[1]->dev_statname,
+ args[0]->b_flags & B_READ ? "R" : "W");
+}
+
+tick-10s
+{
+ exit(0);
+}
diff --git a/examples/language_features/172provider_ip.d b/examples/language_features/172provider_ip.d
new file mode 100755
index 000000000..dce852fbd
--- /dev/null
+++ b/examples/language_features/172provider_ip.d
@@ -0,0 +1,26 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * SYNOPSIS
+ * sudo ./172provider_ip.d
+ *
+ * DESCRIPTION
+ * The ip provider can be used to study IP communications.
+ * Here is an example that tracks sends and receives,
+ * reporting their source and destination addresses for
+ * 10 seconds.
+ *
+ * Consult the documentation for further information about
+ * ip probe arguments.
+ */
+
+ip:::send,
+ip:::receive
+{
+ printf("%s: from %s to %s\n", probename, args[2]->ip_saddr, args[2]->ip_daddr);
+}
+
+tick-10s
+{
+ exit(0);
+}
diff --git a/examples/language_features/180provider_cpc.d b/examples/language_features/180provider_cpc.d
new file mode 100755
index 000000000..a2ce8b271
--- /dev/null
+++ b/examples/language_features/180provider_cpc.d
@@ -0,0 +1,52 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * SYNOPSIS
+ * sudo ./180provider_cpc.d
+ *
+ * DESCRIPTION
+ * The cpc (CPU Performance Counter) provider can be used
+ * profile activity based on hardware performance counters.
+ *
+ * For a list of cpc probes, use "dtrace -lP cpc".
+ *
+ * Probe specifications are of the form:
+ *
+ * cpc:::<event name>-<mode>-<count>
+ *
+ * The "event name" tells you which counters are available
+ * on your hardware.
+ *
+ * The "mode" can be "kernel", "user", or "all", even if
+ * only "all" is listed.
+ *
+ * The "count" indicates how many times the event is seen
+ * before the probe fires. If the listed "count" is not
+ * suitable for your purposes, you can specify a different
+ * value. It is usually best to start with a higher value,
+ * decreasing it if there are not enough probe firings,
+ * rather than starting too low and inundating your system
+ * with very many probe firings.
+ *
+ * Here, an event perf_count_sw_cpu_clock-all-1000000000
+ * was listed by "dtrace -lP cpc". We tweak the "mode"
+ * and "count" for our purposes. The probe will fire every
+ * 300 usecs of kernel activity. We use aggregations to
+ * count how many times each call stack is seen. The
+ * aggregation will be printed by default when the D
+ * script exits, after 10 seconds.
+ *
+ * Consult the documentation for further information about
+ * cpc probes.
+ */
+
+cpc:::perf_count_sw_cpu_clock-kernel-300000000
+{
+ @[stack()] = count();
+}
+
+/* run for only 10 seconds */
+tick-10s
+{
+ exit(0);
+}
diff --git a/examples/language_features/200built-in-variables-probe.d b/examples/language_features/200built-in-variables-probe.d
new file mode 100755
index 000000000..5d7e97260
--- /dev/null
+++ b/examples/language_features/200built-in-variables-probe.d
@@ -0,0 +1,18 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./200built-in-variables-probe.d
+ *
+ * DESCRIPTION
+ * We can get a probe's name components when it fires.
+ * The fully qualified name is provider:module:function:name,
+ * which we get with the built-in variables probeprov,
+ * probemod, probefunc, and probename, respectively.
+ */
+
+syscall:::entry
+{
+ printf("%s:%s:%s:%s\n", probeprov, probemod, probefunc, probename);
+ exit(0);
+}
diff --git a/examples/language_features/201built-in-variables-timestamps.d b/examples/language_features/201built-in-variables-timestamps.d
new file mode 100755
index 000000000..c07ee0456
--- /dev/null
+++ b/examples/language_features/201built-in-variables-timestamps.d
@@ -0,0 +1,31 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./201built-in-variables-timestamps.d
+ *
+ * DESCRIPTION
+ * Built-in variables provide timestamps:
+ *
+ * - timestamp counts nanoseconds since
+ * some arbitrary point in the past.
+ * Use differences between values to measure
+ * elapsed time. The value is captured only
+ * once per clause.
+ *
+ * - walltimestamp counts nanoseconds since
+ * 00:00 Universal Coordinated Time, January 1, 1970.
+ */
+
+dtrace:::BEGIN
+{
+ printf("\n%d %d\n", timestamp, walltimestamp);
+ printf( "%d %d\n", timestamp, walltimestamp);
+}
+
+dtrace:::BEGIN
+{
+ printf("\n%d %d\n", timestamp, walltimestamp);
+ printf( "%d %d\n", timestamp, walltimestamp);
+ exit(0);
+}
diff --git a/examples/language_features/202built-in-variables-args.d b/examples/language_features/202built-in-variables-args.d
new file mode 100755
index 000000000..192fff8e1
--- /dev/null
+++ b/examples/language_features/202built-in-variables-args.d
@@ -0,0 +1,28 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./202built-in-variables-args.d
+ *
+ * DESCRIPTION
+ * A probe's arguments can be accessed through the built-in
+ * variables arg0, arg1, arg2, etc. These are all signed,
+ * 64-bit integers, whose meanings depend on the probe.
+ *
+ * Some probes have typed arguments args[0], args[1], args[2],
+ * etc. To see the types, use "dtrace -lvn $probe". Their
+ * meanings are described in the documentation.
+ *
+ * When arguments are typed, they may also be reordered.
+ * So there may be no correspondence between, say, arg0
+ * and args[0].
+ *
+ * Typically, it is better to use the typed args[] when
+ * the probe has them.
+ */
+
+syscall::write:entry
+{
+ printf("Write %d bytes to fd %d\n", args[2], arg0);
+ exit(0);
+}
diff --git a/examples/language_features/203built-in-variables-process-info.d b/examples/language_features/203built-in-variables-process-info.d
new file mode 100755
index 000000000..82600ba9e
--- /dev/null
+++ b/examples/language_features/203built-in-variables-process-info.d
@@ -0,0 +1,31 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./203built-in-variables-process-info.d
+ *
+ * DESCRIPTION
+ * A number of built-in variables describe the process
+ * that is running.
+ */
+
+syscall::write:entry
+{
+ printf("\n\n");
+ printf("The CPU is %d (%d).\n", curcpu->cpu_id, cpu);
+
+ printf("\n");
+ printf("The exec name can be accessed through\n");
+ printf(" the struct task_struct: %s\n", curthread->comm);
+ printf(" or a built-in variable: %s\n", execname);
+
+ printf("\n");
+ printf("The execargs are: %s\n", execargs);
+
+ printf("\n");
+ printf("The group id and user id are %d and %d.\n", gid, uid);
+ printf("The process id and thread id are %d and %d.\n", pid, tid);
+ printf("The parent process id is %d.\n\n", ppid);
+
+ exit(0);
+}
diff --git a/examples/language_features/204built-in-variables-uregs.d b/examples/language_features/204built-in-variables-uregs.d
new file mode 100755
index 000000000..55e333218
--- /dev/null
+++ b/examples/language_features/204built-in-variables-uregs.d
@@ -0,0 +1,31 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./204built-in-variables-uregs.d
+ *
+ * DESCRIPTION
+ * The uregs[] array can be used to access the current thread's
+ * saved user-mode register values at probe firing time. The
+ * available registers depend on the chip architecture:
+ *
+ * - x86_64
+ * R_SP R_PC R_FP R_TRAPNO R_ERR
+ * R_CS R_DS R_ES R_FS R_GS R_PS R_SS
+ * R_RSP R_EBP R_RFL R_RIP R_RDI R_RSI R_RAX R_RBX R_RCX R_RDX
+ * R_ESP R_RBP R_EFL R_EIP R_EDI R_ESI R_EAX R_EBX R_ECX R_EDX
+ * R_R0 R_R1 R_R8 R_R9 R_R10 R_R11 R_R12 R_R13 R_R14 R_R15
+ *
+ * - aarch64:
+ * R_SP R_PC R_PSTATE R_FP
+ * R_X0 R_X1 R_X2 R_X3 R_X4 R_X5 R_X6 R_X7 R_X8 R_X9
+ * R_X10 R_X11 R_X12 R_X13 R_X14 R_X15 R_X16 R_X17 R_X18 R_X19
+ * R_X20 R_X21 R_X22 R_X23 R_X24 R_X25 R_X26 R_X27 R_X28 R_X29
+ * R_X30
+ */
+
+BEGIN
+{
+ printf("0x%x 0x%x\n", uregs[R_PC], uregs[R_SP]);
+ exit(0);
+}
diff --git a/examples/language_features/300actions-exit.sh b/examples/language_features/300actions-exit.sh
new file mode 100755
index 000000000..fea6cb50d
--- /dev/null
+++ b/examples/language_features/300actions-exit.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# SYNOPSIS
+# sudo ./300actions-exit.sh
+#
+# DESCRIPTION
+# The exit() action terminates the script, returning an
+# unsigned 8-bit integer value.
+
+/usr/sbin/dtrace -n '
+BEGIN
+{
+ x = 123;
+ y = 456;
+ exit(x < y ? x : y);
+}'
+
+echo $?
diff --git a/examples/language_features/301actions-print.d b/examples/language_features/301actions-print.d
new file mode 100755
index 000000000..0b3742644
--- /dev/null
+++ b/examples/language_features/301actions-print.d
@@ -0,0 +1,32 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./301actions-print.d
+ *
+ * DESCRIPTION
+ * There are multiple ways to examine data values.
+ */
+
+BEGIN
+{
+ /* printf() is a C-like formatted print */
+ /* note: %d can be used with any size of integer */
+ printf("%c %d %s\n", 'a', 1234ll, "hello");
+
+ /* trace() uses data-type information to format */
+ trace('a');
+ trace(1234);
+ trace("hello");
+
+ /* tracemem() dumps a specified number of bytes */
+ tracemem(`linux_banner, 64);
+
+ /*
+ * print() uses data-type information to print and annotate
+ * contents at a pointer
+ */
+ print(curthread);
+
+ exit(0);
+}
diff --git a/examples/language_features/302actions-strings.d b/examples/language_features/302actions-strings.d
new file mode 100755
index 000000000..097eff064
--- /dev/null
+++ b/examples/language_features/302actions-strings.d
@@ -0,0 +1,45 @@
+#!/usr/sbin/dtrace -s
+
+#pragma D option quiet
+
+/*
+ * SYNOPSIS
+ * sudo ./302actions-strings.d
+ *
+ * DESCRIPTION
+ * There are functions to manipulate strings.
+ */
+
+BEGIN
+{
+ /* find the length of a string */
+ printf("length of 'abcde' is %d\n", strlen("abcde"));
+
+ /* various other functions also resemble libc */
+ printf("text starts with first 'd': %s\n", strchr("abcdefedbca", 'd'));
+ printf("text starts with last 'd': %s\n", strrchr("abcdefedbca", 'd'));
+ printf("text starts with 'def': %s\n", strstr("abcdefedbca", "def"));
+
+ /* break a string up into tokens */
+ printf("token #1: %s\n", strtok("hello world", " "));
+ printf("token #2: %s\n", strtok(NULL, " "));
+
+ /* join (concatenate) strings */
+ printf("join 'abc' and 'def': %s\n", strjoin("abc", "def"));
+
+ /* dump part of a string */
+ printf("start at char #4: %s\n", substr("abcdefghij", 4));
+
+ /* dump part of a string, only 2 chars */
+ printf("start at char #4: %s\n", substr("abcdefghij", 4, 2));
+
+ /* find index of a substring */
+ printf("found at char #%d\n", index("abcdefghij", "def"));
+ printf("found at char #%d\n", rindex("abcdefghij", "def"));
+ printf("found at char #%d\n", index("abcdefghij", "XXXX"));
+
+ /* convert an integer to a string */
+ printf("123000 + 456 = %s\n", lltostr(123000 + 456));
+
+ exit(0);
+}
diff --git a/examples/language_features/303actions-strings-paths.d b/examples/language_features/303actions-strings-paths.d
new file mode 100755
index 000000000..9588d08f5
--- /dev/null
+++ b/examples/language_features/303actions-strings-paths.d
@@ -0,0 +1,25 @@
+#!/usr/sbin/dtrace -s
+
+#pragma D option quiet
+
+/*
+ * SYNOPSIS
+ * sudo ./303actions-strings-paths.d
+ *
+ * DESCRIPTION
+ * There are functions to manipulate strings, specifically path names.
+ */
+
+BEGIN
+{
+ /* find the base name of a path */
+ printf("base is %s\n", basename("/usr/sbin/dtrace"));
+
+ /* find the directory of a path */
+ printf("directory is %s\n", dirname("/usr/sbin/dtrace"));
+
+ /* clean up a path name */
+ printf("cleaned up path is %s\n", cleanpath("////usr/bin/../sbin/././//dtrace"));
+
+ exit(0);
+}
diff --git a/examples/language_features/304actions-system.d b/examples/language_features/304actions-system.d
new file mode 100755
index 000000000..001566808
--- /dev/null
+++ b/examples/language_features/304actions-system.d
@@ -0,0 +1,22 @@
+#!/usr/sbin/dtrace -s
+
+#pragma D option quiet
+#pragma D option destructive
+
+/*
+ * SYNOPSIS
+ * sudo ./304actions-system.d
+ *
+ * DESCRIPTION
+ * One can launch system calls from within D script,
+ * but this must be explicitly allowed with the "destructive"
+ * option or dtrace -w switch.
+ */
+
+BEGIN
+{
+ system("ls");
+ system("echo hello world");
+
+ exit(0);
+}
diff --git a/examples/language_features/305actions-progenyof.d b/examples/language_features/305actions-progenyof.d
new file mode 100755
index 000000000..2aa3e8ea3
--- /dev/null
+++ b/examples/language_features/305actions-progenyof.d
@@ -0,0 +1,20 @@
+#!/usr/sbin/dtrace -s
+
+#pragma D option quiet
+
+/*
+ * SYNOPSIS
+ * sudo ./305actions-progenyof.d
+ *
+ * DESCRIPTION
+ * One can test whether one is progeny of another process.
+ */
+
+BEGIN
+{
+ printf("I am%s progeny of pid 1234\n", progenyof(1234) ? "" : " not");
+ printf("I am%s progeny of myself\n", progenyof(pid) ? "" : " not");
+ printf("I am%s progeny of my parent\n", progenyof(ppid) ? "" : " not");
+
+ exit(0);
+}
diff --git a/examples/language_features/306actions-speculations.d b/examples/language_features/306actions-speculations.d
new file mode 100755
index 000000000..7e0d21370
--- /dev/null
+++ b/examples/language_features/306actions-speculations.d
@@ -0,0 +1,57 @@
+#!/usr/sbin/dtrace -s
+
+#pragma D option quiet
+
+/*
+ * SYNOPSIS
+ * sudo ./306actions-speculations.d
+ *
+ * DESCRIPTION
+ * In DTrace, one can write output speculatively, deciding at a
+ * later time whether to commit or discard the speculative output.
+ */
+#pragma D option nspec=2
+
+BEGIN
+{
+ /* create two speculations */
+ s1 = speculation();
+ s2 = speculation();
+}
+
+BEGIN
+{
+ /* the clause has "speculate()" before data recording */
+ speculate(s1);
+ printf("one\n");
+}
+
+BEGIN
+{
+ speculate(s2);
+ printf("two\n");
+}
+
+BEGIN
+{
+ speculate(s1);
+ printf("three\n");
+}
+
+BEGIN
+{
+ speculate(s2);
+ printf("four\n");
+}
+
+BEGIN
+{
+ commit(s1); /* commit "one" "three" output */
+ discard(s2); /* discard "two" "four" output */
+}
+
+BEGIN
+{
+ /* cannot be in same clause as commit/discard */
+ exit(0);
+}
diff --git a/examples/language_features/307actions-callstack.d b/examples/language_features/307actions-callstack.d
new file mode 100755
index 000000000..8e3d6fe47
--- /dev/null
+++ b/examples/language_features/307actions-callstack.d
@@ -0,0 +1,54 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * SYNOPSIS
+ * sudo ./307actions-callstack.d
+ *
+ * DESCRIPTION
+ * In DTrace, one can get information about the call stack.
+ */
+
+/* have a probe fire somewhere in the kernel */
+fbt::ksys_write:entry
+{
+ /* dump the kernel call stack */
+ stack();
+
+ /* a built-in variable gives the number of frames */
+ printf("%d frames\n", stackdepth);
+
+ /* another built-in variable gives the caller PC */
+ printf("second frame is the caller %p\n", caller);
+
+ /* we can get the symbolic name of its module */
+ printf( " module "); mod(caller);
+
+ /* we can get the symbolic name of its function */
+ printf("\n function "); func(caller);
+
+ /* sym() is an alias for func() */
+ printf("\n == symbol"); sym(caller);
+
+ /*
+ * Similarly, we can also get the user-space call stack
+ * through ustack(). The related built-in variables are
+ * ustackdepth and ucaller. Conversion to symbolic names
+ * can be made via umod(), ufunc(), usym(), and uaddr().
+ * User-space call stacks face a few challenges:
+ *
+ * - The BPF helper functions rely on frame-pointer
+ * chasing, which can be impaired or even incorrect
+ * unless -fno-omit-frame-pointer is specified.
+ *
+ * - Conversion to symbolic names does not take place when
+ * the probe fires but later, in user space, when results
+ * are printed. It is possible that the user application
+ * has already terminated and the information about its
+ * address space gone.
+ *
+ * - For a stripped executable, you must specify
+ * --export-dynamic when linking the program.
+ */
+
+ exit(0);
+}
diff --git a/examples/language_features/310actions-alloca-copy.d b/examples/language_features/310actions-alloca-copy.d
new file mode 100755
index 000000000..1a48c696b
--- /dev/null
+++ b/examples/language_features/310actions-alloca-copy.d
@@ -0,0 +1,95 @@
+#!/usr/sbin/dtrace -qs
+
+#pragma D option strsize=32
+
+/*
+ * SYNOPSIS
+ * sudo ./310actions-alloca-copy.d
+ *
+ * DESCRIPTION
+ * A DTrace program has scratch memory that it manages
+ * for its own purposes. The program can allocate scratch
+ * memory as well as copy into, out of, and between buffers.
+ * It is automatically freed at the end of each clause.
+ */
+
+/* alloca */
+BEGIN
+{
+ /* alloca() a string */
+ ptr = (string *) alloca(32);
+
+ /* set its contents (truncated to strsize chars, including NUL) */
+ *ptr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ /* print it */
+ trace(*ptr);
+
+ /* end of the clause: ptr is freed */
+}
+
+/* bcopy */
+BEGIN
+{
+ /* alloca() a string */
+ ptr = (string *) alloca(32);
+
+ /* copy from kernel memory to scratch memory */
+ bcopy(`linux_banner, ptr, 32);
+
+ /* print it */
+ printf("\n%s", *ptr);
+
+ /* end of the clause: ptr is freed */
+}
+
+/* copyinto */
+syscall::write:entry
+{
+ /* alloca() a string */
+ ptr = (string *) alloca(32);
+
+ /* copy from user space into scratch memory */
+ copyinto(arg1, 32, ptr);
+
+ /* print it */
+ printf("\n%s to fd %d, %d bytes", *ptr, arg0, arg2);
+
+ /* end of the clause: ptr is freed */
+}
+
+/* copyin */
+syscall::write:entry
+{
+ /* copy from user space to scratch memory, allocating the pointer */
+ ptr = copyin(arg1, 32);
+
+ /* print it */
+ printf("\n%s to fd %d, %d bytes", *ptr, arg0, arg2);
+
+ /* end of the clause: ptr is freed */
+}
+
+/* copyinstr */
+syscall::write:entry
+{
+ /* copy string from user space to scratch memory, allocating the pointer */
+ str = copyinstr(arg1);
+
+ /* print it */
+ printf("\n%s to fd %d, %d bytes", str, arg0, arg2);
+
+ /* end of the clause: ptr is freed */
+}
+
+/*
+ * There are also copyout() and copyoutstr() functions, that may be
+ * used to copy from scratch memory to user-space buffers. Since they
+ * alter the behavior of the user code, the "destructive" option -w
+ * must be specified.
+ */
+
+syscall::write:entry
+{
+ exit(0);
+}
diff --git a/examples/language_features/311actions-rand.d b/examples/language_features/311actions-rand.d
new file mode 100755
index 000000000..54500fb3b
--- /dev/null
+++ b/examples/language_features/311actions-rand.d
@@ -0,0 +1,25 @@
+#!/usr/sbin/dtrace -qs
+
+/*
+ * SYNOPSIS
+ * sudo ./311actions-rand.d
+ *
+ * DESCRIPTION
+ * The rand() function generates a random integer.
+ */
+
+BEGIN
+{
+ printf(" %3d\n", rand() & 0xff);
+ printf(" %3d\n", rand() & 0xff);
+ printf(" %3d\n", rand() & 0xff);
+ printf(" %3d\n", rand() & 0xff);
+ printf(" %3d\n", rand() & 0xff);
+ printf(" %3d\n", rand() & 0xff);
+ printf(" %3d\n", rand() & 0xff);
+ printf(" %3d\n", rand() & 0xff);
+ printf(" %3d\n", rand() & 0xff);
+ printf(" %3d\n", rand() & 0xff);
+
+ exit(0);
+}
diff --git a/examples/language_features/500aggregations-intro.d b/examples/language_features/500aggregations-intro.d
new file mode 100755
index 000000000..54b5cbe6b
--- /dev/null
+++ b/examples/language_features/500aggregations-intro.d
@@ -0,0 +1,24 @@
+#!/usr/sbin/dtrace -s
+
+#pragma D option quiet
+
+/*
+ * SYNOPSIS
+ * sudo ./500aggregations-intro.d
+ *
+ * DESCRIPTION
+ * Aggregations can be used to collect statistical data on
+ * some value. Results are printed by default when the
+ * script terminates.
+ */
+
+tick-20hz
+{
+ /* do not even bother naming the aggregation; just "@" */
+ @ = count();
+}
+
+tick-1sec
+{
+ exit(0);
+}
diff --git a/examples/language_features/501aggregations-names-keys.d b/examples/language_features/501aggregations-names-keys.d
new file mode 100755
index 000000000..06ede5301
--- /dev/null
+++ b/examples/language_features/501aggregations-names-keys.d
@@ -0,0 +1,19 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ * SYNOPSIS
+ * sudo ./501aggregations-names-keys.d
+ *
+ * DESCRIPTION
+ * Aggregations can be named or use keys.
+ */
+
+tick-20hz
+{
+ @my_count[(timestamp % 2 == 0) ? "even" : "odd"] = count();
+}
+
+tick-1sec
+{
+ exit(0);
+}
diff --git a/examples/language_features/502aggregations-basic-funcs.d b/examples/language_features/502aggregations-basic-funcs.d
new file mode 100755
index 000000000..b55a42117
--- /dev/null
+++ b/examples/language_features/502aggregations-basic-funcs.d
@@ -0,0 +1,26 @@
+#!/usr/sbin/dtrace -s
+
+# pragma D option quiet
+
+/*
+ * SYNOPSIS
+ * sudo ./501aggregations-basic-funcs.d
+ *
+ * DESCRIPTION
+ * Aggregations can include basic statistical functions.
+ */
+
+tick-20hz
+{
+ @my_count["count"] = count();
+ @my_sum["sum"] = sum(timestamp);
+ @my_avg["average"] = avg(timestamp);
+ @my_stddev["standard deviation"] = stddev(timestamp);
+ @my_min["minimum"] = min(timestamp);
+ @my_max["maximum"] = max(timestamp);
+}
+
+tick-1sec
+{
+ exit(0);
+}
diff --git a/examples/language_features/503aggregations-stack.d b/examples/language_features/503aggregations-stack.d
new file mode 100755
index 000000000..3e297c34b
--- /dev/null
+++ b/examples/language_features/503aggregations-stack.d
@@ -0,0 +1,24 @@
+#!/usr/sbin/dtrace -s
+
+# pragma D option quiet
+
+/*
+ * SYNOPSIS
+ * sudo ./503aggregations-stack.d
+ *
+ * DESCRIPTION
+ * An interesting key to use is "stack()", giving you
+ * information, for example, about hot kernel call stacks.
+ * Each distinct kernel call stack found will be reported
+ * along with the number of times it was encountered.
+ */
+
+tick-20hz
+{
+ @[stack()] = count();
+}
+
+tick-1sec
+{
+ exit(0);
+}
diff --git a/examples/language_features/504aggregations-printa.d b/examples/language_features/504aggregations-printa.d
new file mode 100755
index 000000000..6867511e2
--- /dev/null
+++ b/examples/language_features/504aggregations-printa.d
@@ -0,0 +1,29 @@
+#!/usr/sbin/dtrace -s
+
+# pragma D option quiet
+
+/*
+ * SYNOPSIS
+ * sudo ./504aggregations-printa.d
+ *
+ * DESCRIPTION
+ * While aggregations are printed by default when the D
+ * script terminates, it can be useful to print aggregations
+ * explicitly using the printa() function -- either to use
+ * detailed formatting or if results should be printed
+ * while the script is still running. In addition to the
+ * usual formatting directives used by printf(), printa()
+ * also uses "@" directives for the aggregation values.
+ */
+
+tick-20hz
+{
+ @["key"] = count();
+}
+
+tick-1sec
+{
+ printa("KEY BEFORE VALUE: %s %@d\n", @);
+ printa("VALUE BEFORE KEY: %@d %s\n", @);
+ exit(0);
+}
diff --git a/examples/language_features/505aggregations-quantize.d b/examples/language_features/505aggregations-quantize.d
new file mode 100755
index 000000000..5ae382843
--- /dev/null
+++ b/examples/language_features/505aggregations-quantize.d
@@ -0,0 +1,65 @@
+#!/usr/sbin/dtrace -s
+
+# pragma D option quiet
+
+/*
+ * SYNOPSIS
+ * sudo ./505aggregations-quantize.d
+ *
+ * DESCRIPTION
+ * While avg(), stddev(), min(), and max() are useful for
+ * characterizing the distribution of values crudely, one
+ * may also be interested in more detail on a distribution.
+ *
+ * Aggregations can count by value after the value has been
+ * "quantized" -- that is, grouped into bins.
+ */
+
+BEGIN
+{
+ /* time origin at the beginning of the script's execution */
+ t0 = timestamp;
+
+ /* for this example, use some dummy value that will change in scale */
+ dummy = t0;
+}
+
+tick-20hz
+{
+ /*
+ * If you have no sense for the distribution of values --
+ * not even of the scale -- then quantize(val) can be a
+ * good starting point. Its only input parameter is the
+ * value. Bins are powers of two -- you reduce values
+ * log2() -- giving you a sense of the scale of the values.
+ */
+ @crude = quantize(dummy >>= 1);
+
+ /*
+ * But perhaps you know the scale and want to chop some
+ * range of values up linearly. So we use lquantize().
+ */
+ @linear = lquantize(
+ (timestamp - t0) / 1000000, /* number of msecs since D script start */
+ 0, /* lower bound */
+ 2000, /* upper bound (msecs in 2 secs) */
+ 200); /* number per bin */
+
+ /*
+ * Finally, and this is a little complicated, what if you
+ * liked the original, logarithmic quantization, but you
+ * just want a little more detail. Then, there is a
+ * log-linear quantization.
+ */
+ @log_linear = llquantize(
+ dummy, /* number of msecs since some arbitrary time in the past */
+ 100, /* use log10() */
+ 3, /* lower bound is 10 to the 3 = 1000 */
+ 5, /* upper bound is 10 to the 9 = 1000000000 */
+ 4); /* number of steps per logarithmic range */
+}
+
+tick-2sec
+{
+ exit(0);
+}
diff --git a/examples/language_features/506aggregations-clear-trunc.d b/examples/language_features/506aggregations-clear-trunc.d
new file mode 100755
index 000000000..26314d8a8
--- /dev/null
+++ b/examples/language_features/506aggregations-clear-trunc.d
@@ -0,0 +1,63 @@
+#!/usr/sbin/dtrace -s
+
+# pragma D option quiet
+
+/*
+ * SYNOPSIS
+ * sudo ./506aggregations-clear-trunc.d
+ *
+ * DESCRIPTION
+ * Here, we show clear() and trunc(), used with aggregations.
+ *
+ * One reason to use printa() is to get aggregation values
+ * periodically while the D script is executing. In that
+ * case, however, you may want to reset the aggregations.
+ * There are two ways of doing so.
+ */
+
+tick-20hz
+{
+ /* in this example, consider two aggregations */
+
+ /*
+ * "parity" counts whether the timestamp is even or odd.
+ * In each one-second time interval, both cases should
+ * get some values.
+ */
+ @parity[(timestamp & 1) ? "odd" : "even"] = count();
+
+ /*
+ * "low_bits" counts how often the low bits (0-255) appear.
+ * It is reasonable that some keys will not reappear.
+ */
+ @low_bits[timestamp & 0xff] = count();
+}
+
+tick-1sec
+{
+ /*
+ * Every second, we print the values for the recent
+ * one-second interval.
+ */
+ printa("parity: %-4s %@2d\n", @parity);
+ printa("low bits: %3d %@d\n", @low_bits);
+
+ /*
+ * We clear out the "parity" values, leaving the keys,
+ * since almost surely those keys will recur. And if
+ * a key ends up with no counts, we want to know about it!
+ */
+ clear(@parity);
+
+ /*
+ * We trunc() (truncate) "low_bits", however, since keys
+ * might not reoccur. Unused keys take up memory and
+ * pollute the periodic output.
+ */
+ trunc(@low_bits);
+}
+
+tick-4sec
+{
+ exit(0);
+}
diff --git a/examples/language_features/507aggregations-trunc5.d b/examples/language_features/507aggregations-trunc5.d
new file mode 100755
index 000000000..ca5fdae02
--- /dev/null
+++ b/examples/language_features/507aggregations-trunc5.d
@@ -0,0 +1,50 @@
+#!/usr/sbin/dtrace -s
+
+# pragma D option quiet
+
+/*
+ * SYNOPSIS
+ * sudo ./507aggregations-trunc5.d
+ *
+ * DESCRIPTION
+ * Here, is another use of trunc() -- with an additional
+ * argument to focus attention on the top values.
+ */
+
+BEGIN
+{
+ /*
+ * The mask will change size. When it is wide, it will
+ * spread values over many keys. When it is narrow, it
+ * will concentrate values over a few keys. So, some
+ * keys will get many values, while others will get few.
+ */
+ mask = 255;
+}
+
+tick-100hz
+{
+ /* the aggregation */
+ @[timestamp & mask] = count();
+
+ /* update the mask */
+ mask >>= 1;
+ mask = (mask == 0) ? 255 : mask;
+}
+
+tick-1sec
+{
+ printf("entire result\n");
+ printa(" %3d %@3d\n", @);
+
+ trunc(@, 5);
+
+ printf("top 5 keys\n");
+ printa(" %3d %@3d\n", @);
+
+ /*
+ * On exit, we will no longer print the aggregation
+ * by default, since it was just printed.
+ */
+ exit(0);
+}
diff --git a/examples/language_features/508aggregations-normalize.d b/examples/language_features/508aggregations-normalize.d
new file mode 100755
index 000000000..5c2429f74
--- /dev/null
+++ b/examples/language_features/508aggregations-normalize.d
@@ -0,0 +1,49 @@
+#!/usr/sbin/dtrace -s
+
+# pragma D option quiet
+
+/*
+ * SYNOPSIS
+ * sudo ./508aggregations-normalize.d
+ *
+ * DESCRIPTION
+ * Here, is another use of trunc() -- with an additional
+ * argument to focus attention on the top values.
+ */
+
+BEGIN
+{
+ treport = timestamp;
+ ttick = timestamp;
+}
+
+/* add the number of nanoseconds since the last tick */
+tick-100hz
+{
+ @ = sum(timestamp - ttick);
+ ttick = timestamp;
+}
+
+/* report at erratic intervals */
+tick-3100ms,
+tick-3600ms
+{
+ /* determine number of usecs since last report */
+ this->us_since_last = (timestamp - treport) / 1000;
+ treport = timestamp;
+ printf("%8d usecs since the last report\n", this->us_since_last);
+
+ /* normalize the total number of nsecs by the number of usecs */
+ normalize(@, this->us_since_last);
+
+ /* report aggregation (do not worry about formatting) */
+ printa(@);
+
+ /* clear the aggregation before resuming */
+ clear(@);
+}
+
+tick-12sec
+{
+ exit(0);
+}
--
2.47.3
More information about the DTrace-devel
mailing list