Speaking about performance, the first thought is to measure how long it takes to perform a single well-delimited operation, for instance reading the current value of the temperature sensor of a Yocto-Meteo. The sensor measures the temperature continuously, but the driving software requests the current value at a given t time only and waits for the answer:
Moving information by USB always takes some milliseconds, by rule: the USB bus cuts data into frames, that are transmitted every millisecond. When we acess a module through a remote TCP connection, the transfer time rises easily to several dozens of milliseconds for every exchange.
In order to save on transport time, the Yoctopuce library maximizes the amount of data transferred with regard to waiting time, by transmitting in advance any available data from a sensor at once. In this way, if one starts by reading the current temperature on the Yocto-Meteo, it replies at the same time with the min and max values, as well as with pressure and humidity measures. There is a small extra cost for the first transmission, but then a big saving when looking for that data.
Here are the typical durations for reading a Yoctopuce sensor:
- using C++ and C#, via USB: 27 [ms] for the 1st sensor, <1 [ms] for the next ones
- using C++ and C#, via TCP: 31 [ms] for the 1st sensor, <1 [ms] for the next ones
- using PHP, via TCP: 34 [ms] for the 1st sensor, <1 [ms] for the next ones
Until here, nothing really surprising. Given that this kind of sensor only changes value once or twice per second, nobody asks for more than this.
For command modules, we need much better. When driving a motor or a light, one may want to change the control value much more quickly, and to control a large number of modules. For instance, our musical Christmas tree had 24 leds to blink according to the music beats, which requires significantly higher performances. Luckily, the problem is much simpler. Let's see how it works:
The latency is difficult to measure directly, as we will see below. First, have a look at the typical duration needed to send a command to a Yoctopuce module (the time used in the control program):
- using C++, via USB (Mac OS X, Linux): ~1.5 [ms]
- using C++ and C#, via USB (Windows): <1 [ms]
- using C++, via TCP (Mac OS X, Linux): ~1.5 [ms]
- using C++ and C#, via TCP (Windows): ~2.5 [ms]
- using PHP, via TCP: <1 [ms]
This is not much. And thanks to this, you can easily use a Yocto-Color for creating small animated light shows.
Another case where performance matters is when reading a control knob, or an analog input in general. This is the job of a Yocto-Knob for instance. One could use repeated synchronous readings (polling), but this would require to use a very demanding active loop when high reactivity is required. The proper way to handle this application is to use callbacks, triggered automatically straight from the device when an event (such as a value change) occurs.
This method takes almost no time in the control software (< 1ms in all cases), since everything is done in advance in the Yoctopuce module. However, as for running a command, one question remains: how long is the latency between the real event and the callback ? Is it possible to keep it short enough to appear simultaneous for all programming languages ?
Measuring the latency
The difficulty in measuring latency is the fact that the boundaries of the interval to measure do not occur at the same location. Therefore, there is no simple way to measure the duration. However, we can easily setup a small test circuit with devices, that adds up the two latency that we want to measure, and is completely controlled from our main software. To do so, we simply connect an output of a Yocto-Relay to an input of a Yocto-Knob:
Our test bench: a Yocto-Relay and a Yocto-Knob linked together
The principle is very simple: the software starts a timer, commands the relay to change its state, and waits until it receives a callback from the Yocto-Knob regarding the contact that was just opened/closed. The time duration between the start of the command and the callback then includes:
- the time needed to trigger the command (approx. 1ms)
- the command execution latency (to be determined)
- the time needed for the relay to actually move (approx. 3ms)
- the latency for the event to come back as a callback (to be determined)
If the cumulated latency gets over 100 [ms], it is perceived as a lag by the observer, and may also cause issues for applications where an instantaneous reaction is needed. Here is the latency time for some common one-way user interfaces:
- PS/2 mouse latency: 25 [ms]
- USB mouse latency: 8 [ms]
- Radio-commanded airplane latency: 30 [ms]
And here are the results of our cumulated latency measure, through the two Yoctopuce modules:
- using C++, via USB (Mac OS X, Linux): 7.5 [ms]
- using C++ and C#, via USB (Windows): 6 [ms]
- using C++, via TCP (Mac OS X, Linux): 16 [ms]
- using C++ and C#, via TCP (Windows): 18 [ms]
- using PHP, via TCP: 13 [ms]
Knowing that these durations include twice the latency in addition to the relay commuting time, it shows that the latency of Yoctopuce modules is in the order of a few milliseconds, far from being perceptible by a human observer.
- C++ and C# measurements on Windows have been made on a Lenovo X301 (Core 2 duo).
- C++ measurements on Linux have been made using an ASUS notebook (Core i3).
- C++ measurements on Mac OS X have been made using a 2010 iMac (Core i7).
- The source code used for the tests is available here.