-- Copyright (C) 1984, 1985 by Xerox Corporation. All rights reserved.
-- IdleTime.mesa
-- HGM, 21-May-85 23:35:01
-- last edited by Hankins 14-Aug-84 8:44:29
DIRECTORY
Inline USING [LowHalf],
LogDefs USING [DisplayNumber, Percentage],
Process USING [
Detach, GetPriority, Milliseconds, MsecToTicks, Priority, SetPriority,
SetTimeout, Yield],
ProcessPriorities USING [priorityClientHigh, priorityClientLow],
ProcessorFace USING [SetMP],
SpecialSpace USING [MakeProcedureResident],
System USING [
GetClockPulses, MicrosecondsToPulses, Pulses, PulsesToMicroseconds];
IdleTime: MONITOR IMPORTS Inline, LogDefs, Process, ProcessorFace, SpecialSpace, System =
BEGIN
-- Types, Constants, Vars:
updateDisplay: CONDITION;
displayUpdateMsec: Process.Milliseconds ← 1000;
priorityPublisher: Process.Priority ← ProcessPriorities.priorityClientHigh;
priorityIdler: Process.Priority ← ProcessPriorities.priorityClientLow;
-- CPU utilization related declarations:
cycles: LONG CARDINAL ← 0;
cyclesPerRefresh, pulsesPerRefresh: LONG CARDINAL ← 0; -- set by Calibrate
idleFive: CARDINAL ← 0; -- last sec, average last 10 sec (percentage*100)
idlePercent: LogDefs.Percentage ← LAST[LogDefs.Percentage];
-- Internal Procedures --
Idler: PROCEDURE = {
DO
THROUGH [0..10000) DO cycles ← cycles.SUCC; Process.Yield[]; ENDLOOP;
ENDLOOP};
Calibrate: PROCEDURE =
BEGIN
cyclesToSample: CARDINAL = 10000; -- about a second on a DLion
priorityPrev: Process.Priority ← Process.GetPriority[];
first, last: System.Pulses;
nanoSecPerCycle: LONG CARDINAL;
Process.SetPriority[Process.Priority.LAST];
first ← System.GetClockPulses[];
THROUGH [0..cyclesToSample) DO cycles ← cycles.SUCC; Process.Yield[]; ENDLOOP;
-- This seems slow if an extra timeout scan happens, packet arrives or ...
-- Unfortunately, that causes confusion when idle > 100%
last ← System.GetClockPulses[];
cycles ← (cycles - cyclesToSample);
Process.SetPriority[priorityPrev];
nanoSecPerCycle ←
System.PulsesToMicroseconds[[LONG[1000] * (last - first)]] / cyclesToSample;
cyclesPerRefresh ← (1000000 * displayUpdateMsec) / nanoSecPerCycle;
pulsesPerRefresh ← System.MicrosecondsToPulses[
displayUpdateMsec * LONG[1000]];
END;
Publisher: ENTRY PROCEDURE =
BEGIN
startPulses: LONG CARDINAL ← System.GetClockPulses[];
startCycles: LONG CARDINAL ← cycles;
pulsesThisRefresh, cyclesThisRefresh: LONG CARDINAL ← 0;
idle: CARDINAL ← 0;
Process.SetPriority[priorityPublisher];
DO
startPulses ← (startPulses + pulsesThisRefresh);
startCycles ← (startCycles + cyclesThisRefresh);
-- wait for a second
WAIT updateDisplay;
-- now update
pulsesThisRefresh ← (System.GetClockPulses[] - startPulses);
cyclesThisRefresh ← (cycles - 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;
idlePercent ← idle / 100;
--idleTen ← Inline.LongDiv[idle + Inline.LongMult[idleTen,9], 10];
-- this latter would be more interesting info (slower fluctuations) but
-- not sure of the cost of latter calculation so won't use, instead try this:
idlePercent ← idleFive ← (idlePercent + idleFive * 4) / 5;
ProcessorFace.SetMP[100-idlePercent];
ENDLOOP;
END;
Initialize: PROCEDURE =
BEGIN -- once-only initialization.
priorityPrev: Process.Priority;
Process.SetTimeout[@updateDisplay, Process.MsecToTicks[displayUpdateMsec]];
SpecialSpace.MakeProcedureResident[Idler];
Calibrate[];
-- start up Publisher process
Process.Detach[FORK Publisher[]];
priorityPrev ← Process.GetPriority[];
-- start up Idle process
Process.SetPriority[priorityIdler];
Process.Detach[FORK Idler[]];
Process.SetPriority[priorityPrev];
LogDefs.DisplayNumber["Idle time"L, [percent[@idlePercent]]];
END; --Initialize
-- Main Body:
Initialize[];
END.
13-Aug-84 9:40:40: blh - threw away old code and copied from Klamath ActivityImpl hack.