Access Cookbook - Ken Getz [143]
Public Function acbGetStackItems( ) As Integer
' Retrieve the number of items in the stack.
acbGetStackItems = mintStackTop
End Function
The acbGetStack function is a little more complex. It accepts an item number (requesting item 0 returns the item at the top of the stack) and calculates the position of the item to retrieve. Its source code is:
Public Function acbGetStack(mintItem As Integer) As String
' Retrieve the item that's mintItems from the top of the
' stack. That is,
' ? acbGetStack(0)
' would return the same value as acbCurrentProc.
' ? acbGetStack(3) would return the third value from the top.
If mintStackTop >= mintItem Then
acbGetStack = mastrStack(mintStackTop - mintItem - 1)
Else
acbGetStack = ""
End If
End Function
For the procedure stack to work, you have to place calls to acbPushStack and acbPopStack on entry and exit from every procedure call. Good coding practice supports the concept of only one exit point from each procedure, but even the best programmer sometimes breaks this rule. To use the call stack, however, you must catch every exit point with a call to acbPopStack. Keep this in mind as you retrofit old code to use this mechanism and when you devise new code to use it. You can always code for a single exit point, and you will find code maintenance much easier if you do.
7.3. Create an Execution Time Profiler
Problem
You'd like to optimize your VBA code, but it's almost impossible to tell how long Access is spending inside any one routine and it's difficult to track which procedures are called by your code most often. You'd like some way to track which routines are called, in what order, and how much time each takes to run. Can you do this?
Solution
As outlined in the Solution in Recipe 7.2, you can create a code profiler using a stack data structure to keep track of the execution order and timing of the procedures in your application. Though the code involved is a bit more advanced than that in the Solution in Recipe 7.2, it's not terribly difficult to create the profiler. Using it is simple, as all the work is wrapped up in a single module.
Steps
Open the database 07-03.MDB and load the module basTestProfiler in design mode. In the Immediate window, type:
? A( )
to run the test procedures. Figure 7-4 shows the profile stack and the code in A. As you can see, A calls B, which calls C, which calls D, which waits 100 ms and then returns to C. C waits 100 ms and then calls D again. Once D returns, C returns to B, which waits 100 ms and then calls C again. This pattern repeats until the code gets back to A, where it finally quits. The timings in the profile stack in Figure 7-4 are actual timings from one run of the sample.
Figure 7-4. The profile stack and the sample routines used to fill it
As the code is set up now, the profiler writes to a text file named C:\LOGFILE.TXT. You can read this file in any text editor. For a sample run of function A, the file contained this text:
********************************
Procedure Profiling
8/13/2003 3:29:11 PM
********************************
+ Entering procedure: A( )
+ Entering procedure: B
+ Entering procedure: C
+ Entering procedure: D
- Exiting procedure : D 101 msecs.
+ Entering procedure: D
- Exiting procedure : D 100 msecs.
- Exiting procedure : C 301 msecs.
+ Entering procedure: C
+ Entering procedure: D
- Exiting procedure : D 100 msecs.
+ Entering procedure: D
- Exiting procedure : D 100 msecs.
- Exiting procedure : C 300 msecs.
- Exiting procedure : B 701 msecs.
+ Entering procedure: B
+ Entering procedure: C
+ Entering procedure: D
- Exiting procedure : D 100 msecs.
+ Entering procedure: D
- Exiting procedure : D 100 msecs.
- Exiting procedure : C 300 msecs.
+ Entering procedure: C
+ Entering procedure: D
- Exiting procedure : D 100 msecs.
+ Entering procedure: D
- Exiting procedure : D 101 msecs.
- Exiting procedure : C 301 msecs.
- Exiting procedure : B 701 msecs.
- Exiting procedure : A( ) 1513