PDA

View Full Version : Use more CPU cores



satoshi
20th April 2010, 09:57
Hi there,
is there a way to run a Qt application using all the cores of the CPU? I've a two-core CPU and there are two threads in my program. This application has to be as fast as possible, a smart thing will be assign a thread for each core. Is it possible?

If yes, is there a way to determine the number of CPU cores of the machine where the application is running?

Sorry for my english

Thanks, Dario

wysota
20th April 2010, 10:12
If there are two threads in your application then if your system policy allows it, two cores will be used.

satoshi
20th April 2010, 11:27
If there are two threads in your application then if your system policy allows it, two cores will be used.
Thanks, this is what I was expecting but it seems it's using only one core.

I'm running Qt 4.5.3 under Windows XP. The effect is the same under Ubuntu.

Any suggestion?

wysota
20th April 2010, 11:30
Maybe you are not using two threads? :)

satoshi
20th April 2010, 11:34
Maybe you are not using two threads? :)
I see two threads when I debug...

wysota
20th April 2010, 11:41
I see two threads when I debug...

Which doesn't mean both are doing something. If you have bugs in your code concerning thread affinity, then one of the threads will be idle all the time and won't use practically any cpu power.

satoshi
20th April 2010, 11:43
Which doesn't mean both are doing something. If you have bugs in your code concerning thread affinity, then one of the threads will be idle all the time and won't use practically any cpu power.
Ok, thanks. I'll verify that.

Dario

satoshi
20th April 2010, 12:23
Maybe I'm not using threads correctly.. Here's my code:

for(int i = 0; i < numCores; i++)
{
new MyThread(...);
}

The class MyThread is:

//HEADER
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>

class MyThread : public QThread
{
public:
MyThread(...);

protected:
void run();
};

#endif // MYTHREAD_H


// BODY
#include "mythread.h"

MyThread::MyThread(...)
{
start();
}

void MyThread::run()
{
...
}

Is it right? Have I to call exec() in the run() method? If yes, where?

Thanks,

Dario

wysota
20th April 2010, 12:25
start() should not be called from the constructor, that's for sure. But what is important is the contents of the run() method too.

satoshi
20th April 2010, 12:34
Ok, I've removed the start() method in the constructor of MyThread, now the code is:


MyThread *mt;
for(int i = 0; i < numCores; i++)
{
mt = new MyThread(...);
mt->start();
}

The result is the same, it will only create one new thread (numCores = 2)...

The content of run() isn't nothing special, say for(int i = 0; i < INT_MAX; i++){}

Thanks for the help you're giving me.

Dario

satoshi
20th April 2010, 12:43
I think the problem is the debugger, since if i put numCores = 50, the debugger says that 10 threads has been created. This is too strange to be real, or not?

Anyway, always one core is 100% busy, the second is free.

satoshi
20th April 2010, 12:58
Ok, now I'm sure that the threads are running correctly. With numCores=2, if I put a breakpoint in the execution of the run() method, the debugger will stop there sometimes with one thread (id=4) and sometimes with the other thread (id=5).

Always one core is 100% busy, the second is free.

wysota
20th April 2010, 13:02
Open the task manager, right click on your process and check its processor affinity. Both checkboxes should be checked.

borisbn
20th April 2010, 13:05
1. Use QThread::idealThreadCount (http://qt.nokia.com/doc/4.6/qthread.html#idealThreadCount) to retrieve processors core count
2. I think, that one of your thread doesn't give any time to another. Try to call

msleep( 1 );
inside for in your run functions as following:


for(int i = 0; i < INT_MAX; i++)
{
if ( ( i % 100 ) == 0 )
{
msleep( 1 );
}
}

satoshi
20th April 2010, 13:12
Open the task manager, right click on your process and check its processor affinity. Both checkboxes should be checked.
Both checked


1. Use QThread::idealThreadCount (http://qt.nokia.com/doc/4.6/qthread.html#idealThreadCount) to retrieve processors core count
2. I think, that one of your thread doesn't give any time to another. Try to call

msleep( 1 );
inside for in your run functions as following:


for(int i = 0; i < INT_MAX; i++)
{
if ( ( i % 100 ) == 0 )
{
msleep( 1 );
}
}

Thanks for that but sorry, I just discovered that the threads are running correctly... :)


So, after starting this new 2 thread, I've 4 threads running in the application.

The first thread (which created the second) is waiting for a timer which will timeout in 3 minutes. This is a QApplication.
The second thread (which created the 2 new threads) is waiting for the termination of these new 2 threads (with QWaitCondition), which are calculating and need a lot of CPU.

I'm wondering if the OS is stupid and put the first 2 threads in one core and the others 2 in the other thread...

wysota
20th April 2010, 13:43
The affinity should be dynamically changing to balance the load between two cores. If one thread waits on a wait condition, it is not scheduled by the OS so it won't add to the overall load of the processing unit. Maybe it is your OS that reports usage incorrectly.

spud
20th April 2010, 14:06
start() should not be called from the constructor, that's for sure.
Why not? That way the user of the class cannot forget to call it;).

wysota
20th April 2010, 14:58
For one thing start() calls a method that calls a virtual method. It's true that the virtual method is called on behalf of another thread but I won't guarantee the object will be fully constructed by then. So it might work in 99% of the cases but it will fail when you need it the most (acc. to Murphy's Law).

spud
20th April 2010, 15:10
Ok, fair enough. I can't see that start() calls any virtual methods in Qt 4.6, though.

P.S. I'm not nitpicking, it's just that if it's not safe, I'll have too change a lot of code.

wysota
20th April 2010, 15:16
Ok, fair enough. I can't see that start() calls any virtual methods in Qt 4.6, though.
It calls QThreadPrivate::start() which in turn calls QThread::run() (which is virtual).


P.S. I'm not nitpicking, it's just that if it's not safe, I'll have too change a lot of code.
As I said, in 99% of the cases it will work without problems. But if start subclassing and adding variables, something might explode.

spud
20th April 2010, 15:23
Ok, I see your point.

satoshi
20th April 2010, 22:24
Solved, my fault. The 2 threads wasn't calculating so much, so after 1 second the threads have finished.. And in one second I can't have the time to see the CPU usage in the 2 cores.. :p

Now I have a thread which creates two other threads to make some computation and then I've to continue in the old thread:


Thread #1
... create two threads...
/ \
/ \
/ \
v v
Thread #2 Thread #3
... do some computation...
\ /
\ /
\ /
v v
Thread #1
... use the results of the computation...

In other words, I split the task of computation in two threads to perform it faster. To do this I use a QWaitCondition and two QMutex:

QWaitCondition waitCondition;
QMutex waitConditionMutex, antsFinishedMutex;
int threadFinished = 0;

waitConditionMutex.lock();
//... create two threads...
for(int i = 0; i < numCores; i++)
{
(new MyThread(..., &waitCondition, &threadFinishedMutex, &threadFinished))->start();
}
waitCondition.wait(&waitConditionMutex);
waitConditionMutex.unlock();

//... use the results of the computation...


void MyThread::run()
{
//... do some computation...

threadFinishedMutex->lock();
(*threadFinished)++;
threadFinishedMutex->unlock();

if((*threadFinished) == Thread::idealThreadCount())
{
waitCondition->wakeAll();
}

It works, but it isn't elegant. Is there a better way?

Thanks a lot to all!

Dario

wysota
20th April 2010, 22:29
Yep... It's called QtConcurrent.

satoshi
21st April 2010, 17:35
Yep... It's called QtConcurrent.
That's really fantastic! Works fine ;)

Thanks!!

Dario