Saturday, February 25, 2012

Qt Performance Tips

As I've been moving away from Qt, I thought I should write some notes about things I've been taking care of when writing a Qt application. Even if they are not the super-duper tips , they may be useful for some people out there.

These tips, and more you may know or apply by default, can make a huge impact on your application. As I remember, the right compination of these tips has helped me to reduce the time of a big operation, and I was shocked by numbers. Imagine a process that takes 7 milliseconds and a smooth UX  instead of 10~30 seconds and a laggy UX!

1- QCoreApplication::processEvents
When getting inside a long loop (for or while loop) the application will freeze because of the intensive resource consumption, so it is advised to process events inside the loops to allow other thread to run. You will notice the difference if, for example, you have a progress bar and you update it from inside the loop. The progress bar UI will not be updated eventhough its values have been set, because the loop is not giving the chance for other processes to work. A line like the following can do the job:

2- Timer slots instead of threads
Sometimes you want to make a non-blocking process inside your application, so you make another thread, then may get in the hastle of communication with the current thread or modifying the UI. An example I saw and liked was as follows:
QTimer::singleShot(0, this, SLOT(doSomething()));

It was used in a GUI application when there was much code to write in the constructor, and the code was making much delay in the appearence of the main window. So the solution was to move this code to a slot with zero timeout.
Another usage was when querying much data from a database, showing the results of the query simultiniously in the UI (e.g. filling a datasheet line by line) instead of waiting for the query to finish had a great impact on both performance and user experience.

3- QCache
One of the tasks I hate in my application is accessing a database or filesystem. So using the QCache class in my application could minimize the time of accessing a file or database. If you know how computer cache memory works on hardware level you will get the idea. When I query some data from database, I save them in QCache. So the next time I need the data, I look for it inside my cache member before going to the database. If I find it, I use it. I don't find it, I go to the database. This can help boosting the performance if you have an intensive usage of your database or filesystem in runtime (like a game data maybe or history suggestions). So what it the advantage of QCache over QMap or other classes? Here is a quote from the documentation:
When inserting an object into the cache, you can specify a cost, which should bear some approximate relationship to the amount of memory taken by the object. When the sum of all objects' costs (totalCost()) exceeds the cache's limit (maxCost()), QCache starts deleting objects in the cache to keep under the limit, starting with less recently accessed objects.

4- Qt Resource System
"The Qt resource system is a platform-independent mechanism for storing binary files in the application's executable". But it is not always the best choice when you have a lot of files. Remember that this increases the size of your executable, and memory usage. So when you have files that can be placed beside the app instead of beig inside it, this will make less memory usage, leaving more momory for later computations, especially when you have limited hardware resources. Keep the resource system for a minimal number of basic resources like, as the documantation says, a certain set of files (icons, translation files, etc.) that you don't want to run the risk of losing them.

5- Painting
When you paint some graphics inside the application, whether for a game or just a background, it is advisable to take care of the following.
a) You do not always need to repaint all the space. Sometimes, for example, you want to update a logo at the center of your window or splash screen, then why repainting hundreds of thousands of pixels when you only want to repaint a 64x64 rectangle in the middle?
b) When you repaint the same image over and over (for example, a background in the update() method), it is useless to load the image every time in a temporary variable inside the method because loading takes time. It is better to declare a local variable in your header file and load it once (in the constructor or anywhere when needed) then only repaint it without reloading the same image.

6- Database indexing
This may not be a Qt-specific tip, but it is still very important when you have a database of tables of 500,000 entries.
A database index is a data structure that improves the speed of data retrieval operations on a database table at the cost of slower writes and increased storage space. [Wikipedia]
If you do not know about this topic, I suggest you spent an hour reading and applying it on any database to notice the difference it makes.

7- You application in idle state
Some application features are only useful when the user is looking at them. For example when you are retrieving weather conditions from a remote server. What is the benefit of downloading an XML file, parsing, and updating your UI every couple of minutes when the user is not even looking? When the user is in a state when he does not benefit from a feature, it is better to stop/pause it.

So ... these were the performance tips I had in mind till now. I hope you learned something new from them.

No comments:

Post a Comment