我正在开发一个 Linux 内核驱动程序,它为用户空间提供一块物理内存。我有驱动程序的工作版本,但目前速度很慢。所以,我退回了几步,尝试制作一个小巧、简单的驱动程序来重现问题。
我在启动时使用内核参数 memmap=2G$1G
保留内存.然后,在驱动程序的 __init
函数,我 ioremap
一些内存,并将其初始化为已知值。我也输入了一些代码来测量时间:
#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
这样做是一种糟糕的方式(正如 Ben 在下面建议的那样),我愿意接受其他建议,这些建议将使我能够获得任何可由硬件和软件直接访问的大块内存。我也可以使用较小的缓冲区。请参阅下面我的最终解决方案。
最佳答案
ioremap
分配不可缓存的页面,因为您希望访问内存映射 io 设备。那可以解释你表现不佳的原因。
您可能想要 kmalloc
或 vmalloc
. usual reference materials将解释每个的能力。
关于ioremap 后的内存访问非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4452400/