Table of Contents
All of the tools used to generate human-readable output have to take roughly the same steps to collect the data for processing. First, the profile specification given by the user has to be parsed. Next, a list of sample files matching the specification has to obtained. Using this list, we need to locate the binary file for each sample file, and then use them to extract meaningful data, before a final collation and presentation to the user.
The profile specification presented by the user is parsed in
the function profile_spec::create()
. This
creates an object representing the specification. Then we
use profile_spec::generate_file_list()
to search for all sample files and match them against the
profile_spec
.
To enable this matching process to work, the attributes of each sample file is encoded in its filename. This is a low-tech approach to matching specifications against candidate sample files, but it works reasonably well. A typical sample file might look like these:
/var/lib/oprofile/samples/current/{root}/bin/ls/{dep}/{root}/bin/ls/{cg}/{root}/bin/ls/CPU_CLK_UNHALTED.100000.0.all.all.all /var/lib/oprofile/samples/current/{root}/bin/ls/{dep}/{root}/bin/ls/CPU_CLK_UNHALTED.100000.0.all.all.all /var/lib/oprofile/samples/current/{root}/bin/ls/{dep}/{root}/bin/ls/CPU_CLK_UNHALTED.100000.0.7423.7424.0 /var/lib/oprofile/samples/current/{kern}/r128/{dep}/{kern}/r128/CPU_CLK_UNHALTED.100000.0.all.all.all |
This looks unnecessarily complex, but it's actually fairly simple. First
we have the session of the sample, by default located here
/var/lib/oprofile/samples/current
. This location
can be changed by specifying the --session-dir option at command-line.
This session could equally well be inside an archive from oparchive.
Next we have one of the tokens {root}
or
{kern}
. {root}
indicates
that the binary is found on a file system, and we will encode its path
in the next section (e.g. /bin/ls
).
{kern}
indicates a kernel module - on 2.6 kernels
the path information is not available from the kernel, so we have to
special-case kernel modules like this; we encode merely the name of the
module as loaded.
Next there is a {dep}
token, indicating another
token/path which identifies the dependent binary image. This is used even for
the "primary" binary (i.e. the one that was
execve()
d), as it simplifies processing. Finally,
if this sample file is a normal flat profile, the actual file is next in
the path. If it's a call-graph sample file, we need one further
specification, to allow us to identify cross-binary arcs in the call
graph.
The actual sample file name is dot-separated, where the fields are, in order: event name, event count, unit mask, task group ID, task ID, and CPU number.
This sample file can be reliably parsed (with
parse_filename()
) into a
filename_spec
. Finally, we can check whether to
include the sample file in the final results by comparing this
filename_spec
against the
profile_spec
the user specified (for the interested,
see valid_candidate()
and
profile_spec::match
). Then comes the really
complicated bit...