-- 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..