On my last summer vacation, I had an experience that was strikingly familiar
- one that I think most software programmers will also recognize in their
own projects. On this vacation, my family and I spent two days on Vancouver
Island, Canada. Our hotel, with a strong British heritage, was praised
for its famous afternoon tea, and I convinced my family to take part in
this major tourist attraction.
On the first day, we found that afternoon
tea was "sold out" and learned that a "reservation at the dining reservation
desk is mandatory." The next day, we approached the dining room - with
our reservation - to find... a terribly long line. It took us 20 minutes
to be seated, a delay that killed any enthusiasm we might have had. But
if only guests with reservations are permitted, I wondered, why the delay?
When we reached the head of the line, the
reason was quite apparent: only a single host was seating the guests.
While this procedure may have worked quite well with more staff, fewer
tables, and fewer guests, it was now creating a bottleneck - and an absolutely
avoidable one, at that.
Bottlenecks in the Tearoom - And In Your Applications
Why do I waste your time with my travel story? Because, as unlikely as
it seems, it's a good analogy to performance problems in computer programs!
Many programmers have experienced this
phenomenon of software engineering: software components are often deployed
under conditions they were not developed for. You can find this effect
with both simple functions and complete packages.
It's an undesired consequence of a highly
valuable principle of software reuse: reuse of components can considerably
improve the quality of a system - even if the components are constructed
for a slightly different situation. On the other hand, it's the most important
reason that the same software package works well in one condition and
produces performance problems in another.
Even worse, it's very unlikely that standard
performance tests can unveil these issues completely. What can help, though,
are simple plausibility checks.
To encourage you to use plausibility checks
to find performance bottlenecks, I'll give you an example prepared by
Thomas Manzke, a key developer in SAP's ABAP department.
This problem was originally detected by
the SAP Performance Group, a unit that puts much effort in improving the
performance of SAP software.
|It's very unlikely that standard performance tests can unveil
performance problems completely. What can help, though, are simple
Detecting Application Bottlenecks for ABAP Software
If you need a gauge for time measurement in ABAP programs, you use ABAP
Runtime Analysis. It enables programmers to find performance problems
before deployment, and allows the system administrator to analyze bottlenecks
during deployment of software written in ABAP. In the October 2000 issue
of SAP Insider, I presented the ABAP Short Dump as an instrument
that qualifies ABAP as "the Business Application Language," and with ABAP
Runtime Analysis, I'll give you another helpful tool.
ABAP Runtime Analysis consists of a recording
component and an analysis component. Although it was available for ABAP
early on, ABAP Runtime Analysis was completely revamped with Release 4.6,
and now allows the user to record dramatically more data and to record
the data of any executing process. To start recording, choose transaction
Use the Measurement frame to specify the object - program, function
module, or transaction - and the session you are interested in. To record
data of the current session, press the "Execute" button. ABAP Runtime
then automatically executes the specified object and starts recording.
If you use the "Back" button, recording of the session is terminated and
the overview of the ABAP Runtime Analysis Evaluation appears. To "catch" a different session, press the "Enable/Disable" button.
In the Restrictions frame, you specify the variant that you want
to use: "Default" or individually defined. You define a variant in order
to describe how the recording is performed and what data is recorded.
To define the variant, you:
- Select the aggregation mode. (Note that the degree of aggregation
influences the size of the trace file and the resolution of the analysis.
In order to produce a hit list of only the most important performance
consumers, use "Full" aggregation.)
- Restrict the size of the trace file.
- Restrict the recording time.
- Restrict recording to specific ABAP statements.
- Restrict recording to specific programs or procedural units.
Using the Performance file frame, you can analyze the actual
Testing an Application Using Plausibility Checks
The test candidate is ME21, a transaction used to create a purchase order.
The test should determine whether the execution time of the transaction
is growing linearly along with the number of order items - which would
be plausible because there are no dependencies between the items. So we
decided to record performance data for two purchase orders: one with 50
items and one with 495 items.
It's crucial to understand that merely
comparing the elapsed times of the two transactions would be misleading.
Business transactions always include SQL statements, and the elapsed time
of SQL statements is influenced by many factors, including net traffic,
table buffers, etc. As a result, the elapsed times of two executions of
a single SQL statement always differ. You can use the ABAP Runtime Analysis
"Hit List" icon (on the overview window) to get more detailed information.
The hit list is a presentation of the top "performance consumers" in transaction
ME21: function modules, form routines, methods, and SQL statements. After
sorting the hit lists of the 50-item order and the 495-item
order according to net execution time, we are able to
start our research.
When investigating performance issues,
it's always a good idea to start with only the biggest performance users,
and then proceed to the lesser "performance hogs." (But be careful when
deciding who's who - in a linearity check, even a 0.3-percent consumer
may be using a large amount of execution time.)
The first step is to find lines in the
hit list of the 495-item order that are significantly more expensive (i.e.,
take the longest execution time) than those in the 50-item order. Again,
SQL statements (OPEN, FETCH, etc.) must be checked in separate tests.
This can easily be done by comparing the corresponding entries in the
"Net (%)" (net percentage) column.
Now the surprise: the ME_CHECK_ PRICING_RESULT
function module requires 0.3 percent of the total execution time in the
first purchase order, but takes 1.4 percent of the total
time in the second one. Moreover, gross and net time are
identical, which means within this function module there is no SQL, function
call, or PERFORM statement. This is suspicious, even if its share in the
complete elapsed time is relatively small.
To display the ABAP source code of the
function module, select the "Display source code" button.
In our example, the culprit was found in
the ABAP statement in Listing 1. The LOOP statement performs a
linear search of the item number on the internal table T_KOMV. This table
holds the pricing conditions of all items in the order. A single item
may have no pricing conditions or thousands - the size of this table isn't
really predictable. With most purchase orders, a linear search may work
without any problems. But with 100,000 table entries, it produces a performance
disaster (something like the afternoon tea in my travel story). A simple
plausibility check executed with a professional tool helped to find a
potential performance bottleneck! I hope that you now eagerly try out