X86 使用gdb的计数机指令

X86 使用gdb的计数机指令,x86,gdb,trace,X86,Gdb,Trace,我需要根据x86机器指令计数估计程序中某个热点的确切起始位置(以便以后可以在某些模拟器/模拟器中运行)。有没有一种方法可以使用gdb计算断点前执行的机器指令数 当然,还有其他选择,我可以使用仿真/二进制指令插入工具(如Pin),并在计算指令时跟踪运行,但这需要在我工作的每个平台上安装此工具—并非总是可能的。我需要一些几乎可以在任何linux机器上使用的工具 使用gdb,我想也可以大步运行stepix,作为某种粗粒度搜索,直到我们到达断点,然后以降低的分辨率重复,但速度会非常慢。还有别的办法吗 试

我需要根据x86机器指令计数估计程序中某个热点的确切起始位置(以便以后可以在某些模拟器/模拟器中运行)。有没有一种方法可以使用gdb计算断点前执行的机器指令数

当然,还有其他选择,我可以使用仿真/二进制指令插入工具(如Pin),并在计算指令时跟踪运行,但这需要在我工作的每个平台上安装此工具—并非总是可能的。我需要一些几乎可以在任何linux机器上使用的工具

使用gdb,我想也可以大步运行
stepix
,作为某种粗粒度搜索,直到我们到达断点,然后以降低的分辨率重复,但速度会非常慢。还有别的办法吗

试试这个:

set pagination off
set $count = 0
while $pc != 0xyourstoppingaddress
  stepi
  set $count++
end
print $count

然后去喝杯咖啡。或者是一顿长长的午餐。

这实际上只是对Mark解决方案可用性的一点小小改进

我们可以定义一个函数
do\u count

define do_count
set $count=0
while ($pc != $arg0)
stepi
set $count=$count+1
end
print $count
end
然后可以重复使用此函数反复计算步骤数:

set pagination off
do_count 0xaddress1
do_count 0xaddress2

甚至可以将此定义放入主文件夹中的
.gdbinit
(在Linux上,在Windows上应称为
gdb.ini
),这样在gdb启动后它就会自动可用(使用
show user
查看是否加载了该函数)

如果您确实想要一个周期计数(可能是已知IPC指令计数的近似值),并且您在裸机ARM上运行,那么您可能能够读取周期计数器,请参阅示例


在您的场景中,我将尝试获取已用指令计数(自GDB 7.0起可用,并在以后改进):

  • 开始测量:
    记录btrace
    (或者
    记录完整的
    ,如果前者不可用)
  • 继续执行
    执行(直到出现断点,或使用
    next
    或其他命令单步执行)
  • 获取测量值:
    信息记录
  • 清除记录结果:
    记录停止
    (建议使用缓冲区,因为缓冲区大小有限)
  • 例如:

    (gdb) record btrace (gdb) frame #0 __sanitizer::InitTlsSize () at .../lib/sanitizer_common/sanitizer_linux_libcdep.cc:220 220 void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info"); (gdb) info record Active record target: record-btrace Recording format: Branch Trace Store. Buffer size: 64kB. Recorded 0 instructions in 0 functions (0 gaps) for thread 1 (Thread 0xf7c92300 (LWP 20579)). (gdb) next 226 ... (gdb) info record Active record target: record-btrace Recording format: Branch Trace Store. Buffer size: 64kB. Recorded 2859 instructions in 145 functions (0 gaps) for thread 1 (Thread 0xf7c92300 (LWP 20579)). (gdb)记录btrace (gdb)框架 #0\uuu sanitizer::InitTlsSize()位于…/lib/sanitizer\u common/sanitizer\u linux\u libcdep.cc:220 220 void*get_tls_static_info_ptr=dlsym(RTLD_NEXT,“\u dl_get_tls_static_info”); (gdb)信息记录 活动记录目标:记录btrace 记录格式:分支跟踪存储。 缓冲区大小:64kB。 在线程1(线程0xf7c92300(LWP 20579))的0个函数(0个间隙)中记录了0条指令。 (gdb)下一步 226 ... (gdb)信息记录 活动记录目标:记录btrace 记录格式:分支跟踪存储。 缓冲区大小:64kB。 在线程1(线程0xf7c92300(LWP 20579))的145个函数(0个间隙)中记录了2859条指令。 限制:

    • 记录缓冲区的大小有限(可通过
      set record btrace pt buffer size
      增加此大小。对于上述BTS格式,请参阅以了解其他类型)
    • 使用
      记录完整
      ,并非所有指令都能被捕获。值得注意的是,SSE和AVX指令不受支持,将导致gdb暂停执行
    • 记录每条指令(尤其是完整格式的指令)时会有一些开销。尽管它不应该像其他答案中描述的gdb步骤方法那样糟糕(每次都必须通过ptrace)

    GDB完全不适合用于此目的。使用类似的方法来精确测量应用程序的性能。不管怎样,只要有编辑器,你就应该在任何地方都有插装工具。@mfukar谢谢,但我不确定它在任何地方都像GDB一样容易获得。我也不会说GDB是完全不合适的,它似乎是一个非常简单的功能,因为它已经知道如何在机器上进行操作-它所需要的只是跟踪某个地方的指令计数。
    ptrace
    在调试器中运行程序会改变程序状态,这可能对性能至关重要(缓存状态、TLB未命中等)。在调试器中运行程序时得到的结果仅适用于这种情况。为什么要计算机器指令数?如果这是关于评测的,那么这不是一个非常有用的度量。@pentadecagon,就像我说的-我需要在模拟器中运行某个部分(例如gem5),它可以被触发以给定的指令计数开始回答不错,但是为什么要提到周期计数呢?这个问题是关于确切的指令数,IPC是可变的,这取决于许多微体系结构因素,包括来自其他内核的内存/缓存争用,因此对于相同的代码,它甚至不完全是可重复的。对于x86,这可能是真的,但如果您使用单个内核运行裸机ARM,它们将是相同的。这正是我需要解决的问题。如果您的ARM没有缓存或分支预测,可能是热的,也可能不是热的,并且没有来自DMA的可能争用,那么请确定。e、 g.Cortex-M3。但是更快的ARM CPU不一定是确定性的,因为缓存的局部性不同,不同的输入数据可能会产生不同的IPC。实际上,并非Cortex-M3上的所有指令都需要相同的周期(重新加载管道需要额外的分支成本),因此读取周期计时器仍然不能回答这里的问题。当我想等待segfault或程序中存在的任何其他信号时,如何使用它?@124312344123411234123尝试更改
    ,而$pc!=0xyourstoppingaddress
    而$pc!=0xyourstoppingaddress&$\u siginfo.si\u signo!=11
    运行循环,直到收到SIGSEGV。
    stepi
    命令将导致程序获得SIGTRAP信号(5),因此如果您想在SIGTRAP以外的任何信号上停止,请尝试
    while$pc!=0xyourstoppingaddress&&$\u siginfo.si\u signo==5
    当($pc!=$arg0)如此时,我们如何更改条件