-- File: FrameFinderAlto.mesa, Last Edit: HGM January 24, 1981 12:31 PM DIRECTORY ControlDefs USING [ControlLink, FrameHandle, GlobalFrameHandle, NullLink], PrincOps USING [ AllocationVector, AllocationVectorSize, AV, AVItem, FrameVec, LastAVSlot], ProcessOps USING [FirstProcess, LastProcess], PSBDefs USING [PSB], Resident USING [SegListHead], DebugUsefulDefs USING [Enumerate, Name, ShortREAD, ShortCopyREAD], Event USING [AddNotifier, Item, Masks, Notifier], Format USING [], -- Needed by Put.Number Menu USING [ItemObject, MCRType, Create, Instantiate], UserInput USING [GetDefaultWindow], Put USING [Char, CR, Decimal, Line, Number, Octal, Text], String USING [EquivalentStrings], Window USING [Handle]; FrameFinderAlto: PROGRAM IMPORTS DebugUsefulDefs, Event, Menu, UserInput, Put, String = BEGIN wh: Window.Handle ← NIL; AvIndex: TYPE = [0..PrincOps.AllocationVectorSize); All: PROCEDURE = BEGIN Free[]; InUse[]; Extra[]; END; Free: PROCEDURE = BEGIN myAV: PrincOps.AllocationVector; total: CARDINAL ← 0; Put.CR[wh]; Put.Line[wh, "AV table statistics:"L]; Put.Line[wh, "fsi size cnt words"L]; DebugUsefulDefs.ShortCopyREAD[ to: @myAV, from: PrincOps.AV, nwords: SIZE[PrincOps.AllocationVector]]; FOR fsi: AvIndex IN AvIndex DO n: CARDINAL ← 0; item: PrincOps.AVItem ← myAV[fsi]; Put.Number[wh, fsi, [8, FALSE, TRUE, 3]]; IF fsi <= PrincOps.LastAVSlot THEN Put.Number[wh, PrincOps.FrameVec[fsi], [10, FALSE, TRUE, 6]] ELSE Put.Text[wh, " "L]; DO SELECT item.tag FROM frame => n ← n + 1; empty => EXIT; indirect => EXIT; enable => EXIT; ENDCASE => ERROR; IF item.tag # frame THEN EXIT; IF n > 10000 THEN ERROR; item ← DebugUsefulDefs.ShortREAD[item.frame]; ENDLOOP; Put.Number[wh, n, [10, FALSE, TRUE, 6]]; IF n # 0 AND fsi <= PrincOps.LastAVSlot THEN BEGIN words: CARDINAL ← n*(PrincOps.FrameVec[fsi] + 1); total ← total + words; Put.Number[wh, words, [10, FALSE, TRUE, 6]]; END ELSE Put.Text[wh, " "L]; SELECT item.tag FROM frame => ERROR; empty => NULL; indirect => BEGIN Put.Text[wh, " indirect to "L]; Put.Number[wh, item.fsi, [8, FALSE, TRUE, 0]]; END; enable => Put.Text[wh, "enable"L]; ENDCASE => ERROR; Put.CR[wh]; ENDLOOP; Put.Text[wh, "There are a total of "L]; Put.Decimal[wh, total]; Put.Line[wh, " words in use by (small) free frames."L]; END; InUse: PROCEDURE = BEGIN this, last: POINTER TO PSBDefs.PSB; that: PSBDefs.PSB; hits: ARRAY AvIndex OF CARDINAL ← ALL[0]; total: CARDINAL ← 0; this ← DebugUsefulDefs.ShortREAD[ProcessOps.FirstProcess]; last ← DebugUsefulDefs.ShortREAD[ProcessOps.LastProcess]; Put.CR[wh]; Put.Line[wh, "Scanning active processes..."L]; DO DebugUsefulDefs.ShortCopyREAD[ to: @that, from: this, nwords: SIZE[PSBDefs.PSB]]; IF that.state = alive THEN BEGIN frame: ControlDefs.FrameHandle ← that.frame; count: CARDINAL ← 0; Put.Octal[wh, this]; Put.Text[wh, ": "L]; DO index: AvIndex; link: ControlDefs.ControlLink; IF count # 0 THEN Put.Text[wh, ", "L]; Put.Octal[wh, frame]; link.frame ← frame; IF link.tag # frame OR link = ControlDefs.NullLink THEN EXIT; count ← count + 1; index ← DebugUsefulDefs.ShortREAD[frame - 1]; Put.Char[wh, '(]; Put.Number[wh, index, [8, FALSE, TRUE, 0]]; Put.Char[wh, ')]; IF index >= PrincOps.AllocationVectorSize THEN ERROR; hits[index] ← hits[index] + 1; link ← DebugUsefulDefs.ShortREAD[@frame.returnlink]; frame ← link.frame; ENDLOOP; Put.CR[wh]; END; IF this = last THEN EXIT; this ← this + SIZE[PSBDefs.PSB]; ENDLOOP; Put.CR[wh]; Put.Line[wh, "Active frame statistics:"L]; Put.Line[wh, "fsi size cnt words"L]; FOR fsi: AvIndex IN AvIndex DO slot: CARDINAL ← hits[fsi]; Put.Number[wh, fsi, [8, FALSE, TRUE, 3]]; IF fsi <= PrincOps.LastAVSlot THEN Put.Number[wh, PrincOps.FrameVec[fsi], [10, FALSE, TRUE, 6]] ELSE Put.Text[wh, " "L]; Put.Number[wh, slot, [10, FALSE, TRUE, 6]]; IF slot # 0 AND fsi <= PrincOps.LastAVSlot THEN BEGIN words: CARDINAL ← slot*(PrincOps.FrameVec[fsi] + 1); total ← total + words; Put.Number[wh, words, [10, FALSE, TRUE, 6]]; END ELSE Put.Text[wh, " "L]; Put.CR[wh]; ENDLOOP; Put.Text[wh, "There are a total of "L]; Put.Decimal[wh, total]; Put.Line[wh, " words in use by frames in active processes."L]; END; Extra: PROCEDURE = BEGIN -- Can't get the Compiler to find Resident.SegHeader; SegHeader: TYPE = RECORD [seg: POINTER, link: POINTER TO SegHeader]; count: CARDINAL ← 0; overflow: POINTER TO SegHeader; IF resident = NIL THEN BEGIN Put.Line[wh, "Looking for Resident."L]; LookForFrames[]; IF resident = NIL THEN BEGIN Put.Line[NIL, "**** Can't find Resident!"L]; RETURN; END; END; overflow ← DebugUsefulDefs.ShortREAD[@resident.SegListHead]; UNTIL overflow = NIL DO IF count # 0 THEN Put.Text[wh, ", "]; Put.Number[wh, overflow, [8, FALSE, TRUE, 6]]; count ← count + 1; IF count > 1000 THEN ERROR; overflow ← DebugUsefulDefs.ShortREAD[@overflow.link]; ENDLOOP; IF count # 0 THEN Put.CR[wh]; Put.Text[wh, "There are "L]; Put.Decimal[wh, count]; Put.Line[wh, " pages used by overflow frames."L]; END; items: ARRAY [0..3] OF Menu.ItemObject ← [["All", DoInfo], ["Free", DoInfo], ["InUse", DoInfo], ["Extra", DoInfo]]; all: CARDINAL = 0; free: CARDINAL = 1; inUse: CARDINAL = 2; extra: CARDINAL = 3; DoInfo: Menu.MCRType = BEGIN SELECT index FROM all => All[]; free => Free[]; inUse => InUse[]; extra => Extra[]; ENDCASE => ERROR; END; nMods: CARDINAL = 1; resident: POINTER TO FRAME[Resident] ← NIL; LookForFrames: PROCEDURE = BEGIN moduleName: ARRAY [0..nMods) OF STRING ← ["Resident"L]; basePtr: ARRAY [0..nMods) OF POINTER ← [@resident]; keyString: STRING = [40]; nFound: CARDINAL ← 0; CheckOneFrame: PROCEDURE [han: ControlDefs.GlobalFrameHandle] RETURNS [BOOLEAN] = BEGIN name: POINTER TO ARRAY [0..nMods) OF STRING = @moduleName; base: POINTER TO ARRAY [0..nMods) OF POINTER = @basePtr; key: STRING = keyString; key.length ← 0; DebugUsefulDefs.Name[name: key, gf: han]; FOR i: CARDINAL IN [0..nMods) DO IF String.EquivalentStrings[key, name[i]] THEN BEGIN IF base[i]↑ = NIL THEN BEGIN base[i]↑ ← han; nFound ← nFound + 1 END ELSE BEGIN Put.Text[NIL, "Duplicate: "L]; Put.Line[NIL, key]; END; EXIT END; ENDLOOP; RETURN[nFound = nMods]; END; FOR i: CARDINAL IN [0..nMods) DO basePtr[i]↑ ← NIL; ENDLOOP; [] ← DebugUsefulDefs.Enumerate[CheckOneFrame]; IF nFound # nMods THEN BEGIN FOR i: CARDINAL IN [0..nMods) DO IF basePtr[i]↑ = NIL THEN BEGIN Put.Text[NIL, "Missing: "L]; Put.Line[NIL, moduleName[i]]; END; ENDLOOP; END; END; notifierItem: Event.Item ← [eventMask: Event.Masks[newSession], eventProc: Notify]; Notify: Event.Notifier = BEGIN SELECT why FROM newSession => resident ← NIL; ENDCASE; END; -- initialization Event.AddNotifier[@notifierItem]; Menu.Instantiate[ Menu.Create[DESCRIPTOR[items], "Frames"], UserInput.GetDefaultWindow[]]; END.