I'm a shareware developer using Delphi 6 to develop an email messages classifier application; its main goal is to fight spam. The application uses an advanced message contents analysis based on the Naive Bayes Classifier. My problem was related to the interface. Every mail message processed by my software is saved in a folder. The folder contains email messages in the RAW format. If a user wanted to browse through the messages history, he would open a history page where every mail message located in the history folder is represented as an item in a TListView component. The TListView has four columns, each showing different data assigned to the message from the history folder. My problem was that creating the list was very slow even on a fast machine, because many files had to be read at once while the data was found and displayed in the list. This was an extremely irritating issue, and I've spent quite a bit of time researching why the list view refresh was so slow.
I decided to search for a tool which would work with Delphi 6, allowing me to precisely analyze my code. This sort of task is typical for tools called "profilers". A profiler monitors an application, reporting on how much time is spent in functions (timing) and how many times a function is called (hit count). This can give an idea of where a performance logjam might be in an application's code.
I remembered I had used a tool called "MemProof" for some time, it is a simple but powerful piece of software designed to find memory leaks. I was curious if the tool was still developed and what its current status was. I hoped that I would find that MemProof was now also a profiler, so I optimistically performed a Google search for "MemProof", and clicked the first resulting URL. What did I find? A page where MemProof is still available for free download; unfortunately, it still had the same features. It's a memory leak finder; pity... But the page where MemProof is listed offered a few more tools. I decided to spend some time there reading about the other products. I clicked the Products menu above and found a profiler! I was very happy reading, "AQtime 3 - AQtime is a profiling toolkit for thorough analysis of Delphi, Visual Basic, Visual C++, C++Builder, Intel C++, GCC and Visual Fortran applications." I decided to give it a try and began downloading a free trial. During the download process I read the AQtime 3 page and took a look at the interactive tutorial which was very exciting. Finally I had the software on my hard drive and I could install and play with it.
The installation was easy. A few steps and voila! A powerful profiler ready to use. So, I thought, let's try to find out what the problem is with my application. Once I compiled my application with debug information, I was ready to analyze it with AQtime 3.
My first view of AQtime 3 made me a little shy. There were many panels, tabs and mini windows, but there must be some idea in this, I thought. And there is! A great idea to make a developer's life so easy! Of course I had to read some help (the "Getting started" topic) to better understand the philosophy, but it was quick, I then began creating my first new project.
To create a project one can simply go to the File menu and open an EXE file. There are, of course, other options, but I didn't need them at the moment. If the EXE file contains debug information, AQtime 3 creates a tree of all units, forms, functions, objects and other things used in the loaded application. The tree is available at the left, on the "Setup" tab. At the right there is an "Areas" window where we can define what the program should profile. By default, "Full check" is turned on. It is a good idea to define your own areas to profile only these functions that you need and not the whole application. So, I turned off the "Full check" switch and created a line-level profiling area.
My problem was my function ShowMessagesHistory located in the MainWindow unit of my application source code. So, I unfolded the tree and located the MainWindow unit and the function I was interested in. I was able to simply drag and drop the function from the tree onto the profiling area I had created, and that's it. Everything I need to profile the function is already prepared. Oh, I've almost forgotten. AQtime 3 offers not only a timing profiler, but many more! However I was interested in the timing profiler at the moment, so I selected it from the profiler list. I was then able to begin the profiling run of the project using even the same shortcut as in Delphi: F9.
My application started and I performed some actions in the UI to cause the problematic function to be called. Then I stopped my application and what I saw ... I have no words to describe my happiness. In the Editor panel at the bottom of AQtime, my source code was displayed. Each line of code have a percentage value presented on the gutter. But this is only one method of presenting the results! The Results window includes the following tabs: "Event view", "Graph", "Disassembly", "Details", "Editor" and "Call Graph". Each of these displays a lot of very useful information regarding the profiling process. There are graphs of percentage of time spent in each profiled routine, diagrams showing how the function calls other routines, there is even a disassembly view that shows the machine code of each line of the profiled function! But the most interesting are the Details and Editor panels. They offer a lot of very useful information. Displayed, for example, are all the line numbers in the profiled function along with information about the time each line takes, time with calls to children routines, a graph of the percentage work time and even the hit count, which gives information about how many times the line had been called. One look at this information and I knew which lines of code devoured the most of the time.
In my case the problem was not in the function itself but in some child routines called from it. So, I went to the setup tab and located the time consuming functions in the application tree. I added them to my profiling area and executed the profile run once again. Now I had a detailed inspection of what takes the most time in the second function. It was also very helpful to know how many times the lines had been called. I easily noticed that a time consuming line: "if FileExists(afilename) then" was called more than 500 times in only two calls to my ShowMessagesHistory function. What's the funniest is that the line was not vital to the function flow. I made the required modifications in my Delphi code and compiled my application again. I started it, profiled and the new report was impressive. My function worked 10% faster! I spent a lot of time profiling other lines. It not only made my application more effective but also gave me a lot of pleasure.
AQtime 3 changed the way I test my application's performance. Looking back I must admit that I spent too much time doing many different tests and profiling my application in some prehistoric way. AQtime 3 not only makes my life easier, but also saves me time and first of all gives incredible results in application profiling. I've been a Delphi developer for over 7 years and there have not been many similar moments in my history that I could name "revolutionary", but the day I met AQtime 3 was definitely one of them!
Rafal Platek Cream Software