As mentioned, the sample is logged into the buffer specific to the current CPU. The CPU buffer is a simple array of pairs of unsigned long values; for a sample, they hold the PC value and the counter for the sample. (The counter value is later used to translate back into the relevant event type the counter was programmed to).
In addition to logging the sample itself, we also log task switches.
This is simply done by storing the address of the last task to log a
sample on that CPU in a data structure, and writing a task switch entry
into the buffer if the new value of current()
has
changed. Note that later we will directly de-reference this pointer;
this imposes certain restrictions on when and how the CPU buffers need
to be processed.
Finally, as mentioned, we log whether we have changed between kernel and
userspace using a similar method. Both of these variables
(last_task
and last_is_kernel
) are
reset when the CPU buffer is read.