你的意思是让 perf 继续覆盖,而不是追加,所以你只有最后一秒?
一种方法是让您自己的程序管道perf stat -I1000进入自身(例如,通过 C stdiopopen或使用 POSIX pipe// dup2fork/exec)。然后,您可以实现选择将行写入文件的位置和方式的逻辑。您可以在每次写入之前查找输出文件的开头,而不仅仅是正常写入它们。或者pwrite不要write总是在文件位置 0 处写入。您可以附加一些空格以填充到固定宽度,以确保较长的行不会在文件中留下一些您没有覆盖的字符。(或ftruncate写入后的输出文件比前一行短)。
或者:perf stat -I 1000 >> file.log使用 O_APPEND 重定向,并定期截断长度。
为追加而打开的文件将自动写入当前结尾的任何位置,因此您可以perf ... -I 1000每秒或每 5 秒左右保持运行并截断文件。所以最多你有 5 行要通读,才能读到你真正想要的最后一行。如果system用于通过 shell 运行它,请使用>>. 或者使用open(O_APPEND)/dup2如果使用fork/ execve。
在循环中truncate()通过路径或ftruncate()打开 fd进行实际截断。sleep理想情况下,您会在即将编写新行之前截断,因此大多数时候都会有一行。但是除非您进行额外的系统调用,fstat否则inotify您将不知道何时确切地期待另一个系统调用,尽管航位推算并假设 sleep 睡眠时间最短可以正常工作。
或者:重定向perf stat -I 1000(不附加),并从父进程中查找它的 fd,以创建与通过在写入前查找的进程/线程进行管道相同的效果。
为什么分叉我的进程会导致文件被无限读取表明具有共享相同打开文件描述的文件描述符的父/子进程可以影响彼此的文件位置lseek。
这仅在您使用open/自己进行重定向时才有效dup2,而不是在您通过system. 您需要自己的描述符来引用相同的打开文件描述
不确定您是否可以lseek在子进程打开的同一个 fd 上玩技巧;在这种情况下,避免 O_APPEND 可以让您将写入位置设置为 0 而不会截断,因此下一次写入将覆盖内容。但这仅在您open///并且父进程中的 fd 的文件位置与子进程中的 fd 绑定时才有效dup2。forkexec
完全未经测试的例子
即使使用正确的标头,这实际上也可能无法编译,但希望能说明这个想法。
// must *not* use O_APPEND, otherwise file position is ignored for write.
int fd = open("system.log", O_WRONLY|O_CREAT|O_TRUNC, 0666);
if ((pid = fork()) != 0){
// parent
while(1) {
sleep(1);
lseek(fd, 0, SEEK_SET); // reset the position at which perf will do its next write
}
} else {
// child
dup2(fd, 1); // redirect stdout to the open file
// TODO: look up best practices for fork/exec, and error checking
execlp("sudo", "perf", "kvm", "stat", "-er10f4", "-a", "sleep", "1", NULL);
perror("execlp sudo perf failed");
}
请注意完全缺乏对返回值的错误检查。这更像是伪代码,即使它是用(希望)有效的 C 语法编写的。
顺便说一句,您可以将该管道减少为一个sed命令,仅sed -n 4p打印第 4 行而不是其他行。但是perf ... stat -I 1000不会浪费行,因此无需以这种方式过滤行号。