I've been working on tracking down Rosegarden performance issues when
recording MIDI. I think I've identified the problem, and unfortunately,
it is rather pervasive. It will require quite a bit of time and effort
to fix. My time is pretty limited when working on rg, so I anticipate
this may take months for me to chip away at.
I'd like to outline my findings at this point, and my plan.
Basically, I wanted to warn everyone about the kinds of changes I'll be
making and get some opinions.
First, the problem. When I start up rg and hit record, I see CPU
usage of around 15/9/7 (rosegarden, Xorg, compiz respectively). Now I
start playing on my MIDI keyboard. The CPU jumps up to 67/54/16. After
a few days of digging, I've discovered that the majority of the problem
is related to the call to m_trackButtons->slotUpdateTracks() in
TrackEditor::paintEvent(). Remove this call, and performance is
significantly better. This is because in record mode, when notes are
coming in, slotUpdateTracks() is called every 20msecs even though there
are no changes for it to display.
TrackButtons::slotUpdateTracks() should not be called from
TrackEditor::paintEvent(). There is a comment in the code to this
effect, "These calls from within a paintEvent look ugly." They're worse
than just ugly. According to the Qt docs, they are wrong: "Generally,
you should refrain from calling update() or repaint() inside a
paintEvent(). For example, calling update() or repaint() on children
inside a paintevent() results in undefined behavior; the child may or
may not get a paint event." In this case, the problem is worse. The
child is being asked to redraw itself when there's no reason for the redraw.
The solution? TrackButtons should properly respond to changes to its
underlying data structure (Composition). It should be notified of any
changes and do whatever is necessary to update the UI to stay in sync.
Composition already has a mechanism in place, but it is not complete.
My goal is to get TrackButtons to the point where the software will
work fine even with the call to slotUpdateTracks() removed from
TrackEditor::paintEvent(). This will require improvements to the change
notification mechanisms in Compostion, and improvements to TrackButtons
to allow it to respond to change notifications.
I am going to work on this "one test case at a time". For each test
case there will be changes to Composition and TrackButtons which I will
commit. But I will leave the call to slotUpdateTracks() in
TrackEditor::paintEvent() so that the software will continue to work
until all of the required changes are complete. Then I'll pull the call
out and we should see a huge performance improvement.
That's the plan. Feedback appreciated.
From: Chris Cannam <cannam@al...> - 2011-12-04 13:07:51
On 3 December 2011 23:02, Ted Felix <ted@...> wrote:
> TrackButtons::slotUpdateTracks() should not be called from
Indeed, this whole update procedure is really a hangover from our very
earliest attempts to get things working with Qt3, never satisfactorily
refactored during the Qt4 conversion.
> My goal is to get TrackButtons to the point where the software will
> work fine even with the call to slotUpdateTracks() removed from
Sounds like a good plan to me.