ARM A7 PMU+perf简单记录
关键词:pmu,perf等等。
简单记录PMU及其内核驱动,内核中perf相关内容,以及两者是如何关联的。然后记录perf应用是如何和PMU硬件关联的,以及如何使用perf查看PMU结果。
A7 PMU概要
PMU作为一个扩展功能,是一种非侵入式的调试组件。
对PMU寄存器的访问可以通过CP15协处理器指令和Memory-Mapped地址。
更详细内容参考:
《Arm CoreSight Performance Monitoring Unit Architecture》:关于PMU架构介绍,包括寄存器解释、规格、安全等等。
《ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition》:介绍了PMU在Armv7-A/R中的实现。
《Chapter C12 The Performance Monitors Extension》:PMU基本功能介绍
《Appendix D2 Recommended Memory-mapped and External Debug Interfaces for the Performance Monitors》:PMU寄存器介绍。
kernel PMU
Linux内核中已经集成了PMU代码,需要配置的是dts部分:
pmu-a7 { compatible = "arm,cortex-a7-pmu"; interrupts = <GIC_SPI 12 (IRQ_TYPE_LEVEL_HIGH)>; interrupt-patent = <&gic>; }
PMU默认使用CP15寄存器即可进行配置,还提供了Memory-Mapped方式。
这里主要配置了中断号。
arm_pmu_hp_init()注册CPU HogPlug时online和offline回调函数。
arm_pmu_hp_init ->cpuhp_setup_state_multi ->arm_perf_starting_cpu ->arm_perf_teardown_cpu
armv7 pmu驱动根据dts compatile匹配到对应的函数初始化struct armpmu结构体,并从dts中获取中断并注册。
然后对接perf,提供相关初始化函数。
armv7_pmu_driver(builtin_platfrom_driver) ->armv7_pmu_device_probe ->arm_pmu_device_probe ->armpmu_alloc ->__armpmu_alloc--分配struct pmu结构体,并给相关的处理函数赋值。 ->pmu_parse_irqs ->platform_get_irq--从dts中获取中断号。 ->__platform_get_irq ->of_irq_get ->of_irq_parse_one ->of_irq_parse_raw ->request_irq ->request_threaded_irq ->__setup_irq ->__irq_set_trigger ->gic_set_type--irq-gic.c中chip->irq_set_type,型号为GIC400。 ->gic_configure_irq
->of_id->data--根据“arm,cortex-a7-pmu”指向armv7_a7_pmu_init,对struct arm_pmu进行初始化。
->armv7_a7_pmu_init--“arm,cortex-a7-pmu”对应的初始化函数。
->armv7pmu_init--给struct arm_pmu结构体函数赋值。
->armv7_read_num_pmnc_events--读取PMCR寄存器,获取PMU支持的事件数量。
->armpmu_request_irqs ->armpmu_request_irq--注册pmu中断处理函数armpmu_dispatch_irq()。 ->armpmu_register ->cpu_pmu_init ->cpuhp_state_add_instance ->cpu_pm_pmu_register ->perf_pmu_register--和perf工具相关的初始化,包括一些函数指针初始化。 ->perf_pmu_register ->armv7_pmu_of_device_ids--支持的dts compatible列表。
kernel perf
perf的sw/hw等事件注册初始化。
start_kernel ->perf_event_init ->idr_init ->perf_event_init_all_cpus ->perf_pmu_register(perf_swevent/perf_cpu_clock/perf_task_clock) ->perf_tp_register ->perf_event_init_cpu
->perf_swevent_init_cpu ->register_reboot_notifier--注册reboot回调函数。 ->init_hw_breakpoint--perf使用断点初始化。
内核提供系统调用perf_event_open()返回CPU+PID组合的文件句柄,应用通过此句柄设置刚兴趣的事件。
在kernel/events/core.c中:
/** * sys_perf_event_open - open a performance event, associate it to a task/cpu * * @attr_uptr: event_id type attributes for monitoring/sampling * @pid: target pid * @cpu: target cpu * @group_fd: group leader event fd */ SYSCALL_DEFINE5(perf_event_open, struct perf_event_attr __user *, attr_uptr, pid_t, pid, int, cpu, int, group_fd, unsigned long, flags) { }
perf文件操作函数集是perf_fops:
static const struct file_operations perf_fops = { .llseek = no_llseek, .release = perf_release, .read = perf_read,--读取结果。 .poll = perf_poll, .unlocked_ioctl = perf_ioctl,--对event进行配置。 .compat_ioctl = perf_compat_ioctl, .mmap = perf_mmap, .fasync = perf_fasync,-- };
perf
perf命令源码位于内核tools/perf中,有多个子命令组成,下面以perf list hw为例,简单看一下是如何和PMU关联的。
main ->commands ->cmd_list(list) ->print_symbol_events--perf list hw命令对应函数。
->is_event_supported
->evsel__new
->evsel__open
->perf_event_open
->sys_perf_event_open--对应内核的perf_event_open系统调用。 ->cmd_record(record)
PMU+perf使用
perf list hw查看A7支持的PMU事件,在armv7_pmuv2_event_attrs中包含30个events:
armv7cortex_a7/br_immed_retired armv7_cortex_a7/br_mis_pred/ armv7_cortex_a7/br_pred/ armv7_cortex_a7/br_return_retired/ armv7_cortex_a7/bus_access/ armv7_cortex_a7/bus_cycles/ armv7_cortex_a7/cid_write_retired/ armv7_cortex_a7/cpu_cycles/ armv7_cortex_a7/exc_return/ armv7_cortex_a7/exc_taken/ armv7_cortex_a7/inst_retired/ armv7_cortex_a7/inst_spec/ armv7_cortex_a7/l1d_cache/ armv7_cortex_a7/l1d_cache_refill/ armv7_cortex_a7/l1d_cache_wb/ armv7_cortex_a7/l1d_tlb_refill/ armv7_cortex_a7/l1i_cache/ armv7_cortex_a7/l1i_cache_refill/ armv7_cortex_a7/lli_tlb_refill/ armv7_cortex_a7/12d_cache/ armv7_cortex_a7/l1d_cache_refill/ armv7_cortex_a7/12d_cache_wb/ armv7_cortex_a7/ld_retired/ armv7_cortex_a7/mem_access/ armv7_cortex_a7/memory_error/ armv7_cortex_a7/pc_write_retired/ armv7_cortex_a7/st_retired/ armv7_cortex_a7/sw_incr/ armv7_cortex_a7/ttbr_write_retired/ armv7_cortex_a7/unaligned_ldst_retired/
如果想查看某一程序执行时PMU事件,比如bus-cycles:
perf stat -e bus-cycles xxx