Benchmarking Raspberry Pi GPIO Speed

UPDATE2: You may also want to check out my Raspberry 2 vs 1 GPIO benchmark!

UPDATED: 2015-02-15! This article has been very popular, so I’ve now updated all the benchmarks using the latest firmware and library versions. The scope has also been upgraded to a PicoScope 5444B with better resolution and bandwith than the earlier models. :)


Don’t try this at home! Shorting GND and VCC with a probe might fry your Pi and more!

Method and Summary of Results

The basic test setup was to toggle one of the GPIO pins between zero and one as fast as possible. GPIO 4 was selected due to easy access and no overlapping functionality. This is basically the “upper limit” for any signalling one can hope to achieve with the GPIO pins – real-life scenarios where processing needs to be done would need to aim for some fraction of these values. Here are the current results:

Language Library Tested / version Square wave
Shell /proc/mem access 2015-02-14 2.8 kHz
Shell / gpio utility WiringPi gpio utility 2015-02-15 / 2.25 40 Hz
Python RPi.GPIO 2015-02-15 / 0.5.10 70 kHz
Python wiringpi2 bindings 2015-02-15 / latest github 28 kHz
Ruby wiringpi bindings 2015-02-15 / latest gem (1.1.0) 21 kHz
C Native library 2015-02-15 / latest RaspPi wiki code 22 MHz
C BCM 2835 2015-02-15 / 1.38 5.4 MHz
C wiringPi 2015-02-15 / 2.25 4.1 – 4.6 MHz
Perl BCM 2835 2015-02-15 / 1.9 48 kHz

Shell script

The easiest way to manipulate the Pi GPIO pins is via console. Here’s a simple shell script to toggle the GPIO 4 as fast as possible (add sleep 1 after both to get a nice LED toggle test):


echo "4" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio4/direction

while true
	echo 1 > /sys/class/gpio/gpio4/value
	echo 0 > /sys/class/gpio/gpio4/value

As expected, the performance of this implementation is not good: A 2.9 kHz square wave can be generated using this method. For some reason, this figure has come down since 2012, when I measured 3.4 kHz. Might be a firmware update. For turnings things on and off this is enough, but no signalling and hardly even LED PWM is feasible.


Update: Note that I have my probes at 1:10 setting, so the actual voltage value is 10x what is displayed in the figures!

Shell with WiringPi gpio utility

WiringPi comes with the gpio command, but its performance is almost 100x slower (40 Hz) than the plain shell, possibly due to starting delay of the executable. Code is a bit cleaner, though:


gpio mode 7 out

while true
        gpio write 7 1
        gpio write 7 0


Python with RPi.GPIO

One of the simplest ways to access the GPIO with a “real programming language” (sorry bashers :) is with the RPi.GPIO Python library. Installing it was simple: Just download the .tar.gz file, extract files and run python install. Our test script is simple as well:

import RPi.GPIO as GPIO


GPIO.setup(4, GPIO.OUT)

while True:
    GPIO.output(4, True)
    GPIO.output(4, False)

The library performance has increased steadily. 0.2.0 was less than 1 kHz, but 0.3.0 already bumped this to 44 kHz. As of version 0.5.10, the rate has again increased, and is now around 70 kHz!

2015_python_RPi.GPIO 0.5.10

The improved performance in Python is probably enough for simple multiplexing and LED PWM applications. Note that the new version requires some additional steps in installation, name getting Python development kit with sudo apt-get install python-dev. I originally got errors while trying this, but upgrading my packages solved that problem.

Python with WiringPi2 bindings

Another alternative for Python are the wiringPi Python bindings. Installation requires cloning the respective version and apt-get installation of python-dev and python-setuptools.

I installed the newer WiringPi2-Python version. Earlier tests with older version 1 gave a 19.5 kHz square wave. New test version with wiringpi2 module has improved to 28 kHz:

import wiringpi2

io = wiringpi2.GPIO(wiringpi2.GPIO.WPI_MODE_PINS)


while True:


Ruby with WiringPi bindings

WiringPi also has Ruby bindings, which can easily be installed:

sudo apt-get install ruby-dev
sudo gem install wiringpi

Code is also very simple:

require 'wiringpi'

io =

while true do

Performance is about the same as Python version, around 21 kHz square wave is generated:


C: Maximum performance

The Raspberry Pi Wiki gives a nice C code example for true hardware-level access to the GPIO. The interfacing is slightly more difficult, but code isn’t too bad. I took the example program and simplified the main method after setup_io() to this:

// Set GPIO pin 4 to output
INP_GPIO(4); // must use INP_GPIO before we can use OUT_GPIO

while(1) {
  GPIO_SET = 1<<4;
  GPIO_CLR = 1<<4;

Without any optimizations, I got an excellent 14 MHz square wave. Adding -O3 to the compile command (gcc -O3 strobe.c -o strobe) increases the rate to hefty 22 MHz. Measuring the waveform with oscilloscope starts to require VERY short wiring between probe and ground, otherwise it just looks like a sine wave due to capacitance in helper wires!


C with BCM2835 library

Mike McCauley has made a nice C library called bcm2835 that can also be used to interface with the GPIO pins using C. Its installation was also quite easy: download, run the standard configure / make / make install commands and you’re good to go. Compiling the code is done with the -lbcm2835 compiler flag to include the library. Benchmark code looked like this (note that in Broadcom numbering, GPIO 4 is P1_07):

#include <bcm2835.h>

#define PIN RPI_GPIO_P1_07 // GPIO 4

int main(int argc, char *argv[]) {
	return 1;

    // Set the pin to be an output
    bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP);

    while(1) { // Blink
	bcm2835_gpio_write(PIN, HIGH);
	bcm2835_gpio_write(PIN, LOW);

    return 0;

The performance is not far beyond the earlier C example: A solid 5.4 MHz with the use of -O3 optimization flag. Definitely enough for most applications!


C with WiringPi

Gordon Henderson has written an Arduino-like wiringPi library using C. It’s a popular one and quite easy to use. Here’s the simple test program:

#include <wiringPi.h>

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main() {
  if (wiringPiSetup () == -1)
    exit (1) ;

  pinMode(7, OUTPUT);

  while(1) {
    digitalWrite(7, 0);
    digitalWrite(7, 1);

  return 0 ;

With the normal GPIO access method, the library already clocks an impressive 4.1 MHz square wave:


There’s also a GPIO access method which involves calling wiringPiSetupGpio() instead of wiringPiSetup(), and using the normal GPIO numbering instead of wiringPi native renumbering system, so 7 becomes 4 in the above code. The performance is increased slightly to 4.6 MHz:


Since 2012, the WiringPi performance has somewhat decreased, as I originally got 7.1 MHz from the GPIO access method. This might of course also be due to firmware changes (I am running the tests over multitasking OS in a SSH shell, after all).

Also, a /proc/sys based access method was provided, but it was a lot slower, running at 120 kHz on average (200 kHz). The wiringPi library also has Python, Ruby and Perl bindings. See above for the Python version performance, I’d expect the Perl and Ruby bindings to be on the same speed level.

Perl with

Mike McCauley has also made a Perl module that uses the above C library to provide GPIO access in our favorite language (who doesn’t love Perl?). For installation, I recommend skipping cpan command and searching for the latest version from CPAN, downloading the .tar.gz with wget, extracting, and running perl Makefile.PL / make / make install commands. Like it usually is, the Perl code isn’t pretty, but it does the job well:

use Device::BCM2835;
use strict;

Device::BCM2835::init() || die "Could not init library";

# Set RPi pin P1_07 (GPIO 4) to be an output

while (1) { # Strobe
    Device::BCM2835::gpio_write(&Device::BCM2835::RPI_GPIO_P1_07, 1);
    Device::BCM2835::gpio_write(&Device::BCM2835::RPI_GPIO_P1_07, 0);

Compared to the Python version, the Perl module packs a bit more punch: 48 kHz square wave was achieved – enough for some PWM applications, if not quite enough for audio generation etc.


As with the Python version, any tips to improve Perl execution performance are welcome! Interestingly enough, the 1.0 version achieved slightly better performance than the latest 1.9 version – around 59 kHz. The difference isn’t large enough to not upgrade, though.


Based on these simple benchmarks, I can conclude that shell is only usable for simple automation tasks etc., but at least Python/Ruby/Perl is needed for anything more complex such as LED PWM. Python with RPi.GPIO is the fastest of these, but Perl with BCM 2835 bindings comes close. For actual signalling applications, C seems like the only choice. I haven’t tried the C# and Java interfaces, but I’d expect them to be on the level of C and Perl, respectively, or a bit slower.

What is not evident from the snapshots, however, is that due to multitasking nature of Linux, the GPIO manipulation is constantly interrupted for short periods when the CPU is doing something else, such as receiving or sending data over network, writing log files, etc. Only a realtime OS is suitable for timing-critical stuff, or using the hardware level support for I2C, UART and such. A good alternative is an independent add-on board with a microcontroller, such as Arduino or several other alternatives. Communicating over UART is simple with such devices.

Published by

Joonas Pihlajamaa

Coding since 1990 in Basic, C/C++, Perl, Java, PHP, Ruby and Python, to name a few. Also interested in math, movies, anime, and the occasional slashdot now and then. Oh, and I also have a real life, but lets not talk about it!

128 thoughts on “Benchmarking Raspberry Pi GPIO Speed”

  1. If you didn’t know, the python RPi.GPIO module has a pwm class.
    It is still started the normal way but you set a variable up with the class and you can change frequency as well as work time.

    1. Yes I noticed that some libraries expose the PWM functionality. I left it outside the benchmark scope, as hardware PWM is independent of programming language performance, and of course a bit more limited on what you can do (no signalling, for example).

      1. PWM with RPi.GPIO produces some flicker, particularly at short (<10%) duty cycles. As I understand it, the PWM routines use software timing for the PWM, not the hardware.

  2. I just tried your “C: Maximum performance” code on a PI2. The results are 41.667MHz. Measured with a Tek MSO4104 & TDP1000 probe.

  3. Hey mate,
    in python 2.7 for loops are faster than while loops.
    Can you measure using?

    while True:
    for i in xrange(4294967295): #2^32-1

    Also make sure to use Xrange not Range.

    1. No. Longer answer: Based on a quick test, a raw while True -loop with counter increment and test can do about 600 000 iterations per second on a RaspPi. With 70 kHz strobe it means the Pi spends less than 10 % (most likely even less than 5 %) of its time processing the while statement, and over 90 % of time doing the strobe. So if the for loop on Python 2.7 is 2x faster, it would only change the result by less than 5 %.

      My personal guess would be that the optimized for-loop version might give 1 % speed boost at best. For some reason, a quick timing of a for loop and while actually gave me worse results on for loop…

  4. I believe it can go beyond the results gathered. There’s a Pi program that is used to transmit FM signals from 88 MHz to 108 MHz called PiFM, so on GPIO 4 it can definitely reach >100 MHz, the pi runs on 700 MHz clock speed without the interrupts it would be possible to achieve GPIO speeds close to 700MHz.

  5. Hi, this article is great. Have you had a chance to test the Java library (pi4j ?) I made a small Java class to test, but the result is very disappointed. On Raspberry2, it can only toggle the GPIO 1300 times per seconds, which is 1.3kHZ. I feel quite strange that it is much slower than the Python or Ruby (I think it is reasonable that Java is slower than C. But it is no reasonable that Java is much more slower than Python or Perl)

    I have attached my test class. I will also made some investigation.


    * Created by LFF on 2015/11/7.
    public class SpeedTest {

    private static GpioPinDigitalOutput DIO;

    static final GpioController gpio = GpioFactory.getInstance();

    public static void main(String[] argu) {

    private static void test() {
    long l0 = System.currentTimeMillis();
    int count = 10000;
    for (int i=0;i<count;i++) {
    long time = (System.currentTimeMillis() – l0);
    System.out.println(time + " used.");

    float per = time / (float)count;

    System.out.println(per + " per toggle, " + (1000 / per) + " per second");

    private static void init() {
    // create gpio controller
    DIO = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_04, "dio", PinState.HIGH);

  6. you can go >100MHz if you abuse parallel Video port
    DPI is used by VGA666, but you can hijack it for (18 pins) output GPIO by filling screen buffer with your data on Vblank. As a bonus you get reliable timing with no jitter and smooth frequency setting

  7. One easy way to improve the speed of the shell version is to use a file descriptor rather than opening the “value” file each time. Try benchmarking this instead (and be sure to use /bin/dash and not /bin/bash for additional speed):


    echo “4” >/sys/class/gpio/export
    echo “out” >/sys/class/gpio/gpio4/direction

    exec 3>/sys/class/gpio/gpio4/value

    while true
    echo 1 >&3
    echo 0 >&2

  8. hi, you could try asm blinking program to test the speed, i think it may be the fastest but you’re right about raspi os isn’t a rtos and is constantly been interrupted by another task.

    sorry my english, thanks for your work

    1. I might be, what would the exact test setup be? Generate a square wave on a microcontroller/signal generator, and have a input loop on Pi side and record the transitions? Due to O/S lag, probably with 1 kHz test signal (2k transitions) and Pi achieving 2+ kHz read speed, there would be a 1-5 % loss of transitions. Or does the Pi have an interrupt which could be used to count transitions?

      1. The pi has interupt handling so the question is how close can interupt trigers be before they get missed. For example if we are monitoring RPM using the interupt handler at what pulse frequency do we start to miss trigers. Google raspberry pi interupts.

        Further – How long does the pin read take? Is there a minimum period for which a pin must be kept stable for a read to complete.

        So there are two aspects. The frequency of the square wave and the duty cycle.

        Real application. A sensor/instrument trigers an interupt telling the Pi that data is ready to be read. How long must the data be kept stable before it is changed.

  9. We are building a weather station for our club.
    Anemometer – Will generate pulses fed into a ripple counter. To few pulses per revolution leads to degraded low speed accuracy. To many pulses per revolution may lead to high speed errors on the Pi. Yup, there are lots of solutions and we will likely take the trial and error approach.
    Wind Vane – It you watch a weather station wind vane it almost never stays still. We are using an optical disk setup with latching and a monostabilizer.
    At the end of the day I’m sure the Pi performance will not be an issue but since I came across your work I figured I’d ask :)

  10. hi! nice article.

    did you try any tests with real-time kernels for the raspbian? i wonder how much would it help if prio’s are set right.

    and also: what was the CPU load when doing above tests? 100%?

  11. does anyone here know assembly?
    what happens if you give it a block output command?
    how fast can it read the gpio?
    say i want to put a million sps conversion adc on the gpio with a 50 MHz oscillator, how many samples can i store in a burst?

  12. Toggling GPIO pin 20 on a 2016 Raspberry Pi 3 Model B running on Win 10 Core IoT 10.0.14393.67 delivers a maximum of around 230 kHz with the following c# code:
    long i = 0;
    long kHz;
    long HiResTimeStamp1 = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
    while (i < 1000000)
    long HiResTimeStamp2 = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
    kHz = (i/(HiResTimeStamp2 – HiResTimeStamp1));

    Haven't got a scope so can't provide any waveforms… :-(

  13. Nice article. Do you know how i can configure a real time os over the raspberry pi? What options do i have?

    thank yu

  14. Would be very interested in seeing an update to your benchmark using a simplistic kernel driver for the pin access instead of in user space, as that would give an indication of the maximum performance that could theoretically be delivered by the Pi hardware in any practical implementation.

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload the CAPTCHA.