Linux驱动程序开发:如何调查copy_to_user()时序?

时间:2013-12-04 01:27:31

标签: linux linux-kernel linux-device-driver

我正在开发一个Linux驱动程序,并且在某些情况下发现copy_to_user()需要比预期更长的时间。我猜它可能正在等待mm->mmap_sem semaphore,也许?在不利的情况下,似乎还有额外的CPU活动。

对于如何进一步调查此问题和/或该怎么做,我将不胜感激。

更多细节:

该平台有一个 I7 ,其中2个物理内核运行在2.5GHz, 32位X86 构建 Linux 2.6.32 。驱动程序通过 PCI Express 接受数据,并通过字符设备将其提供给用户空间。测试过程以高优先级运行,读入我认为被调入的缓冲区。目标是支持相当高的数据速率,目前几百兆比特每秒,最终约1Gbps,持续至少几秒钟。

我的测试涉及在一秒左右读取 25MB 的数据。使用正确的数据集,驱动程序可以 100Mbps 400Mbps 可靠地接收。由于 100Mbps 数据略有不同,它偶尔会失败。驱动程序和测试工具都不关心数据的内容,所以我希望它没有任何区别。到达时间和突发性可能存在统计差异,但在阅读时间戳列表时没有什么能够突出显示。

问题的直接原因是接收缓冲区溢出(大约1MB)。这是因为过程阅读速度太慢,而这又是copy_to_user()花费很长时间的结果。副本通常传输几百个字节。通过良好的 100Mbps 输入,此功能可以合理快速地返回,通常在微秒级下通过循环计数判断。对于有问题的 100Mbps 数据,一些调用需要长达10毫秒,这可能会发生多次,而不仅仅是一次性。

I7Z 工具(link here)表示CPU活动的差异。处理好的100Mbps数据时,一个核心大部分时间都处于电源状态C1,另一个核心主要处于C6(低功耗)。对于错误的数据,一个核心主要位于C0(最活跃的状态),另一个核心可以在C1中花费0到70%的时间,其余大部分位于C6 }。所以看起来它正在进行正常处理以及许多额外的C0。也许很多人在旋转?

驱动程序和测试工具相关部分的伪代码摘要:

pseudo_interrupt_handler()
{
        if(DMA finished) {
                advance head;
                wake_up_interruptible();
        }
        if(new data && no DMA in progress) {
                start DMA into head;
        }
}

pseudo_file_read(filp, user buf, size)
{
        wait_event_interruptible(head != tail);

        while(head != tail && space in user buf) {
                copy_to_user(from tail);
                advance tail;
        }
        return total copied;
}

pseudo_test_process()
{
        buffer = malloc(25MB);
        write to each page in buffer; // page in

        while(buffer not full) {
                read(STDIN_FILENO, position in buffer, 4000B);
                advance position in buffer
        }
}

目前我没有令人满意的解决方法。我可以在驱动程序中缓冲更多数据,但这只会有助于暂时延迟。这个问题似乎会使系统性地降低速度并限制整体数据速率。如果没有其他解决方案,那么mmap是可能的,但这需要对现有应用软件进行大量更改。

更新(1月)。谢谢你的建议。我现在正在解决缓冲区的一些扩大和重组问题。我们现在使用较少数量的较大copy_to_user()操作,因此一小部分较慢的操作影响较小。

更新(六月)。正如所建议的那样,我已经实现了一个mmap()接口,它确实可以避免这个问题。不再有copy_to_user()瓶颈。

1 个答案:

答案 0 :(得分:0)

copy_to_user()和copy_from_user()总是涉及复制数据,这本质上是一个缓慢的过程(当然,取决于观点)。为获得最佳性能, only 方式为'mmap'。请参阅以下摘录here

  

内存映射是在用户和内核空间之间传输数据的唯一方法,不涉及显式复制,是处理大量数据的最快方法。