mmap langsamer als ioremap

Ich entwickle für ein ARM-Gerät mit Linux-2.6.37. Ich bin versucht zu wechseln, ein IO-pin so schnell wie möglich. Ich machte einen kleinen kernel-Moduls und einer user-space-Anwendung. Ich habe versucht, zwei Dinge :

  1. Manipulieren die GPIO-control-Register, die direkt aus dem kernel-space mit ioremap.
  2. mmap() die GPIO-control-Register ohne Zwischenspeicherung und Verwendung von user-space.

Beide Methoden funktionieren, aber der zweite ist etwa 3-mal langsamer als die erste (beobachtet am Oszilloskop). Ich denke, dass ich alle deaktiviert caching-Mechanismen.

Natürlich würde ich gerne das beste aus beiden Welten : Flexibilität und einfache Entwicklung von user-space mit der Geschwindigkeit des kernel-space.

Weiß jemand, warum die mmap() könnte langsamer sein als die ioremap() ?

Hier ist mein code :

Kernel-Modul-code

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);
}

User-space-Anwendung-code

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;
}
  • Was meinst du mit 3x langsamer ? Individuelle Schwingung länger sind, oder die Allgemeine Ausführung ?
  • Beide, die Schwingungen sind 3 mal langsamer über den Umfang, der Prozessor mehr Zeit damit verbringt, in der "str" - Anweisung, aber ich weiß nicht, warum. Ist es noch für einige hardware (bus-transfer ?), oder einige software wie ein kernel page fault exception-handler ? Das ist das Herz meiner Frage...
  • Beachten Sie, dass in Ihrem Beispiel-code die Anzahl der Iterationen der Schleifen ist sehr unterschiedlich.
  • zu kompensieren, die Tatsache, das man schneller ist (in der Frequenz) als das andere :-). Mit 30000000 Iterationen im kernel-space, ich habe kaum die Zeit, um etwas zu Messen, der auf meinem Rahmen.
InformationsquelleAutor Julien | 2012-06-07
Schreibe einen Kommentar