[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