(Qt)WebKit Sprint in Wiesbaden

(Qt)WebKit Sprint in Wiesbaden

The sprint is over for some time. You can see summaries of the different sessions and some slides in the wiki. Besides talking about QtWebKit and how to improve it (API, features, speed, make people aware that they can contribute, influence the release schedule, policies.. *hint*) the thing that has impressed me the most is unrelated to coding.

We all hear when someone from our Community is leaving the Qt department, and we always wonder how life will continue, who will fill the gap. In the last year a couple of new people got hired at Oslo and I’m really impressed how they find such capable people that are technically skilled and willing to move to Oslo! kudos!

Talking about performance measurements at foss.in

Talking about performance measurements at foss.in

It is the second time I’m at foss.in and this time I was talking about the current work I’m doing on QtWebKit. Nokia is kind enough to give me enough time to explore the performance of QtWebKit (mostly on Qt Embedded Linux and ARM) and do fixes across the stack in WebKit, Qt or whereever we think it will be necessary.

Performance for me comes in memory footprint and runtime speed (how long does it take?) and for this I have experimented using OProfile, Memprof/Memusage, QBENCHMARK but also wrote some WebKit specific tools. E.g. a tool that allows me to mirror webpages to turn them into a benchmark (which still has quite some problems), a simple http server to serve the content, some test case reductions in order to look into specific areas like networking, image decoding, painting, fonts.

The slides and links can be found here and they link back to the WebKIt wiki where you can find an introduction to the (Qt)WebKit specific tools, a set of bugs and pending patches, and a set of issues that are known but not yet handled.

The main message of the talk is to not do optimisation by myth, but to use a stable environment and one of the existing tools to see what is going. It is really easy.

What is the size of a QList::Data, RenderObject?

What is the size of a QList::Data, RenderObject?

We tend to write classes without really caring about what the compile will do to create the binary file. When looking into performance and specially memory usage and you create certain objects thousands of times it becomes interesting of how much memory one is wasting for padding/no good reason.

The Linux kernel hackers wrote a tool called pahole that will analyze the DWARF2 symbols and then spit out friendly messages like the one below.


struct Data {
class QBasicAtomicInt ref; /* 0 4 */
int alloc; /* 4 4 */
int begin; /* 8 4 */
int end; /* 12 4 */
uint sharable:1; /* 16:31 4 */

/* XXX 31 bits hole, try to pack */

void * array[1]; /* 20 4 */

/* size: 24, cachelines: 1, members: 6 */
/* bit holes: 1, sum bit holes: 31 bits */
/* last cacheline: 24 bytes */

In this case QList::Data could have used at least three bytes less memory and changing the definition of sharable and array would have removed a whole in the struct. Maybe that is something for Qt5 to keep in mind.

The research question. Can QtWebKit memory usage be reduced by shrinking some of the Qt structs without losing functionality?

Memory profiling on GNU systems

Memory profiling on GNU systems

This is a small guide on how to observe memory allocations of a process. When carrying out a change it is not only of interest if all test cases still pass, if the benchmarks are faster but it is also important to figure out if there was a change in storage (stack and RAM) requirement.

If you are using the GNU libc it is likely you have a /lib/libmemusage.so installed on your system. This library can be preloaded using LD_PRELOAD and will intercept calls to malloc,free,realloc and various other calls. In short it will trace memory allocations for you. The limitation of that tool is that it will not tell you how much memory the kernel actually mapped, anything about memory fragmentation, etc.

To use libmemusage all you have to do is to prepend MEMUSAGE_OUTPUT=mytrace and LD_PRELOAD=/lib/libmemusage.so to your application. This will instruct the library to write out a trace to the mytrace file.

This trace file can be converted to a graph using the memusagestat utility. It is not installed by most GNU distributions and can be either build from the glibc sources or from the QtWebKit performance measurement utilities. Using memusagestat -o output.png mytrace an image with memory allocations and stack usage like the one at the end of this post will be created. The redline is the heap usage, the green one is the stack usage of the application. The x-scale is the number of allocations.

NOTES: As of today the graph creation with the x-Axis being the time is broken as the generated trace file has some issues, I’m looking into the problem but it will take some more days.

memusage on qtwebkit

WebKit on non mainstream platforms

WebKit on non mainstream platforms

We have seen some interest in MIPS on the mailinglist and little in the bugtracker but no contribution from these folks. So the other week I decided to attempt to run some of our regression tests on a MIPS platform. The only problem is that I don’t have any MIPS hardware… can you change that?

I had this idea of implementing enough of MacroAssembler to run/compile yarr with the RegexJIT.cpp. In the absence of MIPS hardware I used qemu-mipsel useremulation, enabled yarr/RegexInterpreter.cpp and ran into an infinite loop. I have fixed the bug and landed the patch upstream and now I’m able to complete run-javascriptcore-tests using yarr. The next step will be to work on the MacroAssembler and learn about MIPS assembly…. maybe I progress a bit more next weekend.

The WebKit mailinglists

The WebKit mailinglists

In the beginning there was webkit-dev but we were overwhelmed by the feedback we got. Last week Maciej announced how to use the new lists.

  • webkit-dev should be used for the development of WebCore/JavaScriptCore itself.
  • webkit-help should be used for questions on how to use WebKit API in applications, porting to new platforms, building it…
  • webkit-jobs is there to not force one to send job posts to every single commiter but to only one place.
Taking over memprof

Taking over memprof

Where did all my memory go? Who is allocating it, how much is being allocated? From where were theses QImages allocated? valgrind provides an accurate leak checker, but for a running application you might want to know about allocations and browse through them and don’t take the performance hit of valgrind (e.g with massif).

There is an easy way to answer these questions, use memprof. memprof used to be a GNOME application, it was unmaintained, the website was gone from the net, but this tool is just way too good to just drop out of the net. After trying to reach the maintainer twice I decided to adopt the orphaned thing.

Check the application out, it is great, it helps me to get an overview of memory allocations for WebKit/GTK+…

Scrolling in GTK+ and WebKit/GTK+

Scrolling in GTK+ and WebKit/GTK+

  • Model/View GtkAdjustment and GtkScrollbar

    The GtkAdjustment is probably best described as a model for scrolling. It has several properties, e.g. the current position (value), the lower and upper possibilities, and the size increments. The GtkScrollbar is operating on top of a GtkAdjustment. It is responsible for taking user events and painting. When scrolling it will look at the lower and upper properties, it will update the value in case of something is happening.

  • WebCore::Scrollbar in WebCore

    The Scrollbar is created by the Scrollbar::createNativeScrollbar “factory”. For many platforms the painting/theming and behaviour is entriely done within that class. For GTK+ we will use a GtkScrollbar, this widget happens to not have its own GdkWindow which makes painting a bit more easy, we will just forward the original expose event and let it draw as well (from ScrollbarGtk::paint). WebCore::Scrollbar in WebCore are used in two places. One prominent one is the WebCore::ScrollView which is the base class of the WebCore::FrameView and will be used to enable people to scroll on their content in horizontal and vertical direction, the other big user are scrollable div’s (we have a manual test in WebCore/manual-tests/gtk/ to test positioning of these scrollbars).

  • Scrolling on GtkWidget

    The scrolling starts quite innocently with the description of gtk_widget_set_scroll_adjustments. In case of WebKitWebView in WebKit/GTK+ we do want to support scrolling so we need to return TRUE… but how. If you take a look at the class structure of GtkWidget there is a GObject signal identifier you will have to set with the signal you have created. This is done in the WebKitWebView class init and we will remember and use the GtkAdjustment, e.g. set by a GtkScrolledWindow, in the WebCore::ScrollView (base of WebCore::FrameView class). The usage of GtkAdjustment allows to have different means of scrolling, e.g. by fingers on a touchscreen, or by a wheel… the representation of the scroll concept will change, the implementation not…

  • The problem of mainFrame and subframes

    So far we will most of the times only have external GtkAdjustment set on the mainFrame that is embedded in something like a GtkScrolledWindow but there are pages that will create a frameset and you will have subframes that require scrolling (my test case here is Google Images). What we are ending up with is having a WebCore::FrameView with GtkAdjustments set from the WebKitWebView and some WebCore::FrameView without GtkAdjustments set at all. On cases without a GtkAdjustment, there is no one that will place a GtkScrollbar (and resize the WebKitWebView to be next to it), so the WebCore::ScrollView will create a ScrollbarGtk to handle this job. This creates the siutation that one WebCore::FrameView class will or will not have a Scrollbar (and manage its size…).

  • The current solution

    When we have a GtkAdjustment set in the WebCore::ScrollView do not think about scrollbars, the need of them, the positioning of them at all. Simply update the properties including the current value, the visibleWidth and contentWidth. The upside is we have a GtkWidget that is working like a GtkWidget and can be embedded into a GtkScrolledWindow or a MokoFingerScroll (back in the better days). The downside of this include that we have more platform specific code and that we will not send onscroll events… due not going through ScollbarClient::valueChanged….

  • The new solution

    Wrap the GtkAdjustment we get set into a ScrollbarGtk but do not create a GtkScrollbar. This should create a WebCore::Widget with WebCore::Widget::platformWidget() returning zero and this should set the width() and height() of this Scrollbar to zero meaning that the ScrollView calculation (e.g. updating visibleWidth/visibleHeight) is not negatively influenced, we can kill some more #ifdef PLATFORM(GTK) from WebCore::ScrollView and that we properly send onscroll events as all scrolling is going through the WebCore::Scrollbar code path, like with every other port. For having navigation working we must be sure to reset the GtkAdjustment, due the nature of the FrameView this is best done when creating the ScrollBar… The progress of this can be tracked in bug #25646.

FrameView and navigation

FrameView and navigation

Visiting a site can have certain changes on a FrameView that will not be undone when leaving it. The most prominent example is a fixed background (by CSS) which will disable using blit on scrolling. There might be different things as well. Another one would be the PageCache and navigation to pages in it. The result is that for every page navigation you will create a new FrameView. For most/all ports this is done in FrameLoaderClient::transitionToCommittedForNewPage(). There is even a convience method shared between most ports in the form of Frame::createView.

From an API point of view this means that there is one WebKitWebView (in terms of Gtk+) and this WebKitWebView has one WebCore::Page and this page has exactly one WebCore::Frame the so called mainFrame but throughout the lifetime of WebKitWebView there will be multiple instances of FrameView’s setup on the WebCore::Frame mainFrame. This also means that there are times were multiple WebCore::FrameView instances are around but only one should be active at a time.

For WebKit/GTK+ we will need to make sure that all the state of a WebKitWebView is transferred/set to the WebCore::FrameView when it gets created and ever change to a WebKitWebView gets forwarded to it. The most prominet state information are colors and GtkAdjustment (another posting). I think Gustavo is also about to introduce Scrollbar policies soon.