Conversation
|
For the history, benchmark for the simple roundtrip (create, get state, shutdown): |
Perhaps you can add a benchmark for the existing provider? |
That's for the the stage 2 :) I tried to quickly do it and failed, due to lack of build targets for desktop (amd64) of natives. I can try to run the benchmark on a real hardware, but since we are testing in comparison with other approaches, it is better to stay with gpio-sim. |
|
Okay, a bit of journey on benchmarks :) TLDRFor libgpiod (Java code -> JNA Code -> libpi4j-gpiod.so (JNI-wrapper) -> libgpiod.so (native library) -> GPIO kernel syscalls) For FFM API (Java code -> GPIO kernel syscalls) Bit of detailsSo first things first I built manually all gpiod natives (that was a lot more easier without maven) and pointed to the library folder in the code of So for the sake of comparison I did the same thing with FFM code (commented out monitoring thread creation) and rerun benchmark. The results are as expected almost similar, with a slight faster with FFM. That happens, just because the roundtrip between native world and Java world is shorter. |
|
Nice write up! Thanks a lot for that insight! |
| // if 'flags' were provided in the SPI config, then accept them | ||
| if(config().flags() != null){ | ||
| flags = config().flags().intValue(); | ||
| } |
There was a problem hiding this comment.
in the linuxfs spi implementation we error out is the flags parm was used, This pertained to the pigpio provider and it continued use would put limits on the linuxfs code.
| if(bus.getBus() > 1){ | ||
| throw new IOException("Unsupported BUS by PiGPIO SPI Provider: bus=" + bus.toString()); | ||
| } | ||
|
|
There was a problem hiding this comment.
also, ignoring the old pigpio limitations, the linuxfs spi will allow any bus and channel the user wants. They are required to do the config.txt updates to the spi actually exists.
| if(bus == SpiBus.BUS_1 && (mode == SpiMode.MODE_1 || mode == SpiMode.MODE_3)) { | ||
| throw new IOException("Unsupported SPI mode on AUX SPI BUS_1: mode=" + mode.toString()); | ||
| } | ||
|
|
There was a problem hiding this comment.
broken record, this limitation does not exist in linuxfs
|
@taartspi just for the record - SPI classes are just the boilerplate code now, I copy-pasted it for future reference. You can have a look on my implementation here (which I'll be using): https://github.com/DigitalSmile/gpio/blob/main/src/main/java/org/digitalsmile/gpio/spi/SPIBus.java |
# Conflicts: # pi4j-core/src/main/java/com/pi4j/io/pwm/PwmBase.java
# Conflicts: # plugins/pi4j-plugin-linuxfs/src/main/java/com/pi4j/plugin/linuxfs/LinuxFsPlugin.java # plugins/pi4j-plugin-linuxfs/src/test/java/com/pi4j/plugin/linuxfs/PWMChipTest.java
plugins/pi4j-plugin-ffm/src/main/java/com/pi4j/plugin/ffm/providers/pwm/PwmFFMProviderImpl.java
Show resolved
Hide resolved
|
Looks the merge is complete and ffm updates are ready for HW testing |
taartspi
left a comment
There was a problem hiding this comment.
I have reviewed parts of the code not all. This delivery is a great deal of work. I will continue to review and test I think we should merge and build this to make testing and any new issue discussions easier.
|
So i'll update develop to 4.0.0-SNAPSHOT and then merge this branch. Any objections? @FDelporte @DigitalSmile @taartspi |
|
@eitch the branch is already on |
|
Done. |
This PR is work in progress, will be adding new implementations step by step.
Implementation details
FFM API provides new robust access to native code from JVM world. Moreover, all pi4j plugins relies on third party native libraries, which in the end calls linux kernel functions.
So, the typical flow was:
Java method (pi4j) -> JNA Java Code (jna) -> JNI Wrapper Call (pi4j) -> Native Library Call (gpiod, pigpio, etc) -> Kernel syscall
Now with the power of FFM API:
Java method (pi4j) -> Kernel syscall
This changes leads to better maintanability, less unsecure native calls, speed and better understanding of the code.
Main package
New plugin consists of several packages:
commonpackage with internal structures needed to FFM workfile- all needed code to access file descriptors with open/read/write/close/... methodsgpio- all needed structures to work with GPIO (DigitalInput/Output) interfacei2c- all needed structures to make I2C work (direct/ioctl/file). The only runtime dependency to work isi2c-toolsioctl- syscall wrapper to work with linux kernel HALpoll- syscall wrapper to work with poll/epoll messagesserial- all needed structures to work with Serial interfacespi- all needed structures to work with SPI busproviderspackage with all user-facing implementationsgpio- contains DigitalInputFFM and DigitalOutputFFM implementationsi2c- contains I2CSMBus (usingi2c-toolsuserspace library), I2CFile (using simple files) and I2CDirect (usingioctl)pwm- contains PwmFFMHardware implementationserial- contains SerialFFM implementation (beta version for now)spi- contains SpiFFM implementationTests
Since testing hardware is non-trivial tasks, I used an approach with different tests for different purposes.
Tests are organized in several packages:
unit- classic unit testing with support ofMockitoframework. Mocks are located at packagemocksmodel- tests, that covers model conversion from Java objects to FFM API structuresintegration- tests that are using mock drivers on linux kernel side to simulate the behaviour of real hardware.i2c-stub,gpio-simand customspi-mockkernel drivers (source code located innativefolder)jmh- classic JMH tests to measure speed of end-to-end calls with FFM/non-FFM plugins.JMH Test results
Pi4j has 3 providers that are used in common:
gpiodprovider with access to GPIO pins, useslibgpiodunder the hoodpigpioprovider with GPIO, I2C, PWM, Serial and SPI, useslibpigpiounder the hood with access through/dev/memlinuxfsprovider with GPIO, I2C, PWM, Serial and SP, usessysfsunder the hoodAll tests were run in VirtualBox environment using mock linux drivers:
sim-gpiodriveri2c-stubdriverSetup scripts are located here.
Because we are using mock drivers, we cannot test
pigpioas it requires real hardware with available DMA addresses, so this library is out of scope of performance benchmark.PWM is excluded from performance tests, because it is relying on filesystem in every provider available.
Serial is excluded, because FFM implementation is in beta and is out of scope with this PR.
How to read results
The results should be analysed in terms of relative numbers, but not absolute. The less is average time - the best score it wins.
GPIO (tested September, 20 2025)
OpenJDK Runtime Environment Corretto-25.0.0.36.2 (build 25+36-LTS)Linux ds-VirtualBox 6.14.0-29-generic #29~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Aug 14 16:52:50 UTC 2 x86_64 x86_64 x86_64 GNU/LinuxAMD Ryzen 7 5800X 8-Core Processor 29GiB System memoryResults:
SPI (tested September, 20 2025)
OpenJDK Runtime Environment Corretto-25.0.0.36.2 (build 25+36-LTS)Linux ds-VirtualBox 6.14.0-29-generic #29~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Aug 14 16:52:50 UTC 2 x86_64 x86_64 x86_64 GNU/LinuxAMD Ryzen 7 5800X 8-Core Processor 29GiB System memoryResults:
I2C (tested September, 20 2025)
OpenJDK Runtime Environment Corretto-25.0.0.36.2 (build 25+36-LTS)Linux ds-VirtualBox 6.14.0-29-generic #29~24.04.1-Ubuntu SMP PREEMPT_DYNAMIC Thu Aug 14 16:52:50 UTC 2 x86_64 x86_64 x86_64 GNU/LinuxAMD Ryzen 7 5800X 8-Core Processor 29GiB System memoryResults: