| perf-intel-pt(1) |
| ================ |
| |
| NAME |
| ---- |
| perf-intel-pt - Support for Intel Processor Trace within perf tools |
| |
| SYNOPSIS |
| -------- |
| [verse] |
| 'perf record' -e intel_pt// |
| |
| DESCRIPTION |
| ----------- |
| |
| Intel Processor Trace (Intel PT) is an extension of Intel Architecture that |
| collects information about software execution such as control flow, execution |
| modes and timings and formats it into highly compressed binary packets. |
| Technical details are documented in the Intel 64 and IA-32 Architectures |
| Software Developer Manuals, Chapter 36 Intel Processor Trace. |
| |
| Intel PT is first supported in Intel Core M and 5th generation Intel Core |
| processors that are based on the Intel micro-architecture code name Broadwell. |
| |
| Trace data is collected by 'perf record' and stored within the perf.data file. |
| See below for options to 'perf record'. |
| |
| Trace data must be 'decoded' which involves walking the object code and matching |
| the trace data packets. For example a TNT packet only tells whether a |
| conditional branch was taken or not taken, so to make use of that packet the |
| decoder must know precisely which instruction was being executed. |
| |
| Decoding is done on-the-fly. The decoder outputs samples in the same format as |
| samples output by perf hardware events, for example as though the "instructions" |
| or "branches" events had been recorded. Presently 3 tools support this: |
| 'perf script', 'perf report' and 'perf inject'. See below for more information |
| on using those tools. |
| |
| The main distinguishing feature of Intel PT is that the decoder can determine |
| the exact flow of software execution. Intel PT can be used to understand why |
| and how did software get to a certain point, or behave a certain way. The |
| software does not have to be recompiled, so Intel PT works with debug or release |
| builds, however the executed images are needed - which makes use in JIT-compiled |
| environments, or with self-modified code, a challenge. Also symbols need to be |
| provided to make sense of addresses. |
| |
| A limitation of Intel PT is that it produces huge amounts of trace data |
| (hundreds of megabytes per second per core) which takes a long time to decode, |
| for example two or three orders of magnitude longer than it took to collect. |
| Another limitation is the performance impact of tracing, something that will |
| vary depending on the use-case and architecture. |
| |
| |
| Quickstart |
| ---------- |
| |
| It is important to start small. That is because it is easy to capture vastly |
| more data than can possibly be processed. |
| |
| The simplest thing to do with Intel PT is userspace profiling of small programs. |
| Data is captured with 'perf record' e.g. to trace 'ls' userspace-only: |
| |
| perf record -e intel_pt//u ls |
| |
| And profiled with 'perf report' e.g. |
| |
| perf report |
| |
| To also trace kernel space presents a problem, namely kernel self-modifying |
| code. A fairly good kernel image is available in /proc/kcore but to get an |
| accurate image a copy of /proc/kcore needs to be made under the same conditions |
| as the data capture. 'perf record' can make a copy of /proc/kcore if the option |
| --kcore is used, but access to /proc/kcore is restricted e.g. |
| |
| sudo perf record -o pt_ls --kcore -e intel_pt// -- ls |
| |
| which will create a directory named 'pt_ls' and put the perf.data file (named |
| simply 'data') and copies of /proc/kcore, /proc/kallsyms and /proc/modules into |
| it. The other tools understand the directory format, so to use 'perf report' |
| becomes: |
| |
| sudo perf report -i pt_ls |
| |
| Because samples are synthesized after-the-fact, the sampling period can be |
| selected for reporting. e.g. sample every microsecond |
| |
| sudo perf report pt_ls --itrace=i1usge |
| |
| See the sections below for more information about the --itrace option. |
| |
| Beware the smaller the period, the more samples that are produced, and the |
| longer it takes to process them. |
| |
| Also note that the coarseness of Intel PT timing information will start to |
| distort the statistical value of the sampling as the sampling period becomes |
| smaller. |
| |
| To represent software control flow, "branches" samples are produced. By default |
| a branch sample is synthesized for every single branch. To get an idea what |
| data is available you can use the 'perf script' tool with all itrace sampling |
| options, which will list all the samples. |
| |
| perf record -e intel_pt//u ls |
| perf script --itrace=ibxwpe |
| |
| An interesting field that is not printed by default is 'flags' which can be |
| displayed as follows: |
| |
| perf script --itrace=ibxwpe -F+flags |
| |
| The flags are "bcrosyiABExgh" which stand for branch, call, return, conditional, |
| system, asynchronous, interrupt, transaction abort, trace begin, trace end, |
| in transaction, VM-entry, and VM-exit respectively. |
| |
| perf script also supports higher level ways to dump instruction traces: |
| |
| perf script --insn-trace --xed |
| |
| Dump all instructions. This requires installing the xed tool (see XED below) |
| Dumping all instructions in a long trace can be fairly slow. It is usually better |
| to start with higher level decoding, like |
| |
| perf script --call-trace |
| |
| or |
| |
| perf script --call-ret-trace |
| |
| and then select a time range of interest. The time range can then be examined |
| in detail with |
| |
| perf script --time starttime,stoptime --insn-trace --xed |
| |
| While examining the trace it's also useful to filter on specific CPUs using |
| the -C option |
| |
| perf script --time starttime,stoptime --insn-trace --xed -C 1 |
| |
| Dump all instructions in time range on CPU 1. |
| |
| Another interesting field that is not printed by default is 'ipc' which can be |
| displayed as follows: |
| |
| perf script --itrace=be -F+ipc |
| |
| There are two ways that instructions-per-cycle (IPC) can be calculated depending |
| on the recording. |
| |
| If the 'cyc' config term (see config terms section below) was used, then IPC is |
| calculated using the cycle count from CYC packets, otherwise MTC packets are |
| used - refer to the 'mtc' config term. When MTC is used, however, the values |
| are less accurate because the timing is less accurate. |
| |
| Because Intel PT does not update the cycle count on every branch or instruction, |
| the values will often be zero. When there are values, they will be the number |
| of instructions and number of cycles since the last update, and thus represent |
| the average IPC since the last IPC for that event type. Note IPC for "branches" |
| events is calculated separately from IPC for "instructions" events. |
| |
| Also note that the IPC instruction count may or may not include the current |
| instruction. If the cycle count is associated with an asynchronous branch |
| (e.g. page fault or interrupt), then the instruction count does not include the |
| current instruction, otherwise it does. That is consistent with whether or not |
| that instruction has retired when the cycle count is updated. |
| |
| Another note, in the case of "branches" events, non-taken branches are not |
| presently sampled, so IPC values for them do not appear e.g. a CYC packet with a |
| TNT packet that starts with a non-taken branch. To see every possible IPC |
| value, "instructions" events can be used e.g. --itrace=i0ns |
| |
| While it is possible to create scripts to analyze the data, an alternative |
| approach is available to export the data to a sqlite or postgresql database. |
| Refer to script export-to-sqlite.py or export-to-postgresql.py for more details, |
| and to script exported-sql-viewer.py for an example of using the database. |
| |
| There is also script intel-pt-events.py which provides an example of how to |
| unpack the raw data for power events and PTWRITE. The script also displays |
| branches, and supports 2 additional modes selected by option: |
| |
| --insn-trace - instruction trace |
| --src-trace - source trace |
| |
| As mentioned above, it is easy to capture too much data. One way to limit the |
| data captured is to use 'snapshot' mode which is explained further below. |
| Refer to 'new snapshot option' and 'Intel PT modes of operation' further below. |
| |
| Another problem that will be experienced is decoder errors. They can be caused |
| by inability to access the executed image, self-modified or JIT-ed code, or the |
| inability to match side-band information (such as context switches and mmaps) |
| which results in the decoder not knowing what code was executed. |
| |
| There is also the problem of perf not being able to copy the data fast enough, |
| resulting in data lost because the buffer was full. See 'Buffer handling' below |
| for more details. |
| |
| |
| perf record |
| ----------- |
| |
| new event |
| ~~~~~~~~~ |
| |
| The Intel PT kernel driver creates a new PMU for Intel PT. PMU events are |
| selected by providing the PMU name followed by the "config" separated by slashes. |
| An enhancement has been made to allow default "config" e.g. the option |
| |
| -e intel_pt// |
| |
| will use a default config value. Currently that is the same as |
| |
| -e intel_pt/tsc,noretcomp=0/ |
| |
| which is the same as |
| |
| -e intel_pt/tsc=1,noretcomp=0/ |
| |
| Note there are now new config terms - see section 'config terms' further below. |
| |
| The config terms are listed in /sys/devices/intel_pt/format. They are bit |
| fields within the config member of the struct perf_event_attr which is |
| passed to the kernel by the perf_event_open system call. They correspond to bit |
| fields in the IA32_RTIT_CTL MSR. Here is a list of them and their definitions: |
| |
| $ grep -H . /sys/bus/event_source/devices/intel_pt/format/* |
| /sys/bus/event_source/devices/intel_pt/format/cyc:config:1 |
| /sys/bus/event_source/devices/intel_pt/format/cyc_thresh:config:19-22 |
| /sys/bus/event_source/devices/intel_pt/format/mtc:config:9 |
| /sys/bus/event_source/devices/intel_pt/format/mtc_period:config:14-17 |
| /sys/bus/event_source/devices/intel_pt/format/noretcomp:config:11 |
| /sys/bus/event_source/devices/intel_pt/format/psb_period:config:24-27 |
| /sys/bus/event_source/devices/intel_pt/format/tsc:config:10 |
| |
| Note that the default config must be overridden for each term i.e. |
| |
| -e intel_pt/noretcomp=0/ |
| |
| is the same as: |
| |
| -e intel_pt/tsc=1,noretcomp=0/ |
| |
| So, to disable TSC packets use: |
| |
| -e intel_pt/tsc=0/ |
| |
| It is also possible to specify the config value explicitly: |
| |
| -e intel_pt/config=0x400/ |
| |
| Note that, as with all events, the event is suffixed with event modifiers: |
| |
| u userspace |
| k kernel |
| h hypervisor |
| G guest |
| H host |
| p precise ip |
| |
| 'h', 'G' and 'H' are for virtualization which is not supported by Intel PT. |
| 'p' is also not relevant to Intel PT. So only options 'u' and 'k' are |
| meaningful for Intel PT. |
| |
| perf_event_attr is displayed if the -vv option is used e.g. |
| |
| ------------------------------------------------------------ |
| perf_event_attr: |
| type 6 |
| size 112 |
| config 0x400 |
| { sample_period, sample_freq } 1 |
| sample_type IP|TID|TIME|CPU|IDENTIFIER |
| read_format ID |
| disabled 1 |
| inherit 1 |
| exclude_kernel 1 |
| exclude_hv 1 |
| enable_on_exec 1 |
| sample_id_all 1 |
| ------------------------------------------------------------ |
| sys_perf_event_open: pid 31104 cpu 0 group_fd -1 flags 0x8 |
| sys_perf_event_open: pid 31104 cpu 1 group_fd -1 flags 0x8 |
| sys_perf_event_open: pid 31104 cpu 2 group_fd -1 flags 0x8 |
| sys_perf_event_open: pid 31104 cpu 3 group_fd -1 flags 0x8 |
| ------------------------------------------------------------ |
| |
| |
| config terms |
| ~~~~~~~~~~~~ |
| |
| The June 2015 version of Intel 64 and IA-32 Architectures Software Developer |
| Manuals, Chapter 36 Intel Processor Trace, defined new Intel PT features. |
| Some of the features are reflect in new config terms. All the config terms are |
| described below. |
| |
| tsc Always supported. Produces TSC timestamp packets to provide |
| timing information. In some cases it is possible to decode |
| without timing information, for example a per-thread context |
| that does not overlap executable memory maps. |
| |
| The default config selects tsc (i.e. tsc=1). |
| |
| noretcomp Always supported. Disables "return compression" so a TIP packet |
| is produced when a function returns. Causes more packets to be |
| produced but might make decoding more reliable. |
| |
| The default config does not select noretcomp (i.e. noretcomp=0). |
| |
| psb_period Allows the frequency of PSB packets to be specified. |
| |
| The PSB packet is a synchronization packet that provides a |
| starting point for decoding or recovery from errors. |
| |
| Support for psb_period is indicated by: |
| |
| /sys/bus/event_source/devices/intel_pt/caps/psb_cyc |
| |
| which contains "1" if the feature is supported and "0" |
| otherwise. |
| |
| Valid values are given by: |
| |
| /sys/bus/event_source/devices/intel_pt/caps/psb_periods |
| |
| which contains a hexadecimal value, the bits of which represent |
| valid values e.g. bit 2 set means value 2 is valid. |
| |
| The psb_period value is converted to the approximate number of |
| trace bytes between PSB packets as: |
| |
| 2 ^ (value + 11) |
| |
| e.g. value 3 means 16KiB bytes between PSBs |
| |
| If an invalid value is entered, the error message |
| will give a list of valid values e.g. |
| |
| $ perf record -e intel_pt/psb_period=15/u uname |
| Invalid psb_period for intel_pt. Valid values are: 0-5 |
| |
| If MTC packets are selected, the default config selects a value |
| of 3 (i.e. psb_period=3) or the nearest lower value that is |
| supported (0 is always supported). Otherwise the default is 0. |
| |
| If decoding is expected to be reliable and the buffer is large |
| then a large PSB period can be used. |
| |
| Because a TSC packet is produced with PSB, the PSB period can |
| also affect the granularity to timing information in the absence |
| of MTC or CYC. |
| |
| mtc Produces MTC timing packets. |
| |
| MTC packets provide finer grain timestamp information than TSC |
| packets. MTC packets record time using the hardware crystal |
| clock (CTC) which is related to TSC packets using a TMA packet. |
| |
| Support for this feature is indicated by: |
| |
| /sys/bus/event_source/devices/intel_pt/caps/mtc |
| |
| which contains "1" if the feature is supported and |
| "0" otherwise. |
| |
| The frequency of MTC packets can also be specified - see |
| mtc_period below. |
| |
| mtc_period Specifies how frequently MTC packets are produced - see mtc |
| above for how to determine if MTC packets are supported. |
| |
| Valid values are given by: |
| |
| /sys/bus/event_source/devices/intel_pt/caps/mtc_periods |
| |
| which contains a hexadecimal value, the bits of which represent |
| valid values e.g. bit 2 set means value 2 is valid. |
| |
| The mtc_period value is converted to the MTC frequency as: |
| |
| CTC-frequency / (2 ^ value) |
| |
| e.g. value 3 means one eighth of CTC-frequency |
| |
| Where CTC is the hardware crystal clock, the frequency of which |
| can be related to TSC via values provided in cpuid leaf 0x15. |
| |
| If an invalid value is entered, the error message |
| will give a list of valid values e.g. |
| |
| $ perf record -e intel_pt/mtc_period=15/u uname |
| Invalid mtc_period for intel_pt. Valid values are: 0,3,6,9 |
| |
| The default value is 3 or the nearest lower value |
| that is supported (0 is always supported). |
| |
| cyc Produces CYC timing packets. |
| |
| CYC packets provide even finer grain timestamp information than |
| MTC and TSC packets. A CYC packet contains the number of CPU |
| cycles since the last CYC packet. Unlike MTC and TSC packets, |
| CYC packets are only sent when another packet is also sent. |
| |
| Support for this feature is indicated by: |
| |
| /sys/bus/event_source/devices/intel_pt/caps/psb_cyc |
| |
| which contains "1" if the feature is supported and |
| "0" otherwise. |
| |
| The number of CYC packets produced can be reduced by specifying |
| a threshold - see cyc_thresh below. |
| |
| cyc_thresh Specifies how frequently CYC packets are produced - see cyc |
| above for how to determine if CYC packets are supported. |
| |
| Valid cyc_thresh values are given by: |
| |
| /sys/bus/event_source/devices/intel_pt/caps/cycle_thresholds |
| |
| which contains a hexadecimal value, the bits of which represent |
| valid values e.g. bit 2 set means value 2 is valid. |
| |
| The cyc_thresh value represents the minimum number of CPU cycles |
| that must have passed before a CYC packet can be sent. The |
| number of CPU cycles is: |
| |
| 2 ^ (value - 1) |
| |
| e.g. value 4 means 8 CPU cycles must pass before a CYC packet |
| can be sent. Note a CYC packet is still only sent when another |
| packet is sent, not at, e.g. every 8 CPU cycles. |
| |
| If an invalid value is entered, the error message |
| will give a list of valid values e.g. |
| |
| $ perf record -e intel_pt/cyc,cyc_thresh=15/u uname |
| Invalid cyc_thresh for intel_pt. Valid values are: 0-12 |
| |
| CYC packets are not requested by default. |
| |
| pt Specifies pass-through which enables the 'branch' config term. |
| |
| The default config selects 'pt' if it is available, so a user will |
| never need to specify this term. |
| |
| branch Enable branch tracing. Branch tracing is enabled by default so to |
| disable branch tracing use 'branch=0'. |
| |
| The default config selects 'branch' if it is available. |
| |
| ptw Enable PTWRITE packets which are produced when a ptwrite instruction |
| is executed. |
| |
| Support for this feature is indicated by: |
| |
| /sys/bus/event_source/devices/intel_pt/caps/ptwrite |
| |
| which contains "1" if the feature is supported and |
| "0" otherwise. |
| |
| fup_on_ptw Enable a FUP packet to follow the PTWRITE packet. The FUP packet |
| provides the address of the ptwrite instruction. In the absence of |
| fup_on_ptw, the decoder will use the address of the previous branch |
| if branch tracing is enabled, otherwise the address will be zero. |
| Note that fup_on_ptw will work even when branch tracing is disabled. |
| |
| pwr_evt Enable power events. The power events provide information about |
| changes to the CPU C-state. |
| |
| Support for this feature is indicated by: |
| |
| /sys/bus/event_source/devices/intel_pt/caps/power_event_trace |
| |
| which contains "1" if the feature is supported and |
| "0" otherwise. |
| |
| |
| AUX area sampling option |
| ~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| To select Intel PT "sampling" the AUX area sampling option can be used: |
| |
| --aux-sample |
| |
| Optionally it can be followed by the sample size in bytes e.g. |
| |
| --aux-sample=8192 |
| |
| In addition, the Intel PT event to sample must be defined e.g. |
| |
| -e intel_pt//u |
| |
| Samples on other events will be created containing Intel PT data e.g. the |
| following will create Intel PT samples on the branch-misses event, note the |
| events must be grouped using {}: |
| |
| perf record --aux-sample -e '{intel_pt//u,branch-misses:u}' |
| |
| An alternative to '--aux-sample' is to add the config term 'aux-sample-size' to |
| events. In this case, the grouping is implied e.g. |
| |
| perf record -e intel_pt//u -e branch-misses/aux-sample-size=8192/u |
| |
| is the same as: |
| |
| perf record -e '{intel_pt//u,branch-misses/aux-sample-size=8192/u}' |
| |
| but allows for also using an address filter e.g.: |
| |
| perf record -e intel_pt//u --filter 'filter * @/bin/ls' -e branch-misses/aux-sample-size=8192/u -- ls |
| |
| It is important to select a sample size that is big enough to contain at least |
| one PSB packet. If not a warning will be displayed: |
| |
| Intel PT sample size (%zu) may be too small for PSB period (%zu) |
| |
| The calculation used for that is: if sample_size <= psb_period + 256 display the |
| warning. When sampling is used, psb_period defaults to 0 (2KiB). |
| |
| The default sample size is 4KiB. |
| |
| The sample size is passed in aux_sample_size in struct perf_event_attr. The |
| sample size is limited by the maximum event size which is 64KiB. It is |
| difficult to know how big the event might be without the trace sample attached, |
| but the tool validates that the sample size is not greater than 60KiB. |
| |
| |
| new snapshot option |
| ~~~~~~~~~~~~~~~~~~~ |
| |
| The difference between full trace and snapshot from the kernel's perspective is |
| that in full trace we don't overwrite trace data that the user hasn't collected |
| yet (and indicated that by advancing aux_tail), whereas in snapshot mode we let |
| the trace run and overwrite older data in the buffer so that whenever something |
| interesting happens, we can stop it and grab a snapshot of what was going on |
| around that interesting moment. |
| |
| To select snapshot mode a new option has been added: |
| |
| -S |
| |
| Optionally it can be followed by the snapshot size e.g. |
| |
| -S0x100000 |
| |
| The default snapshot size is the auxtrace mmap size. If neither auxtrace mmap size |
| nor snapshot size is specified, then the default is 4MiB for privileged users |
| (or if /proc/sys/kernel/perf_event_paranoid < 0), 128KiB for unprivileged users. |
| If an unprivileged user does not specify mmap pages, the mmap pages will be |
| reduced as described in the 'new auxtrace mmap size option' section below. |
| |
| The snapshot size is displayed if the option -vv is used e.g. |
| |
| Intel PT snapshot size: %zu |
| |
| |
| new auxtrace mmap size option |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Intel PT buffer size is specified by an addition to the -m option e.g. |
| |
| -m,16 |
| |
| selects a buffer size of 16 pages i.e. 64KiB. |
| |
| Note that the existing functionality of -m is unchanged. The auxtrace mmap size |
| is specified by the optional addition of a comma and the value. |
| |
| The default auxtrace mmap size for Intel PT is 4MiB/page_size for privileged users |
| (or if /proc/sys/kernel/perf_event_paranoid < 0), 128KiB for unprivileged users. |
| If an unprivileged user does not specify mmap pages, the mmap pages will be |
| reduced from the default 512KiB/page_size to 256KiB/page_size, otherwise the |
| user is likely to get an error as they exceed their mlock limit (Max locked |
| memory as shown in /proc/self/limits). Note that perf does not count the first |
| 512KiB (actually /proc/sys/kernel/perf_event_mlock_kb minus 1 page) per cpu |
| against the mlock limit so an unprivileged user is allowed 512KiB per cpu plus |
| their mlock limit (which defaults to 64KiB but is not multiplied by the number |
| of cpus). |
| |
| In full-trace mode, powers of two are allowed for buffer size, with a minimum |
| size of 2 pages. In snapshot mode or sampling mode, it is the same but the |
| minimum size is 1 page. |
| |
| The mmap size and auxtrace mmap size are displayed if the -vv option is used e.g. |
| |
| mmap length 528384 |
| auxtrace mmap length 4198400 |
| |
| |
| Intel PT modes of operation |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Intel PT can be used in 3 modes: |
| full-trace mode |
| sample mode |
| snapshot mode |
| |
| Full-trace mode traces continuously e.g. |
| |
| perf record -e intel_pt//u uname |
| |
| Sample mode attaches a Intel PT sample to other events e.g. |
| |
| perf record --aux-sample -e intel_pt//u -e branch-misses:u |
| |
| Snapshot mode captures the available data when a signal is sent or "snapshot" |
| control command is issued. e.g. using a signal |
| |
| perf record -v -e intel_pt//u -S ./loopy 1000000000 & |
| [1] 11435 |
| kill -USR2 11435 |
| Recording AUX area tracing snapshot |
| |
| Note that the signal sent is SIGUSR2. |
| Note that "Recording AUX area tracing snapshot" is displayed because the -v |
| option is used. |
| |
| The advantage of using "snapshot" control command is that the access is |
| controlled by access to a FIFO e.g. |
| |
| $ mkfifo perf.control |
| $ mkfifo perf.ack |
| $ cat perf.ack & |
| [1] 15235 |
| $ sudo ~/bin/perf record --control fifo:perf.control,perf.ack -S -e intel_pt//u -- sleep 60 & |
| [2] 15243 |
| $ ps -e | grep perf |
| 15244 pts/1 00:00:00 perf |
| $ kill -USR2 15244 |
| bash: kill: (15244) - Operation not permitted |
| $ echo snapshot > perf.control |
| ack |
| |
| The 3 Intel PT modes of operation cannot be used together. |
| |
| |
| Buffer handling |
| ~~~~~~~~~~~~~~~ |
| |
| There may be buffer limitations (i.e. single ToPa entry) which means that actual |
| buffer sizes are limited to powers of 2 up to 4MiB (MAX_ORDER). In order to |
| provide other sizes, and in particular an arbitrarily large size, multiple |
| buffers are logically concatenated. However an interrupt must be used to switch |
| between buffers. That has two potential problems: |
| a) the interrupt may not be handled in time so that the current buffer |
| becomes full and some trace data is lost. |
| b) the interrupts may slow the system and affect the performance |
| results. |
| |
| If trace data is lost, the driver sets 'truncated' in the PERF_RECORD_AUX event |
| which the tools report as an error. |
| |
| In full-trace mode, the driver waits for data to be copied out before allowing |
| the (logical) buffer to wrap-around. If data is not copied out quickly enough, |
| again 'truncated' is set in the PERF_RECORD_AUX event. If the driver has to |
| wait, the intel_pt event gets disabled. Because it is difficult to know when |
| that happens, perf tools always re-enable the intel_pt event after copying out |
| data. |
| |
| |
| Intel PT and build ids |
| ~~~~~~~~~~~~~~~~~~~~~~ |
| |
| By default "perf record" post-processes the event stream to find all build ids |
| for executables for all addresses sampled. Deliberately, Intel PT is not |
| decoded for that purpose (it would take too long). Instead the build ids for |
| all executables encountered (due to mmap, comm or task events) are included |
| in the perf.data file. |
| |
| To see buildids included in the perf.data file use the command: |
| |
| perf buildid-list |
| |
| If the perf.data file contains Intel PT data, that is the same as: |
| |
| perf buildid-list --with-hits |
| |
| |
| Snapshot mode and event disabling |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| In order to make a snapshot, the intel_pt event is disabled using an IOCTL, |
| namely PERF_EVENT_IOC_DISABLE. However doing that can also disable the |
| collection of side-band information. In order to prevent that, a dummy |
| software event has been introduced that permits tracking events (like mmaps) to |
| continue to be recorded while intel_pt is disabled. That is important to ensure |
| there is complete side-band information to allow the decoding of subsequent |
| snapshots. |
| |
| A test has been created for that. To find the test: |
| |
| perf test list |
| ... |
| 23: Test using a dummy software event to keep tracking |
| |
| To run the test: |
| |
| perf test 23 |
| 23: Test using a dummy software event to keep tracking : Ok |
| |
| |
| perf record modes (nothing new here) |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| perf record essentially operates in one of three modes: |
| per thread |
| per cpu |
| workload only |
| |
| "per thread" mode is selected by -t or by --per-thread (with -p or -u or just a |
| workload). |
| "per cpu" is selected by -C or -a. |
| "workload only" mode is selected by not using the other options but providing a |
| command to run (i.e. the workload). |
| |
| In per-thread mode an exact list of threads is traced. There is no inheritance. |
| Each thread has its own event buffer. |
| |
| In per-cpu mode all processes (or processes from the selected cgroup i.e. -G |
| option, or processes selected with -p or -u) are traced. Each cpu has its own |
| buffer. Inheritance is allowed. |
| |
| In workload-only mode, the workload is traced but with per-cpu buffers. |
| Inheritance is allowed. Note that you can now trace a workload in per-thread |
| mode by using the --per-thread option. |
| |
| |
| Privileged vs non-privileged users |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Unless /proc/sys/kernel/perf_event_paranoid is set to -1, unprivileged users |
| have memory limits imposed upon them. That affects what buffer sizes they can |
| have as outlined above. |
| |
| The v4.2 kernel introduced support for a context switch metadata event, |
| PERF_RECORD_SWITCH, which allows unprivileged users to see when their processes |
| are scheduled out and in, just not by whom, which is left for the |
| PERF_RECORD_SWITCH_CPU_WIDE, that is only accessible in system wide context, |
| which in turn requires CAP_PERFMON or CAP_SYS_ADMIN. |
| |
| Please see the 45ac1403f564 ("perf: Add PERF_RECORD_SWITCH to indicate context |
| switches") commit, that introduces these metadata events for further info. |
| |
| When working with kernels < v4.2, the following considerations must be taken, |
| as the sched:sched_switch tracepoints will be used to receive such information: |
| |
| Unless /proc/sys/kernel/perf_event_paranoid is set to -1, unprivileged users are |
| not permitted to use tracepoints which means there is insufficient side-band |
| information to decode Intel PT in per-cpu mode, and potentially workload-only |
| mode too if the workload creates new processes. |
| |
| Note also, that to use tracepoints, read-access to debugfs is required. So if |
| debugfs is not mounted or the user does not have read-access, it will again not |
| be possible to decode Intel PT in per-cpu mode. |
| |
| |
| sched_switch tracepoint |
| ~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| The sched_switch tracepoint is used to provide side-band data for Intel PT |
| decoding in kernels where the PERF_RECORD_SWITCH metadata event isn't |
| available. |
| |
| The sched_switch events are automatically added. e.g. the second event shown |
| below: |
| |
| $ perf record -vv -e intel_pt//u uname |
| ------------------------------------------------------------ |
| perf_event_attr: |
| type 6 |
| size 112 |
| config 0x400 |
| { sample_period, sample_freq } 1 |
| sample_type IP|TID|TIME|CPU|IDENTIFIER |
| read_format ID |
| disabled 1 |
| inherit 1 |
| exclude_kernel 1 |
| exclude_hv 1 |
| enable_on_exec 1 |
| sample_id_all 1 |
| ------------------------------------------------------------ |
| sys_perf_event_open: pid 31104 cpu 0 group_fd -1 flags 0x8 |
| sys_perf_event_open: pid 31104 cpu 1 group_fd -1 flags 0x8 |
| sys_perf_event_open: pid 31104 cpu 2 group_fd -1 flags 0x8 |
| sys_perf_event_open: pid 31104 cpu 3 group_fd -1 flags 0x8 |
| ------------------------------------------------------------ |
| perf_event_attr: |
| type 2 |
| size 112 |
| config 0x108 |
| { sample_period, sample_freq } 1 |
| sample_type IP|TID|TIME|CPU|PERIOD|RAW|IDENTIFIER |
| read_format ID |
| inherit 1 |
| sample_id_all 1 |
| exclude_guest 1 |
| ------------------------------------------------------------ |
| sys_perf_event_open: pid -1 cpu 0 group_fd -1 flags 0x8 |
| sys_perf_event_open: pid -1 cpu 1 group_fd -1 flags 0x8 |
| sys_perf_event_open: pid -1 cpu 2 group_fd -1 flags 0x8 |
| sys_perf_event_open: pid -1 cpu 3 group_fd -1 flags 0x8 |
| ------------------------------------------------------------ |
| perf_event_attr: |
| type 1 |
| size 112 |
| config 0x9 |
| { sample_period, sample_freq } 1 |
| sample_type IP|TID|TIME|IDENTIFIER |
| read_format ID |
| disabled 1 |
| inherit 1 |
| exclude_kernel 1 |
| exclude_hv 1 |
| mmap 1 |
| comm 1 |
| enable_on_exec 1 |
| task 1 |
| sample_id_all 1 |
| mmap2 1 |
| comm_exec 1 |
| ------------------------------------------------------------ |
| sys_perf_event_open: pid 31104 cpu 0 group_fd -1 flags 0x8 |
| sys_perf_event_open: pid 31104 cpu 1 group_fd -1 flags 0x8 |
| sys_perf_event_open: pid 31104 cpu 2 group_fd -1 flags 0x8 |
| sys_perf_event_open: pid 31104 cpu 3 group_fd -1 flags 0x8 |
| mmap size 528384B |
| AUX area mmap length 4194304 |
| perf event ring buffer mmapped per cpu |
| Synthesizing auxtrace information |
| Linux |
| [ perf record: Woken up 1 times to write data ] |
| [ perf record: Captured and wrote 0.042 MB perf.data ] |
| |
| Note, the sched_switch event is only added if the user is permitted to use it |
| and only in per-cpu mode. |
| |
| Note also, the sched_switch event is only added if TSC packets are requested. |
| That is because, in the absence of timing information, the sched_switch events |
| cannot be matched against the Intel PT trace. |
| |
| |
| perf script |
| ----------- |
| |
| By default, perf script will decode trace data found in the perf.data file. |
| This can be further controlled by new option --itrace. |
| |
| |
| New --itrace option |
| ~~~~~~~~~~~~~~~~~~~ |
| |
| Having no option is the same as |
| |
| --itrace |
| |
| which, in turn, is the same as |
| |
| --itrace=cepwx |
| |
| The letters are: |
| |
| i synthesize "instructions" events |
| b synthesize "branches" events |
| x synthesize "transactions" events |
| w synthesize "ptwrite" events |
| p synthesize "power" events (incl. PSB events) |
| c synthesize branches events (calls only) |
| r synthesize branches events (returns only) |
| e synthesize tracing error events |
| d create a debug log |
| g synthesize a call chain (use with i or x) |
| G synthesize a call chain on existing event records |
| l synthesize last branch entries (use with i or x) |
| L synthesize last branch entries on existing event records |
| s skip initial number of events |
| q quicker (less detailed) decoding |
| Z prefer to ignore timestamps (so-called "timeless" decoding) |
| |
| "Instructions" events look like they were recorded by "perf record -e |
| instructions". |
| |
| "Branches" events look like they were recorded by "perf record -e branches". "c" |
| and "r" can be combined to get calls and returns. |
| |
| "Transactions" events correspond to the start or end of transactions. The |
| 'flags' field can be used in perf script to determine whether the event is a |
| transaction start, commit or abort. |
| |
| Note that "instructions", "branches" and "transactions" events depend on code |
| flow packets which can be disabled by using the config term "branch=0". Refer |
| to the config terms section above. |
| |
| "ptwrite" events record the payload of the ptwrite instruction and whether |
| "fup_on_ptw" was used. "ptwrite" events depend on PTWRITE packets which are |
| recorded only if the "ptw" config term was used. Refer to the config terms |
| section above. perf script "synth" field displays "ptwrite" information like |
| this: "ip: 0 payload: 0x123456789abcdef0" where "ip" is 1 if "fup_on_ptw" was |
| used. |
| |
| "Power" events correspond to power event packets and CBR (core-to-bus ratio) |
| packets. While CBR packets are always recorded when tracing is enabled, power |
| event packets are recorded only if the "pwr_evt" config term was used. Refer to |
| the config terms section above. The power events record information about |
| C-state changes, whereas CBR is indicative of CPU frequency. perf script |
| "event,synth" fields display information like this: |
| cbr: cbr: 22 freq: 2189 MHz (200%) |
| mwait: hints: 0x60 extensions: 0x1 |
| pwre: hw: 0 cstate: 2 sub-cstate: 0 |
| exstop: ip: 1 |
| pwrx: deepest cstate: 2 last cstate: 2 wake reason: 0x4 |
| Where: |
| "cbr" includes the frequency and the percentage of maximum non-turbo |
| "mwait" shows mwait hints and extensions |
| "pwre" shows C-state transitions (to a C-state deeper than C0) and |
| whether initiated by hardware |
| "exstop" indicates execution stopped and whether the IP was recorded |
| exactly, |
| "pwrx" indicates return to C0 |
| For more details refer to the Intel 64 and IA-32 Architectures Software |
| Developer Manuals. |
| |
| PSB events show when a PSB+ occurred and also the byte-offset in the trace. |
| Emitting a PSB+ can cause a CPU a slight delay. When doing timing analysis |
| of code with Intel PT, it is useful to know if a timing bubble was caused |
| by Intel PT or not. |
| |
| Error events show where the decoder lost the trace. Error events |
| are quite important. Users must know if what they are seeing is a complete |
| picture or not. The "e" option may be followed by flags which affect what errors |
| will or will not be reported. Each flag must be preceded by either '+' or '-'. |
| The flags supported by Intel PT are: |
| -o Suppress overflow errors |
| -l Suppress trace data lost errors |
| For example, for errors but not overflow or data lost errors: |
| |
| --itrace=e-o-l |
| |
| The "d" option will cause the creation of a file "intel_pt.log" containing all |
| decoded packets and instructions. Note that this option slows down the decoder |
| and that the resulting file may be very large. The "d" option may be followed |
| by flags which affect what debug messages will or will not be logged. Each flag |
| must be preceded by either '+' or '-'. The flags support by Intel PT are: |
| -a Suppress logging of perf events |
| +a Log all perf events |
| By default, logged perf events are filtered by any specified time ranges, but |
| flag +a overrides that. |
| |
| In addition, the period of the "instructions" event can be specified. e.g. |
| |
| --itrace=i10us |
| |
| sets the period to 10us i.e. one instruction sample is synthesized for each 10 |
| microseconds of trace. Alternatives to "us" are "ms" (milliseconds), |
| "ns" (nanoseconds), "t" (TSC ticks) or "i" (instructions). |
| |
| "ms", "us" and "ns" are converted to TSC ticks. |
| |
| The timing information included with Intel PT does not give the time of every |
| instruction. Consequently, for the purpose of sampling, the decoder estimates |
| the time since the last timing packet based on 1 tick per instruction. The time |
| on the sample is *not* adjusted and reflects the last known value of TSC. |
| |
| For Intel PT, the default period is 100us. |
| |
| Setting it to a zero period means "as often as possible". |
| |
| In the case of Intel PT that is the same as a period of 1 and a unit of |
| 'instructions' (i.e. --itrace=i1i). |
| |
| Also the call chain size (default 16, max. 1024) for instructions or |
| transactions events can be specified. e.g. |
| |
| --itrace=ig32 |
| --itrace=xg32 |
| |
| Also the number of last branch entries (default 64, max. 1024) for instructions or |
| transactions events can be specified. e.g. |
| |
| --itrace=il10 |
| --itrace=xl10 |
| |
| Note that last branch entries are cleared for each sample, so there is no overlap |
| from one sample to the next. |
| |
| The G and L options are designed in particular for sample mode, and work much |
| like g and l but add call chain and branch stack to the other selected events |
| instead of synthesized events. For example, to record branch-misses events for |
| 'ls' and then add a call chain derived from the Intel PT trace: |
| |
| perf record --aux-sample -e '{intel_pt//u,branch-misses:u}' -- ls |
| perf report --itrace=Ge |
| |
| Although in fact G is a default for perf report, so that is the same as just: |
| |
| perf report |
| |
| One caveat with the G and L options is that they work poorly with "Large PEBS". |
| Large PEBS means PEBS records will be accumulated by hardware and the written |
| into the event buffer in one go. That reduces interrupts, but can give very |
| late timestamps. Because the Intel PT trace is synchronized by timestamps, |
| the PEBS events do not match the trace. Currently, Large PEBS is used only in |
| certain circumstances: |
| - hardware supports it |
| - PEBS is used |
| - event period is specified, instead of frequency |
| - the sample type is limited to the following flags: |
| PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_ADDR | |
| PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_STREAM_ID | |
| PERF_SAMPLE_DATA_SRC | PERF_SAMPLE_IDENTIFIER | |
| PERF_SAMPLE_TRANSACTION | PERF_SAMPLE_PHYS_ADDR | |
| PERF_SAMPLE_REGS_INTR | PERF_SAMPLE_REGS_USER | |
| PERF_SAMPLE_PERIOD (and sometimes) | PERF_SAMPLE_TIME |
| Because Intel PT sample mode uses a different sample type to the list above, |
| Large PEBS is not used with Intel PT sample mode. To avoid Large PEBS in other |
| cases, avoid specifying the event period i.e. avoid the 'perf record' -c option, |
| --count option, or 'period' config term. |
| |
| To disable trace decoding entirely, use the option --no-itrace. |
| |
| It is also possible to skip events generated (instructions, branches, transactions) |
| at the beginning. This is useful to ignore initialization code. |
| |
| --itrace=i0nss1000000 |
| |
| skips the first million instructions. |
| |
| The q option changes the way the trace is decoded. The decoding is much faster |
| but much less detailed. Specifically, with the q option, the decoder does not |
| decode TNT packets, and does not walk object code, but gets the ip from FUP and |
| TIP packets. The q option can be used with the b and i options but the period |
| is not used. The q option decodes more quickly, but is useful only if the |
| control flow of interest is represented or indicated by FUP, TIP, TIP.PGE, or |
| TIP.PGD packets (refer below). However the q option could be used to find time |
| ranges that could then be decoded fully using the --time option. |
| |
| What will *not* be decoded with the (single) q option: |
| |
| - direct calls and jmps |
| - conditional branches |
| - non-branch instructions |
| |
| What *will* be decoded with the (single) q option: |
| |
| - asynchronous branches such as interrupts |
| - indirect branches |
| - function return target address *if* the noretcomp config term (refer |
| config terms section) was used |
| - start of (control-flow) tracing |
| - end of (control-flow) tracing, if it is not out of context |
| - power events, ptwrite, transaction start and abort |
| - instruction pointer associated with PSB packets |
| |
| Note the q option does not specify what events will be synthesized e.g. the p |
| option must be used also to show power events. |
| |
| Repeating the q option (double-q i.e. qq) results in even faster decoding and even |
| less detail. The decoder decodes only extended PSB (PSB+) packets, getting the |
| instruction pointer if there is a FUP packet within PSB+ (i.e. between PSB and |
| PSBEND). Note PSB packets occur regularly in the trace based on the psb_period |
| config term (refer config terms section). There will be a FUP packet if the |
| PSB+ occurs while control flow is being traced. |
| |
| What will *not* be decoded with the qq option: |
| |
| - everything except instruction pointer associated with PSB packets |
| |
| What *will* be decoded with the qq option: |
| |
| - instruction pointer associated with PSB packets |
| |
| The Z option is equivalent to having recorded a trace without TSC |
| (i.e. config term tsc=0). It can be useful to avoid timestamp issues when |
| decoding a trace of a virtual machine. |
| |
| |
| dump option |
| ~~~~~~~~~~~ |
| |
| perf script has an option (-D) to "dump" the events i.e. display the binary |
| data. |
| |
| When -D is used, Intel PT packets are displayed. The packet decoder does not |
| pay attention to PSB packets, but just decodes the bytes - so the packets seen |
| by the actual decoder may not be identical in places where the data is corrupt. |
| One example of that would be when the buffer-switching interrupt has been too |
| slow, and the buffer has been filled completely. In that case, the last packet |
| in the buffer might be truncated and immediately followed by a PSB as the trace |
| continues in the next buffer. |
| |
| To disable the display of Intel PT packets, combine the -D option with |
| --no-itrace. |
| |
| |
| perf report |
| ----------- |
| |
| By default, perf report will decode trace data found in the perf.data file. |
| This can be further controlled by new option --itrace exactly the same as |
| perf script, with the exception that the default is --itrace=igxe. |
| |
| |
| perf inject |
| ----------- |
| |
| perf inject also accepts the --itrace option in which case tracing data is |
| removed and replaced with the synthesized events. e.g. |
| |
| perf inject --itrace -i perf.data -o perf.data.new |
| |
| Below is an example of using Intel PT with autofdo. It requires autofdo |
| (https://github.com/google/autofdo) and gcc version 5. The bubble |
| sort example is from the AutoFDO tutorial (https://gcc.gnu.org/wiki/AutoFDO/Tutorial) |
| amended to take the number of elements as a parameter. |
| |
| $ gcc-5 -O3 sort.c -o sort_optimized |
| $ ./sort_optimized 30000 |
| Bubble sorting array of 30000 elements |
| 2254 ms |
| |
| $ cat ~/.perfconfig |
| [intel-pt] |
| mispred-all = on |
| |
| $ perf record -e intel_pt//u ./sort 3000 |
| Bubble sorting array of 3000 elements |
| 58 ms |
| [ perf record: Woken up 2 times to write data ] |
| [ perf record: Captured and wrote 3.939 MB perf.data ] |
| $ perf inject -i perf.data -o inj --itrace=i100usle --strip |
| $ ./create_gcov --binary=./sort --profile=inj --gcov=sort.gcov -gcov_version=1 |
| $ gcc-5 -O3 -fauto-profile=sort.gcov sort.c -o sort_autofdo |
| $ ./sort_autofdo 30000 |
| Bubble sorting array of 30000 elements |
| 2155 ms |
| |
| Note there is currently no advantage to using Intel PT instead of LBR, but |
| that may change in the future if greater use is made of the data. |
| |
| |
| PEBS via Intel PT |
| ----------------- |
| |
| Some hardware has the feature to redirect PEBS records to the Intel PT trace. |
| Recording is selected by using the aux-output config term e.g. |
| |
| perf record -c 10000 -e '{intel_pt/branch=0/,cycles/aux-output/ppp}' uname |
| |
| Note that currently, software only supports redirecting at most one PEBS event. |
| |
| To display PEBS events from the Intel PT trace, use the itrace 'o' option e.g. |
| |
| perf script --itrace=oe |
| |
| XED |
| --- |
| |
| include::build-xed.txt[] |
| |
| |
| Tracing Virtual Machines |
| ------------------------ |
| |
| Currently, only kernel tracing is supported and only with either "timeless" decoding |
| (i.e. no TSC timestamps) or VM Time Correlation. VM Time Correlation is an extra step |
| using 'perf inject' and requires unchanging VMX TSC Offset and no VMX TSC Scaling. |
| |
| Other limitations and caveats |
| |
| VMX controls may suppress packets needed for decoding resulting in decoding errors |
| VMX controls may block the perf NMI to the host potentially resulting in lost trace data |
| Guest kernel self-modifying code (e.g. jump labels or JIT-compiled eBPF) will result in decoding errors |
| Guest thread information is unknown |
| Guest VCPU is unknown but may be able to be inferred from the host thread |
| Callchains are not supported |
| |
| Example using "timeless" decoding |
| |
| Start VM |
| |
| $ sudo virsh start kubuntu20.04 |
| Domain kubuntu20.04 started |
| |
| Mount the guest file system. Note sshfs needs -o direct_io to enable reading of proc files. root access is needed to read /proc/kcore. |
| |
| $ mkdir vm0 |
| $ sshfs -o direct_io root@vm0:/ vm0 |
| |
| Copy the guest /proc/kallsyms, /proc/modules and /proc/kcore |
| |
| $ perf buildid-cache -v --kcore vm0/proc/kcore |
| kcore added to build-id cache directory /home/user/.debug/[kernel.kcore]/9600f316a53a0f54278885e8d9710538ec5f6a08/2021021807494306 |
| $ KALLSYMS=/home/user/.debug/[kernel.kcore]/9600f316a53a0f54278885e8d9710538ec5f6a08/2021021807494306/kallsyms |
| |
| Find the VM process |
| |
| $ ps -eLl | grep 'KVM\|PID' |
| F S UID PID PPID LWP C PRI NI ADDR SZ WCHAN TTY TIME CMD |
| 3 S 64055 1430 1 1440 1 80 0 - 1921718 - ? 00:02:47 CPU 0/KVM |
| 3 S 64055 1430 1 1441 1 80 0 - 1921718 - ? 00:02:41 CPU 1/KVM |
| 3 S 64055 1430 1 1442 1 80 0 - 1921718 - ? 00:02:38 CPU 2/KVM |
| 3 S 64055 1430 1 1443 2 80 0 - 1921718 - ? 00:03:18 CPU 3/KVM |
| |
| Start an open-ended perf record, tracing the VM process, do something on the VM, and then ctrl-C to stop. |
| TSC is not supported and tsc=0 must be specified. That means mtc is useless, so add mtc=0. |
| However, IPC can still be determined, hence cyc=1 can be added. |
| Only kernel decoding is supported, so 'k' must be specified. |
| Intel PT traces both the host and the guest so --guest and --host need to be specified. |
| Without timestamps, --per-thread must be specified to distinguish threads. |
| |
| $ sudo perf kvm --guest --host --guestkallsyms $KALLSYMS record --kcore -e intel_pt/tsc=0,mtc=0,cyc=1/k -p 1430 --per-thread |
| ^C |
| [ perf record: Woken up 1 times to write data ] |
| [ perf record: Captured and wrote 5.829 MB ] |
| |
| perf script can be used to provide an instruction trace |
| |
| $ perf script --guestkallsyms $KALLSYMS --insn-trace --xed -F+ipc | grep -C10 vmresume | head -21 |
| CPU 0/KVM 1440 ffffffff82133cdd __vmx_vcpu_run+0x3d ([kernel.kallsyms]) movq 0x48(%rax), %r9 |
| CPU 0/KVM 1440 ffffffff82133ce1 __vmx_vcpu_run+0x41 ([kernel.kallsyms]) movq 0x50(%rax), %r10 |
| CPU 0/KVM 1440 ffffffff82133ce5 __vmx_vcpu_run+0x45 ([kernel.kallsyms]) movq 0x58(%rax), %r11 |
| CPU 0/KVM 1440 ffffffff82133ce9 __vmx_vcpu_run+0x49 ([kernel.kallsyms]) movq 0x60(%rax), %r12 |
| CPU 0/KVM 1440 ffffffff82133ced __vmx_vcpu_run+0x4d ([kernel.kallsyms]) movq 0x68(%rax), %r13 |
| CPU 0/KVM 1440 ffffffff82133cf1 __vmx_vcpu_run+0x51 ([kernel.kallsyms]) movq 0x70(%rax), %r14 |
| CPU 0/KVM 1440 ffffffff82133cf5 __vmx_vcpu_run+0x55 ([kernel.kallsyms]) movq 0x78(%rax), %r15 |
| CPU 0/KVM 1440 ffffffff82133cf9 __vmx_vcpu_run+0x59 ([kernel.kallsyms]) movq (%rax), %rax |
| CPU 0/KVM 1440 ffffffff82133cfc __vmx_vcpu_run+0x5c ([kernel.kallsyms]) callq 0xffffffff82133c40 |
| CPU 0/KVM 1440 ffffffff82133c40 vmx_vmenter+0x0 ([kernel.kallsyms]) jz 0xffffffff82133c46 |
| CPU 0/KVM 1440 ffffffff82133c42 vmx_vmenter+0x2 ([kernel.kallsyms]) vmresume IPC: 0.11 (50/445) |
| :1440 1440 ffffffffbb678b06 native_write_msr+0x6 ([guest.kernel.kallsyms]) nopl %eax, (%rax,%rax,1) |
| :1440 1440 ffffffffbb678b0b native_write_msr+0xb ([guest.kernel.kallsyms]) retq IPC: 0.04 (2/41) |
| :1440 1440 ffffffffbb666646 lapic_next_deadline+0x26 ([guest.kernel.kallsyms]) data16 nop |
| :1440 1440 ffffffffbb666648 lapic_next_deadline+0x28 ([guest.kernel.kallsyms]) xor %eax, %eax |
| :1440 1440 ffffffffbb66664a lapic_next_deadline+0x2a ([guest.kernel.kallsyms]) popq %rbp |
| :1440 1440 ffffffffbb66664b lapic_next_deadline+0x2b ([guest.kernel.kallsyms]) retq IPC: 0.16 (4/25) |
| :1440 1440 ffffffffbb74607f clockevents_program_event+0x8f ([guest.kernel.kallsyms]) test %eax, %eax |
| :1440 1440 ffffffffbb746081 clockevents_program_event+0x91 ([guest.kernel.kallsyms]) jz 0xffffffffbb74603c IPC: 0.06 (2/30) |
| :1440 1440 ffffffffbb74603c clockevents_program_event+0x4c ([guest.kernel.kallsyms]) popq %rbx |
| :1440 1440 ffffffffbb74603d clockevents_program_event+0x4d ([guest.kernel.kallsyms]) popq %r12 |
| |
| Example using VM Time Correlation |
| |
| Start VM |
| |
| $ sudo virsh start kubuntu20.04 |
| Domain kubuntu20.04 started |
| |
| Mount the guest file system. Note sshfs needs -o direct_io to enable reading of proc files. root access is needed to read /proc/kcore. |
| |
| $ mkdir -p vm0 |
| $ sshfs -o direct_io root@vm0:/ vm0 |
| |
| Copy the guest /proc/kallsyms, /proc/modules and /proc/kcore |
| |
| $ perf buildid-cache -v --kcore vm0/proc/kcore |
| same kcore found in /home/user/.debug/[kernel.kcore]/cc9c55a98c5e4ec0aeda69302554aabed5cd6491/2021021312450777 |
| $ KALLSYMS=/home/user/.debug/\[kernel.kcore\]/cc9c55a98c5e4ec0aeda69302554aabed5cd6491/2021021312450777/kallsyms |
| |
| Find the VM process |
| |
| $ ps -eLl | grep 'KVM\|PID' |
| F S UID PID PPID LWP C PRI NI ADDR SZ WCHAN TTY TIME CMD |
| 3 S 64055 16998 1 17005 13 80 0 - 1818189 - ? 00:00:16 CPU 0/KVM |
| 3 S 64055 16998 1 17006 4 80 0 - 1818189 - ? 00:00:05 CPU 1/KVM |
| 3 S 64055 16998 1 17007 3 80 0 - 1818189 - ? 00:00:04 CPU 2/KVM |
| 3 S 64055 16998 1 17008 4 80 0 - 1818189 - ? 00:00:05 CPU 3/KVM |
| |
| Start an open-ended perf record, tracing the VM process, do something on the VM, and then ctrl-C to stop. |
| IPC can be determined, hence cyc=1 can be added. |
| Only kernel decoding is supported, so 'k' must be specified. |
| Intel PT traces both the host and the guest so --guest and --host need to be specified. |
| |
| $ sudo perf kvm --guest --host --guestkallsyms $KALLSYMS record --kcore -e intel_pt/cyc=1/k -p 16998 |
| ^C[ perf record: Woken up 1 times to write data ] |
| [ perf record: Captured and wrote 9.041 MB perf.data.kvm ] |
| |
| Now 'perf inject' can be used to determine the VMX TCS Offset. Note, Intel PT TSC packets are |
| only 7-bytes, so the TSC Offset might differ from the actual value in the 8th byte. That will |
| have no effect i.e. the resulting timestamps will be correct anyway. |
| |
| $ perf inject -i perf.data.kvm --vm-time-correlation=dry-run |
| ERROR: Unknown TSC Offset for VMCS 0x1bff6a |
| VMCS: 0x1bff6a TSC Offset 0xffffe42722c64c41 |
| ERROR: Unknown TSC Offset for VMCS 0x1cbc08 |
| VMCS: 0x1cbc08 TSC Offset 0xffffe42722c64c41 |
| ERROR: Unknown TSC Offset for VMCS 0x1c3ce8 |
| VMCS: 0x1c3ce8 TSC Offset 0xffffe42722c64c41 |
| ERROR: Unknown TSC Offset for VMCS 0x1cbce9 |
| VMCS: 0x1cbce9 TSC Offset 0xffffe42722c64c41 |
| |
| Each virtual CPU has a different Virtual Machine Control Structure (VMCS) |
| shown above with the calculated TSC Offset. For an unchanging TSC Offset |
| they should all be the same for the same virtual machine. |
| |
| Now that the TSC Offset is known, it can be provided to 'perf inject' |
| |
| $ perf inject -i perf.data.kvm --vm-time-correlation="dry-run 0xffffe42722c64c41" |
| |
| Note the options for 'perf inject' --vm-time-correlation are: |
| |
| [ dry-run ] [ <TSC Offset> [ : <VMCS> [ , <VMCS> ]... ] ]... |
| |
| So it is possible to specify different TSC Offsets for different VMCS. |
| The option "dry-run" will cause the file to be processed but without updating it. |
| Note it is also possible to get a intel_pt.log file by adding option --itrace=d |
| |
| There were no errors so, do it for real |
| |
| $ perf inject -i perf.data.kvm --vm-time-correlation=0xffffe42722c64c41 --force |
| |
| 'perf script' can be used to see if there are any decoder errors |
| |
| $ perf script -i perf.data.kvm --guestkallsyms $KALLSYMS --itrace=e-o |
| |
| There were none. |
| |
| 'perf script' can be used to provide an instruction trace showing timestamps |
| |
| $ perf script -i perf.data.kvm --guestkallsyms $KALLSYMS --insn-trace --xed -F+ipc | grep -C10 vmresume | head -21 |
| CPU 1/KVM 17006 [001] 11500.262865593: ffffffff82133cdd __vmx_vcpu_run+0x3d ([kernel.kallsyms]) movq 0x48(%rax), %r9 |
| CPU 1/KVM 17006 [001] 11500.262865593: ffffffff82133ce1 __vmx_vcpu_run+0x41 ([kernel.kallsyms]) movq 0x50(%rax), %r10 |
| CPU 1/KVM 17006 [001] 11500.262865593: ffffffff82133ce5 __vmx_vcpu_run+0x45 ([kernel.kallsyms]) movq 0x58(%rax), %r11 |
| CPU 1/KVM 17006 [001] 11500.262865593: ffffffff82133ce9 __vmx_vcpu_run+0x49 ([kernel.kallsyms]) movq 0x60(%rax), %r12 |
| CPU 1/KVM 17006 [001] 11500.262865593: ffffffff82133ced __vmx_vcpu_run+0x4d ([kernel.kallsyms]) movq 0x68(%rax), %r13 |
| CPU 1/KVM 17006 [001] 11500.262865593: ffffffff82133cf1 __vmx_vcpu_run+0x51 ([kernel.kallsyms]) movq 0x70(%rax), %r14 |
| CPU 1/KVM 17006 [001] 11500.262865593: ffffffff82133cf5 __vmx_vcpu_run+0x55 ([kernel.kallsyms]) movq 0x78(%rax), %r15 |
| CPU 1/KVM 17006 [001] 11500.262865593: ffffffff82133cf9 __vmx_vcpu_run+0x59 ([kernel.kallsyms]) movq (%rax), %rax |
| CPU 1/KVM 17006 [001] 11500.262865593: ffffffff82133cfc __vmx_vcpu_run+0x5c ([kernel.kallsyms]) callq 0xffffffff82133c40 |
| CPU 1/KVM 17006 [001] 11500.262865593: ffffffff82133c40 vmx_vmenter+0x0 ([kernel.kallsyms]) jz 0xffffffff82133c46 |
| CPU 1/KVM 17006 [001] 11500.262866075: ffffffff82133c42 vmx_vmenter+0x2 ([kernel.kallsyms]) vmresume IPC: 0.05 (40/769) |
| :17006 17006 [001] 11500.262869216: ffffffff82200cb0 asm_sysvec_apic_timer_interrupt+0x0 ([guest.kernel.kallsyms]) clac |
| :17006 17006 [001] 11500.262869216: ffffffff82200cb3 asm_sysvec_apic_timer_interrupt+0x3 ([guest.kernel.kallsyms]) pushq $0xffffffffffffffff |
| :17006 17006 [001] 11500.262869216: ffffffff82200cb5 asm_sysvec_apic_timer_interrupt+0x5 ([guest.kernel.kallsyms]) callq 0xffffffff82201160 |
| :17006 17006 [001] 11500.262869216: ffffffff82201160 error_entry+0x0 ([guest.kernel.kallsyms]) cld |
| :17006 17006 [001] 11500.262869216: ffffffff82201161 error_entry+0x1 ([guest.kernel.kallsyms]) pushq %rsi |
| :17006 17006 [001] 11500.262869216: ffffffff82201162 error_entry+0x2 ([guest.kernel.kallsyms]) movq 0x8(%rsp), %rsi |
| :17006 17006 [001] 11500.262869216: ffffffff82201167 error_entry+0x7 ([guest.kernel.kallsyms]) movq %rdi, 0x8(%rsp) |
| :17006 17006 [001] 11500.262869216: ffffffff8220116c error_entry+0xc ([guest.kernel.kallsyms]) pushq %rdx |
| :17006 17006 [001] 11500.262869216: ffffffff8220116d error_entry+0xd ([guest.kernel.kallsyms]) pushq %rcx |
| :17006 17006 [001] 11500.262869216: ffffffff8220116e error_entry+0xe ([guest.kernel.kallsyms]) pushq %rax |
| |
| |
| |
| SEE ALSO |
| -------- |
| |
| linkperf:perf-record[1], linkperf:perf-script[1], linkperf:perf-report[1], |
| linkperf:perf-inject[1] |