MODULE BenchInterrupts;
IMPORT
SYSTEM,
Machine, Heaps, Streams, Commands, MathL;
CONST
InterruptVectorNumber = Machine.SoftInt;
MinNofSamples = 1000;
MaxNofSamples = 1000000;
VAR
mhz : LONGINT;
start, stop : HUGEINT;
ngc : LONGINT;
data : POINTER TO ARRAY OF LONGINT;
PROCEDURE InterruptHandler(VAR state: Machine.State);
BEGIN
stop := Machine.GetTimer();
END InterruptHandler;
PROCEDURE -SoftwareInterrupt;
CODE {SYSTEM.AMD64}
INT InterruptVectorNumber
END SoftwareInterrupt;
PROCEDURE Bench*(context : Commands.Context);
VAR nofSamples, index, oldNgc, ignore : LONGINT;
BEGIN {EXCLUSIVE}
context.arg.GetInteger(nofSamples, FALSE);
IF (nofSamples < MinNofSamples) THEN nofSamples := MinNofSamples;
ELSIF (nofSamples > MaxNofSamples) THEN nofSamples := MaxNofSamples;
END;
context.out.String("Starting 1st level interrupt handler latency benchmark (");
context.out.Int(nofSamples, 0); context.out.String(" samples) ... ");
context.out.Update;
NEW(data, nofSamples);
Machine.InstallHandler(InterruptHandler, InterruptVectorNumber);
ignore := Machine.AcquirePreemption();
oldNgc := Heaps.Ngc;
FOR index := 0 TO LEN(data)-1 DO
start := Machine.GetTimer();
SoftwareInterrupt;
data[index] := SHORT(stop - start);
END;
ngc := Heaps.Ngc - oldNgc;
Machine.ReleasePreemption;
Machine.RemoveHandler(InterruptHandler, InterruptVectorNumber);
context.out.String("done."); context.out.Ln;
END Bench;
PROCEDURE CyclesToMs(cycles : HUGEINT; mhz : LONGINT) : LONGREAL;
BEGIN
RETURN Machine.HIntToLReal(cycles) / (1000*mhz);
END CyclesToMs;
PROCEDURE ShowMs(cycles : HUGEINT; out : Streams.Writer);
BEGIN
IF (mhz # 0) THEN
out.String(" ("); out.FloatFix(CyclesToMs(cycles, mhz), 0, 6, 0); out.String(" ms)");
END;
END ShowMs;
PROCEDURE Show*(context : Commands.Context);
VAR
nofSamples, min, avg, max, i : LONGINT; sum : HUGEINT;
diff, diffSum, standardDeviation : LONGREAL;
BEGIN {EXCLUSIVE}
context.arg.GetInteger(mhz, FALSE);
IF (data # NIL) THEN
nofSamples := LEN(data);
min := MAX(LONGINT); max := MIN(LONGINT); sum := 0;
FOR i := 0 TO LEN(data)-1 DO
IF (data[i] < min) THEN min := data[i];
ELSIF (data[i] > max) THEN max := data[i];
END;
sum := sum + data[i];
END;
avg := SHORT(Machine.DivH(sum, nofSamples));
diffSum := 0;
FOR i := 0 TO LEN(data)-1 DO
diff := avg - data[i];
diffSum := diffSum + (diff * diff);
END;
standardDeviation := MathL.sqrt(diffSum / nofSamples);
context.out.String("NofSamples: "); context.out.Int(nofSamples, 0); context.out.Ln;
context.out.String("Nof GC runs while benchmarking: "); context.out.Int(ngc, 0); context.out.Ln;
context.out.String("CPU clock rate: ");
IF (mhz # 0) THEN context.out.Int(mhz, 0); context.out.String(" MHz"); ELSE context.out.String("Unknown"); END;
context.out.Ln;
context.out.String("Interrupt Latency in CPU cycles: "); context.out.Ln;
context.out.String("Min: "); context.out.Int(min, 0); ShowMs(min, context.out); context.out.Ln;
context.out.String("Max: "); context.out.Int(max, 0); ShowMs(max, context.out); context.out.Ln;
context.out.String("Avg: "); context.out.Int(avg, 0); ShowMs(avg, context.out); context.out.Ln;
context.out.String("Standard Deviation: "); context.out.FloatFix(standardDeviation, 0, 0, 0); context.out.Ln;
ELSE
context.out.String("No data available."); context.out.Ln;
END;
END Show;
END BenchInterrupts.
SystemTools.Free BenchInterrupts ~
BenchInterrupts.Bench 1000000 ~
BenchInterrupts.Show 2000 ~