Linux内核作为一种广泛使用的开源操作系统内核,在多种硬件和设备上运行,提供了强大的功能和灵活的配置选项。然而,随着技术的发展和应用需求的增加,内核中出现的不确定行为也日益成为开发者和系统管理员关注的焦点。这些不确定行为包括/不限于锁竞争、中断处理延迟和服务例程的不可预测性,它们可能导致性能瓶颈、响应时间延迟甚至系统不稳定。持续发现以及消除这些不确定行为对于提高Linux操作系统的实时性和稳定性有着重要意义。
导致Linux内核的非确定行为的主要因素
导致Linux内核非确定行为的主要因素包括并不限于:锁竞争、中断处理、服务调度等。
-
锁竞争
锁竞争主要发生在多线程环境中,多个进程或线程尝试同时访问共享资源。在Linux内核中,锁机制(如自旋锁、读写锁、互斥锁等)是管理对共享资源访问的主要手段,如果出现锁竞争,会导致关键任务在获取共享资源之前出现长时间停顿。
-
中断处理
中断处理是操作系统中的一个基本功能,用于响应外部事件。当中断发生时,关键任务的正常运行会被打断,直到中断服务完成,才会恢复正常运行。
- 服务调度
Linux操作系统中存在一些具有高优先级的服务进程需要定期执行。例如Linux的Read Copy Update(RCU)模块的内核服务进程需要定期检查系统的宽限期,以及对RCU的回调进行处理。这些服务进程的执行会和用户的任务抢占CPU资源。
不确定行为的发现
Linux内核不确定行为可以采用ftrace内核跟踪工具进行跟踪。Linux内核的ftrace(Function Tracer)是一个强大的内核跟踪工具,它主要用于分析和监测内核中函数调用和事件的发生。ftrace的工作原理基于内核预留的跟踪点。在内核编译过程中,编译器会在每个函数的入口插入一个nop操作,这些nop操作可以在运行时被替换为跳转到ftrace的处理函数。当ftrace被启用时,这些nop会被替换为调用ftrace的代码,从而记录函数的调用信息。
图1 ftrace的工作原理
Linux ftrace的详细使用方法可见[1]。
例如,笔者想要监控Linux内核非确定行为对dpdk程序运行的干扰,使用了如下步骤进行配置:
echo 2 > /sys/kernel/debug/tracing/tracing_cpumask
echo 1 > /sys/kernel/debug/tracing/tracing_on
echo function > /sys/kernel/debug/tracing/current_tracer
echo "sched:sched_switch sched:sched_wakeup" >> /sys/kernel/debug/tracing/set_event
cat /sys/kernel/debug/tracing/trace > trace.txt
得到如下日志
图2 ftrace对dpdk进程的监控
由上图可见,dpdk的转发进程lcore-worker在第129.378929秒被操作系统进程调度机制切换出去,而接下来在CPU 1上运行的进程是ksoftirqd。
消除不确定行为的方法
为了减少锁竞争,可以采取以下措施:引入更细粒度的锁,通过降低锁的覆盖范围,减少锁的争用,从而提高系统的并行性。优化锁的类型,根据不同的使用场景选择合适的锁类型。例如,对于读多写少的资源,采用读写锁可能更合适。锁消除和锁降级,在确定某些代码路径线程安全时,可以移除不必要的锁,同时,可以将独占锁降级为共享锁。
为减轻中断对Linux内核不确定性的影响,可以采用中断亲和性(affinity):将中断处理过程绑定到特定的CPU,这可以减少CPU间的上下文切换。也可以采用中断线程化,将中断处理的某些过程的优先级降低。
为减轻服务调度对Linux内核不确定性的影响,可以通过优先级调度实现更细致的优先级分级系统,确保关键任务优先执行。也可采用负载均衡,在多处理器系统中,合理分配任务负载,以避免某一处理器过载而其他处理器空闲。
结论
持续消除Linux内核中的不确定行为需要系统的方法和持续的努力。通过优化锁机制、中断处理和服务调度,不仅可以提高系统的性能,还可以提高系统的稳定性和预测性。以后也可探索进一步的优化技术,例如引入更智能的调度算法和自适应锁策略,以应对不断增长的系统复杂性和多样性的挑战。
参考资料
[1] https://www.kernel.org/doc/html/v4.17/trace/ftrace.html