首页 文章

ioremap之后的内存访问非常慢

提问于
浏览
3

我正在开发一个Linux内核驱动程序,它可以为用户空间提供一大块物理内存 . 我有一个工作版本的驱动程序,但它目前非常慢 . 所以,我已经退回了几步,尝试制作一个小而简单的驱动程序来重现问题 .

我使用内核参数 memmap=2G$1G 在启动时保留内存 . 然后,在驱动程序的 __init 函数中,我将一些内存初始化为已知值 . 我还提供了一些代码来测量时序:

#define RESERVED_REGION_SIZE    (1 * 1024 * 1024 * 1024)   // 1GB
#define RESERVED_REGION_OFFSET  (1 * 1024 * 1024 * 1024)   // 1GB

static int __init memdrv_init(void)
{
    struct timeval t1, t2;
    printk(KERN_INFO "[memdriver] init\n");

    // Remap reserved physical memory (that we grabbed at boot time)
    do_gettimeofday( &t1 );
    reservedBlock = ioremap( RESERVED_REGION_OFFSET, RESERVED_REGION_SIZE );
    do_gettimeofday( &t2 );
    printk( KERN_ERR "[memdriver] ioremap() took %d usec\n", usec_diff( &t2, &t1 ) );

    // Set the memory to a known value
    do_gettimeofday( &t1 );
    memset( reservedBlock, 0xAB, RESERVED_REGION_SIZE );
    do_gettimeofday( &t2 );
    printk( KERN_ERR "[memdriver] memset() took %d usec\n", usec_diff( &t2, &t1 ) );

    // Register the character device
    ...

    return 0;
}

我加载驱动程序,并检查dmesg . 它报告:

[memdriver] init
[memdriver] ioremap() took 76268 usec
[memdriver] memset() took 12622779 usec

这是memset的12.6秒 . 这意味着memset在 81 MB/sec 运行 . 为什么它这么慢?

这是Fedora 13上的内核2.6.34,它是一个x86_64系统 .

编辑:

此方案背后的目标是获取一大块物理内存并使其可用于PCI设备(通过内存的总线/物理地址)和用户空间应用程序(通过调用 mmap ,由驱动程序支持) . 然后,PCI设备将不断用数据填充此内存,用户空间应用程序将读取它 . 如果 ioremap 是一个不好的方法(如下面Ben所建议的那样),我允许我获得可由硬件和软件直接访问的任何大块内存 . 我也可以使用更小的缓冲区 .


请参阅下面的最终解决方案 .

4 回答

  • 1

    ioremap 分配不可缓存的页面,因为您需要访问内存映射的io设备 . 这可以解释你的糟糕表现 .

    你可能想要 kmallocvmalloc . usual reference materials将解释每个人的能力 .

  • 4

    我不认为 ioremap() 是你想要的 . 您应该只使用 readbreadlwritebmemcpy_toio 等访问结果(您称之为 reservedBlock ) . 甚至不能保证返回虚拟映射(尽管它显然在您的平台上) . 我猜这个区域被映射为未缓存(适用于IO寄存器),导致可怕的性能 .

  • 1

    已经有一段时间了,但我正在更新,因为我最终找到了这个ioremap问题的解决方法 .

    由于我们将自定义硬件直接写入内存,因此将其标记为不可缓存可能更为正确,但它无法忍受缓慢且无法用于我们的应用程序 . 我们的解决方案是只有在有足够的新数据填充我们架构上的整个缓存行时才读取该内存(环形缓冲区)(我认为这是256字节) . 这保证了我们从来没有过时的数据,而且速度非常快 .

  • 2

    我试过用 memmap 做一个巨大的内存块保留

    这个块的 ioremap ping给了我一个映射的内存地址空间,超过几个tera字节 .

    当您要求从64 GB开始保留128GB内存时 . 你在/ proc / vmallocinfo中看到以下内容

    0xffffc9001f3a8000-0xffffc9201f3a9000 137438957568 0xffffffffa00831c9 phys=1000000000 ioremap
    

    因此地址空间从0xffffc9001f3a8000开始(这太大了) .

    其次,你的观察是正确的 . 甚至 memset_io 导致触摸所有这些内存的极大延迟(几十分钟) .

    因此,所花费的时间主要是地址空间转换和非可缓存页面加载 .

相关问题