我正在开发一个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/秒的运行。为什么这么慢?
这是Fedora 13上的内核2.6.34,它是一个x86_64系统。
编辑:
该方案的目标是获取一块物理内存,并将其提供给PCI设备(通过内存的总线/物理地址)和用户空间应用程序(通过调用mmap,由驱动程序支持)。然后PCI设备将不断地用数据填充这个内存,用户空间应用程序将把它读出来。如果ioremap不是这样做的好方法(如本在下面所建议的那样),我愿意接受其他建议,这些建议将允许我获得任何可以通过硬件和软件直接访问的内存块。我可能也可以用一个更小的缓冲区。
见下面我的最终解决方案。
发布于 2010-12-15 20:27:17
ioremap分配不可缓存的页面,就像您希望访问内存映射的io设备一样。那就能解释你的糟糕表现了。
你可能想要kmalloc或vmalloc。平日 参考文献 材料将解释每个功能。
发布于 2010-12-15 17:48:47
我不认为ioremap()是你想要的。您应该只使用readb、readl、writeb、memcpy_toio等访问结果(您称之为“readl”)。甚至不能保证返回实际上是映射的(尽管它显然在您的平台上)。我猜想该区域正在被映射为未被映射(适用于IO寄存器),从而导致了糟糕的性能。
发布于 2012-03-29 13:36:58
已经有一段时间了,但我一直在更新,因为我最终找到了解决这个ioremap问题的方法。
由于我们有自定义硬件直接写入内存,因此标记它可能更正确,但速度慢得令人无法忍受,而且不适合我们的应用程序。我们的解决方案是,一旦有足够的新数据来填充我们架构上的整个缓存行(我认为是256字节),我们就只能从该内存(一个环形缓冲区)中读取数据。这保证了我们永远不会得到过时的数据,而且速度很快。
https://stackoverflow.com/questions/4452400
复制相似问题