Dec 232017
 
Pascal News Letter #4 --> Binary-Trees and a TP Profiler.
File PNL004.ZIP from The Programmer’s Corner in
Category Pascal Source Code
Pascal News Letter #4 –> Binary-Trees and a TP Profiler.
File Name File Size Zip Size Zip Type
PNL004.TXT 75793 22202 deflated
PROFILE.PAS 4573 1442 deflated
PROFILER.PAS 18380 3983 deflated
PROTIMER.ASM 2499 844 deflated

Download File PNL004.ZIP Here

Contents of the PNL004.TXT file






//////// // // //
// // /// // //
// // //// // //
//////// // // // //
// // //// //
// // /// //
// // // ///////





Pascal NewsLetter
Issue #4
September, 1990


Editor: Pete Davis













The Programmer's Forum BBS is the home of
PNL. It can be reached in Washington, DC at
(202)966-3647. Information is available
through the following locations:

FidoNet: Pete [email protected]:109/138
Genie: P.DAVIS5
BitNet: [email protected] & [email protected]
InterNet: [email protected]
or [email protected]
or [email protected]

Table of Contents
Introduction .................................. 3 (P.D.)
Letters to the Editor ......................... 5 (****)
Binary Trees For Sorting ...................... 7 (R.M.)
Putting the Spurs to Pascal ................... 15 (J.R.)
For Beginners ................................. 22 (B.G.)
Review of TechnoJock's Turbo Toolkit .......... 27 (J.A.)
Review of Turbo Pascal-The Complete Reference . 29 (P.D.)
Key to author names:
P.D. -> Pete Davis - Senior editor and writer
B.G. -> Bob Gowans - Staff writer
J.R. -> Jan-Erik Rosinowski - Contributing writer
R.M. -> Robert Mashlan - Contributing writer
J.A. -> John A. Abele - Contributing writer
3
Introduction
Well, PNL003 finally got off, so now I guess it's about time
to get started on issue #4. I was so pleased with PNL003 that I
was worried I might break my arm patting myself on the back. It
was a good issue, though, and I was very pleased. I hope issue 4,
and all the issues to follow for that matter, are just as good or
better.
I received a wonderful letter the other day from a reader
who said he got a subscription to the Cobb Group newsletter on
Turbo Pascal. He said that he and a friend compared it to PNL and
said that they preferred mine. It's this kind of support that
really makes me want to keep writing this.
I hope that people will keep up the contributions. They've
been a fantastic support for me. Without them, I don't know if
I'd be able to go on with this. There have already been a lot
sent that I couldn't have written myself and I think that makes
it more interesting for the regular readers.
Because of the time consuming nature of writing the
NewsLetter, I'm afraid I might be stuck with only putting out one
issue every two months or so. I doubt it would really be much
longer than that. I am looking into getting some more permanent
writers who I can count on to write an article for every issue
and maybe even pitch in on the editing. Right now, Bob Gowans is
the only person who has had the time to be able to contribute on
a regular basis. PNL is still young, though, and growth can be
expected, but it might slow down a bit. Since the first issue,
the PNL has grown very quickly, but things seem to be steadying
out a bit.
Well, in this issue we've got an article on Binary Trees, a
very powerful data structure, which once understood, can be very
easy to implement. I had already planned on doing an article on
Binary Trees, but got a submission from a reader on them. Since
Robert's article covers the basics of Binary trees, I decided I
would take a bit more complex route and discuss the AVL tree
balancing algorithm in a future issue.
I've also had a reader, John Abele, who sent in a terrific
review of the TechnoJock's Turbo Toolkit. I am doing a review of
Turbo Pascal - The Complete Reference by Stephen K. O'Brien.
These will be only the start of reviews that will be done on
books, toolkits, and software related to Pascal.
I think the star of this issue is going to be the PROFILER
and accompanying article that are in this issue. I've used to
profiler a bit myself and have found it very useful. I hope you
like it. Originally the article was written in German and thanks
to the tremendous effort of one of my BBS users, Howard Sanner, I
4
was able to get the article translated to English. Howard
suggested, and I agreed, that it was best to leave the article
using some of the expressions that are distinctly German, in the
article, instead of trying to write something in English that
wouldn't convey the meaning the author was trying to get across.
I hope this poses no problems.
All-in-all, I think this issue came out very well, and
again, let me thank all those who contributed and hopefully I can
get other readers to contribute also.
5
Letters to the Editor
From uunet!GWUVM.BITNET!HJ647C
From: uunet!CUNYVM.CUNY.EDU!CDCKAB%EMUVM1.BITNET (Karl Brendel)
To: Pete Davis
Date: Fri, 27 Jul 1990 13:04 EDT
Pete--
I've just read the second issue of PNL (the first one I've seen).
Thanks for this work!
Not wanting to be critical of article--being critical is so
much easier than writing--but Craig Thurber's references to the
$L compiler directive is completely wrong, to the point that you
really need to issue a correction in your next issue.
Reference _Turbo Pascal Reference Guide_ for 5.0 or 5.5, pp
434-5 and 437-8 in my copy. {$L filename} is the "link object
file" directive. {$L- or {$L+ are the "local symbol information"
directives. Craig indicates that {$L filename} is the local
symbol information directive and that it is ignored if debug
information is off ({$D-}) (PNL002, pg 17). He shows an external
file linked as {$L+ HELLO.OBJ}. This will not work. It appears
that Craig doesn't understand how to use the link directive.
It appears to me that neither he nor you tried to compile or
use his code. As printed, the program "Hello" will neither
compile nor run. One of the compile errors is from a typo (a
problem every publication has), but the other is from Craig's
misuse of {$L+. I urge you to require your writers to compile and
run every single line of code they send you, and to repeat the
compilation and running yourself before publication.
Best wishes. I'm looking forward to PNL003.
Karl Brendel
Centers for Disease Control
Epidemiology Program Office
Atlanta, GA
Karl,
You bring up a valid point. To be honest, not all of the
code that goes into the articles themselves has really been
checked by me to see if it works. I do read through the articles
and try to get an idea of the competency of the writer and see if
the ideas are valid. I must admit that from time to time things
will slip by, but from now on, actual code going into the
articles will be tested.
It appears Craig had made a small mistake and I thank you
for pointing it out to the readers. I am afraid that this will
6
probably happen again, at some point and hope that in the future
readers will respond, as you have to make the corrections that
slip by us here at PNL.
_Pete Davis
Editor
7
Binary Trees for Sorting
By Robert Mashlan
A binary tree is a useful sorting device in structured
programming. It is a quick and easy way to maintain data in a
sorted order.
A binary tree is composed of units called 'nodes'. These
nodes are linked together in a special way to form a tree. A
tree requires the use of pointers, and each node of the tree must
be allocated dynamically. If you don't quite understand the
concept of a pointer, don't worry, just read on.
A pointer is nothing more than a variable that holds the
address of another variable. Pointers are used to access dynamic
variables, that is, variables that you can create or destroy at
will. Besides possessing this flexibility, you may hold more
data with dynamic variables than you could by using global and/or
local variables.
In a program, the construction of pointers is
straightforward. In the type declaration of a program consider
the declaration
Type
stringptr = ^string;
or in English, 'Let stringptr denote that all things of this type
point to things of type string!'. In the declaration there is a
caret '^' which simply means 'pointer to'. It takes on a
slightly different meaning when used in the actual code.
Now we need to declare an instance of a pointer so that it can be
used:
Var
sp : stringptr;
What we have done is to declare an instance of a variable
that points to a string. This variable doesn't take much space;
pointer in Turbo Pascal it is 4 bytes.
Now we need to allocate storage for a string on the heap:
begin
New(sp);
What we have done here is told a set of routines called the
'Heap Manager' that we need some space for a string. If there
are 255 bytes in a row, the Heap manager complies and sets the
value of sp to the address of the space that it gave us for the
string. This space will be protected from being given to other
8
requests for space until the space is reclaimed with dispose.
Now that we have allocated space for it, we can now use it. The
caret '^' comes into play again as it is needed to dereference a
pointer. This means 'refer to the thing I point at'.
sp^ := 'I am a dynamic string!';
writeln(sp^);
Now when we no longer need the string, we can get rid of it,
possibly reusing the space that it occupied. This is done with
the dispose function:
dispose(sp);
end.
After using dispose, the value that sp had is now no longer
valid. That means don't read it, don't change it, don't use it
for anything unless you reallocate space for it with the new
procedure. A pointer with an invalid value that is being used
often causes really mean bugs. It may write to almost anywhere
in memory, like the next instruction to be executed, the IDE, the
operating system, etc. The problem is that these kind of
problems may not show up until much later, such as when you exit
your program and run another.
You should also try not to lose track of your pointers, or
you'll get a 'memory leak' that wastes space that could be used
for other purposes. Whenever a pointer goes out of scope always
dispose the space it points at.
A pointer can also have the special value nil. This simply
means that the pointer points at nothing. It can be assigned to
any pointer.
Ok, now on to the forest:
First a graphical demonstration of creating a binary tree:
Say we have these pieces of data and we want to sort them in
alphabetical order:
G, B, A, H, I, E, J, F, C, D
The first letter G, we will denote as the root of our tree:
G
/ \
The node that G is in points to other nodes, which are
currently pointing at nothing.
9
Now we add the next letter B. To add it, we use the algorithm:
1) Start at the root node
2) if the node is empty then
place the data here
else
if the data is greater than the data at the node then
go to the right node
else
go to the left node
go to step 2
By using this algorithm, we now have
G
/ \
B
( Unused datum: A, H, I, E, J, F, C, D )
The next step would be:
G
/ \
B
/
A
to
G
/ \
B H
/ \
A I
to
G
/ \
B H
/ \ \
A E I
to
G
/ \
B H
/ \ \
A E I
\
J
10
to
G
/ \
B H
/ \ \
A E I
\ \
F J
to
G
/ \
B H
/ \ \
A E I
\ \
F J
to
G
/ \
B H
/ \ \
A E I
/ \ \
C F J
to
G
/ \
B H
/ \ \
A E I
/ \ \
C F J
\
D
Now we have a strange looking upside down tree that seems to
have no reason to it. To use this tree, we must transverse it.
This is the name of a special algorithm that we use to 'travel'
through the tree so that it comes out in sorted order. The
traversal algorithm:
1) start at the root node
2) do procedure 2
3) end
4) if node is not empty then
do this procedure with the left node
process the data at this node
do this procedure for the right node
11
Using this algorithm with the tree we start at the root node. The instructions tell us to go left, so we go to B. Next we
go to A. Since there is no left node to A, we process A, or in
this case, write it down. We now return to B and print it. The
instructions say go right, so we end up at E. Now we go left to
the C node and print it. Mentally traversing the rest of this
tree is left as an exercise to the reader.
The traversing algorithm is called recursive, that is, the
algorithm calls itself.
If you have a good mental picture of what a tree is, read on
for a demonstration of implementing it in Pascal.
----------------------
Program TreeSort;
Const
MaxStr = 255; { The maximum length of strings to be used }
Type
Str = string[MaxStr]; { Our string type to be used }
{ We now declare a node record and pointer type: }
nodeptr = ^node;
node = record
data : str;
left, right : nodeptr;
end; { record }
{ The node record type has three fields. The first field data,
is used to store a string, the things we are to sort. The left
and right fields contain pointers to other nodes. When these
nodes aren't pointing at other nodes, they will be assigned the
value nil. }
{ Next we must have a root to our tree: }
Var
root : nodeptr;
{ Root is not actually the root, but a pointer that will point to
the root node of our tree. }
InData : str;
{ This variable will be used by the main block of this program }
12
Function NewNode( var newdata : str ) : nodeptr;
{ The purpose of this function is to allocate and and initialize
space for a node. The newdata parameter is the string that
will be placed into the Node's data field. newdata is passed
by reference to reduce stack usage. }
var
result : nodeptr; { the value to be returned }
begin
New(result); { allocate space for the new node }
with result^ do
begin
left := nil; { set these pointers to point at nothing }
right := nil;
data := newdata; { store the data in the node }
end; {with}
NewNode := result;
end; {Function NewNode}
Procedure Add( var newdata : str );
{ This procedure is an implementation of the 'word' algorithm
used
to add data to the graphical tree. The string that is passed
as a parameter will be stored in the tree. }
var
chase : nodeptr; { this pointer is used for }
{ moving through the tree }
done : boolean; { the done flag }
Function Compare( var a,b : str ) : boolean;
{ This nested function tells the outer procedure the order
that the data is to be sorted. It is to return TRUE is a is
to go to the left of b. In this case we are comparing
strings in alphabetical order with no regard to case }
var
i, limit : integer;
begin
if length(a) < length(b) then { limit is to be the maximum}
limit := length(a) { number of times to loop, }
else { In this case, the length }
limit := length(b); { of the shortest string. }
i := 1;
while ( i <= limit ) and ( Upcase(a[i]) = UpCase(b[i]) ) do
i := succ(i); { Increment i }
{ at this point either a mismatch occured or the strings
13
Matched up to the length of the shortest string }
if UpCase(a[i])=UpCase(b[i]) then
Compare := length(a) > length(b)
{ longer strings go after shorter ones }
else
Compare := UpCase(a[i]) > UpCase(b[i]);
end; {Function Add.Compare}
begin
if root = nil then
root := NewNode(newdata) { gotta start somewhere }
else
begin
done := false;
chase := root; { start at root }
repeat
with chase^ do
begin
if Compare( data, NewData ) then {go to the left}
if left = nil then
begin {put the data here}
left := NewNode(newdata);
done := true;
end
else
chase := left { move on to the left node }
else { go to the right }
if right = nil then
begin { put the data here }
right := NewNode(newdata);
done := true;
end
else
chase := right; { move on to the right node }
end; {with}
until done;
end; {else root=nil}
end; {Procedure Add}
Procedure Transverse( np : nodeptr );
{ This is the transversal procedure to the tree. It calls the
nested function Process in sorted order. Note that this
procedure is recursive. }
Procedure Process;
begin
writeln(Output, np^.data);{write data to standard output}
end; {Procedure Transverse.Process}
begin
14
if np <> nil then
with np^ do
begin
Transverse(left);
Process;
Transverse(right);
end; {with}
end; {Procedure Transverse}
{Pretty short, huh?}
begin {Program TreeSort}
{ This program is a filter, that is, it takes input from
standard input, sorts it, and send it to standard output.
It works like the sort filter you get with MS-DOS }
root := nil; { initialize Root }
while( not eof(Input) ) do { read all the input datum }
begin
readln(Input,InData);
Add(InData);
end;
Transverse(root);
{ transverse the tree and write out the datum }
end. {Program TreeSort}
----------------------
To use this program, create an ascii text file of strings to
sort. Type in the command:
>treesort < data.dat
and the sorted output will be displayed.
Binary trees are useful for many sorting applications, and
are fairly quick. There are a few disadvantages to binary trees,
namely the recursive nature of the transversal algorithm. In a
case where the incoming data is nearly or already sorted. The
tree will appear to look like a linked list, or a very long
chain. This will cause the transversal algorithm to call itself
many times and possibly cause a stack overflow error.
That's it. If you have in questions or comments, you may ask
them in the FidoNet International Pascal Echo or via FidoNet
NetMail to Robert Mashlan @ 1:147/34.33
15
PUTTING THE SPURS TO PASCAL
by Jan-Erik Rosinowski
Does it un-nerve you when, with increasing development time,
your program runs progressively slower? Editors that cannot keep
up with the cursor? Databases that seem to be stored on cassette
tape? Though the complexity of the problem can cause bewildering
frustration, it is constructive to use a profiler at this point.
It will expose the time-consuming procedures, so that nothing
will stand in the way of subsequent significant optimization of
the program. Such a profiler for Turbo Pascal v. 4 and 5 programs
is described below.
There are two approaches to program optimization, the
theoretical and the practical. They will both be briefly
sketched.
PROGRAM OPTIMIZATION IN THEORY AND PRACTICE

The theorist uses the following method: using a simply
canonical approach, he searches for the theoretically lower
limits of the best algorithm. The time to formulate and verify an
algorithm is limited only by the author's maximum writing
speed--at the latest, after a midnight snack of pizza he is in
the know. For him, the implementation of the algorithm is almost
secondary: This would require him to write a small program, and
in such a manner could many free hours and years pass!
In contrast, the graceless practitioner: He writes his
database program using a BASIC interpreter. Before thinking two
minutes about the program, he has written 100 lines. After a
hundred test runs that help him in the "verification" of his
program, he has a bug free version. He often thinks the
following: The program's done. Only he can no longer coordinate
the long coffee break his computer's run time has forced upon
him. After a compiler doesn't help him, he decides to re-write
the program in assembler. For quick access to his data, he once
again uses a linear, sequential search.
AND HOW ONE DOES IT RIGHT
Though both examples were exaggerated, it is clear that
neither approach is workable. Clever optimization of a program
comes after a careful analysis of the problem and costs. Then one
must next analyze the kernel functions of the planned program. In
a database program, these would be, for example, functions to
insert, update, delete, search, and index data records. Along
with the expected quantity and format of data and operations, one
16
also selects appropriate data structures. Thus one chooses here
suitable algorithms, for example, linear searching, B-trees, or
hashing. An estimation of the expected overall complexity, the
provision of resources (time, money, tools), and taste/experience
will quickly determine the high or low-level programming language
to be used.
After solving the general complexity of the problem, one
should, in the first, analytical phase, in no case underestimate
the time taken up by operating system functions. In many programs
they claim a large part of the total run time. Bypassing DOS and
BIOS calls will definitely yield a copious increase in speed, at
the cost of many gray hairs when porting the program to another
system. Routines with extreme requirements, for example, a screen
handling package for a text program, will need to be purchased.
AND THEN!
After choosing appropriate algorithms, data structures, and
programming languages, places ripe for optimization can be
quickly identified. There are, of course, many sloppily-written
small routines that are called unexpectedly often. If these are
optimized first, relatively small optimizations will yield a big
improvement in run time. Routines should be re-written in
assembler or, for example, a bubble sort replaced with a
quicksort.
The amount of improvement to be gained from using a profiler
is inversely proportional to the amount of thought put into the
original design. In other words, the greater effort put into a
statement, analysis, and evaluation of the problem, the fewer the
opportunities for improvement. The true art of efficient
programming thus lies in appropriate decisions in the analysis
and coding phase.
PRACTICE
With the profiler's help, you can quickly do away with the
worst time wasters in a Turbo Pascal program. The program package
consists of a preprocessor (PROFILER.PAS) as well as the analysis
unit, PROFILE.PAS. The work of the preprocessor is to imbed a
call to "PBegin" and PEnd" at the beginning and end of each
function, respectively. (See listings 4 and 5.) When the program
runs, these procedures capture timing statistics. Both the format
and use of upper and lower case in the source code are
unimportant. Include files and source code of available units are
both processed. In addition, the Pascal ugliness of "Record,"
"Case," and "End" (in contrast to Modula-2 or single logic only
17
"End") is digested without complaint.
The programs were developed under Turbo Pascal 5.0. Only
changes to a few CONST declarations and case selectors are needed
to adapt it to the previous version. The assembler part,
PROTIMER.ASM, was assembled with MASM.
WILLY GO!
The preprocessor "PROFILER" runs only from the DOS command
line. The first parameter expected is that of the name of the
module to be analyzed. This can be either one unit or the whole
program. Modules linked in with "uses" or include directives are
each processed. If one wants to omit a module (e.g., one that
exclusively reads the keyboard via the BIOS), one can name the
file to be excluded after the /X: option. Names without extension
are interpreted as ".PAS," and this applies to all source files
(thus units to be excluded with "/X: XYZ.TPU" will cause an
error).
In order not to inflate the profiler's size, it assumes that
the program to be processed has no syntax errors. This isn't
really a restriction, since the profiler is intended to be used
to put the finishing touches on the program. The profiler will
also not be of help to people who, as already mentioned above,
plan their programs in the coding phase. The module to be
profiled must always have either a "Program" or "Unit"
identifier.
THE BIG RENAMING
So that one can't work with source code the profiler has
processed (the time checking calls will not be found in the
finished program), the files to be processed are renamed. Thus
the first and last letters of the extension are exchanged (".PAS"
becomes ".SAP"). This can nevertheless lead to problems should a
program be run through the profiler again, as well as with files
like, for example, "INCLUDE.010." The latter must be renamed to
something reasonable. The PAS-SAP collision is best avoided with
a batch file that will copy the identically named ".SAP" files
over the ".PAS" files. The latter may then be deleted.
INTERPRETING THE RUN TIME PROFILE
After one has compiled the profiler-processed program and
tested it adequately, the unit PROFILE will generate the run time
analysis [PROGRAM/UNIT NAME].PRF from the file [PROGRAM/UNIT
18
NAME].PR$ produced by the profiler. In the first column is the
procedure name, in the second the number of calls, and in the
third column the run time in milliseconds. In contrast to the
notion of run time in reference (1), here it means only the run
time of the procedure itself. It does not include that of the
subprocedures it calls. This considerably simplifies usage, so
that one can directly see the true time a procedure consumes
(figure 1). By means of the DOS SORT program one can generate a
list by run time, so that one can immediately find the slow parts
of a large program.
The definition of run time in reference (1), in contrast to
that given here, always shows 100% for the main program's run
time, which is true in few cases.
A marginal note: Anyone who tests the entire program being
analyzed with the profiler and gets unexpected results must
remember that the time the profiling unit itself takes can be
compensated for by setting the variable "adjusttimer" to a more
precise value. The true run time of the program is small compared
to that of the stopped.
Should one wish to test the program isolated in diverse
situations, one can delete the uninteresting procedures from the
".PR$" file with a text editor. (Delete whole lines.) This will
greatly reduce the confusion of paper, since the profile unit
will only emit a run time profile for procedures in the ".PR$"
file.
Should the program terminate before the "End." statement,
there will nevertheless be a run time analysis. In this case the
profiler will issue a corresponding warning. This can happen, for
example, if the profiler is used to analyze itself, since the
main program terminates with a halt statement. The run time of
the "open" procedure will be approximate.
One small piece of bad news: External procedures (in
assembler or C, for example) cannot be directly analyzed. If this
is desired, one must enclose them in an outer procedure. This
presupposes changes to the external procedures (public names); an
extension of the profiler in this regard would be excessively
complex.
INTERNALS
The profiler consists of two kernel procedures: one, the
recursive function "prep_module" that inserts the calls to the
profiler. It is recursive, since it calls itself in analyzing
uses and include modules. This serves to simplify the file
management, since thus Turbo Pascal gets stuck with the dirty
19
work. The second important procedure, "getsymbol," supplies
"prep_module" with tokens and handles include modules. That the
rest of allocated storage isn't released should not trouble you;
DOS also takes no notice of it, since the management is handled
internally by Turbo Pascal.
The most important function of the unit PROFILE is
"readtimer." It makes possible accurate timing at microsecond
intervals; it thus has substantially greater resolution than the
BIOS or DOS timers. In spite of what the manuals say, the DOS
timer cannot resolve time finer than five milliseconds. The more
precise results of the "readtimer" procedure are also not
surprising, when we consider the fact that the BIOS timer, which
is also used by DOS, is incremented whenever the timer used in
the "readtimer" procedure counts down to zero. Timer zero of the
8253 chip acts as time keeper. It is critical in this connection
to coordinate with the 8259 interrupt controller; under the worst
circumstances it can falsify the measurements "catastrophically"
(by five milliseconds). This can happen if the timer has been
latched and an interrupt is triggered between the time the
counter value is stored and the interrupt request register is
read. An extremely low counter value indicates that request flag
has been set. Since this is nevertheless influenced by the timer-
independent CPU frequency, an adjustment of the constant "corr"
in PROTIMER.ASM is needed. Also, the DRAM refresh and installed
cache programs (DOS buffers, FASTOPEN, VCache, etc.) falsify the
measurement not inconsiderably. For these reasons it is important
to keep the timer resolution under 1/100000 seconds and not to
put the unit PROFILE into an overlay. The constant "fracs" in
PROFILE.PAS determines the number of decimal digits to which the
run time in milliseconds will be displayed.
The unit PROFILE will normally be the first unit entered
once the program is started and the last left (via an Exitproc).
The counter is installed, and the correction value needed to
account for calls to "PBegin" and "Pend" calculated, via calls to
the initialization blocks. The local stack as well as the storage
space "procstore" are statically declared, and the constants
"stacksize" and "maxprocedures" must be adjusted. Dynamic memory
allocation in the profiler might cause errors, since the program
to be analyzed could also manage its storage by means of
MARK/RELEASE or also DISPOSE.
Listing 5 is presented as an example of capturing timing
information. Time measurement begins with PBegin (1). Since
nothing is on the stack yet, PBegin stores only the number of the
active procedure (1) as well as the system time. The call to
PBegin (2) in the procedure "a" causes the time used in procedure
1 (stored time-elapsed time- correction value) to be saved in
"procedure[1].time." Again the number of the active procedure (2)
and the system time are pushed on the stack. PEnd performs the
analog: it closes off the active procedure and then pops its
20
record off the stack. Since the system time is once again read,
the second call to PEnd can determine the run time of the main
program correctly.
LIMITATIONS OF USE
Use of the profiler can lead to problems in the following
circumstances:
1. As mentioned above, extra steps are needed
to analyze procedures written in other languages.
They must be given different public names so that
one can write enclosing procedures with their
original names. If only a few modules are involved,
it may be quicker to change the names in the Pascal
source.
2. Programs or PCs that themselves make use of
timer zero can cause minor irritations and
influence the unit PROFILE, respectively. In this
case, the procedure READTIMER (PROTIMER.ASM) must
be changed.
3. The run time analysis is only procedural.
The time taken by DOS and run time library calls
must also be accounted for. One would be well
advised, for example, to redefine the file
functions in their own unit. "READ" and "WRITE"
statements unfortunately often evade this method.
In individual, truly critical cases, one can extend
the ".PR$" file with a pseudo-procedure after the
last line. It will then carry all the PBegin and
PEnd calls associated with the "READ" and "WRITE"
statements.
4. Time critical procedures, as, for example,
a serial port handler, will take longer to run, and
thus the profiler may interfere with their
operation. For this reason, interrupt procedures
are automatically excluded from analysis. One must
either delete the PBegin and PEnd statements from
time critical procedures or put them in units or
include modules that are excluded with the /X
directive from analysis.
5. "Inline" procedures cannot be analyzed with
any tricks. This corresponds to their character.
The shortest machine programs execute in a fraction
of a microsecond. Anyone who would like to analyze
such a time critical section should perhaps
21
consider coding it completely in assembler.
With these hurdles crossed, nothing stands in the way of
analyzing your critical source code. One should, however, always
put readability and correctness of a program before its speed,
otherwise one can program the same as in C or BASIC.

References

1. Profilgewinn, c't 5/89.
2. Interrupts auf Reihe, 5/86.
3. Die PC-Referenz


Figures
1. PROTEST.PRF: This is the result of the analysis
of PROTEST with the unit PROFILE.

Listings

1. PROFILER.PAS: This program links calls into
Turbo Pascal 4/5 compatible source code that
make possible an analysis accurate to the
microsecond.
2. PROFILE.PAS: This unit measures the procedure
run times and generates a run time profile from
them.
3. PROTIMER.ASM: This procedure can read the timer
with microsecond precision.
4. PROTEST.SAP: The program to be analyzed
appeared thus before the application of the
profiler.
5. PROTEST.PAS: The profiler has here performed
all of its work.
22
For Beginners
By Bob Gowans
In the last issue of PNL the beginners column discussed the
use of the Pascal assignment operator ( := ) to assign values to
variables. We were concerned mainly with operations on the
variable data type integer, a simple Pascal data type, and were
made aware of other Pascal data types such as char, Boolean and
real. In this issue we will further increase our knowledge of
variable operations by designing a simple program and
implementing our design as a Pascal program. In particular we
will be paying close attention to correct initialization of
variables and input and output.
Later you will be presented with a simple problem and from
this we will devise a design to solve this problem but first lets
discuss the technique by which we may solve the problem. First we
must make sure that we fully understand the problem. How?... By
asking relevant questions so that we are made fully aware of all
the details of the problem. For example, if we were asked to
update a catalogue of books we might ask How many books are
there? Are they to be ordered? How are they to be ordered, by
title or by author? You can probably think of many more questions
to ask until you are fully satisfied that you thoroughly
understand the problem.
Next we would start to devise a solution keeping in mind
that our ultimate aim is to implement the solution to the problem
by making use of a computer. Devising an efficient solution when
using a computer is something that comes about as you gain
experience of your computer system's capabilities, its advantages
and disadvantages.
One of the best methods of problem solving is by a process
known as TOP-DOWN DESIGN. This involves simplifying the problem
into a series of broad terms and then adding more detail as you
look at each term. For example, the solution to the problem of
how to update a bank account is given as follows:
(a) Give a broad outline
1. read in transactions
2. bring the accounts up to date
3. print out a list of transactions
(b) Start to refine the broad outline
1.1 read in credits
1.2 read in debits
2.1 calculate the total credits
2.2 calculate the total debits
2.3 calculate the new balance
3.1 print out credits
3.2 print out debits
23
3.3 print out new balance
Each step would then be further refined until we are at a
position to implement the solution.
Implementing the solution would result in the construction
of a Pascal program from our refined design. When the program is
entered into the computer and successfully executed then the
associated problem is solved. Whenever a solution is to be
implemented there are three important stages to consider :
1) Data input or reading in information to the program.
2) Processing instructions - the main body of the
program.
3) Results or output. For example, to the printer or
screen or some other output device.
After having completed the implementation of your design
successfully, always go back over what you have done, ask
yourself if you managed to solve the problem to your satisfaction
and does the solution work for all cases that could arise?
Finally it is vital that you make a written record of what you
have done. Say for example several months later, you want to
amend the program. If you have clear, concise documentation
covering all aspects of your design and solution then the process
of amendment should be made much less painful.
Now lets take a simple problem and using the above, process
solutions ready for implementation in Pascal.
Problem 1 : We are going back to the bank again. This time the
bank manager has asked us to devise a program that will assist
his customers. He wants an interactive program that will prompt
the user for the balance in his deposit account and then print
out, to the computer screen, the new balance with interest at the
end of the first interest period.
First lets ask some questions :
1) What is the current rate of interest?
2) Over what period is the interest calculated?
3) How is the new balance to be calculated?
4) What will happen if there is a withdrawal from the account?
Ask as many questions as you like until you are fully
satisfied that you understand the problem. For the purpose of
this problem the bank manager supplies you with the following
answers :
1) Interest is paid annually at 13%
2) The period of interest is quarterly ie 3 months
3) The new balance is the current deposit plus the accumulated
interest.
24
4) The account is new and no withdrawals are allowed
We are now in a position to construct a broad design of the
intended program.
1. set values of variables ( or initialize variables )
2. calculate the new balance at the end of the quarter
3. write out the result
The broad outline is easy and understandable and although
this is a much simplified case the same principles apply when
dealing with more complex design. Let us continue by refining the
broad outline to a more specific list of instructions.
1.1 initialize interest rate
1.2 initialize interest period
1.3 initialize deposit
2.1 calculate interest
2.2 set balance to deposit + interest
3.1 write out 'New balance is ', balance
The design is now at a stage where it could be implemented
as a Pascal program, however there is nothing to stop you from
further refining the design if you think it necessary. At this
point it would be beneficial to stop and reflect over our design
for a moment or two. In our design there are three statements
asking us to initialize certain data, if a data table is
constructed we can make clear the data structures and what we
intend to do with them.
Identifier Description Type
========== =========== ====
deposit amount of money in account real variable
rate interest rate per year real variable
interest calculated interest real variable
quarter period over which the
interest is calculated real variable
balance total money in the account
after first quarter real variable
The design has introduced a new data type REAL. A real data
type is defined as 'positive and negative numbers that include
decimal points'. Our real variables must be initialized, or given
a starting value before they can appear in an expression in the
program. It is true to say that many Pascal systems will
automatically initialize variables to zero, however it is not
good programming practice to presume this and it is much better
if you ensure that all variables used in the program are properly
initialized.
Using the data table we can now write the declarations part
of the program ( the part where all the variables are declared ).
25
var
deposit : real;
rate : real;
quarter : real;
interest : real;
balance : real;
Note this could also be written as
var
deposit,rate,quarter,interest,balance : real;
Initializing the variables in Pascal is as follows, using the
statements from lines 1.1, 1.2 and 1.3 of our design
rate := 0.13; { 13% as a decimal fraction }
quarter := 0.25; { 1/4 of a year expressed as a decimal }
readln(deposit);
The first two lines make use of the Pascal assignment
operator ( := ) which we discussed in the last issue of PNL. The
readln statement is new to us and merits a brief discussion. The
use of the readln statement results in assigning a value to a
variable from an external source ie from outside the program. As
our program specified an interactive design we expect the user to
input some information, a passing of information must take place
between the user and the computer. The program will temporarily
halt when it encounters the readln statement, expecting some data
to be input. It is vital that interactive programs communicate
while they run so that the user will know when he is required to
input the data. The way to do this is to use a program prompt. It
is also important that interactive prompts ask make clear their
purpose. Lets add an interactive prompt to our program ensuring
it comes before the readln statement.
write('Please enter your deposit here > ');
Steps 2.1 and 2.2 of our design are fairly straight forward
and are implemented as follows :
interest := deposit*rate*quarter;
balance := deposit + interest;
Finally step1 requires the output to the screen for the
information of the user.
writeln('The new balance is ',balance:10:2);
The writeln statement informs the user of his balance plus
interest and provides a neat format. The :10 after the variable
balance allows a field width of 10 characters for the output and
the :2 ensures the output is rounded to two decimal places. Try
26
the program without these output controls and note the results.
The whole program can now be put together;
program new_balance;
{ calculates balance on deposit at a rate of 13 % over 3
months }
var
deposit : real; { entered by user }
rate : real; { current rate of interest}
quarter : real; { a period of three months }
interest : real; { calculated interest on deposit }
balance : real; { the new balance }
begin
rate := 0.13;
quarter := 0.25;
write('Please enter your deposit here > ');
readln(deposit);
interest := deposit*rate*quarter;
balance := deposit + interest;
writeln('New balance is ',balance:10:2)
end.
In conclusion top down design is a method for designing a
solution to a problem that is going to be implemented on a
computer. If you look at the design, it is understandable to a
non programming person as it conveys a broad outline of the
problem. With further levels of refinement and a data table you
are ready to implement your design. Show your final coded program
to the same non programming person and the chances are that he
will have no idea what it is about. By designing your programs
before coding them, you will have a much more clear understanding
of exactly what your program does and will find that coding soon
becomes routine and effortless.
Error : In PNL # 3 the following line should be inserted in the
program add_up
after male := 100; :- total := male + female;
I hope that this did not distract from the understanding of the
program.
27
TechnoJock's Turbo Toolkit
A Review
by John A. Abele
Those of us who are serious/professional programmers need to
know about those rare individuals who have become programmer's
programmers. These folks write the toolkits and other utilities
that save the rest of us from a lot of tedious "grunt work" in
our programming.
TechnoJock's Turbo Toolkit is a well done series of 12 Turbo
Pascal units that is worthy of your consideration. It is
published by TechnoJock Software, Inc. of Houston, Texas.
Briefly, the 12 units are as follows: 1) fast screen
updating, 2) windows and boxes, 3) user input training, 4)
directory display and retrieval, 5) keyboard manipulation and
reading, 6) dynamic list management (this one is a real winner),
7) menu display, 8) nested menuing, 9) pull down (Lotus-like)
menuing, 10) data type reading (like reading only integers from
the keyboard), 11) string manipulating (some good functions found
here), and 12) things that don't fit anywhere else such as date
manipulating, file information, on-screen clock and some printer
testers.
You'll find some razzle-dazzle procedures in this toolkit,
such as sliding part of a screen in from the left or windows that
appear to explode from the center.
What I appreciate about this toolkit is its overall concern
with what the screen looks like. We are all aware that some of
the best programs never get used because the screen is sloppy or
un-inviting to the user. The programmer who uses this toolkit is
constantly encouraged to make a nice looking screen.
Definitely "home-brewed", these units bear the stamp of
experience: one programmer knowing what another programmer is
likely to need. This shows itself in the intuitive names given
to procedures and functions. A procedure named "TempMessageBox"
is fairly self-explanatory as to what it is likely to do.
The Toolkit sells for $49.95 and includes full source code
to all the units, a printed manual and a diskette full of short
demo programs showing how to use each of the units.
I have, on several occasions, written to Bob Ainsbury, the
so-called "janitor" of TechnoJock Software, Inc., with questions
or problems about the units. In EVERY CASE I have received
either a personal letter explaining how to modify the source code
to do what I want, or, a diskette with a fixed bug. This support
alone is well worth the price of registration. In addition, there
28
are no royalty payments for using his units in compiled programs
you distribute and he gives his customers price breaks on
upgrades, etc.
Are there any minuses? Yes, I've found two things that may
stand in your way when using this toolkit. One, a minor
complaint, is that the manual could be cleaned up. There are
several inconsistent references to procedure calls and places
where some information is missing. These errors are not serious
enough to prohibit your effectively using the manual, but they
may slow you down at times. A second and more serious
consideration is getting used to how one uses all the functions
and procedures in the toolkit. Fortunately, the disk comes with
an ample supply of programs which demo how to use the various
units. But be prepared to spend some time looking at these
programs and studying the code in them. Doing so at the
beginning will save frustration later. You probably won't hit
the ground running with this toolkit.
Beginner and advanced programmers who are looking for a
workhorse toolbox that can do a lot and get the job done should
consider TechnoJock's Turbo Toolkit.
29
Turbo Pascal - The Complete Reference

A Review
By Pete Davis
I picked this book as my first to review because I feel that
this book is invaluable for any Turbo Pascal Programmer. The book
would be useful for everyone from beginner to the veteran Turbo
Pascal Programmer. Stephen K. O'Brien, the Author is obviously
very comfortable with Turbo Pascal and his book is official
enough to have been published by Borland-Osbourne/McGraw-Hill.
My copy is actually for Version 4 but it has been re-
released for Version 5.5 of Turbo Pascal, which for the most part
is almost identical in content with the addition of coverage of
some 5.5 features.
The first seven chapters are devoted mostly to the beginner,
covering everything from basic data structures to program
structure to the Turbo Pascal environment. Chapter eight then
begins on more complex ideas like pointers and dynamic memory.
The explanations of ideas are very clear and to the point
and the most useful feature is the volume of examples included in
the text. Almost every idea covered includes examples which drive
home the point of every section.
My personal favorite is chapter eighteen : 'Optimizing Turbo
Pascal Programs', in which the author provides incredible insight
into how to make you programs run faster and use less memory.
This chapter alone nearly pays for the book, especially when you
are involved in large projects where speed and code size are very
important.
Another nice feature is the Procedure and Function reference
near the end of the book. This and other reference areas in the
book make the Turbo Pascal Reference Guide, which comes with
Turbo Pascal, almost worthless. (I shouldn't really say that, as
the reference guide is quite useful, but many of the more
important aspects are covered in The Complete Reference).
I give Stephen K. O'Brien five stars for a fantastic book.
If you have been using Turbo Pascal for a long time, or you are
just learning to use it, I suggest that you grab a copy and read
through it. It is by far the most useful book on Turbo Pascal
that I have ever seen.
_Pete Davis
Editor
30
Conclusion
Well, I would first like to thank everyone for being so
patient in waiting for the release of this issue of the Pascal
NewsLetter. I apologize for the delay, but there were a lot of
things that held this issue up. Some of them, many of you already
know about. Between my vacation and some computer problems, there
was about a two week delay.
When I was just getting ready to start finishing up the
issue, I got a the Profiler article and program which I just had
to include in this issue. I think you'll agree that it was worth
the wait. Getting the article translated to English was the last
thing holding this issue up, but it was worth the wait for me.
I would like to thank everyone who contributed to this
issue, in particular, I would like to thank Bob Gowans for his
continued support and work in the For Beginners column. I would
like to thank Jan-Erik Rosinowski for a fantastic program. His
contributions are welcome here anytime. I would also like to
thank Howard Sanner for putting in a lot of time in translating
the article for me. I couldn't have done it without him.
I have a few surprises that I hope I can spring in the next
issue, but I can't be sure of whether or not things will go
through by then. If not, I still plan on having a good issue out.
Please send in your contributions. They're what keeps this
newsletter coming out. Even if you don't write well, send in the
best you can do, and if you're uncomfortable with it, I'll be
happy to go through and edit it.
Also, please keep the comments and suggestions coming.
They're a great help.
Until the next issue, happy computing.
_Pete Davis

31
The Pascal NewsLetter is Copyrighted by Pete Davis.
Articles submitted by others are the property of the authors and
are used with permission. They may not be treated separately
from this newsletter without the author's permission and thus
maintain all distribution rules of the newsletter as a whole. It
may be freely distributed in un-modified form, but no charge
whatsoever may be incurred on the recipient. All code is provided
'as-is' with no guarantees whatsoever.
The Pascal NewsLetter can be obtained from the following
locations:
GEnie : General Electric Network for Information
Exchange. It is located in the IBMPC
filelist.
Simtel : Internet address: 26.2.0.74 or
Simtel20.ARPA It is located in the
directory.
Programmer's Forum : This is the home of the PNL.

Each issue can be found in
the MAG directory from the main area.
The number is on the title page.
If you would like to receive back issues of PNL
directly from me, send a diskette and $2.00 for shipping.
Don't forget to include your address.
Send your order to:
Peter Davis
4851 Brandywine St. NW
Washington, DC 20016
If you are a SysOp that will regularly carry PNL and
would like to have your bulletin board listed as such, here,
send me a message either by postal mail or at one of the
electronic addresses given on the title page, with your
bulletin board's name, phone number, and your name.
32
Distribution List
The following is the phone numbers to bulletin boards known
to carry PNL. If you would like your bulletin board's name and
number added to or deleted from this list, please send me a
message at one of my many addresses. I can not guarantee whether
a listed board will have any particular issue, however.
The Programmer's Forum ................. Phone: (202) 966-3647
The Programmer's Forum is the home of the PNL.
The Bored .............................. Phone: (512) 303-0471
Classic City ........................... Phone: (404) 548-0726
Theive's World ......................... Phone: (713) 463-8053
Hippocampus ............................ Phone: (203) 484-4621
Rogers State College BBS ............... Phone: (918) 341-8982
The Foxtrot BBS ........................ Phone: (914) 567-1814
Turbo City BBS ......................... Phone: (209) 599-7435
Austin IEMUG/MIDI BBS .................. Phone: (512) 528-0626
Laser Publishers ....................... Phone: (918) 438-2749
Fargo RBBS-PC .......................... Phone: (701) 293-5973
Momentary Lapse of Reason .............. Phone: (704) 327-6361
The Demon's Den ........................ Phone: (508) 433-2702
The Cannibal Cafe ...................... Phone: (508) 840-6589
IBM Tech FIDO .......................... Phone: (508) 433-6491
The User Friendly BBS .................. Phone: (704) 323-8223
The Disseminator BBS (Australia)........ Phone: 61-7-368-1239
Beyound Frontiers BBS (Denmark)......... Phone: (+45)8694-1609
Collision Theory ....................... Phone: (703) 503-9441
Ed-Net 9600 ............................ Phone: (604) 732-8877


 December 23, 2017  Add comments

Leave a Reply