Discussion:
[pyqtgraph] Slower update performance with ImageExporter than GUI window
jimbo1qaz
2018-11-22 05:50:52 UTC
Permalink
I'm developing an audio oscilloscope-type program, which outputs frames as
raw bytes to ffmpeg and ffplay (which plays back video and audio together,
synchronized). I can also tell ffmpeg to output to file instead.

Originally I used matplotlib. I tried switching to pyqtgraph because I
thought it would be faster.

Unfortunately it ended up too slow for my use case.

- Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz, turbo 2.70GHz
- Windows 10 x64 (I can try Kubuntu 18.04 later)
- Miniconda Python 3.6.6
- pyqtgraph 0.11.0.dev0+g2e69b9c

I adapted pyqtgraph's speed test to resemble my data more closely (hide all
axises, no title, don't write fps to canvas):

-
https://gist.github.com/jimbo1qaz/472242d89a8fde421c39b4f86bf48b0e#file-pyqtgraph-speed-gui-py
- output to GUI
- 200-300fps
-
https://gist.github.com/jimbo1qaz/472242d89a8fde421c39b4f86bf48b0e#file-pyqtgraph-speed-image-py
- output to QImage
- starts at 766.36 fps, declines to 40-80fps (randomly toggles every
few seconds, may possibly depend on window focus)

In my own app rendering tests, I usually get 50-120fps, depending on data
and number of plots. In any case, this is far worse than matplotlib with
axis drawing disabled (118-158fps).

In either case, stopping in PyCharm (which sends Ctrl+C) results in
"Process finished with exit code -1" instead of a stacktrace, which
prevents me from taking a cProfile snapshot of my above speed demo.

I attached 2 cProfile logs. I closed the GUI after an approximate amount of
time, and terminated the QImage code using "for i in range(600)".
--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/055c582e-5018-4c37-a977-6b07062e103e%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
jimbo1qaz
2018-11-22 07:08:38 UTC
Permalink
I've attached new profiles, where both GUI and QImage run 600 times.

Source at https://gist.github.com/jimbo1qaz/a5d041032ba9244c0a67eeb8455e923d
Post by jimbo1qaz
I'm developing an audio oscilloscope-type program, which outputs frames as
raw bytes to ffmpeg and ffplay (which plays back video and audio together,
synchronized). I can also tell ffmpeg to output to file instead.
Originally I used matplotlib. I tried switching to pyqtgraph because I
thought it would be faster.
Unfortunately it ended up too slow for my use case.
- Windows 10 x64 (I can try Kubuntu 18.04 later)
- Miniconda Python 3.6.6
- pyqtgraph 0.11.0.dev0+g2e69b9c
I adapted pyqtgraph's speed test to resemble my data more closely (hide
-
https://gist.github.com/jimbo1qaz/472242d89a8fde421c39b4f86bf48b0e#file-pyqtgraph-speed-gui-py
- output to GUI
- 200-300fps
-
https://gist.github.com/jimbo1qaz/472242d89a8fde421c39b4f86bf48b0e#file-pyqtgraph-speed-image-py
- output to QImage
- starts at 766.36 fps, declines to 40-80fps (randomly toggles
every few seconds, may possibly depend on window focus)
In my own app rendering tests, I usually get 50-120fps, depending on data
and number of plots. In any case, this is far worse than matplotlib with
axis drawing disabled (118-158fps).
In either case, stopping in PyCharm (which sends Ctrl+C) results in
"Process finished with exit code -1" instead of a stacktrace, which
prevents me from taking a cProfile snapshot of my above speed demo.
I attached 2 cProfile logs. I closed the GUI after an approximate amount
of time, and terminated the QImage code using "for i in range(600)".
--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/1b0b5e97-394f-40a5-9fcf-e0ba0763e34e%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
jimbo1qaz
2018-11-23 10:16:50 UTC
Permalink
It turns out ImageExporter is terribly optimized for speed. I assume the
authors designed it to be acceptable for one-shot screenshots, and never
tested it for exporting animations.

- Initializing image to background color:
- buf[:,:,0] = color.red()...etc. is slow.
- Solution? QImage.fill(color) is near-instant.
- GUI plots render to QPixmap (GPU/etc texture), and no copy is
performed?. Image plots are inherently slower since they require copying to
QImage (memory buffer).
- This is very slow with Format_ARGB32, but much faster with
Format_RGB32.
- Solution: I create QImage(w, h, Format_RGB32) without passing in
`bg` ndarray.
- Speed of various QImage formats:
- Format_RGB32 = 280fps or less
- Format_ARGB32 = 150fps or less
- Format_RGB888 = 110fps
- I have no need for an alpha channel when piping video frames to
ffmpeg, and I doubt many plots have transparent backgrounds.
- Initializes `self.bg` buffer and `self.png` QImage, and overwrites
with new objects during next screenshot (discards local QPainter too, but
it isn't a major slowdown)
- Not 100% sure if this causes slowdown. Changing QPainter(QPixmap())
and calling qpixmap.toImage() performs wasteful allocations? but isn't
noticeably slower than my final solution.
- Solution? Save and reuse QPainter and QImage (I renamed self.png to
qimage, and self.painter).
- Delete variable self.bg, since I let QImage allocate memory.
- self.setExportMode() is slow, but is called twice per screenshot
(once to enable, once to disable).
- Solution? Call it once during the first screenshot, and never turn
it back off.
- This is not an issue for me, since I never display the widgets
in a window.
- You could move enabling/disabling setExportMode to a `with`
statement, which Exporter callers are required to use.
- Called every frame: 180fps
- Called once: 250fps
- Not called: 200fps?

Source code for my modified ImageExporter:
https://gist.github.com/jimbo1qaz/24b0f74dfac8d48dc998bcf6a9451f96
Post by jimbo1qaz
I'm developing an audio oscilloscope-type program, which outputs frames as
raw bytes to ffmpeg and ffplay (which plays back video and audio together,
synchronized). I can also tell ffmpeg to output to file instead.
Originally I used matplotlib. I tried switching to pyqtgraph because I
thought it would be faster.
Unfortunately it ended up too slow for my use case.
- Windows 10 x64 (I can try Kubuntu 18.04 later)
- Miniconda Python 3.6.6
- pyqtgraph 0.11.0.dev0+g2e69b9c
I adapted pyqtgraph's speed test to resemble my data more closely (hide
-
https://gist.github.com/jimbo1qaz/472242d89a8fde421c39b4f86bf48b0e#file-pyqtgraph-speed-gui-py
- output to GUI
- 200-300fps
-
https://gist.github.com/jimbo1qaz/472242d89a8fde421c39b4f86bf48b0e#file-pyqtgraph-speed-image-py
- output to QImage
- starts at 766.36 fps, declines to 40-80fps (randomly toggles
every few seconds, may possibly depend on window focus)
In my own app rendering tests, I usually get 50-120fps, depending on data
and number of plots. In any case, this is far worse than matplotlib with
axis drawing disabled (118-158fps).
In either case, stopping in PyCharm (which sends Ctrl+C) results in
"Process finished with exit code -1" instead of a stacktrace, which
prevents me from taking a cProfile snapshot of my above speed demo.
I attached 2 cProfile logs. I closed the GUI after an approximate amount
of time, and terminated the QImage code using "for i in range(600)".
--
You received this message because you are subscribed to the Google Groups "pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyqtgraph+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pyqtgraph/f8aca7b9-f044-485c-8e5c-fe0aab3ab5fb%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Loading...