PERF_EVENT_OPEN - Linux手册页
Linux程序员手册 第2部分
更新日期: 2020-06-09
名称
perf_event_open-设置性能监控
语法
#include <linux/perf_event.h> #include <linux/hw_breakpoint.h> int perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu, int group_fd, unsigned long flags);
注意:此系统调用没有glibc包装器。请参阅注释。
说明
给定参数列表,perf_event_open()返回文件描述符,以用于后续系统调用(read(2),mmap(2),prctl(2),fcntl(2)等)。
调用perf_event_open()会创建一个文件描述符,该文件描述符可用于评估性能信息。每个文件描述符都对应一个要测量的事件;这些可以组合在一起以同时测量多个事件。
可以通过两种方式启用和禁用事件:通过ioctl(2)和通过prctl(2)。禁用事件后,它不会计数或不会产生溢出,但会继续存在并保持其计数值。
事件有两种形式:计数和采样。计数事件是用于对发生的事件总数进行计数的事件。通常,计数事件结果是通过read(2)调用收集的。采样事件会定期将测量结果写入缓冲区,然后可以通过mmap(2)访问该缓冲区。
Arguments
pid和cpu参数允许指定要监视的进程和cpu:
- pid == 0and cpu == -1
- 这可以测量任何CPU上的调用进程/线程。
- pid == 0and cpu >= 0
- 仅当在指定的CPU上运行时,才测量调用进程/线程。
- pid > 0and cpu == -1
- 这将测量任何CPU上的指定进程/线程。
- pid > 0and cpu >= 0
- 仅当在指定的CPU上运行时,才测量指定的进程/线程。
- pid == -1and cpu >= 0
- 这将测量指定CPU上的所有进程/线程。这需要CAP_SYS_ADMIN功能或/ proc / sys / kernel / perf_event_paranoid值小于1。
- pid == -1and cpu == -1
- 此设置无效,将返回错误。
当pid大于零时,执行此系统调用的权限由ptrace访问模式PTRACE_MODE_READ_REALCREDS检查控制;参见ptrace(2)。
group_fd参数允许创建事件组。一个事件组有一个事件,即组长。首先创建领导者,group_fd = -1。其余的组成员是通过随后的perf_event_open()调用创建的,其中group_fd设置为组长的文件描述符。 (一个单独的事件是使用group_fd = -1创建的,并且被认为是只有1个成员的组。)一个事件组作为一个单元安排在CPU上:只有当所有可以将组中的事件放入CPU。这意味着可以将成员事件的值彼此进行有意义的比较(相加,除(以获得比率)等等),因为它们已经为同一组已执行指令计数了事件。
flags参数是通过对以下零个或多个值进行"或"运算而形成的:
- PERF_FLAG_FD_CLOEXEC(since Linux 3.14)
- 该标志为创建的事件文件描述符启用close-on-exec标志,以便在execve(2)上自动关闭文件描述符。在创建时而不是稍后使用fcntl(2)设置close-on-exec标志可以避免潜在的竞争情况,在这种情况下,调用线程与另一个线程调用fork(2)同时调用perf_event_open()和fcntl(2)然后执行(2)。
- PERF_FLAG_FD_NO_GROUP
- 除了使用PERF_FLAG_FD_OUTPUT标志设置输出重定向的目的之外,此标志告诉事件忽略group_fd参数。
- PERF_FLAG_FD_OUTPUT(broken since Linux 2.6.35)
- 该标志重新路由事件的采样输出,以代替包含在group_fd指定的事件的mmap缓冲区中。
- PERF_FLAG_PID_CGROUP(since Linux 2.6.39)
- 该标志激活每个容器的全系统监视。容器是一种抽象,它隔离一组资源以进行更细粒度的控制(CPU,内存等)。在这种模式下,仅当在受监视的CPU上运行的线程属于指定的容器(cgroup)时,才测量事件。通过传递在cgroupfs文件系统中其目录上打开的文件描述符来标识cgroup。例如,如果要监视的cgroup称为test,则必须将在/ dev / cgroup / test(假定cgroupfs安装在/ dev / cgroup上)上打开的文件描述符作为pid参数传递。 cgroup监视仅适用于系统范围的事件,因此可能需要额外的权限。
perf_event_attr结构提供有关正在创建的事件的详细配置信息。
struct perf_event_attr { __u32 type; /* Type of event */ __u32 size; /* Size of attribute structure */ __u64 config; /* Type-specific configuration */ union { __u64 sample_period; /* Period of sampling */ __u64 sample_freq; /* Frequency of sampling */ }; __u64 sample_type; /* Specifies values included in sample */ __u64 read_format; /* Specifies values returned in read */ __u64 disabled : 1, /* off by default */ inherit : 1, /* children inherit it */ pinned : 1, /* must always be on PMU */ exclusive : 1, /* only group on PMU */ exclude_user : 1, /* don't count user */ exclude_kernel : 1, /* don't count kernel */ exclude_hv : 1, /* don't count hypervisor */ exclude_idle : 1, /* don't count when idle */ mmap : 1, /* include mmap data */ comm : 1, /* include comm data */ freq : 1, /* use freq, not period */ inherit_stat : 1, /* per task counts */ enable_on_exec : 1, /* next exec enables */ task : 1, /* trace fork/exit */ watermark : 1, /* wakeup_watermark */ precise_ip : 2, /* skid constraint */ mmap_data : 1, /* non-exec mmap data */ sample_id_all : 1, /* sample_type all events */ exclude_host : 1, /* don't count in host */ exclude_guest : 1, /* don't count in guest */ exclude_callchain_kernel : 1, /* exclude kernel callchains */ exclude_callchain_user : 1, /* exclude user callchains */ mmap2 : 1, /* include mmap with inode data */ comm_exec : 1, /* flag comm events that are due to exec */ use_clockid : 1, /* use clockid for time fields */ context_switch : 1, /* context switch data */ __reserved_1 : 37; union { __u32 wakeup_events; /* wakeup every n events */ __u32 wakeup_watermark; /* bytes before wakeup */ }; __u32 bp_type; /* breakpoint type */ union { __u64 bp_addr; /* breakpoint address */ __u64 kprobe_func; /* for perf_kprobe */ __u64 uprobe_path; /* for perf_uprobe */ __u64 config1; /* extension of config */ }; union { __u64 bp_len; /* breakpoint length */ __u64 kprobe_addr; /* with kprobe_func == NULL */ __u64 probe_offset; /* for perf_[k,u]probe */ __u64 config2; /* extension of config1 */ }; __u64 branch_sample_type; /* enum perf_branch_sample_type */ __u64 sample_regs_user; /* user regs to dump on samples */ __u32 sample_stack_user; /* size of stack to dump on samples */ __s32 clockid; /* clock to use for time fields */ __u64 sample_regs_intr; /* regs to dump on samples */ __u32 aux_watermark; /* aux bytes before wakeup */ __u16 sample_max_stack; /* max frames in callchain */ __u16 __reserved_2; /* align to u64 */ };
perf_event_attr结构的字段在下面更详细地描述:
- type
- This field specifies the overall event type.
It has one of the following values:
- PERF_TYPE_HARDWARE
- 这表示内核提供的"通用"硬件事件之一。有关更多详细信息,请参见配置字段定义。
- PERF_TYPE_SOFTWARE
- 这表明内核提供了软件定义的事件之一(即使没有可用的硬件支持)。
- PERF_TYPE_TRACEPOINT
- 这表示内核跟踪点基础结构提供的跟踪点。
- PERF_TYPE_HW_CACHE
- 这表示硬件高速缓存事件。这具有特殊的编码,在config字段定义中描述。
- PERF_TYPE_RAW
- 这表示config字段中的"原始"实现特定事件。
- PERF_TYPE_BREAKPOINT(since Linux 2.6.33)
- 这表示CPU提供的硬件断点。断点可以是对地址的读/写访问,也可以是指令地址的执行。
- dynamic PMU
- 从Linux 2.6.38开始,perf_event_open()可以支持多个PMU。为此,可以在类型字段中使用内核导出的值来指示要使用的PMU。可以在sysfs文件系统中找到要使用的值:每个PMU实例在/ sys / bus / event_source / devices下都有一个子目录。在每个子目录中,都有一个类型文件,其内容是可以在类型字段中使用的整数。例如,/ sys / bus / event_source / devices / cpu / type包含核心CPU PMU的值,通常为4。
- kprobeand uprobe(since Linux 4.17)
- 这两个动态PMU创建一个kprobe / uprobe,并将其附加到perf_event_open生成的文件描述符中。 kprobe / uprobe将在破坏文件描述符时被破坏。有关更多详细信息,请参见字段kprobe_func,uprobe_path,kprobe_addr和probe_offset。
- size
- 用于向前/向后兼容性的perf_event_attr结构的大小。使用sizeof(struct perf_event_attr)进行设置,以允许内核在编译时看到结构大小。
- 相关的定义PERF_ATTR_SIZE_VER0设置为64;这是第一个发布的struct的大小。 PERF_ATTR_SIZE_VER1为72,对应于Linux 2.6.33中添加的断点。 PERF_ATTR_SIZE_VER2为80,对应于Linux 3.4中增加的分支采样。 PERF_ATTR_SIZE_VER3为96,对应于Linux 3.7中的sample_regs_user和sample_stack_user添加。 PERF_ATTR_SIZE_VER4是104,对应于Linux 3.19中的sample_regs_intr添加。 PERF_ATTR_SIZE_VER5是112,与Linux 4.1中aux_watermark的增加相对应。
- config
- 这与type字段一起指定了您想要的事件。在64位不足以完全指定事件的情况下,还将考虑config1和config2字段。这些字段的编码取决于事件。
- 有多种方法可以设置配置字段,具体取决于先前描述的类型字段的值。以下是按类型分开的config的各种可能设置。
- If
type
is
PERF_TYPE_HARDWARE,we are measuring one of the generalized hardware CPU events.
Not all of these are available on all platforms.
Set
configto one of the following:
- PERF_COUNT_HW_CPU_CYCLES
- 总周期。警惕在CPU频率缩放期间会发生什么。
- PERF_COUNT_HW_INSTRUCTIONS
- 退休说明。请注意,这些可能会受到各种问题的影响,最明显的是硬件中断计数。
- PERF_COUNT_HW_CACHE_REFERENCES
- 缓存访问。通常,这表示"最后一级缓存"访问,但这可能因您的CPU而异。这可能包括预取和一致性消息;同样,这取决于您的CPU设计。
- PERF_COUNT_HW_CACHE_MISSES
- 缓存未命中。通常,这表示"最后一级缓存未命中"。它打算与PERF_COUNT_HW_CACHE_REFERENCES事件一起使用以计算高速缓存未命中率。
- PERF_COUNT_HW_BRANCH_INSTRUCTIONS
- 退休的分支机构指示。在Linux 2.6.35之前的版本中,这在AMD处理器上使用了错误的事件。
- PERF_COUNT_HW_BRANCH_MISSES
- 错误的分支指令。
- PERF_COUNT_HW_BUS_CYCLES
- 总线周期,可以与总周期不同。
- PERF_COUNT_HW_STALLED_CYCLES_FRONTEND(since Linux 3.0)
- 发行期间停滞的周期。
- PERF_COUNT_HW_STALLED_CYCLES_BACKEND(since Linux 3.0)
- 退休期间停滞不前。
- PERF_COUNT_HW_REF_CPU_CYCLES(since Linux 3.3)
- 总周期;不受CPU频率缩放的影响。
- If
type
is
PERF_TYPE_SOFTWARE,we are measuring software events provided by the kernel.
Set
configto one of the following:
- PERF_COUNT_SW_CPU_CLOCK
- 它报告CPU时钟,即每个CPU的高分辨率计时器。
- PERF_COUNT_SW_TASK_CLOCK
- 这将报告特定于正在运行的任务的时钟计数。
- PERF_COUNT_SW_PAGE_FAULTS
- 这将报告页面错误数。
- PERF_COUNT_SW_CONTEXT_SWITCHES
- 这计算上下文切换。在Linux 2.6.34之前,它们都被报告为用户空间事件,之后它们被报告为在内核中发生。
- PERF_COUNT_SW_CPU_MIGRATIONS
- 这将报告进程已迁移到新CPU的次数。
- PERF_COUNT_SW_PAGE_FAULTS_MIN
- 这会计算次要页面错误的数量。这些不需要磁盘I / O来处理。
- PERF_COUNT_SW_PAGE_FAULTS_MAJ
- 这计算出主要页面错误的数量。这些需要处理的磁盘I / O。
- PERF_COUNT_SW_ALIGNMENT_FAULTS(since Linux 2.6.33)
- 这将计算对准故障的数量。这些发生在未对齐的内存访问发生时。内核可以处理这些,但会降低性能。这仅在某些体系结构上发生(在x86上则永远不会发生)。
- PERF_COUNT_SW_EMULATION_FAULTS(since Linux 2.6.33)
- 这计算了仿真故障的数量。内核有时会捕获未实现的指令,并为用户空间模拟它们。这会对性能产生负面影响。
- PERF_COUNT_SW_DUMMY(since Linux 3.12)
- 这是一个占位符事件,不计任何费用。信息样本记录类型(例如mmap或comm)必须与活动事件相关联。该虚拟事件允许收集此类记录,而无需计数事件。
- 如果type为PERF_TYPE_TRACEPOINT,则我们正在测量内核跟踪点。如果在内核中启用了ftrace,则可以从debugfs tracing / events / * / * / id下获取在config中使用的值。
- If
type
is
PERF_TYPE_HW_CACHE,then we are measuring a hardware CPU cache event.
To calculate the appropriate
configvalue use the following equation:
(perf_hw_cache_id) | (perf_hw_cache_op_id << 8) | (perf_hw_cache_op_result_id << 16)
其中perf_hw_cache_id是以下之一:
- PERF_COUNT_HW_CACHE_L1D
- 用于测量1级数据缓存
- PERF_COUNT_HW_CACHE_L1I
- 用于测量1级指令缓存
- PERF_COUNT_HW_CACHE_LL
- 用于测量最后一级缓存
- PERF_COUNT_HW_CACHE_DTLB
- 用于测量数据TLB
- PERF_COUNT_HW_CACHE_ITLB
- 用于测量指令TLB
- PERF_COUNT_HW_CACHE_BPU
- 用于测量分支预测单元
- PERF_COUNT_HW_CACHE_NODE(since Linux 3.1)
- 用于测量本地内存访问
perf_hw_cache_op_id是以下之一:
- PERF_COUNT_HW_CACHE_OP_READ
- 用于读取访问
- PERF_COUNT_HW_CACHE_OP_WRITE
- 用于写访问
- PERF_COUNT_HW_CACHE_OP_PREFETCH
- 用于预取访问
perf_hw_cache_op_result_id是以下之一:
- PERF_COUNT_HW_CACHE_RESULT_ACCESS
- 衡量访问
- PERF_COUNT_HW_CACHE_RESULT_MISS
- 测量未命中
如果类型为PERF_TYPE_RAW,则需要一个自定义的"原始"配置值。大多数CPU支持"通用"事件未涵盖的事件。这些是实现定义的;请参阅您的CPU手册(例如,英特尔第3B卷文档或《 AMD BIOS和内核开发人员指南》)。 libpfm4库可用于将体系结构手册中的名称转换为该字段中perf_event_open()期望的原始十六进制值。
如果类型为PERF_TYPE_BREAKPOINT,则将配置设置为零。它的参数在其他地方设置。
如果类型是kprobe或uprobe,则将retprobe(配置的位0,请参见/ sys / bus / event_source / devices / [k,u] probe / format / retprobe)设置为kretprobe / uretprobe。有关更多详细信息,请参见字段kprobe_func,uprobe_path,kprobe_addr和probe_offset。
- kprobe_func, uprobe_path, kprobe_addr, and probe_offset
- 这些字段描述了动态PMU的kprobe和uprobe。对于kprobe:使用kprobe_func和probe_offset,或使用kprobe_addr并将kprobe_func保留为NULL。对于uprobe:使用uprobe_path和probe_offset。
- sample_period, sample_freq
- "采样"事件是每N个事件生成一个溢出通知的事件,其中N由sample_period给出。采样事件的sample_period>0。发生溢出时,请求的数据记录在mmap缓冲区中。 sample_type字段控制每次溢出时记录的数据。
- 如果您希望使用频率而非周期,则可以使用sample_freq。在这种情况下,您可以设置频率标志。内核将调整采样周期以尝试达到所需的速率。调整率是一个计时器刻度。
- sample_type
- The various bits in this field specify which values to include
in the sample.
They will be recorded in a ring-buffer,
which is available to user space using
mmap(2).
The order in which the values are saved in the
sample are documented in the MMAP Layout subsection below;
it is not the
enum perf_event_sample_formatorder.
- PERF_SAMPLE_IP
- 记录指令指针。
- PERF_SAMPLE_TID
- 记录进程和线程ID。
- PERF_SAMPLE_TIME
- 记录时间戳。
- PERF_SAMPLE_ADDR
- 记录地址(如果适用)。
- PERF_SAMPLE_READ
- 记录组中所有事件的计数器值,而不仅仅是组长。
- PERF_SAMPLE_CALLCHAIN
- 记录调用链(堆栈回溯)。
- PERF_SAMPLE_ID
- 为打开的事件的组长记录唯一的ID。
- PERF_SAMPLE_CPU
- 记录CPU编号。
- PERF_SAMPLE_PERIOD
- 记录当前采样周期。
- PERF_SAMPLE_STREAM_ID
- 记录打开的事件的唯一ID。与PERF_SAMPLE_ID不同,返回的是实际ID,而不是组长。此ID与PERF_FORMAT_ID返回的ID相同。
- PERF_SAMPLE_RAW
- 记录其他数据(如果适用)。通常由跟踪事件返回。
- PERF_SAMPLE_BRANCH_STACK(since Linux 3.4)
- 这提供了由CPU分支采样硬件提供的最近分支的记录(例如Intel Last Branch Record)。并非所有硬件都支持此功能。
- 请参阅branch_sample_type字段,以了解如何过滤报告的分支。
- PERF_SAMPLE_REGS_USER(since Linux 3.7)
- 记录当前用户级别的CPU寄存器状态(调用内核之前进程中的值)。
- PERF_SAMPLE_STACK_USER(since Linux 3.7)
- 记录用户级别的堆栈,允许展开堆栈。
- PERF_SAMPLE_WEIGHT(since Linux 3.10)
- 记录硬件提供的权重值,该权重值表示采样事件的成本。这允许硬件在配置文件中突出显示昂贵的事件。
- PERF_SAMPLE_DATA_SRC(since Linux 3.10)
- 记录数据源:与采样指令关联的数据在存储器层次结构中的位置。仅当基础硬件支持此功能时,此功能才可用。
- PERF_SAMPLE_IDENTIFIER(since Linux 3.12)
- 将SAMPLE_ID值放置在记录中的固定位置,无论是在开头(对于样本事件)还是在结尾(如果是非样本事件)。
- 这是必需的,因为样本流可能具有来自具有不同sample_type设置的各种不同事件源的记录。无法正确解析事件流,因为需要记录的格式来查找SAMPLE_ID,但是如果不知道样本属于哪个事件,就无法找到该格式(导致循环依赖)。
- PERF_SAMPLE_IDENTIFIER设置通过将SAMPLE_ID放在固定位置来使事件流始终可解析,即使这意味着在记录中具有重复的SAMPLE_ID值。
- PERF_SAMPLE_TRANSACTION(since Linux 3.13)
- 记录事务性内存中止事件的原因(例如,来自Intel TSX事务性内存支持)。
- precision_ip设置必须大于0,并且必须测量事务性存储器中止事件,否则将不记录任何值。另请注意,某些perf_event测量(例如采样周期计数)可能会导致外来异常终止(通过在事务期间引起中断)。
- PERF_SAMPLE_REGS_INTR(since Linux 3.19)
- 记录由sample_regs_intr指定的当前CPU寄存器状态的子集。与PERF_SAMPLE_REGS_USER不同,如果在内核代码运行时发生溢出,则寄存器值将返回内核寄存器状态。如果CPU支持对寄存器状态进行硬件采样(即Intel x86上的PEBS)并且precision_ip设置为大于零,则返回的寄存器值是在采样指令退出时由硬件捕获的寄存器值。
- read_format
- This field specifies the format of the data returned by
read(2)
on a
perf_event_open()file descriptor.
- PERF_FORMAT_TOTAL_TIME_ENABLED
- 添加64位的time_enabled字段。如果PMU过量使用并且正在发生多路复用,则可用于计算估计总数。
- PERF_FORMAT_TOTAL_TIME_RUNNING
- 添加64位time_running字段。如果PMU过量使用并且正在发生多路复用,则可用于计算估计总数。
- PERF_FORMAT_ID
- 添加一个与事件组相对应的64位唯一值。
- PERF_FORMAT_GROUP
- 允许一次读取一次事件组中的所有计数器值。
- disabled
- 禁用位指定计数器开始时是禁用还是启用。如果禁用,则以后可以通过ioctl(2),prctl(2)或enable_on_exec启用该事件。
- 创建事件组时,通常将组长初始化为禁用设置为1,将任何子事件初始化为禁用设置为0。尽管禁用设置为0,但直到启用组长后,子事件才会开始。
- inherit
- 继承位指定此计数器应计数子任务以及指定任务的事件。这仅适用于新子代,不适用于创建计数器时的任何现有子代(也不适用于现有子代的任何新子代)。
- 继承不适用于某些read_format值组合,例如PERF_FORMAT_GROUP。
- pinned
- 固定位指定计数器应尽可能始终位于CPU上。它仅适用于硬件计数器,并且仅适用于组长。如果无法将固定计数器放到CPU上(例如,由于没有足够的硬件计数器或由于与其他事件发生冲突),则计数器进入"错误"状态,读取返回文件末尾(即read(2)返回0),直到随后启用或禁用计数器为止。
- exclusive
- 独占位指定当该计数器的组在CPU上时,它应该是使用CPU计数器的唯一组。将来,这可能允许监视程序支持需要单独运行的PMU功能,以使它们不会破坏其他硬件计数器。
- 请注意,许多意外情况可能会阻止具有独占位设置的事件永远运行。这包括运行系统范围的测量的所有用户以及性能计数器(包括常用的NMI Watchdog Timer接口)在内核中的任何使用。
- exclude_user
- 如果该位置1,则计数不包括用户空间中发生的事件。
- exclude_kernel
- 如果该位置1,则计数不包括内核空间中发生的事件。
- exclude_hv
- 如果设置了此位,则计数将排除虚拟机管理程序中发生的事件。这主要适用于具有内置支持的PMU(例如POWER)。在大多数机器上处理虚拟机监控程序测量需要额外的支持。
- exclude_idle
- 如果设置,则不计入CPU运行空闲任务的时间。尽管您当前可以为任何事件类型启用此功能,但除了软件事件以外的所有事件都将忽略它。
- mmap
- mmap位允许为每个已设置PROT_EXEC的mmap(2)调用生成PERF_RECORD_MMAP样本。这使工具可以注意到新的可执行代码已映射到程序中(例如,动态共享库),从而可以将地址映射回原始代码。
- comm
- comm位可跟踪由exec(2)和prctl(PR_SET_NAME)系统调用修改的进程命令名称,以及写入/ proc / self / comm。如果还成功设置了comm_exec标志(从Linux 3.16开始可能),则杂项标志PERF_RECORD_MISC_COMM_EXEC可用于区分exec(2)情况与其他情况。
- freq
- 如果设置了此位,则在设置采样间隔时将使用sample_frequency而不是sample_period。
- inherit_stat
- 通过该位,可以在上下文切换中保存继承任务的事件计数。仅当设置了继承字段时,这才有意义。
- enable_on_exec
- 如果设置了此位,则在调用exec(2)之后将自动启用计数器。
- task
- 如果该位置1,则分叉/退出通知将包含在环形缓冲区中。
- watermark
- 如果设置,当我们越过wakeup_watermark边界时,会发生溢出通知。否则,在wakeup_events样本之后会发生溢出通知。
- precise_ip(since Linux 2.6.35)
- 这可以控制打滑量。 Skid是在感兴趣的事件发生与内核能够停止并记录该事件之间执行的指令数量。滑移越小越好,并且可以更准确地报告哪些事件与哪些指令相对应,但是硬件通常受到限制,因为它可能很小。
- The possible values of this field are the following:
- 0
- SAMPLE_IP可以任意滑动。
- 1
- SAMPLE_IP必须具有恒定的防滑性。
- 2
- SAMPLE_IP请求打滑0。
- 3
- SAMPLE_IP必须具有0打滑。另请参阅PERF_RECORD_MISC_EXACT_IP的描述。
- mmap_data(since Linux 2.6.36)
- 这是mmap字段的对应内容。这可以为未设置PROT_EXEC的mmap(2)调用生成PERF_RECORD_MMAP样本(例如,数据和SysV共享内存)。
- sample_id_all(since Linux 2.6.38)
- 如果设置,则如果选择了相应的sample_type,则TID,TIME,ID,STREAM_ID和CPU可以另外包含在non-PERF_RECORD_SAMPLE中。
- 如果指定了PERF_SAMPLE_IDENTIFIER,则附加的ID值将作为最后一个值包括在内,以便于解析记录流。这可能导致id值出现两次。
- 布局由此伪结构描述:
struct sample_id { { u32 pid, tid; } /* if PERF_SAMPLE_TID set */ { u64 time; } /* if PERF_SAMPLE_TIME set */ { u64 id; } /* if PERF_SAMPLE_ID set */ { u64 stream_id;} /* if PERF_SAMPLE_STREAM_ID set */ { u32 cpu, res; } /* if PERF_SAMPLE_CPU set */ { u64 id; } /* if PERF_SAMPLE_IDENTIFIER set */ };
- exclude_host(since Linux 3.2)
- 在进行包括运行VM实例的进程(即已执行KVM_RUN ioctl(2))的测量时,仅测量发生在来宾实例内部的事件。这仅在客人之外有意义;此设置不会更改来宾内部收集的计数。当前,此功能仅适用于x86。
- exclude_guest(since Linux 3.2)
- 在进行包括运行VM实例的进程(即已执行KVM_RUN ioctl(2))的测量时,请勿测量来宾实例内部发生的事件。这仅在客人之外有意义;此设置不会更改来宾内部收集的计数。当前,此功能仅适用于x86。
- exclude_callchain_kernel(since Linux 3.7)
- 不包括内核调用链。
- exclude_callchain_user(since Linux 3.7)
- 不包括用户呼叫链。
- mmap2(since Linux 3.16)
- 生成扩展的可执行mmap记录,其中包含足够的附加信息以唯一地标识共享映射。必须设置mmap标志才能使它起作用。
- comm_exec(since Linux 3.16)
- 这纯粹是一个功能检测标志,它不会更改内核行为。如果可以成功设置此标志,则在启用comm后,如果报告的重命名事件是由对exec(2)的调用引起的,则将在comm记录头的misc字段中设置PERF_RECORD_MISC_COMM_EXEC标志。这允许工具区分各种类型的过程重命名。
- use_clockid(since Linux 4.1)
- 这样可以通过clockid字段选择生成时间戳时要使用的内部Linux时钟。这样可以更容易地将性能采样时间与其他工具生成的时间戳相关联。
- context_switch(since Linux 4.3)
- 这样可以在发生上下文切换时生成PERF_RECORD_SWITCH记录。当在CPU范围内的模式下采样时,它还可以生成PERF_RECORD_SWITCH_CPU_WIDE记录。此功能是用于测量上下文切换的现有跟踪点和软件事件的补充。此方法的优点是,即使使用严格的perf_event_paranoid设置,它也将提供完整的信息。
- wakeup_events, wakeup_watermark
- 此联合设置在发生溢出通知之前发生了多少样本(wakeup_events)或字节(wakeup_watermark)。通过水印位标志选择使用哪一个。
- wakeup_events仅计算PERF_RECORD_SAMPLE记录类型。要接收所有PERF_RECORD类型的溢出通知,请选择水印,然后将wakeup_watermark设置为1。
- 在Linux 3.0之前的版本中,将wakeup_events设置为0不会导致任何溢出通知。最近的内核将0等同于1。
- bp_type(since Linux 2.6.33)
This chooses the breakpoint type.
It is one of:- HW_BREAKPOINT_EMPTY
- 没有断点。
- HW_BREAKPOINT_R
- 当我们读取内存位置时计数。
- HW_BREAKPOINT_W
- 当我们写入内存位置时计数。
- HW_BREAKPOINT_RW
- 当我们读取或写入内存位置时计数。
- HW_BREAKPOINT_X
- 当我们在内存位置执行代码时计数。
值可以按位或进行组合,但不允许将HW_BREAKPOINT_R或HW_BREAKPOINT_W与HW_BREAKPOINT_X组合。
- bp_addr(since Linux 2.6.33)
- 这是断点的地址。对于执行断点,这是目标指令的内存地址;对于读取和写入断点,它是目标内存位置的内存地址。
- config1(since Linux 2.6.39)
- config1用于设置需要额外寄存器的事件,否则将不适合常规config字段。 Nehalem / Westmere / SandyBridge上的Raw OFFCORE_EVENTS在Linux 3.3和更高版本的内核上使用此字段。
- bp_len(since Linux 2.6.33)
- bp_len是类型为PERF_TYPE_BREAKPOINT时要测量的断点的长度。选项为HW_BREAKPOINT_LEN_1,HW_BREAKPOINT_LEN_2,HW_BREAKPOINT_LEN_4和HW_BREAKPOINT_LEN_8。对于执行断点,请将其设置为sizeof(long)。
- config2(since Linux 2.6.39)
- config2是config1字段的进一步扩展。
- branch_sample_type(since Linux 3.4)
- 如果启用了PERF_SAMPLE_BRANCH_STACK,则此选项指定要在分支记录中包括哪些分支。
- The first part of the value is the privilege level, which
is a combination of one of the values listed below.
If the user does not set privilege level explicitly, the kernel
will use the event's privilege level.
Event and branch privilege levels do not have to match.
- PERF_SAMPLE_BRANCH_USER
- 分支目标在用户空间中。
- PERF_SAMPLE_BRANCH_KERNEL
- 分支目标位于内核空间中。
- PERF_SAMPLE_BRANCH_HV
- 分支目标位于虚拟机监控程序中。
- PERF_SAMPLE_BRANCH_PLM_ALL
- 一个便利值,它是三个前面的值进行或运算的结果。
除特权值外,还必须设置以下至少一个或多个位。
- PERF_SAMPLE_BRANCH_ANY
- 任何分支类型。
- PERF_SAMPLE_BRANCH_ANY_CALL
- 任何呼叫分支(包括直接呼叫,间接呼叫和远距转移)。
- PERF_SAMPLE_BRANCH_IND_CALL
- 间接呼叫。
- PERF_SAMPLE_BRANCH_CALL(since Linux 4.4)
- 直接通话。
- PERF_SAMPLE_BRANCH_ANY_RETURN
- 任何返回分支。
- PERF_SAMPLE_BRANCH_IND_JUMP(since Linux 4.2)
- 间接跳跃。
- PERF_SAMPLE_BRANCH_COND(since Linux 3.16)
- 有条件分支。
- PERF_SAMPLE_BRANCH_ABORT_TX(since Linux 3.11)
- 事务性内存中止。
- PERF_SAMPLE_BRANCH_IN_TX(since Linux 3.11)
- 在事务内存事务中分支。
- PERF_SAMPLE_BRANCH_NO_TX(since Linux 3.11)
- 分支不在事务内存事务中。 PERF_SAMPLE_BRANCH_CALL_STACK(自Linux 4.1起)分支是硬件生成的调用堆栈的一部分。这需要硬件支持,当前仅在Intel x86 Haswell或更高版本上才能找到。
- sample_regs_user(since Linux 3.7)
- 该位掩码定义了要在样本上转储的用户CPU寄存器的集合。寄存器掩码的布局是特定于体系结构的,并在内核头文件arch / ARCH / include / uapi / asm / perf_regs.h中进行了描述。
- sample_stack_user(since Linux 3.7)
- 如果指定了PERF_SAMPLE_STACK_USER,这将定义要转储的用户堆栈的大小。
- clockid(since Linux 4.1)
- 如果设置了use_clockid,则此字段选择用于时间戳的内部Linux计时器。可用的计时器在linux / time.h中定义,目前支持CLOCK_MONOTONIC,CLOCK_MONOTONIC_RAW,CLOCK_REALTIME,CLOCK_BOOTTIME和CLOCK_TAI。
- aux_watermark(since Linux 4.1)
- 这指定了触发PERF_RECORD_AUX样本需要多少数据。
- sample_max_stack(since Linux 4.8)
- 当sample_type包括PERF_SAMPLE_CALLCHAIN时,此字段指定生成呼叫链时要报告的堆栈帧数。
Reading results
一旦打开了perf_event_open()文件描述符,就可以从文件描述符中读取事件的值。在那里的值由打开时attr结构中的read_format字段指定。
如果您尝试读入一个不足以容纳数据的缓冲区,则会导致错误ENOSPC。
这是读取返回的数据的布局:
- *
- 如果指定PERF_FORMAT_GROUP允许一次读取组中的所有事件:
struct read_format { u64 nr; /* The number of events */ u64 time_enabled; /* if PERF_FORMAT_TOTAL_TIME_ENABLED */ u64 time_running; /* if PERF_FORMAT_TOTAL_TIME_RUNNING */ struct { u64 value; /* The value of the event */ u64 id; /* if PERF_FORMAT_ID */ } values[nr]; };
- *
- 如果未指定PERF_FORMAT_GROUP:
struct read_format { u64 value; /* The value of the event */ u64 time_enabled; /* if PERF_FORMAT_TOTAL_TIME_ENABLED */ u64 time_running; /* if PERF_FORMAT_TOTAL_TIME_RUNNING */ u64 id; /* if PERF_FORMAT_ID */ };
读取的值如下:
- nr
- 此文件描述符中的事件数。仅在指定了PERF_FORMAT_GROUP时可用。
- time_enabled, time_running
- 启用并运行事件的总时间。通常,这些值是相同的。如果事件数量大于可用PMU计数器插槽的数量,则会发生多路复用。在那种情况下,事件仅在部分时间运行,并且time_enabled和时间运行值可用于缩放计数的估计值。
- value
- 包含计数器结果的无符号64位值。
- id
- 此特定事件的全球唯一值;仅当以read_format指定PERF_FORMAT_ID时才存在。
MMAP layout
在采样模式下使用perf_event_open()时,异步事件(例如计数器溢出或PROT_EXEC mmap跟踪)将记录到环形缓冲区中。该环形缓冲区是通过mmap(2)创建和访问的。
mmap大小应为1 + 2 ^ n页,其中第一页是元数据页(结构perf_event_mmap_page),其中包含各种信息位,例如环形缓冲区头的位置。
在内核2.6.39之前,存在一个错误,这意味着即使您不打算访问它,也必须在采样时分配mmap环形缓冲区。
第一个元数据mmap页面的结构如下:
struct perf_event_mmap_page { __u32 version; /* version number of this structure */ __u32 compat_version; /* lowest version this is compat with */ __u32 lock; /* seqlock for synchronization */ __u32 index; /* hardware counter identifier */ __s64 offset; /* add to hardware counter value */ __u64 time_enabled; /* time event active */ __u64 time_running; /* time event on CPU */ union { __u64 capabilities; struct { __u64 cap_usr_time / cap_usr_rdpmc / cap_bit0 : 1, cap_bit0_is_deprecated : 1, cap_user_rdpmc : 1, cap_user_time : 1, cap_user_time_zero : 1, }; }; __u16 pmc_width; __u16 time_shift; __u32 time_mult; __u64 time_offset; __u64 __reserved[120]; /* Pad to 1 k */ __u64 data_head; /* head in the data section */ __u64 data_tail; /* user-space written tail */ __u64 data_offset; /* where the buffer starts */ __u64 data_size; /* data buffer size */ __u64 aux_head; __u64 aux_tail; __u64 aux_offset; __u64 aux_size; }
以下列表更详细地描述了perf_event_mmap_page结构中的字段:
- version
- 此结构的版本号。
- compat_version
- 与此兼容的最低版本。
- lock
- 同步的序列锁。
- index
- 唯一的硬件计数器标识符。
- offset
- 使用rdpmc进行读取时,必须将此偏移值添加到rdpmc返回的值中,以获取当前的事件总数。
- time_enabled
- 活动活动的时间。
- time_running
- 事件运行的时间。
- cap_usr_time/ cap_usr_rdpmc/ cap_bit0(since Linux 3.4)
- 从Linux 3.4到Linux 3.11,在cap_usr_time和cap_usr_rdpmc的定义中存在一个错误。两个位都定义为指向同一位置,因此无法知道是否实际设置了cap_usr_time或cap_usr_rdpmc。
- 从Linux 3.12开始,它们被重命名为cap_bit0,您应该改用cap_user_time和cap_user_rdpmc字段。
- cap_bit0_is_deprecated(since Linux 3.12)
- 如果设置,则该位表示内核支持正确分隔的cap_user_time和cap_user_rdpmc位。
- 如果未设置,则表示较旧的内核,其中cap_usr_time和cap_usr_rdpmc映射到同一位,因此应谨慎使用这两个功能。
- cap_user_rdpmc(since Linux 3.12)
- 如果硬件在不进行系统调用的情况下支持用户空间读取性能计数器(这是x86上的" rdpmc"指令),则可以使用以下代码进行读取:
u32 seq, time_mult, time_shift, idx, width; u64 count, enabled, running; u64 cyc, time_offset; do { seq = pc->lock; barrier(); enabled = pc->time_enabled; running = pc->time_running; if (pc->cap_usr_time && enabled != running) { cyc = rdtsc(); time_offset = pc->time_offset; time_mult = pc->time_mult; time_shift = pc->time_shift; } idx = pc->index; count = pc->offset; if (pc->cap_usr_rdpmc && idx) { width = pc->pmc_width; count += rdpmc(idx - 1); } barrier(); } while (pc->lock != seq);
- cap_user_time(since Linux 3.12)
- 该位指示硬件具有恒定的不间断时间戳计数器(x86上的TSC)。
- cap_user_time_zero(since Linux 3.12)
- 指示time_zero的存在,该时间允许将时间戳记值映射到硬件时钟。
- pmc_width
- 如果是cap_usr_rdpmc,则此字段提供使用rdpmc或等效指令读取的值的位宽。这可以用来签署扩展结果,例如:
pmc <<= 64 - pmc_width; pmc >>= 64 - pmc_width; // signed shift right count += pmc;
- time_shift, time_mult, time_offset
- 如果使用cap_usr_time,则这些字段可用于计算使用rdtsc或类似功能启用time_enabled以来的时间增量(以纳秒为单位)。
u64 quot, rem; u64 delta; quot = (cyc >> time_shift); rem = cyc & (((u64)1 << time_shift) - 1); delta = time_offset + quot * time_mult + ((rem * time_mult) >> time_shift);
- 在上述seqcount循环中读取time_offset,time_mult,time_shift和cyc。然后可以将此增量添加到已启用且可能正在运行的状态(如果是idx),从而改善缩放比例:
enabled += delta; if (idx) running += delta; quot = count / running; rem = count % running; count = quot * enabled + (rem * enabled) / running;
- time_zero(since Linux 3.12)
- 如果设置了cap_usr_time_zero,则可以根据time_zero,time_mult和time_shift值计算硬件时钟(x86上的TSC时间戳计数器):
time = timestamp - time_zero; quot = time / time_mult; rem = time % time_mult; cyc = (quot << time_shift) + (rem << time_shift) / time_mult;
- 反之亦然:
quot = cyc >> time_shift; rem = cyc & (((u64)1 << time_shift) - 1); timestamp = time_zero + quot * time_mult + ((rem * time_mult) >> time_shift);
- data_head
- 这指向数据部分的开头。该值持续增加,不会自动换行。在访问样本之前,需要根据mmap缓冲区的大小手动包装该值。
- 在支持SMP的平台上,读取data_head值后,用户空间应发出rmb()。
- data_tail
- 当映射为PROT_WRITE时,应由用户空间写入data_tail值以反映最近读取的数据。在这种情况下,内核将不会覆盖未读取的数据。
- data_offset(since Linux 4.1)
- 包含mmap缓冲区中perf样本数据开始的位置的偏移量。
- data_size(since Linux 4.1)
- 包含mmap缓冲区中的perf样本区域的大小。
- aux_head, aux_tail, aux_offset, aux_size(since Linux 4.1)
- AUX区域允许为高带宽数据流映射一个单独的样本缓冲区(与主要性能样本缓冲区分开)。高带宽流的一个示例是指令跟踪支持,如在较新的英特尔处理器中所发现的。
- 要设置AUX区域,首先需要将aux_offset设置为大于data_offset + data_size的偏移,然后将aux_size设置为所需的缓冲区大小。所需的偏移量和大小必须页面对齐,并且大小必须为2的幂。然后将这些值传递给mmap,以映射AUX缓冲区。 AUX缓冲区中的页面是RLIMIT_MEMLOCK资源限制的一部分(请参见setrlimit(2)),还包括在perf_event_mlock_kb配额中。
- 默认情况下,如果AUX缓冲区不适合环形缓冲区中的可用空间,则会被截断。如果将AUX缓冲区映射为只读缓冲区,则它将在环形缓冲区模式下运行,在此模式下旧数据将被新数据覆盖。在覆盖模式下,可能无法推断新数据的开始位置,并且消费者的工作是在读取时禁用测量以避免可能的数据竞争。
- aux_head和aux_tail环形缓冲区指针的行为和排序规则与前面描述的data_head和data_tail相同。
以下2 ^ n个环形缓冲区页面具有以下描述的布局。
如果设置了perf_event_attr.sample_id_all,则所有事件类型将具有与以下PERF_RECORD_SAMPLE中描述的事件发生的时间/时间(身份)相关的所选sample_type字段(TID,TIME,ID,CPU,STREAM_ID),它将被隐藏在perf_event_header和现有字段已经存在的字段之后,即在有效负载的末尾。这允许较旧的perf工具支持较新的perf.data文件,而新的可选字段将被忽略。
mmap值以标题开头:
struct perf_event_header { __u32 type; __u16 misc; __u16 size; };
下面,我们更详细地描述perf_event_header字段。为了便于阅读,首先介绍了简短说明的字段。
- size
- 这表示记录的大小。
- misc
- misc字段包含有关样本的其他信息。
- The CPU mode can be determined from this value by masking with
PERF_RECORD_MISC_CPUMODE_MASK
and looking for one of the following (note these are not
bit masks, only one can be set at a time):- PERF_RECORD_MISC_CPUMODE_UNKNOWN
- 未知的CPU模式。
- PERF_RECORD_MISC_KERNEL
- 样本发生在内核中。
- PERF_RECORD_MISC_USER
- 示例发生在用户代码中。
- PERF_RECORD_MISC_HYPERVISOR
- 样本发生在管理程序中。
- PERF_RECORD_MISC_GUEST_KERNEL(since Linux 2.6.35)
- 样本发生在来宾内核中。
- PERF_RECORD_MISC_GUEST_USER (since Linux 2.6.35)
- 样本发生在访客用户代码中。
- Since the following three statuses are generated by
different record types, they alias to the same bit:
- PERF_RECORD_MISC_MMAP_DATA(since Linux 3.10)
- 当映射不可执行时设置。否则,映射是可执行的。
- PERF_RECORD_MISC_COMM_EXEC(since Linux 3.16)
- 如果进程名称更改是由exec(2)系统调用引起的,则此设置是针对比Linux 3.16更新的内核上的PERF_RECORD_COMM记录设置的。
- PERF_RECORD_MISC_SWITCH_OUT(since Linux 4.3)
- 当生成PERF_RECORD_SWITCH或PERF_RECORD_SWITCH_CPU_WIDE记录时,该位指示上下文切换远离当前进程(而不是当前进程)。
- In addition, the following bits can be set:
- PERF_RECORD_MISC_EXACT_IP
- 这表明PERF_SAMPLE_IP的内容指向触发事件的实际指令。另请参见perf_event_attr.precise_ip。
- PERF_RECORD_MISC_EXT_RESERVED(since Linux 2.6.35)
- 这表明存在可用的扩展数据(当前未使用)。
- PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT
- 内核未设置此位。保留给用户空间perf实用程序以指示/ proc / i [pid] / maps解析花费的时间太长并且已停止,因此mmap记录可能会被截断。
- type
- The
type
value is one of the below.
The values in the corresponding record (that follows the header)
depend on the
typeselected as shown.
- PERF_RECORD_MMAP
- MMAP事件记录了PROT_EXEC映射,因此我们可以将用户空间IP与代码相关联。它们具有以下结构:
struct { struct perf_event_header header; u32 pid, tid; u64 addr; u64 len; u64 pgoff; char filename[]; };
- pid
- 是进程ID。
- tid
- 是线程ID。
- addr
- 是分配的内存的地址。 len是分配的内存的长度。 pgoff是分配的内存的页面偏移量。 filename是一个字符串,描述分配的内存的支持。
- PERF_RECORD_LOST
- 该记录指示事件丢失的时间。
struct { struct perf_event_header header; u64 id; u64 lost; struct sample_id sample_id; };
- id
- 是丢失样本的唯一事件ID。
- lost
- 是丢失的事件数。
- PERF_RECORD_COMM
- 该记录表明进程名称已更改。
struct { struct perf_event_header header; u32 pid; u32 tid; char comm[]; struct sample_id sample_id; };
- pid
- 是进程ID。
- tid
- 是线程ID。
- comm
- 是一个字符串,其中包含进程的新名称。
- PERF_RECORD_EXIT
- 该记录指示进程退出事件。
struct { struct perf_event_header header; u32 pid, ppid; u32 tid, ptid; u64 time; struct sample_id sample_id; };
- PERF_RECORD_THROTTLE, PERF_RECORD_UNTHROTTLE
- 该记录指示节气门/节气门事件。
struct { struct perf_event_header header; u64 time; u64 id; u64 stream_id; struct sample_id sample_id; };
- PERF_RECORD_FORK
- 该记录指示派生事件。
struct { struct perf_event_header header; u32 pid, ppid; u32 tid, ptid; u64 time; struct sample_id sample_id; };
- PERF_RECORD_READ
- 该记录指示读取事件。
struct { struct perf_event_header header; u32 pid, tid; struct read_format values; struct sample_id sample_id; };
- PERF_RECORD_SAMPLE
- 该记录表示一个样本。
struct { struct perf_event_header header; u64 sample_id; /* if PERF_SAMPLE_IDENTIFIER */ u64 ip; /* if PERF_SAMPLE_IP */ u32 pid, tid; /* if PERF_SAMPLE_TID */ u64 time; /* if PERF_SAMPLE_TIME */ u64 addr; /* if PERF_SAMPLE_ADDR */ u64 id; /* if PERF_SAMPLE_ID */ u64 stream_id; /* if PERF_SAMPLE_STREAM_ID */ u32 cpu, res; /* if PERF_SAMPLE_CPU */ u64 period; /* if PERF_SAMPLE_PERIOD */ struct read_format v; /* if PERF_SAMPLE_READ */ u64 nr; /* if PERF_SAMPLE_CALLCHAIN */ u64 ips[nr]; /* if PERF_SAMPLE_CALLCHAIN */ u32 size; /* if PERF_SAMPLE_RAW */ char data[size]; /* if PERF_SAMPLE_RAW */ u64 bnr; /* if PERF_SAMPLE_BRANCH_STACK */ struct perf_branch_entry lbr[bnr]; /* if PERF_SAMPLE_BRANCH_STACK */ u64 abi; /* if PERF_SAMPLE_REGS_USER */ u64 regs[weight(mask)]; /* if PERF_SAMPLE_REGS_USER */ u64 size; /* if PERF_SAMPLE_STACK_USER */ char data[size]; /* if PERF_SAMPLE_STACK_USER */ u64 dyn_size; /* if PERF_SAMPLE_STACK_USER && size != 0 */ u64 weight; /* if PERF_SAMPLE_WEIGHT */ u64 data_src; /* if PERF_SAMPLE_DATA_SRC */ u64 transaction; /* if PERF_SAMPLE_TRANSACTION */ u64 abi; /* if PERF_SAMPLE_REGS_INTR */ u64 regs[weight(mask)]; /* if PERF_SAMPLE_REGS_INTR */ };
- sample_id
- 如果启用了PERF_SAMPLE_IDENTIFIER,则将包含64位唯一ID。这是PERF_SAMPLE_ID id值的重复,但包含在样本的开头,因此解析器可以轻松获取该值。
- ip
- 如果启用了PERF_SAMPLE_IP,则将包含64位指令指针值。
- pid, tid
- 如果启用了PERF_SAMPLE_TID,则将包含32位进程ID和32位线程ID。
- time
- 如果启用了PERF_SAMPLE_TIME,则将包含64位时间戳。这是通过local_clock()获得的,它是硬件时间戳(如果有),还有jiffies值(如果没有)。
- addr
- 如果启用了PERF_SAMPLE_ADDR,则将包含一个64位地址。这通常是跟踪点,断点或软件事件的地址。否则值为0。
- id
- 如果启用了PERF_SAMPLE_ID,则将包含64位唯一ID。如果事件是事件组的成员,则返回组长ID。此ID与PERF_FORMAT_ID返回的ID相同。
- stream_id
- 如果启用了PERF_SAMPLE_STREAM_ID,则将包含64位唯一ID。与PERF_SAMPLE_ID不同,返回的是实际ID,而不是组长。此ID与PERF_FORMAT_ID返回的ID相同。
- cpu, res
- 如果启用了PERF_SAMPLE_CPU,则除了保留(未使用)32位值外,这是一个32位值,指示正在使用哪个CPU。
- period
- 如果启用了PERF_SAMPLE_PERIOD,则将写入指示当前采样周期的64位值。
- v
- 如果启用了PERF_SAMPLE_READ,则将包括类型为read_format的结构,该结构具有事件组中所有事件的值。包含的值取决于perf_event_open()时使用的read_format值。
- nr, ips[nr]
- 如果启用了PERF_SAMPLE_CALLCHAIN,则将包括一个64位数字,该数字指示将跟随多少后续的64位指令指针。这是当前的呼叫链。
- size, data[size]
- 如果启用了PERF_SAMPLE_RAW,则将包括指示大小的32位值,然后是长度为8位的值数组。这些值将填充0以具有64位对齐方式。
- 相对于ABI,此RAW记录数据是不透明的。 ABI对其内容的稳定性不做任何保证,它可能根据事件,硬件和内核版本而有所不同。
- bnr, lbr[bnr]
- If
PERF_SAMPLE_BRANCH_STACK
is enabled, then a 64-bit value indicating
the number of records is included, followed by
bnrperf_branch_entry
structures which each include the fields:
- from
- 这表示源指令(可能不是分支)。
- to
- 分支目标。
- mispred
- 分支目标被错误预测。
- predicted
- 预测了分支目标。
- in_tx(since Linux 3.11)
- 该分支处于事务性内存事务中。
- abort(since Linux 3.11)
- 该分支处于中止的事务内存事务中。
- cycles(since Linux 4.3)
- 这报告自上一个分支堆栈更新以来经过的周期数。
这些条目是从最新到最近的条目,因此第一个条目具有最新的分支。
对错误预测,预测和周期的支持是可选的;如果不支持,则这些值为0。
记录的分支类型由branch_sample_type字段指定。
- abi, regs[weight(mask)]
- 如果启用了PERF_SAMPLE_REGS_USER,则将记录用户CPU寄存器。
- abi字段是PERF_SAMPLE_REGS_ABI_NONE,PERF_SAMPLE_REGS_ABI_32或PERF_SAMPLE_REGS_ABI_64之一。
- regs字段是由sample_regs_user attr字段指定的CPU寄存器的数组。值的数量是在sample_regs_user位掩码中设置的位数。
- size, data[size], dyn_size
- 如果启用了PERF_SAMPLE_STACK_USER,则将记录用户堆栈。这可用于生成堆栈回溯。 size是用户在sample_stack_user中请求的大小,否则为最大记录大小。 data是堆栈数据(采样时由堆栈指针指向的内存的原始转储)。 dyn_size是实际转储的数据量(可以小于size)。请注意,如果size为0,则将省略dyn_size。
- weight
- 如果启用了PERF_SAMPLE_WEIGHT,则将记录硬件提供的64位值,该值指示事件的代价。这样可以使昂贵的事件在配置文件中更清晰地突出显示。
- data_src
- If
PERF_SAMPLE_DATA_SRC
is enabled, then a 64-bit value is recorded that is made up of
the following fields:- mem_op
- 操作码的类型,按位组合:
- PERF_MEM_OP_NA
- 无法使用
- PERF_MEM_OP_LOAD
- 加载指令
- PERF_MEM_OP_STORE
- 店铺指示
- PERF_MEM_OP_PFETCH
- 预取
- PERF_MEM_OP_EXEC
- 可执行代码
- mem_lvl
- 存储器层次结构级别命中或未命中(以下各项的按位组合),向左移动PERF_MEM_LVL_SHIFT:
- PERF_MEM_LVL_NA
- 无法使用
- PERF_MEM_LVL_HIT
- 击中
- PERF_MEM_LVL_MISS
- 小姐
- PERF_MEM_LVL_L1
- 一级缓存
- PERF_MEM_LVL_LFB
- 行填充缓冲区
- PERF_MEM_LVL_L2
- 2级缓存
- PERF_MEM_LVL_L3
- 三级缓存
- PERF_MEM_LVL_LOC_RAM
- 本地DRAM
- PERF_MEM_LVL_REM_RAM1
- 远程DRAM 1跳
- PERF_MEM_LVL_REM_RAM2
- 远程DRAM 2跳
- PERF_MEM_LVL_REM_CCE1
- 远程缓存1跳
- PERF_MEM_LVL_REM_CCE2
- 远程缓存2跳
- PERF_MEM_LVL_IO
- I / O内存
- PERF_MEM_LVL_UNC
- 未缓存的内存
- mem_snoop
- 探听模式(以下各项的按位组合)向左移动PERF_MEM_SNOOP_SHIFT:
- PERF_MEM_SNOOP_NA
- 无法使用
- PERF_MEM_SNOOP_NONE
- 没有窥探
- PERF_MEM_SNOOP_HIT
- 史努比
- PERF_MEM_SNOOP_MISS
- 史努比小姐
- PERF_MEM_SNOOP_HITM
- 史努比命中
- mem_lock
- 锁定指令(以下各项的按位组合)向左移动PERF_MEM_LOCK_SHIFT:
- PERF_MEM_LOCK_NA
- 无法使用
- PERF_MEM_LOCK_LOCKED
- 锁定交易
- mem_dtlb
- TLB访问命中或未命中,以下各项的按位组合,向左移PERF_MEM_TLB_SHIFT:
- PERF_MEM_TLB_NA
- 无法使用
- PERF_MEM_TLB_HIT
- 击中
- PERF_MEM_TLB_MISS
- 小姐
- PERF_MEM_TLB_L1
- 1级TLB
- PERF_MEM_TLB_L2
- 2级TLB
- PERF_MEM_TLB_WK
- 五金助行器
- PERF_MEM_TLB_OS
- 操作系统故障处理程序
- transaction
- 如果设置了PERF_SAMPLE_TRANSACTION标志,则将记录一个64位字段,该字段描述任何事务性内存中止的来源。
- The field is a bitwise combination of the following values:
- PERF_TXN_ELISION
- 中止省略类型事务(特定于Intel-CPU)。
- PERF_TXN_TRANSACTION
- 中止一般交易。
- PERF_TXN_SYNC
- 同步中止(与报告的指令有关)。
- PERF_TXN_ASYNC
- 异步中止(与报告的指令无关)。
- PERF_TXN_RETRY
- 可重试中止(重试事务可能已成功)。
- PERF_TXN_CONFLICT
- 由于内存与其他线程冲突而中止。
- PERF_TXN_CAPACITY_WRITE
- 由于写容量溢出而中止。
- PERF_TXN_CAPACITY_READ
- 由于读取容量溢出而中止。
- 此外,通过向右移PERF_TXN_ABORT_SHIFT并用值PERF_TXN_ABORT_MASK进行掩蔽,可以从该字段的高32位获得用户指定的中止码。
- abi, regs[weight(mask)]
- 如果启用了PERF_SAMPLE_REGS_INTR,则将记录用户CPU寄存器。
- abi字段是PERF_SAMPLE_REGS_ABI_NONE,PERF_SAMPLE_REGS_ABI_32或PERF_SAMPLE_REGS_ABI_64之一。
- regs字段是由sample_regs_intr attr字段指定的CPU寄存器的数组。值的数量是在sample_regs_intr位掩码中设置的位数。
- PERF_RECORD_MMAP2
- 该记录包括有关mmap(2)调用的扩展信息,这些信息返回可执行映射。该格式与PERF_RECORD_MMAP记录的格式相似,但是包含允许唯一标识共享映射的额外值。
struct { struct perf_event_header header; u32 pid; u32 tid; u64 addr; u64 len; u64 pgoff; u32 maj; u32 min; u64 ino; u64 ino_generation; u32 prot; u32 flags; char filename[]; struct sample_id sample_id; };
- pid
- 是进程ID。
- tid
- 是线程ID。
- addr
- 是分配的内存的地址。
- len
- 是分配的内存的长度。
- pgoff
- 是分配的内存的页面偏移量。
- maj
- 是基础设备的主要ID。
- min
- 是基础设备的次设备ID。
- ino
- 是索引节点号。
- ino_generation
- 是inode代。
- prot
- 是保护信息。
- flags
- 是标志信息。
- filename
- 是一个字符串,描述分配的内存的支持。
- PERF_RECORD_AUX(since Linux 4.1)
- 该记录报告新数据在单独的AUX缓冲区中可用。
struct { struct perf_event_header header; u64 aux_offset; u64 aux_size; u64 flags; struct sample_id sample_id; };
- aux_offset
- 在新数据开始的AUX mmap区域中的偏移量。
- aux_size
- 可用数据的大小。
- flags
- describes the AUX update.
- PERF_AUX_FLAG_TRUNCATED
- 如果设置,则返回的数据将被截断以适合可用的缓冲区大小。
- PERF_AUX_FLAG_OVERWRITE
- 如果设置,则返回的数据将覆盖先前的数据。
- PERF_RECORD_ITRACE_START(since Linux 4.1)
- 该记录指示哪个进程启动了指令跟踪事件,从而允许工具将AUX缓冲区中的指令地址与适当的可执行文件正确关联。
struct { struct perf_event_header header; u32 pid; u32 tid; };
- pid
- 开始指令跟踪的线程的进程ID。
- tid
- 开始指令跟踪的线程的线程ID。
- PERF_RECORD_LOST_SAMPLES(since Linux 4.2)
- 当使用硬件采样(例如Intel PEBS)时,该记录表明可能丢失了一些采样。
struct { struct perf_event_header header; u64 lost; struct sample_id sample_id; };
- lost
- 可能丢失的样本数。
- PERF_RECORD_SWITCH(since Linux 4.3)
- 该记录表明发生了上下文切换。 misc字段中的PERF_RECORD_MISC_SWITCH_OUT位指示它是上下文切换到当前进程还是从当前进程切换。
struct { struct perf_event_header header; struct sample_id sample_id; };
- PERF_RECORD_SWITCH_CPU_WIDE(since Linux 4.3)
- 与PERF_RECORD_SWITCH一样,该记录表明发生了上下文切换,但仅在以CPU范围模式进行采样时才会发生,并且提供有关正在切换到/从进程切换的其他信息。 misc字段中的PERF_RECORD_MISC_SWITCH_OUT位指示它是上下文切换到当前进程还是从当前进程切换。
struct { struct perf_event_header header; u32 next_prev_pid; u32 next_prev_tid; struct sample_id sample_id; };
- next_prev_pid
- CPU上一个(如果是切入)或下一个(如果切出)进程的进程ID。
- next_prev_tid
- CPU上一个(如果输入)或下一个(如果输出)线程的线程ID。
Overflow handling
可以设置事件以通知何时超过阈值,指示发生溢出。可以通过使用poll(2),select(2)或epoll(7)监视事件文件描述符来捕获溢出条件。另外,通过在文件描述符上启用I / O信令,可以通过信号处理程序捕获溢出事件。请参阅fcntl(2)中有关F_SETOWN和F_SETSIG操作的讨论。
溢出仅通过采样事件生成(sample_period必须具有非零值)。
有两种方法可以生成溢出通知。
第一种是设置一个wakeup_events或wakeup_watermark值,如果将一定数量的样本或字节写入mmap环形缓冲区,则将触发该值。在这种情况下,指示POLL_IN。
另一种方法是使用PERF_EVENT_IOC_REFRESH ioctl。此ioctl添加到一个计数器,该计数器在每次事件溢出时递减。如果为非零,则指示POLL_IN,但是一旦计数器达到0,就会指示POLL_HUP并禁用基础事件。
刷新事件组负责人会刷新所有同级,并且使用参数0刷新当前会启用无限刷新。这些行为不受支持,因此不应依赖。
从Linux 3.18开始,如果要监视的事件附加到另一个进程并且该进程退出,则指示POLL_HUP。
rdpmc instruction
从x86上的Linux 3.4开始,您可以使用rdpmc指令获得低延迟读取,而不必进入内核。请注意,使用rdpmc不一定比其他读取事件值的方法快。
可以通过mmap页面中的cap_usr_rdpmc字段检测到对此的支持。在该部分中可以找到有关如何计算事件值的文档。
最初,启用rdpmc支持后,任何进程(不仅仅是具有活动perf事件的进程)都可以使用rdpmc指令访问计数器。从Linux 4.0开始,仅当在进程上下文中当前启用事件时,才允许rdpmc支持。要恢复旧的行为,请将值2写入/ sys / devices / cpu / rdpmc。
perf_event ioctl calls
各种ioctl作用于perf_event_open()文件描述符:
- PERF_EVENT_IOC_ENABLE
- 这将启用由文件描述符参数指定的单个事件或事件组。
- 如果ioctl参数中的PERF_IOC_FLAG_GROUP位置1,则即使指定的事件不是组长(但请参阅BUGS),也会启用组中的所有事件。
- PERF_EVENT_IOC_DISABLE
- 这将禁用由文件描述符参数指定的单个计数器或事件组。
- 启用或禁用组长可以启用或禁用整个组;也就是说,在禁用组长时,组中的任何计数器都不会计数。启用或禁用组长(而不是组长)的成员只会影响该计数器;禁用非领导者将停止该计数器的计数,但不会影响任何其他计数器。
- 如果ioctl参数中的PERF_IOC_FLAG_GROUP位置1,则即使指定的事件不是组长(但请参阅BUGS),也会禁用组中的所有事件。
- PERF_EVENT_IOC_REFRESH
- 非继承的溢出计数器可以使用它来启用针对该参数指定的大量溢出的计数器,然后将其禁用。此ioctl的后续调用会将参数值添加到当前计数中。每次溢出前都会发生设置了POLL_IN的溢出通知,直到计数达到0为止;发生这种情况时,将发送设置了POLL_HUP的通知,并禁用该事件。使用参数0视为未定义行为。
- PERF_EVENT_IOC_RESET
- 将文件描述符参数指定的事件计数重置为零。这只会重置计数;无法重置多路复用time_enabled或time_running值。
- 如果ioctl参数中的PERF_IOC_FLAG_GROUP位置1,则即使指定的事件不是组长(但请参阅BUGS),也会重置组中的所有事件。
- PERF_EVENT_IOC_PERIOD
- 这将更新事件的溢出周期。
- 从Linux 3.7(在ARM上)和Linux 3.14(所有其他体系结构)开始,新时期立即生效。在较旧的内核上,新的周期直到下一次溢出后才生效。
- 该参数是指向包含所需新周期的64位值的指针。
- 在Linux 2.6.36之前,此ioctl总是由于内核中的错误而失败。
- PERF_EVENT_IOC_SET_OUTPUT
- 这告诉内核将事件通知报告给指定的文件描述符,而不是默认的文件描述符。文件描述符必须全部在同一CPU上。
- 该参数指定所需的文件描述符;如果应忽略输出,则为-1。
- PERF_EVENT_IOC_SET_FILTER(since Linux 2.6.33)
- 这将向该事件添加ftrace过滤器。
- 该参数是指向所需ftrace过滤器的指针。
- PERF_EVENT_IOC_ID(since Linux 3.12)
- 这将返回给定事件文件描述符的事件ID值。
- 该参数是一个指向要保存结果的64位无符号整数的指针。
- PERF_EVENT_IOC_SET_BPF(since Linux 4.1)
- 这允许将Berkeley数据包筛选器(BPF)程序附加到现有的kprobe跟踪点事件。您需要CAP_SYS_ADMIN权限才能使用此ioctl。
- 该参数是由先前的bpf(2)系统调用创建的BPF程序文件描述符。
- PERF_EVENT_IOC_PAUSE_OUTPUT(since Linux 4.7)
- 这允许暂停和恢复事件的环形缓冲区。暂停的环形缓冲区不会阻止采样的产生,而只是丢弃它们。丢弃的样本被视为丢失,并在可能的情况下导致生成PERF_RECORD_LOST样本。即使环形缓冲区保持为空,丢弃的样本仍可能触发溢出信号。
- 参数是一个无符号的32位整数。非零值将暂停环形缓冲区,而零值将恢复环形缓冲区。
- PERF_EVENT_MODIFY_ATTRIBUTES(since Linux 4.17)
- 这允许修改现有事件,而无需关闭和重新打开新事件的开销。当前,仅断点事件支持此功能。
- 该参数是指向包含更新后的事件设置的perf_event_attr结构的指针。
- PERF_EVENT_IOC_QUERY_BPF(since Linux 4.16)
- 这允许查询将哪些Berkeley数据包筛选器(BPF)程序附加到现有的kprobe跟踪点。每个事件只能附加一个BPF程序,但是可以将多个事件附加到跟踪点。在一个跟踪点事件上查询此值将返回在附加到跟踪点的所有事件中所有BPF程序的ID。您需要CAP_SYS_ADMIN权限才能使用此ioctl。
- 参数是指向结构的指针
- ids_len字段指示可以容纳在提供的id数组中的id的数量。内核会使用附加的BPF程序的数量来填充prog_cnt值。 ids数组填充有每个附加的BPF程序的id。如果程序数量超出了阵列中的容量,则内核将返回ENOSPC,并且ids_len将指示已成功复制的程序ID的数量。
Using prctl(2)
进程可以使用prctl(2)PR_TASK_PERF_EVENTS_ENABLE和PR_TASK_PERF_EVENTS_DISABLE操作启用或禁用所有当前打开的事件组。这仅适用于调用过程在本地创建的事件。这不适用于由附加到调用进程的其他进程创建的事件或从父进程继承的事件。仅启用和禁用组长,组中其他成员均未启用。
perf_event related configuration files
/ proc / sys / kernel /中的文件
- /proc/sys/kernel/perf_event_paranoid
- 可以设置perf_event_paranoid文件以限制对性能计数器的访问。
- 2
- 仅允许用户空间测量(自Linux 4.6起为默认值)。
- 1
- 允许内核和用户测量(Linux 4.6之前是默认值)。
- 0
- 允许访问特定于CPU的数据,但不能访问原始跟踪点样本。
- -1
- 没有限制。
- perf_event_paranoid文件的存在是确定内核是否支持perf_event_open()的正式方法。
- /proc/sys/kernel/perf_event_max_sample_rate
- 设置最大采样率。将该值设置得太高可能会使用户以影响整体机器性能的速率进行采样,并有可能锁定机器。默认值为100000(每秒采样数)。
- /proc/sys/kernel/perf_event_max_stack
- 该文件设置生成呼叫跟踪时报告的最大堆栈帧条目深度。
- /proc/sys/kernel/perf_event_mlock_kb
- 非特权用户可以锁(2)的最大页面数。默认值为516(kB)。
/ sys / bus / event_source / devices /中的文件
- Since Linux 2.6.34, the kernel supports having multiple PMUs
available for monitoring.
Information on how to program these PMUs can be found under
/sys/bus/event_source/devices/.
Each subdirectory corresponds to a different PMU.
- /sys/bus/event_source/devices/*/type(since Linux 2.6.38)
- 它包含一个可以在perf_event_attr的type字段中使用的整数,以指示您希望使用此PMU。
- /sys/bus/event_source/devices/cpu/rdpmc(since Linux 3.4)
- 如果该文件为1,则可以通过rdpmc指令直接在用户空间中访问性能计数器寄存器。可以通过在文件中回显0来禁用此功能。
- 从Linux 4.0开始,行为已更改,因此1表示只允许访问具有活动perf事件的进程,2表示旧的allow-anyone-access行为。
- /sys/bus/event_source/devices/*/format/(since Linux 3.4)
- 该子目录包含有关特定于体系结构的子字段的信息,这些子字段可用于对perf_event_attr结构中的各种配置字段进行编程。
- 每个文件的内容是config字段的名称,后跟一个冒号,然后是一系列用逗号分隔的整数位范围。例如,文件事件可能包含值config1:1,6-10,44,该值指示事件是占据perf_event_attr :: config1的位1,6-10和44的属性。
- /sys/bus/event_source/devices/*/events/(since Linux 3.4)
- 此子目录包含具有预定义事件的文件。内容是描述事件设置的字符串,这些事件设置是根据前面提到的./format/目录中的字段表示的。这些不一定是PMU支持的所有事件的完整列表,而是通常被认为有用或有趣的事件子集。
- 每个文件的内容都是用逗号分隔的属性名称列表。每个条目都有一个可选值(十六进制或十进制)。如果未指定任何值,则假定它是值为1的单个字段。示例条目可能类似于:event = 0x2,inv,ldlat = 3。
- /sys/bus/event_source/devices/*/uevent
- 该文件是用于注入热插拔事件的标准内核设备接口。
- /sys/bus/event_source/devices/*/cpumask(since Linux 3.7)
- cpumask文件包含一个逗号分隔的整数列表,这些整数表示主板上每个插槽(包装)的代表CPU编号。设置非核心或北桥事件时,这是必需的,因为这些PMU会显示套接字范围的事件。
返回值
perf_event_open()返回新的文件描述符,如果发生错误,则返回-1(在这种情况下,将正确设置errno)。
错误说明
perf_event_open()返回的错误可能不一致,并且在处理器体系结构和性能监视单元之间可能有所不同。
- E2BIG
- 如果perf_event_attr大小值太小(小于PERF_ATTR_SIZE_VER0),太大(大于页面大小)或大于内核支持,并且额外字节不为零,则返回。当返回E2BIG时,内核会覆盖perf_event_attr size字段,使其成为所需结构的大小。
- EACCES
- 当请求的事件需要CAP_SYS_ADMIN权限(或更宽松的perf_event偏执设置)时返回。非特权进程可能会遇到此错误的一些常见情况:附加到另一个用户拥有的进程;监视给定CPU上的所有进程(即,将pid参数指定为-1);并且在偏执设置需要时不设置exclude_kernel。
- EBADF
- 如果group_fd文件描述符无效,或者如果设置了PERF_FLAG_PID_CGROUP,则pid中的cgroup文件描述符无效,则返回该值。
- EBUSY(since Linux 4.1)
- 如果另一个事件已经具有对PMU的独占访问权,则返回。
- EFAULT
- 如果attr指针指向无效的内存地址,则返回。
- EINVAL
- 如果指定的事件无效,则返回。造成这种情况的原因很多。一个不详尽的列表:sample_freq高于最大值设置;要监视的CPU不存在; read_format超出范围; sample_type超出范围;标志值超出范围;排他集或固定集,且该活动不是组长;事件配置值超出范围或设置了保留位;不支持所选的通用事件;或没有足够的空间来添加所选事件。
- EINTR
- 尝试混合perf和ftrace处理伪装时返回。
- EMFILE
- 每个打开的事件使用一个文件描述符。如果打开大量事件,则将达到打开文件描述符数量的每个进程限制,并且无法创建更多事件。
- ENODEV
- 当事件涉及当前CPU不支持的功能时返回。
- ENOENT
- 如果类型设置无效,则返回。对于某些不受支持的通用事件,也会返回此错误。
- ENOSPC
- 在Linux 3.3之前的版本中,如果没有足够的空间容纳该事件,则返回ENOSPC。在Linux 3.3中,将其更改为EINVAL。如果尝试添加的断点事件多于硬件支持的数量,则仍返回ENOSPC。
- ENOSYS
- 如果在sample_type中设置了PERF_SAMPLE_STACK_USER,并且硬件不支持,则返回该值。
- EOPNOTSUPP
- 如果请求了需要特定硬件功能的事件但没有硬件支持,则返回该值。这包括请求不支持的防滑事件,不可用的分支跟踪,没有可用的PMU中断的采样以及软件事件的分支堆栈。
- EOVERFLOW(since Linux 4.8)
- 如果请求PERF_SAMPLE_CALLCHAIN并且sample_max_stack大于/ proc / sys / kernel / perf_event_max_stack中指定的最大值,则返回。
- EPERM
- 当指定了不受支持的exclude_hv,exclude_idle,exclude_user或exclude_kernel设置时,在许多(但不是全部)体系结构上返回。
- 与EACCES一样,当请求的事件需要CAP_SYS_ADMIN权限(或更宽松的perf_event偏执设置)时,也会发生这种情况。这包括在内核地址上设置断点,以及(从Linux 3.13开始)设置内核功能跟踪点。
- ESRCH
- 如果尝试附加到不存在的进程,则返回。
VERSION
perf_event_open()在Linux 2.6.31中引入,但被称为perf_counter_open()。在Linux 2.6.32中将其重命名。
遵循规范
此perf_event_open()系统调用特定于Linux,不应在打算移植的程序中使用。
备注
Glibc没有为该系统调用提供包装器;使用syscall(2)调用它。请参见下面的示例。
知道是否启用了perf_event_open()支持的正式方法是检查文件/ proc / sys / kernel / perf_event_paranoid。
BUGS
需要fcntl(2)的F_SETOWN_EX选项才能正确获取线程中的溢出信号。这是在Linux 2.6.32中引入的。
在Linux 2.6.33之前(至少对于x86是这样),内核直到检查时间才检查事件是否可以一起安排。如果启用了NMI看门狗,则在所有已知内核上也会发生相同的情况。这意味着要查看给定的事件集是否有效,您必须先perf_event_open(),开始,然后阅读,然后再确定是否可以获取有效的度量。
在Linux 2.6.34之前,内核不强制执行事件约束。在这种情况下,如果内核将它们安排在不适当的计数器插槽中,则某些事件将静默返回" 0"。
在Linux 2.6.34之前的版本中,多路复用时存在一个错误,该错误会返回错误的结果。
如果启用了"继承"并且启动了许多线程,则从Linux 2.6.35到Linux 2.6.39的内核可以使内核快速崩溃。
在Linux 2.6.35之前,PERF_FORMAT_GROUP不适用于附加进程。
在Linux 2.6.36和Linux 3.0之间的内核代码中有一个错误,该错误会忽略"水印"字段,并且如果联合中包含非零值,则其作用就好像是选择了clear_up_event。
从Linux 2.6.31到Linux 3.4,PERF_IOC_FLAG_GROUP ioctl参数已损坏,它将对指定的事件重复操作,而不是遍历组中的所有同级事件。
从Linux 3.4到Linux 3.11,mmap cap_usr_rdpmc和cap_usr_time位映射到同一位置。代码应改为迁移到新的cap_user_rdpmc和cap_user_time字段。
始终仔细检查您的结果!各种广义事件具有错误的值。例如,在Linux 2.6.35之前,退休的分支机构在AMD机器上测量了错误的结果。
示例
以下是一个简短的示例,用于测量对printf(3)的调用的总指令计数。
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/ioctl.h> #include <linux/perf_event.h> #include <asm/unistd.h> static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags) { int ret; ret = syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags); return ret; } int main(int argc, char **argv) { struct perf_event_attr pe; long long count; int fd; memset(&pe, 0, sizeof(struct perf_event_attr)); pe.type = PERF_TYPE_HARDWARE; pe.size = sizeof(struct perf_event_attr); pe.config = PERF_COUNT_HW_INSTRUCTIONS; pe.disabled = 1; pe.exclude_kernel = 1; pe.exclude_hv = 1; fd = perf_event_open(&pe, 0, -1, -1, 0); if (fd == -1) { fprintf(stderr, "Error opening leader %llx\n", pe.config); exit(EXIT_FAILURE); } ioctl(fd, PERF_EVENT_IOC_RESET, 0); ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); printf("Measuring instruction count for this printf\n"); ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); read(fd, &count, sizeof(long long)); printf("Used %lld instructions\n", count); close(fd); }
另外参见
perf(1),fcntl(2),mmap(2),open(2),prctl(2),read(2)
内核源代码树中的Documentation / admin-guide / perf-security.rst
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。