-- Copyright (C) 1984 by Xerox Corporation. All rights reserved. -- CpuIdleImpl.mesa -- Last edited by: Hoffman 27-Mar-84 11:03:48 DIRECTORY CourierInternal USING [numberOfStreams], CpuIdle, Inline USING [LongDiv, LowHalf, LongMult], Process USING [Detach, GetPriority, Milliseconds, MsecToTicks, Pause, Priority, SetPriority, SetTimeout, Yield], ProcessPriorities USING [priorityClientHigh, priorityClientLow], SpecialSpace USING [MakeProcedureResident, SpecialError], System USING [GetClockPulses, MicrosecondsToPulses, Pulses, PulsesToMicroseconds]; CpuIdleImpl: MONITOR IMPORTS CourierInternal, Inline, Process, SpecialSpace, System EXPORTS CpuIdle = BEGIN publicationMsecs: Process.Milliseconds = 1000; priorityPublisher: Process.Priority = ProcessPriorities.priorityClientHigh; priorityIdler: Process.Priority = ProcessPriorities.priorityClientLow; cpu, cpuTen: LONG CARDINAL ← 0; cyclesPerRefresh, pulsesPerRefresh: LONG CARDINAL ← 0; calibrated: BOOLEAN ← FALSE; cycleCount: LONG CARDINAL ← 0; publicationInterval: CONDITION; GetRawCpuUtilization: PUBLIC PROCEDURE RETURNS [LONG CARDINAL] = BEGIN RETURN[cpu]; END; GetSmoothedCpuUtilization: PUBLIC PROCEDURE RETURNS [CARDINAL] = BEGIN RETURN[CARDINAL[cpuTen/100]]; END; GetCalibration: PUBLIC PROCEDURE RETURNS[ cyclesPerSecond, pulsesPerSecond: LONG CARDINAL, calibrateDone: BOOLEAN] = BEGIN RETURN[cyclesPerRefresh, pulsesPerRefresh, calibrated]; END; GetCycles: PUBLIC PROCEDURE RETURNS[cycles: LONG CARDINAL] = BEGIN RETURN[cycleCount]; END; StartIdler: PROCEDURE = BEGIN ENABLE UNWIND => NULL; priorityPrev: Process.Priority; Calibrate[]; priorityPrev ← Process.GetPriority[]; SpecialSpace.MakeProcedureResident[Idler! SpecialSpace.SpecialError => CONTINUE]; Process.SetPriority[priorityIdler]; Process.Detach[FORK Idler[]]; Process.SetPriority[priorityPublisher]; Process.SetTimeout[ @publicationInterval, Process.MsecToTicks[publicationMsecs]]; Process.Detach[FORK Updater[]]; Process.SetPriority[priorityPrev]; END; Calibrate: PROCEDURE = -- NOTE: If we get a frame fault with the priority set, calibration -- could be off by a considerable amount BEGIN cyclesToSample: CARDINAL = 10000; -- about a second on a DLion priorityPrev: Process.Priority ← Process.GetPriority[]; first, last: System.Pulses; nanoSecPerCycle: LONG CARDINAL; WHILE CourierConnections[] > 0 DO -- because of the comment below Process.Pause[Process.MsecToTicks[1000]]; ENDLOOP; Process.SetPriority[LAST[Process.Priority]]; first ← System.GetClockPulses[]; THROUGH [0..cyclesToSample) DO cycleCount ← SUCC[cycleCount]; Process.Yield[]; ENDLOOP; -- This appears to go slow if an extra timeout scan happens, -- packet arrives or ... -- Unfortunately, that causes confusion when idle > 100% last ← System.GetClockPulses[]; cycleCount ← cycleCount - cyclesToSample; Process.SetPriority[priorityPrev]; nanoSecPerCycle ← System.PulsesToMicroseconds[[LONG[1000]*(last - first)]]/cyclesToSample; cyclesPerRefresh ← (1000000*publicationMsecs)/nanoSecPerCycle; pulsesPerRefresh ← System.MicrosecondsToPulses[publicationMsecs*LONG[1000]]; calibrated ← TRUE; END; CourierConnections: PROCEDURE RETURNS [CARDINAL] = INLINE BEGIN RETURN[CourierInternal.numberOfStreams] END; Idler: PROCEDURE = BEGIN DO -- forever THROUGH [0..10000) DO cycleCount ← SUCC[cycleCount]; Process.Yield[]; ENDLOOP; ENDLOOP; END; Updater: ENTRY PROCEDURE = BEGIN startPulses: LONG CARDINAL ← System.GetClockPulses[]; startCycles: LONG CARDINAL ← cycleCount; pulsesThisRefresh, cyclesThisRefresh: LONG CARDINAL ← 0; idle: CARDINAL ← 0; DO startPulses ← startPulses + pulsesThisRefresh; startCycles ← startCycles + cyclesThisRefresh; WAIT publicationInterval; -- get cpu utilization pulsesThisRefresh ← System.GetClockPulses[] - startPulses; cyclesThisRefresh ← cycleCount - startCycles; THROUGH [0..10) DO cyclesThisTry: LONG CARDINAL = cyclesThisRefresh*pulsesPerRefresh/pulsesThisRefresh; idle ← Inline.LowHalf[cyclesThisTry*10000/cyclesPerRefresh]; IF idle > 10000 THEN { -- Calibration screwed up cyclesPerRefresh ← cyclesPerRefresh + 1; LOOP} ELSE EXIT; REPEAT FINISHED => idle ← 10000; ENDLOOP; cpu ← (10000 - idle); cpuTen ← Inline.LongDiv[cpu + Inline.LongMult[CARDINAL[cpuTen],9], 10]; ENDLOOP; END; -- Mainline Code Process.Detach[FORK StartIdler[]]; END..