PERF_EVENT_OPEN - Linux手册页

时间:2019-08-20 17:59:06  来源:igfitidea点击:

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_funcuprobe_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
config

to 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
config

to 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
config

value 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_funcuprobe_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_format

order.

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_1HW_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_MONOTONICCLOCK_MONOTONIC_RAWCLOCK_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_offsettime_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
type

selected 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
bnr

perf_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_hvexclude_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/