我正在尝试在我正在测试的PostgreSQL构建中跟踪一些幻像I/O. 它是一个多进程服务器,将磁盘I/O关联回特定的后端和查询并不简单.
我认为Linux的perf工具对此非常理想,但我正在努力捕获块I/O性能计数器指标并将它们与用户空间活动相关联.
通过以下方式记录块I/O请求和完成很容易:
sudo perf record -g -T -u postgres -e 'block:block_rq_*'
Run Code Online (Sandbox Code Playgroud)
并且记录了用户空间pid,但是没有捕获内核或用户空间堆栈,或者能够对用户空间进程堆的快照位(例如,查询文本)等进行快照.所以当你有pid时,你就不会我知道那个过程在那一点上做了什么.只是perf script输出,如:
postgres 7462 [002] 301125.113632: block:block_rq_issue: 8,0 W 0 () 208078848 + 1024 [postgres]
Run Code Online (Sandbox Code Playgroud)
如果我向其添加-g标志,perf record则会获取内核堆栈的快照,但不会捕获内核中捕获的perf事件的用户空间状态.用户空间堆只上升到从用户空间,如入口点LWLockRelease,LWLockAcquire,memcpy(mmap'd IO),__GI___libc_write等
所以.有小费吗?能够捕获用户空间堆栈的快照以响应内核事件将是理想的.
我在Fedora 19,3.11.3-201.fc19.x86_64,Schrödinger的Cat,使用perf版本3.10.9-200.fc19.x86_64.
我试图了解如何衡量性能并决定编写非常简单的程序:
section .text
global _start
_start:
mov rax, 60
syscall
Run Code Online (Sandbox Code Playgroud)
我用perf stat ./bin 这个程序运行我感到惊讶的stalled-cycles-frontend是太高了.
0.038132 task-clock (msec) # 0.148 CPUs utilized
0 context-switches # 0.000 K/sec
0 cpu-migrations # 0.000 K/sec
2 page-faults # 0.052 M/sec
107,386 cycles # 2.816 GHz
81,229 stalled-cycles-frontend # 75.64% frontend cycles idle
47,654 instructions # 0.44 insn per cycle
# 1.70 stalled cycles per insn
8,601 branches # 225.559 M/sec
929 branch-misses # 10.80% of all branches
0.000256994 seconds time elapsed …Run Code Online (Sandbox Code Playgroud) 我试图想出一个具有高缓存未命中率的示例程序.我想我可以尝试逐列访问矩阵,如下所示:
#include <stdlib.h>
int main(void)
{
int i, j, k;
int w = 1000;
int h = 1000;
int **block = malloc(w * sizeof(int*));
for (i = 0; i < w; i++) {
block[i] = malloc(h * sizeof(int));
}
for (k = 0; k < 10; k++) {
for (i = 0; i < w; i++) {
for (j = 0; j < h; j++) {
block[j][i] = 0;
}
}
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我使用-O0flag 编译它并使用perf …
摘要:perf lock配置文件pthread_mutex?
细节:
该工具perf有一个选项perf lock.手册页说:
You can analyze various lock behaviours and statistics with this perf lock command.
'perf lock record <command>' records lock events
between start and end <command>. And this command
produces the file "perf.data" which contains tracing
results of lock events.
'perf lock trace' shows raw lock events.
'perf lock report' reports statistical data.
Run Code Online (Sandbox Code Playgroud)
但是当我试着跑步时,perf lock record我得到一个错误说:invalid or unsupported event: 'lock:lock_acquire'.我看了,似乎错误可能是因为我的内核没有编译CONFIG_LOCKDEP或CONFIG_LOCK_STAT. …
我想计算某些代码的(或多或少)确切数量的指令.此外,我希望在通过特定数量的指令后收到信号.
为此,我使用perf_event_open提供的溢出信号行为 .
我正在使用manpage建议实现溢出信号的第二种方式:
信号溢出
可以设置事件以在超过阈值时传递信号.使用poll(2),select(2),epoll(2)和fcntl(2),系统调用来设置信号处理程序.
[...]
另一种方法是使用PERF_EVENT_IOC_REFRESH ioctl.这个ioctl增加了一个计数器,每次事件溢出时减少.当非零时,溢出时发送POLL_IN信号,但一旦值达到0,就会发送类型为POLL_HUP的信号,并禁用基础事件.
PERF_EVENT_IOC_REFRESH ioctl的进一步说明:
PERF_EVENT_IOC_REFRESH
非继承溢出计数器可以使用它来为参数指定的多个溢出启用计数器,之后禁用它.此ioctl的后续调用将参数值添加到当前计数.设置POLL_IN的信号将在每次溢出时发生,直到计数达到0; 当发生这种情况时,发送设置了POLL_HUP的信号并禁用该事件.使用0的参数被视为未定义的行为.
一个非常小的例子看起来像这样:
#define _GNU_SOURCE 1
#include <asm/unistd.h>
#include <fcntl.h>
#include <linux/perf_event.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long perf_event_open(struct perf_event_attr* event_attr, pid_t pid, int cpu, int group_fd, unsigned long flags)
{
return syscall(__NR_perf_event_open, event_attr, pid, cpu, group_fd, flags);
}
static void perf_event_handler(int signum, siginfo_t* info, void* ucontext) {
if(info->si_code != POLL_HUP) {
// Only POLL_HUP should happen.
exit(EXIT_FAILURE);
}
ioctl(info->si_fd, PERF_EVENT_IOC_REFRESH, 1); …Run Code Online (Sandbox Code Playgroud) 我试图在一个过程中获得单个功能的性能。我怎样才能使用 perf 工具做到这一点?有没有其他工具可以做到这一点?
例如,假设 main 函数调用函数 A 、 B 、 C 。我想分别获得主要功能以及功能 A、B、C 的性能。
是否有一个很好的文档来低估 perf 源代码?
谢谢你。
我已经使用Linux perf一段时间来进行应用程序分析.通常情况下,配置文件应用程序相当复杂,因此只要根据第一原则与您的预期没有任何严重差异,就可以简单地将报告的计数器值视为面值.
然而,最近,我已经描述了一些简单的64位汇编程序 - 足够的竞争,人们几乎可以计算各种计数器的预期值,而且似乎perf stat是过度计算.
以下面的循环为例:
.loop:
nop
dec rax
nop
jne .loop
Run Code Online (Sandbox Code Playgroud)
这将简单地循环n次数,其中n是初始值rax.循环的每次迭代都执行4条指令,因此您可以期望4 * n执行指令,加上一些用于进程启动和终止的固定开销,以及n在进入循环之前设置的一小段代码.
这是(典型)perf stat输出n = 1,000,000,000:
~/dev/perf-test$ perf stat ./perf-test-nop 1
Performance counter stats for './perf-test-nop 1':
301.795151 task-clock (msec) # 0.998 CPUs utilized
0 context-switches # 0.000 K/sec
0 cpu-migrations # 0.000 K/sec
2 page-faults # 0.007 K/sec
1,003,144,430 cycles # 3.324 GHz
4,000,410,032 instructions …Run Code Online (Sandbox Code Playgroud) 我试图在Docker容器中使用perf工具来记录给定的命令.
kernel.perf_event_paranoid设置为1,但是当我没有放置--privileged标志时,容器的行为就像2那样.
我可以使用--privileged,但是我运行perf的代码不受信任,如果我通过允许perf工具承担轻微的安全风险,那么在容器上给予特权权限似乎是不同的风险级别.
有没有其他方法在容器内使用perf?
~$ docker version
Client:
Version: 17.03.1-ce
API version: 1.27
Go version: go1.7.5
Git commit: 7392c3b/17.03.1-ce
Built: Tue May 30 17:59:44 2017
OS/Arch: linux/amd64
Server:
Version: 17.03.1-ce
API version: 1.27 (minimum version 1.12)
Go version: go1.7.5
Git commit: 7392c3b/17.03.1-ce
Built: Tue May 30 17:59:44 2017
OS/Arch: linux/amd64
Experimental: false
~$ cat /proc/sys/kernel/perf_event_paranoid
1
~$ perf record ./my-executable
perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error 1 (Operation not permitted)
perf_event_open(..., 0) failed unexpectedly with error 1 (Operation not permitted) …Run Code Online (Sandbox Code Playgroud) 我试图了解linux perf,发现一些非常令人困惑的行为:
我写了一个简单的多线程示例,其中一个线程固定到每个核心; 每个线程在本地运行计算,并且不相互通信(见test.cc下文).我在想这个例子应该有非常低的(如果不是零)上下文切换.但是,使用linux perf来分析示例显示了数千个上下文切换 - 远远超出了我的预期.我进一步分析了linux命令sleep 20以进行比较,显示更少的上下文切换.
此个人资料结果对我没有任何意义.什么导致如此多的上下文切换?
> sudo perf stat -e sched:sched_switch ./test
Performance counter stats for './test':
6,725 sched:sched_switch
20.835 seconds time elapsed
> sudo perf stat -e sched:sched_switch sleep 20
Performance counter stats for 'sleep 20':
1 sched:sched_switch
20.001 seconds time elapsed
Run Code Online (Sandbox Code Playgroud)
要重现结果,请运行以下代码:
perf stat -e context-switches sleep 20
perf stat -e context-switches ./test
Run Code Online (Sandbox Code Playgroud)
要编译源代码,请输入以下代码:
g++ -std=c++11 -pthread -o test test.cc
Run Code Online (Sandbox Code Playgroud)
// test.cc
#include <iostream>
#include <thread>
#include <vector> …Run Code Online (Sandbox Code Playgroud) for (int i = 0; i < 100000; ++i) {
int *page = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
page[0] = 0;
munmap(page, PAGE_SIZE);
}
Run Code Online (Sandbox Code Playgroud)
我期望在用户空间中获得~100000 dTLB-store-miss,每次迭代一次(同样~100000页错误和内核的dTLB-load-miss).运行以下命令,结果大约是我期望的2倍.如果有人能澄清为什么会这样,我将不胜感激:
perf stat -e dTLB-store-misses:u ./test
Performance counter stats for './test':
200,114 dTLB-store-misses
0.213379649 seconds time elapsed
Run Code Online (Sandbox Code Playgroud)
PS我已经验证并确定生成的代码没有引入任何可以证明这个结果的东西.此外,我确实得到~100000页错误和dTLB加载未命中:k.