diff options
Diffstat (limited to 'doc/SystemTap_Beginners_Guide/en-US/Array-Operations.xml')
-rw-r--r-- | doc/SystemTap_Beginners_Guide/en-US/Array-Operations.xml | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/doc/SystemTap_Beginners_Guide/en-US/Array-Operations.xml b/doc/SystemTap_Beginners_Guide/en-US/Array-Operations.xml new file mode 100644 index 00000000..ebac139f --- /dev/null +++ b/doc/SystemTap_Beginners_Guide/en-US/Array-Operations.xml @@ -0,0 +1,232 @@ +<?xml version='1.0'?> +<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ +]> + +<section id="arrayoperators"> + <title>Array Operations in SystemTap</title> + +<para>This section enumerates some of the most commonly used array operations in SystemTap.</para> + +<section id="arrayops-assignvalue"> + <title>Assigning an Associated Value</title> + <para>Use <command>=</command> to set an associated value to indexed unique pairs, as in:</para> + +<screen> +<replaceable>array_name</replaceable>[<replaceable>index_expression</replaceable>] = <replaceable>value</replaceable> +</screen> + +<para><xref linkend="arraysimplestexample"/> shows a very basic example of how to set an explicit associated value to a unique key. You can also use a handler function as both your <command><replaceable>index_expression</replaceable></command> and <command><replaceable>value</replaceable></command>. For example, you can use arrays to set a timestamp as the associated value to a process name (which you wish to use as your unique key), as in:</para> + +<example id="arrays-timestampprocessname"> + <title>Associating Timestamps to Process Names</title> +<programlisting> +foo[execname()] = gettimeofday_s() +</programlisting> +</example> + +<para>Whenever an event invokes the statement in <xref linkend="arrays-timestampprocessname"/>, SystemTap returns the appropriate <command>execname()</command> value (i.e. the name of a process, which is then used as the unique key). At the same time, SystemTap also uses the function <command>gettimeofday_s()</command> to set the corresponding timestamp as the associated value to the unique key defined by the function <command>execname()</command>. This creates an array composed of key pairs containing process names and timestamps.</para> + +<para>In this same example, if <command>execname()</command> returns a value that is already defined in the array <command>foo</command>, the operator will discard the original associated value to it, and replace it with the current timestamp from <command>gettimeofday_s()</command>.</para> +</section> +<section id="arrayops-readvalues"> + <title>Reading Values From Arrays</title> + <para>You can also use the <command>=</command> operator to read values from an array. This is accomplished by simply including the <command><replaceable>array_name</replaceable>[<replaceable>index_expression</replaceable>]</command> as an element in a mathematical expression. For example:</para> + +<example id="arrayreadingvaluesfrom"> + <title>Using Array Values in Simple Computations</title> +<screen> +foo[execname()] = gettimeofday_s() +delta = gettimeofday_s() - foo[execname()] +</screen> +</example> + +<para>In <xref linkend="arrayreadingvaluesfrom"/>, the first statement sets a timestamp associated with the returned value of the handler function <command>execname()</command> as a <emphasis>reference point</emphasis>. The second statement computes a value for the variable <command>delta</command> by subtracting the associated value the reference point from the current <command>gettimeofday_s()</command>.</para> + +<para>In this situation, if the <command><replaceable>index_expression</replaceable></command> cannot find the unique key, it returns a null value (zero) by default. </para> +</section> +<section id="arrayops-increment"> + <title>Incrementing Associated Values</title> + <para>Use <command>++</command> to increment the associated value of a unique key in an array, as in:</para> + +<screen> +<replaceable>array_name</replaceable>[<replaceable>index_expression</replaceable>] ++ +</screen> + +<para>Again, you can also use a handler function for your <command><replaceable>index_expression</replaceable></command>. For example, if you wanted to tally how many times a specific process performed a read to the virtual file system (using the event <command>kernel.function("vfs_read")</command>), you can use the following probe:</para> + +<example id="simplesimplevfsread"> + <title>vfsreads.stp</title> +<programlisting> +probe kernel.function("vfs_read") +{ + reads[execname()] ++ +} +</programlisting> +</example> + +<para>In <xref linkend="simplesimplevfsread"/>, the first time that the probe returns the process name <command>gnome-terminal</command> (i.e. the first time <command>gnome-terminal</command> performs a VFS read), that process name is set as the unique key <literal>gnome-terminal</literal> with an associated value of 1. The next time that the probe returns the process name <command>gnome-terminal</command>, SystemTap increments the associated value of <literal>gnome-terminal</literal> by 1. SystemTap performs this operation for <emphasis>all</emphasis> process names as the probe returns them.</para> +</section> + +<section id="arrayops-foreach"> + <title>Processing Elements in a Tuple as Iterations</title> + <para>Once you've collected enough information in an array, you will need to retrieve and process all elements in that array to make it useful. Consider <xref linkend="simplesimplevfsread"/>: the script collects information about how many VFS reads each process performs, but does not specify what to do with it. The obvious means for making <xref linkend="simplesimplevfsread"/> useful is to print the key pairs in the array <command>reads</command>, but how?</para> + + <para>The best way to process all elements in a tuple (treating each element as an iteration) is to use the <command>foreach</command> statement. Consider the following example:</para> + +<example id="simplevfsreadprint"> + <title>cumulative-vfsreads.stp</title> +<programlisting> +global reads +probe kernel.function("vfs_read") +{ + reads[execname()] ++ +} +probe timer.s(3) +{ + foreach (count in reads) + printf("%s : %d \n", count, reads[count]) +} +</programlisting> +</example> + +<para>In the second probe of <xref linkend="simplevfsreadprint"/>, the <command>foreach</command> statement uses the variable <command>count</command> to reference each iteration of a unique key in the array <command>reads</command>. The <command>reads[count]</command> array statement in the same probe retrieves the associated value of each unique key.</para> + +<para>Given what we know about the first probe in <xref linkend="simplevfsreadprint"/>, the script prints VFS-read statistics every 3 seconds, displaying names of processes that performed a VFS-read along with a corresponding VFS-read count.</para> + +<para>Now, remember that the <command>foreach</command> statement in <xref linkend="simplevfsreadprint"/> prints <emphasis>all</emphasis> iterations of process names in the array, and in no particular order. You can instruct the script to process the iterations in a particular order by using <command>+</command> (ascending) or <command>-</command> (descending). In addition, you can also limit the number of iterations the script needs to process with the <command>limit <replaceable>value</replaceable></command> option.</para> + +<para>For example, consider the following replacement probe:</para> +<screen> +probe timer.s(3) +{ + foreach (count in reads+ limit 4) + printf("%s : %d \n", count, reads[count]) +} +</screen> + +<para>This <command>foreach</command> statement instructs the script to process the elements in the array <command>reads</command> in ascending order (of associated value). The <command>limit 4</command> option instructs the script to only process the first four elements in the array (i.e. the first 4, starting with the lowest value).</para> +</section> + +<section id="arrayops-deleting"> + <title>Clearing/Deleting Arrays and Array Elements</title> + + <para>Sometimes, you may need to clear the associated values in array elements, or reset an entire array for re-use in another probe. <xref linkend="simplevfsreadprint"/> in <xref linkend="arrayops-foreach"/> allows you to track how the number of VFS reads per process grows over time, but it does not show you the number of VFS reads each process makes per 3-second period.</para> + + <para>To do that, you will need to clear the values accumulated by the array. You can accomplish this using the <command>delete</command> operator to delete elements in an array, or an entire array. Consider the following example:</para> + +<example id="simplevfsreadprintnotcumulative"> + <title>vfsreads-per-2secs.stp</title> +<programlisting> +global reads
+probe kernel.function("vfs_read")
+{
+ reads[execname()] ++
+}
+probe timer.s(2)
+{
+ printf("=======\n")
+ foreach (count in reads+)
+ printf("%s : %d \n", count, reads[count])
+ delete reads
+}
+</programlisting> +</example> + +<para>In <xref linkend="simplevfsreadprintnotcumulative"/>, the second probe prints the number of VFS reads each process made <emphasis>within the probed 2-second period only</emphasis>. The <command>delete reads</command> statement clears the <command>reads</command> array within the probe.</para> + +<note> + <title>Note</title> + <para>You can have multiple array operations within the same probe. Using the examples from <xref linkend="arrayops-foreach"/> and <xref linkend="arrayops-deleting"/> , you can track the number of VFS reads each process makes per 2-second period <emphasis>and</emphasis> tally the cumulative VFS reads of those same processes. Consider the following example:</para> + +<screen> +global reads, totalreads
+
+probe kernel.function("vfs_read")
+{
+ reads[execname()] ++
+ totalreads[execname()] ++
+}
+
+probe timer.s(2)
+{
+ printf("=======\n")
+ foreach (count in reads+)
+ printf("%s : %d \n", count, reads[count])
+ delete reads
+
+}
+probe end
+{
+ printf("TOTALS\n")
+ foreach (total in totalreads+)
+ printf("%s : %d \n", total, totalreads[total])
+}
+</screen> + +<para>In this example, the arrays <command>reads</command> and <command>totalreads</command> track the same information, and are printed out in a similar fashion. The only difference here is that <command>reads</command> is cleared every 2-second period, whereas <command>totalreads</command> keeps growing.</para> +</note> +</section> +<section id="arrayops-conditionals"> + <title>Using Arrays in Conditional Statements</title> + +<para>You can also use associative arrays in <command>if</command> statements. This is useful if you want to execute a subroutine once a value in the array matches a certain condition. Consider the following example:</para> + +<example id="simplevfsreadprintif"> + <title>vfsreads-stop-on-stapio.stp</title> +<programlisting> +global reads
+probe kernel.function("vfs_read")
+{
+ reads[execname()] ++
+}
+probe timer.s(2)
+{
+ printf("=======\n")
+ foreach (count in reads+)
+ printf("%s : %d \n", count, reads[count])
+ if(reads["stapio"] >= 20)
+ {exit()}
+} +</programlisting> +</example> + +<para>The <command>if(reads["stapio"] >= 20)</command> instructs the script to execute the subroutine <command>exit()</command> once the value associated with the unique key <command>stapio</command> (in the array <command>reads</command>) is greater than or equal to 20.</para> + +<formalpara> + <title>Testing for Membership</title> +<para>You can also test whether a specific unique key is a member of an array. Further, membership in an array can be used in <command>if</command> statements, as in:</para> +</formalpara> + +<screen> +if([<replaceable>index_expression</replaceable>] in <replaceable>array_name</replaceable> +</screen> + +<para>To illustrate this, consider the following example:</para> + +<example id="simplesimplevfsreadprintifmember"> + <title>vfsreads-stop-on-stapio2.stp</title> +<programlisting> +global reads
+
+probe kernel.function("vfs_read")
+{
+ reads[execname()] ++
+}
+
+probe timer.s(2)
+{
+ printf("=======\n")
+ foreach (count in reads+)
+ printf("%s : %d \n", count, reads[count])
+ if(["stapio"] in reads)
+ {printf("stapio read detected, exiting\n")
+ exit()
+ }
+}
+</programlisting> +</example> + +<para>The <command>if(["stapio"] in reads)</command> statement instructs the script to print <computeroutput>stapio read detected, exiting</computeroutput> once the unique key <command>stapio</command> is added to the array <command>reads</command>.</para> +</section> + +</section>
\ No newline at end of file |