[sched BUG] 引入 GNU time 测试多核调度性能的时候 panic

背景:

GNU time 的基本功能

  • 测量程序执行时间和系统资源使用情况
  • 提供比 shell 内建 time 更详细的统计信息

考虑引入GNU time 来对内核调度子系统的性能进行测试,方便实现 PELT 跨核负载均衡。

预期效果:


实际执行的时候发生了Panic,原因是 preempt_count > 0

具体复现方法:

  1. 在 DragonOS 中通过 dadk 引入GNU time
{
  "name": "gnu time",
  "version": "1.9",
  "description": "gnu time",
  "rust_target": null,
  "task_type": {
    "BuildFromSource": {
      "Archive": {
        "url": "https://ftp.gnu.org/gnu/time/time-1.9.tar.gz"
      }
    }
  },
  "depends": [],
  "build": {
    "build_command": "./configure CC=x86_64-linux-musl-gcc CFLAGS=-static && make -j $(nproc) && DESTDIR=$DADK_CURRENT_BUILD_DIR make install"
  },
  "clean": {
    "clean_command": "make clean"
  },
  "install": {
    "in_dragonos_path": "/"
  },

  "build_once": true,

  "install_once": true,
  "target_arch": ["x86_64"]
}
  1. 编译启动后,执行 time ls,或者其他自定义的测试程序/指令
  2. 触发 panic:
e[41m[ ERROR ] e[0m(src/lib.rs:117)	 Kernel Panic Occurred.
Location:
	File: src/sched/mod.rs
	Line: 823, Column: 5
Message:
	assertion `left == right` failed
  left: 1
 right: 0

由于 preempt_count 相关的上下文无法通过 log 打印日志debug,暂时无法定位问题出在哪里,或许需要比较熟悉调度的同学一起看一下

1 个赞

由于 锁追踪 相关的 lockdep 是一个比较复杂的内核模块,并没有成熟的可移植的针对内核的工具(至少我目前了解到的情况),所以我采取修改 GNU time 源码通过打日志的方式来排查是哪一步触发了 panic 。据目前的排查情况来看,问题有可能出现在 signal 这一块。见下图:


圈出来的部分,如果该函数中有四个 signal 函数调用,如果不注释掉前面两个调用,程序无法执行到打印日志 “signal” 就 panic 了,注释掉之后,又会在后面的 signal 调用中触发 panic 而不会打印出 “signal 2”。

试了一下,发现好像是父进程在等待子进程终止这个过程结束的时候,获取的rd_children没有drop掉


drop掉之后得到下面的结果

1 个赞

这个问题是因为子进程 do_execve() 的时候需要加载可执行文件,但是 ls 并不在当前的 /bin 目录下,而是在 /usr/local/bin/ls,所以发生了非法的访问

目前在注释掉 do_wait() 中的一行 unsafe { ProcessManager::release(*pid) }; (否则执行完release函数后发生了一个很奇怪的阻塞)后, time 基本可以正常使用。
注释后:


注释前:

相关日志代码片段:

// 截取自 do_wait()
if state.is_exited() {
                    kwo.ret_status = state.exit_code().unwrap() as i32;
                    log::debug!("Child process {:?} has exited with status: {}", pid, kwo.ret_status);
                    drop(pcb);
                    log::debug!("Dropped PCB");
                    unsafe { ProcessManager::release(*pid) };
                    log::debug!("Released process");
                    drop(irq_guard);
                    log::debug!("Dropped IRQ guard");
                    log::debug!("do_wait return");
                    return Ok((*pid).into());
                }
pub unsafe fn release(pid: Pid) {
        let pcb = ProcessManager::find(pid);
        if pcb.is_some() {
            log::debug!("have find {:?}, ready to release", pid);
            // let pcb = pcb.unwrap();
            // 判断该pcb是否在全局没有任何引用
            // TODO: 当前,pcb的Arc指针存在泄露问题,引用计数不正确,打算在接下来实现debug专用的Arc,方便调试,然后解决这个bug。
            //          因此目前暂时注释掉,使得能跑
            // if Arc::strong_count(&pcb) <= 2 {
            //     drop(pcb);
            //     ALL_PROCESS.lock().as_mut().unwrap().remove(&pid);
            // } else {
            //     // 如果不为1就panic
            //     let msg = format!("pcb '{:?}' is still referenced, strong count={}",pcb.pid(),  Arc::strong_count(&pcb));
            //     error!("{}", msg);
            //     panic!()
            // }

            log::debug!("ready to remove process {:?} from ALL_PROCESS", pid);
            ALL_PROCESS.lock_irqsave().as_mut().unwrap().remove(&pid);
            log::debug!("has remove process {:?} from ALL_PROCESS", pid);
        } else {
            log::debug!("didn't find {:?}", pid);
        }
    }

time 主要关注执行的总时间,无法直接提供关于进程在哪些核心上运行的信息。因此,单独使用 time 无法精确地测试进程是否进行了跨核调度。它只能给出整体的执行时间,而无法揭示进程在各个 CPU 核心之间的调度过程。

如果目标是测试进程的执行时间,并且关心的是跨核调度对总执行时间的影响(例如,通过增加多核间的迁移或缓存失效),time 可以提供一些线索,但它不会告诉我们跨核调度是否发生。我们需要通过其他方法来更好地控制和观察这一过程,例如:

  • 使用 taskset:指定进程运行在哪些核心上,这样可以排除跨核调度对性能的影响,或强制进程跨核运行来测试其影响。
  • 监控工具:使用诸如 tophtopperf 等工具来观察进程是否被调度到多个核心。

所以如果要测试多核调度性能或许需要内核先支持 CPU 亲和性并实现 sched_setaffinity 系统调用,从而为 taskset 的引入提供支持
【任务发布】实现 sched_setaffinity 系统调用 和 CPU 亲和性 · Issue #1035 · DragonOS-Community/DragonOS

另外, 虽然 timetaskset 可以给出基本的性能指标,但它们没有办法提供多核负载均衡的详细分析。

而支持 tophtop 则需要先支持通过 /proc 文件系统来访问进程信息(如 /proc/[pid]/stat)和系统资源使用情况(如 /proc/meminfo/proc/stat);perf 需要内核的 perf_events 子系统支持。
【任务发布】支持通过 /proc 来访问进程信息和系统资源使用情况 · Issue #1036 · DragonOS-Community/DragonOS

1 个赞

问题: