Telegraf Intel PMU 输入插件实战指南:通过 Linux Perf 子系统采集核心与 Uncore 硬件性能计数器
2026/9/14 2:40:55 网站建设 项目流程

Telegraf Intel PMU 输入插件实战指南:通过 Linux Perf 子系统采集核心与 Uncore 硬件性能计数器

【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf

本文以 Telegraf 仓库内plugins/inputs/intel_pmu插件为对象,系统讲解如何通过 Linux Perf 子系统采集 Intel 处理器 Performance Monitoring Unit(PMU)指标。阅读本文后,你将掌握该插件的事件定义文件准备、核心事件(core events)与 Uncore 事件(uncore events)配置、perf 修饰符语义、事件组(perf group)与聚合行为,以及输出指标中raw/enabled/running/scaled四个字段的真实含义,可直接用于 CPU 性能剖析与利用率监控的落地配置。

插件概览与适用场景

Intel PMU 插件(intel_pmu)用于采集 Linux Perf 子系统暴露的 Intel Performance Monitoring Unit 指标。性能计数器是 CPU 上的硬件寄存器,用于统计诸如已执行指令数(instructions executed)、缓存未命中数(cache-misses suffered)、分支预测失败数(branches mispredicted)等硬件事件,是应用性能剖析、动态控制流追踪与热点识别的数据基础。

随着核心数持续增长、处理器拓扑日趋复杂,对 IA 处理器内部组件(包括 core 与 uncore 单元)性能与健康状态的洞察,成为保障 CPU 最佳性能与利用率的关键。该插件正是面向这一场景:既采集每个核心的 core 事件,也采集分布在 CPU 包(socket)内各 PMU 上的 uncore 事件。

  • 引入版本:⭐ Telegraf v1.21.0(见 插件 README)
  • 分类标签:🏷️ hardware、system
  • 运行平台:💻 仅支持Linux 64-bit(amd64)系统

插件在非 Linux/amd64 平台上的实现会退化为空操作:在Init阶段打印"Current platform is not supported"警告,Gather不产生任何数据(见 intel_pmu_notamd64linux.go)。

插件依赖 iaevents 库(当前仓库 go.mod 锁定版本为github.com/intel/iaevents v1.1.0)来访问 Linux 内核的 perf 接口,通过perf_event_open系统调用完成事件激活与计数读取。

工作原理与测量流程

从 intel_pmu.go 的InitGather实现可以看出,插件遵循"初始化一次、周期读取"的模型:

  1. 初始化(Init)

    • 校验event_definitions指向的 JSON 文件存在、且为常规文件(拒绝符号链接);
    • 通过ia.JSONFilesReader读取事件定义文件(旧版 perfmon 事件格式会被识别并打印警告后跳过);
    • 解析配置中的 core/uncore 事件、core/socket ID;
    • 将用户提供的事件名与 JSON 中的事件定义匹配(resolver),翻译为对应的 perf 属性;
    • 估算所需文件描述符数量并做上限校验(详见下文"文件描述符注意事项");
    • 激活(activate)所有事件,开始计数。
  2. 周期采集(Gather):在每个 Telegraf 采集间隔,并行读取每个已激活事件的计数值,计算 scaled 值后发布为pmu_metric指标。

  3. 停止(Stop):依次Deactivate所有 core 与 uncore 激活事件。

值得注意的实现细节(可参见 resolver.go):

  • core 事件块中若出现 uncore 事件名,会报错uncore event found in core entity,反之亦然——两者被严格区分。
  • 当未显式指定events列表(allEvents模式)时,会解析文件中全部事件,无法解析的事件被跳过并在日志中警告"Some events may be omitted"。
  • 事件激活时以进程号-1(即所有运行中的进程)为目标,因此采集到的计数反映系统全局活动,而非某个特定进程

另外,从 reader.go 可以看到,每个事件值的读取通过errgroup并发执行;uncore 事件聚合时使用ia.AggregateValues对同一 socket 上多个同类型 PMU 的 raw/enabled/running 分别求和。

环境要求与事件定义文件

  • 平台限制:插件仅适用于 Linux 64-bit(amd64)系统,这是使用前提。
  • 事件定义文件:插件不内置任何事件定义。不同微架构的 PMU 事件定义以 JSON 文件形式发布在 perfmon 仓库(Intel 官方事件文件仓库)中,你需要下载与当前 CPU 型号匹配的 core 与 uncore 事件定义文件,并保存在系统上的安全位置。

事件定义 JSON 文件命名通常形如GenuineIntel-6-55-4-core.json(core 事件)与GenuineIntel-6-55-4-uncore.json(uncore 事件),其中6-55-4对应 CPUID 的 family-model-stepping。可使用 perfmon 仓库配套的 PMU 工具脚本下载适配当前系统的文件,并建议统一存放于/var/cache/pmu/这类固定目录,以便在配置中引用。

在启动前可通过系统命令确认 CPU 拓扑与事件源:uncore 事件的 PMU 名称可在/sys/bus/event_source/devices/下列出(如uncore_cbox_0uncore_imc_1等)。

完整配置示例与参数详解

以下为插件官方sample.conf(见 sample.conf)的完整内容,可直接复制并替换事件定义路径与事件列表:

# Intel Performance Monitoring Unit plugin exposes Intel PMU metrics available through Linux Perf subsystem # This plugin ONLY supports Linux on amd64 [[inputs.intel_pmu]] ## List of filesystem locations of JSON files that contain PMU event definitions. event_definitions = ["/var/cache/pmu/GenuineIntel-6-55-4-core.json", "/var/cache/pmu/GenuineIntel-6-55-4-uncore.json"] ## List of core events measurement entities. There can be more than one core_events sections. [[inputs.intel_pmu.core_events]] ## List of events to be counted. Event names shall match names from event_definitions files. ## Single entry can contain name of the event (case insensitive) augmented with config options and perf modifiers. ## If absent, all core events from provided event_definitions are counted skipping unresolvable ones. events = ["INST_RETIRED.ANY", "CPU_CLK_UNHALTED.THREAD_ANY:config1=0x4043200000000k"] ## Limits the counting of events to core numbers specified. ## If absent, events are counted on all cores. ## Single "0", multiple "0,1,2" and range "0-2" notation is supported for each array element. ## example: cores = ["0,2", "4", "12-16"] cores = ["0"] ## Indicator that plugin shall attempt to run core_events.events as a single perf group. ## If absent or set to false, each event is counted individually. Defaults to false. ## This limits the number of events that can be measured to a maximum of available hardware counters per core. ## Could vary depending on type of event, use of fixed counters. # perf_group = false ## Optionally set a custom tag value that will be added to every measurement within this events group. ## Can be applied to any group of events, unrelated to perf_group setting. # events_tag = "" ## List of uncore event measurement entities. There can be more than one uncore_events sections. [[inputs.intel_pmu.uncore_events]] ## List of events to be counted. Event names shall match names from event_definitions files. ## Single entry can contain name of the event (case insensitive) augmented with config options and perf modifiers. ## If absent, all uncore events from provided event_definitions are counted skipping unresolvable ones. events = ["UNC_CHA_CLOCKTICKS", "UNC_CHA_TOR_OCCUPANCY.IA_MISS"] ## Limits the counting of events to specified sockets. ## If absent, events are counted on all sockets. ## Single "0", multiple "0,1" and range "0-1" notation is supported for each array element. ## example: sockets = ["0-2"] sockets = ["0"] ## Indicator that plugin shall provide an aggregated value for multiple units of same type distributed in an uncore. ## If absent or set to false, events for each unit are exposed as separate metric. Defaults to false. # aggregate_uncore_units = false ## Optionally set a custom tag value that will be added to every measurement within this events group. # events_tag = ""

顶层参数

参数类型必填说明
event_definitionsstring 数组必填包含 PMU 事件定义的 JSON 文件路径列表。Init阶段会校验每个文件存在、且为常规文件(符号链接会被拒绝,见 intel_pmu.go 的checkFiles)。

core_events 小节参数

每个[[inputs.intel_pmu.core_events]]小节定义一个核心事件测量实体,可重复出现多个小节:

参数类型默认说明
eventsstring 数组无(缺省时统计文件内全部 core 事件)要计数的事件名,须与事件定义文件中的名称匹配,大小写不敏感;单条目可在事件名后追加配置选项与 perf 修饰符
coresstring 数组无(缺省时统计所有核心)限制在指定的核心上计数;数组每个元素支持单个"0"、多个"0,1,2"与范围"0-2"三种记法,可混合使用如cores = ["0,2", "4", "12-16"]
perf_groupboolfalse若为 true,尝试将本小节的events作为一个 perf 事件组整体调度(详见下文"核心事件组")
events_tagstring可选的自定义标签值,会附加到本小节产生的每条测量上;与perf_group设置无关,可独立使用

uncore_events 小节参数

参数类型默认说明
eventsstring 数组无(缺省时统计文件内全部 uncore 事件)同 core 事件,名称须匹配定义文件,大小写不敏感,可带修饰符
socketsstring 数组无(缺省时统计所有 socket)限制在指定的 socket(CPU 包)上计数;同样支持单个、多个与范围记法,如sockets = ["0-2"]
aggregate_uncore_unitsboolfalse为 true 时,将同一 socket 内同类型多个 PMU 单元的计数聚合为一条测量;为 false 时每个单元独立输出一条测量
events_tagstring同 core 小节,附加自定义标签值

配置解析的边界行为(源码印证)

来自 config.go 的细节:

  • core_eventsuncore_events均未配置,启动报错neither core nor uncore entities configured
  • events列表中的重复事件会被去重,并输出警告duplicated event ... will be removed
  • core/socket ID 解析支持逗号与a-b范围展开,a >= b时(start大于等于end)会报错;ID 总数上限为 8192(maxIDsSize = 1 << 13,基于 Linux 内核支持的最大 CPU 数)。
  • 重复的 ID 会被去重并警告。
  • 空列表(events = []cores = [])会被视为配置错误。

事件修饰符(Modifiers)

每个events列表元素可以按如下通用格式追加修饰符,用于调整事件特定的 perf 属性以满足特定采集需求:

EVENT_NAME(:(config|config1|config2)=(0x[0-9a-f]{1-16})(p|k|u|h|H|I|G|D))*

即事件名后通过冒号分隔、可叠加多个key=value或单字母标志。各修饰符与perf_event_open系统调用(其perf_event_attr结构)的对应关系如下表:

Modifier底层属性说明
configperf_event_attr.config事件类型相关的配置
config1perf_event_attr.config1config 的扩展
config2perf_event_attr.config2config1 的扩展
pperf_event_attr.precise_ip滑步(skid)约束,限制采样精度
kperf_event_attr.exclude_user不统计用户态(user space)
uperf_event_attr.exclude_kernel不统计内核态(kernel space)
h / Hperf_event_attr.exclude_guest不在 guest(虚拟机)中计数
Iperf_event_attr.exclude_idle空闲时不计
Gperf_event_attr.exclude_hv不计 hypervisor
Dperf_event_attr.pinned事件必须一直固定在 PMU 上(不可被复用)

示例:"CPU_CLK_UNHALTED.THREAD_ANY:config1=0x4043200000000k"表示对CPU_CLK_UNHALTED.THREAD_ANY事件设置自定义config1值,并附加k修饰符(不统计用户态)。

注意单字母修饰符(p/k/u/h/H/I/G/D)彼此并不互斥,可自由组合;但ku同时出现时语义上"既不统计用户态也不统计内核态",请按实际需求谨慎组合。

核心事件组(Core Event Groups)

Perf 允许将多个事件组装成一个事件组(group)。事件组作为一个整体被调度到 CPU 上:仅当组内所有事件都能同时放置到 CPU 时,整个组才会被调度。这意味着组内成员事件的计数值可以相互有意义地比较——相加、相除求比率等——因为它们针对的是同一批已执行指令进行计数。

在插件中,将某个core_events小节的perf_group = true即可启用此行为(源码见 activators.go 的activateCoreEventsGroup,内部调用ia.ActivateGroup)。

注意:当尝试创建的事件组大小超过该核心可用的 PMU 硬件计数器数量时,插件会抛出错误,perf 系统调用返回的错误信息为 "invalid argument"。若需确认你的 Intel CPU 支持多少个 PMU 计数器,可使用cpuid命令查询。

同时要注意,启用perf_group会把可同时测量的事件数量限制在每核心可用硬件计数器上限内;该上限会随事件类型、是否使用固定计数器(fixed counters)而变化。

文件描述符(File Descriptors)注意事项

插件打开的文件描述符数量取决于被监控的 CPU 数量被监控的计数器数量的乘积:核心事件约为事件数 × 核心数,uncore 事件约为事件数 × PMU 类型数 × socket 数(估算逻辑见 intel_pmu.go 的estimateCoresFd/estimateUncoreFd)。

它很容易超过系统默认的单进程文件描述符上限。插件在初始化阶段会主动进行双重校验:

  1. 与内核级上限/proc/sys/fs/file-max比较;
  2. 与当前进程的软限制RLIMIT_NOFILE(通过syscall.Getrlimit(syscall.RLIMIT_NOFILE, ...)获取)比较。

任一超限都会报错,提示"consider increasing the limit"。根据配置规模,可能需要调高允许打开的文件描述符数量,例如通过ulimit -n命令(或为 Telegraf 服务配置相应的 LimitNOFILE)来提升。相关错误路径均有单元测试覆盖(见 intel_pmu_test.go 的exceeded file descriptors用例)。

指标格式与标签定义

每个 Telegraf 间隔,插件发布名为pmu_metric的测量,包含以下字段与标签。

Metric Fields

字段类型描述
enableduint64时间计数器,事件被启用的总时间
runninguint64时间计数器,事件实际被计数的总时间
rawuint64值计数器,事件实际计数期间的事件计数值
scaleduint64值计数器,按scaled = raw * (enabled / running)公式计算的事件连续计数近似值

关于四个字段的关系:正常情况下enabledrunning相等。但当启动的事件数量超过 PMU 可用计数器槽位时会发生时间复用(multiplexing),事件只在部分时间内被计数,此时二者出现差异。scaled值正是据此估算"若事件被持续计数"时的近似值,由 iaevents 库的EventScaledValue计算(见 intel_pmu.go 的Gather)。若 scaled 值超过 uint64 上限,插件会报错终止本次采集。

Metric Tags

通用标签(core 与 uncore 事件共有):

Tag描述
hostTelegraf 读取到的主机名
event事件名称

core 事件附加标签:

Tag描述
cpuCPU id(由 Linux OS 标识:启用超线程时为逻辑 CPU id,否则为物理 CPU id)
events_tag(可选)intel_pmu.core_events配置中定义的自定义标签值

uncore 事件附加标签:

Tag描述
socketsocket 号(由 Linux OS 标识,即physical_package_id
unit_type事件所计数 PMU 的类型,提供 PMU 类别信息,如 cbox(对应uncore_cbox_1)、r2pcie(对应uncore_r2pcie)等
unit事件所计数 PMU 的名称,与/sys/bus/event_source/devices/下列出的名字一致(如uncore_cbox_1uncore_imc_1);仅非聚合的 uncore 事件出现
events_tag(可选)intel_pmu.uncore_events配置中定义的自定义标签值

从 intel_pmu.go 的publishCoreMeasurements/publishUncoreMeasurements可以看到:聚合模式下(aggregate_uncore_units = true)不输出unit标签,仅输出unit_typeevents_tag只有在配置了非空值时才会作为标签出现。

输出示例解读

事件组(Event Group)

perf_group = trueevents_tag = "unhalted"时,core 事件在多个 CPU 上各自输出:

pmu_metric,cpu=0,event=CPU_CLK_THREAD_UNHALTED.REF_XCLK,events_tag=unhalted,host=xyz enabled=2871237051i,running=2871237051i,raw=1171711i,scaled=1171711i 1621254096000000000 pmu_metric,cpu=0,event=CPU_CLK_UNHALTED.THREAD_P_ANY,events_tag=unhalted,host=xyz enabled=2871240713i,running=2871240713i,raw=72340716i,scaled=72340716i 1621254096000000000 pmu_metric,cpu=1,event=CPU_CLK_THREAD_UNHALTED.REF_XCLK,events_tag=unhalted,host=xyz enabled=2871118275i,running=2871118275i,raw=1646752i,scaled=1646752i 1621254096000000000 pmu_metric,cpu=1,event=CPU_CLK_UNHALTED.THREAD_P_ANY,events_tag=unhalted,host=xyz raw=108802421i,scaled=108802421i,enabled=2871120107i,running=2871120107i 1621254096000000000 pmu_metric,cpu=2,event=CPU_CLK_THREAD_UNHALTED.REF_XCLK,events_tag=unhalted,host=xyz enabled=2871143950i,running=2871143950i,raw=1316834i,scaled=1316834i 1621254096000000000 pmu_metric,cpu=2,event=CPU_CLK_UNHALTED.THREAD_P_ANY,events_tag=unhalted,host=xyz enabled=2871074681i,running=2871074681i,raw=68728436i,scaled=68728436i 1621254096000000000

可见组内事件在同一 CPU 上的enabled/running值非常接近,这正是事件组"同进同出"调度语义的体现——便于对CPU_CLK_THREAD_UNHALTED.REF_XCLKCPU_CLK_UNHALTED.THREAD_P_ANY计算比率。

Uncore 事件(非聚合)

同一 uncore 事件在 socket 0 上的多个 cbox 单元分别输出(带unit标签):

pmu_metric,event=UNC_CBO_XSNP_RESPONSE.MISS_XCORE,host=xyz,socket=0,unit=uncore_cbox_0,unit_type=cbox enabled=2870630747i,running=2870630747i,raw=183996i,scaled=183996i 1621254096000000000 pmu_metric,event=UNC_CBO_XSNP_RESPONSE.MISS_XCORE,host=xyz,socket=0,unit=uncore_cbox_1,unit_type=cbox enabled=2870608194i,running=2870608194i,raw=185703i,scaled=185703i 1621254096000000000 pmu_metric,event=UNC_CBO_XSNP_RESPONSE.MISS_XCORE,host=xyz,socket=0,unit=uncore_cbox_2,unit_type=cbox enabled=2870600211i,running=2870600211i,raw=187331i,scaled=187331i 1621254096000000000 pmu_metric,event=UNC_CBO_XSNP_RESPONSE.MISS_XCORE,host=xyz,socket=0,unit=uncore_cbox_3,unit_type=cbox enabled=2870593914i,running=2870593914i,raw=184228i,scaled=184228i 1621254096000000000 pmu_metric,event=UNC_CBO_XSNP_RESPONSE.MISS_XCORE,host=xyz,socket=0,unit=uncore_cbox_4,unit_type=cbox scaled=195355i,enabled=2870558952i,running=2870558952i,raw=195355i 1621254096000000000 pmu_metric,event=UNC_CBO_XSNP_RESPONSE.MISS_XCORE,host=xyz,socket=0,unit=uncore_cbox_5,unit_type=cbox enabled=2870554131i,running=2870554131i,raw=197756i,scaled=197756i 1621254096000000000

Uncore 事件(聚合)

设置aggregate_uncore_units = true后,同一 socket、同一unit_type下多个单元合并为一条测量(不再有unit标签,计数为各单元之和):

pmu_metric,event=UNC_CBO_XSNP_RESPONSE.MISS_XCORE,host=xyz,socket=0,unit_type=cbox enabled=13199712335i,running=13199712335i,raw=467485i,scaled=467485i 1621254412000000000

时间复用(Time Multiplexing)

当事件数超过硬件计数器槽位时,可观察到enabledrunning明显不一致,scaled值高于raw值:

pmu_metric,cpu=0,event=CPU_CLK_THREAD_UNHALTED.REF_XCLK,host=xyz raw=2947727i,scaled=4428970i,enabled=2201071844i,running=1464935978i 1621254412000000000 pmu_metric,cpu=0,event=CPU_CLK_UNHALTED.THREAD_P_ANY,host=xyz running=1465155618i,raw=302553190i,scaled=454511623i,enabled=2201035323i 1621254412000000000 pmu_metric,cpu=0,event=CPU_CLK_UNHALTED.REF_XCLK,host=xyz enabled=2200994057i,running=1466812391i,raw=3177535i,scaled=4767982i 1621254412000000000 pmu_metric,cpu=0,event=CPU_CLK_UNHALTED.REF_XCLK_ANY,host=xyz enabled=2200963921i,running=1470523496i,raw=3359272i,scaled=5027894i 1621254412000000000 pmu_metric,cpu=0,event=L1D_PEND_MISS.PENDING_CYCLES_ANY,host=xyz enabled=2200933946i,running=1470322480i,raw=23631950i,scaled=35374798i 1621254412000000000 pmu_metric,cpu=0,event=L1D_PEND_MISS.PENDING_CYCLES,host=xyz raw=18767833i,scaled=28169827i,enabled=2200888514i,running=1466317384i 1621254412000000000

此处enabled ≈ 2.2e9running ≈ 1.46e9,说明事件仅在大约三分之二的时间内被实际计数,scaled已将这部分"缺失时间"折算进估算值,在做长期趋势与比率分析时应优先使用scaled

使用建议与常见排错

  • 先确认平台:非 Linux amd64 平台上插件静默不产出数据,只打印一条平台不支持警告,排查时留意日志。
  • 事件名匹配失败:事件名须与下载的事件定义文件完全对应(大小写不敏感);若某个事件无法解析,插件会报failed to resolve unknown event。缺省全量模式下无法解析的事件会被跳过并警告。
  • core/uncore 混用:core 小节中写 uncore 事件(或反之)会直接报错,请核对事件定义文件划分。
  • 事件组过大:启用perf_group后若报 "invalid argument",说明组内事件数超出该核心可用硬件计数器数,可通过cpuid确认 PMU 数量并精简事件。
  • 文件描述符超限:启动报required file descriptors number ... exceeds ...时,按错误提示提升上限(如ulimit -n或服务单元的LimitNOFILE)。
  • 事件定义文件格式:插件支持新版 perfmon 事件格式(v1.1.0 起),旧格式仍被接受但会在日志中打印警告,建议从 perfmon 仓库更新事件文件(见 插件 README 的 Changelog 与 intel_pmu.go 中DeprecatedFormatError处理逻辑)。

变更日志

版本说明
v1.0.0初始版本
v1.1.0支持新的 perfmon 事件格式(上游 perfmon 仓库 issue #22 引入);旧格式仍被接受,但会在日志中打印警告

相关资源

  • 插件完整文档与示例输出:插件 README
  • 可直接引用的最小可运行配置模板:sample.conf
  • 插件主实现(Init/Gather/Stop、文件描述符校验、指标发布):intel_pmu.go
  • 配置解析(事件/核心/socket ID 解析与去重):config.go
  • 事件解析与翻译(resolver):resolver.go
  • 事件激活与 perf group 逻辑:activators.go
  • 计数值读取与聚合(scaled 计算、aggregate_uncore_units 实现):reader.go
  • 单元测试(初始化链路、文件描述符校验等):intel_pmu_test.go
  • 插件注册入口(custom builder 场景下按需加载):plugins/inputs/all/intel_pmu.go
  • Telegraf 插件的通用全局配置(别名、标签/字段处理、插件排序等):CONFIGURATION.md

【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询