QCachingLocale: speeding up QSystemLocale::query() calls

published on November 21, 2010

QCachingLocale speeds up Qt’s slow QSystemLocale::query() calls by caching the answers. This seems to be particularly necessary on Mac OS X 10.6.

The other day I was working on my master thesis, on the parser that is going to parse Episodes log files. I had finished a rough version that parses all fields on an Episodes log line. Unfortunately, performance turned out to be extremely poor: 4.8 seconds for parsing 1000 lines.

After a bit of research, it became clear that it was the call to QDateTime::fromString() that was the cause of the performance issues. Unable to figure it out on my own — I tried for an hour or so, I hopped onto the #qt IRC channel and I posted a simple test case that could reproduce the problem:

[18:06] WimLeers: heinz: Xenakios https://gist.github.com/707963
[18:07] Xenakios: it seems quite pathological if parsing 1000 strings takes
several seconds
[18:08] WimLeers: Xenakios: what do you mean?
[18:09] Xenakios: just that that kind of thing should only happen if something
is really rottenly wrong somewhere
[18:09] w00t_: 46 ms were necessary for parsing the date 1000 times.
[18:09] WimLeers: Xenakios: I'm parsing a log file. I have no choice.
[18:09] Xenakios: perhaps the compiler does something weird for that loop
because you are not using the result anywhere
[18:09] WimLeers: woot_: thanks!
[18:09] WimLeers: 4779 ms were necessary for parsing the date 1000 times.
[18:10] WimLeers: Quite a difference.
[18:10] w00t_: what Qt version are you running this on?
[18:10] WimLeers: Xenakios: Eh, no. It's the same in this simple test case as
in the actual parser, where I do use the result.
[18:10] WimLeers: 4.7.1
[18:10] Xenakios: ayway w00t_'s result seems more realistic
[18:10] WimLeers: On OS X
[18:11] w00t_: mmm
[18:12] w00t_: I really don't see anything there that would explain that
[18:13] WimLeers: Is somebody else here on OS X 10.6.5/Qt 4.7.1? That'd either
confirm that it's a platform-specific bug or something severely wrong with my
installation. kind of time difference
[18:15] w00t_: fwiw I'm running it in linux inside a windows VM right now, so
I'm even more amazed that it's as fast as it is for me

Basically, everybody was puzzled. How could there be such a blatant performance issue in Qt? Unimaginable! I had strong suspicion that this was a platform-specific bug (i.e. specific to Mac OS X). Other people’s testing confirms this:

[18:16] w00t_: I get ~40-50ms, WimLeers gets like 4 or more *seconds* :P
[18:15] WimLeers: heh
[18:16] Xenakios: ok here i got 30ms, on windows 7, intel q8200
[18:17] Xenakios: latest qt 4.7.1
[18:17] cbreak: w00t_: 5016 ms were necessary for parsing the date 1000 times.
in debug mode
[18:17] w00t_: cbreak: ...wow
[18:17] w00t_: what the hell? 
[18:18] cbreak: 4955 ms were necessary for parsing the date 1000 times in
release mode
[18:18] WimLeers: cbreak: ok Mac-specific issue then I guess! Also 10.6.5?
Qt 4.7.1? Release is ± the same probably.
[18:18] cbreak: no, qt 4.6.3 here

A few minutes later, the user with nickname ‘cbreak’ posted two screenshots:

See the attached figures:

This clearly portrayed the problem: calls to QSystemLocale::query are taking enormous amounts of time, and it seems this really is just a bug in OS X: system libs are being excessively active for such a simple function call.

A little while later, that same user cbreak posted a rough version of QCachingLocale that partially worked. I then worked on it to make sure it supports caching all query types, and ensured thread-safety. It’s licensed under the Unlicense. I worked on it, but couldn’t have come up with it without cbreak. Thanks again, cbreak!

I’ve provided a test case that shows the difference in performance (which expands on the initial test case). On my system, it generates the following output:

Without QCachingLocale:
4839 ms were necessary for parsing the date 1000 times.

With QCachingLocale:
23 ms were necessary for parsing the date 1000 times.

That’s pretty significant. A 210 speed-up factor!

So, if you’re using Qt and QSystemLocale::query() calls are making your app much slower than you would expect it to be, give QCachingLocale a try.
Integration is trivial. Create a QCachingLocale instance as soon as possible, preferably in the main() function. This will automatically install this object as the system locale and remove any earlier installed system locales.

Update on December 19, 2010

Apparently there was still a problem with thread-safety. That’s fixed now, in commit e6f51533bc15b12a2270a3ba0be87fce79644fb4.

Update on February 7, 2011

Reported to the Qt bug tracker: [#QTBUG-17271] QSystemLocale::query() performance issues on OS X (±100 times slower than on Windows).

Comments

 Twitter Trackbacks for QCachingLocale: speeding up QSystemL's picture

[…] QCachingLocale: speeding up QSystemLocale::query() calls | Wim Leers wimleers.com/blog/qcachinglocale-speeding-up-qsystemlocalequery-calls – view page – cached QCachingLocale speeds up Qt’s QSystemLocale::query() calls by caching the answers. Seems to be particularly necessary on Mac OS X 10.6. Tweets about this link […]

w00t's picture

Hi!

(I’m w00t from that conversation - nice to see you made a writeup on this).

Can I also ask whether you reported it on Qt’s tracker? The likelyhood of it getting fixed isn’t so great if it isn’t officially known.

Wim Leers's picture

Wim Leers

Hi again, w00t! :) Unfortunately, I haven’t added this to Qt’s tracker yet. But I’ll add it to my todo list — I can’t give you an ETA though :)

Thanks for commenting — that’s how I just ended up skimming several of your blog posts and how I just added added another feed subscription :) Your Qt blog posts are very interesting! :)