perf
架构图总览
Events
事件主要有哪些
hardware events:CPU performance monitoring counters
software events: 基于kernel counters的低水平事件,比如cpu迁移、minor faults、major faults等等
kernel tracepoint events:编码嵌入在内核中的内核级别静态测试点
User statically-defined tracing(USDT): 用户级别的静态测试点
Dynamic Traceing:动态软件测试点,可以在任何地方创建。内核态使用kprobes框架,用户态使用uprobes工具
Timed Profiling:perf-record -F Hz可以按照指定的频率进行监测,这个常被用于监测CPU使用率以及创建定时的中断事件
Hardware [Cache] Events:
CPU相关计数器
CPU周期、指令重试,内存间隔周期、L2CACHE miss等
These instrument low-level processor activity based on CPU performance counters.
For example, CPU cycles, instructions retired, memory stall cycles, level 2 cache misses, etc.
Some will be listed as Hardware Cache Events.
Software Events:
内核相关计数器
These are low level events based on kernel counters.
For example, CPU migrations, minor faults, major faults, etc.
Tracepoint Events:
内核ftrace框架相关,例如系统调用,TCP事件,文件系统IO事件,块设备事件等。
根据LIBRARY归类。如sock表示socket事件。
This are kernel-level events based on the ftrace framework. These tracepoints are placed in interesting and logical locations of the kernel, so that higher-level behavior can be easily traced.
For example, system calls, TCP events, file system I/O, disk I/O, etc.
These are grouped into libraries of tracepoints;
eg, "sock:" for socket events, "sched:" for CPU scheduler events.
Dynamic Tracing:
动态跟踪,可以在代码中的任何位置创建事件跟踪节点。很好很强大。
内核跟踪使用kprobe,user-level跟踪使用uprobe。
Software can be dynamically instrumented, creating events in any location.
For kernel software, this uses the kprobes framework.
For user-level software, uprobes.
Timed Profiling:
采样频度,按指定频率采样,被用于perf record。
Snapshots can be collected at an arbitrary frequency, using perf record -FHz.
This is commonly used for CPU usage profiling, and works by creating custom timed interrupt events.
PMU:
Most processors nowadays have special, on‐chip hardware that monitors micro architectural events like elapsed cycles, cache hits, cache miss etc.It is a subsystem which helps in analyzing how an application or operating systems are performing on the processor.
The Performance Monitoring Events can be broadly categorized in two types
• Hardware
Ex: CPU‐Cycles, Instructions, Cache References
• Software
Ex: Page Fault, Context Switch, etc
page fault
Linux 内核给每个进程都提供了一个独立的虚拟地址空间,并且这个地址空间是连续的。这样,进程就可以很方便地访问内存,更确切地说是访问虚拟内存。虚拟地址空间的内部又被分为内核空间和用户空间两部分。并不是所有的虚拟内存都会分配物理内存,只有那些实际使用的虚拟内存才分配物理内存,并且分配后的物理内存,是通过内存映射来管理的。
内存映射,其实就是将虚拟内存地址映射到物理内存地址。为了完成内存映射,内核为每个进程都维护了一张页表,记录虚拟地址与物理地址的映射关系。页表实际上存储在 CPU 的内存管理单元 MMU 中。而当进程访问的虚拟地址在页表中查不到时,系统会产生一个缺页异常,进入内核空间分配物理内存、更新进程页表,最后再返回用户空间,恢复进程的运行,这是一个次缺页异常(minor page fault)。minor page fault 也称为 soft page fault, 指需要访问的内存不在虚拟地址空间,但是在物理内存中,只需要MMU建立物理内存和虚拟地址空间的映射关系即可。
major page fault指需要访问的内存不在虚拟地址空间,也不在物理内存中,进入内核空间分配物理内存,更新进程页表,还需要swap从磁盘中读取数据换入物理内存中。
当进程访问它的虚拟地址空间中的PAGE时,如果这个PAGE目前还不在物理内存中,此时CPU是不能干活的,Linux会产生一个hard page fault中断。系统需要从慢速设备(如磁盘)将对应的数据PAGE读入物理内存,并建立物理内存地址与虚拟地址空间PAGE的映射关系。然后进程才能访问这部分虚拟地址空间的内存。
page fault 又分为几种,major page fault、 minor page fault、 invalid(segment fault)。
major page fault 也称为 hard page fault, 指需要访问的内存不在虚拟地址空间,也不在物理内存中,需要从慢速设备载入。从swap 回到物理内存也是 hard page fault。
minor page fault 也称为 soft page fault, 指需要访问的内存不在虚拟地址空间,但是在物理内存中,只需要MMU建立物理内存和虚拟地址空间的映射关系即可。
- 当一个进程在调用 malloc 获取虚拟空间地址后,首次访问该地址会发生一次soft page fault。
- 通常是多个进程访问同一个共享内存中的数据,可能某些进程还没有建立起映射关系,所以访问时会出现soft page fault
invalid fault 也称为 segment fault,指进程需要访问的内存地址不在它的虚拟地址空间范围内,属于越界访问,内核会报 segment fault错误。
linux内核映像文件分类
zImage
zImage是ARM Linux常用的一种压缩映像文件,不超过512KB。
bzImage
big zImage,和zImage一样都是gzip压缩的。
uImage
u-boot专用的映像文件,它是在zImage上加上一个长度为0x40的“头部”,包含了这个映像文件的类型、加载位置、生成时间、大小等信息。如果直接从zImage的0x40位置开始加载,其和zImage就没有区别。
vmlinuz
可引导、压缩的内核。“vm”代表“virtual memory”。Linux支持虚拟内存。vmlinuz是可执行的linux内核。
vmlinux
未压缩的linux内核,vmlinuz是vmlinux的压缩文件。
initrd-xxx.img
initrd是initial ramdisk的缩写,initrd一般被用来临时的引导硬件到实际内核vmlinuz能够接管并继续引导的状态
perf详解
1. 简介
perf工具是基于linux内核提供的perf_event接口工作的。
2. 命令行
root@ubuntu:~# perf -h
usage: perf [--version] [--help] [OPTIONS] COMMAND [ARGS]
The most commonly used perf commands are:
annotate Read perf.data (created by perf record) and display annotated code
archive Create archive with object files with build-ids found in perf.data file
bench General framework for benchmark suites
buildid-cache Manage build-id cache.
buildid-list List the buildids in a perf.data file
c2c Shared Data C2C/HITM Analyzer.
config Get and set variables in a configuration file.
data Data file related processing
diff Read perf.data files and display the differential profile
evlist List the event names in a perf.data file
ftrace simple wrapper for kernel's ftrace functionality
inject Filter to augment the events stream with additional information
kallsyms Searches running kernel for symbols
kmem Tool to trace/measure kernel memory properties
kvm Tool to trace/measure kvm guest os
list List all symbolic event types
lock Analyze lock events
mem Profile memory accesses
record Run a command and record its profile into perf.data
report Read perf.data (created by perf record) and display the profile
sched Tool to trace/measure scheduler properties (latencies)
script Read perf.data (created by perf record) and display trace output
stat Run a command and gather performance counter statistics
test Runs sanity tests.
timechart Tool to visualize total system behavior during a workload
top System profiling tool.
version display the version of perf binary
probe Define new dynamic tracepoints
trace strace inspired tool
See 'perf help COMMAND' for more information on a specific command.
annotate | perf annotate用于解析由perf record记录的数据文件perf.data并将代码注解显示。如果源代码开启了debug符号,则源码和汇编一起解析。如果源码未开启debug,则解析汇编代码 |
archive | 根据数据文件记录的build-id,将所有被采样到的elf文件打包。利用此压缩包,可以再任何机器上分析数据文件中记录的采样数据。 |
bench | perf中内置的benchmark。子系统:调度器和IPC机制、内存管理、NUMA调度、futex压力基准、epoll压力基准等 |
buildid-cache | 管理perf的buildid缓存,每个elf文件都有一个独一无二的buildid。buildid被perf用来关联性能数据与elf文件。 |
buildid-list | 列出perf.data文件中的buildid |
c2c | 用于调试cache to cache的false sharing问题,用于Shared Data C2C/HITM分析,可以追踪cacheline竞争问题 |
config | perf config用于读取和配置 .perfconfig配置文件 |
diff | 对比两个数据文件的差异。能够给出每个符号(函数)在热点分析上的具体差异。 |
evlist | 列出数据文件perf.data中所有性能事件 |
ftrace | 是内核ftrace功能的简化封装,可以跟踪指定进程的内核函数调用栈 |
inject | 该工具读取perf record工具记录的事件流,并将其定向到标准输出 |
kallsyms | 查找运行中的内核符号 |
kmem | 针对内核内存(slab)子系统进行追踪测量的工具 |
kvm | 用于测试kvm客户机的性能参数 |
list | 列出event事件 |
lock | 分析内核锁统计信息 |
mem | 测试内存存取性能数据 |
record | 运行一个命令,并将其数据保存到perf.data中。随后,可以使用perf report进行分析 |
report | 显示perf数据 |
sched | 分析调度器性能 |
script | 执行测试脚本 |
stat | perf stat能完整统计应用整个生命周期的信息 |
test | 用于sanity test |
timechart | 生成图标 |
top | 类似linux的top命令,查看整体性能 |
version | 查看版本信息 |
probe | 动态监测点 |
trace | 跟踪系统调用 |
annotate中文意思:
vi. 注释;给…作注释或评注
vt. 注释;作注解
perf annotate用于解析由perf record记录的数据文件perf.data并将代码注解显示。如果源代码开启了debug符号,则源码和汇编一起解析。如果源码未开启debug,则解析汇编代码。
Usage: perf annotate [<options>]
-C, --cpu <cpu> list of cpus to profile
-d, --dsos <dso[,dso...]>
only consider symbols in these dsos
-D, --dump-raw-trace dump raw trace in ASCII
-f, --force don't complain, do it
-i, --input <file> input file name
-k, --vmlinux <file> vmlinux pathname
-l, --print-line print matching source lines (may be slow)
-M, --disassembler-style <disassembler style>
Specify disassembler style (e.g. -M intel for intel syntax)
-m, --modules load module symbols - WARNING: use only with -k and LIVE kernel
-n, --show-nr-samples
Show a column with the number of samples
-P, --full-paths Don't shorten the displayed pathnames
-q, --quiet do now show any message
-s, --symbol <symbol>
symbol to annotate
-v, --verbose be more verbose (show symbol address, etc)
--asm-raw Display raw encoding of assembly instructions (default)
--group Show event group information together
--group Show event group information together
--gtk Use the GTK interface
--ignore-vmlinux don't load vmlinux even if found
--objdump <path> objdump binary to use for disassembly and annotations
--percent-type <local-period>
Set percent type local/global-period/hits
--show-total-period
Show a column with the sum of periods
--skip-missing Skip symbols that cannot be annotated
--source Interleave source code with assembly code (default)
--stdio Use the stdio interface
--stdio-color <mode>
'always' (default), 'never' or 'auto' only applicable to --stdio mode
--stdio2 Use the stdio interface
--symfs <directory>
Look for files with symbols relative to this directory
--tui Use the TUI interface
实验perf annotate -i perf.data -C0
,其结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EJinn4YB-1615448861782)(https://raw.githubusercontent.com/junixcn/images/master/image-20201209142209833.png)]
根据数据文件记录的build-id,将所有被采样到的elf文件打包。利用此压缩包,可以再任何机器上分析数据文件中记录的采样数据。
该命令需要perf buildid-list --with-hits配合使用。
perf archive [file]
没搞清楚是怎么用的,总是报错
https://linux-perf-users.vger.kernel.narkive.com/gjAAds7D/perf-archive-is-not-a-perf-command
照网上上面这个例子,给cflags加上buildid和fno-xxx参数,还是不行
root@ubuntu:test# make
gcc -g -Wl,--build-id -fno-omit-frame-pointer -o t1 test.c
root@ubuntu:test# perf record -e cpu-clock ./t1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.017 MB perf.data (207 samples) ]
root@ubuntu:test# perf buildid-list -i perf.data
8b5069415e14c65b746661feb0b23246a1d44ea7 [kernel.kallsyms]
e22e5fae1bd7e9508834fdfce490ba5b12f6bcf6 /root/test/t1
cbbbd6f042b731b98a8df7ecc2de408198cf3506 [vdso]
root@ubuntu:test# perf archive perf.data
perf: 'archive' is not a perf-command. See 'perf --help'.
root@ubuntu:test# perf archive
perf: 'archive' is not a perf-command. See 'perf --help'.
root@ubuntu:test# perf buildid-list -i perf.data -H
8b5069415e14c65b746661feb0b23246a1d44ea7 /proc/kcore
e22e5fae1bd7e9508834fdfce490ba5b12f6bcf6 /root/test/t1
除了调度器之外,很多时候人们都需要衡量自己的工作对系统性能的影响。benchmark 是衡量性能的标准方法,对于同一个目标,如果能够有一个大家都承认的 benchmark,将非常有助于”提高内核性能”这项工作
benchmark:基准测试
root@ubuntu:~# perf bench -h
# benchmark:基准
Usage: perf bench [<common options>] <collection> <benchmark> [<options>]
-f, --format <default|simple>
Specify the output formatting style
-r, --repeat <n> Specify amount of times to repeat the run
#使用方法
# perf bench [<common options>] <subsystem> <suite> [<options>]
# subsystem子系统包括有sched、mem、numa、futex、epoll以及all选项;
子系统 | 说明 |
---|---|
sched | 测试调度器和IPC机制 |
mem | 测试内存性能 |
numa | NUMA内存和调度 |
futex | futex压力测试 |
epoll | epoll压力测试 |
all | 所有benchmark子系统 |
-
sched message 是从经典的测试程序 hackbench 移植而来,用来衡量调度器的性能,overhead 以及可扩展性。该 benchmark 启动 N 个 reader/sender 进程或线程对,通过 IPC(socket 或者 pipe) 进行并发的读写。一般人们将 N 不断加大来衡量调度器的可扩展性。Sched message 的用法及用途和 hackbench 一样
-
sched pipe 从 Ingo Molnar 的 pipe-test-1m.c 移植而来。当初 Ingo 的原始程序是为了测试不同的调度器的性能和公平性的。其工作原理很简单,两个进程互相通过 pipe 拼命地发 1000000 个整数,进程 A 发给 B,同时 B 发给 A。。。因为 A 和 B 互相依赖,因此假如调度器不公平,对 A 比 B 好,那么 A 和 B 整体所需要的时间就会更长。
本地虚拟机和树莓派4B数据对比
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jALVFFZL-1615448861784)(https://raw.githubusercontent.com/junixcn/images/master/image-20201211155615950.png)]
这个是 perf bench 的作者 Hitoshi Mitake 自己写的一个执行 memcpy 的 benchmark。该测试衡量一个拷贝 1M 数据的 memcpy() 函数所花费的时间。我尚不明白该 benchmark 的使用场景。。。或许是一个例子,告诉人们如何利用 perf bench 框架开发更多的 benchmark 吧。
-
memcpy
用于评估简单的内存复制性能
-
memset
用于简单评估内存写性能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1oNY0eVZ-1615448861785)(https://raw.githubusercontent.com/junixcn/images/master/image-20201211162923972.png)]
NUMA(Non Uniform Memory Access)即非一致内存访问架构,市面上主要有X86_64(JASPER)和MIPS64(XLP)体系。
测试:
perf bench numa mem
NUMA架构介绍
1. SMP vs AMP
- SMP(Symmetric Multiprocessing), 即对称多处理器架构,是目前最常见的多处理器计算机架构。
- AMP(Asymmetric Multiprocessing), 即非对称多处理器架构,则是与SMP相对的概念。
那么两者之间的主要区别是什么呢? 总结下来有这么几点,
- SMP的多个处理器都是同构的,使用相同架构的CPU;而AMP的多个处理器则可能是异构的。
- SMP的多个处理器共享同一内存地址空间;而AMP的每个处理器则拥有自己独立的地址空间。
- SMP的多个处理器操通常共享一个操作系统的实例;而AMP的每个处理器可以有或者没有运行操作系统, 运行操作系统的CPU也是在运行多个独立的实例。
- SMP的多处理器之间可以通过共享内存来协同通信;而AMP则需要提供一种处理器间的通信机制。
现今主流的x86多处理器服务器都是SMP架构的, 而很多嵌入式系统则是AMP架构的
2. NUMA vs UMA
NUMA(Non-Uniform Memory Access) 非均匀内存访问架构是指多处理器系统中,内存的访问时间是依赖于处理器和内存之间的相对位置的。 这种设计里存在和处理器相对近的内存,通常被称作本地内存;还有和处理器相对远的内存, 通常被称为非本地内存。
UMA(Uniform Memory Access) 均匀内存访问架构则是与NUMA相反,所以处理器对共享内存的访问距离和时间是相同的。
由此可知,不论是NUMA还是UMA都是SMP架构的一种设计和实现上的选择。
阅读文档时,也常常能看到ccNUMA(Cache Coherent NUMA),即缓存一致性NUMA架构。 这种架构主要是在NUMA架构之上保证了多处理器之间的缓存一致性。降低了系统程序的编写难度。
x86多处理器发展历史上,早期的多核和多处理器系统都是UMA架构的。这种架构下, 多个CPU通过同一个北桥(North Bridge)芯片与内存链接。北桥芯片里集成了内存控制器(Memory Controller),
参考:https://houmin.cc/posts/b893097a/
Futex 是Fast Userspace muTexes的缩写。
Futex按英文翻译过来就是快速用户空间互斥体。其设计思想其实 不难理解,在传统的Unix系统中,System V IPC(inter process communication),如 semaphores, msgqueues, sockets还有文件锁机制(flock())等进程间同步机制都是对一个内核对象操作来完成的,这个内核对象对要同步的进程都是可见的,其提供了共享 的状态信息和原子操作。当进程间要同步的时候必须要通过系统调用(如semop())在内核中完成。可是经研究发现,很多同步是无竞争的,即某个进程进入 互斥区,到再从某个互斥区出来这段时间,常常是没有进程也要进这个互斥区或者请求同一同步变量的。但是在这种情况下,这个进程也要陷入内核去看看有没有人 和它竞争,退出的时侯还要陷入内核去看看有没有进程等待在同一同步变量上。这些不必要的系统调用(或者说内核陷入)造成了大量的性能开销。为了解决这个问 题,Futex就应运而生,Futex是一种用户态和内核态混合的同步机制。首先,同步的进程间通过mmap共享一段内存,futex变量就位于这段共享 的内存中且操作是原子的,当进程尝试进入互斥区或者退出互斥区的时候,先去查看共享内存中的futex变量,如果没有竞争发生,则只修改futex,而不 用再执行系统调用了。当通过访问futex变量告诉进程有竞争发生,则还是得执行系统调用去完成相应的处理(wait 或者 wake up)。简单的说,futex就是通过在用户态的检查,(motivation)如果了解到没有竞争就不用陷入内核了,大大提高了low-contention时候的效率。 Linux从2.5.7开始支持Futex。
Futex是一种用户态和内核态混合机制,所以需要两个部分合作完成,linux上提供了sys_futex系统调用,对进程竞争情况下的同步处理提供支持。
所有的futex同步操作都应该从用户空间开始,首先创建一个futex同步变量,也就是位于共享内存的一个整型计数器。
当进程尝试持有锁或者要进入互斥区的时候,对futex执行"down"操作,即原子性的给futex同步变量减1。如果同步变量变为0,则没有竞争发生, 进程照常执行。
如果同步变量是个负数,则意味着有竞争发生,需要调用futex系统调用的futex_wait操作休眠当前进程。
当进程释放锁或 者要离开互斥区的时候,对futex进行"up"操作,即原子性的给futex同步变量加1。如果同步变量由0变成1,则没有竞争发生,进程照常执行。
如果加之前同步变量是负数,则意味着有竞争发生,需要调用futex系统调用的futex_wake操作唤醒一个或者多个等待进程。
hash | 评估哈希表性能 |
wake | Suite for evaluating wake calls |
wake-parallel | Suite for evaluating p |