<> <> <> <> <<>> DIRECTORY BasicTime USING [GetClockPulses, Pulses, PulsesToMicroseconds], Buttons USING [Button, ButtonProc, Create, SetDisplayStyle], Containers USING [ChildXBound, Create], Convert USING [RopeFromInt], DebuggerSwap USING [WorryCallDebugger], Disk USING [GetStatistics], File USING [GetVolumePages, SystemVolume], FileStats USING [Data, GetData], FSExtras USING [NextRemoteEvent, RemoteEvent, RemoteOp], Graphics USING [black, DrawBox, SetColor, SetStipple, white], Labels USING [Create, Label, Set, SetDisplayStyle], Menus USING [MenuProc], NumberLabels USING [CreateNumber, NumberLabel, NumberLabelUpdate], PrincOps USING [GFT, GFTItem, PageCount, SD, sGFTLength], Process USING [Detach, MsecToTicks, Pause, SecondsToTicks, SetPriority, SetTimeout], Real USING [RoundI], Rope USING [Cat, Concat, Find, Length, ROPE, Substr], SafeStorage USING [ NWordsAllocated, ReclaimCollectibleObjects, ReclamationReason, SetCollectionInterval, WaitForCollectorDone, WaitForCollectorStart], UserProfile USING [Number], ViewerClasses USING [DestroyProc, PaintProc, Viewer, ViewerClass, ViewerClassRec], ViewerOps USING [ ComputeColumn, CreateViewer, PaintViewer, RegisterViewerClass, SetOpenHeight, ViewerColumn], ViewerSpecs USING [openRightWidth], VM USING [Allocate, CantAllocate, PageCount], VMStatistics USING [ checkoutConflicts, laundryCleanCalls, laundryWakeups, pageFaults, pagesCleaned, pagesCleanedPanic, panicLaundryWakeups, pinnedPages, readOnlyPages, rmAllocPasses, rmCleanPasses, rmDirty, rmFreeList, rmNewClean, rmOldClean, rmReclamations, swapInAlreadyIn, swapInCalls, swapInDirtyVictims, swapInFailedToCleanVictims, swapInNoRead, swapInPages, swapInPhysicalRuns, swapInReads, swapInVirtualRuns, uselessLaundryWakeups, VirtualAllocation], WatchStats USING [WatchStatsRecord]; Watch: CEDAR MONITOR IMPORTS BasicTime, Buttons, Containers, Convert, DebuggerSwap, Disk, File, FileStats, FSExtras, Graphics, Labels, NumberLabels, Process, Real, Rope, SafeStorage, UserProfile, ViewerOps, ViewerSpecs, VM, VMStatistics EXPORTS WatchStats = BEGIN <<**** Useful types from other interfaces ****>> Button: TYPE = Buttons.Button; Label: TYPE = Labels.Label; NumberLabel: TYPE = NumberLabels.NumberLabel; RemoteEventHandle: TYPE = REF READONLY FSExtras.RemoteEvent; RemoteOp: TYPE = FSExtras.RemoteOp; ROPE: TYPE = Rope.ROPE; <<**** Useful local types and constants ****>> GraphData: TYPE = REF GraphDataRec; GraphEntry: TYPE = RECORD [ value: REAL _ 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: Label, value,increment,lo,hi: INT]; <<**** The following stats are exported via GetWatchStats ****>> watchStats: WatchStats.WatchStatsRecord; GetWatchStats: PUBLIC ENTRY PROC RETURNS [WatchStats.WatchStatsRecord] = { RETURN [watchStats]; }; <<**** Global variables for Watch ****>> quit: BOOLEAN _ FALSE; -- watched by various processes for exit notification waitCond: CONDITION; newOpenHeight: INTEGER _ 0; oldOpenHeight: INTEGER _ 0; smallerOpenHeight: INTEGER _ 0; biggerOpenHeight: INTEGER _ 0; defaultInterval: INT _ UserProfile.Number["Watch.GCInterval", 16000]; defaultSample: INT _ UserProfile.Number["Watch.SamplePause", 2]; longPause: INT _ UserProfile.Number["Watch.LongPause", 30] * 1000; millisSinceLastBigBang: INT _ longPause; <<**** Procedures for Watch ****>> GraphPaint: ViewerClasses.PaintProc = { myGrey: CARDINAL = 122645B; 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 => { Graphics.SetStipple[context, myGrey]; Graphics.DrawBox[context, [0, 2*self.ch/3, data.top.value, self.ch]]}; smaller => { Graphics.SetColor[context, Graphics.white]; Graphics.DrawBox[context, [data.top.value, 2*self.ch/3, self.cw, self.ch]]}; ENDCASE; SELECT data.middle.updateHint FROM bigger => { Graphics.SetStipple[context, myGrey]; Graphics.DrawBox[context, [0, self.ch/3, data.middle.value, 2*self.ch/3]]}; smaller => { Graphics.SetColor[context, Graphics.white]; Graphics.DrawBox[context, [data.middle.value, self.ch/3, self.cw, 2*self.ch/3]]}; ENDCASE; SELECT data.bottom.updateHint FROM bigger => { Graphics.SetStipple[context, myGrey]; Graphics.DrawBox[context, [0, 0, data.bottom.value, self.ch/3]]}; smaller => { Graphics.SetColor[context, Graphics.white]; Graphics.DrawBox[context, [data.bottom.value, 0, self.cw, self.ch/3]]}; ENDCASE; Graphics.SetColor[context, Graphics.black] }; 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; 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; myData.top.updateHint _ IF tempR > myData.top.value THEN bigger ELSE IF tempR < myData.top.value THEN smaller ELSE same; myData.top.value _ tempR; tempR _ IF myData.middle.fullScale<0 THEN m*graph.cw ELSE Log10[1 + m]*graph.cw/myData.middle.fullScale; myData.middle.updateHint _ IF tempR > myData.middle.value THEN bigger ELSE IF tempR < myData.middle.value THEN smaller ELSE same; myData.middle.value _ tempR; tempR _ IF myData.bottom.fullScale<0 THEN b*graph.cw ELSE Log10[1 + b]*graph.cw/myData.bottom.fullScale; myData.bottom.updateHint _ IF tempR > myData.bottom.value THEN bigger ELSE IF tempR < myData.bottom.value THEN smaller ELSE same; myData.bottom.value _ tempR; 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.RopeFromInt[int]]}; AdjustParameter: Menus.MenuProc = { <<[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]; }; }; 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[]]; }; DisplayFSStatus: PROC [readFSlabel, writeFSlabel, flushFSlabel, NreadFSlabel, NwriteFSlabel, NflushFSlabel: Label] = { WaitForFSUpdate: ENTRY PROC = {WAIT fsPause}; fsPause: CONDITION _ [timeout: Process.MsecToTicks[200]]; readCount: INT _ 0; writeCount: INT _ 0; flushCount: INT _ 0; h: RemoteEventHandle _ NIL; r: ROPE; UNTIL quit DO countLabel, nameLabel: Label _ NIL; count: INT _ 0; style: ATOM _ $BlackOnWhite; WaitForFSUpdate[]; h _ FSExtras.NextRemoteEvent[h]; r _ h.fName; IF quit THEN EXIT; SELECT h.op FROM startRetrieving => { nameLabel _ readFSlabel; countLabel _ NreadFSlabel; count _ readCount _ readCount + 1; style _ $WhiteOnBlack; }; endRetrieving => { nameLabel _ readFSlabel; countLabel _ NreadFSlabel; count _ readCount; }; startStoring => { nameLabel _ writeFSlabel; countLabel _ NwriteFSlabel; count _ writeCount _ writeCount + 1; style _ $WhiteOnBlack; }; endStoring => { nameLabel _ writeFSlabel; countLabel _ NwriteFSlabel; count _ writeCount; }; startFlushing => { nameLabel _ flushFSlabel; countLabel _ NflushFSlabel; count _ flushCount _ flushCount + 1; style _ $WhiteOnBlack; }; endFlushing => { nameLabel _ flushFSlabel; countLabel _ NflushFSlabel; count _ flushCount; }; ENDCASE => LOOP; Labels.Set[nameLabel, r.Substr[FindPosAfter[r, "[Indigo]"]]]; Labels.SetDisplayStyle[nameLabel, style]; SetLabel[countLabel, count]; ENDLOOP; }; IdleProcess: PROC = TRUSTED { Process.SetPriority[0]; WHILE NOT quit DO watchStats.idleCount _ watchStats.idleCount + 1; IF PrincOpsUtils.ReadWDC[] # 0 THEN DebuggerSwap.WorryCallDebugger["Idle with interrupts disabled?"]; ENDLOOP; }; CountGFI: PROC RETURNS [free: NAT] = TRUSTED { free _ 0; FOR i: CARDINAL DECREASING IN [1..PrincOps.SD[PrincOps.sGFTLength]) DO item: PrincOps.GFTItem = PrincOps.GFT[i]; IF item.data = 0 THEN free _ free + 1; ENDLOOP; }; CountFreePages: PROC RETURNS [INT] = { RETURN[File.GetVolumePages[File.SystemVolume[]].free]; }; CauseGCHit: Menus.MenuProc = 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 = blue]; IF control OR shift THEN ForceSampleEntry[]; Buttons.SetDisplayStyle[viewer, $BlackOnWhite]; }; }; CollectorWatcher: PROC [gcStatusLabel: Label] = { ENABLE ABORTED => GO TO done; active: ROPE = "BUSY: "; inactive: ROPE = "done."; WHILE NOT quit DO cReasons: ARRAY SafeStorage.ReclamationReason OF ROPE = ["clientRequest", "clientTandSRequest", "clientNoTraceRequest", "rcTableOverflow", "allocationInterval", "quantaNeeded", "finalizationThreshold"]; wrds,objs: LONG CARDINAL; GCnumber: CARDINAL; msg: ROPE _ inactive; r: SafeStorage.ReclamationReason_ SafeStorage.WaitForCollectorStart[].reason; IF quit THEN EXIT; TRUSTED{ Labels.Set[gcStatusLabel, active.Concat[cReasons[r]] ] }; [incarnation: GCnumber, reason: r, wordsReclaimed: wrds, objectsReclaimed: objs] _ SafeStorage.WaitForCollectorDone[]; 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: PROC [parm: Parameter] = { [] _ 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; WAIT waitCond; }; SetPause: ENTRY PROC [parm: Parameter] = TRUSTED { ENABLE UNWIND => NULL; Process.SetTimeout[@waitCond, Process.SecondsToTicks[parm.value]]; BROADCAST waitCond; }; ForceSample: Menus.MenuProc = { <<[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; millisSinceLastBigBang _ longPause; BROADCAST waitCond; }; Watcher: PROC = TRUSTED { ENABLE ABORTED => GO TO done; graphClass: ViewerClasses.ViewerClass = NEW[ViewerClasses.ViewerClassRec _ [paint: GraphPaint, destroy: MyDestroy]]; container, graph: ViewerClasses.Viewer _ NIL; wordsLabel, diskIOLabel: Label _ NIL; <> diskLabel, gfiLabel, mdsLabel, freeVMLabel, maxFreeLabel: Label _ NIL; <> readFSlabel, writeFSlabel, flushFSlabel: Label _ NIL; NreadFSlabel, NwriteFSlabel, NflushFSlabel: Label _ NIL; <> diskPercentQueuedLabel, diskActiveSecsLabel, diskTotalSecsLabel: Label _ NIL; diskReadLabel, diskWriteLabel, diskReadPgsLabel, diskWritePgsLabel: Label _ NIL; <> vmFaultsLabel, vmReadOnlyLabel: Label _ NIL; vmPinnedPagesLabel, vmCheckoutConflictsLabel: Label _ NIL; <> rmAllocPassesLabel, rmReclamationsLabel: Label _ NIL; rmFreeListLabel, rmOldCleanLabel, rmNewCleanLabel, rmDirtyLabel: Label _ NIL; <> rmCleanPassesLabel, laundryWakeupsLabel, pagesCleanedLabel: Label _ NIL; panicLaundryWakeupsLabel, pagesCleanedPanicLabel: Label _ NIL; uselessLaundryWakeupsLabel, laundryCleanCallsLabel: Label _ NIL; <> swapInCallsLabel, swapInVirtualRunsLabel, swapInPhysicalRunsLabel: Label _ NIL; swapInPagesLabel, swapInAlreadyInLabel: Label _ NIL; swapInNoReadLabel, swapInReadsLabel: Label _ NIL; swapInDirtyVictimsLabel, swapInFailedToCleanVictimsLabel: Label _ NIL; <> fsOpenCallsLabel, fsOpenPagesLabel, fsOpenMSecsLabel: Label _ NIL; fsCreateCallsLabel, fsCreatePagesLabel, fsCreateMSecsLabel: Label _ NIL; fsDeleteCallsLabel, fsDeletePagesLabel, fsDeleteMSecsLabel: Label _ NIL; fsExtendCallsLabel, fsExtendPagesLabel, fsExtendMSecsLabel: Label _ NIL; fsContractCallsLabel, fsContractPagesLabel, fsContractMSecsLabel: Label _ NIL; fsReadCallsLabel, fsReadPagesLabel, fsReadMSecsLabel: Label _ NIL; fsWriteCallsLabel, fsWritePagesLabel, fsWriteMSecsLabel: Label _ NIL; gapX: INTEGER = 2; gapY: INTEGER = 2; lastX: INTEGER; nextX: INTEGER _ gapX; nextY: INTEGER _ 0; diskIORate, diskPercent, oldDiskPercent: REAL _ 0.0; diskIO: INT _ 0; words, wordsRate, oldWordsRate, deltaWords: INT _ 0; oldActiveDiskPulses, oldTotalDiskPulses: BasicTime.Pulses _ 0; maxIdleRate: INT _ 1; oldIdleRate, idleRate, lastIdle: INT _ 0; mark: BasicTime.Pulses; delta, deltaMillis: LONG CARDINAL _ 0; vmWanted: BOOL _ TRUE; -- whether to sample VM stats this time -- newMDS, oldMDS: INT _ 0; newGFI, oldGFI: INT _ 0; freeVM: INT _ 0; maxFreeVM: INT _ 0; AddLabel: PROC [prefix: ROPE, chars: NAT _ 0, lastInLine: BOOL _ FALSE, ww: INTEGER _ 0] RETURNS [label: 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.StringWidth[r]/2]; }; xTemp: CARDINAL; tempLabel: Labels.Label; wordsLabel _ AddLabel["Words", 9, TRUE]; xTemp _ lastX; [] _ AddLabel["CPU Load ", 0, TRUE]; xTemp _ MAX[xTemp, lastX]; diskIOLabel _ AddLabel["DiskIO", 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: diskIOLabel.wy - (wordsLabel.wy + wordsLabel.wh), data: NEW[GraphDataRec _ [[fullScale: 5], [fullScale: -1], [fullScale: -1]]]], 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; tempLabel _ Labels.Create [info: [name: "0%", parent: container, wx: viewer.wx - W2["1"], wy: diskIOLabel.wy, border: FALSE], paint: FALSE]; tempLabel _ Labels.Create [info: [name: "25%", parent: container, wx: viewer.wx + xTemp - W2["3"], wy: diskIOLabel.wy, border: FALSE], paint: FALSE]; tempLabel _ Labels.Create [info: [name: "50%", parent: container, wx: viewer.wx + xTemp*2 - W2["10"], wy: diskIOLabel.wy, border: FALSE], paint: FALSE]; tempLabel _ Labels.Create [info: [name: "75%", parent: container, wx: viewer.wx + xTemp*3 - W2["30"], wy: diskIOLabel.wy, border: FALSE], paint: FALSE]; }; --CreateGraph-- pauseParm: Parameter _ NEW[ParameterBlock _ [SetPause, NIL, defaultSample, 0, 1, 64]]; gcParm: Parameter _ NEW[ParameterBlock _ [SetGCInt, NIL, defaultInterval, 0, 1000, 512000]]; <> container _ Containers.Create[ info: [name: "Watch", iconic: TRUE, column: right, scrollable: FALSE]]; <> ViewerOps.RegisterViewerClass[$BarGraph, graphClass]; graph _ CreateGraph[]; <> [] _ AddLabel["Free "]; diskLabel _ AddLabel["disk", 5]; gfiLabel _ AddLabel["gfi", 3]; mdsLabel _ AddLabel["mds", 3]; freeVMLabel _ AddLabel["VM", 5]; maxFreeLabel _ AddLabel["VM run", 5, TRUE]; <> [] _ AddButton[buttonName: "GC interval", chars: 6, parm: gcParm]; SetLabel[gcParm.label, gcParm.value]; SetGCInt[gcParm]; [] _ AddButton[buttonName: "GC", proc: CauseGCHit]; { gcStatusLabel: 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: 2, parm: pauseParm]; SetLabel[pauseParm.label, pauseParm.value]; SetPause[pauseParm]; readFSlabel _ AddLabel[ "FS status (inverted iff busy)", 0, TRUE, ViewerSpecs.openRightWidth]; Containers.ChildXBound[container, readFSlabel]; <> newOpenHeight _ oldOpenHeight _ smallerOpenHeight _ nextY + gapY - 1; ViewerOps.SetOpenHeight[container, oldOpenHeight]; <> <<>> <> [] _ AddLabel["Flushing "]; flushFSlabel _ AddLabel[ "(FS file being flushed)", 0, TRUE, ViewerSpecs.openRightWidth]; Containers.ChildXBound[container, flushFSlabel]; <<>> <> [] _ AddLabel["Storing "]; writeFSlabel _ AddLabel[ "(FS file being stored)", 0, TRUE, ViewerSpecs.openRightWidth]; Containers.ChildXBound[container, writeFSlabel]; <> [] _ AddLabel["FS "]; NreadFSlabel _ AddLabel["fetches", 5]; NflushFSlabel _ AddLabel["flushes", 5]; NwriteFSlabel _ AddLabel["stores", 5, TRUE]; <> [] _ AddLabel["Disk "]; diskPercentQueuedLabel _ AddLabel["% busy", 3]; diskActiveSecsLabel _ AddLabel["secs busy", 6]; diskTotalSecsLabel _ AddLabel["secs total", 7, TRUE]; diskReadLabel _ AddLabel[" reads", 6]; diskReadPgsLabel _ AddLabel["rPgs", 7]; diskWriteLabel _ AddLabel["writes", 6]; diskWritePgsLabel _ AddLabel["wPgs", 7, TRUE]; <> [] _ AddLabel["VM "]; vmFaultsLabel _ AddLabel["faults", 7]; vmReadOnlyLabel _ AddLabel["readOnly", 5]; vmPinnedPagesLabel _ AddLabel["pinned", 5]; vmCheckoutConflictsLabel _ AddLabel["conflicts", 4, TRUE]; <> [] _ AddLabel["Replacement "]; rmAllocPassesLabel _ AddLabel["passes", 4]; rmReclamationsLabel _ AddLabel["pages", 6, TRUE]; rmFreeListLabel _ AddLabel[" free", 6]; rmOldCleanLabel _ AddLabel["old", 6]; rmNewCleanLabel _ AddLabel["new", 6]; rmDirtyLabel _ AddLabel["dirty", 6, TRUE]; <> [] _ AddLabel["Laundry "]; rmCleanPassesLabel _ AddLabel["passes", 6]; laundryWakeupsLabel _ AddLabel["wakeups", 6]; pagesCleanedLabel _ AddLabel["pages", 7, TRUE]; panicLaundryWakeupsLabel _ AddLabel[" panic", 3]; pagesCleanedPanicLabel _ AddLabel["panicPgs", 5]; uselessLaundryWakeupsLabel _ AddLabel["useless", 6]; laundryCleanCallsLabel _ AddLabel["cleanCalls", 5, TRUE]; <> [] _ AddLabel["SwapIn "]; swapInCallsLabel _ AddLabel["calls", 6]; swapInVirtualRunsLabel _ AddLabel["vRuns", 6]; swapInPhysicalRunsLabel _ AddLabel["pRuns", 6, TRUE]; swapInPagesLabel _ AddLabel[" pages", 7]; swapInAlreadyInLabel _ AddLabel["alreadyIn", 7]; swapInNoReadLabel _ AddLabel["undef", 7]; swapInReadsLabel _ AddLabel["read", 7, TRUE]; swapInDirtyVictimsLabel _ AddLabel[" dirtyVictims", 5]; swapInFailedToCleanVictimsLabel _ AddLabel["cleanFailed", 5, TRUE]; {-- line 11: FileStats stuff ww: INTEGER; [] _ AddLabel["File Statistics", 0, TRUE]; ww _ AddLabel[" Open "].ww; fsOpenCallsLabel _ AddLabel["calls", 6]; fsOpenPagesLabel _ AddLabel["pages", 7]; fsOpenMSecsLabel _ AddLabel["msecs", 8, TRUE]; [] _ AddLabel[" Create", 0, FALSE, ww]; fsCreateCallsLabel _ AddLabel["calls", 6]; fsCreatePagesLabel _ AddLabel["pages", 7]; fsCreateMSecsLabel _ AddLabel["msecs", 8, TRUE]; [] _ AddLabel[" Delete", 0, FALSE, ww]; fsDeleteCallsLabel _ AddLabel["calls", 6]; fsDeletePagesLabel _ AddLabel["pages", 7]; fsDeleteMSecsLabel _ AddLabel["msecs", 8, TRUE]; [] _ AddLabel[" Extend", 0, FALSE, ww]; fsExtendCallsLabel _ AddLabel["calls", 6]; fsExtendPagesLabel _ AddLabel["pages", 7]; fsExtendMSecsLabel _ AddLabel["msecs", 8, TRUE]; [] _ AddLabel[" Contract", 0, FALSE, ww]; fsContractCallsLabel _ AddLabel["calls", 6]; fsContractPagesLabel _ AddLabel["pages", 7]; fsContractMSecsLabel _ AddLabel["msecs", 8, TRUE]; [] _ AddLabel[" Read", 0, FALSE, ww]; fsReadCallsLabel _ AddLabel["calls", 6]; fsReadPagesLabel _ AddLabel["pages", 7]; fsReadMSecsLabel _ AddLabel["msecs", 8, TRUE]; [] _ AddLabel[" Write", 0, FALSE, ww]; fsWriteCallsLabel _ AddLabel["calls", 6]; fsWritePagesLabel _ AddLabel["pages", 7]; fsWriteMSecsLabel _ AddLabel["msecs", 8, TRUE]; }; biggerOpenHeight _ nextY + gapY - 1; <> Process.Detach[ FORK DisplayFSStatus[ readFSlabel, writeFSlabel, flushFSlabel, NreadFSlabel, NwriteFSlabel, NflushFSlabel]]; mark _ BasicTime.GetClockPulses[]; watchStats.idleCount _ 0; Process.Detach[FORK IdleProcess[]]; words _ SafeStorage.NWordsAllocated[]; WHILE NOT quit AND NOT container.destroyed DO <> reads,writes,readPgs,writePgs: INT; newActiveDiskPulses, newTotalDiskPulses: BasicTime.Pulses; nextMark: BasicTime.Pulses = BasicTime.GetClockPulses[]; delta _ BasicTime.PulsesToMicroseconds[nextMark - mark]; deltaMillis _ (delta + 500) / 1000; IF deltaMillis <= 1 THEN LOOP; mark _ nextMark; <> idleRate _ (watchStats.idleCount-lastIdle) / deltaMillis; lastIdle _ watchStats.idleCount; IF idleRate > maxIdleRate THEN { IF deltaMillis > 100 THEN maxIdleRate _ idleRate ELSE idleRate _ maxIdleRate; }; <> [active: newActiveDiskPulses, total: newTotalDiskPulses, reads: reads, writes: writes, readPages: readPgs, writePages: writePgs] _ Disk.GetStatistics[]; IF newTotalDiskPulses > oldTotalDiskPulses THEN diskPercent _ (1.0*(newActiveDiskPulses-oldActiveDiskPulses)) / (newTotalDiskPulses-oldTotalDiskPulses); oldActiveDiskPulses _ newActiveDiskPulses; oldTotalDiskPulses _ newTotalDiskPulses; diskIO _ reads+writes; <> deltaWords _ SafeStorage.NWordsAllocated[] - words; words _ words + deltaWords; wordsRate _ (deltaWords * 1000 + 500) / deltaMillis; IF container.iconic THEN { <> Process.Pause[Process.SecondsToTicks[1]]; LOOP; }; millisSinceLastBigBang _ MIN[longPause, millisSinceLastBigBang + deltaMillis]; <<>> <> {pagesAllocated, pagesFreed, pagesInPartition: VM.PageCount; [pagesAllocated, pagesFreed, pagesInPartition] _ VMStatistics.VirtualAllocation[mds]; newMDS _ MAX[0, pagesInPartition - pagesAllocated + pagesFreed]; [pagesAllocated, pagesFreed, pagesInPartition] _ VMStatistics.VirtualAllocation[normalVM]; freeVM _ MAX[0, pagesInPartition - pagesAllocated + pagesFreed]; IF millisSinceLastBigBang >= longPause AND NOT container.iconic THEN { <> millisSinceLastBigBang _ 0; [] _ VM.Allocate[pagesInPartition+pagesInPartition ! VM.CantAllocate => {maxFreeVM _ bestInterval.count; CONTINUE}; ]; <> newGFI _ CountGFI[]; }; }; 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[diskLabel, watchStats.diskFree _ CountFreePages[]]; SetLabel[mdsLabel, watchStats.mdsFree _ newMDS]; SetLabel[gfiLabel, watchStats.gfiFree _ oldGFI _ newGFI]; SetLabel[freeVMLabel, watchStats.vmFree _ freeVM]; SetLabel[maxFreeLabel, watchStats.vmRun _ maxFreeVM]; <<>> <> SetLabel[wordsLabel, words]; SetLabel[diskIOLabel, diskIO]; IF oldDiskPercent # diskPercent OR oldWordsRate # wordsRate OR oldIdleRate # idleRate THEN GraphSet[ graph, oldWordsRate _ wordsRate, watchStats.cpuLoad _ 1 - (oldIdleRate _ idleRate)/(maxIdleRate*1.0), oldDiskPercent _ diskPercent]; IF container.wh > smallerOpenHeight THEN { <> SetLabel[diskPercentQueuedLabel, Real.RoundI[diskPercent*100.0]]; SetLabel[ diskActiveSecsLabel, (BasicTime.PulsesToMicroseconds[newActiveDiskPulses]+500000)/1000000]; SetLabel[ diskTotalSecsLabel, (BasicTime.PulsesToMicroseconds[newTotalDiskPulses]+500000)/1000000]; SetLabel[diskReadLabel, reads]; SetLabel[diskWriteLabel, writes]; SetLabel[diskReadPgsLabel, readPgs]; SetLabel[diskWritePgsLabel, writePgs]; <> SetLabel[vmFaultsLabel, VMStatistics.pageFaults]; SetLabel[vmReadOnlyLabel, VMStatistics.readOnlyPages]; SetLabel[vmPinnedPagesLabel, VMStatistics.pinnedPages]; SetLabel[vmCheckoutConflictsLabel, VMStatistics.checkoutConflicts]; <> SetLabel[rmAllocPassesLabel, VMStatistics.rmAllocPasses]; SetLabel[rmReclamationsLabel, VMStatistics.rmReclamations]; SetLabel[rmFreeListLabel, VMStatistics.rmFreeList]; SetLabel[rmOldCleanLabel, VMStatistics.rmOldClean]; SetLabel[rmNewCleanLabel, VMStatistics.rmNewClean]; SetLabel[rmDirtyLabel, VMStatistics.rmDirty]; <> SetLabel[rmCleanPassesLabel, VMStatistics.rmCleanPasses]; SetLabel[laundryWakeupsLabel, VMStatistics.laundryWakeups]; SetLabel[pagesCleanedLabel, VMStatistics.pagesCleaned]; SetLabel[panicLaundryWakeupsLabel, VMStatistics.panicLaundryWakeups]; SetLabel[pagesCleanedPanicLabel, VMStatistics.pagesCleanedPanic]; SetLabel[uselessLaundryWakeupsLabel, VMStatistics.uselessLaundryWakeups]; SetLabel[laundryCleanCallsLabel, VMStatistics.laundryCleanCalls]; <> SetLabel[swapInCallsLabel, VMStatistics.swapInCalls]; SetLabel[swapInVirtualRunsLabel, VMStatistics.swapInVirtualRuns]; SetLabel[swapInPhysicalRunsLabel, VMStatistics.swapInPhysicalRuns]; SetLabel[swapInPagesLabel, VMStatistics.swapInPages]; SetLabel[swapInAlreadyInLabel, VMStatistics.swapInAlreadyIn]; SetLabel[swapInNoReadLabel, VMStatistics.swapInNoRead]; SetLabel[swapInReadsLabel, VMStatistics.swapInReads]; SetLabel[swapInDirtyVictimsLabel, VMStatistics.swapInDirtyVictims]; SetLabel[swapInFailedToCleanVictimsLabel, VMStatistics.swapInFailedToCleanVictims]; {-- FileStats stuff data: FileStats.Data; data _ FileStats.GetData[open]; SetLabel[fsOpenCallsLabel, data.calls]; SetLabel[fsOpenPagesLabel, data.pages]; SetLabel[ fsOpenMSecsLabel, (BasicTime.PulsesToMicroseconds[data.pulses]+500)/1000]; data _ FileStats.GetData[create]; SetLabel[fsCreateCallsLabel, data.calls]; SetLabel[fsCreatePagesLabel, data.pages]; SetLabel[ fsCreateMSecsLabel, (BasicTime.PulsesToMicroseconds[data.pulses]+500)/1000]; data _ FileStats.GetData[delete]; SetLabel[fsDeleteCallsLabel, data.calls]; SetLabel[fsDeletePagesLabel, data.pages]; SetLabel[ fsDeleteMSecsLabel, (BasicTime.PulsesToMicroseconds[data.pulses]+500)/1000]; data _ FileStats.GetData[extend]; SetLabel[fsExtendCallsLabel, data.calls]; SetLabel[fsExtendPagesLabel, data.pages]; SetLabel[ fsExtendMSecsLabel, (BasicTime.PulsesToMicroseconds[data.pulses]+500)/1000]; data _ FileStats.GetData[contract]; SetLabel[fsContractCallsLabel, data.calls]; SetLabel[fsContractPagesLabel, data.pages]; SetLabel[ fsContractMSecsLabel, (BasicTime.PulsesToMicroseconds[data.pulses]+500)/1000]; data _ FileStats.GetData[read]; SetLabel[fsReadCallsLabel, data.calls]; SetLabel[fsReadPagesLabel, data.pages]; SetLabel[ fsReadMSecsLabel, (BasicTime.PulsesToMicroseconds[data.pulses]+500)/1000]; data _ FileStats.GetData[write]; SetLabel[fsWriteCallsLabel, data.calls]; SetLabel[fsWritePagesLabel, data.pages]; SetLabel[ fsWriteMSecsLabel, (BasicTime.PulsesToMicroseconds[data.pulses]+500)/1000]; }; }; <<>> <> vmWanted _ WaitForUpdate[]; ENDLOOP; GO TO done; EXITS done => {quit _ TRUE}; }; <<**** Initialization code ****>> TRUSTED { Process.Detach[FORK Watcher]; }; END.