Re: [Interest] Poor QMethod::invoke performance across threads on i.MX53

2015-05-28 Thread Thiago Macieira
On Thursday 28 May 2015 11:28:53 Matthew Woehlke wrote:
 I create an object in Thread 1 (e.g. the main thread). This object is
 memory-owned by T1, i.e. it is expected that T1 will delete the object.

This is what's wrong. T1 *cannot* delete the object that represents T1. If T1 
is trying to delete it, then T1 is running and you have a deadlock.

And you can't have another thread delete it unless you move the object to that 
thread first.
-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel Open Source Technology Center

___
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest


Re: [Interest] Poor QMethod::invoke performance across threads on i.MX53

2015-05-28 Thread Thiago Macieira
On Thursday 28 May 2015 11:31:10 Matthew Woehlke wrote:
  Again missing the move-back.
 
 Why is a move-back needed? What goes sideways without it?

Because you want to destroy the object. You can only destroy a QObject in its 
thread of affinity.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel Open Source Technology Center

___
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest


Re: [Interest] Poor QMethod::invoke performance across threads on i.MX53

2015-05-28 Thread Matthew Woehlke
On 2015-05-28 01:22, Bo Thorsen wrote:
 The finished() signal on QThread - which thread do you expect this to 
 run in? And which thread would you expect a slot connected to it to run in?

I don't understand the question. I would expect that the signal is
executed in the QThread thread. I don't see how anything else is
possible unless some *internal* process causes an event to be queued in
some other thread telling that other thread (which must be running an
event loop?) to emit the signal instead. Is this the case?

 [...] you can only have a single reason left for 
 moveToThread(this): Signals and slots on the QThread. Refactor your code 
 and create another object that does all the work you put in the run instead.

I don't think you understand what I am actually doing.

I create an object in Thread 1 (e.g. the main thread). This object is
memory-owned by T1, i.e. it is expected that T1 will delete the object.
This object internally encapsulates a QThread, T2, to which it moves
itself upon construction. Slots belonging to the object are thus
executed in T2.

AFAICT this works fine, or at least I have yet to encounter any
noticeable issues with this approach. Am I missing something?

-- 
Matthew

___
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest


Re: [Interest] Poor QMethod::invoke performance across threads on i.MX53

2015-05-27 Thread Matthew Woehlke
On 2015-05-18 03:46, Thiago Macieira wrote:
 On Thursday 14 May 2015 18:18:52 Robert Daniels wrote:
 moveToThread(this);
 
 This is wrong. Never do moveToThread(this), since it's very difficult to 
 then 
 destroy the QThread object. This is unrelated to the problem and it's 
 probably 
 only for simplicity of your testcase.

Sort of OT, but... why? If the object in question is destroyed by the
same thread that created it, after the thread that the object
represents has terminated cleanly, what is the problem?

(I have my own code that is potentially affected by this... I'm not
doing a *literal* self-owning object, but I have an object which owns
a thread and lives on that same thread. I don't try to destroy said
object from its thread, however, but rather the thread that created
the object.)

-- 
Matthew

___
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest


Re: [Interest] Poor QMethod::invoke performance across threads on i.MX53

2015-05-27 Thread Thiago Macieira
On Wednesday 27 May 2015 15:02:36 Matthew Woehlke wrote:
 On 2015-05-18 03:46, Thiago Macieira wrote:
  On Thursday 14 May 2015 18:18:52 Robert Daniels wrote:
  moveToThread(this);
  
  This is wrong. Never do moveToThread(this), since it's very difficult to
  then destroy the QThread object. This is unrelated to the problem and
  it's probably only for simplicity of your testcase.
 
 Sort of OT, but... why? If the object in question is destroyed by the
 same thread that created it, after the thread that the object
 represents has terminated cleanly, what is the problem?

The problem is a QThread living inside the thread that it started.

You can't destroy that object inside that thread because the QThread 
destructor will wait() until the thread exits. And the thread can't exit until 
the destructor has returned. That's a deadlock.

The correct way to dispose of the thread that did moveToThread(this); is:

void MyThread::run()
{
exec(); // or do whatever work you want to do
connect(this, QThread::finished, this, QObject::deleteLater);
moveToThread(QCoreApplication::instance()-thread());
}

This assumes that the main thread isn't blocked and is still processing 
events. In fact, it assumes that QCoreApplication::instance() isn't being 
destroyed, otherwise you have a race condition.

You can't do moveToThread(nullptr) because you need queued delivery in order 
to call deleteLater() *after* finished() has finished emitting.

Another way, without subclassing:

class ThreadManager
{
Q_OBJECT
QThread thr;

public:
void doit()
{
connect(thr, QThread::finished,
[this]() { 
thr-moveToThread(this-thread()); 
this-deleteLater();
})
thr.moveToThread(thr);
thr.start();
}
};

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel Open Source Technology Center

___
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest


Re: [Interest] Poor QMethod::invoke performance across threads on i.MX53

2015-05-27 Thread Matthew Woehlke
On 2015-05-27 16:41, Thiago Macieira wrote:
 On Wednesday 27 May 2015 15:02:36 Matthew Woehlke wrote:
 On 2015-05-18 03:46, Thiago Macieira wrote:
 On Thursday 14 May 2015 18:18:52 Robert Daniels wrote:
 moveToThread(this);

 This is wrong. Never do moveToThread(this), since it's very difficult to
 then destroy the QThread object. This is unrelated to the problem and
 it's probably only for simplicity of your testcase.

 Sort of OT, but... why? If the object in question is destroyed by the
 same thread that created it, after the thread that the object
 represents has terminated cleanly, what is the problem?
 
 The problem is a QThread living inside the thread that it started.
 
 You can't destroy that object inside that thread because the QThread 
 destructor will wait() until the thread exits. And the thread can't exit 
 until 
 the destructor has returned. That's a deadlock.

Right. An example probably helps. What's wrong with this approach?

  class MyThread : public QThread { ... } // has moveToThread(this)

  int main()
  {
auto* t = new MyThread;
t.start();
// ...
t.wait();
delete t; // QThread deleted from main thread, not itself
  }

The QThread is memory-managed from a thread other than itself. It's just
that the thread affinity is circular. Note that I am *NOT* trying to
deleteLater the QObject! (Because, yes, that would be horrible! And for
that matter, would leak, since in my usage, the thread has exited before
I try to delete it.)

Anyway, a more accurate depiction of my case is:

  class MyThread : public QObject
  {
QThread self;
MyThread() { moveToThread(self); }
  }

...where again, it is assumed that MyThread is deleted from a thread
other than MyThread::self. Is this approach broken? (I think no? It
seems similar to the alternate approach you gave.)

-- 
Matthew

___
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest


Re: [Interest] Poor QMethod::invoke performance across threads on i.MX53

2015-05-27 Thread Bo Thorsen
Den 27-05-2015 kl. 23:16 skrev Matthew Woehlke:
 On 2015-05-27 16:41, Thiago Macieira wrote:
 On Wednesday 27 May 2015 15:02:36 Matthew Woehlke wrote:
 On 2015-05-18 03:46, Thiago Macieira wrote:
 On Thursday 14 May 2015 18:18:52 Robert Daniels wrote:
  moveToThread(this);

 This is wrong. Never do moveToThread(this), since it's very difficult to
 then destroy the QThread object. This is unrelated to the problem and
 it's probably only for simplicity of your testcase.

 Sort of OT, but... why? If the object in question is destroyed by the
 same thread that created it, after the thread that the object
 represents has terminated cleanly, what is the problem?

 The problem is a QThread living inside the thread that it started.

 You can't destroy that object inside that thread because the QThread
 destructor will wait() until the thread exits. And the thread can't exit 
 until
 the destructor has returned. That's a deadlock.

 Right. An example probably helps. What's wrong with this approach?

class MyThread : public QThread { ... } // has moveToThread(this)

int main()
{
  auto* t = new MyThread;
  t.start();
  // ...
  t.wait();
  delete t; // QThread deleted from main thread, not itself
}

 The QThread is memory-managed from a thread other than itself. It's just
 that the thread affinity is circular. Note that I am *NOT* trying to
 deleteLater the QObject! (Because, yes, that would be horrible! And for
 that matter, would leak, since in my usage, the thread has exited before
 I try to delete it.)

 Anyway, a more accurate depiction of my case is:

class MyThread : public QObject
{
  QThread self;
  MyThread() { moveToThread(self); }
}

 ...where again, it is assumed that MyThread is deleted from a thread
 other than MyThread::self. Is this approach broken? (I think no? It
 seems similar to the alternate approach you gave.)

There are a lot of problems with this. Thiago already gave you a couple 
of them. Here are two more:

The finished() signal on QThread - which thread do you expect this to 
run in? And which thread would you expect a slot connected to it to run in?

What about objects with your thread as parent? Those will all be deleted 
by the wrong thread. If you delete them all before the thread itself is 
deleted, then you can only have a single reason left for 
moveToThread(this): Signals and slots on the QThread. Refactor your code 
and create another object that does all the work you put in the run instead.

QThread is an object that you should think of as living between the two 
threads. The object itself is running in the creating thread, anything 
in run() and objects moved to this thread is in the created thread. The 
signals it emits have clearly defined threads they are emitted in - 
finished() in the creating thread, started() in the created etc.

It's not that you can't create code with your way that will work. It's 
more that it will be impossible for anyone schooled in the proper way 
of thinking to know what's going on. You will create weird bugs that are 
very hard to fix with this approach.

Bo.

-- 
Viking Software
Qt and C++ developers for hire
http://www.vikingsoft.eu
___
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest


Re: [Interest] Poor QMethod::invoke performance across threads on i.MX53

2015-05-27 Thread Thiago Macieira
On Wednesday 27 May 2015 17:16:54 Matthew Woehlke wrote:
 Right. An example probably helps. What's wrong with this approach?
 
   class MyThread : public QThread { ... } // has moveToThread(this)
 
   int main()
   {
 auto* t = new MyThread;
 t.start();
 // ...
 t.wait();
 delete t; // QThread deleted from main thread, not itself
   }

You cannot delete t; while the t object is associated with the other thread.

Do you have a moveToThread(nullptr) or moveToThread(mainThread)? If so, where? 
That's what my examples were trying to show.

 The QThread is memory-managed from a thread other than itself. It's just
 that the thread affinity is circular. Note that I am *NOT* trying to
 deleteLater the QObject! (Because, yes, that would be horrible! And for
 that matter, would leak, since in my usage, the thread has exited before
 I try to delete it.)
 
 Anyway, a more accurate depiction of my case is:
 
   class MyThread : public QObject
   {
 QThread self;
 MyThread() { moveToThread(self); }
   }
 
 ...where again, it is assumed that MyThread is deleted from a thread
 other than MyThread::self. Is this approach broken? (I think no? It
 seems similar to the alternate approach you gave.)

Again missing the move-back.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel Open Source Technology Center

___
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest


Re: [Interest] Poor QMethod::invoke performance across threads on i.MX53

2015-05-18 Thread Thiago Macieira
On Thursday 14 May 2015 18:18:52 Robert Daniels wrote:
 I'm working on a project that uses a QThread to process communication over a
 TCP connection. In trying to improve performance I've tracked down an odd
 slow-down when we use QMethod::invoke to force a method to be called on the
 correct thread.

You don't need threads to get acceptable performance of TCP. The networking is 
usually much slower than the processing itself.

 This is an embedded project running on a Freescale i.MX53.  On this board,
 I've measured the time to make this call and it is on average around 40
 ns. I've measured this on our i.MX6 board as well (with only one core
 enabled) and it takes only 6 ns. This doesn't look right to me. I would
 expect the difference to be at most 2x, not 6x.

Can you benchmark this in any way? What is consuming CPU time here? Is it in 
kernel mode? Is it waiting? Is it the QSemaphore inside the blocking queued 
connection

 Is there something I'm missing here in my expectations or is there something
 fundamentally wrong causing this slow-down?

There are problems, but not related to the issue you're reporting.

 class WorkerThread : public QThread
 {
 Q_OBJECT
 
 public:
 WorkerThread()
 {
 moveToThread(this);

This is wrong. Never do moveToThread(this), since it's very difficult to then 
destroy the QThread object. This is unrelated to the problem and it's probably 
only for simplicity of your testcase.

 private slots:
 void onTimer()
 {
 qDebug()  Begin test.;
 QElapsedTimer timer;
 qint64 total = 0;
 const int cnt = 10;
 
 for (int i = 0; i  cnt; i++) {
 timer.start();
 worker.myMethod(i);
 total += timer.nsecsElapsed();

nsecsElapsed may not have enough resolution on your board. The problem might 
not be slowness, but simply that the clock isn't good enough.

Move the timer.start() and timer.elapsed() calls outside of the loop.

And please check with your admins if they can remove this message in emails 
you send to the public, which are archived and distributed all over the 
Internet:

 Ce message, ainsi que tous les fichiers joints à ce message, peuvent
 contenir des informations sensibles et/ ou confidentielles ne devant pas
 être divulguées. Si vous n'êtes pas le destinataire de ce message (ou que
 vous recevez ce message par erreur), nous vous remercions de le notifier
 immédiatement à son expéditeur, et de détruire ce message. Toute copie,
 divulgation, modification, utilisation ou diffusion, non autorisée, directe
 ou indirecte, de tout ou partie de ce message, est strictement interdite.
 Se désabonner: Si vous souhaitez être retiré de notre liste de diffusion,
 s'il vous plaît envoyer vos coordonnées à
 casl.unsubscr...@legrand.camailto:casl.unsubscr...@legrand.ca et indiquer
 quels sont les messages que vous ne souhaitez plus recevoir.
 
 
 This e-mail, and any document attached hereby, may contain confidential

PS: hereto, not hereby.

 and/or privileged information. If you are not the intended recipient (or
 have received this e-mail in error) please notify the sender immediately
 and destroy this e-mail. Any unauthorized, direct or indirect, copying,
 disclosure, distribution or other use of the material or parts thereof is
 strictly forbidden. Unsubscribe: If you would like to be removed from our
 mailing list, please send your contact information to
 casl.unsubscr...@legrand.camailto:casl.unsubscr...@legrand.ca and
 indicate what messages you no longer wish to receive.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel Open Source Technology Center

___
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest


[Interest] Poor QMethod::invoke performance across threads on i.MX53

2015-05-18 Thread Robert Daniels

I'm working on a project that uses a QThread to process communication over a 
TCP connection. In trying to improve performance I've tracked down an odd 
slow-down when we use QMethod::invoke to force a method to be called on the 
correct thread.

This is an embedded project running on a Freescale i.MX53.  On this board, I've 
measured the time to make this call and it is on average around 40 ns. I've 
measured this on our i.MX6 board as well (with only one core enabled) and it 
takes only 6 ns. This doesn't look right to me. I would expect the 
difference to be at most 2x, not 6x.

Is there something I'm missing here in my expectations or is there something 
fundamentally wrong causing this slow-down?

I'm including my test code which I've run on both targets. In the sample code 
I'm using Qt::BlockingQueuedConnection when calling invoke - normally we don't 
do that but for the test it makes it much simpler to see the effect of the 
slow-down.

- Robert Daniels

#include QCoreApplication
#include QThread
#include QMetaMethod
#include QDebug
#include QTimer
#include QElapsedTimer

class WorkerThread : public QThread
{
Q_OBJECT

public:
WorkerThread()
{
moveToThread(this);
method = 
metaObject()-method(metaObject()-indexOfMethod(myMethod(int)));
start();
sum = 0;
qDebug()  Started Worker Thread.;
}

Q_INVOKABLE void myMethod(int test)
{
if (currentThread() != this) {
method.invoke(this, Qt::BlockingQueuedConnection, Q_ARG(int, test));
} else {
sum += test;
}
}

int getSum() { return sum; }
private:
QMetaMethod method;
int sum;
};

class Test : public QObject
{
Q_OBJECT

public:
Test()
{
QTimer *timer = new QTimer(this);

timer-setInterval(10);
connect(timer, SIGNAL(timeout()), SLOT(onTimer()));
timer-start();
}

private slots:
void onTimer()
{
qDebug()  Begin test.;
QElapsedTimer timer;
qint64 total = 0;
const int cnt = 10;

for (int i = 0; i  cnt; i++) {
timer.start();
worker.myMethod(i);
total += timer.nsecsElapsed();
}

qDebug()  Average ms:  (total / cnt)  sum =  
worker.getSum();

worker.exit();
QCoreApplication::exit();
}

private:
WorkerThread worker;
};

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

Test test;

return a.exec();
}

#include main.moc



Ce message, ainsi que tous les fichiers joints à ce message, peuvent contenir 
des informations sensibles et/ ou confidentielles ne devant pas être 
divulguées. Si vous n'êtes pas le destinataire de ce message (ou que vous 
recevez ce message par erreur), nous vous remercions de le notifier 
immédiatement à son expéditeur, et de détruire ce message. Toute copie, 
divulgation, modification, utilisation ou diffusion, non autorisée, directe ou 
indirecte, de tout ou partie de ce message, est strictement interdite.
Se désabonner: Si vous souhaitez être retiré de notre liste de diffusion, s'il 
vous plaît envoyer vos coordonnées à 
casl.unsubscr...@legrand.camailto:casl.unsubscr...@legrand.ca et indiquer 
quels sont les messages que vous ne souhaitez plus recevoir.


This e-mail, and any document attached hereby, may contain confidential and/or 
privileged information. If you are not the intended recipient (or have received 
this e-mail in error) please notify the sender immediately and destroy this 
e-mail. Any unauthorized, direct or indirect, copying, disclosure, distribution 
or other use of the material or parts thereof is strictly forbidden.
Unsubscribe: If you would like to be removed from our mailing list, please send 
your contact information to 
casl.unsubscr...@legrand.camailto:casl.unsubscr...@legrand.ca and indicate 
what messages you no longer wish to receive.
___
Interest mailing list
Interest@qt-project.org
http://lists.qt-project.org/mailman/listinfo/interest