【问题标题】:mmap slower than ioremapmmap 比 ioremap 慢
【发布时间】:2012-06-11 08:09:56
【问题描述】:

我正在为运行 Linux 2.6.37 的 ARM 设备进行开发。我正在尝试尽快切换 IO 引脚。我做了一个小内核模块和一个用户空间应用程序。我尝试了两件事:

  1. 使用ioremap直接从内核空间操作GPIO控制寄存器。
  2. mmap() GPIO 控制寄存器,无需从用户空间缓存和使用它们。

两种方法都有效,但第二种方法比第一种方法慢约 3 倍(在示波器上观察)。我想我禁用了所有缓存机制。

当然,我希望获得两全其美:从用户空间开发的灵活性和易用性以及内核空间的速度。

有人知道为什么mmap() 会比ioremap() 慢吗?

这是我的代码:

内核模块代码

static int ti81xx_usmap_mmap(struct file* pFile, struct vm_area_struct* pVma)
{
  pVma->vm_flags |= VM_RESERVED;
  pVma->vm_page_prot = pgprot_noncached(pVma->vm_page_prot);

  if (io_remap_pfn_range(pVma, pVma->vm_start, pVma->vm_pgoff,
                          pVma->vm_end - pVma->vm_start, pVma->vm_page_prot))
     return -EAGAIN;

  pVma->vm_ops = &ti81xx_usmap_vm_ops;
  return 0;
}

static void ti81xx_usmap_test_gpio(void)
{
  u32* pGpIoRegisters = ioremap_nocache(TI81XX_GPIO0_BASE, 0x400);
  const u32 pin = 1 << 24;
  int i;

  /* I should use IO read/write functions instead of pointer deferencing, 
   * but portability isn't the issue here */

  pGpIoRegisters[OMAP4_GPIO_OE >> 2] &= ~pin;    /* Set pin as output*/

  for (i = 0; i < 200000000; ++i)
  {
     pGpIoRegisters[OMAP4_GPIO_SETDATAOUT >> 2] = pin;
     pGpIoRegisters[OMAP4_GPIO_CLEARDATAOUT >> 2] = pin;
  }

  pGpIoRegisters[OMAP4_GPIO_OE >> 2] |= pin;    /* Set pin as input*/

  iounmap(pGpIoRegisters);
}

用户空间应用代码

int main(int argc, char** argv)
{
   int file, i;
   ulong* pGpIoRegisters = NULL;
   ulong pin = 1 << 24;

   file = open("/dev/ti81xx-usmap", O_RDWR | O_SYNC);

   if (file < 0)
   {
      printf("open failed (%d)\n", errno);
      return 1;
   }


   printf("Toggle from kernel space...");
   fflush(stdout);

   ioctl(file, TI81XX_USMAP_IOCTL_TEST_GPIO);

   printf(" done\n");    

   pGpIoRegisters = mmap(NULL, 0x400, PROT_READ | PROT_WRITE, MAP_SHARED, file, TI81XX_GPIO0_BASE);
   printf("Toggle from user space...");
   fflush(stdout);

   pGpIoRegisters[OMAP4_GPIO_OE >> 2] &= ~pin;

   for (i = 0; i < 30000000; ++i)
   {
      pGpIoRegisters[OMAP4_GPIO_SETDATAOUT >> 2] = pin;
      pGpIoRegisters[OMAP4_GPIO_CLEARDATAOUT >> 2] = pin;
   }

   pGpIoRegisters[OMAP4_GPIO_OE >> 2] |= pin;

   printf(" done\n");
   fflush(stdout);
   munmap(pGpIoRegisters, 0x400);    

   close(file);    
   return 0;
}

【问题讨论】:

  • 慢 3 倍是什么意思?个别振荡时间较长,还是整体执行?
  • 两者,示波器上的振荡慢了 3 倍,处理器在“str”指令上花费了更多时间,但我不知道为什么。它是在等待一些硬件(总线传输?),还是像内核页面错误异常处理程序这样的软件?这是我的问题的核心......
  • 请注意,在您的示例代码中,循环的迭代次数非常不同。
  • @ysap 以补偿一个比另一个更快(频率)的事实:-)。在内核空间中进行了 30000000 次迭代,我几乎没有时间在我的范围内测量某些东西。

标签: linux kernel mmap gpio


【解决方案1】:

我的猜测是,由于mmap 必须检查以确保您正在写入您被允许写入的内存,它会比内核版本慢(我相信/假设不会做这种检查——使用你负责测试的内核模块,直到你非常确定你没有破坏东西)。

尝试使用do_mmap(我相信就是这个)在内核空间使用mmap,然后看看比较。如果它相对更快,那么我是对的。如果不是,那就是别的东西了。

【讨论】:

  • 好主意!我刚刚测试过,它与用户空间的速度相同。所以它与mmap有关,可能与内核或用户空间无关......
  • 权限检查应该是在 mmap() 期间一次性完成的事情。我不认为内核可以拦截内存访问,一旦该区域通过 TLB 映射到用户空间,我认为任何访问都是纯硬件的。
【解决方案2】:

这是因为 ioremap_nocache() 仍然在 VM 映射中启用 CPU 写入缓冲区,而 pgprot_noncached() 禁用缓冲性和缓存性。

苹果与苹果的比较将改为使用 ioremap_strongly_ordered()。

【讨论】:

  • 感谢您的回答!我可以两全其美(用户空间中的写入缓冲区)吗?我应该使用什么 pgprot ?你有这方面的文档吗?
猜你喜欢
  • 1970-01-01
  • 2015-04-03
  • 2011-07-27
  • 2021-01-16
  • 2012-02-29
  • 2021-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多