home *** CD-ROM | disk | FTP | other *** search
- Uses CRT;
- {═══════════════════════════ MICROMTR.PAS ═══════════════════════════}
- { Usage: MicroMtr (From Editor, just Run) }
- {═══════════════════════════ MICROMTR.PAS ═══════════════════════════}
-
- {- This demonstration illustrates the use of Assemble in place of }
- {- Inline to create (Assembly) Inline Directive/MACROs. The Macros }
- {- StartMicroMeter and StopMicroMeter are used to examine code }
- {- length and execution speed of the section of Pascal or Assembly }
- {- code placed between them. Precision is sufficient to measure }
- {- down to a single assembly language instruction, however be }
- {- forewarned: the actual in-place execution speed will depend on a }
- {- number of complicated factors, including Prefetch Queue status }
- {- and Byte/Word alignment. For this reason, differences of 10 }
- {- clock cycles (about 3 timer counts) should not be considered }
- {- significant. For further explanation please see Byron Sheppard, }
- {- "High-Performance Software Analysis on the IBM PC", BYTE Magazine }
- {- January 1987, p157. }
-
- {- StartMicroMeter and StopMicroMeter calls cannot be nested -}
-
- {- MAKE SURE START AND STOP 'MACROS' ARE OF EVEN BYTE LENGTH -}
- {- THEY SHOULD THEN GIVE AN ACCURATE COUNT FOR IN-PLACE CODE -}
-
-
- {════════════════ Global Variables used by MicroMeter ═══════════════}
- VAR
- CodeOverHead : WORD;
- AverageCount, CountOverHead,
- AverageCycles,CycleOverHead : LongInt;
- LoopLoc, Count, Counter, TimerSumLo, TimerSumHi, CodeCount : WORD;
- TimerSum: LongInt Absolute TimerSumLo;
-
- {═════════════════════════ StartMicroMeter ══════════════════════════}
- { MACRO to start timer and REPEATEDly execute subsequent code. Use }
- { MicroMeterInit(1) to examine sections of a working program. }
- {═════════════════════════ StartMicroMeter ══════════════════════════}
- PROCEDURE StartMicroMeter;
- ASSEMBLE {- Assembly Inline Directive -}
- ; Start Code
- Nop ; Pad to even byte length
- Mov Ax,Count
- Mov Counter,Ax
- Xor Ax,Ax
- Mov TimerSumLo,Ax
- Mov TimerSumHi,Ax
- Jmp Short PushLoopLC
- PopLoopLoc:
- Pop LoopLoc
- Jmp Short TimerLoop
- PushLoopLC:
- Call PopLoopLoc
- TimerLoop:
- ;- Initialize timer, counter 0
- Mov Al,$34 ;counter 0, LSB then MSB, mode 2, binary
- Out $43,Al ;mode register
- Xor Ax,Ax
- Out $40,Al ;Set LSB
- Out $40,Al ;Then MSB
- END Assemble; {- StartMicroMeter -}
-
-
- {══════════════════════════ StopMicroMeter ══════════════════════════}
- { MACRO to stop timer and REPEATEDly loop back to last Start. Use }
- { MicroMeterInit(1) to examine sections of a working program. }
- {══════════════════════════ StopMicroMeter ══════════════════════════}
- PROCEDURE StopMicroMeter;
- ASSEMBLE {- Assembly Inline Directive -}
- ; Stop code
- ;- read timer, counter 0
- Nop ;Pad to even byte length
- Mov Al,0
- Out $43,Al ;mode register
- In Al,$40
- Mov Dl,Al
- In Al,$40
- Mov Dh,Al ;Dx has 16 bit timer count
- Neg Dx ; = $10000 - Dx
- Add TimerSumLo,Dx
- IF C Inc TimerSumHi
- Dec Counter
- IF NZ Jmp LoopLoc ;Indirect Jmp to Addr stored during StartMicroMeter
- ;Else Finished: Use 4*TimerSum/Count to estimate clock cycles
- Call PopLocCounter
- PopLocCounter:
- Pop Ax
- Sub Ax,LoopLoc
- Sub Ax,CodeOverhead
- Mov CodeCount,Ax
- END Assemble; {- StopMicroMeter -}
-
-
- {══════════════════════════ MicroMeterRead ══════════════════════════}
- { Read accumulated sums from last Start/StopMicroMeter loop. }
- {══════════════════════════ MicroMeterRead ══════════════════════════}
- PROCEDURE MicroMeterRead;
- BEGIN
- AverageCount := Round(TimerSum/Count - CountOverHead);
- AverageCycles:= Round(4*TimerSum/Count - CycleOverHead);
- WRITELN(CodeCount,' bytes code ',
- 'Count: ',AverageCount,' Cycles: ',AverageCycles);
- END;
-
- {════════════════════════════ ReadCount ═════════════════════════════}
- { Display String S, Code Length, and Average timer counts from last }
- { StartMicroMeter/StopMicroMeter loop. }
- {════════════════════════════ ReadCount ═════════════════════════════}
- PROCEDURE ReadCount(S:String);
- BEGIN
- AverageCount:= Round(TimerSum/Count - CountOverHead);
- WRITELN(S,'':30-Length(S),CodeCount:5,' bytes code, Averages ',
- AverageCount,' Timer Counts');
- END;
-
- {════════════════════════════ ReadCycles ════════════════════════════}
- { Display String S, Code Length, and Average clock cycles from last }
- { StartMicroMeter/StopMicroMeter loop. (assumes 4 cycles/count) }
- {════════════════════════════ ReadCycles ════════════════════════════}
- PROCEDURE ReadCycles(S:String);
- BEGIN
- AverageCycles:= Round(4*TimerSum/Count - CycleOverHead);
- WRITELN(S,'':30-Length(S),CodeCount:5,' bytes code, Averages ',
- AverageCycles,' Clock Cycles');
- END;
-
-
- {══════════════════════════ MicroMeterInit ══════════════════════════}
- { Initialize Global repetition Count and determine overhead due to }
- { StartMicroMeter and StopMicroMeter code }
- {══════════════════════════ MicroMeterInit ══════════════════════════}
- PROCEDURE MicroMeterInit(RepCount:WORD);
- BEGIN
- Count := RepCount; {- Set Global Variable -}
- CodeOverHead := 0;
- CountOverHead := 0;
- CycleOverHead := 0;
- StartMicroMeter;
- StopMicroMeter;
- Write('Initializing: ');
- MicroMeterRead; {- Compute averages and display -}
- CodeOverHead := CodeCount;
- CountOverHead := AverageCount;
- CycleOverHead := AverageCycles;
- END; {PROCEDURE MicroMeterInit;}
-
-
-
-
- {══════════════════════ Demonstrate MicroMeter ══════════════════════}
- VAR
- n,Dummy : INTEGER;
-
- PROCEDURE MulTest;
- BEGIN
- WRITELN('Multiply tests:');
- StartMicroMeter;
- ASSEMBLE
- mov dl,15
- mul dl
- End; {Assemble}
- StopMicroMeter;
- ReadCycles('Mul Instruction');
-
- StartMicroMeter;
- ASSEMBLE
- mov dx,ax
- mov cl,4
- sal al,cl
- sub ax,dx
- End; {Assemble}
- StopMicroMeter;
- ReadCycles('Shift(Cl) and subtract');
-
- StartMicroMeter;
- ASSEMBLE
- mov dx,ax
- sal al,1
- sal al,1
- sal al,1
- sal al,1
- sub ax,dx
- End; {Assemble}
- StopMicroMeter;
- ReadCycles('Repeated Shift(1) and subtract');
-
- END; {PROCEDURE MulTest;}
-
- PROCEDURE IncTest;
- BEGIN
- WRITELN('Increment tests:');
- StartMicroMeter;
- Dummy := Dummy + 1;
- StopMicroMeter;
- ReadCycles('Dummy := Dummy + 1;');
-
- StartMicroMeter;
- Dummy := Succ(Dummy);
- StopMicroMeter;
- ReadCycles('Dummy := Succ(Dummy);');
-
- StartMicroMeter;
- Inc(Dummy);
- StopMicroMeter;
- ReadCycles('Inc(Dummy);');
-
- StartMicroMeter;
- Inc(Dummy);
- StopMicroMeter;
- ReadCycles('Inc(Dummy);');
-
- StartMicroMeter;
- Asm Inc Dummy;
- StopMicroMeter;
- ReadCycles('asm Inc Dummy');
-
- StartMicroMeter;
- Asm Inc Dummy;
- StopMicroMeter;
- ReadCycles('asm Inc Dummy');
-
- StartMicroMeter;
- Inc(Dummy);
- StopMicroMeter;
- ReadCycles('Inc(Dummy);');
-
- StartMicroMeter;
- ASSEMBLE
- Mov Ax,Dummy
- Inc Ax
- Mov Dummy,Ax
- End;
- StopMicroMeter;
- ReadCycles('asm Inc Ax:Dummy');
-
- END; {PROCEDURE IncTest;}
-
- BEGIN
- MicroMeterInit(1000);
-
- StartMicroMeter;
- Dummy := 0;
- StopMicroMeter;
- ReadCycles('Dummy := 0; ');
-
- StartMicroMeter;
- ASSEMBLE
- Mov Dummy,0
- End;
- StopMicroMeter;
- ReadCycles('Mov Dummy,0 ');
-
- StartMicroMeter;
- ASSEMBLE
- Xor ax,ax
- Mov Dummy,ax
- End;
- StopMicroMeter;
- ReadCycles('Xor Ax,Ax | Mov Dummy,Ax ');
-
-
- IncTest;
- MulTest;
- MicroMeterInit(100);
- StartMicroMeter;
- {- This is a MICROmeter - overflow beyond count 65535 is not detected -}
- {- Experiment by increasing the loop limit below to cause overflow -}
- FOR n := 1 TO 20 DO WRITE('Direct Video Write'#13);
- StopMicroMeter;
- ReadCycles('Direct Video Write');
- MicroMeterRead;
- END.
-