关于系统调用的性能报告
perf report about system call
我对进程 A、B 的性能报告(关于 malloc)有以下输出:
记录者:perf record -e cycles:u
进程A:
0.00% 1833448 Test-Recv libc-2.17.so [.] malloc
0.00% 1833385 Test-Recv [kernel.kallsyms] [k] system_call
0.00% 916588 Test-Recv libc-2.17.so [.] _int_malloc
以及流程 B 的以下内容:
24.90% 10855848444 test.exe libc-2.17.so [.] _int_malloc
15.78% 6881565672 test.exe libc-2.17.so [.] _int_free
7.48% 3261672221 test.exe libc-2.17.so [.] malloc
4.66% 2030332370 test.exe libc-2.17.so [.] systrim.isra.2
2.43% 1061251259 test.exe libc-2.17.so [.] free
2.12% 925588492 test.exe test.exe [.] main
他们都在源代码中做了一些malloc
我可以假设在进程 A 的情况下,malloc 确实发生系统调用,
但是在进程B的情况下,没有系统调用发生,因为在
Process B perf report ,根本没有[k]system_call!!!
是的,似乎有道理。可能进程 B 从内核中获得了一些内存,然后能够满足其从空闲列表中分配的所有内存。即,空闲列表从来没有变得足够大(或者过于分散),以至于 glibc 的 malloc
实现无法决定将任何页面还给内核。
这一切都归结为分配/释放模式,以及映射的大小。对于大型 malloc
请求,glibc 直接使用 mmap(MAP_ANONYMOUS)
,因此它可以 munmap
它在 free
.
您不会通过使用采样获得某些程序调用的所有函数,您将获得一些调用的函数,即事件被采样最多的函数,"cycles:u" 您将在用户 space 中获取 "hottest" 函数(无内核函数)。
考虑使用跟踪而不是采样,例如:'perf trace workload'。考虑使用回溯,例如,查看 'brk' 系统调用的回溯 'ls' 我们可以获得:
# perf trace -e brk --call-graph dwarf ls
0.933 (0.009 ms): ls brk(brk: 0x5577c4683000) = 0x5577c4683000
__brk (/usr/lib64/libc-2.26.so)
__GI___sbrk (inlined)
__GI___default_morecore (inlined)
sysmalloc (/usr/lib64/libc-2.26.so)
_int_malloc (/usr/lib64/libc-2.26.so)
tcache_init.part.5 (/usr/lib64/libc-2.26.so)
__GI___libc_malloc (inlined)
__GI___strdup (inlined)
[0xffff80aa65b9ae49] (/usr/lib64/libselinux.so.1)
[0xffff80aa65b9af0e] (/usr/lib64/libselinux.so.1)
call_init.part.0 (/usr/lib64/ld-2.26.so)
_dl_init (/usr/lib64/ld-2.26.so)
_dl_start_user (/usr/lib64/ld-2.26.so)
这表明系统调用在这种情况下被调用,以响应调用 malloc() 的 strdup(),最终通过 'brk' 调用向内核内核请求更多内存。
再玩 'perf trace' 一些,您会发现类似于 'strace' 提供的统计数据,例如,程序调用 brk 和其他系统调用的次数。
我对进程 A、B 的性能报告(关于 malloc)有以下输出:
记录者:perf record -e cycles:u
进程A:
0.00% 1833448 Test-Recv libc-2.17.so [.] malloc
0.00% 1833385 Test-Recv [kernel.kallsyms] [k] system_call
0.00% 916588 Test-Recv libc-2.17.so [.] _int_malloc
以及流程 B 的以下内容:
24.90% 10855848444 test.exe libc-2.17.so [.] _int_malloc
15.78% 6881565672 test.exe libc-2.17.so [.] _int_free
7.48% 3261672221 test.exe libc-2.17.so [.] malloc
4.66% 2030332370 test.exe libc-2.17.so [.] systrim.isra.2
2.43% 1061251259 test.exe libc-2.17.so [.] free
2.12% 925588492 test.exe test.exe [.] main
他们都在源代码中做了一些malloc
我可以假设在进程 A 的情况下,malloc 确实发生系统调用, 但是在进程B的情况下,没有系统调用发生,因为在 Process B perf report ,根本没有[k]system_call!!!
是的,似乎有道理。可能进程 B 从内核中获得了一些内存,然后能够满足其从空闲列表中分配的所有内存。即,空闲列表从来没有变得足够大(或者过于分散),以至于 glibc 的 malloc
实现无法决定将任何页面还给内核。
这一切都归结为分配/释放模式,以及映射的大小。对于大型 malloc
请求,glibc 直接使用 mmap(MAP_ANONYMOUS)
,因此它可以 munmap
它在 free
.
您不会通过使用采样获得某些程序调用的所有函数,您将获得一些调用的函数,即事件被采样最多的函数,"cycles:u" 您将在用户 space 中获取 "hottest" 函数(无内核函数)。
考虑使用跟踪而不是采样,例如:'perf trace workload'。考虑使用回溯,例如,查看 'brk' 系统调用的回溯 'ls' 我们可以获得:
# perf trace -e brk --call-graph dwarf ls
0.933 (0.009 ms): ls brk(brk: 0x5577c4683000) = 0x5577c4683000
__brk (/usr/lib64/libc-2.26.so)
__GI___sbrk (inlined)
__GI___default_morecore (inlined)
sysmalloc (/usr/lib64/libc-2.26.so)
_int_malloc (/usr/lib64/libc-2.26.so)
tcache_init.part.5 (/usr/lib64/libc-2.26.so)
__GI___libc_malloc (inlined)
__GI___strdup (inlined)
[0xffff80aa65b9ae49] (/usr/lib64/libselinux.so.1)
[0xffff80aa65b9af0e] (/usr/lib64/libselinux.so.1)
call_init.part.0 (/usr/lib64/ld-2.26.so)
_dl_init (/usr/lib64/ld-2.26.so)
_dl_start_user (/usr/lib64/ld-2.26.so)
这表明系统调用在这种情况下被调用,以响应调用 malloc() 的 strdup(),最终通过 'brk' 调用向内核内核请求更多内存。
再玩 'perf trace' 一些,您会发现类似于 'strace' 提供的统计数据,例如,程序调用 brk 和其他系统调用的次数。