[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