[SOLVED] Performance issue with Flickable+Column+Repeater inside a PathView
-
My app consists of a PathView of pages, and each page consists of simple rows of text represented with a Flickable+Column+Repeater. Could you take a look at my QML to see, if there is some way I could optimize the performance of drawing the text rows?
@import QtQuick 1.1
import com.nokia.symbian 1.1Window {
id: pageRectangle { id: pageControl anchors.fill: parent PathView { id: pathView anchors.fill: parent model: pageModel flickDeceleration: 500 preferredHighlightBegin: 0.5 preferredHighlightEnd: 0.5 focus: true interactive: pathView.model.count > 1 delegate: pageDelegate path: Path { startX: - pathView.width * pathView.model.count / 2 + pathView.width / 2 startY: pathView.height / 2 PathLine { x: pathView.width * pathView.model.count / 2 + pathView.width / 2 y: pathView.height / 2 } } } Component { id: pageDelegate Rectangle { width: pathView.width height: pathView.height color: "white" Flickable { id: flickable clip: true anchors { left: parent.left; right: parent.right; top: parent.top; bottom: parent.bottom; leftMargin: 6; rightMargin: 6; topMargin: 6; bottomMargin: 6 } contentHeight: contentColumn.height contentWidth: contentColumn.width flickableDirection: Flickable.VerticalFlick Column { id: contentColumn Repeater { model: contentModel delegate: Text { width: flickable.width wrapMode: Text.Wrap font.pixelSize: 16 textFormat: Text.RichText text: time + (author != "" ? " <b><" + author + "></b> " : " ") + content } } } } } } } ListModel { id: pageModel ListElement { name: "page 1" } ListElement { name: "page 2" } ListElement { name: "page 3" } ListElement { name: "page 3" } } ListModel { id: contentModel ListElement { time: "11:11" author: "1" content: "feiwjf wie iew jigwguregiuareuiriuea uireahi fsferghraegaregrg" } ListElement { time: "11:12" author: "2" content: "feiwjf wie iew jigwguregiuareuiriuea uireahi fsferghraegaregrg" } ListElement { time: "11:13" author: "3" content: "feiwjf wie iew jigwguregiuareuiriuea uireahi fsferghraegaregrg" } ListElement { time: "11:14" author: "4" content: "feiwjf wie iew jigwguregiuareuiriuea uireahi fsferghraegaregrg" } ListElement { time: "11:15" author: "5" content: "feiwjf wie iew jigwguregiuareuiriuea uireahi fsferghraegaregrg" } }
}
@The performance issue comes up when switching orientation between portrait and landscape on a Symbian device. The orientation switch takes more than 10 seconds with the amount of content I would like to support (at least 5 pages with around 150 rows of text each). I know this might be a Symbian specific problem, but I would like to rule out performance issues with my QML first.
I've tried:
-
Removing the width property binding from the Repeater's delegate: This improves the performance a bit, but I want to wrap long rows onto the next line, so I guess I have to define the width like this.
-
Having a ListView instead of Flickable+Column+Repeater for each page: This caused the application to randomly crash when scrolling the ListView fast.
-
Having the page content inside one huge scrollable text element: The scrolling performance was really bad for this.
I've considered:
- Having a ListView instead of PathView for the page control: I doubt this would help much, because I would want to have at least one page on either side of the visible page to be in the cache and ready for being swiped visible, and the performance with 3 pages of around 150 rows of text is already unacceptable.
-
-
Don't use RichText if you can avoid it. It incurs a huge overhead when laying out text.
Can you post a backtrace for the crash you saw when scrolling the list view? Is it an out-of-memory error, or a "real" crash? If it's a real crash, please file a bug. Most likely it's an out-of-memory error, though - scrolling the list fast means that it's creating a LOT of delegates every frame. Your delegates are quite complex, so that could cause it.
In general, try to simplify your delegates as much as possible, for best performance.
Cheers,
Chris. -
Thanks for the suggestions.
I need to use RichText, because the text contains links and I need the onLinkActivated signal to launch web browser for those.
I tried the ListView implementation again, and this is what happens also when scrolling fast: http://qt-project.org/forums/viewthread/23178/. So the pages from my pageModel get automatically deleted and when I swipe to a page that has been deleted, the crash of course happens. I agree that it probably is due to out-of-memory.
I modified the code so that I put all the text formatting logic inside the QAbstractListModel in C++, and a quick test looks promising. I wasn't able to reproduce the crash or the performance problem with orientation switch using a ListView and a very minimal Text element as the delegate. I'll continue with this implementation and report back if I run into any more problems, but thanks so far.
(It bothers me a bit to have the text formatting in the C++ model since it should be purely a UI decision, what color and font to use, and what is the ordering of the 'time', 'author', and 'content' parts of the text. But it's a small price to pay, if it solves the other problems.)
-
The fact that some of the pages from the page model get automatically deleted sounds... wrong. That's not how OOM situations are handled, in my experience (generally, whole processes will be killed off instead of arbitrarily freeing random bits of memory that a running process requires).
More likely, you're hitting the case that in the low memory situation, the JavaScript garbage collector is being invoked, and the gc is cleaning up QObject's exposed to JavaScript which don't have living QObject parents. If you make the page model the QObject parent of every page, do you still see the crash issue?
But yes, that's unrelated to the performance problem, per se.
The issue with formatting text in C++ is unfortunate, but yes sometimes such "impure" decisions need to be made for the sake of performance.It's a real shame that you need to use rich text, because quite seriously, if you benchmark your code, I'd say that that is probably resulting in 50% of your CPU time. (Of course that's an uneducated guess, but laying out rich text is slow).
Cheers,
Chris. -
Excellent, now the root cause to my seemingly random crashes has been fixed, thanks Chris.
Indeed, making the model a parent for the pages gets rid of the page deletions and crashes.
Even with the ListView and a minimal delegate, I was encountering the page deletions very easily after I attached a ScrollBar to the view, but with the parent fix this also works.
Regarding the RichText, there is a visible difference in performance compared to PlainText, but the performance is luckily "ok" even with RichText. And I just don't see any way of avoiding RichText in my application. The page content is conversations such as IRC channels, and it's a pretty important requirement that user can open any links simply by tapping on them.