gpt4 book ai didi

c - 在linux内核模块中寻找意外抢占的原因

转载 作者:太空狗 更新时间:2023-10-29 16:36:37 25 4
gpt4 key购买 nike

我有一个小的 linux 内核模块,它是目前还不存在的硬件设备驱动程序的原型(prototype)。代码需要从头到尾尽可能快地进行一小段计算,持续时间为几微秒。我正在尝试使用 ndelay() 调用来模拟计算,以衡量这是否可以通过 intel rdtscp 指令实现。我发现 99.9% 的时间它按预期运行,但 0.1% 的时间它有一个非常大的延迟,尽管在应该禁用中断的自旋锁内运行,但看起来好像其他东西正在抢占代码。这是使用 Ubuntu 64 位内核 (4.4.0-112) 运行的,没有额外的实时或低延迟补丁。

下面是一些复制此行为的示例代码。这是作为 /proc 文件系统条目的处理程序编写的,以便于测试,但我只展示了实际计算延迟的函数:

#define ITERATIONS 50000
#define SKIPITER 10
DEFINE_SPINLOCK(timer_lock);
static int timing_test_show(struct seq_file *m, void *v)
{
uint64_t i;
uint64_t first, start, stop, delta, max=0, min=1000000;
uint64_t avg_ticks;
uint32_t a, d, c;
unsigned long flags;
int above30k=0;

__asm__ volatile ("rdtscp" : "=a" (a), "=d" (d) : : "rcx");
first = a | (((uint64_t)d)<<32);
for (i=0; i<ITERATIONS; i++) {
spin_lock_irqsave(&timer_lock, flags);
__asm__ volatile ("rdtscp" : "=a" (a), "=d" (d) : : "rcx");
start = a | (((uint64_t)d)<<32);
ndelay(1000);
__asm__ volatile ("rdtscp" : "=a" (a), "=d" (d) : : "rcx");
stop = a | (((uint64_t)d)<<32);
spin_unlock_irqrestore(&timer_lock, flags);
if (i < SKIPITER) continue;
delta = stop-start;
if (delta < min) min = delta;
if (delta > max) max = delta;
if (delta > 30000) above30k++;
}
seq_printf(m, "min: %llu max: %llu above30k: %d\n", min, max, above30k);
avg_ticks = (stop - first) / ITERATIONS;
seq_printf(m, "Average total ticks/iteration: %llu\n", avg_ticks);
return 0;
}

然后如果我运行:

# cat /proc/timing_test
min: 4176 max: 58248 above30k: 56
Average total ticks/iteration: 4365

这是在 3.4 GHz sandy bridge 一代 Core i7 上。 TSC 的约 4200 个滴答声大约适合 1 微秒多一点的延迟。大约 0.1% 的时间我看到延迟比预期长 10 倍左右,在某些情况下,我看到的时间长达 120,000 次滴答。

这些延迟似乎太长,不可能是单个缓存未命中,即使对于 DRAM 也是如此。所以我认为它要么必须是几次缓存未命中,要么是另一个任务在我的临界区中间抢占了 CPU。我想了解造成这种情况的可能原因,看看我们是否可以消除它们,或者我们是否必须转向定制处理器/FPGA 解决方案。

我尝试过的事情:

  • 我考虑过这是否是缓存未命中造成的。我不认为可能是这种情况,因为我忽略了应该加载缓存的前几次迭代。我已经通过检查反汇编验证了在对 rdtscp 的两次调用之间没有内存操作,所以我认为唯一可能的缓存未命中是指令缓存。
  • 以防万一,我将 spin_lock 调用移到外循环周围。那么在第一次迭代之后就不可能有任何缓存未命中。然而,这使问题变得更糟
  • 我听说 SMM 中断是不可屏蔽的,而且大部分是透明的,可能会导致不需要的抢占。但是,您可以使用 rdmsrMSR_SMI_COUNT 上读取 SMI 中断计数。我尝试在之前和之后添加它,并且在我的代码执行时没有发生 SMM 中断。
  • 我知道 SMP 系统中也存在可能会中断的处理器间中断,但我查看了前后的/proc/interrupts,没有看到足够多的内容来解释这种行为。
  • 我不知道 ndelay() 是否考虑了可变时钟速度,但我认为 CPU 时钟仅变化 2 倍,因此这不应导致 >10 倍的变化。
  • 我使用 nopti 启动以禁用页表隔离以防出现问题。

最佳答案

我刚刚注意到的另一件事是,不清楚 ndelay() 的作用。也许您应该展示它,因为其中可能潜伏着不平凡的问题。

例如,我曾经观察到我的一段内核驱动程序代码在内部发生内存泄漏时仍然被抢占,所以一旦它达到某个水印限制,即使它禁用了中断,它也会被搁置.

关于c - 在linux内核模块中寻找意外抢占的原因,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48632626/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com