Classic Computer Magazine Archive COMPUTE! ISSUE 36 / MAY 1983 / PAGE 118

Hescount For PET/CBM And VIC

Steve Leth

One of the facilities available on many mainframe computer systems is a program profiler – a utility that monitors the execution of a program and counts how many times each statement is executed. This information can be used in a number of ways to assist in the development of a new program or the modification of an old one. For instance, statements in a program that are executed many times are prime candidates for various time-saving techniques. Speeding up a line that is executed a thousand times will have a much greater effect on a program's total run time than doing the same thing to a line that is executed only once. We'll see more of this in an example later on.

Profiler information can also be used for general program testing and debugging. Finding the cause of an endless loop is a lot easier when you know exactly which statements are part of the loop. Another area of program development that is often ignored is the testing of seldom-used paths through a program's logic. Many a "well-tested" program contains large stretches that were never executed during its debugging stages. A profiler lets you find these unexecuted statements and devise input or other conditions that will force them to be executed.

Simple To Use

"OK, sounds great. But I don't have a mainframe, I've got a VIC!" Yes, I know, and so do the people at Human Engineered Software, who have developed Hescount, a BASIC program profiler for all versions of Commodore PET/CBM and VIC.

For the most part, using Hescount is pretty simple: you load it by running a BASIC loader program. As usual, the loader resets the top-of-memory pointer so Hescount won't be destroyed by running your program. Next, you load the BASIC program you want profiled and type "SYS 0".

Hescount will now set up the program so that its execution can be monitored by hooking into the zero-page CHARGET routine and reserving memory space for the line counts. You just run the program as usual. While your program is running, Hescount will keep track of how many times each line is executed, placing this count in the space it' reserved during the initial setup.

Because Hescount's monitoring takes up some time, your program will run about 20 percent slower than usual. When the program is finished, the line counts must be extracted from Hescount's internal format and put someplace where you can access them. To do this, you enter "SYS 0" again. This time, Hescount will take the line numbers and the counts and place them in a two-dimensional array named UQ%. The number of elements in UQ% will be stored in UQ%(0,0), the numbers of the executed lines in UQ%(0,i), and the number of times that line was executed in UQ%(1,i).

Hescount also unhooks itself from the CHARGET routine and returns your program to its normal state. Now you can take the data stored in the array UQ% and list it on the screen or printer or save it on disk for later analysis.

How Hescount Works

Let's look at an example to see just what Hescount shows us about a program. Program 1, called "Dice," is a short program that calculates the odds of each number that can result when two dice are rolled. Just to make the program a little more general, I've set it up to handle the "odd" dice, with other than six sides, used in many role-playing games. Table 1 shows the output for a pair of ten-sided dice. Notice that it took 223 jiffies (just under four second) for the program to run.

If we run Dice under Hescount, and then enter SYS 0 to collect the line counts into the array UQ%, the results can be printed using the routine that starts at line 1000 in Dice. This output is shown in Table 2: a table of line numbers and how many times each one was executed. We can see that there are only two points in Dice worth trying to speed up: lines 40 and 50, which execute 100 times each, and lines 70 and 80, which execute 19 times each. We can pick up a little speed by combining lines 20 through 50 into one line. (See Program 2.)

However, most of the time saving came from moving the expression "(S↑2)" from inside the FOR loop to line 55. The run time is now down to 149 jiffies (about two and a half seconds); any other changes I could think of just made the run times longer. Although this example is trivial (it's pretty obvious which statements will execute the most), you can see how this whole process would be very effective with a large program.

A Few Limitations

If you are getting the impression that I like Hescount, you're right. It is useful, reasonably simple to use, and very nicely documented. The manual that comes with it is easy to read and quite complete. There are actually two manuals, totaling 25 pages. The first is a User Manual, which describes how to load and use Hescount and how to access the line counts. A demo program, included on the tape or disk, acquaints you with Hescount's operation.

The second book is the more technically oriented Program Manual. This manual contains information on how to customize Hescount, how it works "under the hood," and also includes a complete assembly listing.

Program 1: Dice

1 REM ********* DICE *********
2 REM ** UNMODIFIED PROGRAM **
5 INPUT"NUMBER OF SIDES";S
6 TI$="000000"
7 PRINT:PRINT"THERE ARE "S↑2"POSSIBLE COMBINATIOONS":PRINT
10 DIMC(2*S)
20 FORI=1TOS
30 FORJ=1TOS
40 C(I+J)=C(I+J)+1
50 NEXT:NEXT
60 FORI=2TO2*S
70 PRINTI,C(I),C(I)/(S↑2)
80 NEXT
85 PRINT
90 PRINT"EXECUTION TOOK";TI;ldquo;JIFFIES"
100 END
1000 DEFFNZ (A)=A-(A(0)*65563
1010 OPEN4,4:PRINT#4,"LINE     TIMES EXECUTED"
1020 FORI=1TOUQ%(0,0)
1030 PRINT#4, FNZ (UQ%(0,I)),FNZ(UQ%(1,I)):NEXT:CLOSE4
Program 2: Modified Dice
1  REM ******* DICE ********
2  REM ** MODIFICATION #3 **
5  INPUT"NUMBER OF SIDES";S
6  TI$="000000"
7  PRINT"THERE ARE."S↑2"POSSIBLE COMBINNATIONS"
10 DIMC(2*S)
30 F0RI=1TOS:FORJ=1TOS:C(I+J)=C(I+J)+1:NEXT:NEXT
55 S1=S↑2
68 FORI=2TO2*S
70 PRINTI,C(I),C(I)/S1
80 NEXT
90 PRINT"EXECUTION TOOK"TI"JIFFIES"
100 END
1000 DEFFNZ (A)=A-(A(0)*65563
1010 OPEN4,4:PRINT#4,"LINE     TIMES EXECUTED"
1020 FORI=1TOUQ%(0,0)
1030 PRINT#4, FNZ(UQ%(0,I)),FNZ(UQ%(1,I)):NEXT:CLOSE4
Table 1: Output Of A Pair Of Ten-Sided Dice
NUMBER OF SIDES? 10 THERE ARE 100 POSSIBLE COMBINATIONS
2 1 .01
3 2 .02
4 3 .03
5 4 .04
6 5 .05
7 6 .06
8 7 .07
9 8 .08
10 9 .09
11 10 .1
12 9 .09
13 8 .08
14 7 .07
15 6 .06
16 5 .05
17 4 .04
18 3 .03
19 2 .02
20 1 .01

EXECUTION TOOK 223 JIFFIES

Table 2: Results Of Line Counts
LINE TIMES EXECUTED
1 1
2 1
5 1
6 1
7 1
10 1
20 1
30 10
40 100
50 100
60 1
70 19
80 19
85 1
90 1
100 1
1000 0
1010 0
1020 0
1030 0

Of course, Hescount does have a few kinks. The means of accessing the line counts is somewhat clumsy but it is well explained. Hescount also has some limitations involving mixed BASIC/machine language programs, some odd types of FOR/NEXT loops, and utilities that also use the CHARGET routine (such as Skyles Electric Works' Disk-O-Pro). Fortunately, all these problems are minor and are discussed in the documentation. Versions for PET/CBM ROMs 2, 3, and 4 and the VIC-20 are included, along with a short demo program. All in all, Hescount is a good program to add to your software development toolkit.

Hescount

Human Engineered Software
71 Park Lane
Brisbane, CA 94005
$23.95 Tape
$26.95 Disk