Macos “dtrace”如何探测内存分配(Mac OS)
是否有人知道Macos “dtrace”如何探测内存分配(Mac OS),macos,profiling,memory-profiling,dtrace,Macos,Profiling,Memory Profiling,Dtrace,是否有人知道dtrace用于跟踪mallocs的功能/机制?我正在尝试分析一段代码,我可以借助调试器和一些命令行脚本来完成,即: sudo dtrace -n "pid`pgrep Mail | head -n 1`::malloc:entry { @sizes=quantize(arg0); }" 给我一些类似的信息: dtrace: description 'pid31411::malloc:entry ' matched 4 probes ^C value ------
dtrace
用于跟踪malloc
s的功能/机制?我正在尝试分析一段代码,我可以借助调试器和一些命令行脚本来完成,即:
sudo dtrace -n "pid`pgrep Mail | head -n 1`::malloc:entry { @sizes=quantize(arg0); }"
给我一些类似的信息:
dtrace: description 'pid31411::malloc:entry ' matched 4 probes
^C
value ------------- Distribution ------------- count
-1 | 0
0 | 214
1 | 7
2 | 191
4 | 1054
8 |@@@@ 15992
16 |@@@@@@@@@@@@ 44569
32 |@@@@@@@@@@ 37003
64 |@@@@ 15426
128 |@@@@ 15695
256 |@ 2616
512 |@ 1967
1024 |@ 1891
2048 |@@ 6010
4096 | 523
8192 | 43
16384 | 110
32768 | 19
65536 | 0
131072 | 69
262144 | 0
但这对我来说真的很乏味。我想知道如何从代码内部以编程方式实现这一点。我认为您对问题的看法是错误的。您的示例显示了对进程和函数任意组合中的任意参数的相当复杂的解释—能够在一行中完成这项工作而不修改您自己的程序是非常强大的。试图让您自己的代码执行相同的分析是没有意义的:例如,如果您想要线性比例而不是对数比例,您会怎么做?是否也要重新实现lquantize() 专注于编写所需的代码,并让DTrace进行评测 编辑以响应第一条评论 您给出的示例的执行路径非常迂回。非常广泛地说,
dtrace(1)
请求内核修改malloc
的序言,以便在进入时,调用线程捕获dtrace内核模块。在那里,在将控制返回到插入指令的线程之前,数据在每个cpu缓冲区内聚合。每隔一段时间,dtrace
通过libdtrace
处理请求,通过ioctl(2)
处理内核每CPU缓冲区的快照。合并这些缓冲区,然后呈现您看到的图形也是由libdtrace
执行的函数。在macos上,包含与内核交换的记录格式的libdtrace
API是私有的。因此,即使是在简单的示例中重用这些基础设施,也将是“使用大锤敲开螺母”
进一步考虑的是,您将添加本身需要调试和维护的代码。如果你的代码足够复杂,它保证它自己的仪器,那么似乎有道理,有一天,你会想考虑<代码> CALLUNE()/<代码>,<代码> RealCube()/<代码>和<代码> MAMP()/<代码>。也许您还希望显式地包括或排除对这些函数的调用,这些调用不仅来自您自己的代码,也来自链接它的其他库
最后,最好将实现实际任务的代码与用于调试它的代码分开。一种示例方法是为
malloc()
编写您自己的、插入指令的包装器,并将其放入一个共享对象中,您可以在可执行文件和libc
之间进行插入。我认为您看待问题的方式是错误的。您的示例显示了对进程和函数任意组合中的任意参数的相当复杂的解释—能够在一行中完成这项工作而不修改您自己的程序是非常强大的。试图让您自己的代码执行相同的分析是没有意义的:例如,如果您想要线性比例而不是对数比例,您会怎么做?是否也要重新实现lquantize()
专注于编写所需的代码,并让DTrace进行评测
编辑以响应第一条评论
您给出的示例的执行路径非常迂回。非常广泛地说,dtrace(1)
请求内核修改malloc
的序言,以便在进入时,调用线程捕获dtrace内核模块。在那里,在将控制返回到插入指令的线程之前,数据在每个cpu缓冲区内聚合。每隔一段时间,dtrace
通过libdtrace
处理请求,通过ioctl(2)
处理内核每CPU缓冲区的快照。合并这些缓冲区,然后呈现您看到的图形也是由libdtrace
执行的函数。在macos上,包含与内核交换的记录格式的libdtrace
API是私有的。因此,即使是在简单的示例中重用这些基础设施,也将是“使用大锤敲开螺母”
进一步考虑的是,您将添加本身需要调试和维护的代码。如果你的代码足够复杂,它保证它自己的仪器,那么似乎有道理,有一天,你会想考虑<代码> CALLUNE()/<代码>,<代码> RealCube()/<代码>和<代码> MAMP()/<代码>。也许您还希望显式地包括或排除对这些函数的调用,这些调用不仅来自您自己的代码,也来自链接它的其他库
最后,最好将实现实际任务的代码与用于调试它的代码分开。一种示例方法是为
malloc()
编写自己的插入指令的包装器,并将其放在一个共享对象中,您可以在可执行文件和libc
之间插入该对象。pid提供程序使用类似于调试器断点的机制。Dtrace与调试器一样附加到进程。它在您的案例中查找malloc函数的第一条指令的地址,并在入口点插入陷阱指令。每当调用malloc时,trap指令都会触发到dtrace进程的控制传输,dtrace进程会将第一个参数的值保存到malloc的数据结构中,以供以后聚合,并根据ABI查找参数的值,最有可能的情况是在受控进程状态的特定寄存器中。Dtrace恢复在malloc入口被trap指令替换的指令的原始操作码,使受控进程(您的应用程序)在该指令上单步执行,并再次将其替换为trap