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).