[DTrace-devel] [PATCH] examples: Add "language features" demo scripts

Ruud van der Pas ruud.vanderpas at oracle.com
Tue Sep 2 21:07:20 UTC 2025


Reviewed-by: Ruud van der Pas <ruud.vanderpas at oracle.com>

> On 2 Sep 2025, at 22:02, eugene.loh at oracle.com wrote:
> 
> 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