We have described how the user interface fills in the desired
configuration of the counters and transmits the information to the
kernel. It is the job of the ->setup()
method
to actually program the performance counter registers. Clearly, the
details of how this is done is architecture-specific; it is also
model-specific on many architectures. For example, i386 provides methods
for each model type that programs the counter registers correctly
(see the op_model_*
files in
arch/i386/oprofile
for the details). The method
reads the values stored in the virtual oprofilefs files and programs
the registers appropriately, ready for starting the actual profiling
session.
The architecture-specific drivers make sure to save the old register settings before doing OProfile setup. They are restored when OProfile shuts down. This is useful, for example, on i386, where the NMI watchdog uses the same performance counter registers as OProfile; they cannot run concurrently, but OProfile makes sure to restore the setup it found before it was running.
In addition to programming the counter registers themselves, other setup is often necessary. For example, on i386, the local APIC needs programming in order to make the counter's overflow interrupt appear as an NMI (non-maskable interrupt). This allows sampling (and therefore profiling) of regions where "normal" interrupts are masked, enabling more reliable profiles.
Initiating a profiling session is done via writing an ASCII '1'
to the file /dev/oprofile/enable
. This sets up the
core, and calls into the architecture-specific driver to actually
enable each configured counter. Again, the details of how this is
done is model-specific (for example, the Athlon models can disable
or enable on a per-counter basis, unlike the PPro models).
The IA64 architecture provides a different interface from the other
architectures, using the existing perfmon driver. Register programming
is handled entirely in user-space (see
daemon/opd_perfmon.c
for the details). A process
is forked for each CPU, which creates a perfmon context and sets the
counter registers appropriately via the
sys_perfmonctl
interface. In addition, the actual
initiation and termination of the profiling session is handled via the
same interface using PFM_START
and
PFM_STOP
. On IA64, then, there are no oprofilefs
files for the performance counters, as the kernel driver does not
program the registers itself.
Instead, the perfmon driver for OProfile simply registers with the
OProfile core with an OProfile-specific UUID. During a profiling
session, the perfmon core calls into the OProfile perfmon driver and
samples are registered with the OProfile core itself as usual (with
oprofile_add_sample()
).