2.7 Simple Data Aggregations

DTrace provides several functions for aggregating the data that individual probes gather. These functions include avg(), count(), max(), min(), stddev(), and sum(), which return the mean, number, maximum value, minimum value, standard deviation, and summation of the data being gathered. See Aggregations in the Oracle Linux Dynamic Tracing Guide for a description of aggregation functions.

DTrace indexes the results of an aggregation using a tuple expression similar to that used for an associative array:

@name[list_of_keys] = aggregating_function(args);

The name of the aggregation is prefixed with an @ character. The keys describe the data that the aggregating function is collecting. If you do not specify a name for the aggregation, DTrace uses @ as an anonymous aggregation name, which is usually sufficient for simple D programs.

For example, the following command counts the number of write() system calls invoked by processes until you type Ctrl-C.

# dtrace -n 'syscall::write:entry { @["write() calls"] = count(); }'
dtrace: description 'syscall:::' matched 1 probe
^C

  write() calls                                              9
Note

Rather than create a separate D script for this simple example, we specify the probe and the action on the dtrace command line.

DTrace prints out the result of the aggregation automatically. Alternatively, you can use the printa() function to format the result of the aggregation.

The next example counts the number of both read() and write() system calls:

# dtrace -n 'syscall::write:entry,syscall::read:entry \
{ @[strjoin(probefunc,"() calls")] = count(); }'
dtrace: description 'syscall::write:entry,syscall::read:entry' matched 2 probes
^C

  write() calls                                            150
  read() calls                                            1555

The D program countsyscalls.d shown below counts the number of times that a process specified by its process ID invokes different system calls.

Example 2.14 countsyscalls.d: Count system calls invoked by a process

#!/usr/sbin/dtrace -qs

/* countsyscalls.d -- Count system calls invoked by a process */

syscall:::entry
/pid == $1/
{
  @num[probefunc] = count();
}

After making the syscalls.d file executable, you can run it from the command line, specifying a process ID as its argument:

# chmod +x countsyscalls.d
# ./countsyscalls.d $(pgrep -u guest firefox)
^C

  newuname                                                          1
  getdents                                                          2
  getsockname                                                       2
  clone                                                             3
  close                                                             3
  sched_setscheduler                                                3
  mmap                                                              6
  sched_get_priority_max                                            6
  sched_get_priority_min                                            6
  open                                                              7
  munmap                                                            9
  lseek                                                            16
  newfstat                                                         31
  access                                                           45
  write                                                            49
  fcntl                                                            58
  newstat                                                         104
  futex                                                          1045
  writev                                                         3102
  clock_gettime                                                  4079
  poll                                                           7938
  read                                                           9746
  gettimeofday                                                  10165

In this example, we use pgrep to determine the process ID of the firefox program that the user guest is running.

The following D program counts the number of times that a program reads from different files in ten seconds, and displays only the top five results.

Example 2.16 fdscount.d: Count the number of times that a program reads from different files

/* fdscount.d -- Count the number of times that a program reads from different files */

tick-10s
{
  exit(0);
}
  
syscall::read:entry
/execname==ENAME/
{ 
  @[fds[arg0].fi_pathname] = count(); 
} 

END 
{
  trunc(@,5);
}

We use the fds[] built-in array to determine which file corresponds to the file descriptor argument arg0 to read(). The fi_pathname member of the fileinfo_t structure indexed in fds[] by arg0 contains the full pathname of the file.

See fileinfo_t in the Oracle Linux Dynamic Tracing Guide for more information about the members of the fileinfo_t structure.

The trunc() function in the END action instructs DTrace to display only the top five results from the aggregation.

Before running the program, we load the profile, sdt and systrace kernel modules so that DTrace has access to the profile:::tick-10s probe, the fds[] built-in array, and the syscall::read:entry probe. We specify a C preprocessor directive to dtrace that sets the value of the ENAME variable to "thunderbird", which is the name of the Mozilla Thunderbird executable. We also need to use additional single quotes to escape the string quotes.

# modprobe profile
# modprobe sdt
# modprobe systrace
# dtrace -C -D ENAME='"thunderbird"' -qs fdscount.d

  /home/guest/.thunderbird/default/panacea.dat                    105
  /proc/4846/maps                                                 120
  /home/guest/.thunderbird/default/ImapMail/mydom.com/Sent-1.msf  281
  pipe:[57103]                                                    531
  socket:[57480]                                                22084

The /proc/pid/maps entry in the output is a file in the procfs file system that contains information about the process's mapped memory regions and their permissions. The pipe:[inode] and socket:[inode] entries refer to inodes in the pipefs and socketfs file systems.