Philip
Philip

Reputation: 1921

How can I profile events in a PyQt application?

This stack overflow answer seems to provide a really clean way to monitor the duration of all Qt events in C++. I'm interested in doing something similar in Python for a PyQt5 application.

The high level goal is to have profiling we can optionally enable to get hard numbers for what is making the application feel slow. How long did the paint take? How long did that mouse click take? Any ideas?

Upvotes: 1

Views: 2027

Answers (2)

mfh
mfh

Reputation: 21

Reusing the same QElapsedTimer instance is a bad idea because notify may be called inside of the method itself. In that case start will be called again, which results in incorrect shorter time measurements. Also, I would expect that to cause problems if you are using threads. To avoid all that I would make use of local variables and use time.monotonic instead of QElapsedTimer to measure the time difference.

I ran occasionally into exceptions when I tried calling receiver.objectName() after notify(). Qt complained that receiver had been deleted.

This works for me:

import time
from PyQt5.QtWidgets import QApplication, QPushButton

class MyApplication(QApplication):

    def notify(self, receiver, event):
        eventType = event.type()
        receiverName = receiver.objectName()
        start = time.monotonic()
        ret = QApplication.notify(self, receiver, event)
        end = time.montonic()
        elapsedMSec = (end - start) * 1000
        if(elapsedMSec > 10):
            print(f"processing event type {eventType} for object {receiverName} took {elapsedMSec} msec")
        return ret


if __name__ == "__main__":
    app = MyApplication([])
    ....
    app.exec()

Upvotes: 2

Heike
Heike

Reputation: 24430

You could just pythonify the C++ code in the linked answer:

from PyQt5.QtCore import QElapsedTimer
from PyQt5.QtWidgets import QApplication, QPushButton

class MyApplication(QApplication):

    t = QElapsedTimer()

    def notify(self, receiver, event):
        self.t.start()
        ret = QApplication.notify(self, receiver, event)
        if(self.t.elapsed() > 10):
            print(f"processing event type {event.type()} for object {receiver.objectName()} " 
                  f"took {self.t.elapsed()}ms")
        return ret


if __name__ == "__main__":
    app = MyApplication([])
    ....
    app.exec()

Upvotes: 3

Related Questions