[prev in list] [next in list] [prev in thread] [next in thread]
List: pykde
Subject: Re: [PyQt] QGraphicsView very slow under Linux and Mac OS X
From: Clemens Brunner <clemens.brunner () tugraz ! at>
Date: 2013-07-18 9:10:25
Message-ID: A69DF924-8064-40D2-810A-018AF16FBB72 () tugraz ! at
[Download RAW message or body]
Hi!
I investigated the problem a bit more, and it seems like it occurs only =
when I'm running KDE -- in Gnome, everything works as expected (the =
difference is 1). Since it is now working on both Windows, Mac OS X, and =
non-KDE systems, it is probably related to KDE (maybe the window =
manager). Funny though, since KDE is based on Qt :-).
So if anyone running KDE wants to confirm the problem, I've attached the =
test program again.
Concerning the C++ version, the problem is also there on KDE, only you =
don't see it when just looking at the timer intervals (because they're =
always 25ms irrespective of the window size). However, the exposedRect =
on KDE is still wrong, so I assume that the C++ is just a lot faster so =
that performance is not (yet) affected in my example.
Clemens
["graphicsviewtest.py" (graphicsviewtest.py)]
import sys
from PyQt4 import QtGui, QtCore
import random
import math
class SignalItem(QtGui.QGraphicsItem):
def __init__(self, nr):
super(SignalItem, self).__init__()
self.setFlags(QtGui.QGraphicsItem.ItemUsesExtendedStyleOption)
self.nr = nr
self.fr = random.randint(3, 50)
self.bg = QtGui.QColor(random.randint(200,255),random.randint(200,255),random.randint(200,255))
def boundingRect(self):
return QtCore.QRectF(0, self.nr*50, 10000, 50)
def paint(self, painter, option, widget):
painter.fillRect(option.exposedRect, self.bg)
self.prevY = math.sin((int(option.exposedRect.left()) - 1)/float(self.fr))*10 + 25 + self.nr*50
print(int(option.exposedRect.right()) - int(option.exposedRect.left()))
for x in range(int(option.exposedRect.left()), int(option.exposedRect.right())):
y = math.sin(x/float(self.fr))*10 + 25 + self.nr*50
painter.drawLine(x-1, self.prevY, x, y)
self.prevY = y
class Dummy(QtCore.QObject):
def __init__(self):
super(Dummy, self).__init__()
self.scene = QtGui.QGraphicsScene()
for i in range(40):
item = SignalItem(i)
self.scene.addItem(item)
self.view = QtGui.QGraphicsView(self.scene)
self.view.show()
self.startTimer(25)
self.x = 0
self.lastTimerEvent = None
def timerEvent(self,event):
self.x += 1
self.view.horizontalScrollBar().setValue(self.x)
#currentTime = QtCore.QTime.currentTime()
#if self.lastTimerEvent:
# print self.lastTimerEvent.msecsTo(currentTime)
#self.lastTimerEvent = currentTime
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
d = Dummy()
sys.exit(app.exec_())
On 04/05/2013 08:33 PM, Clemens Brunner wrote:
> Hi!
>
> I think I found the problem: https://bugreports.qt-project.org/browse/QTBUG-13573
>
> The exposedRect returns the whole window width on Linux and Mac OS X, whereas it \
> correctly returns only the area that needs to be updated on Windows.
> To illustrate this, just add the following line to my example code within the \
> paint() function just before the for loop:
> print int(option.exposedRect.right()) - int(option.exposedRect.left())
>
> On Windows, this is always 1, as expected. On Linux, this corresponds to the window \
> width.
> This bug explains why it is so damn slow. However, it doesn't seem to occur on all \
> Linux platforms, since you guys get timer intervals as expected. Maybe you want to \
> check the output of the print statement above, but I assume it is 1 on your \
> platform. Which leads me to the question: how can we fix this bug? Or is there at \
> least a workaround?
> I suspect that it might have something to do with the Intel graphics chip, which I \
> have in both my Linux and Mac machine.
> [Update:] I just tested the behavior on my Mac again: in the first second, I get \
> the whole width for the exposedRect and large timer intervals (and therefore slow \
> performance). However, after about a second, I get the correct value of 1, because \
> Mac OS X switches from the Intel onboard chip to the nVidia graphics chip. This is \
> just a speculation, because disabling graphics switching (which should permanently \
> enable the nVidia chip) yields the same behavior. Strangely though, it does work on \
> my Mac now after this initial second (maybe some updated got installed that fixed \
> the problem?).
> Any more ideas?
>
> Clemens
>
>
>
> On Apr 4, 2013, at 17:15 , Clemens Brunner <clemens.brunner@tugraz.at> wrote:
>
> > On 04/03/2013 06:46 PM, Hans-Peter Jansen wrote:
> >
> > > Which graphic driver do you use? (that doesn't tell us much, since the C++
> > > version behave with the same driver, just for the record..)
> >
> > xf86-video-intel 2.21.5-1
> > intel-dri 9.1.1-1
> >
> > > Might be worth to compare the C++ version (that you should publish hereš)
> > > and the Python versions with perf. Of course, they differ...
> >
> > Attached.
> >
> > > python versions, perf running for about 10 sec.
> > >
> > > QT_GRAPHICSSYSTEM=raster perf record -f python graphicsviewtest.py
> > >
> > > [...]
> > >
> > >
> > > QT_GRAPHICSSYSTEM=opengl perf record -f python graphicsviewtest.py
> > >
> > > [...]
> > >
> > >
> > > The former looks nice, it's a great example, why PyQt rocks. The hottest
> > > areas are there, where they should be: down under, moving bits. Great.
> > >
> > > But the latter looks strange indeed.
> > >
> > > Phil, do you have any idea, why PyEval_EvalFrameEx is the top sucker in
> > > this scenario? This looks, like in opengl mode, it is evaluating some
> > > python expression in its hottest path (data type conversions or the like?).
> >
> > My raster perf report doesn't look nice at all:
> >
> > 14.30% python2 libpython2.7.so.1.0 [.] PyEval_EvalFrameEx
> > 9.39% python2 libQtGui.so.4.8.4 [.] 0x00000000001bf673
> > 8.99% python2 sip.so [.] 0x000000000000b086
> > 6.10% python2 libpython2.7.so.1.0 [.] lookdict_string
> > 4.02% python2 libpython2.7.so.1.0 [.] PyDict_GetItem
> > 3.94% python2 libpython2.7.so.1.0 [.] _PyType_Lookup
> > 3.01% python2 libm-2.17.so [.] 0x00000000000105e0
> > 2.27% python2 libm-2.17.so [.] feraiseexcept
> > 2.23% python2 libpython2.7.so.1.0 [.] _PyObject_GenericGetAttrWithDict
> > 1.71% python2 libpython2.7.so.1.0 [.] binary_op1
> > 1.50% python2 libpython2.7.so.1.0 [.] PyType_IsSubtype
> > 1.40% python2 libpython2.7.so.1.0 [.] PyErr_Restore
> > 1.33% python2 QtGui.so [.] 0x000000000036120b
> > 1.27% python2 libpython2.7.so.1.0 [.] PyObject_Malloc
> > 1.19% python2 libc-2.17.so [.] malloc
> >
> > Same thing but even worse with opengl:
> >
> > 15.49% python2 i965_dri.so [.] 0x000000000003ae99
> > 6.08% python2 libpython2.7.so.1.0 [.] PyEval_EvalFrameEx
> > 5.96% python2 libdrm_intel.so.1.0.0 [.] 0x0000000000007468
> > 5.60% python2 libQtOpenGL.so.4.8.4 [.] 0x0000000000031262
> > 4.96% python2 sip.so [.] 0x000000000000b055
> > 4.32% python2 libdricore9.1.1.so.1.0.0 [.] 0x00000000001ea2b4
> > 2.76% python2 libpython2.7.so.1.0 [.] lookdict_string
> > 2.11% python2 libpython2.7.so.1.0 [.] PyDict_GetItem
> > 1.95% python2 libpython2.7.so.1.0 [.] _PyType_Lookup
> > 1.42% python2 libm-2.17.so [.] 0x00000000000105c0
> > 1.32% python2 libc-2.17.so [.] __memcmp_sse4_1
> > 1.03% python2 libc-2.17.so [.] _int_malloc
> > 1.01% python2 libm-2.17.so [.] feraiseexcept
> > 0.93% python2 libc-2.17.so [.] __memcpy_ssse3_back
> >
> > In both cases, PyEval_EvalFrameEx is at or near the top, and so are other Python \
> > things.
> > For the sake of completeness, here's the perf output for the C++ version (which \
> > runs perfectly):
> > 43.56% graphicsviewtes libQtGui.so.4.8.4 [.] 0x00000000001c0bb2 \
> > q 20.58% graphicsviewtes libm-2.17.so [.] feraiseexcept
> > 15.48% graphicsviewtes libm-2.17.so [.] 0x0000000000015622
> > 4.47% graphicsviewtes graphicsviewtest [.] \
> > SignalItem::paint(QPainter*, QStyleOptionGraphicsItem 3.09% graphicsviewtes \
> > libQtGui.so.4.8.4 [.] QPen::dashPattern() const 1.17% graphicsviewtes \
> > libQtGui.so.4.8.4 [.] QTransform::map(QPointF const&) const 0.77% \
> > graphicsviewtes libc-2.17.so [.] free 0.72% graphicsviewtes \
> > libQtGui.so.4.8.4 [.] QPainter::drawLines(QLine const*, int) 0.46% \
> > graphicsviewtes libpthread-2.17.so [.] __pthread_mutex_unlock_usercnt \
> > 0.45% graphicsviewtes libpthread-2.17.so [.] pthread_mutex_lock
> > I tested this program on openSUSE (in a VirtualBox), and in contrast to Vincent, \
> > it doesn't work for me there either (same behavior as in my native Arch Linux). \
> > BTW, I use KDE and not Gnome, but I doubt that this is relevant. Furthermore, I \
> > still have the same bad behavior on my Mac.
> > Clemens
> > <graphicsviewtest.cpp><graphicsviewtest.pro>
>
["graphicsviewtest.py" (graphicsviewtest.py)]
import sys
from PySide import QtGui, QtCore
import random
import math
class SignalItem(QtGui.QGraphicsItem):
def __init__(self, nr):
super(SignalItem, self).__init__()
self.setFlags(QtGui.QGraphicsItem.ItemUsesExtendedStyleOption)
self.nr = nr
self.fr = random.randint(3, 50)
self.bg = QtGui.QColor(random.randint(200,255),random.randint(200,255),random.randint(200,255))
def boundingRect(self):
return QtCore.QRectF(0, self.nr*50, 10000, 50)
def paint(self, painter, option, widget):
painter.fillRect(option.exposedRect, self.bg)
self.prevY = math.sin((int(option.exposedRect.left()) - 1)/float(self.fr))*10 + 25 + self.nr*50
print int(option.exposedRect.right()) - int(option.exposedRect.left())
for x in range(int(option.exposedRect.left()), int(option.exposedRect.right())):
y = math.sin(x/float(self.fr))*10 + 25 + self.nr*50
painter.drawLine(x-1, self.prevY, x, y)
self.prevY = y
class Dummy(QtCore.QObject):
def __init__(self):
super(Dummy, self).__init__()
self.scene = QtGui.QGraphicsScene()
for i in range(40):
item = SignalItem(i)
self.scene.addItem(item)
self.view = QtGui.QGraphicsView(self.scene)
self.view.show()
self.startTimer(25)
self.x = 0
self.lastTimerEvent = None
def timerEvent(self,event):
self.x += 1
self.view.horizontalScrollBar().setValue(self.x)
#currentTime = QtCore.QTime.currentTime()
#if self.lastTimerEvent:
# print self.lastTimerEvent.msecsTo(currentTime)
#self.lastTimerEvent = currentTime
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
d = Dummy()
sys.exit(app.exec_())
_______________________________________________
PyQt mailing list PyQt@riverbankcomputing.com
http://www.riverbankcomputing.com/mailman/listinfo/pyqt
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic