-- Copyright (C) 1984  by Xerox Corporation. All rights reserved. 
-- Calibrate.mesa, HGM, 11-Jan-84 17:15:43

DIRECTORY
  Ascii USING [CR],
  Inline USING [LowHalf],
  Process USING [GetPriority, MsecToTicks, Pause, Priority, SetPriority, Yield],
  ProcessorFace USING [SetMP],
  Put USING [Text],
  String USING [AppendChar, AppendLongDecimal, AppendLongNumber, AppendString],
  System USING [
    GetClockPulses, Microseconds, MicrosecondsToPulses, Pulses, PulsesToMicroseconds];

Calibrate: MONITOR
  IMPORTS Inline, Process, ProcessorFace, Put, String, System =
  BEGIN

  TestPulseConversion: PROCEDURE =
    BEGIN
    temp: STRING = [200];
    convert: ARRAY [0..12) OF LONG CARDINAL = [
      1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
      100000000, 200000000, 500000000, 1000000000];
    String.AppendString[temp, "Conversion Info, LAST[LONG CARDINAL] => "L];
    AppendLongCardinal[temp, LAST[LONG CARDINAL]];
    String.AppendChar[temp, Ascii.CR];
    String.AppendString[temp, "      Pulses => Microseconds =>       Pulses => Microseconds"L];
    String.AppendChar[temp, Ascii.CR];
    Put.Text[NIL, temp];
    FOR i: CARDINAL IN [0..12) DO
      pulses: System.Pulses;
      microseconds: System.Microseconds;
      temp: STRING = [200];
      pulses ← [convert[i]];
      AppendLongCardinal[temp, pulses];
      String.AppendString[temp, " => "L];
      microseconds ← System.PulsesToMicroseconds[pulses];
      AppendLongCardinal[temp, microseconds];
      String.AppendString[temp, " => "L];
      pulses ← System.MicrosecondsToPulses[microseconds];
      AppendLongCardinal[temp, pulses];
      String.AppendString[temp, " => "L];
      microseconds ← System.PulsesToMicroseconds[pulses];
      AppendLongCardinal[temp, microseconds];
      String.AppendChar[temp, Ascii.CR];
      Put.Text[NIL, temp];
      Process.Pause[Process.MsecToTicks[2000]];
      ENDLOOP;
    END;

  LookForGaps: PROCEDURE =
    BEGIN
    priorityPrev: Process.Priority ← Process.GetPriority[];
    first, last: System.Pulses;
    max: System.Microseconds ← 0;
    FOR i: CARDINAL IN [0..5) DO
      Process.SetPriority[LAST[Process.Priority]];
      FOR j: CARDINAL IN [0..1000) DO
        first ← System.GetClockPulses[];
        Process.Yield[];
        last ← System.GetClockPulses[];
        pulses ← last-first;
        microseconds ← System.PulsesToMicroseconds[[last-first]];
	max ← MAX[max, microseconds];
        IF microseconds > 350 THEN EXIT;
        ENDLOOP;
      Process.SetPriority[priorityPrev];
      ProcessorFace.SetMP[Inline.LowHalf[max]];
      IF microseconds > 350 THEN
        BEGIN
        temp: STRING = [200];
        String.AppendString[temp, "Long gap:  Yield took "L];
        String.AppendLongDecimal[temp, microseconds];
        String.AppendString[temp, " microseconds."L];
        String.AppendChar[temp, Ascii.CR];
        Put.Text[NIL, temp];
	END;
      Process.Yield[];
      ENDLOOP;
    BEGIN
    temp: STRING = [200];
    String.AppendString[temp, "The longest Yield took "L];
    String.AppendLongDecimal[temp, max];
    String.AppendString[temp, " microseconds."L];
    String.AppendChar[temp, Ascii.CR];
    Put.Text[NIL, temp];
    END;
    END;
  
  CalibrateCPU: PROCEDURE =
    BEGIN
    cyclesToTest: ARRAY [0..25) OF CARDINAL = [
      100, 100, 100, 100,
      100, 100, 100, 100, 100,
      500, 1000, 2000, 5000,
      10000, 10000, 10000, 10000, 10000,
      20000, 50000,
      50000, 50000, 50000, 50000, 50000];
    temp: STRING = [500];
    String.AppendString[temp, "Assuming a DLion gets 13100 cycles/sec."L];
    String.AppendChar[temp, Ascii.CR];
    String.AppendString[temp, "      Cycles      Pulses    Microsec  Cycles/Sec   %"L];
    String.AppendChar[temp, Ascii.CR];
    Put.Text[NIL, temp];
    FOR i: CARDINAL IN [0..25) DO
      temp: STRING = [200];
      cycles: CARDINAL = cyclesToTest[i];
      CollectNumbers[cycles];
      AppendLongCardinal[temp, cycles];
      AppendLongCardinal[temp, pulses];
      AppendLongCardinal[temp, microseconds];
      AppendLongCardinal[temp, cyclesPerSecond];
      AppendPercent[temp, cyclesPerSecond, 13100];
      String.AppendChar[temp, Ascii.CR];
      Put.Text[NIL, temp];
      Process.Pause[Process.MsecToTicks[5000]];
      ENDLOOP;
    END;

  cycles, pulses, microseconds, cyclesPerSecond: LONG CARDINAL ← 0;
  
  pointer: LONG POINTER TO LONG CARDINAL = @cycles;
  Decr: PROCEDURE [x: CARDINAL] RETURNS [CARDINAL] = BEGIN RETURN[x+2]; END;
  
  CollectNumbers: PROCEDURE [cyclesToSample: CARDINAL] =
    BEGIN
    string: STRING = "123"L;
    priorityPrev: Process.Priority ← Process.GetPriority[];
    first, last: System.Pulses;
    nanoSecPerCycle: LONG CARDINAL;
    -- Beware, things might hang (SV lockup) if our code (GF, EV) get swapped out.
    Process.SetPriority[LAST[Process.Priority]];
    first ← System.GetClockPulses[];
    THROUGH [0..cyclesToSample) DO
      x: CARDINAL ← 0;
      char: CHARACTER ← string[1];
      FOR i: CARDINAL IN [20..25) DO
        x ← x + 1;
	ENDLOOP;
      x ← Decr[x];
      pointer↑ ← pointer↑ + 1;
      ENDLOOP;
    -- This appears to go slow if an extra timeout scan happens, packet arrives or ...
    last ← System.GetClockPulses[];
    Process.SetPriority[priorityPrev];
    pulses ← last-first;
    microseconds ← System.PulsesToMicroseconds[[last-first]];
    SELECT microseconds FROM
      > 100000 =>
        nanoSecPerCycle ← System.PulsesToMicroseconds[[LONG[100]*pulses]]/(cyclesToSample/10);
      ENDCASE =>
        nanoSecPerCycle ← System.PulsesToMicroseconds[[LONG[1000]*pulses]]/cyclesToSample;
    cyclesPerSecond ← (1000000000)/nanoSecPerCycle;
    END;
  
  AppendLongCardinal: PROCEDURE [s: LONG STRING, n: LONG CARDINAL] =
    BEGIN
    temp: STRING = [20];
    String.AppendLongNumber[temp, n, 10];
    FOR i: CARDINAL IN [temp.length..12) DO String.AppendChar[s, ' ]; ENDLOOP;
    String.AppendString[s, temp];
    END;    
    
  AppendPercent: PROCEDURE [s: LONG STRING, n, m: LONG CARDINAL] =
    BEGIN
    temp: STRING = [20];
    String.AppendLongNumber[temp, (1000*n)/m, 10];
    FOR i: CARDINAL IN [temp.length..5) DO String.AppendChar[s, ' ]; ENDLOOP;
    FOR i: CARDINAL IN [0..temp.length) DO
      IF i = (temp.length -1) THEN String.AppendChar[s, '.];
      String.AppendChar[s, temp[i]];
      ENDLOOP;
    ProcessorFace.SetMP[0];
    Process.Pause[Process.MsecToTicks[100]];
    ProcessorFace.SetMP[Inline.LowHalf[(1000*n)/m]];
    END;    
    


  CalibrateCPU[];
  LookForGaps[];
  TestPulseConversion[];
  END.