我使用 C 来制作 apache 模块,我使用 strace 作为调试时序的主要工具。这是我拼凑的代码。如果变量名称不符合标准,我深表歉意。
#include <stdio.h>
int main(){
long ct2,ct; //counters
int a=0; //dummy value
FILE *f0=fopen("/","r"); //measuring point
ct2=10;
while (--ct2>0){
ct=5000000;
while (--ct>0){
if (!!a){
printf("%d",a);
}
}
}
FILE *f=fopen("/","r"); //measuring point
ct2=10;
while (--ct2>0){
ct=5000000;
while (--ct>0){
if (a){
printf("%d",a);
}
}
}
FILE *f2=fopen("/","r"); //measuring point
return 0;
}
这段代码编译通过。然后我通过 strace 运行它(通过在终端中输入:strace -r -ttt ./a.out
),我看到:
0.000000 execve("./a.out", ["./a.out"], [/* 47 vars */]) = 0
0.000315 brk(0) = 0x804a000
0.000124 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
0.000144 open("/etc/ld.so.cache", O_RDONLY) = 3
0.000116 fstat64(3, {st_mode=S_IFREG|0644, st_size=139721, ...}) = 0
0.000138 mmap2(NULL, 139721, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7ece000
0.000114 close(3) = 0
0.000109 open("/lib/libc.so.6", O_RDONLY) = 3
0.000113 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\360d\1"..., 512) = 512
0.000130 fstat64(3, {st_mode=S_IFREG|0755, st_size=1575187, ...}) = 0
0.000131 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7ecd000
0.000122 mmap2(NULL, 1357360, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7d81000
0.000119 mmap2(0xb7ec7000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x146) = 0xb7ec7000
0.000146 mmap2(0xb7eca000, 9776, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7eca000
0.000139 close(3) = 0
0.000112 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7d80000
0.000119 set_thread_area({entry_number:-1 -> 6, base_addr:0xb7d806c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
0.000217 mprotect(0xb7ec7000, 4096, PROT_READ) = 0
0.000108 munmap(0xb7ece000, 139721) = 0
0.000174 brk(0) = 0x804a000
0.000099 brk(0x806b000) = 0x806b000
0.000110 open("/", O_RDONLY) = 3
0.203487 open("/", O_RDONLY) = 4
0.202225 open("/", O_RDONLY) = 5
0.000133 exit_group(0) = ?
我可以在结尾处立即断定:
0.000110 open("/", O_RDONLY) = 3
0.203487 open("/", O_RDONLY) = 4
0.202225 open("/", O_RDONLY) = 5
回到我设置的三个测量点。
我希望能够在我的代码中调整测量点线,这样当我运行 strace 时,我可以像现在一样找到我的测量点,但系统在这些地方进行的操作不那么密集。除了文件调用之外,我没有从 strace 中看到与我的程序相关的任何其他内容。
我在想,如果 C 语言中有一个内置的 MeasureMe 函数这样的东西,我可以用它来代替我代码中的测量点线,那么 strace 可以输出:
0.000110 MeasureMe called in code
0.203487 MeasureMe called in code
0.202225 MeasureMe called in code
我可以用 Strace 解决这个问题吗?
我询问 strace 而不是 gdb 的原因是因为我用它来调试对我的 apache 服务器的请求,就像这个视频中的人那样,我将能够看到 apache 模块的运行:
https://www.youtube.com/watch?v=eF-p--AH37E
知道如何解决这个问题吗?还是我必须继续尝试打开不存在的文件失败?
最佳答案
我了解到您当前使用的是 open("/",O_RDONLY)
[或 open("/i_do_not_exist",O_RDONLY)
] 作为“跟踪点” .不幸的是,因为您使用的是 strace
,所以您只能使用系统调用。但是, 有一种方法可以达到您想要的效果。
对于在源代码中的不同位置手动插入的跟踪点,您需要/想要的是:
- 任何不会损害任何东西的独特系统调用
- 很容易与真实代码区分开来[即使是可能返回错误的代码,例如打开文件或使用
access
检查是否存在] - 最小开销/最快执行
实际上,dup
在一个坏的 fildes 上很好地填补了账单:
dup(-10000);
它将返回 EBADF
。它作为跟踪点很容易区分,因为大多数“错误”的真实 dup
调用将是 dup(-1)
您可以根据需要拥有任意数量的这些。实际参数变为“跟踪点编号”:
dup(-10001); // tracepoint 1
...
dup(-10002); // tracepoint 2
...
dup(-10003); // tracepoint 3
输出如下:
0.000044 dup(-10001) = -1 EBADF (Bad file descriptor)
0.000022 dup(-10002) = -1 EBADF (Bad file descriptor)
0.000019 dup(-10003) = -1 EBADF (Bad file descriptor)
我通常将它封装在一个宏中:
#ifdef DEBUG
#define TRACEPOINT(_tno) tracepoint(_tno)
#else
#define TRACEPOINT(_tno) /**/
#endif
void
tracepoint(int tno)
{
dup(-10000 - tno);
}
然后,我添加如下内容:
TRACEPOINT(1); // initialization phase
...
TRACEPOINT(2); // execution phase
...
TRACEPOINT(3); // cleanup/shutdown
现在,我将编写一个 perl
或 python
脚本来读取源文件,提取给定跟踪点的注释,并将它们附加到匹配行在 strace
输出文件中:
0.000044 TRACEPOINT(1) initialization phase
0.000022 TRACEPOINT(2) execution phase
0.000019 TRACEPOINT(3) cleanup/shutdown
后处理脚本的更复杂版本可以做各种各样的事情:
- 跟踪时间戳并将一个跟踪点与前一个跟踪点之间的时间差附加到跟踪线
- 在跟踪点行中添加文件名和行号信息
- 跟踪给定跟踪点被击中的次数[类似于
gdb
和断点] - 生成与跟踪点相关的摘要报告
关于c - 生成漂亮的和/或更少的系统密集型测量点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35529144/