-- Copyright (C) 1980, 1981, 1983, 1984, 1985 by Xerox Corporation. All rights reserved. -- File: MDSWatcher.mesa -- HGM, 14-Sep-85 22:16:20 -- Ted Wobber 8-Aug-83 11:11:17 -- Randy Gobbel 7-Aug-81 16:11:44 -- Roy Levin 10-Sep-80 18:46:53 -- Andrew Birrell 16-Oct-80 18:30:01 -- Hankins 23-Aug-84 10:38:03 DIRECTORY Ascii USING [NUL], BufferOps USING [GetStatistics, Statistics], EnquiryDefs USING [DisplayStats, Histograms, RemoteServers, PolicyControls], GlassDefs USING [Handle, HandleObject, StringType], LogDefs USING [DisplayNumber], LogPrivateDefs USING [tty], Process USING [ Detach, InvalidProcess, Pause, Priority, SecondsToTicks, SetPriority, Ticks, ValidateProcess], ProcessPriorities USING [priorityFrameFault], ProcessOperations USING [ DisableInterrupts, EnableInterrupts, Notify, ReEnter, Wait], PSB USING [ Condition, FaultIndex, PDABase, PDA, PsbIndex, PsbNull, qPageFault, StartPsb], SpecialSpace USING [MakeProcedureResident], RestartDefs, TTY USING [GetChar, PutChar, PutDecimal, PutLongDecimal, PutString]; MDSWatcher: PROGRAM IMPORTS BufferOps, EnquiryDefs, LogDefs, LogPrivateDefs, Process, ProcessOperations, SpecialSpace, TTY EXPORTS RestartDefs = BEGIN screen: GlassDefs.Handle = @screenObject; screenObject: GlassDefs.HandleObject ← [ ReadChar: ReadCharNull, ReadString: ReadStringNull, WriteChar: MyWriteChar, WriteString: MyWriteString, WriteDecimal: MyWriteDecimal, WriteLongDecimal: MyWriteLongDecimal, SendNow: NullProc, CharsLeft: CardNullProc, LinesLeft: CardNullProc, SetWidth: SetWidthNull, SetHeight: SetHeightNull, DelTyped: BoolNullProc, Synch: NullProc, Flush: NullProc]; availablePages, availablePSBs, availablePups: CARDINAL ← 0; savedStorageFaults, storageFaults: CARDINAL ← 0; oneMinute: Process.Ticks = Process.SecondsToTicks[60]; tenSeconds: Process.Ticks = Process.SecondsToTicks[10]; StartKeyWatcher: PUBLIC PROCEDURE = BEGIN Process.Detach[FORK KeyboardWatcher[]]; END; Init: PROCEDURE = BEGIN -- LogDefs.DisplayNumber["Free MDS"L, [short[@availablePages]]]; LogDefs.DisplayNumber["Free PSBs"L, [short[@availablePSBs]]]; LogDefs.DisplayNumber["Free Pup Buffers"L, [short[@availablePups]]]; LogDefs.DisplayNumber["Page faults/min"L, [short[@savedStorageFaults]]]; END; WatchMDS: PROCEDURE = BEGIN << this is looking at MDS and seeing how much has been carved up for new, smaller, spaces. this is no longer possible to do in any clean way (could import global from of some Pilot impl and look at a variable therein (SpecialSpaceImpl?) so we'll just not calculate it any longer. firstPage: Space.PageNumber = Space.PageFromLongPointer[Space.MDS[].pointer]; lastPage: Space.PageNumber = firstPage + Environment.maxPagesInMDS; should also be equivalent to firstPage+Space.MDS[].count? >> DO available: CARDINAL ← 0; << FOR page: Space.PageNumber ← firstPage, SUCC[page] UNTIL page > lastPage DO IF Space.GetHandle[page] = Space.mds THEN available ← available + 1; ENDLOOP; availablePages ← available; available ← 0; >> FOR i: CARDINAL IN [PSB.StartPsb..PSB.StartPsb + PSB.PDA.count) DO Process.ValidateProcess[ LOOPHOLE[i, PROCESS] ! Process.InvalidProcess => {available ← available + 1; CONTINUE}]; ENDLOOP; availablePSBs ← available; savedStorageFaults ← storageFaults; storageFaults ← 0; Process.Pause[oneMinute]; ENDLOOP; END; WatchPupBuffers: PROCEDURE = BEGIN stats: ARRAY BufferOps.Statistics OF CARDINAL; DO stats ← BufferOps.GetStatistics[]; availablePups ← stats[available]; Process.Pause[tenSeconds]; ENDLOOP END; KeyboardWatcher: PROCEDURE = BEGIN DO c: CHAR ← TTY.GetChar[LogPrivateDefs.tty]; SELECT c FROM 'h, 'H => EnquiryDefs.Histograms[screen]; 'o, 'O => EnquiryDefs.RemoteServers[screen]; 'p, 'P => EnquiryDefs.PolicyControls[screen]; ENDCASE => EnquiryDefs.DisplayStats[screen]; ENDLOOP; END; -- Stuff stolen from BLyon's UsageMonitor tool priorityStorageFaultRecorders: Process.Priority ← ProcessPriorities.priorityFrameFault - 1; -- should be higher than Pilot's page and write fault handlers' priorities. pda: PSB.PDABase = PSB.PDA; qPageFault: PSB.FaultIndex = PSB.qPageFault; pPageFaultCondition: LONG POINTER TO PSB.Condition = @pda.fault[ qPageFault].condition; pPageFaultCONDITION: LONG POINTER TO CONDITION = LOOPHOLE[pPageFaultCondition]; PageFaultRecorder: --EXTERNAL-- PROCEDURE [] = BEGIN pageFaultLock: MONITORLOCK; shouldNotifyPilot: BOOLEAN ← FALSE; Process.SetPriority[priorityStorageFaultRecorders]; -- NO PAGE FAULTS or calls to swappable code from this point on! (else the state vector goblin will get ya) --FOREVER-- DO -- wait for a page fault.. ProcessOperations.Wait[@pageFaultLock, pPageFaultCONDITION, --timeout:-- 1]; UNTIL ProcessOperations.ReEnter[@pageFaultLock, pPageFaultCONDITION] DO NULL ENDLOOP; -- either a new page fault came along or we timed out.. IF pda.fault[qPageFault].queue.tail = PSB.PsbNull THEN -- no page fault, just timed out.. BEGIN IF shouldNotifyPilot AND pda.fault[qPageFault].condition.tail ~= PSB.PsbNull THEN { NakedNotify[pPageFaultCONDITION]; shouldNotifyPilot ← FALSE}; LOOP; -- go back and wait again. END; -- wake up the Pilot fault handler: ProcessOperations.DisableInterrupts[]; IF pPageFaultCondition↑.tail = PSB.PsbNull THEN shouldNotifyPilot ← TRUE -- Pilot not ready for this fault yet.. ELSE NakedNotify[pPageFaultCONDITION]; ProcessOperations.EnableInterrupts[]; -- log the fault: storageFaults ← SUCC[storageFaults]; ENDLOOP; -- Note: following code never executed in current implementation. -- Must get back to ordinary priority before exiting since Process.End is swappable.. -- Process.SetPriority[Process.priorityForeground]; END; -- PageFaultRecorder (process disappears) NakedNotify: PROCEDURE [pCondition: LONG POINTER TO CONDITION] = INLINE { -- Used ONLY to notify a condition from a high priority process outside the relevant monitor. pCond: LONG POINTER TO PSB.Condition = LOOPHOLE[pCondition]; ProcessOperations.DisableInterrupts[]; IF pCond↑.tail = PSB.PsbNull THEN { pCond↑.wakeup ← TRUE; ProcessOperations.EnableInterrupts[]} ELSE { ProcessOperations.EnableInterrupts[]; ProcessOperations.Notify[pCondition]}}; -- GlassDefs.HandleOject implementors NullProc: PROCEDURE = {}; BoolNullProc: PROCEDURE RETURNS [BOOLEAN] = {RETURN[FALSE]}; CardNullProc: PROCEDURE RETURNS [CARDINAL] = {RETURN[0]}; ReadCharNull: PROCEDURE RETURNS [CHARACTER] = {RETURN[Ascii.NUL]}; ReadStringNull: PROC [prompt, s: LONG STRING, type: GlassDefs.StringType] RETURNS [CHARACTER] = {RETURN[Ascii.NUL]}; SetWidthNull, SetHeightNull: PROCEDURE [CARDINAL] = {}; MyWriteChar: PROCEDURE [c: CHARACTER] = {TTY.PutChar[LogPrivateDefs.tty, c]}; MyWriteString: PROC [s: LONG STRING] = {TTY.PutString[LogPrivateDefs.tty, s]}; MyWriteDecimal: PROCEDURE [n: CARDINAL] = { TTY.PutDecimal[LogPrivateDefs.tty, n]}; MyWriteLongDecimal: PROCEDURE [n: LONG CARDINAL] = { TTY.PutLongDecimal[LogPrivateDefs.tty, n]}; Init[]; SpecialSpace.MakeProcedureResident[PageFaultRecorder]; Process.Detach[FORK WatchMDS[]]; Process.Detach[FORK WatchPupBuffers[]]; END.