<> <> <> <> <> <> DIRECTORY Buttons USING [Button, ButtonProc, Create, SetDisplayStyle], CIFSFeedback USING [Register], Containers USING [ChildXBound, Create], Convert USING [ValueToRope], DiskDriverSharedImpl USING [totalNumberOfRequests], File USING [Capability, nullCapability, ShowCapability], Imager USING [black, MaskIntRectangle, SetColor, white], Labels USING [Create, Label, Set, SetDisplayStyle], NumberLabels USING [CreateNumber, NumberLabel, NumberLabelUpdate], PrincOpsRuntime USING [GFT, GFTItem], Process USING [Detach, Pause, SecondsToTicks, SetPriority, SetTimeout], Real USING [RoundI], Rope USING [Cat, Concat, Find, Length, Replace, ROPE], RTProcess USING [GetTotalPageFaults, StartWatchingFaults, StopWatchingFaults], RTQuanta USING [PagesPerQuantum], RTRefCounts USING [AMapOiOe, AMapPiRce, GetMapOiOe, GetMapPiRce, mapOiOeLimit, mapOiOeStart, OverflowEntry, ProbeSize, rceEmpty, RCEntry, rcFinalize, RefCt], RTZones USING [MapQZf, mzVacant, TMapQZf, ZoneFinger], Runtime USING [IsBound], SafeStorage USING [NWordsAllocated, ReclaimCollectibleObjects, ReclamationReason, TrimAllZones, TrimRootBase, SetCollectionInterval, WaitForCollectorDone, WaitForCollectorStart], SDDefs USING [SD, sGFTLength], ShowTime USING [GetMark, Microseconds], Space USING [GetAttributes, GetHandle, GetWindow, Handle, mds, nullHandle, PageFromLongPointer, PageNumber, virtualMemory], System USING [GetGreenwichMeanTime, gmtEpoch, GreenwichMeanTime], UserProfile USING [Number], ViewerClasses USING [DestroyProc, PaintProc, Viewer, ViewerClass, ViewerClassRec], ViewerOps USING [ComputeColumn, CreateViewer, PaintViewer, RegisterViewerClass, SetOpenHeight, ViewerColumn], ViewerSpecs USING [openRightWidth], Volume USING [GetAttributes, SystemID]; Watch: CEDAR MONITOR IMPORTS Buttons, CIFSFeedback, Containers, Convert, DiskDriverSharedImpl, File, Imager, Labels, NumberLabels, Process, Real, Rope, RTProcess, RTRefCounts, RTZones, Runtime, SafeStorage, ShowTime, Space, System, UserProfile, ViewerOps, ViewerSpecs, Volume SHARES DiskDriverSharedImpl = BEGIN <<**** Useful types from other interfaces ****>> Button: TYPE = Buttons.Button; Label: TYPE = Labels.Label; NumberLabel: TYPE = NumberLabels.NumberLabel; ROPE: TYPE = Rope.ROPE; <<**** Useful local types and constants ****>> NormalSize: CARDINAL = RTRefCounts.ProbeSize; OverflowSize: CARDINAL = RTRefCounts.mapOiOeLimit-1; OiRange: TYPE = [RTRefCounts.mapOiOeStart..RTRefCounts.mapOiOeStart+OverflowSize); GraphData: TYPE = REF GraphDataRec; GraphEntry: TYPE = RECORD [ value: INTEGER _ 0, -- current value (scaled) updateHint: UpdateHint _ bigger, fullScale: REAL]; -- log of full scale value (-1 = linear in [0..1]) UpdateHint: TYPE = {bigger, smaller, same}; GraphDataRec: TYPE = RECORD [top, middle, bottom: GraphEntry]; Parameter: TYPE = REF ParameterBlock; ParameterBlock: TYPE = RECORD [ action: PROC [Parameter], label: Labels.Label, value,increment,lo,hi: INT]; <<**** The following stats can be examined by the interpreter ****>> WatchStats: TYPE = RECORD [ diskFree, gfiFree, mdsFree: INT _ 0, vmFree, vmRun: INT _ 0, vmCedar, vmZones: INT _ 0, seconds: INT _ 0, cpuLoad: REAL _ 0.0 ]; watchStats: WatchStats; <<**** Global variables for Watch ****>> cifsLabel: Labels.Label _ NIL; cifsChanges: LIST OF Rope.ROPE _ NIL; cifsPause: CONDITION _ [timeout: Process.SecondsToTicks[1]]; cifsWait: CONDITION; idleCount: INT _ 0; quit: BOOLEAN _ FALSE; -- watched by various processes for exit notification waitCond: CONDITION; lastVMPoll: System.GreenwichMeanTime _ System.gmtEpoch; newOpenHeight: INTEGER _ 0; oldOpenHeight: INTEGER _ 0; smallerOpenHeight: INTEGER _ 0; biggerOpenHeight: INTEGER _ 0; <<**** Procedures for Watch ****>> GraphPaint: ViewerClasses.PaintProc = { OPEN Imager; data: GraphData = NARROW[self.data]; IF whatChanged = NIL THEN data.bottom.updateHint _ data.middle.updateHint _ data.top.updateHint _ bigger; SELECT data.top.updateHint FROM bigger => TRUSTED { SetColor[context, black]; MaskIntRectangle[context, [0, 2*self.ch/3, data.top.value, self.ch/3]]}; smaller => { SetColor[context, white]; MaskIntRectangle[context, [data.top.value, 2*self.ch/3, self.cw, self.ch/3]]}; ENDCASE; SELECT data.middle.updateHint FROM bigger => TRUSTED { SetColor[context, black]; MaskIntRectangle[context, [0, self.ch/3, data.middle.value, self.ch/3]]}; smaller => { SetColor[context, white]; MaskIntRectangle[context, [data.middle.value, self.ch/3, self.cw, self.ch/3]]}; ENDCASE; SELECT data.bottom.updateHint FROM bigger => TRUSTED { SetColor[context, black]; MaskIntRectangle[context, [0, 0, data.bottom.value, self.ch/3]]}; smaller => { SetColor[context, white]; MaskIntRectangle[context, [data.bottom.value, 0, self.cw, self.ch/3]]}; ENDCASE; }; Log10: PROC [x: REAL] RETURNS [lx: REAL] = { <> < 0>> < log(x) {absolute error < .0007}>> < 1e6 => 6>> <> sqrt10: REAL = 3.162278; t: REAL; <> SELECT x FROM < 1e0 => {x _ 1.0; lx _ 0}; < 1e1 => lx _ 0; < 1e2 => {x _ x * 1e-1; lx _ 1}; < 1e3 => {x _ x * 1e-2; lx _ 2}; < 1e4 => {x _ x * 1e-3; lx _ 3}; < 1e5 => {x _ x * 1e-4; lx _ 4}; < 1e6 => {x _ x * 1e-5; lx _ 5}; ENDCASE => {x _ 1.0; lx _ 6}; <> IF x > sqrt10 THEN {x _ x*(1/sqrt10); lx _ lx + 0.5}; <> t _ (x - 1)/(x + 1); lx _ lx + 0.86304*t + 0.36415*(t*t*t) }; GraphSet: PROC [graph: ViewerClasses.Viewer, t, m, b: REAL] = { tempR: REAL; tempI: INTEGER; myData: GraphData _ NARROW[graph.data]; IF myData = NIL THEN RETURN; tempR _ IF myData.top.fullScale<0 THEN t*graph.cw ELSE Log10[1 + t]*graph.cw/myData.top.fullScale; tempI _ Real.RoundI[tempR]; myData.top.updateHint _ IF tempI > myData.top.value THEN bigger ELSE IF tempI < myData.top.value THEN smaller ELSE same; myData.top.value _ tempI; tempR _ IF myData.middle.fullScale<0 THEN m*graph.cw ELSE Log10[1 + m]*graph.cw/myData.middle.fullScale; tempI _ Real.RoundI[tempR]; myData.middle.updateHint _ IF tempI > myData.middle.value THEN bigger ELSE IF tempI < myData.middle.value THEN smaller ELSE same; myData.middle.value _ tempI; tempR _ IF myData.bottom.fullScale<0 THEN b*graph.cw ELSE Log10[1 + b]*graph.cw/myData.bottom.fullScale; tempI _ Real.RoundI[tempR]; myData.bottom.updateHint _ IF tempI > myData.bottom.value THEN bigger ELSE IF tempI < myData.bottom.value THEN smaller ELSE same; myData.bottom.value _ tempI; IF NOT graph.parent.iconic THEN TRUSTED{ ViewerOps.PaintViewer[graph, client, FALSE, $Update] } }; Decimal: PROC [int: INT] RETURNS [ROPE] = { SELECT int FROM 0 => RETURN ["0"]; 1 => RETURN ["1"]; 2 => RETURN ["2"]; 3 => RETURN ["3"]; ENDCASE; RETURN[Convert.ValueToRope[[signed[int, 10]]]]}; AdjustParameter: Buttons.ButtonProc = { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> IF NOT quit THEN { viewer: ViewerClasses.Viewer _ NARROW[parent]; data: Parameter _ NARROW[clientData]; new: INT _ data.value; IF mouseButton = red THEN { IF data.increment = 0 THEN new _ new * 2 ELSE new _ new + data.increment} ELSE { IF data.increment = 0 THEN new _ new / 2 ELSE new _ new - data.increment}; IF new < data.lo THEN new _ data.lo; IF new > data.hi THEN new _ data.hi; IF data.value # new THEN { data.value _ new; data.action[data]; SetLabel[data.label, data.value]}; }; }; SetLabel: PROC [label: NumberLabel, value: INT, paint: BOOL _ TRUE] = { IF NOT quit THEN { IF label.destroyed THEN RETURN; NumberLabels.NumberLabelUpdate[label, value]; }; }; UpdateCifsStatus: ENTRY PROC [r: ROPE] = TRUSTED { prev: LIST OF Rope.ROPE _ NIL; IF quit THEN RETURN; FOR this: LIST OF Rope.ROPE _ cifsChanges, this.rest UNTIL this = NIL DO prev _ this; ENDLOOP; IF prev = NIL THEN cifsChanges _ CONS[first: r, rest: NIL] ELSE prev.rest _ CONS[first: r, rest: NIL]; NOTIFY cifsWait; }; NextCifsStatus: ENTRY PROC RETURNS [r: ROPE] = TRUSTED { WAIT cifsPause; -- force one second between display changes -- WHILE cifsChanges = NIL AND NOT quit DO WAIT cifsWait ENDLOOP; IF quit THEN {cifsChanges _ NIL; RETURN}; r _ cifsChanges.first; cifsChanges _ cifsChanges.rest; }; FindPosAfter: PROC [base: ROPE, object: ROPE, pos: INT _ 0] RETURNS [INT] = TRUSTED { start: INT _ Rope.Find[s1: base, pos1: pos, s2: object, case: FALSE]; IF start < 0 THEN RETURN [pos]; RETURN [start + object.Length[]]; }; DisplayCifsStatus: PROC = TRUSTED { UNTIL quit DO r: ROPE _ NextCifsStatus[]; IF r.Length[] = 0 THEN Labels.SetDisplayStyle[cifsLabel, $BlackOnWhite] ELSE { pos: INT _ FindPosAfter[r, "Retrieving "]; IF pos # 0 THEN r _ r.Replace[0, FindPosAfter[r, "/Indigo/", pos], "Cifs: "]; Labels.Set[cifsLabel, r]; Labels.SetDisplayStyle[cifsLabel, $WhiteOnBlack]; }; ENDLOOP; cifsLabel _ NIL; cifsChanges _ NIL; }; IdleProcess: PROC = TRUSTED { Process.SetPriority[0]; WHILE NOT quit DO idleCount _ idleCount + 1; ENDLOOP; }; SumZones: PROC RETURNS [inZones: CARDINAL _ 0] = TRUSTED { map: RTZones.TMapQZf _ RTZones.MapQZf; FOR i: NAT IN [0..map.length) DO f: RTZones.ZoneFinger _ map[i]; IF f = RTZones.mzVacant THEN LOOP; inZones _ inZones + RTQuanta.PagesPerQuantum; ENDLOOP; }; SameFile: PROC [cap1,cap2: File.Capability] RETURNS [BOOL] = TRUSTED { RETURN [File.ShowCapability[cap1].fID = File.ShowCapability[cap2].fID]; }; FileFromAddress: PROC [addr: LONG POINTER] RETURNS [File.Capability] = TRUSTED { ENABLE {ABORTED => GO TO abort; ANY => GO TO none}; page: Space.PageNumber _ Space.PageFromLongPointer[addr]; space: Space.Handle _ Space.GetHandle[page]; RETURN [Space.GetWindow[space].file]; EXITS abort => ERROR ABORTED; none => RETURN [File.nullCapability]; }; CountVM: PROC [parent: Space.Handle] RETURNS [ total--pages in use--, largest--largest leaf space--, avg--size of leaf spaces--, count--number of leaf spaces--, totalFree--number of free pages--, largestFree--largest free run--, avgFree--size of free run--, countFree--number of free runs--, mdsFree--number of MDS pages free--, cedarPages--pages mapped to Cedar backing file--, mappedPages--pages mapped to some backing file--, unmappedPages--pages in allocated spaces, but not mapped--, anonPages--pages mapped to anonymous backing file--, unknownPages--pages mapped to some file, but not known which file--, sparePages--spare pages within low-level spaces--, toBoot--pages mapped to boot file--: INT] = { accumForSpace: PROC [space: Space.Handle, level: INTEGER _ 0, tryMapped: BOOL _ TRUE] = TRUSTED { child: Space.Handle; spaceBase, spaceLim, nextStart, pages: CARDINAL; mapped: BOOL; [lowestChild: child, size: pages, base: spaceBase, mapped: mapped] _ Space.GetAttributes[space]; nextStart _ 0; spaceLim _ spaceBase + pages; IF tryMapped AND mapped THEN TRUSTED { <> file: File.Capability _ File.nullCapability; mappedPages _ mappedPages + pages; {ENABLE {ABORTED => GO TO abort; ANY => GO TO noGood}; file _ Space.GetWindow[space].file; EXITS noGood => unknownPages _ unknownPages + pages; abort => ERROR ABORTED; }; SELECT TRUE FROM SameFile[file, CedarVMFile] => cedarPages _ cedarPages + pages; SameFile[file, File.nullCapability] => anonPages _ anonPages + pages; SameFile[bootFile, File.nullCapability] => { <> bootFile _ file; toBoot _ toBoot + pages}; SameFile[file, bootFile] => { toBoot _ toBoot + pages}; ENDCASE; }; IF NOT mapped AND child # Space.nullHandle THEN { childSize: CARDINAL _ 0; nextChild: Space.Handle; base: CARDINAL; [] _ Space.GetAttributes[child ! ANY => GO TO forceLeaf]; WHILE child # Space.nullHandle DO [nextSibling: nextChild, size: childSize, base: base] _ Space.GetAttributes[child ! ANY => GO TO moreUnknown]; IF base > nextStart THEN { <> free: CARDINAL _ base-nextStart; IF level > 1 THEN IF space = Space.mds THEN mdsFree _ mdsFree + free ELSE sparePages _ sparePages + free ELSE { totalFree _ totalFree + free; countFree _ countFree + 1; IF free > largestFree THEN largestFree _ free}; }; nextStart _ base + childSize; accumForSpace[child, level+1, tryMapped AND NOT mapped]; child _ nextChild; ENDLOOP; base _ pages; IF base > nextStart THEN { <> free: CARDINAL _ base-nextStart; IF level > 1 THEN IF space = Space.mds THEN mdsFree _ mdsFree + free ELSE sparePages _ sparePages + free ELSE { totalFree _ totalFree + free; countFree _ countFree + 1; IF free > largestFree THEN largestFree _ free}; }; RETURN; EXITS forceLeaf => {}; moreUnknown => { unknownPages _ unknownPages + pages - (nextStart-spaceBase); RETURN; }; }; <> total _ total + pages; count _ count + 1; IF largest < pages THEN largest _ pages; IF tryMapped AND NOT mapped THEN unmappedPages _ unmappedPages + pages; }; bootFile: File.Capability _ File.nullCapability; CedarVMFile: File.Capability _ File.nullCapability; TRUSTED { rope: ROPE _ "rope"; CedarVMFile _ FileFromAddress[LOOPHOLE[rope]]; bootFile _ FileFromAddress[LOOPHOLE[DiskDriverSharedImpl,POINTER]]; }; FOR i: NAT IN [0..10) DO total _ largest _ avg _ count _ totalFree _ largestFree _ avgFree _ countFree _ cedarPages _ mappedPages _ unmappedPages _ anonPages _ unknownPages _ sparePages _ toBoot _ mdsFree _ 0; accumForSpace[parent, 1 ! ABORTED => GO TO abort; ANY => LOOP]; EXIT; ENDLOOP; IF count > 0 THEN avg _ total / count; IF countFree > 0 THEN avgFree _ totalFree / countFree; EXITS abort => ERROR ABORTED; }; CountGFI: PROC RETURNS [free: INT] = TRUSTED { free _ 0; FOR i: CARDINAL DECREASING IN [1..SDDefs.SD[SDDefs.sGFTLength]) DO item: PrincOpsRuntime.GFTItem _ PrincOpsRuntime.GFT[i]; IF item.data # 0 THEN EXIT; free _ free + 1; ENDLOOP; }; GetRCTabStats: PROC RETURNS [ normal, pinned, finalize, chains, normalFree, overflow, overflowFree: INTEGER _ 0] = TRUSTED { mapPiRce: LONG POINTER TO RTRefCounts.AMapPiRce = RTRefCounts.GetMapPiRce[]; rPtr: LONG POINTER TO RTRefCounts.RCEntry _ @mapPiRce[0]; mapOiOe: LONG POINTER TO RTRefCounts.AMapOiOe = RTRefCounts.GetMapOiOe[]; oPtr: LONG POINTER TO RTRefCounts.OverflowEntry _ @mapOiOe[0]; FOR pi: CARDINAL IN [0..NormalSize) DO entry: RTRefCounts.RCEntry = rPtr^; rPtr _ rPtr + SIZE[RTRefCounts.RCEntry]; IF entry = RTRefCounts.rceEmpty THEN {normalFree _ normalFree + 1; LOOP}; WITH e: entry SELECT FROM overflow => chains _ chains + 1; normal => { normal _ normal + 1; SELECT e.rc FROM LAST[RTRefCounts.RefCt] => pinned _ pinned + 1; <= RTRefCounts.rcFinalize => finalize _ finalize + 1; ENDCASE; }; ENDCASE; ENDLOOP; FOR oi: CARDINAL IN OiRange DO oe: RTRefCounts.OverflowEntry = oPtr^; rce: RTRefCounts.RCEntry = oe.rce; oPtr _ oPtr + SIZE[RTRefCounts.OverflowEntry]; WITH e: rce SELECT FROM overflow => overflowFree _ overflowFree + 1; normal => { overflow _ overflow + 1; SELECT e.rc FROM LAST[RTRefCounts.RefCt] => pinned _ pinned + 1; <= RTRefCounts.rcFinalize => finalize _ finalize + 1; ENDCASE; }; ENDCASE; ENDLOOP; }; CountDisk: PROC RETURNS [free: INT] = { [freePageCount: free] _ Volume.GetAttributes[Volume.SystemID[]]; }; CauseGCHit: Buttons.ButtonProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> IF NOT quit THEN { viewer: ViewerClasses.Viewer _ NARROW[parent]; Buttons.SetDisplayStyle[viewer, $BlackOnGrey]; SafeStorage.ReclaimCollectibleObjects[TRUE, mouseButton # red]; IF shift THEN SafeStorage.TrimAllZones[]; IF control THEN [] _ SafeStorage.TrimRootBase[]; IF control OR shift THEN ForceSampleEntry[]; Buttons.SetDisplayStyle[viewer, $BlackOnWhite]; }; }; CollectorWatcher: PROC [gcStatusLabel: Labels.Label] = { ENABLE ABORTED => GO TO done; active: ROPE = "BUSY: "; trimming: ROPE = "BUSY: trimming zones"; inactive: ROPE = "done."; wordsBetweenTrim: INT _ 0; defaultBetweenTrim: INT _ UserProfile.Number["Watch.BetweenTrim", 256*LONG[1024]]; defaultCedarDelta: INT _ UserProfile.Number["Watch.CedarDelta", 1600]; WHILE NOT quit DO cReasons: ARRAY SafeStorage.ReclamationReason OF ROPE = ["clientRequest", "clientTandSRequest", "clientNoTraceRequest", "rcTableOverflow", "allocationInterval", "quantaNeeded", "finalizationThreshold"]; r: SafeStorage.ReclamationReason; wrds,objs: LONG CARDINAL; GCnumber: CARDINAL; msg: ROPE _ inactive; [reason: r] _ SafeStorage.WaitForCollectorStart[]; IF quit THEN EXIT; TRUSTED{ Labels.Set[gcStatusLabel, active.Concat[cReasons[r]] ] }; [incarnation: GCnumber, reason: r, wordsReclaimed: wrds, objectsReclaimed: objs] _ SafeStorage.WaitForCollectorDone[]; wordsBetweenTrim _ wordsBetweenTrim + wrds; IF quit THEN EXIT; IF watchStats.vmRun < 1000 AND watchStats.vmCedar - watchStats.vmZones > defaultCedarDelta AND defaultBetweenTrim > 0 AND wordsBetweenTrim > defaultBetweenTrim THEN { Labels.Set[gcStatusLabel, trimming]; wordsBetweenTrim _ 0; SafeStorage.TrimAllZones[]; [] _ SafeStorage.TrimRootBase[]; }; TRUSTED{ IF quit THEN EXIT; Labels.Set[ gcStatusLabel, inactive.Cat[ " (GC#", Decimal[GCnumber], " got ", Decimal[LOOPHOLE[wrds]].Concat[" words, "], Decimal[LOOPHOLE[objs]].Concat[" objs)"]]]; }; ENDLOOP; EXITS done => {}; }; SetGCInt: ENTRY PROC [parm: Parameter] = { ENABLE UNWIND => NULL; [] _ SafeStorage.SetCollectionInterval[parm.value]; }; MyDestroy: ENTRY ViewerClasses.DestroyProc = { ENABLE UNWIND => NULL; viewer: ViewerClasses.Viewer _ NARROW[self]; quit _ TRUE; BROADCAST waitCond; }; WaitForUpdate: ENTRY PROC RETURNS[ vmWanted: BOOL ] = { ENABLE UNWIND => NULL; now: System.GreenwichMeanTime; vmInterval: INT _ 60; -- seconds -- interval: INT; WAIT waitCond; now _ System.GetGreenwichMeanTime[]; interval _ now - lastVMPoll; vmWanted _ interval > vmInterval; watchStats.seconds _ watchStats.seconds + interval; }; SetPause: ENTRY PROC [parm: Parameter] = TRUSTED { ENABLE UNWIND => NULL; Process.SetTimeout[@waitCond, Process.SecondsToTicks[parm.value]]; BROADCAST waitCond; }; ForceSample: Buttons.ButtonProc = { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> ENABLE UNWIND => NULL; viewer: ViewerClasses.Viewer _ NARROW[parent]; IF control THEN newOpenHeight _ smallerOpenHeight; IF shift THEN newOpenHeight _ biggerOpenHeight; ForceSampleEntry[]; }; ForceSampleEntry: ENTRY PROC = { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> ENABLE UNWIND => NULL; lastVMPoll _ System.gmtEpoch; BROADCAST waitCond; }; Watcher: PROC = TRUSTED { ENABLE ABORTED => GO TO done; defaultInterval: INT _ UserProfile.Number["Watch.GCInterval", 16000]; defaultSample: INT _ UserProfile.Number["Watch.SamplePause", 2]; graphClass: ViewerClasses.ViewerClass = NEW[ViewerClasses.ViewerClassRec _ [paint: GraphPaint, destroy: MyDestroy]]; container, graph: ViewerClasses.Viewer _ NIL; wordsLabel, faultLabel, diskReqLabel, mdsLabel, gfiLabel, diskLabel: Labels.Label _ NIL; freeVMLabel, maxFreeLabel: Labels.Label _ NIL; cedarVMLabel, inZonesLabel: Labels.Label _ NIL; mappedPagesLabel,unmappedPagesLabel: Labels.Label _ NIL; unmappedFullLabel,unmappedPartLabel,unmappedMDSLabel: Labels.Label _ NIL; anonPagesLabel,toBootLabel,spareLabel: Labels.Label _ NIL; usedNormalLabel,finalizeNormalLabel: Labels.Label _ NIL; pinnedNormalLabel,freeNormalLabel: Labels.Label _ NIL; usedOverflowLabel,chainsOverflowLabel,freeOverflowLabel: Labels.Label _ NIL; gapX: INTEGER = 2; gapY: INTEGER = 2; lastX: INTEGER; nextX: INTEGER _ gapX; nextY: INTEGER _ 0; faults, faultRate, oldFaultRate, deltaFaults: INT _ 0; words, wordsRate, oldWordsRate, deltaWords: INT _ 0; maxIdleRate: INT _ 1; oldIdleRate, idleRate, lastIdle: INT _ 0; delta, mark, deltaMillis: ShowTime.Microseconds _ 0; vmWanted: BOOL _ TRUE; -- whether to sample VM stats this time -- newMDS, oldMDS: INT _ 0; newGFI, oldGFI: INT _ 0; unknownPages: INT _ 0; newDiskReq: INT _ 0; newDisk: INT _ 0; freeVM: INT _ 0; maxFreeVM: INT _ 0; cedarVM: INT _ 0; inZones: INT _ 0; mappedPages: INT _ 0; unmappedPages: INT _ 0; unmappedFullPages: INT _ 0; unmappedPartPages: INT _ 0; anonPages: INT _ 0; toBoot: INT _ 0; usedNormal: INTEGER _ 0; finalizeNormal: INTEGER _ 0; pinnedNormal: INTEGER _ 0; freeNormal: INTEGER _ 0; usedOverflow: INTEGER _ 0; chainsOverflow: INTEGER _ 0; freeOverflow: INTEGER _ 0; AddLabel: PROC [prefix: ROPE, chars: NAT _ 0, lastInLine: BOOL _ FALSE, ww: INTEGER _ 0] RETURNS [label: Labels.Label] = TRUSTED { IF chars # 0 THEN { label _ Labels.Create[ info: [ name: prefix, parent: container, border: FALSE, wx: nextX, wy: nextY, ww: ww], paint: FALSE]; nextX _ nextX + label.ww; label _ NumberLabels.CreateNumber[ info: [name: NIL, parent: container, border: FALSE, wx: nextX, wy: nextY], chars: chars, paint: FALSE]; } ELSE label _ Labels.Create [ info: [ name: prefix, parent: container, border: FALSE, wx: nextX, wy: nextY, ww: ww], paint: FALSE]; lastX _ nextX _ label.wx + label.ww + gapX; IF lastInLine THEN { nextX _ gapX; nextY _ label.wy + label.wh + gapY}; }; AddButton: PROC [buttonName: ROPE _ NIL, chars: NAT _ 0, parm: Parameter _ NIL, proc: Buttons.ButtonProc _ NIL, lastInLine: BOOL _ FALSE] RETURNS [button: Buttons.Button] = TRUSTED { label: ViewerClasses.Viewer _ NIL; IF proc = NIL THEN proc _ AdjustParameter; button _ Buttons.Create [ info: [name: buttonName, parent: container, wx: nextX, wy: nextY, border: TRUE], fork: TRUE, proc: proc, clientData: parm, paint: FALSE]; nextX _ nextX + button.ww; SELECT TRUE FROM chars # 0 => label _ NumberLabels.CreateNumber[ info: [name: NIL, parent: container, border: FALSE, wx: nextX, wy: nextY], chars: chars, paint: FALSE]; parm # NIL => label _ Labels.Create [ info: [name: NIL, parent: container, border: FALSE, wx: nextX, wy: nextY], paint: FALSE]; ENDCASE; IF label # NIL THEN { nextX _ nextX + label.ww; IF parm # NIL THEN parm.label _ label; }; lastX _ nextX _ nextX + gapX; IF lastInLine THEN { nextX _ gapX; nextY _ button.wy + button.wh + gapY}; }; CreateGraph: PROC RETURNS[viewer: ViewerClasses.Viewer] = TRUSTED { W2: PROC [r: ROPE] RETURNS [INTEGER] = TRUSTED INLINE {RETURN[VFonts.RopeWidth[r]/2]}; xTemp: CARDINAL; wordsLabel _ AddLabel["Words", 9, TRUE]; xTemp _ lastX; [] _ AddLabel["CPU Load ", 0, TRUE]; xTemp _ MAX[xTemp, lastX]; faultLabel _ AddLabel["Faults", 9, TRUE]; xTemp _ MAX[xTemp, lastX]; viewer _ ViewerOps.CreateViewer[ flavor: $BarGraph, info: [parent: container, wx: xTemp, wy: wordsLabel.wy + wordsLabel.wh, ww: ViewerSpecs.openRightWidth - xTemp - 5, wh: faultLabel.wy - (wordsLabel.wy + wordsLabel.wh), data: NEW[GraphDataRec _ [[fullScale: 5], [fullScale: -1], [fullScale: 2]]]], paint: FALSE]; xTemp _ viewer.ww/5; [] _ Labels.Create [info: [name: "1", parent: container, wx: viewer.wx - W2["1"], wy: wordsLabel.wy, border: FALSE], paint: FALSE]; [] _ Labels.Create [info: [name: "10", parent: container, wx: viewer.wx + xTemp - W2["10"], wy: wordsLabel.wy, border: FALSE], paint: FALSE]; [] _ Labels.Create [info: [name: "100", parent: container, wx: viewer.wx + 2*xTemp - W2["100"], wy: wordsLabel.wy, border: FALSE], paint: FALSE]; [] _ Labels.Create [info: [name: "1000", parent: container, wx: viewer.wx + 3*xTemp - W2["1000"], wy: wordsLabel.wy, border: FALSE], paint: FALSE]; [] _ Labels.Create [info: [name: "10000", parent: container, wx: viewer.wx + 4*xTemp - W2["10000"], wy: wordsLabel.wy, border: FALSE], paint: FALSE]; xTemp _ viewer.ww/4; [] _ Labels.Create [info: [name: "1", parent: container, wx: viewer.wx - W2["1"], wy: faultLabel.wy, border: FALSE], paint: FALSE]; [] _ Labels.Create [info: [name: "3", parent: container, wx: viewer.wx + xTemp - W2["3"], wy: faultLabel.wy, border: FALSE], paint: FALSE]; [] _ Labels.Create [info: [name: "10", parent: container, wx: viewer.wx + xTemp*2 - W2["10"], wy: faultLabel.wy, border: FALSE], paint: FALSE]; [] _ Labels.Create [info: [name: "30", parent: container, wx: viewer.wx + xTemp*3 - W2["30"], wy: faultLabel.wy, border: FALSE], paint: FALSE]; }; --CreateGraph-- pauseParm: Parameter _ NEW[ParameterBlock _ [SetPause, NIL, defaultSample, 0, 1, 256]]; gcParm: Parameter _ NEW[ParameterBlock _ [SetGCInt, NIL, defaultInterval, 0, 1000, 1024000]]; WHILE NOT Runtime.IsBound[NumberLabels.CreateNumber] DO Process.Pause[Process.SecondsToTicks[1]]; ENDLOOP; <> container _ Containers.Create[ info: [name: "Watch", iconic: TRUE, column: right, scrollable: FALSE]]; <> ViewerOps.RegisterViewerClass[$BarGraph, graphClass]; graph _ CreateGraph[]; <> diskReqLabel _ AddLabel["requests", 7]; diskLabel _ AddLabel["disk", 5]; gfiLabel _ AddLabel["gfi", 3]; mdsLabel _ AddLabel["mds", 2]; freeVMLabel _ AddLabel["VM", 4]; maxFreeLabel _ AddLabel["VM run", 4, TRUE]; <> [] _ AddButton[buttonName: "GC interval", chars: 7, parm: gcParm]; SetLabel[gcParm.label, gcParm.value]; SafeStorage.TrimAllZones[]; SetGCInt[gcParm]; [] _ AddButton[buttonName: "GC", proc: CauseGCHit]; { gcStatusLabel: Labels.Label = AddLabel ["inactive.", 0, TRUE, ViewerSpecs.openRightWidth]; Containers.ChildXBound[container, gcStatusLabel]; Process.Detach[FORK CollectorWatcher[gcStatusLabel]]; }; <> [] _ AddButton[buttonName: "Sample", proc: ForceSample]; [] _ AddButton[buttonName: "interval", chars: 3, parm: pauseParm]; SetLabel[pauseParm.label, pauseParm.value]; SetPause[pauseParm]; cifsLabel _ AddLabel["CIFS status (inverted iff active)", 0, TRUE, ViewerSpecs.openRightWidth]; Containers.ChildXBound[container, cifsLabel]; CIFSFeedback.Register[UpdateCifsStatus]; Process.Detach[FORK DisplayCifsStatus]; <> newOpenHeight _ oldOpenHeight _ smallerOpenHeight _ nextY + gapY - 1; ViewerOps.SetOpenHeight[container, oldOpenHeight]; <> mappedPagesLabel _ AddLabel["mapped", 5]; toBootLabel _ AddLabel["boot", 4]; anonPagesLabel _ AddLabel["anon", 4]; cedarVMLabel _ AddLabel["Cedar", 4]; inZonesLabel _ AddLabel["zones", 4, TRUE]; <> unmappedPagesLabel _ AddLabel["unmapped", 4]; unmappedFullLabel _ AddLabel["full", 4]; unmappedPartLabel _ AddLabel["part", 4]; unmappedMDSLabel _ AddLabel["mds", 2, TRUE]; <> usedNormalLabel _ AddLabel["normalRC", 5]; finalizeNormalLabel _ AddLabel["finalize", 4]; pinnedNormalLabel _ AddLabel["pinned", 4]; freeNormalLabel _ AddLabel["free", 5, TRUE]; <> usedOverflowLabel _ AddLabel["overflowRC", 5]; chainsOverflowLabel _ AddLabel["chains", 4]; freeOverflowLabel _ AddLabel["free", 5, TRUE]; biggerOpenHeight _ nextY + gapY - 1; <> mark _ ShowTime.GetMark[]; idleCount _ 0; Process.Detach[FORK IdleProcess[]]; RTProcess.StartWatchingFaults[]; faults _ RTProcess.GetTotalPageFaults[]; words _ SafeStorage.NWordsAllocated[]; WHILE NOT quit AND NOT container.destroyed DO <> delta _ ShowTime.GetMark[] - mark; deltaMillis _ (delta + 500) / 1000; IF deltaMillis = 0 THEN LOOP; mark _ mark + delta; <> idleRate _ (idleCount-lastIdle) / deltaMillis; lastIdle _ idleCount; IF idleRate > maxIdleRate THEN { IF deltaMillis > 100 THEN maxIdleRate _ idleRate ELSE idleRate _ maxIdleRate }; <> deltaFaults _ RTProcess.GetTotalPageFaults[] - faults; faults _ faults + deltaFaults; faultRate _ (deltaFaults * 1000 + 500) / deltaMillis; <> deltaWords _ SafeStorage.NWordsAllocated[] - words; words _ words + deltaWords; wordsRate _ (deltaWords * 1000 + 500) / deltaMillis; IF container.iconic THEN { <> Process.Pause[Process.SecondsToTicks[1]]; LOOP; }; <> newGFI _ CountGFI[]; newDiskReq _ DiskDriverSharedImpl.totalNumberOfRequests; newDisk _ CountDisk[]; IF vmWanted AND NOT container.iconic THEN { <> [totalFree: freeVM, largestFree: maxFreeVM, mdsFree: newMDS, cedarPages: cedarVM, mappedPages: mappedPages, unmappedPages: unmappedFullPages, anonPages: anonPages, unknownPages: unknownPages, sparePages: unmappedPartPages, toBoot: toBoot] _ CountVM[Space.virtualMemory]; inZones _ SumZones[]; <> IF newOpenHeight > smallerOpenHeight THEN [usedNormal, pinnedNormal, finalizeNormal, chainsOverflow, freeNormal, usedOverflow, freeOverflow] _ GetRCTabStats[]; lastVMPoll _ System.GetGreenwichMeanTime[]; }; IF newOpenHeight # oldOpenHeight THEN { ViewerOps.SetOpenHeight[container, oldOpenHeight _ newOpenHeight]; IF NOT container.iconic THEN ViewerOps.ComputeColumn[ViewerOps.ViewerColumn[container]]; }; <> IF quit OR container.destroyed THEN RETURN; SetLabel[diskReqLabel, newDiskReq]; SetLabel[diskLabel, watchStats.diskFree _ newDisk]; SetLabel[mdsLabel, watchStats.mdsFree _ newMDS]; SetLabel[unmappedMDSLabel, newMDS]; SetLabel[gfiLabel, watchStats.gfiFree _ oldGFI _ newGFI]; SetLabel[wordsLabel, words]; SetLabel[faultLabel, faults]; IF oldFaultRate # faultRate OR oldWordsRate # wordsRate OR oldIdleRate # idleRate THEN GraphSet[ graph, oldWordsRate _ wordsRate, watchStats.cpuLoad _ 1 - (oldIdleRate _ idleRate)/(maxIdleRate*1.0), oldFaultRate _ faultRate]; SetLabel[freeVMLabel, watchStats.vmFree _ freeVM]; SetLabel[maxFreeLabel, watchStats.vmRun _ maxFreeVM]; SetLabel[inZonesLabel, watchStats.vmZones _ inZones]; SetLabel[cedarVMLabel, watchStats.vmCedar _ cedarVM]; SetLabel[mappedPagesLabel, mappedPages]; SetLabel[unmappedFullLabel, unmappedFullPages]; SetLabel[unmappedPartLabel, unmappedPartPages]; unmappedPages _ unmappedFullPages + unmappedPartPages + newMDS; SetLabel[unmappedPagesLabel, unmappedPages]; SetLabel[anonPagesLabel, anonPages]; SetLabel[toBootLabel, toBoot]; SetLabel[usedNormalLabel, usedNormal]; SetLabel[finalizeNormalLabel, finalizeNormal]; SetLabel[pinnedNormalLabel, pinnedNormal]; SetLabel[freeNormalLabel, freeNormal]; SetLabel[usedOverflowLabel, usedOverflow]; SetLabel[chainsOverflowLabel, chainsOverflow]; SetLabel[freeOverflowLabel, freeOverflow]; <> vmWanted _ WaitForUpdate[]; ENDLOOP; quit _ TRUE; RTProcess.StopWatchingFaults[]; EXITS done => {RTProcess.StopWatchingFaults[]}; }; <<**** Initialization code ****>> TRUSTED { Process.Detach[FORK Watcher]; }; END.