BIOS.BenchInterrupts.Mod 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. MODULE BenchInterrupts; (** AUTHOR "staubesv"; PURPOSE "Interrupt latency benchmarks"; *)
  2. (**
  3. Non-comrehensive list of aspects to be considered:
  4. - The garbage collector prohibits interrupts while running. Depending on the current state of the heap, this can
  5. introduce delays in the order of seconds
  6. - There can be multipe handlers per interrupt vector
  7. - The Machine.SoftInt is a temporary interrupt vector that is potentially used by other applications
  8. - Result is dependent on other interrupts that have a higher priority and can interrupt our handler
  9. *)
  10. IMPORT
  11. SYSTEM,
  12. Machine, Heaps, Streams, Commands, MathL;
  13. CONST
  14. (* Interrupt vector number for 1st level interrupt handler benchmark
  15. This is a temporary interrupt vector number that is potentially used for different purposes *)
  16. InterruptVectorNumber = Machine.SoftInt;
  17. MinNofSamples = 1000;
  18. MaxNofSamples = 1000000;
  19. VAR
  20. mhz : LONGINT;
  21. start, stop : HUGEINT;
  22. ngc : LONGINT;
  23. data : POINTER TO ARRAY OF LONGINT;
  24. PROCEDURE InterruptHandler(VAR state: Machine.State);
  25. BEGIN
  26. stop := Machine.GetTimer();
  27. END InterruptHandler;
  28. (* Software interrupt call *)
  29. PROCEDURE -SoftwareInterrupt;
  30. CODE
  31. #IF I386 THEN
  32. INT InterruptVectorNumber
  33. #ELSIF AMD64 THEN
  34. INT InterruptVectorNumber
  35. #ELSE
  36. unimplemented
  37. #END
  38. END SoftwareInterrupt;
  39. (** Start the 1st Level Interrupt Handler latency benchmark *)
  40. PROCEDURE Bench*(context : Commands.Context); (** [nofSamples] ~ *)
  41. VAR nofSamples, index, oldNgc, ignore : LONGINT;
  42. BEGIN {EXCLUSIVE}
  43. context.arg.SkipWhitespace; context.arg.Int(nofSamples, FALSE);
  44. IF (nofSamples < MinNofSamples) THEN nofSamples := MinNofSamples;
  45. ELSIF (nofSamples > MaxNofSamples) THEN nofSamples := MaxNofSamples;
  46. END;
  47. context.out.String("Starting 1st level interrupt handler latency benchmark (");
  48. context.out.Int(nofSamples, 0); context.out.String(" samples) ... ");
  49. context.out.Update;
  50. NEW(data, nofSamples);
  51. Machine.InstallHandler(InterruptHandler, InterruptVectorNumber);
  52. ignore := Machine.AcquirePreemption();
  53. oldNgc := Heaps.Ngc;
  54. FOR index := 0 TO LEN(data)-1 DO
  55. start := Machine.GetTimer();
  56. SoftwareInterrupt;
  57. data[index] := SHORT(stop - start);
  58. END;
  59. ngc := Heaps.Ngc - oldNgc;
  60. Machine.ReleasePreemption;
  61. Machine.RemoveHandler(InterruptHandler, InterruptVectorNumber);
  62. context.out.String("done."); context.out.Ln;
  63. END Bench;
  64. PROCEDURE CyclesToMs(cycles : HUGEINT; mhz : LONGINT) : LONGREAL;
  65. BEGIN
  66. RETURN LONGREAL(cycles) / (1000*mhz);
  67. END CyclesToMs;
  68. PROCEDURE ShowMs(cycles : HUGEINT; out : Streams.Writer);
  69. BEGIN
  70. IF (mhz # 0) THEN
  71. out.String(" ("); out.FloatFix(CyclesToMs(cycles, mhz), 0, 6, 0); out.String(" ms)");
  72. END;
  73. END ShowMs;
  74. (** Show the results of the last benchmark run *)
  75. PROCEDURE Show*(context : Commands.Context); (** mhz ~ *)
  76. VAR
  77. nofSamples, min, avg, max, i : LONGINT; sum : HUGEINT;
  78. diff, diffSum, standardDeviation : LONGREAL;
  79. BEGIN {EXCLUSIVE}
  80. context.arg.SkipWhitespace; context.arg.Int(mhz, FALSE);
  81. IF (data # NIL) THEN
  82. nofSamples := LEN(data);
  83. min := MAX(LONGINT); max := MIN(LONGINT); sum := 0;
  84. (* calculate min, max and sum *)
  85. FOR i := 0 TO LEN(data)-1 DO
  86. IF (data[i] < min) THEN min := data[i];
  87. ELSIF (data[i] > max) THEN max := data[i];
  88. END;
  89. sum := sum + data[i];
  90. END;
  91. avg := SHORT(sum DIV nofSamples);
  92. (* calculate standard deviation *)
  93. diffSum := 0;
  94. FOR i := 0 TO LEN(data)-1 DO
  95. diff := avg - data[i];
  96. diffSum := diffSum + (diff * diff);
  97. END;
  98. standardDeviation := MathL.sqrt(diffSum / nofSamples);
  99. context.out.String("NofSamples: "); context.out.Int(nofSamples, 0); context.out.Ln;
  100. context.out.String("Nof GC runs while benchmarking: "); context.out.Int(ngc, 0); context.out.Ln;
  101. context.out.String("CPU clock rate: ");
  102. IF (mhz # 0) THEN context.out.Int(mhz, 0); context.out.String(" MHz"); ELSE context.out.String("Unknown"); END;
  103. context.out.Ln;
  104. context.out.String("Interrupt Latency in CPU cycles: "); context.out.Ln;
  105. context.out.String("Min: "); context.out.Int(min, 0); ShowMs(min, context.out); context.out.Ln;
  106. context.out.String("Max: "); context.out.Int(max, 0); ShowMs(max, context.out); context.out.Ln;
  107. context.out.String("Avg: "); context.out.Int(avg, 0); ShowMs(avg, context.out); context.out.Ln;
  108. context.out.String("Standard Deviation: "); context.out.FloatFix(standardDeviation, 0, 0, 0); context.out.Ln;
  109. ELSE
  110. context.out.String("No data available."); context.out.Ln;
  111. END;
  112. END Show;
  113. END BenchInterrupts.
  114. System.Free BenchInterrupts ~
  115. BenchInterrupts.Bench 1000000 ~
  116. BenchInterrupts.Show 2000 ~