📜 ⬆️ ⬇️

Symbian Multi-Threading Testing

We recently installed an SDK for Qt for Symbian development on Linux. Now it's time to write something on it.
Now almost everywhere, multi-threaded architectures are used to perform any background calculations while the user uses the UI.
Let's see how effective it is when developing for Symbian.

For tests, the Nokia 6120c phone (S60 v3 FP1) was taken. At one time, this phone was popular as a budget and a small smartphone and is quite a typical device on the Symbian platform.

Test Description


The algorithm for checking the numbers for simplicity was taken as background calculations. It is quite simple and short and at the same time consumes a lot of CPU time.
bool isPrime = true ;
for ( int i = 2; i <= currentDummy/2; isPrime &= (currentDummy%i) != 0, ++i);


* This source code was highlighted with Source Code Highlighter .


For the purity of the experiment, we run through all the numbers, and do not stop at the first divider found (otherwise the streams would end with a very large time scatter). The data between the streams are divided evenly and not by segments of the numerical line, but alternate between streams (which again gives us a more honest experiment with almost simultaneously terminating streams).
')
The stream class code (the final one is laid out and includes two options at once, more on this in more detail below).
//workerthread.h
#ifndef WORKERTHREAD_H
#define WORKERTHREAD_H

#include <QThread>

class WorkerThread : public QThread
{
Q_OBJECT
public :
explicit WorkerThread( int start, int end, int step, QObject *parent = 0);

signals:
void updateProcess( int value );

public slots:

protected :
void run();

private :
int rangeStart;
int rangeEnd;
int rangeStep;
};

#endif // WORKERTHREAD_H

//workerthread.cpp
#include "workerthread.h"

WorkerThread::WorkerThread( int start, int end, int step, QObject *parent) :
QThread(parent), rangeStart(start), rangeEnd(end), rangeStep(step)
{
}

void WorkerThread::run()
{
int currentDummy = rangeStart;
int currentProcess = 0;
while (currentDummy <= rangeEnd)
{
bool isPrime = true ;
for ( int i = 2; i <= currentDummy/2; isPrime &= (currentDummy%i) != 0, ++i)
{
//Method 2. Slower, but more responsive UI
// if (!(i%500))
// yieldCurrentThread();
}
if (!(currentProcess%1000))
{
emit updateProcess(currentProcess);
}
currentDummy += rangeStep;
++currentProcess;

//Method 1. Faster, but with UI stucks
yieldCurrentThread();
}
emit updateProcess(currentProcess);
}


* This source code was highlighted with Source Code Highlighter .


For the study of UI slowdowns, the usual slider was taken, which by timer in the GUI stream changed its value. Thus, we can track the moments when the main stream does not receive control (which leads to freezing and freezing of the UI) on this slider.
Here is the appearance of the testing form:
image
It is such a minimalist style that displays only the percentage of calculations (progress bars), the timing of calculations, the UI indicator, the number of threads and the Start button.

Testing


As mentioned earlier, we have two options for implementing a workflow:
  1. Give control to another thread after each checked number
  2. Give control to another thread after a certain number of verified dividers

Even without tests, it is clear that the first option will work faster, but sometimes slow down the UI, and the second will work slower (due to more context switches), but also slow down the UI less. The whole question is how critical it will be and noticeable.
We will test for 1, 2, 3 and 4 workflows, estimating the runtime and the smoothness of the UI (that is, the smoothness of the slider movement).

Testing the first option


1 thread

It was completed for 64255ms, while there were a dozen slowdowns (about a second), but in general the slider moved smoothly.

2 threads

Executed for 49477ms, while there were 6 slowdowns (time about a second). General sensations as from a variant with one stream.

3 threads

Executed for 45988 ms, while there was only one slowdown, but it was from the middle of the calculations to the end. The result is far from satisfactory in terms of UI.

4 threads

Executed for 46275 ms, while working similarly to the 3-flow variant.

Conclusions on the first version

It is undesirable to start more than two worker threads, but two threads give a speed increase of about 25 percent and have little effect on the UI.

Testing the second option


1 thread

Run for 463372ms, while there were a dozen slowdowns (about a second) and a lot of small ones (much less than a second, but noticeable to the eye).

2 threads

Run for 231544ms, while there were 6 slowdowns (time about a second) and also as in the variant with one stream there are a lot of small ones.

3 threads

Executed in 154797ms, while there were about 5 slowdowns (also about a second), but in general the UI worked smoothly.

4 threads

Run for 116959 ms, while working similarly to the 3-flow variant.

Conclusions on the second option

Naturally, the test with one stream in this variant is needed just for comparison, since such aggressive project does not provide any advantages for one stream. The test with two threads also showed not very good results due to too large overhead costs for the scheduler. Tests with three and four threads showed themselves very well.

General conclusions


In the case when we need to divide some kind of homogeneous calculations into threads, it is better to use the first option with two workflows. But in the case when we need to perform some non-uniform operations in different streams, the second option looks better than the first (although it takes two to three times more time), since it allows the user to work normally with the UI during the calculations.

My findings


I am pleased with such results, since they clearly show that even for low-cost (and already quite old) Symbian devices, you can write multi-threaded applications without any special problems, albeit with a few reservations and additional tests (for example, at the optimal model frequency).

Download the above


Sources
sis-file of the first option
sis-file of the second option

UPD about thread priorities


I launched threads with Idle and Low priorities (only the first test version was launched). The results were even worse than with normal priority. Two streams froze in the middle, three and four streams froze almost at the very beginning. The speed differs within the limits of error (48 s for two and 45 for three and four). Apparently the sheduler does not work well with different thread priorities.

Source: https://habr.com/ru/post/85194/


All Articles