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