Typed Python library performance

Typed Python library performance

A few months ago, we launched a second version of our programming library: the Typed Python library. In a previous post, we explained the new features. This week, we'll be analyzing the difference in performance between the two versions.





From a technical point of view, these two libraries work completely differently. The "traditional" library is split into two layers: a high-level layer that implements the Yoctopuce objects (YModules, YTemperature, etc.) and a low-level layer that manages communications with the hardware.

The high-level layer is of course implemented in Python and is supported by all OSes and architectures.

The low-level layer, called "yapi", works differently. It's a dynamic library written in C that interacts directly with the OS. This layer is not portable, and requires a specific version for each supported platform. Incidentally, in the library's /Source/cdll subdirectory, you can find all versions of the "yapi" layer for all OSes and architectures.

On the first call to the library, the Python code of the high-level layer detects the OS and architecture of the machine and loads the correct version of the "yapi" layer.

In contrast, the Typed Python library is written entirely in Python and is therefore 100% portable. The equivalent of the "yapi" layer is either processed by the Python virtual machine or has been rewritten in Python.

Now that we've explained the technical differences, let's look at the performance implications this has.

Size

The size of our library may seem ridiculous on a modern computer with several terabytes of storage, but both libraries are often used with much more modest architectures, such as Raspberry Pi Zero. Let's take a look at 3 scenarios and see the difference in size.

Scenario 1: everything is included. This is probably the most common case. The user installs the library using pip and all library files are included.

PythonTyped Python
Python files1.9 Mb3.93 Mb
Binary files11.9 Mb0 Mb
Total13.8 Mb3.93 Mb




Scenario 2: Only the architecture used is included. In this scenario, we manually download the library from our website or GitHub and copy only the "yapi" library for the current architecture. For this example, we'll copy only the libyapi-aarch64 file, which is the 64-bit ARM Linux version used by most Linux distributions running on Raspberry Pi.

PythonTyped Python
Python files1.9 Mb3.93 Mb
Binary files1.29 Mb0 Mb

Total
3.19 Mb3.93 Mb




Scenario 3: Only the architecture used and only the YRelay class used are included.

PythonTyped Python
Python files371 Kb704 Kb
Binary files1.29 Mb0 Mb

Total
1.70 Mb704 Kb



Performance


To measure the API's performance, we're going to use the same environment we've been using since 2012. That is, a Yocto-Relay connected to a Yocto-Knob. In this way, we can detect the state of the relay output using the Yocto-Knob.

The program changes the status of the Yocto-Relay and times the time difference between the command being sent and the Yocto-Knob's status change notification. For more details on this program and set-up, please reread the post we wrote on the topic.

The program performs 3 measurements: the first measurement is the "set time". This is the average duration of the call that switches the relay state.

The second is "set/get time". This is the average duration of the call to switch the relay and read back the relay status. This test is the longest and least efficient, as it works in polling mode, i.e. the state of the complete Yocto-Relay is reloaded at each iteration.

The final measure is the average time between relay switching and the arrival of the notification that the Yocto-Knob state has changed. This test uses the callback mechanism and is the most efficient way of writing reactive code.

For more details on polling and callback, please read our post on the topic.

We ran this program on a Raspberry Pi 3 with the modules plugged directly into the USB ports. The latest version of VirtualHub is installed. The test application uses the URL "127.0.0.1" to access the modules via VirtualHub. Note: it would be possible to dispense with VirtualHub for the traditional library, but we wanted to compare the two libraries under the same conditions.

Here are the results.

Test Python Typed Python (sync) Typed Python (async)
Set 5.47 ms6.44 ms6.44 ms
Set/get (polling) 25.50 ms25.22 ms24.57 ms
Set/get (callback) 8.08 ms13.65 ms12.74 ms



The performance of the Typed Python library is slightly lower, but it uses fewer resources. In fact, the Typed Python library needs only one thread.

On the other hand, if you need to integrate our modules into a Python application that uses async/await functionality, the Typed Python library is more efficient and responsive.


Conclusion


In conclusion, the Typed Python library, although slightly less efficient in terms of execution speed, offers significant advantages in terms of portability and resource efficiency. The choice between the two Python libraries depends on the project. If raw performance is critical, the traditional library is more suitable, but for applications running on more limited machines or on more exotic architectures, the Typed Python library is more appropriate.

Add a comment No comment yet Back to blog












Yoctopuce, get your stuff connected.