ComputeServerMaintenanceImpl:
CEDAR
MONITOR
IMPORTS AMBridge, AMModel, AMProcess, AMTypes, Basics, BasicTime, CedarProcess, Commander, CommandTool, ComputeServerControllerRpcControl, ComputeServerInternal, ComputeServerRpcControl, ComputeServerServer, ComputeServerStatistics, FSBackdoor, FSFileOps, Idle, Interpreter, IO, Loader, LupineRuntime, MessageWindow, PrincOpsUtils, Process, ProcessBackdoor, Rope, RPC, SafeStorage, SummonerControllerControl, SymTab, SystemVersion, UserCredentials, UserProfile, ViewerIO, ViewerOps, VMSideDoor, VMStatistics, WatchStats, WorldVM
EXPORTS ComputeServerControl, ComputeServerInternal, ComputeServerStatistics
SHARES ComputeServerServer
= BEGIN
Variable Declarations
All code invoked by this process should be resident
ROPE: TYPE = Rope.ROPE;
TimeUpThisIncarnation: PUBLIC INT ← 0;
RequestesThisIncarnation: PUBLIC INT ← 0;
TimeBusyThisIncarnation: PUBLIC INT ← 0;
TotalTimeUp: PUBLIC INT ← 0;
TotalRequestes: PUBLIC INT ← 0;
TotalTimeBusy: PUBLIC INT ← 0 ;
watchStatsRecord: WatchStats.WatchStatsRecord;
lastNoGFI: INT ← -1;
noGFIChanged: BOOL ← TRUE;
LastRMReclamations: INT;
LastTime: BasicTime.GMT ;
serverMachineName: RPC.ShortROPE;
serverMachinePupAddress: RPC.ShortROPE;
wasUp: BOOL ← FALSE;
isIdle: BOOL ← FALSE; -- is Cedar "idle" or not
aConditionSomewhere: LONG POINTER TO CONDITION ← NIL;
usingVerticalRetrace: BOOL ← TRUE;
verticalRetraceTV: AMTypes.TV;
pointerToVerticalRetraceTV: LONG POINTER TO CONDITION ← NIL;
myConditionForCPUStats: CONDITION;
notifyCPUStatsProcess: LONG POINTER TO PrincOps.ProcessStateBlock ← NIL;
PackageEntry: TYPE = ComputeServerInternal.PackageEntry;
CmdEntryObject: TYPE = ComputeServerInternal.CmdEntryObject;
CmdEntry: TYPE = ComputeServerInternal.CmdEntry;
ServiceEnabled: PUBLIC BOOL ← FALSE;
IdleTransitionsEnabled: PUBLIC BOOL ← FALSE;
whatsActiveProcessDead: CONDITION;
whatsActiveProcess: PROCESS ← NIL;
active: BOOL ← FALSE;
enabled: BOOL ← FALSE;
levelCounters: ARRAY PrincOps.Priority OF INT;
backgroundSeen: INT ← 0;
timeOutType: TYPE = ARRAY [0..maxIndex) OF RECORD[process: PrincOps.PsbIndex, gfh: PrincOps.GlobalFrameHandle, pc: CARDINAL];
timeout: REF timeOutType;
maxIndex: CARDINAL = 50;
index: CARDINAL ← 0;
TerminalImplGF: AMTypes.TV;
searchReadyList: BOOLEAN ← TRUE; -- sometimes the user gets the machine gets into a state where searching the ready list is a bad idea. This boolean allows the user to stop the Spy from searching the ready list.
maxVerticalRetraceProcessIndex: CARDINAL = 5;
verticalRetraceProcesses:
ARRAY [0..maxVerticalRetraceProcessIndex)
OF
RECORD[
psbi: PrincOps.PsbIndex,
seenCounter: INT, -- ranges from 0 through 10000; bumped when seen, debumped when not seen
seenThisTime: BOOL
];
nextVerticalRetraceProcesses: CARDINAL ← 0;
verticalRetraceProcessCount: INT ← 0;
maxVerticalRetraceProcessCount: INT = 5;
vrpLockSet: BOOL ← FALSE;
vrpLockAvailable: CONDITION ← [timeout: 0];
triedToPowerOff: BOOL ← FALSE;
Server Startup and Shutdown
ServerOn: Commander.CommandProc = {
argv: CommandTool.ArgumentVector ← NIL;
controllerName, remoteCommandDirectory, localCommandDirectory: Rope.ROPE ← NIL;
IF ServiceEnabled THEN RETURN ["Server already enabled"];
argv ← CommandTool.Parse[cmd ! CommandTool.Failed => { msg ← errorMsg; CONTINUE; }];
IF argv = NIL THEN RETURN[$Failure, msg];
IF argv.argc > 1 THEN controllerName ← argv[1];
IF argv.argc > 2 THEN remoteCommandDirectory ← argv[2];
IF argv.argc > 3 THEN localCommandDirectory ← argv[3];
SummonerControllerControl.StartUpController[controllerName];
msg ← StartUpServer[controllerName, remoteCommandDirectory, localCommandDirectory];
IF ~Rope.IsEmpty[msg] THEN SummonerControllerControl.ShutDownController[];
};
StartUpServer:
PUBLIC
PROC [controllerName: Rope.
ROPE ←
NIL, remoteCommandDirectory: Rope.
ROPE ←
NIL, localCommandDirectory: Rope.
ROPE ←
NIL]
RETURNS [msg:
ROPE ←
NIL] = {
name, password: ROPE;
ComputeServerInternal.LastActiveTime ← BasicTime.Now[];
[name, password] ← UserCredentials.Get[];
msg ← ComputeServerInternal.InitCommands[remoteCommandDirectory, localCommandDirectory];
IF ~Rope.IsEmpty[msg] THEN RETURN;
ServiceEnabled ← TRUE;
ComputeServerInternal.ReportServerEvent[type: serverEnabled, command: NIL, startTime: BasicTime.nullGMT, endTime: BasicTime.nullGMT, remoteMachineName: NIL, userName: NIL];
TRUSTED {Process.Detach[FORK TickStatistics[]]; };
ComputeServerInternal.ControllerGVName ← IF Rope.IsEmpty[controllerName] THEN UserProfile.Token["Summoner.ControllerName"] ELSE controllerName;
IF ComputeServerInternal.ControllerGVName = NIL THEN ComputeServerInternal.ControllerGVName ← "PaloAlto1.summoner" ;
ComputeServerRpcControl.ExportInterface[
interfaceName: [ type: "ComputeServer.summoner", instance: ComputeServerInternal.MyNetAddressRope, version: [1,1]],
user: name,
password: RPC.MakeKey[password]
! LupineRuntime.BindingError => CONTINUE;];
ComputeServerInternal.ControllerInterface ← ComputeServerControllerRpcControl.ImportNewInterface[
interfaceName: [ type: "ComputeServerController.summoner", instance: ComputeServerInternal.ControllerGVName, version: [1,1]]
!
RPC.ImportFailed => {
SummonerControllerControl.ControllerCannnotBeImported[why];
CONTINUE;
};
];
IF ComputeServerInternal.ControllerInterface #
NIL
THEN {
SummonerControllerControl.NoticeControllerIsUp[];
TellControllerAboutExtraCommands[];
};
ComputeServerInternal.InitStats[ComputeServerInternal.myHostName, ComputeServerInternal.MyNetAddressRope];
TRUSTED {Process.Detach[FORK ComputeServerInternal.SummonerServerMonitor[]]; };
StartCounting[];
};
StartCounting:
PUBLIC
ENTRY
PROC = {
priority: CedarProcess.Priority;
enabled ← TRUE;
WHILE whatsActiveProcess # NIL AND ~active DO WAIT whatsActiveProcessDead; ENDLOOP;
IF ~active
THEN {
priority ← CedarProcess.GetPriority[];
CedarProcess.SetPriority[realTime];
TRUSTED {Process.Detach[whatsActiveProcess ← FORK WhatsActive[]]; };
CedarProcess.SetPriority[priority];
};
};
StopCounting:
PUBLIC
ENTRY
PROC = {
IF ~active THEN RETURN; -- already stopped
enabled ← FALSE;
};
WhatsActive:
PROC =
TRUSTED {
topProcess: PrincOps.PsbHandle;
lastTopProcess: PrincOps.PsbHandle;
noBackgroundProcesses: INT ← 0;
done: BOOL ← FALSE;
topLevel: Process.Priority ← Process.priorityIdleProcess;
sameProcessInARow: INT ← 0;
frame: PrincOps.FrameHandle;
myPrincOps: PrincOps.PsbHandle = PrincOpsUtils.ReadPSB[];
handleMask: PrincOps.PsbLink = [
failed: FALSE, priority: 0, next: LAST[PrincOps.PsbIndex], reserved: 0, vector: FALSE];
NextHandle:
PROC [link:
CARDINAL]
RETURNS [PrincOps.PsbHandle] =
TRUSTED
INLINE {
RETURN[LOOPHOLE[Basics.BITAND[link, LOOPHOLE[handleMask]]]]};
SearchReadyList:
PROC =
TRUSTED
INLINE {
once: BOOLEAN ← FALSE;
foundTop: BOOLEAN ← FALSE;
headOfReadyList, current: PrincOps.PsbHandle;
FOR p:
CARDINAL
IN [0..nextVerticalRetraceProcesses)
DO
verticalRetraceProcesses[p].seenThisTime ← FALSE;
ENDLOOP;
noBackgroundProcesses ← 0;
PrincOpsUtils.DisableInterrupts[];
topLevel ← Process.priorityIdleProcess;
headOfReadyList ← NextHandle[LOOPHOLE[PrincOps.PDA.ready]];
headOfReadyList ← NextHandle[LOOPHOLE[PrincOps.PDA[headOfReadyList].link]]; -- want the SECOND psb.
FOR current ← headOfReadyList, NextHandle[
LOOPHOLE[PrincOps.
PDA[current].link]]
DO
psb: LONG POINTER TO PrincOps.ProcessStateBlock = @PrincOps.PDA[current];
link: PrincOps.PsbLink = psb.link;
level: Process.Priority = link.priority;
skip: BOOLEAN ← FALSE;
IF current = headOfReadyList THEN IF once THEN EXIT ELSE once ← TRUE;
IF psb = notifyCPUStatsProcess THEN LOOP;
IF level = Process.priorityIdleProcess THEN LOOP;
IF level = Process.priorityBackground THEN noBackgroundProcesses ← noBackgroundProcesses + 1;
IF foundTop THEN LOOP;
IF current = myPrincOps THEN LOOP;
FOR p:
CARDINAL
IN [0..nextVerticalRetraceProcesses)
DO
skipPsb: LONG POINTER TO PrincOps.ProcessStateBlock = @PrincOps.PDA.block[verticalRetraceProcesses[p].psbi];
IF skipPsb = psb
THEN {
skip ← TRUE;
IF level > Process.priorityForeground
THEN {
IF verticalRetraceProcesses[p].seenCounter < 10000 THEN verticalRetraceProcesses[p].seenCounter ← verticalRetraceProcesses[p].seenCounter + 1;
verticalRetraceProcesses[p].seenThisTime ← TRUE;
};
EXIT;
};
ENDLOOP;
IF skip THEN LOOP;
IF ~link.vector AND PrincOps.PDA.state[level] = PrincOps.NullStateVectorHandle THEN LOOP; -- no SV.
frame ← IF link.vector THEN PrincOps.PDA[psb.context.state].frame ELSE psb.context.frame;
skip over a process that appears in the ready queue because it just timed out.
(The Spy wakes up with all of the other timeouts. Since it is the highest priority,
it will run first. All of the other timeouts will appear on the ready list. Most likely,
they will just check some condition and then go back to sleep. This will mask the
more interesting processes.)
FOR i:
CARDINAL
IN [0..index)
DO
IF timeout[i].gfh = NIL AND timeout[i].pc = 0 THEN EXIT;
IF timeout[i].gfh # frame.accesslink OR timeout[i].pc # frame.pc THEN LOOP;
skip ← TRUE; EXIT;
ENDLOOP;
IF skip THEN LOOP;
we have a good process!
topLevel ← level;
topProcess ← current;
foundTop ← TRUE;
ENDLOOP;
PrincOpsUtils.EnableInterrupts[];
FOR p:
CARDINAL
IN [0..nextVerticalRetraceProcesses)
DO
IF verticalRetraceProcesses[p].seenThisTime = FALSE THEN verticalRetraceProcesses[p].seenCounter ← MAX[0, verticalRetraceProcesses[p].seenCounter - 1];
ENDLOOP;
};
MAIN LOOP
FOR p: PrincOps.Priority
IN PrincOps.Priority
DO
levelCounters[p] ← 0;
ENDLOOP;
Get our hands on the verticalRetrace CONDITION in TerminalImpl. This gets a BROADCAST every vertical retrace, if we are in idle or not.
IF verticalRetraceTV =
NIL
THEN
{
[] ← NotifyProcessDead[];
RETURN;
};
active ← TRUE;
aConditionSomewhere ← pointerToVerticalRetraceTV;
usingVerticalRetrace ← TRUE;
WHILE ~done
DO
ticksToRebuildSetTimeouts: INT ← 0;
rebuildCounter: INT ← 0;
DO
waitForBWVerticalRetrace:
ENTRY
PROC =
TRUSTED {
WAIT aConditionSomewhere;
};
Used to be Terminal.WaitForBWVerticalRetrace, but that does not tick when the machine is idle
waitForBWVerticalRetrace[];
IF ~enabled THEN EXIT;
IF ticksToRebuildSetTimeouts
MOD 3 = 0
THEN {
IF searchReadyList THEN SearchReadyList[];
levelCounters[topLevel] ← levelCounters[topLevel] + 1;
backgroundSeen ← backgroundSeen + noBackgroundProcesses;
IF lastTopProcess = topProcess
THEN {
sameProcessInARow ← sameProcessInARow + 1;
IF topLevel > Process.priorityForeground
AND sameProcessInARow > 512
THEN {
psbi: INT;
alreadySkipped: BOOL ← FALSE;
psbi ← (topProcess - PrincOps.NullPsbHandle)/SIZE[PrincOps.ProcessStateBlock];
FOR p:
CARDINAL
IN [0..nextVerticalRetraceProcesses)
DO
IF verticalRetraceProcesses[p].psbi = psbi
THEN {
alreadySkipped ← TRUE;
EXIT;
};
ENDLOOP;
IF ~alreadySkipped
THEN {
Process.Detach[FORK AddToVerticalRetraceProcesses[topProcess]];
};
};
}
ELSE {
sameProcessInARow ← 0;
lastTopProcess ← topProcess;
};
};
ticksToRebuildSetTimeouts ← ticksToRebuildSetTimeouts + 1;
IF ticksToRebuildSetTimeouts
MOD 1024 = 0
THEN {
IF index = maxIndex
OR (ticksToRebuildSetTimeouts ← ticksToRebuildSetTimeouts + 1) > 7000
THEN {
ticksToRebuildSetTimeouts ← 0;
rebuildCounter ← rebuildCounter + 1;
FOR p:
CARDINAL
IN [0..nextVerticalRetraceProcesses)
DO
IF verticalRetraceProcesses[p].seenCounter <= 0
THEN {
reArrange:
ENTRY
PROC =
TRUSTED {
nextVerticalRetraceProcesses ← nextVerticalRetraceProcesses - 1;
IF nextVerticalRetraceProcesses # p
THEN {
verticalRetraceProcesses[p].psbi ← verticalRetraceProcesses[nextVerticalRetraceProcesses].psbi;
verticalRetraceProcesses[p].seenCounter ← verticalRetraceProcesses[nextVerticalRetraceProcesses].seenCounter;
};
verticalRetraceProcesses[nextVerticalRetraceProcesses].psbi ← 0;
verticalRetraceProcesses[nextVerticalRetraceProcesses].seenCounter ← 0;
};
reArrange[];
};
ENDLOOP;
IF rebuildCounter > 10
THEN {
SetTimeouts[TRUE];
rebuildCounter ← 0;
}
ELSE SetTimeouts[noGFIChanged];
noGFIChanged ← FALSE;
};
};
ENDLOOP;
done ← NotifyProcessDead[];
ENDLOOP;
Process.SetPriority[Process.priorityNormal];
};
NotifyCPUStats:
PROC = {
cnt: INT ← 0 ;
TRUSTED {notifyCPUStatsProcess ← @PrincOps.PDA.block[(PrincOpsUtils.ReadPSB[] - PrincOps.NullPsbHandle)/SIZE[PrincOps.ProcessStateBlock]]; };
CedarProcess.SetPriority[realTime];
DO
doNotify:
ENTRY
PROC = {
NOTIFY myConditionForCPUStats;
};
IF usingVerticalRetrace THEN cnt ← cnt + 1 ELSE cnt ← 0;
IF cnt > 5 THEN EXIT;
doNotify[];
Process.Pause[4];
ENDLOOP;
notifyCPUStatsProcess ← NIL;
};
AddToVerticalRetraceProcesses:
PROC [ topProcess: PrincOps.PsbHandle] =
TRUSTED {
getLock:
ENTRY
PROC =
TRUSTED {
verticalRetraceProcessCount ← verticalRetraceProcessCount + 1;
WHILE vrpLockSet DO WAIT vrpLockAvailable ENDLOOP;
vrpLockSet ← TRUE;
};
freeLock:
ENTRY
PROC =
TRUSTED {
verticalRetraceProcessCount ← verticalRetraceProcessCount - 1;
vrpLockSet ← FALSE;
NOTIFY vrpLockAvailable;
};
localWorld: WorldVM.World;
rootContext: AMModel.Context;
psbi: INT;
stack: AMTypes.TV;
process: AMProcess.Process;
IF verticalRetraceProcessCount > maxVerticalRetraceProcessCount THEN RETURN;
CedarProcess.SetPriority[normal];
getLock[];
IF nextVerticalRetraceProcesses >= maxVerticalRetraceProcessIndex
THEN {
freeLock[];
RETURN;
};
localWorld ← WorldVM.LocalWorld[];
rootContext ← AMModel.RootContext[localWorld];
psbi ← (topProcess - PrincOps.NullPsbHandle)/SIZE[PrincOps.ProcessStateBlock];
FOR p:
CARDINAL
IN [0..nextVerticalRetraceProcesses)
DO
IF verticalRetraceProcesses[p].psbi = psbi
THEN {
freeLock[];
RETURN;
};
ENDLOOP;
process ← AMProcess.PSBIToTV[localWorld, psbi];
AMProcess.Freeze[LIST[process], LIST[rootContext]];
AMProcess.Adjust[LIST[process], LIST[rootContext]];
[stack: stack] ← AMProcess.GetState[process];
{
IF stack #
NIL
THEN {
str: IO.STREAM = IO.ROS[];
gf: AMTypes.TV;
gf ← AMTypes.GlobalParent[stack];
PrintTV.Print[stack, str];
AMProcess.Thaw[LIST[process]];
IF AMTypes.TVEq[gf, TerminalImplGF ! AMTypes.Error => GOTO bailout] THEN {
IF Rope.Run["TerminalImpl.InternalWaitForBWVerticalRetrace", 0, IO.RopeFromROS[str], 0, FALSE] > 40 THEN {
insert:
ENTRY
PROC =
TRUSTED {
recheck under monitor to ensure unique entries and no overflow
IF nextVerticalRetraceProcesses >= maxVerticalRetraceProcessIndex
THEN {
freeLock[];
RETURN;
};
FOR p:
CARDINAL
IN [0..nextVerticalRetraceProcesses)
DO
IF verticalRetraceProcesses[p].psbi = psbi
THEN {
freeLock[];
RETURN;
};
ENDLOOP;
verticalRetraceProcesses[nextVerticalRetraceProcesses].psbi ← psbi;
verticalRetraceProcesses[nextVerticalRetraceProcesses].seenCounter ← 10000;
nextVerticalRetraceProcesses ← nextVerticalRetraceProcesses + 1;
};
insert[];
};
} ELSE AMProcess.Thaw[LIST[process]];
freeLock[];
EXITS
bailout => freeLock[];
};
};
NotifyProcessDead:
ENTRY
PROC
RETURNS[exit:
BOOL ←
TRUE] =
INLINE {
IF enabled THEN RETURN [FALSE]
ELSE {
NOTIFY whatsActiveProcessDead;
active ← FALSE;
whatsActiveProcess ← NIL;
};
};
ServerOff: Commander.CommandProc = {
ShutDownServer[];
SummonerControllerControl.ShutDownController[];
};
ShutDownServer:
PUBLIC
PROC []
RETURNS [] = {
ComputeServerInternal.ControllerInterface ← NIL ;
ServiceEnabled ← FALSE;
ComputeServerInternal.ReportServerEvent[type: serverDisabled, command: NIL, startTime: BasicTime.nullGMT, endTime: BasicTime.nullGMT, remoteMachineName: NIL, userName: NIL];
ComputeServerInternal.PackageTable ← SymTab.Create[mod: 59, case: FALSE];
ComputeServerInternal.ConfigTable ← SymTab.Create[mod: 59, case: FALSE];
StopCounting[];
};
DoStartup:
PROC = {
msg: ROPE;
SummonerControllerControl.StartUpController[ComputeServerInternal.ControllerGVName];
msg ← StartUpServer[ComputeServerInternal.ControllerGVName, ComputeServerInternal.RemoteCommandDir, ComputeServerInternal.LocalCommandDir];
IF ~Rope.IsEmpty[msg]
THEN {
SummonerControllerControl.ShutDownController[];
MessageWindow.Append[message: Rope.Concat["Can't Start Summoner Server because ", msg], clearFirst: TRUE];
};
};
IdleTransition: Idle.IdleHandler = {
PROC [data: REF, reason: IdleReason]
SELECT reason
FROM
becomingBusy => {
isIdle ← FALSE;
};
becomingIdle => {
isIdle ← TRUE;
};
ENDCASE;
IF IdleTransitionsEnabled
THEN {
SELECT reason
FROM
becomingBusy => {
ShutDownServer[];
SummonerControllerControl.ShutDownController[];
};
becomingIdle => {
TRUSTED {Process.Detach[FORK DoStartup[]];};
};
ENDCASE;
};
};
EnableAutoIdle: Commander.CommandProc = {
IdleTransitionsEnabled ← TRUE;
};
DisableAutoIdle: Commander.CommandProc = {
IdleTransitionsEnabled ← FALSE;
};
Issue Statistics
SendStats:
PUBLIC
PROC []
RETURNS [success, terminateService, newPackage:
BOOL ←
FALSE, queueingCommands:
LIST
OF Rope.
ROPE] = {
May Raise RPC.CallFailed
controllerInterface: ComputeServerControllerRpcControl.InterfaceRecord;
numberCPUs: CARDINAL ← 1;
diskPartionSize: INT;
freePagesOnDisk: INT;
freeboard: INT;
oldestLRUFileDate: BasicTime.GMT;
freeProcesses: CARDINAL ← 0;
totalSamples: INT ← 0;
idleBackGroundSamples: INT ← 0;
nonBackgroundCPULoad: REAL;
aveBackgroundLoad: REAL;
NowRMReclamations: INT;
ReclamationRate: REAL;
NowTime: BasicTime.GMT = BasicTime.Now[];
TimePeriod: REAL;
firstCall: BOOL;
[diskPartionSize, freePagesOnDisk, freeboard] ← FSBackdoor.VolumePages[];
Get values for freeGFI, freeMDS, freeVM, and CPULoad
watchStatsRecord ← WatchStats.GetWatchStats[];
IF watchStatsRecord.gfiFree # lastNoGFI THEN {
noGFIChanged ← TRUE;
lastNoGFI ← watchStatsRecord.gfiFree;
};
NowRMReclamations ← VMStatistics.rmReclamations;
TimePeriod ← BasicTime.Period[LastTime, NowTime];
TimePeriod ← MAX[1.0, TimePeriod];
IF LastRMReclamations = 0 THEN ReclamationRate ← -1.0
ELSE ReclamationRate ← (NowRMReclamations - LastRMReclamations) / TimePeriod ;
LastRMReclamations ← NowRMReclamations;
oldestLRUFileDate ← FSFileOps.OldestLruDate[];
IF FSFileSpaceImpl.lru.first = NIL THEN oldestLRUFileDate ← BasicTime.nullGMT
ELSE oldestLRUFileDate ← FSFileSpaceImpl.lru.first.used;
freeProcesses ← ProcessBackdoor.CountFreeProcesses[];
FOR p: PrincOps.Priority
IN PrincOps.Priority
DO
delta: INT = levelCounters[p];
levelCounters[p] ← 0;
totalSamples ← totalSamples + delta;
IF p <= Process.priorityBackground THEN idleBackGroundSamples ← idleBackGroundSamples + delta;
ENDLOOP;
SELECT
TRUE
FROM
~isIdle
AND ~usingVerticalRetrace => {
Get our hands on the bwRetrace CONDITION in TerminalImpl. This gets a BROADCAST every vertical retrace, if we are not idle.
IF verticalRetraceTV #
NIL
THEN
TRUSTED {
aConditionSomewhere ← pointerToVerticalRetraceTV;
usingVerticalRetrace ← TRUE;
};
};
totalSamples = 0
AND usingVerticalRetrace
AND isIdle =>
TRUSTED {
This gets a BROADCAST every vertical retrace, if we are in idle or not.
doBroadcast:
ENTRY
PROC =
TRUSTED INLINE {
IF oldCondition # NIL THEN BROADCAST oldCondition^;
};
oldCondition: LONG POINTER TO CONDITION;
oldCondition ← aConditionSomewhere;
aConditionSomewhere ← @myConditionForCPUStats;
usingVerticalRetrace ← FALSE;
doBroadcast[];
Process.Detach[FORK NotifyCPUStats[]];
};
ENDCASE;
IF totalSamples = 0
THEN {
nonBackgroundCPULoad ← watchStatsRecord.cpuLoad;
aveBackgroundLoad ← -1.0;
}
ELSE {
nonBackgroundCPULoad ← MIN[1.0 - ((1.0*idleBackGroundSamples)/totalSamples), watchStatsRecord.cpuLoad];
aveBackgroundLoad ← (1.0 * backgroundSeen) / totalSamples;
};
backgroundSeen ← 0;
firstCall ← ~wasUp AND ServiceEnabled;
controllerInterface ← ComputeServerInternal.ControllerInterface;
IF controllerInterface # NIL THEN [terminateService, newPackage, queueingCommands] ← controllerInterface.NewStats[serverMachineName: serverMachineName, serverMachinePupAddress: serverMachinePupAddress, serverUP: ServiceEnabled, firstCall: firstCall, machineType: SystemVersion.machineType, mainMemory: VMSideDoor.rmPages, numberCPUs: numberCPUs, diskPartionSize: diskPartionSize, freePagesOnDisk: freePagesOnDisk, freeboard: freeboard, freeGFI: watchStatsRecord.gfiFree, freeMDS: watchStatsRecord.mdsFree, freeVM: watchStatsRecord.vmFree, oldestLRUFileDate: oldestLRUFileDate, CPULoad: watchStatsRecord.cpuLoad, nonBackgroundCPULoad: nonBackgroundCPULoad, reclamationRate: ReclamationRate, freeProcesses: freeProcesses, userName: UserCredentials.Get[].name, currentRequests: ComputeServerInternal.CurrentRequests, aveBackgroundLoad: aveBackgroundLoad ];
success ← TRUE;
wasUp ← ServiceEnabled;
};
Initialization
SetTimeouts:
PROC [computeVerticalRetrace:
BOOL] =
TRUSTED {
ticks: Process.Ticks;
cutoff: Process.Ticks;
found: BOOLEAN;
frame: PrincOps.FrameHandle;
IF index = maxIndex
THEN {
index ← 0;
FOR i:
CARDINAL
IN [0..maxIndex)
DO
timeout[i].process ← 0;
timeout[i].gfh ← PrincOps.NullGlobalFrame;
timeout[i].pc ← 0;
ENDLOOP;
};
cutoff ← Process.SecondsToTicks[10];
ticks ← PrincOpsUtils.ReadPTC[];
FOR psbi: PrincOps.PsbIndex
IN [PrincOps.StartPsb..PrincOps.StartPsb+PrincOps.
PDA.count)
DO
block: PrincOps.ProcessStateBlock = PrincOps.PDA.block[psbi];
IF PrincOps.PDA.block[psbi].mds = 0 THEN LOOP;
IF PrincOps.PDA.block[psbi].mds - ticks > cutoff THEN LOOP; -- not significant
IF PrincOps.
PDA.block[psbi].link.vector
THEN frame ← PrincOps.PDA[PrincOps.PDA.block[psbi].context.state].frame
ELSE frame ← PrincOps.PDA.block[psbi].context.frame;
found ← FALSE;
FOR i:
CARDINAL
IN [0..index)
DO
IF timeout[i].gfh = frame.accesslink AND timeout[i].pc = frame.pc THEN {found ← TRUE; EXIT};
ENDLOOP;
IF found THEN LOOP;
timeout[index] ← [psbi, frame.accesslink, frame.pc];
index ← index + 1;
IF index = maxIndex THEN EXIT;
ENDLOOP;
IF computeVerticalRetrace THEN {
newContext: AMModel.Context;
newProcesses: LIST OF AMProcess.Process;
newContext ← AMModel.MostRecentNamedContext["TerminalImpl", AMModel.RootContext[WorldVM.LocalWorld[]]];
newProcesses ← AMProcess.GetProcesses[LIST[newContext]];
nextVerticalRetraceProcesses ← 0;
DO
stack: AMTypes.TV;
IF newProcesses = NIL THEN EXIT;
[stack: stack] ← AMProcess.GetState[newProcesses.first];
IF stack # NIL THEN {
str: IO.STREAM = IO.ROS[];
PrintTV.Print[stack, str];
IF Rope.Run["TerminalImpl.InternalWaitForBWVerticalRetrace", 0, IO.RopeFromROS[str], 0, FALSE] > 40 THEN {
verticalRetraceProcesses[nextVerticalRetraceProcesses].psbi ← AMProcess.TVToPSBI[newProcesses.first].psbi;
verticalRetraceProcesses[nextVerticalRetraceProcesses].seenCounter ← 0;
nextVerticalRetraceProcesses ← nextVerticalRetraceProcesses + 1;
};
};
AMProcess.Thaw[LIST[newProcesses.first]];
newProcesses ← newProcesses.rest;
ENDLOOP;
};
};
InitializeBackgroundCounting:
PROC = {
newContext: AMModel.Context;
Loader.MakeProcedureResident[WhatsActive];
Loader.MakeGlobalFrameResident[InitializeBackgroundCounting];
TRUSTED {Process.InitializeCondition[@whatsActiveProcessDead, 10000]; };
timeout ← NEW[timeOutType];
SafeStorage.PinObject[timeout];
SetTimeouts[TRUE];
TRUSTED {newContext ← AMModel.MostRecentNamedContext["TerminalImpl", AMModel.RootContext[WorldVM.LocalWorld[]]];};
TerminalImplGF ← newContext;
verticalRetraceTV ← Interpreter.Evaluate["TerminalImpl.verticalRetrace"].result;
IF verticalRetraceTV =
NIL
THEN
TRUSTED {
usingVerticalRetrace ← FALSE;
aConditionSomewhere ← @myConditionForCPUStats;
Process.Detach[FORK NotifyCPUStats[]];
}
ELSE
TRUSTED {
usingVerticalRetrace ← TRUE;
pointerToVerticalRetraceTV ← AMBridge.PointerFromTV[verticalRetraceTV];
aConditionSomewhere ← pointerToVerticalRetraceTV;
};
};
Commander.Register[key: "///Commands/SummonerServerOn", proc: ServerOn, doc: "SummonerServerOn {controllerName {remoteCommandDirectory {localCommandDirectory}}} Turn on use of the Compute Server Service for cluster controllerName using remoteCommandDirectory on a file server and localCommandDirectory on the workstation"];
Commander.Register[key: "///Commands/SummonerServerOff", proc: ServerOff, doc: "Turn off use of the Compute Server Service"];
Commander.Register[key: "///Commands/SummonerEnableAutoIdle", proc: EnableAutoIdle, doc: "Turn on automatic Summoner server toggle at Idle"];
Commander.Register[key: "///Commands/SummonerDisableAutoIdle", proc: DisableAutoIdle, doc: "Turn off automatic Summoner server toggle at Idle"];
Commander.Register[key: "///Commands/SummonerServerTypescript", proc: StartServerEventTypescript, doc: "Start typescript of server events"];
Commander.Register[key: "///Commands/SummonerServerStatistics", proc: ServerStatistics, doc: "Print statistics"];
[] ← Idle.RegisterIdleHandler[IdleTransition];
InitializeBackgroundCounting[];