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 |