Chapter 4. Generating sample files

Table of Contents

1. Processing the buffer
1.1. Handling kernel samples
2. Locating and creating sample files
3. Writing data to a sample file

1. Processing the buffer

Now we can move onto user-space in our description of how raw interrupt samples are processed into useful information. As we described in previous sections, the kernel OProfile driver creates a large buffer of sample data consisting of offset values, interspersed with notification of changes in context. These context changes indicate how following samples should be attributed, and include task switches, CPU changes, and which dcookie the sample value is against. By processing this buffer entry-by-entry, we can determine where the samples should be accredited to. This is particularly important when using the --separate.

The file daemon/opd_trans.c contains the basic routine for the buffer processing. The struct transient structure is used to hold changes in context. Its members are modified as we process each entry; it is passed into the routines in daemon/opd_sfile.c for actually logging the sample to a particular sample file (which will be held in $SESSION_DIR/samples/current).

The buffer format is designed for conciseness, as high sampling rates can easily generate a lot of data. Thus, context changes are prefixed by an escape code, identified by is_escape_code(). If an escape code is found, the next entry in the buffer identifies what type of context change is being read. These are handed off to various handlers (see the handlers array), which modify the transient structure as appropriate. If it's not an escape code, then it must be a PC offset value, and the very next entry will be the numeric hardware counter. These values are read and recorded in the transient structure; we then do a lookup to find the correct sample file, and log the sample, as described in the next section.

1.1. Handling kernel samples

Samples from kernel code require a little special handling. Because the binary text which the sample is against does not correspond to any file that the kernel directly knows about, the OProfile driver stores the absolute PC value in the buffer, instead of the file offset. Of course, we need an offset against some particular binary. To handle this, we keep a list of loaded modules by parsing /proc/modules as needed. When a module is loaded, a notification is placed in the OProfile buffer, and this triggers a re-read. We store the module name, and the loading address and size. This is also done for the main kernel image, as specified by the user. The absolute PC value is matched against each address range, and modified into an offset when the matching module is found. See daemon/opd_kernel.c for the details.