[DTrace-devel] [PATCH] examples: add a new set of scripts

eugene.loh at oracle.com eugene.loh at oracle.com
Thu Oct 16 01:31:53 UTC 2025


From: Eugene Loh <eugene.loh at oracle.com>

This is a set of new example scripts.  These are basic programs to
demonstrate specific functionality.  For example to get an overview
of system calls executed, processes running, I/O statistics, etc.
There is also an example of a D script embedded in a shell script.

Signed-off-by: Ruud van der Pas <ruud.vanderpas at oracle.com>
---
 examples/getting-started/activity.d      | 110 ++++++++++++++++++
 examples/getting-started/activity1.d     | 126 +++++++++++++++++++++
 examples/getting-started/calltrace.d     |  88 +++++++++++++++
 examples/getting-started/countcalls.d    |  38 +++++++
 examples/getting-started/countprogs.d    |  37 ++++++
 examples/getting-started/countsyscalls.d |  31 ++++++
 examples/getting-started/cswpercpu.d     |  81 ++++++++++++++
 examples/getting-started/daterun.d       |  35 ++++++
 examples/getting-started/diskact.d       |  99 +++++++++++++++++
 examples/getting-started/errno.d         |  48 ++++++++
 examples/getting-started/errno1.d        | 136 +++++++++++++++++++++++
 examples/getting-started/execcalls.d     |  44 ++++++++
 examples/getting-started/fsact.sh        | 109 ++++++++++++++++++
 examples/getting-started/goodbye.d       |  29 +++++
 examples/getting-started/hello.d         |  21 ++++
 examples/getting-started/readsizes.d     |  39 +++++++
 examples/getting-started/readtrace.d     |  65 +++++++++++
 examples/getting-started/readtrace1.d    |  71 ++++++++++++
 examples/getting-started/rwdiskact.d     | 110 ++++++++++++++++++
 examples/getting-started/syscalls.d      |  44 ++++++++
 examples/getting-started/syscalls1.d     |  53 +++++++++
 examples/getting-started/tick.d          |  48 ++++++++
 examples/getting-started/tick1.d         |  49 ++++++++
 examples/getting-started/wrun.d          |  48 ++++++++
 24 files changed, 1559 insertions(+)
 create mode 100755 examples/getting-started/activity.d
 create mode 100755 examples/getting-started/activity1.d
 create mode 100755 examples/getting-started/calltrace.d
 create mode 100755 examples/getting-started/countcalls.d
 create mode 100755 examples/getting-started/countprogs.d
 create mode 100755 examples/getting-started/countsyscalls.d
 create mode 100755 examples/getting-started/cswpercpu.d
 create mode 100755 examples/getting-started/daterun.d
 create mode 100755 examples/getting-started/diskact.d
 create mode 100755 examples/getting-started/errno.d
 create mode 100755 examples/getting-started/errno1.d
 create mode 100755 examples/getting-started/execcalls.d
 create mode 100755 examples/getting-started/fsact.sh
 create mode 100755 examples/getting-started/goodbye.d
 create mode 100755 examples/getting-started/hello.d
 create mode 100755 examples/getting-started/readsizes.d
 create mode 100755 examples/getting-started/readtrace.d
 create mode 100755 examples/getting-started/readtrace1.d
 create mode 100755 examples/getting-started/rwdiskact.d
 create mode 100755 examples/getting-started/syscalls.d
 create mode 100755 examples/getting-started/syscalls1.d
 create mode 100755 examples/getting-started/tick.d
 create mode 100644 examples/getting-started/tick1.d
 create mode 100755 examples/getting-started/wrun.d

diff --git a/examples/getting-started/activity.d b/examples/getting-started/activity.d
new file mode 100755
index 000000000..8a5b687aa
--- /dev/null
+++ b/examples/getting-started/activity.d
@@ -0,0 +1,110 @@
+/*
+ *  NAME
+ *    activity.d - report on process create, exec and exit
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s activity.d
+ *
+ *  DESCRIPTION
+ *    Show the processes that are created, executed and exited
+ *    while the script is running.
+ *
+ *  NOTES
+ *    - This script uses the proc provider to trace the following process
+ *    activities: create, exec, and exit.
+ *
+ *    - This script is guaranteed to produce results if you start one or
+ *    more commands while the script is running.  There are two ways to do
+ *    this:
+ *    o Execute this script in the background, and type in the command(s).
+ *    o Alternatively, run the script in the foreground and type the
+ *    command(s) in a separate terminal window on the same system.
+ *
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - Associative arrays are used to store the information from the
+ *    proc provider.
+ *
+ *    - The DTrace User Guide documents the proc provider probe
+ *    arguments like args[0] and also structures like psinfo_t.  It is
+ *    strongly recommended to check the documentation for this info.
+ */
+
+/*
+ *  Fires when a process (or process thread) is created using fork() or
+ *  vfork(), which both invoke clone().  The psinfo_t corresponding to
+ *  the new child process is pointed to by args[0].
+ */
+proc:::create
+{
+/*
+ *  Store the PID of both the parent and child process from the psinfo_t
+ *  structure pointed to by args[0].  Use 3 associative arrays to store the
+ *  various items of interest.
+ */
+  childpid  = args[0]->pr_pid;
+  parentpid = args[0]->pr_ppid;
+
+/*
+ *  Store the parent PID of the new child process.
+ */
+  p_pid[childpid] = parentpid;
+
+/*
+ *  Parent command name.
+ */
+  p_name[childpid] = execname;
+
+/*
+ *  Child has not yet been exec'ed.
+ */
+  p_exec[childpid] = "";
+}
+
+/*
+ *  The process starts.  In case proc:::create has fired, store the
+ *  absolute time and the full name of the child process.
+ */
+proc:::exec
+/ p_pid[pid] != 0 /
+{
+  time[pid]   = timestamp;
+  p_exec[pid] = args[0];
+}
+
+/*
+ *  The process starts, but in this case, proc:::create has not fired.
+ *  In addition to storing the name of the child process, store the
+ *  various other items of interest.
+ */
+proc:::exec
+/ p_pid[pid] == 0 /
+{
+  time[pid]   = timestamp;
+  p_exec[pid] = args[0];
+  p_pid[pid]  = ppid;
+  p_name[pid] = execname;
+}
+
+/*
+ *  The process exits.  Print the information.
+ */
+proc:::exit
+/p_pid[pid] != 0 && p_exec[pid] != ""/
+{
+  printf("%-16s (%d) executed %s (%d) for %d microseconds\n",
+    p_name[pid], p_pid[pid], p_exec[pid], pid, (timestamp - time[pid])/1000);
+}
+
+/*
+ *  The process has forked itself and exits.  Print the information.
+ */
+proc:::exit
+/p_pid[pid] != 0 && p_exec[pid] == ""/
+{
+  printf("%-16s (%d) forked itself (as %d) for %d microseconds\n",
+    p_name[pid], p_pid[pid], pid, (timestamp - time[pid])/1000);
+}
diff --git a/examples/getting-started/activity1.d b/examples/getting-started/activity1.d
new file mode 100755
index 000000000..692e8c343
--- /dev/null
+++ b/examples/getting-started/activity1.d
@@ -0,0 +1,126 @@
+/*
+ *  NAME
+ *    activity1.d - report on process create, exec and exit
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s activity1.d '"bash"'
+ *
+ *  DESCRIPTION
+ *    Show the processes that are created, executed and exited
+ *    in the bash shell while the script is running.
+ *
+ *  NOTES
+ *    - This script uses the proc provider to trace the following process
+ *    activities: create, exec, and exit.
+ *
+ *    - A predicate is used to ensure that only those processes executed
+ *    by bash are traced.  While this could be hard coded, here the name
+ *    is passed in as an argument.
+ *
+ *    - This script is guaranteed to produce results if you execute
+ *    one or more commands while the script is running.  There are two
+ *    ways to do this:
+ *    o Execute this script in the background, and type in the command(s).
+ *    o Alternatively, run the script in the foreground and type the
+ *    command(s) in a separate terminal window on the same system.
+ *
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - Associative arrays are used to store the information from the
+ *    proc provider.
+ *
+ *    - There is on important subtlety to pay attention to.  Since
+ *    bash (and other shells) optimize for performance, it may happen
+ *    that proc:::create does not fire, because there is no call to
+ *    fork(), clone(), etc.  This is why two different probes for
+ *    proc:::exec are defined.
+ *
+ *    - The DTrace User Guide documents the proc provider probe
+ *    arguments like args[0] and also structures like psinfo_t.  It is
+ *    strongly recommended to check the documentation for this info.
+ */
+
+/*
+ *  Fires when a process (or process thread) is created using fork() or
+ *  vfork(), which both invoke clone().  The psinfo_t corresponding to
+ *  the new child process is pointed to by args[0].
+ *
+ *  Use a predicate to only execute the clause if the condition is met.
+ *  In this case that means that only processes executed in the bash
+ *  shell are traced.
+ */
+proc:::create
+/ execname == $1 /
+{
+/*
+ *  Store the PID of both the parent and child process from the psinfo_t
+ *  structure pointed to by args[0].  Use 3 associative arrays to store the
+ *  various items of interest.
+ */
+  childpid  = args[0]->pr_pid;
+  parentpid = args[0]->pr_ppid;
+
+/*
+ *  Store the parent PID of the new child process.
+ */
+  p_pid[childpid] = parentpid;
+
+/*
+ *  Parent command name.
+ */
+  p_name[childpid] = execname;
+
+/*
+ *  Child has not yet been exec'ed.
+ */
+  p_exec[childpid] = "";
+}
+
+/*
+ *  The process starts.  In case proc:::create has fired, store the
+ *  absolute time and the full name of the child process.
+ */
+
+proc:::exec
+/ execname == $1 && p_pid[pid] != 0 /
+{
+  time[pid]   = timestamp;
+  p_exec[pid] = args[0];
+}
+
+/*
+ *  The process starts, but in this case, proc:::create has not fired.
+ *  In addition to storing the name of the child process, store the
+ *  various other items of interest.
+ */
+proc:::exec
+/ execname == $1 && p_pid[pid] == 0 /
+{
+  time[pid]   = timestamp;
+  p_exec[pid] = args[0];
+  p_pid[pid]  = ppid;
+  p_name[pid] = execname;
+}
+
+/*
+ *  The process exits.  Print the information.
+ */
+proc:::exit
+/p_pid[pid] != 0 && p_exec[pid] != ""/
+{
+  printf("%-16s (%d) executed %s (%d) for %d microseconds\n",
+    p_name[pid], p_pid[pid], p_exec[pid], pid, (timestamp - time[pid])/1000);
+}
+
+/*
+ *  The process has forked itself and exits.  Print the information.
+ */
+proc:::exit
+/p_pid[pid] != 0 && p_exec[pid] == ""/
+{
+  printf("%-16s (%d) forked itself (as %d) for %d microseconds\n",
+    p_name[pid], p_pid[pid], pid, (timestamp - time[pid])/1000);
+}
diff --git a/examples/getting-started/calltrace.d b/examples/getting-started/calltrace.d
new file mode 100755
index 000000000..a0ff14c15
--- /dev/null
+++ b/examples/getting-started/calltrace.d
@@ -0,0 +1,88 @@
+/*
+ *  NAME
+ *    calltrace.d - time all system calls for the cp command
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s calltrace.d
+ *
+ *  DESCRIPTION
+ *    List and time all the system calls that are executed while
+ *    a file is copied with the cp command.
+ *
+ *  NOTES
+ *    - This script traces all system calls that are executed when
+ *    the cp command is used to copy a file.
+ *
+ *    This means that you need to execute the cp command while the
+ *    script is running.  There are two ways to do this:
+ *    o Execute this script in the background, and type in the cp command.
+ *    o Alternatively, run the script in the foreground and type
+ *    the cp command in a separate terminal window on the same system.
+ *
+ *    - You can use any file to copy, but you can also generate a file
+ *    and then copy it.  This is an example how to create a 500 MB file,
+ *    copy it with the cp command and remove both files again:
+ *    $ dd if=/dev/zero of=tmp_file bs=100M seek=5 count=0
+ *    $ cp tmp_file tmp_file2
+ *    $ rm tmp_file tmp_file2
+ *
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - Although the results of an aggregation are automatically
+ *    printed when the tracing terminates, in this case, we want to
+ *    control the format of the output.  This is why the results are
+ *    printed using printa() in the END probe
+ */
+
+/*
+ *  Set the base value of the timer.  This is used as an offset in the
+ *  return probe to calculate the time spent in a system call.
+ *
+ *  A predicate is used to select the cp command.  All other commands
+ *  skip executing the clause and do not set ts_base.
+ */
+syscall:::entry
+/ execname == "cp" /
+{
+  self->ts_base = timestamp;
+}
+
+/*
+ *  The predicate ensures that the base timing has been set.
+ *  Since this is only done for the cp command, no information
+ *  is collected for the other processes.
+ */
+syscall:::return
+/self->ts_base != 0/
+{
+/*
+ *  Compute the time passed since the entry probe fired and
+ *  convert the nanosecond value to microseconds.
+ *
+ *  Update the aggregation called totals with this time.  The
+ *  execname (which is cp here) and the system call that caused
+ *  the probe to fire, are the fields in the key.
+ */
+  this->time_call = (timestamp - self->ts_base)/1000;
+  @totals[execname,probefunc] = sum(this->time_call);
+
+/*
+ *  Free the storage for ts_base.
+ */
+  self->ts_base = 0;
+}
+
+/*
+ *  Print the results.  Use printf() to print a description of
+ *  the contents of the aggregation.  The format string in printa()
+ *  is used to create a table lay-out.
+ */
+END
+{
+  printf("System calls executed and their duration:\n");
+  printa("%15s executed %18s - this took a total of %@8d microseconds\n",
+         @totals);
+}
diff --git a/examples/getting-started/countcalls.d b/examples/getting-started/countcalls.d
new file mode 100755
index 000000000..fb22b2aba
--- /dev/null
+++ b/examples/getting-started/countcalls.d
@@ -0,0 +1,38 @@
+/*
+ *  NAME
+ *    countcalls.d - count the open(), read(), and write() calls for 5 seconds
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s countcalls.d
+ *
+ *  DESCRIPTION
+ *    List and count the calls to write(), read(), and open() executed, while
+ *    the script is running.  The script automatically stops after 5 seconds.
+ *
+ *  NOTES
+ *    - This script uses the profile provider to stop the tracing after a
+ *    certain amount of time.  This time can easily be adjusted by changing.
+ *    the number and unit.
+ *
+ *    - An anonymous aggregation is used to store the results.  Like a named
+ *    aggregation, it is automatically printed when the tracing terminates.
+ */
+
+/*
+ *  Fires every 5 seconds.  Since exit() is called, the tracing terminates
+ *  the first time this probe fires and the clause is executed.
+ */
+profile:::tick-5sec
+{
+  exit(0);
+}
+
+/*
+ *  Create the key by concatenating the function name and a string.  An
+ *  alternative is to only use probefunc as a key and print the string as
+ *  part of a printa() in the END probe: printa("%s () calls\n",@);
+ */
+syscall::write:entry, syscall::read:entry, syscall::open:entry
+{
+  @[strjoin(probefunc,"() calls")] = count();
+}
diff --git a/examples/getting-started/countprogs.d b/examples/getting-started/countprogs.d
new file mode 100755
index 000000000..14d791b24
--- /dev/null
+++ b/examples/getting-started/countprogs.d
@@ -0,0 +1,37 @@
+/*
+ *  NAME
+ *    countprogs.d - count processes invoked by a specific user
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s countprogs.d
+ *
+ *  DESCRIPTION
+ *    List and count every processes that is started by the user, while
+ *    this script runs.  The user id is passed in as an argument to the
+ *    script.
+ *
+ *  NOTES
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - To ensure a process is started while the script is running,
+ *    either execute this script in the background, and type in one
+ *    or more commands, or run it in the foreground and type in the
+ *    command(s) in a separate terminal window on the same system.
+ *
+ *    - The results of an aggregation are automatically printed when
+ *    the tracing terminates.
+ */
+
+/*
+ *  Fires on every process that starts execution.  An aggregation called
+ *  proc_name uses the executable name as a key and counts the number of
+ *  times this executable, or process, is started.
+ */
+proc:::exec
+/uid == $1/
+{
+  @proc_name[execname] = count();
+}
diff --git a/examples/getting-started/countsyscalls.d b/examples/getting-started/countsyscalls.d
new file mode 100755
index 000000000..31fa750e2
--- /dev/null
+++ b/examples/getting-started/countsyscalls.d
@@ -0,0 +1,31 @@
+/*
+ *  NAME
+ *    countsyscalls.d - count system calls invoked by a specific user
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s countsyscalls.d
+ *
+ *  DESCRIPTION
+ *    List and count all the system calls executed by the specified user id.
+ *    The user id is passed in as an argument to the script.
+ *
+ *  NOTES
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - The results of the aggregation are automatically printed when
+ *    the tracing terminates.
+ */
+
+/*
+ *  Fires on every system call executed.  An aggregation called syscalls
+ *  uses the function name as a key and counts the number of calls to this
+ *  function.
+ */
+syscall:::entry
+/pid == $1/
+{
+  @syscalls[probefunc] = count();
+}
diff --git a/examples/getting-started/cswpercpu.d b/examples/getting-started/cswpercpu.d
new file mode 100755
index 000000000..e2cac6d9c
--- /dev/null
+++ b/examples/getting-started/cswpercpu.d
@@ -0,0 +1,81 @@
+/*
+ *  NAME
+ *    cswpercpu.d - print the number of context switches per CPU per second
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s cswpercpu.d
+ *
+ *  DESCRIPTION
+ *    Every second, print the CPU id, the number of context switches each
+ *    CPU performed, plus the total number of context switches executed
+ *    across all the CPUs.  For each info block, include a time stamp.
+ *
+ *  NOTES
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - The results are stored in an aggregation called cswpersec.
+ *    Every second, the results are printed with printa() and the
+ *    aggregation is cleared.
+ *
+ *    - In addition to using the CPU ID as a key in the cswpersec
+ *    aggregation, also the string "total" is used.  This entry
+ *    is always printed last, because by default, printa() prints
+ *    the results sorted by the value.  The total count for any of
+ *    the CPU Ids is always equal or less than "total".
+ */
+
+/*
+ *  To avoid that the carefully crafted output is mixed with the
+ *  default output by the dtrace command, enable quiet mode.
+ */
+#pragma D option quiet
+
+/*
+ *  Print the header.
+ */
+BEGIN
+{
+  printf("%-20s %5s %15s", "Timestamp", "CPU", "#csw");
+}
+
+/*
+ *  Fires when a process is scheduled to run on a CPU.
+ */
+sched:::on-cpu
+{
+/*
+ *  Convert the CPU ID to a string.  This needs to be done because
+ *  key "total" is a string.
+ */
+  cpustr = lltostr(cpu);
+/*
+ *  Update the count.
+ */
+  @cswpersec[cpustr]  = count();
+  @cswpersec["total"] = count();
+}
+
+/*
+ *  Fires every second.
+ */
+profile:::tick-1sec
+{
+/*
+ *  Print the date and time first
+ */
+  printf("\n%-20Y ", walltimestamp);
+
+/*
+ *  Print the aggregated counts for each CPU and the total for all CPUs.
+ *  Use some formatting magic to get a special table lay-out.
+ */
+  printa("%5s %@15d\n                     ", @cswpersec);
+
+/*
+ *  Reset the aggregation.
+ */
+  clear(@cswpersec);
+}
diff --git a/examples/getting-started/daterun.d b/examples/getting-started/daterun.d
new file mode 100755
index 000000000..f77dc736e
--- /dev/null
+++ b/examples/getting-started/daterun.d
@@ -0,0 +1,35 @@
+/*
+ *  NAME
+ *    daterun.d - display arguments to write() for the date command
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s daterun.d
+ *
+ *  DESCRIPTION
+ *    Trace the calls to write(), but only when executed by the date
+ *    command.  For such calls, print the file descriptor, the output
+ *    string, and the number of bytes printed.
+ *
+ *  NOTES
+ *    - Execute this script in the background, and type in "date", or
+ *    run it in the foreground and type in "date" in a separate window.
+ *
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - The output string is stored in arg1 and contains a newline (\n)
+ *    character.  This is why the byte count is printed on a separate line.
+ */
+
+syscall::write:entry
+/execname == "date"/
+{
+/*
+ *  Use copyinstr() to copy the string from the user address into a
+ *  DTrace buffer.  This function returns a pointer to the buffer.
+ */
+  printf("%s (fd=%d output=%s bytes=%d)\n",probefunc, arg0,
+                                           copyinstr(arg1), arg2);
+}
diff --git a/examples/getting-started/diskact.d b/examples/getting-started/diskact.d
new file mode 100755
index 000000000..77920035b
--- /dev/null
+++ b/examples/getting-started/diskact.d
@@ -0,0 +1,99 @@
+/*
+ *  NAME
+ *    diskact.d - for block devices show the distribution of I/O throughput
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s diskact.d
+ *
+ *  DESCRIPTION
+ *    The io provider is used to gather the I/O throughput for the block
+ *    devices on the system.  A histogram of the results is printed.
+ *
+ *  NOTES
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *   - The bufinfo_t structure is the abstraction that describes an I/O
+ *   request.  The buffer that corresponds to an I/O request is pointed
+ *   to by args[0] in the start, done, wait-start, and wait-done probes
+ *   available through the io provider.
+ *
+ *   - Detailed information about this data structure can be found in
+ *   the DTrace User Guide.  For more details, you can also check
+ *   /usr/lib64/dtrace/<version>/io.d, where <version> denotes the
+ *   DTrace version number(s) in /usr/lib64/dtrace.
+ *
+ *    - Although the results of an aggregation are automatically
+ *    printed when the tracing terminates, in this case, we want to
+ *    control the format of the output.  This is why the results are
+ *    printed using printa() in the END probe
+ */
+
+/*
+ *  To avoid that the carefully crafted output is mixed with the
+ *  default output by the dtrace command, enable quiet mode.
+ */
+#pragma D option quiet
+
+/*
+ *  The pointer to bufinfo_t is in args[0].  Here it is used to get
+ *  b_edev (the extended device) and b_blkno (the expanded block
+ *  number on the device).  These two fields are used in the key for
+ *  associative array io_start.
+ */
+io:::start
+{
+  io_start[args[0]->b_edev, args[0]->b_blkno] = timestamp;
+}
+
+io:::done
+/ io_start[args[0]->b_edev, args[0]->b_blkno] /
+{
+/*
+ *  We would like to show the throughput to a device in KB/sec, but
+ *  the values that are measured are in bytes and nanoseconds.
+ *  You want to calculate the following:
+ *
+ *  bytes / 1024
+ *  ------------------------
+ *  nanoseconds / 1000000000
+ *
+ *  As DTrace uses integer arithmetic and the denominator is usually
+ *  between 0 and 1 for most I/O, the calculation as shown will lose
+ *  precision.  So, restate the fraction as:
+ *
+ *  bytes         1000000000      bytes * 976562
+ *  ----------- * ------------- = --------------
+ *  nanoseconds   1024            nanoseconds
+ *
+ *  This is easy to calculate using integer arithmetic.
+ */
+
+  this->elapsed = timestamp -  io_start[args[0]->b_edev, args[0]->b_blkno];
+
+/*
+ *  The pointer to structure devinfo_t is in args[1].  Use this to get the
+ *  name (+ instance/minor) and the pathname of the device.
+ *
+ *  Use the formula above to compute the throughput.  The number of bytes
+ *  transferred is in bufinfo_t->b_bcount
+ */
+  @io_throughput[strjoin("device name = ",args[1]->dev_statname),
+                 strjoin("path = ",args[1]->dev_pathname)] =
+                   quantize((args[0]->b_bcount * 976562) / this->elapsed);
+
+/*
+ *  Free the storage for the entry in the associative array.
+ */
+  io_start[args[0]->b_edev, args[0]->b_blkno] = 0;
+}
+
+/*
+ *  Use a format string to print the aggregation.
+ */
+END
+{
+  printa(" %s (%s)\n%@d\n", @io_throughput);
+}
diff --git a/examples/getting-started/errno.d b/examples/getting-started/errno.d
new file mode 100755
index 000000000..b22f4b577
--- /dev/null
+++ b/examples/getting-started/errno.d
@@ -0,0 +1,48 @@
+/*
+ *  NAME
+ *    errno.d - list and count the system calls with a non-zero errno value
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s errno.d
+ *
+ *  DESCRIPTION
+ *    Trace every system call that returns a non-zero value in errno.
+ *    Show the name of the function, the value of errno and how often
+ *    this function returned a non-zero value for errno.
+ *
+ *  NOTES
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - The value of errno is available upon the return from the system call.
+ *
+ *    - To present the results in a compact form, we use an aggregation
+ *    called syscalls.  Otherwise we may get several screens with the
+ *    information.  Plus that we then can't easily count the functions.
+ *
+ *    - Although the results of an aggregation are automatically
+ *    printed when the tracing terminates, in this case, we want to
+ *    control the format of the output.  This is why the results are
+ *    printed using printa() in the END probe
+ */
+
+/*
+ *  Use the predicate to only allow non-zero errno values that are
+ *  within the range for errno.
+ */
+syscall:::return
+/ errno > 0 && errno <= ERANGE /
+{
+  @syscalls[probefunc,errno] = count();
+}
+
+/*
+ *  The printf() line prints the header of the table to follow.
+ */
+END
+{
+  printf("%20s %5s %5s\n\n","syscall","errno","count");
+  printa("%20s %5d %@5d\n", at syscalls);
+}
diff --git a/examples/getting-started/errno1.d b/examples/getting-started/errno1.d
new file mode 100755
index 000000000..01f3a229b
--- /dev/null
+++ b/examples/getting-started/errno1.d
@@ -0,0 +1,136 @@
+/*
+ *  NAME
+ *    errno1.d - list and count the system calls with a non-zero errno value
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s errno1.d
+ *
+ *  DESCRIPTION
+ *    Trace every system call that returns a non-zero value in errno.
+ *    Show the process name, the name of the function it executes, the
+ *    user id, the name of the error that corresponds to the value of
+ *    errno, a descriptive message for the error, and how often this
+ *    combination occurred.
+ *
+ *  NOTES
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - The value of errno is available upon the return from the system call.
+ *
+ *    - To present the results in a compact form, we use an aggregation
+ *    called syscalls.  Otherwise we may get several screens with the
+ *    information.  Plus that we then can't easily count the functions.
+ *
+ *    - Although the results of an aggregation are automatically
+ *    printed when the tracing terminates, in this case, we want to
+ *    control the format of the output.  This is why the results are
+ *    printed using printa() in the END probe
+ */
+
+BEGIN
+{
+/*
+ *  Define an associative array called errno_code that maps a value of errno
+ *  to a string with the name of the error.  This information can be found
+ *  in file /usr/include/asm-generic/errno-base.h.
+ *
+ *  File /usr/include/asm-generic/errno.h has the codes for calling a system
+ *  call that does not exist.  This has not been used here though.
+ */
+  errno_code[EPERM]   = "EPERM";    /* Operation not permitted */
+  errno_code[ENOENT]  = "ENOENT";   /* No such file or directory */
+  errno_code[ESRCH]   = "ESRCH";    /* No such process */
+  errno_code[EINTR]   = "EINTR";    /* Interrupted system call */
+  errno_code[EIO]     = "EIO";      /* I/O error */
+  errno_code[ENXIO]   = "ENXIO";    /* No such device or address */
+  errno_code[E2BIG]   = "E2BIG";    /* Argument list too long */
+  errno_code[ENOEXEC] = "ENOEXEC";  /* Exec format error */
+  errno_code[EBADF]   = "EBADF";    /* Bad file number */
+  errno_code[ECHILD]  = "ECHILD";   /* No child processes */
+  errno_code[EAGAIN]  = "EAGAIN";   /* Try again or operation would block */
+  errno_code[ENOMEM]  = "ENOMEM";   /* Out of memory */
+  errno_code[EACCES]  = "EACCES";   /* Permission denied */
+  errno_code[EFAULT]  = "EFAULT";   /* Bad address */
+  errno_code[ENOTBLK] = "ENOTBLK";  /* Block device required */
+  errno_code[EBUSY]   = "EBUSY";    /* Device or resource busy */
+  errno_code[EEXIST]  = "EEXIST";   /* File exists */
+  errno_code[EXDEV]   = "EXDEV";    /* Cross-device link */
+  errno_code[ENODEV]  = "ENODEV";   /* No such device */
+  errno_code[ENOTDIR] = "ENOTDIR";  /* Not a directory */
+  errno_code[EISDIR]  = "EISDIR";   /* Is a directory */
+  errno_code[EINVAL]  = "EINVAL";   /* Invalid argument */
+  errno_code[ENFILE]  = "ENFILE";   /* File table overflow */
+  errno_code[EMFILE]  = "EMFILE";   /* Too many open files */
+  errno_code[ENOTTY]  = "ENOTTY";   /* Not a typewriter */
+  errno_code[ETXTBSY] = "ETXTBSY";  /* Text file busy */
+  errno_code[EFBIG]   = "EFBIG";    /* File too large */
+  errno_code[ENOSPC]  = "ENOSPC";   /* No space left on device */
+  errno_code[ESPIPE]  = "ESPIPE";   /* Illegal seek */
+  errno_code[EROFS]   = "EROFS";    /* Read-only file system */
+  errno_code[EMLINK]  = "EMLINK";   /* Too many links */
+  errno_code[EPIPE]   = "EPIPE";    /* Broken pipe */
+  errno_code[EDOM]    = "EDOM";     /* Math argument out of domain of func */
+  errno_code[ERANGE]  = "ERANGE";   /* Math result not representable */
+
+/*
+ *  This associative array called errno_msg has a brief description of the
+ *  error for each non-zero value of errno.
+ */
+  errno_msg["EPERM"]   = "Operation not permitted";
+  errno_msg["ENOENT"]  = "No such file or directory";
+  errno_msg["ESRCH"]   = "No such process";
+  errno_msg["EINTR"]   = "Interrupted system call";
+  errno_msg["EIO"]     = "I/O error";
+  errno_msg["ENXIO"]   = "No such device or address";
+  errno_msg["E2BIG"]   = "Argument list too long";
+  errno_msg["ENOEXEC"] = "Exec format error";
+  errno_msg["EBADF"]   = "Bad file number";
+  errno_msg["ECHILD"]  = "No child processes";
+  errno_msg["EAGAIN"]  = "Try again or operation would block";
+  errno_msg["ENOMEM"]  = "Out of memory";
+  errno_msg["EACCES"]  = "Permission denied";
+  errno_msg["EFAULT"]  = "Bad address";
+  errno_msg["ENOTBLK"] = "Block device required";
+  errno_msg["EBUSY"]   = "Device or resource busy";
+  errno_msg["EEXIST"]  = "File exists";
+  errno_msg["EXDEV"]   = "Cross-device link";
+  errno_msg["ENODEV"]  = "No such device";
+  errno_msg["ENOTDIR"] = "Not a directory";
+  errno_msg["EISDIR"]  = "Is a directory";
+  errno_msg["EINVAL"]  = "Invalid argument";
+  errno_msg["ENFILE"]  = "File table overflow";
+  errno_msg["EMFILE"]  = "Too many open files";
+  errno_msg["ENOTTY"]  = "Not a typewriter";
+  errno_msg["ETXTBSY"] = "Text file busy";
+  errno_msg["EFBIG"]   = "File too large";
+  errno_msg["ENOSPC"]  = "No space left on device";
+  errno_msg["ESPIPE"]  = "Illegal seek";
+  errno_msg["EROFS"]   = "Read-only file system";
+  errno_msg["EMLINK"]  = "Too many links";
+  errno_msg["EPIPE"]   = "Broken pipe";
+  errno_msg["EDOM"]    = "Math argument out of domain of func";
+  errno_msg["ERANGE"]  = "Math result not representable";
+}
+
+/*
+ *  Store the information in an aggregation called syscalls.
+ */
+syscall:::return
+/ errno > 0 && errno <= ERANGE /
+{
+  @syscalls[execname,probefunc,uid,errno_code[errno],
+            errno_msg[errno_code[errno]]] = count();
+}
+
+/*
+ *  The printf() line prints the header of the table to follow.
+ */
+END
+{
+  printf("%-20s %-16s %-6s %-7s %-35s %5s\n\n","PROCESS","SYSCALL","UID",
+         "ERROR","DESCRIPTION","COUNT");
+  printa("%-20s %-16s %-6d %-7s %-35s %@5d\n", at syscalls);
+}
diff --git a/examples/getting-started/execcalls.d b/examples/getting-started/execcalls.d
new file mode 100755
index 000000000..f12753cbf
--- /dev/null
+++ b/examples/getting-started/execcalls.d
@@ -0,0 +1,44 @@
+/*
+ *  NAME
+ *    execcalls.d - show all processes that start executing
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s execcals.d
+ *
+ *  DESCRIPTION
+ *    The probe in this script traces the exec() system call.  It
+ *    fires whenever a process loads a new process image.
+ *
+ *  NOTES
+ *    - This script traces the processes that start executing while
+ *    the script is running.  If no process is started during the
+ *    time that the script runs, no output is produced.
+ *
+ *    If that is the case, you can always execute a command yourself
+ *    while this script is running.  One such command is "date" that
+ *    causes the probe to fire.
+ *
+ *    - If you'd like to execute command(s) while the script is running,
+ *    execute this script in the background, and type in one or more
+ *    commands.  If you started the script in the foreground, type in
+ *    the command(s) in a separate terminal window on the same system.
+ *
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ */
+
+proc:::exec
+/ args[0] != NULL /
+{
+/*
+ *  This information is from the DTrace user guide.  The proc:::exec
+ *  probe makes a pointer to a char available in args[0].  This has
+ *  the path to the new process image.
+ *
+ *  The strjoin() function is used to add a newline (\n) to the
+ *  string that is to be printed.
+ */
+  trace(strjoin(stringof(args[0]),"\n"));
+}
diff --git a/examples/getting-started/fsact.sh b/examples/getting-started/fsact.sh
new file mode 100755
index 000000000..1919460db
--- /dev/null
+++ b/examples/getting-started/fsact.sh
@@ -0,0 +1,109 @@
+#!/bin/bash
+#
+#------------------------------------------------------------------------------
+# This example embeds a DTrace script in a bash script.  The bash script
+# is used to set the variables needed in the D script.
+#
+# fsact -- Display cumulative read and write activity across a file
+#          system device
+#
+#          Usage: fsact [<filesystem>]
+#------------------------------------------------------------------------------
+
+#------------------------------------------------------------------------------
+# If no file system is specified, assume /
+#------------------------------------------------------------------------------
+[ $# -eq 1 ] && FSNAME=$1 || FSNAME="/"
+[ ! -e $FSNAME ] && echo "$FSNAME not found" && exit 1
+
+#------------------------------------------------------------------------------
+# Determine the mountpoint, major and minor numbers, and file system size.
+#------------------------------------------------------------------------------
+MNTPNT=$(df $FSNAME | gawk '{ getline; print $1; exit }')
+MAJOR=$(printf "%d\n" 0x$(stat -Lc "%t" $MNTPNT))
+MINOR=$(printf "%d\n" 0x$(stat -Lc "%T" $MNTPNT))
+FSSIZE=$(stat -fc "%b" $FSNAME)
+
+#------------------------------------------------------------------------------
+# Run the embedded D script.
+#------------------------------------------------------------------------------
+sudo dtrace -qs /dev/stdin << EOF
+/*
+ *  DESCRIPTION
+ *    The io:::done probe from the io provider is used to get read and write
+ *    statistics.  In particular, the id of the block that is accessed for
+ *    the read or write operation.
+ */
+
+BEGIN
+{
+  printf("Show how often blocks are accessed in read and write operations\n");
+  printf("The statistics are updated every 5 seconds\n");
+  printf("The block IDs are normalized to a scale from 0 to 10\n");
+  printf("The file system is %s\n","$FSNAME");
+  printf("The mount point is %s\n","$MNTPNT");
+  printf("The file system size is %s bytes\n","$FSSIZE");
+}
+
+/*
+ *  This probe fires after an I/O request has been fulfilled. The
+ *  done probe fires after the I/O completes, but before completion
+ *  processing has been performed on the buffer.
+ *
+ *  A pointer to structure devinfo_t is in args[1].  This is used
+ *  to get the major and minor number of the device.
+ *
+ *  A pointer to structure bufinfo_t is in args[0].  This is used
+ *  to get the flags and the block number.
+ */
+io:::done
+/ args[1]->dev_major == $MAJOR && args[1]->dev_minor == $MINOR /
+{
+/*
+ *  Check if B_READ has been set and assign a string to io_type
+ *  based on the outcome of the check.  This string is used as
+ *  the key in aggregation io_stats.
+ */
+  io_type = args[0]->b_flags & B_READ ? "READ" : "WRITE";
+
+/*
+ *  Structure member b_lblkno identifies which logical block on the
+ *  device is to be accessed.  Normalize thise block number as an
+ *  integer in the range 0 to 10.
+ */
+  blkno = (args[0]->b_blkno)*10/$FSSIZE;
+
+/*
+ *  Aggregate blkno linearly over the range 0 to 10 in steps of 1.
+ */
+  @io_stats[io_type] = lquantize(blkno,0,10,1)
+}
+
+/*
+ *  Fires every 5 seconds.
+ */
+profile:::tick-5s
+{
+  printf("%Y\n",walltimestamp);
+
+/*
+ *  Display the contents of the aggregation.
+ */
+  printa("%s\n%@d\n", at io_stats);
+
+/*
+ *  Reset the aggregation every time this probe fires
+ */
+  clear(@io_stats);
+}
+
+/*
+ *  Fires every 21 seconds.  Since exit() is called, the tracing terminates
+ *  the first time this probe fires and the clause is executed.
+ */
+profile:::tick-21s
+{
+  printf("Tracing is terminated now\n");
+  exit(0);
+}
+EOF
diff --git a/examples/getting-started/goodbye.d b/examples/getting-started/goodbye.d
new file mode 100755
index 000000000..01330d97e
--- /dev/null
+++ b/examples/getting-started/goodbye.d
@@ -0,0 +1,29 @@
+/*
+ *  NAME
+ *    goodbye.d - demonstrate the END probe
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s goodbye.d
+ *
+ *  DESCRIPTION
+ *    Demonstrates the use of the END probe.  Function trace() is
+ *    used to print a string.
+ *
+ *  NOTES
+ *    - The advantage of trace() is that it is simple and does not
+ *    require a format string.  If more control over the output is
+ *    needed, printf() is a good alternative.
+ *
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ */
+
+/*
+ *  The END probe fires once when the tracing has terminated.
+ */
+END
+{
+  trace("Goodbye");
+}
diff --git a/examples/getting-started/hello.d b/examples/getting-started/hello.d
new file mode 100755
index 000000000..cb53039c0
--- /dev/null
+++ b/examples/getting-started/hello.d
@@ -0,0 +1,21 @@
+/*
+ *  NAME
+ *    hello.d - demonstrate the BEGIN probe
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s hello.d
+ *
+ *  DESCRIPTION
+ *    Demonstrate the use of the BEGIN probe.  Function trace() is
+ *    used to print a string.  The exit() function terminates the
+ *    tracing.
+ */
+
+/*
+ *  The BEGIN probe fires once when tracing starts.
+ */
+BEGIN
+{
+  trace("Hello, world");
+  exit(0);
+}
diff --git a/examples/getting-started/readsizes.d b/examples/getting-started/readsizes.d
new file mode 100755
index 000000000..222c63513
--- /dev/null
+++ b/examples/getting-started/readsizes.d
@@ -0,0 +1,39 @@
+/*
+ *  NAME
+ *    readsizes.d - show the distribution of bytes read when running find
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s readsizes.d
+ *
+ *  DESCRIPTION
+ *    Trace the calls to read() and use a predicate to only select those
+ *    calls executed as part of executing the find command.  For such
+ *    calls, show the distribution of the sizes.
+ *
+ *  NOTES
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - The results are stored in an aggregation called dist with
+ *    the string "find" as the key.
+ *
+ *    - The results of an aggregation are automatically printed when
+ *    the tracing terminates.
+ */
+
+/*
+ *  A predicate is used to guarantee that the clause for the read:entry
+ *  probe is only executed in case the call to read() was issued by the
+ *  find command.
+ *
+ *  The quantize() function is used to show the distribution of the sizes
+ *  read, or attempted to be read, by the read() call.  This value is
+ *  stored in arg2.
+ */
+syscall::read:entry
+/execname == "find"/
+{
+  @dist["find"] = quantize(arg2);
+}
diff --git a/examples/getting-started/readtrace.d b/examples/getting-started/readtrace.d
new file mode 100755
index 000000000..63d3c0608
--- /dev/null
+++ b/examples/getting-started/readtrace.d
@@ -0,0 +1,65 @@
+/*
+ *  NAME
+ *    readtrace.d - show the time spent in the read() system call
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s readtrace.d
+ *
+ *  DESCRIPTION
+ *    For each combination of a process and its id, show the total
+ *    time in microseconds that is spent in the read() system call(s).
+ *
+ *  NOTES
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - An aggregation is used to accumulate the timings.  An alternative
+ *    is to print the results in the read:return probe and if required,
+ *    process the output when the script has completed.
+ *
+ *    - Although the results of an aggregation are automatically
+ *    printed when the tracing terminates, in this case, the results
+ *    are printed in the END probe.  The format string is optional,
+ *    but is used to produce a table lay-out.
+ */
+
+/*
+ *  Set the base value of the timer.  This is used as an offset in the
+ *  read:return probe to calculate the time spent.
+ */
+syscall::read:entry
+{
+  self->ts_base = timestamp;
+}
+
+/*
+ *  The predicate ensures that the base timing has been set.
+ */
+syscall::read:return
+/self->ts_base != 0/
+{
+/*
+ *  Clause-local variable time_read is used to store the time passed
+ *  since the read:entry probe fired.  This time is converted from
+ *  nanoseconds to microseconds.
+ *
+ */
+  this->time_read = (timestamp - self->ts_base)/1000;
+  @totals[execname,pid] = sum(this->time_read);
+
+/*
+ *  Free the storage for ts_base.
+ */
+  self->ts_base = 0;
+}
+
+/*
+ *  Print the results.
+ */
+END
+{
+  printa("%15s (pid=%-7d) spent a total of %5 at d microseconds in read()\n",
+         @totals);
+}
diff --git a/examples/getting-started/readtrace1.d b/examples/getting-started/readtrace1.d
new file mode 100755
index 000000000..984dd3cc6
--- /dev/null
+++ b/examples/getting-started/readtrace1.d
@@ -0,0 +1,71 @@
+/*
+ *  NAME
+ *    readtrace.d - show the time spent in the read() system call
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s readtrace.d
+ *
+ *  DESCRIPTION
+ *    For each combination of a process and its id, show the total
+ *    time in microseconds that is spent in the read() system call(s)
+ *    executed by the df command.
+ *
+ *  NOTES
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - An aggregation is used to accumulate the timings.  An alternative
+ *    is to print the results in the read:return probe and if required,
+ *    process the output when the script has completed.
+ *
+ *    - Although the results of an aggregation are automatically
+ *    printed when the tracing terminates, in this case, the results
+ *    are printed in the END probe.  The format string is optional,
+ *    but is used to produce a table lay-out.
+ */
+
+/*
+ *  Set the base value of the timer.  This is used as an offset in the
+ *  read:return probe to calculate the time spent.
+ *
+ *  A predicate is used to select the df command.  All other commands
+ *  skip the clause and do not set ts_base.
+ */
+syscall::read:entry
+/ execname == "df" /
+{
+  self->ts_base = timestamp;
+}
+
+/*
+ *  The predicate ensures that the base timing has been set.  Since this
+ *  is only done for the df command, no information is collected for the
+ *  other processes.
+ */
+syscall::read:return
+/self->ts_base != 0/
+{
+/*
+ *  Clause-local variable time_read is used to store the time passed
+ *  since the read:entry probe fired.  This time is converted from
+ *  nanoseconds to microseconds.
+ */
+  this->time_read = (timestamp - self->ts_base)/1000;
+  @totals[execname,pid] = sum(this->time_read);
+
+/*
+ *  Free the storage for ts_base.
+ */
+  self->ts_base = 0;
+}
+
+/*
+ *  Print the results.  The format is tailored to the df command.
+ */
+END
+{
+  printa("%-3s (pid=%-7d) spent a total of %5 at d microseconds in read()\n",
+         @totals);
+}
diff --git a/examples/getting-started/rwdiskact.d b/examples/getting-started/rwdiskact.d
new file mode 100755
index 000000000..a60a52430
--- /dev/null
+++ b/examples/getting-started/rwdiskact.d
@@ -0,0 +1,110 @@
+/*
+ *  NAME
+ *    rwdiskact.d - for block devices show the read() and write() performance
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s rwdiskact.d
+ *
+ *  DESCRIPTION
+ *    The io provider is used to display the throughput of the read()
+ *    and write calls() for the block devices on the system.  The
+ *    tracing automatically stops after 10 seconds.
+ *
+ *  NOTES
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *   - The bufinfo_t structure is the abstraction that describes an I/O
+ *   request.  The buffer that corresponds to an I/O request is pointed
+ *   to by args[0] in the start, done, wait-start, and wait-done probes
+ *   available through the io provider.
+ *
+ *   - Detailed information about this data structure can be found in
+ *   the DTrace User Guide.  For more details, you can also check
+ *   /usr/lib64/dtrace/<version>/io.d, where <version> denotes the
+ *   DTrace version number(s) in /usr/lib64/dtrace.
+ *
+ *    - Although the results of an aggregation are automatically
+ *    printed when the tracing terminates, in this case, we want to
+ *    control the format of the output.  This is why the results are
+ *    printed using printa() in the END probe
+ */
+
+/*
+ *  To avoid that the carefully crafted output is mixed with the
+ *  default output by the dtrace command, enable quiet mode.
+ */
+#pragma D option quiet
+
+/*
+ *  Fires every 10 seconds.  Since exit() is called, the tracing terminates
+ *  the first time this probe fires and the clause is executed.
+ */
+profile:::tick-10sec
+{
+  exit(0);
+}
+
+/*
+ *  The pointer to bufinfo_t is in args[0].  Here it is used to get
+ *  b_flags (the flags), b_edev (the extended device) and b_blkno (the
+ *  expanded block number on the device).  These three fields are used
+ *  in the key for associative array io_start.
+ */
+io:::start
+{
+  io_type = args[0]->b_flags & B_READ ? "READ" : "WRITE";
+  io_start[args[0]->b_edev, args[0]->b_blkno, io_type] = timestamp;
+}
+
+io:::done
+{
+/*
+ *  We would like to show the throughput to a device in KB/sec, but
+ *  the values that are measured are in bytes and nanoseconds.
+ *  You want to calculate the following:
+ *
+ *  bytes / 1024
+ *  ------------------------
+ *  nanoseconds / 1000000000
+ *
+ *  As DTrace uses integer arithmetic and the denominator is usually
+ *  between 0 and 1 for most I/O, the calculation as shown will lose
+ *  precision.  So, restate the fraction as:
+ *
+ *  bytes         1000000000      bytes * 976562
+ *  ----------- * ------------- = --------------
+ *  nanoseconds   1024            nanoseconds
+ *
+ *  This is easy to calculate using integer arithmetic.
+ */
+  io_type = args[0]->b_flags & B_READ ? "READ" : "WRITE";
+  this->elapsed = timestamp -
+                  io_start[args[0]->b_edev,args[0]->b_blkno,io_type];
+
+/*
+ *  The pointer to structure devinfo_t is in args[1].  Use this to get the
+ *  name (+ instance/minor) and the pathname of the device.
+ *
+ *  Use the formula above to compute the throughput.  The number of bytes
+ *  transferred is in bufinfo_t->b_bcount
+ */
+  @io_throughput[strjoin("device name = ",args[1]->dev_statname),
+                 strjoin("path = ",args[1]->dev_pathname),
+                io_type] =
+                   quantize((args[0]->b_bcount * 976562) / this->elapsed);
+
+/*
+ *  Free the storage for the entry in the associative array.
+ */
+  io_start[args[0]->b_edev, args[0]->b_blkno,io_type] = 0;}
+
+/*
+ *  Use a format string to print the aggregation.
+ */
+END
+{
+  printa(" %s (%s) %s \n%@d\n", @io_throughput);
+}
diff --git a/examples/getting-started/syscalls.d b/examples/getting-started/syscalls.d
new file mode 100755
index 000000000..d01134fb4
--- /dev/null
+++ b/examples/getting-started/syscalls.d
@@ -0,0 +1,44 @@
+/*
+ *  NAME
+ *    syscalls.d - show the read() system calls executed
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s syscalls.d
+ *
+ *  DESCRIPTION
+ *    Show the read() system calls that are executed while the script
+ *    is running.  Since this potentially produces a lot of output,
+ *    an aggregation called totals is used to count the calls.  The
+ *    key has two fields: the name of the process and the file
+ *    descriptor used in the read operation.
+ *
+ *  NOTES
+ *    - This script traces the running processes and the probe fires
+ *    if there are calls to read().  If there are no such calls, no
+ *    output is produced.
+ *
+ *    If that is the case, you can always execute a command that
+ *    executes calls to read().  One such command is "date".  It causes
+ *    the probe to fire, but any other command that issues calls to
+ *    read() will do.
+ *
+ *    - Execute this script in the background, and type in the command,
+ *    or run it in the foreground and type in the command in a separate
+ *    terminal window on the same system.
+ *
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - The results of the aggregation are automatically printed when
+ *    the tracing terminates.
+ */
+
+/*
+ *  The file descriptor used in the read() call is stored in arg0.
+ */
+syscall::read:entry
+{
+  @totals[execname,arg0] = count();
+}
diff --git a/examples/getting-started/syscalls1.d b/examples/getting-started/syscalls1.d
new file mode 100755
index 000000000..3d405ed8c
--- /dev/null
+++ b/examples/getting-started/syscalls1.d
@@ -0,0 +1,53 @@
+/*
+ *  NAME
+ *    syscalls1.d - show the read() system calls executed
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s syscalls1.d
+ *
+ *  DESCRIPTION
+ *    Show the read() system calls that are executed while the script
+ *    is running.  Since this potentially produces a lot of output,
+ *    an aggregation called totals is used to count the calls.  The
+ *    key has four fields: the process id, the user id, the name of
+ *    the process and the file descriptor used in the read operation.
+ *
+ *  NOTES
+ *    - This script traces the running processes and the probe fires
+ *    if there are calls to read().  If there are no such calls, no
+ *    output is produced.
+ *
+ *    If that is the case, you can always execute a command that
+ *    executes calls to read().  One such command is "date".  It causes
+ *    the probe to fire, but any other command that issues calls to
+ *    read() will do.
+ *
+ *    - Execute this script in the background, and type in the command,
+ *    or run it in the foreground and type in the command in a separate
+ *    terminal window on the same system.
+ *
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - Although the results of an aggregation are automatically
+ *    printed when the tracing terminates, in this case, we want to
+ *    control the format of the output.  This is why the results are
+ *    printed in the END probe
+ */
+
+syscall::read:entry
+{
+  @totals[pid,uid,execname,arg0] = count();
+}
+
+/*
+ *  The printf() statement prints a header.  The format string in the
+ *  printa() call is optional.  Here it is used to produce a table lay-out.
+ */
+END
+{
+  printf("%8s %6s %20s %3s %5s\n","PID","UID","EXECNAME","FD","COUNT");
+  printa("%8d %6d %20s %3d %5 at d\n", at totals);
+}
diff --git a/examples/getting-started/tick.d b/examples/getting-started/tick.d
new file mode 100755
index 000000000..b452009bc
--- /dev/null
+++ b/examples/getting-started/tick.d
@@ -0,0 +1,48 @@
+/*
+ *  NAME
+ *    tick.d - perform an action at regular intervals
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s tick.d
+ *
+ *  DESCRIPTION
+ *    Use the tick probe from the profile provider to execute a block of code
+ *    at regular intervals.  In this case, this is the update of a variable
+ *    called "i", but the clause can contain any valid D statements.  The
+ *    final value of "i" is printed in the END probe.
+ *
+ *  NOTES
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - Instead of printf(), trace() can be used and vice-versa.  The
+ *    difference is that trace() does not support a format string.
+ */
+
+/*
+ *  Initialize variable "i" to zero.  This is a global variable that
+ *  can be read and written by any probe.
+ */
+BEGIN
+{
+  i = 0;
+}
+
+/*
+ *  This probe fires every 10 milliseconds.  When it fires, it updates
+ *  variable "i" and prints the result.
+ */
+profile:::tick-100msec
+{
+  printf("i = %d\n",++i);
+}
+
+/*
+ *  Print the final result.
+ */
+END
+{
+  trace(i);
+}
diff --git a/examples/getting-started/tick1.d b/examples/getting-started/tick1.d
new file mode 100644
index 000000000..b2bdf59f5
--- /dev/null
+++ b/examples/getting-started/tick1.d
@@ -0,0 +1,49 @@
+/*
+ *  NAME
+ *    tick1.d - perform an action at regular intervals
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s tick1.d
+ *
+ *  DESCRIPTION
+ *    Use the tick probe from the profile provider to execute a block of code
+ *    at regular intervals.  In this case, this is the update of a variable
+ *    called "i", but the clause can contain any valid D statements.  The
+ *    final value of "i" is printed in the END probe.  The printf() function
+ *    is used to format the output.
+ *
+ *  NOTES
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - Instead of printf(), trace() can be used and vice-versa.  The
+ *    difference is that trace() does not support a format string.
+ */
+
+/*
+ *  Initialize variable "i" to zero.  This is a global variable that
+ *  can be read and written by any probe.
+ */
+BEGIN
+{
+  i = 0;
+}
+
+/*
+ *  This probe fires every 10 milliseconds.  When it fires, it updates
+ *  variable "i" and prints the result.
+ */
+profile:::tick-100msec
+{
+  printf("i = %d\n",++i);
+}
+
+/*
+ *  Print the final result.  Use printf() to format the output.
+ */
+END
+{
+  printf("\nFinal value of i = %d\n",i);
+}
diff --git a/examples/getting-started/wrun.d b/examples/getting-started/wrun.d
new file mode 100755
index 000000000..370c6a87b
--- /dev/null
+++ b/examples/getting-started/wrun.d
@@ -0,0 +1,48 @@
+/*
+ *  NAME
+ *    wrun.d - display arguments to write() for the w command
+ *
+ *  SYNOPSIS
+ *    sudo dtrace -s wrun.d
+ *
+ *  DESCRIPTION
+ *    Trace the calls to write(), but only when executed by the w
+ *    command.  For such calls, print the file descriptor, the
+ *    output string, and the number of bytes printed.
+ *
+ *  NOTES
+ *    - Execute this script in the background, and type in "w", or
+ *    run it in the foreground and type in "w" in a separate window.
+ *
+ *    - The script needs to be terminated with ctrl-C.  In case the
+ *    script is running in the background, get it to run in the
+ *    foreground first by using the fg command and then use ctrl-C
+ *    to terminate the process.  Otherwise, typing in ctrl-C will do.
+ *
+ *    - DTrace has a default limit of 256 bytes for strings.  In this
+ *    example, the output string may be longer than this.  If so,
+ *    either use the "-x strsize=<new-length>" command line option,
+ *    or a "#pragma D option strsize=<new-length>" pragma in the
+ *    script to increase the size.  The latter is shown below.
+ */
+
+#pragma D option strsize=512
+
+/*
+ *  Use a predicate to only execute the clause in case the date
+ *  command causes the probe to fire.
+ */
+syscall::write:entry
+/execname == "w"/
+{
+/*
+ *  Use copyinstr() to copy the string from the user address into a
+ *  DTrace buffer.  This function returns a pointer to the buffer.
+ *  The string it points to, is null terminated.
+ *  The third argument in the call to write() is the number of bytes
+ *  to be printed.  This is used as the second argument in copyinstr()
+ *  so that only this many bytes are copied.
+ */
+  printf("%s(fd=%d\noutput=\n%s\nbytes=%d)\n",probefunc, arg0,
+                                              copyinstr(arg1), arg2);
+}
-- 
2.47.3




More information about the DTrace-devel mailing list