x86 架构提供了硬件一小步陷阱进行调试。它对程序的运行速度有多大影响?
假设,Linux 内核函数只用于单步执行某个进程,那么该进程的运行速度会慢多少?有人能给出准确的估计吗?
在花了一周时间追踪线程错误后,我开始思考这个问题。如果这些错误可以重现就好了。如果可以实现一个功能,按顺序执行两个线程,以可预测的方式交替执行一个线程上的指令和另一个线程上的指令,那会怎么样?我正在考虑一个伪随机数生成器,它会生成一串位 - 0 表示在线程 1 上执行指令,1 表示在线程 2 上执行指令。
然后,您可以为 PRNG 设定种子,并获得可重现的指令交错。不同的 PRNG 种子会产生不同的交错模式。您可以在一组 PRNG 种子下运行测试用例,如果发现一个触发故障的种子,请重现它。
有人听说过类似的事情吗?
更新:
该怎么办呢?
假设我们在 Core i5 之类的处理器上运行,其中有 4 个处理器状态和 2 个内核。我们使用单步陷阱将进程从其用户空间弹回到其内核空间。所以这是两个状态,对吧?然后我们让另一个线程在另一个内核上运行,其用户空间和内核空间状态,对吧?有一个类似自旋锁(可能是两个自旋锁)的东西来同步这两个内核线程。每个线程都自旋锁定,而另一个线程则在其用户空间执行几个指令,然后它们同步并交换角色。
听起来我们拥有的线程和核心数量恰到好处,可以让所有东西都装在芯片上。但它的运行速度有多快?
我们可以尝试一下。有人可以编写一些内核代码。或者也许有人知道。
这些新芯片有这么多花哨的功能。我会印象深刻,如果它跑得快,我也不会完全感到惊讶。
答案1
单步陷阱的工作原理是,在每条指令完成后引发异常。该陷阱的通常用途是,调试器会捕获此异常,并允许您在“单步执行”下一条指令之前查看周围情况。
如果您打算这样做以进行跟踪,详细记录代码正在执行的操作,则跟踪器/调试器将作为异常处理程序被调用,记录您想要记录的任何内容,然后忽略异常 - 重复。我预计这会将您正在跟踪的代码的执行速度降低一到几百倍……至少。
关于您关于交错多个线程的指令的想法,这不是解决序列化问题的方法。您需要在设计中解决它(可证明)。
答案2
您的方法似乎很有用,我也考虑过类似的问题。
该怎么做?(还有一些替代方法,包括静态分析、反射和协程)。
但是,如果你随机跨过多个指令(甚至可能跨过许多指令,这似乎也是很自然的事情):
1) 在开始序列之前确定下一个指令序列的随机长度。使用反汇编程序并将int 3在序列的末尾,而不是单步执行。
2)如果你不想使用int 3由于某种原因或不完全信任反汇编程序,您可以使用单步执行,然后将执行的指令复制到新的内存区域。
现在,下次随机生成器决定从相同的程序位置开始执行相同数量的连续步骤时,只需跳转到包含复制指令的新内存区域并在那里运行直到该序列结束,而无需单步执行。在指令序列结束时,您需要回调到您的调试框架。
对于这两种方法,您都需要为调用、跳转和条件跳转添加特殊处理。