obsproject / obsproject/obs-studio

Qt GUI burns most of a CPU core repeatedly decoding icons

Open
#12,758 18 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

issue/confirmed
Dominant language
C
Stars
76.4k
Forks
10.2k
Avg merge
4d 23h
Merged PRs (30d)
12

Description

Operating System Info

Other

Other OS

Arch Linux

OBS Studio Version

32.0.0

OBS Studio Version (Other)

32.0.1

OBS Studio Log URL

https://obsproject.com/logs/ptpJ2CITAoHKvmns

OBS Studio Crash Log URL

No response

Expected Behavior

OBS Studio does not burn a CPU core decoding icons.

Current Behavior

OBS Studio burns most of a CPU core. Samply profiler shows most of it is spent in QStyleSheetStyle::drawControl(QStyle::ControlElement, QStyleOption const*, QPainter*, QWidget const*) const ... QFusionStyle::standardIcon(QStyle::StandardPixmap, QStyleOption const*, QWidget const*) const ... QFusionStyle::iconFromTheme(QStyle::StandardPixmap) const ... QResourceFileEngine::open(QFlags<QIODeviceBase::OpenModeFlag>, std::optional<QFlags<QFileDevice::Permission> >).

Profiler screenshot:
Image

Manual sampling by hitting Ctrl+C in gdb replicated these results; OBS used 60% of my CPU, and two out of four Ctrl+C backtraces were in QFusionStyle::iconFromTheme.

Example backtrace:

(gdb) bt
#0  simdSwapLoop<unsigned short> (src=0x7fffdda75626 <qt_resource_name+6> "", bytes=28, dst=0x555558665750 "q") at /usr/src/debug/qt6-base/qtbase/src/corelib/global/qendian.cpp:825
#1  bswapLoop<unsigned short> (src=0x7fffdda75626 <qt_resource_name+6> "", n=28, dst=0x555558665750 "q") at /usr/src/debug/qt6-base/qtbase/src/corelib/global/qendian.cpp:852
#2  qbswap<2> (source=0x7fffdda75626 <qt_resource_name+6>, n=<optimized out>, dest=0x555558665750) at /usr/src/debug/qt6-base/qtbase/src/corelib/global/qendian.cpp:865
#3  0x00007ffff2d3f941 in qFromBigEndian<char16_t> (source=<optimized out>, count=14, dest=<optimized out>) at /usr/src/debug/qt6-base/qtbase/src/corelib/global/qendian.h:213
#4  (anonymous namespace)::QResourceRoot::name (this=<optimized out>, node=1) at /usr/src/debug/qt6-base/qtbase/src/corelib/io/qresource.cpp:788
#5  (anonymous namespace)::QResourceRoot::findNode (this=this@entry=0x555555adadd0, _path=..., locale=...) at /usr/src/debug/qt6-base/qtbase/src/corelib/io/qresource.cpp:858
#6  0x00007ffff2d422b9 in QResourcePrivate::load (this=this@entry=0x555557dfdea0, file=...) at /usr/src/debug/qt6-base/qtbase/src/corelib/io/qresource.cpp:339
#7  0x00007ffff2d42b1b in QResourcePrivate::ensureInitialized (this=this@entry=0x555557dfdea0) at /usr/src/debug/qt6-base/qtbase/src/corelib/io/qresource.cpp:389
#8  0x00007ffff2d42f57 in QResource::fileName (this=0x555557dfd0d8) at /usr/src/debug/qt6-base/qtbase/src/corelib/io/qresource.cpp:574
#9  QResourceFileEngine::open (this=<optimized out>, flags=..., permissions=std::optional [no contained value]) at /usr/src/debug/qt6-base/qtbase/src/corelib/io/qresource.cpp:1441
#10 0x00007ffff2d2121f in QFile::open (this=0x555557b7e000, mode=...) at /usr/src/debug/qt6-base/qtbase/src/corelib/global/qflags.h:77
#11 0x00007ffff355b3c2 in QImageReaderPrivate::initHandler (this=0x555557df9570) at /usr/src/debug/qt6-base/qtbase/src/gui/image/qimagereader.cpp:513
#12 0x00007ffff355b6f9 in QImageReader::supportsOption (this=0x7fffffffae00, option=QImageIOHandler::ScaledSize) at /usr/src/debug/qt6-base/qtbase/src/gui/image/qimagereader.cpp:1410
#13 0x00007ffff35145a2 in (anonymous namespace)::ImageReader::ImageReader (this=0x7fffffffae00, fileName=..., size=...) at /usr/src/debug/qt6-base/qtbase/src/gui/image/qicon.cpp:44
#14 QPixmapIconEngine::addFile (this=0x555556112970, fileName=<optimized out>, size=..., mode=QIcon::Normal, state=QIcon::Off) at /usr/src/debug/qt6-base/qtbase/src/gui/image/qicon.cpp:460
#15 0x00007ffff35153b6 in QIcon::addFile (this=this@entry=0x7fffffffb208, fileName=..., size=..., mode=mode@entry=QIcon::Normal, state=state@entry=QIcon::Off) at /usr/src/debug/qt6-base/qtbase/src/gui/image/qicon.cpp:1195
#16 0x00007ffff40384c3 in operator() (prefix=..., icon=..., __closure=<optimized out>) at /usr/src/debug/qt6-base/qtbase/src/widgets/styles/qfusionstyle.cpp:3509
#17 0x00007ffff4038e0c in QFusionStyle::iconFromTheme (this=this@entry=0x555555cb8ec0, standardIcon=standardIcon@entry=QStyle::SP_TitleBarNormalButton) at /usr/src/debug/qt6-base/qtbase/src/widgets/styles/qfusionstyle.cpp:3514
#18 0x00007ffff4038e69 in QFusionStyle::standardIcon (this=0x555555cb8ec0, standardIcon=QStyle::SP_TitleBarNormalButton, option=0x7fffffffbcf0, widget=0x55555611c7b0) at /usr/src/debug/qt6-base/qtbase/src/widgets/styles/qfusionstyle.cpp:3538
#19 0x00007ffff3fb2711 in QProxyStyle::standardIcon (this=<optimized out>, standardIcon=QStyle::SP_TitleBarNormalButton, option=0x7fffffffbcf0, widget=0x55555611c7b0) at /usr/src/debug/qt6-base/qtbase/src/widgets/styles/qproxystyle.cpp:380
#20 0x00007ffff3f8c27d in QCommonStyle::subElementRect (this=<optimized out>, sr=<optimized out>, opt=0x7fffffffbcf0, widget=0x55555611c7b0) at /usr/src/debug/qt6-base/qtbase/src/widgets/styles/qcommonstyle.cpp:3074
#21 0x00007ffff4038145 in QFusionStyle::subElementRect (this=<optimized out>, sr=QStyle::SE_DockWidgetTitleBarText, opt=0x7fffffffbcf0, w=<optimized out>) at /usr/src/debug/qt6-base/qtbase/src/widgets/styles/qfusionstyle.cpp:3467
#22 0x00007ffff400855b in QStyleSheetStyle::subElementRect (this=0x555555ce9b60, se=QStyle::SE_DockWidgetTitleBarText, opt=0x7fffffffbcf0, w=0x55555611c7b0) at /usr/src/debug/qt6-base/qtbase/src/widgets/styles/qstylesheetstyle.cpp:6402
#23 0x00007ffff3ffb3c0 in QStyleSheetStyle::drawControl (this=0x555555ce9b60, ce=<optimized out>, opt=0x7fffffffbcf0, p=0x7fffffffbcd0, w=0x55555611c7b0) at /usr/src/debug/qt6-base/qtbase/src/widgets/styles/qstylesheetstyle.cpp:4442
#24 0x00007ffff409758e in QStylePainter::drawControl (this=0x7fffffffbcd0, ce=QStyle::CE_DockWidgetTitle, opt=...) at /usr/src/debug/qt6-base/qtbase/src/widgets/styles/qstylepainter.h:51
#25 QDockWidget::paintEvent (this=<optimized out>, event=<optimized out>) at /usr/src/debug/qt6-base/qtbase/src/widgets/widgets/qdockwidget.cpp:1633
#26 0x00007ffff3f5d6f3 in QWidget::event (this=0x55555611c7b0, event=0x7fffffffbf40) at /usr/src/debug/qt6-base/qtbase/src/widgets/kernel/qwidget.cpp:9134
#27 0x00007ffff3f020a0 in QApplicationPrivate::notify_helper (this=<optimized out>, receiver=0x55555611c7b0, e=0x7fffffffbf40) at /usr/src/debug/qt6-base/qtbase/src/widgets/kernel/qapplication.cpp:3307
#28 0x00007ffff2d6a6c8 in QCoreApplication::notifyInternal2 (receiver=0x55555611c7b0, event=0x7fffffffbf40) at /usr/src/debug/qt6-base/qtbase/src/corelib/kernel/qcoreapplication.cpp:1109
#29 0x00007ffff2d6a71d in QCoreApplication::sendSpontaneousEvent (receiver=<optimized out>, event=<optimized out>) at /usr/src/debug/qt6-base/qtbase/src/corelib/kernel/qcoreapplication.cpp:1563
#30 0x00007ffff3f4e96e in QWidgetPrivate::sendPaintEvent (this=this@entry=0x5555561c6380, toBePainted=...) at /usr/src/debug/qt6-base/qtbase/src/widgets/kernel/qwidget.cpp:5661
#31 0x00007ffff3f50c27 in QWidgetPrivate::drawWidget (this=this@entry=0x5555561c6380, pdev=pdev@entry=0x555557df9428, rgn=..., offset=..., flags=flags@entry=..., sharedPainter=sharedPainter@entry=0x0, repaintManager=<optimized out>) at /usr/src/debug/qt6-base/qtbase/src/widgets/kernel/qwidget.cpp:5611
#32 0x00007ffff3f53a64 in QWidgetPrivate::paintSiblingsRecursive (this=this@entry=0x555555c6ee10, pdev=pdev@entry=0x555557df9428, siblings=<optimized out>, index=<optimized out>, rgn=..., offset=..., flags=..., sharedPainter=0x0, repaintManager=0x555558857670) at /usr/src/debug/qt6-base/qtbase/src/widgets/kernel/qwidget.cpp:5790
#33 0x00007ffff3f51185 in QWidgetPrivate::drawWidget (this=0x555555c6ee10, pdev=0x555557df9428, rgn=<optimized out>, offset=<optimized out>, flags=..., sharedPainter=<optimized out>, repaintManager=<optimized out>) at /usr/src/debug/qt6-base/qtbase/src/widgets/kernel/qwidget.cpp:5652
#34 0x00007ffff3f75929 in QWidgetRepaintManager::paintAndFlush (this=0x555558857670) at /usr/src/debug/qt6-base/qtbase/src/widgets/kernel/qwidgetrepaintmanager.cpp:907
#35 0x00007ffff3f5d0f6 in QWidget::event (this=0x555555f04720, event=0x555555d326e0) at /usr/src/debug/qt6-base/qtbase/src/widgets/kernel/qwidget.cpp:9298
#36 0x00007ffff3f020a0 in QApplicationPrivate::notify_helper (this=<optimized out>, receiver=0x555555f04720, e=0x555555d326e0) at /usr/src/debug/qt6-base/qtbase/src/widgets/kernel/qapplication.cpp:3307
#37 0x00007ffff2d6a6c8 in QCoreApplication::notifyInternal2 (receiver=0x555555f04720, event=event@entry=0x555555d326e0) at /usr/src/debug/qt6-base/qtbase/src/corelib/kernel/qcoreapplication.cpp:1109
#38 0x00007ffff2d6aab2 in QCoreApplication::sendEvent (receiver=<optimized out>, event=0x555555d326e0) at /usr/src/debug/qt6-base/qtbase/src/corelib/kernel/qcoreapplication.cpp:1549
#39 QCoreApplicationPrivate::sendPostedEvents (receiver=0x0, event_type=0, data=0x555555aa5c20) at /usr/src/debug/qt6-base/qtbase/src/corelib/kernel/qcoreapplication.cpp:1904
#40 0x00007ffff304db18 in QCoreApplication::sendPostedEvents (receiver=0x0, event_type=0) at /usr/src/debug/qt6-base/qtbase/src/corelib/kernel/qcoreapplication.cpp:1757
#41 postEventSourceDispatch (s=0x555555aa5eb0) at /usr/src/debug/qt6-base/qtbase/src/corelib/kernel/qeventdispatcher_glib.cpp:246
#42 0x00007ffff1106f8d in g_main_dispatch (context=0x7fffd8000f60) at ../glib/glib/gmain.c:3565
#43 0x00007ffff1108657 in g_main_context_dispatch_unlocked (context=0x7fffd8000f60) at ../glib/glib/gmain.c:4425
#44 g_main_context_iterate_unlocked (context=context@entry=0x7fffd8000f60, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at ../glib/glib/gmain.c:4490
#45 0x00007ffff1108865 in g_main_context_iteration (context=0x7fffd8000f60, may_block=1) at ../glib/glib/gmain.c:4556
#46 0x00007ffff304a9d2 in QEventDispatcherGlib::processEvents (this=0x555555aa0c30, flags=...) at /usr/src/debug/qt6-base/qtbase/src/corelib/kernel/qeventdispatcher_glib.cpp:399
#47 0x00007ffff2d75a86 in QEventLoop::processEvents (this=0x7fffffffcb70, flags=...) at /usr/src/debug/qt6-base/qtbase/src/corelib/kernel/qeventloop.cpp:104
#48 QEventLoop::exec (this=0x7fffffffcb70, flags=...) at /usr/src/debug/qt6-base/qtbase/src/corelib/kernel/qeventloop.cpp:186
#49 0x00007ffff2d6f171 in QCoreApplication::exec () at /usr/src/debug/qt6-base/qtbase/src/corelib/kernel/qcoreapplication.cpp:1452
#50 0x00007ffff3efd31a in QApplication::exec () at /usr/src/debug/qt6-base/qtbase/src/widgets/kernel/qapplication.cpp:2574
#51 0x000055555583d173 in run_program (logFile=..., argc=<optimized out>, argc@entry=1, argv=argv@entry=0x7fffffffda38) at /usr/src/debug/obs-studio/obs-studio-32.0.1-sources/frontend/obs-main.cpp:690
#52 0x0000555555605649 in main (argc=1, argv=0x7fffffffda38) at /usr/src/debug/obs-studio/obs-studio-32.0.1-sources/frontend/obs-main.cpp:1035
Steps to Reproduce
  1. Launch OBS.
  2. (optional) Hide the preview.

Remarkably, even with preview shown, main thread CPU usage is dominated by repeatedly redrawing icons and trying to locate image decoders, rather than displaying video! (I enabled preview and ran a new profiling session, with results indistinguishable from my previous screenshot.)

Anything else we should know?

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the issue with the OBS launch steps and compare a profiler or Ctrl+C backtrace with the Qt call chain listed in the report. Use frontend/obs-main.cpp as the OBS entry point mentioned in the backtrace, then trace the repeated dock-widget painting; done means OBS no longer repeatedly decodes icons or spends most of a CPU core in that path.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, linux
Domain
desktop, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.