当前位置:嗨网首页>书籍在线阅读

09-rr调试器简介

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

17.2 rr调试器简介

除了GDB和LLDB之外,rr是另一款功能强大的调试器,它在调试因存在非确定性而难以调试的多线程代码时效果特别好。通常,在调试多线程代码时,其中某段代码出现bug,但后续在程序执行时调试会话却难以重现。

195.png 注意

由于多线程代码而产生的错误也被称为heisenbug。

rr 调试器可以为非确定的多线程代码执行可重现的调试会话。它通过记录调试会话来完成此操作,用户可以重播并逐步跟踪来查找问题。它会将程序的跟踪保存到磁盘,其中包含重现程序执行所需的所有信息。

rr调试器的一个不足之处在于,目前它仅为Linux和Intel CPU提供了支持。要在Ubuntu 16.04上设置rr调试器,我们需要下载最新的deb软件包。撰写本文时,rr调试器的版本是5.2.0。下载了deb软件包之后,我们可以通过运行如下代码来安装rr调试器:

sudo dpkg -i
https://github.com/mozilla/rr/releases/download/5.2.0/rr-5.2.0-Linux-x86_64
.deb

注意,上述操作的一个先决条件是已经安装了相关的性能工具。你可以按照如下方式安装它们:

sudo apt-get install linux-tools-4.15.0-43-generic

可以根据需要,将 linux-tools-(版本号)中的版本号替换成与用户本机适配的内核版本号。在Linux上可以使用uname-a命令获取系统内核的版本号。另一个先决条件是将perf_ event_paranoid中的sysctl标志的值由3设置为−1。建议你通过运行如下代码进行临时设置:

sudo sysctl -w kernel.perf_event_paranoid=-1

完成上述配置后,让我们通过运行cargo new rr_demo快速创建一个新项目,并通过rr调试器执行一次调试会话。我们将探讨如何通过rr调试器调试存在非确定性的示例程序。同时会用到rand程序库,因此我们可以通过运行cargo add rand命令将对rand程序库的引用添加到Cargo.toml文件中。我们的main.rs文件包含如下代码:

// rr_demo/src/main.rs
use rand::prelude::*;
use std::thread;
use std::time::Duration;
fn main() {
    for i in 0..10 {
        thread::spawn(move || {
            let mut rng = rand::thread_rng();
            let y: f64 = rng.gen();
            let a: u64 = rand::thread_rng().gen_range(0, 100);
            thread::sleep(Duration::from_millis(a));
            print!("{} ", i);
        });
    }
    thread::sleep(Duration::from_millis(1000));
    println!("Hello, world!");
}

这是一个最简单的存在非确定性的示例程序,它生成10个线程并将它们输出到stdout。为了突出rr调试器的可重现特性,我们将生成线程并随即休眠。

首先,我们需要用rr调试器记录程序的执行。这是通过运行以下代码完成的:

rr record target/debug/rr_demo

上述操作的输出结果如下所示:

196.png 在我的计算机上,这会跟踪记录程序执行的过程并将其存储到如下位置:

rr: Saving execution to trace directory
`/home/creativcoder/.local/share/rr/rr_demo-15`

记录文件rr_demo-15可能会以别的名称存储在你的计算机上。我们现在可以通过运行如下代码重现被录制的程序:

rr replay -d rust-gdb /home/creativcoder/.local/share/rr/rr_demo-15

以下是在rr调试器下运行的GDB会话:

197.png 如你所见,程序每次都会输出相同的数字序列,因为程序是根据上一次运行中记录的会话执行的。这有助于调试多线程程序,由于其中的线程是无序执行的,因此下一次运行程序时可能无法重现该bug。