rpi-gpio-test
is a test to benchmark and compare different approaches to performing GPIO on Raspberry Pi from within a Linux kernel module.
There are quite a few GPIO benchmarking tests for Raspberry Pi available on the web in general and GitHub in particular. The absolute most of those just do write-only GPIO and measure performance of that. In reality, however, it's often crucial to measure the speed of a two-way communication to estimate the expected latency of a response to some external event.
Another thing is, when we benchmark a two-way GPIO communication, it's important to test and compare both interrupt-based and polling-based approaches.
This repo provides a codebase for a more complete testing matrix.
Test | Description |
---|---|
write-only | a simple busy loop which constantly changes the state of a GPIO line from HIGH to LOW and back |
read/write | there are two parties, A and B; each one is both a reader and a writer. Each reader waits for its GPIO line to drop, resets it to back to HIGH, then drops the GPIO line of its counterpart. One of the GPIO lines is dropped initially to start the loop. |
When a reader waits for its GPIO to drop, it can do either of the following:
Method | Description |
---|---|
IRQ-based | use an interrupt handler to be triggered on lowering of a GPIO line |
polling-based | run a thread which would constantly poll the state of a GPIO line in a busy loop |
For reading and writing the states of GPIO lines, two approaches may be used:
Method | Description |
---|---|
GPIO registers | map BCM-2836-specific GPIO registers into kernel address space and use those to read and write GPIO lines |
gpio_get_value / gpio_set_value |
use portable, but less performant GPIO API available in Linux kernel |
Install Linux kernel headers for Raspberry Pi
$ sudo apt install raspberrypi-kernel-headers
Select testing configuration using defines in
rpi-gpio-test.c
Testing scenario can be changed using:
#define Default Description USE_GPIO_REGS
1 use BCM-2836 GPIO registers (otherwise, use the gpio_get_value
/gpio_set_value
API)USE_RW_IRQ
0 use interrupts for read-write benchmark USE_RW_POLL
1 use polling for read-write benchmark USE_RW_YIELD
0 yield CPU with schedule ()
during pollingUSE_WO_BLOCKING
1 perform blocking write-only benchmark in module_init ()
USE_WO_THREADED
0 perform write-only benchmark in a dedicated thread USE_AFFINITY
1 assign threads to different CPU cores GPIO pins can be changed using:
#define Default Description GPIO_A_OUT
17 output pin used to trigger reader A GPIO_A_IN
18 reader A of the read-write test GPIO_B_OUT
23 output pin used to trigger reader B GPIO_B_IN
24 reader B of the read-write test GPIO_C_OUT
22 used for write-only test For read-write tests, connect pins
GPIO_A_OUT
↔GPIO_A_IN
andGPIO_B_OUT
↔GPIO_B_IN
.Iteration counts can be changed using:
#define Default (API) Default (regs) Description RW_IRQ_ITERATION_COUNT
50000 500000 IRQ-based read-write test RW_POLL_ITERATION_COUNT
500000 5000000 polling-based read-write test WO_ITERATION_COUNT
1000000 10000000 write-only test Build kernel module
$ cd src $ make make -C /lib/modules/4.9.80-v7+/build/ M=/home/pi/Projects/rpi-gpio-test/src modules make[1]: Entering directory '/usr/src/linux-headers-4.9.80-v7+' CC [M] /home/pi/Projects/rpi-gpio-test/src/rpi-gpio-test.o Building modules, stage 2. MODPOST 1 modules CC /home/pi/Projects/rpi-gpio-test/src/rpi-gpio-test.mod.o LD [M] /home/pi/Projects/rpi-gpio-test/src/rpi-gpio-test.ko make[1]: Leaving directory '/usr/src/linux-headers-4.9.80-v7+'
Load kernel module
$ sudo insmod rpi-gpio-test
This will launch the testing scenario chosen with the pre-processor definitions during step 2.
Inspect the results
$ dmesg
Unload kernel module
$ sudo rmmod rpi-gpio-test
- Repeat from step 2
The following results are obtained on Raspberry Pi 2 Model B V1.1
The Linux version is:
$ uname -a
Linux raspberrypi 4.9.80-v7+ #1098 SMP Fri Mar 9 19:11:42 GMT 2018 armv7l GNU/Linux
Test | Frequency (API) | Frequency (regs) |
---|---|---|
Write-only test | 1.3 MHz | 41 MHz |
Read-write test (IRQ) | 110 KHz | 140 KHz |
Read-write test (poll) | 370 KHz | 2.7 MHz |