-- Watch.mesa; (Written by McGregor on 13-Oct-81 15:59:40) -- Edited by Paul Rovner on 14-Oct-81 9:34:11) -- Edited by Russ Atkinson on 22-Jan-82 10:43:27 -- Edited by McGregor on July 26, 1982 11:34 am -- Edited by MBrown on July 16, 1982 2:08 pm DIRECTORY Buttons: TYPE USING [Button, ButtonProc, Create, SetDisplayStyle], CIFSFeedback: TYPE USING [Register], Convert: TYPE USING [IntFromRope, ValueToRope], Graphics: TYPE USING [black, DrawBox, SetColor, SetStipple, white], Labels: TYPE USING [Create, Label, Set], Menus: TYPE USING [CreateMenu, InsertMenuEntry, Menu, MenuProc], PrincOpsRuntime, Process: TYPE USING [Detach, MsecToTicks, Pause, SecondsToTicks, SetPriority, Yield], Real USING [LargestNumber], Rope: TYPE USING [Cat, Concat, Length, Replace, ROPE, SkipTo], RTProcess: TYPE USING [GetTotalPageFaults, StartWatchingFaults], SafeStorage: TYPE USING [NWordsAllocated, SetCollectionInterval, WaitForCollectorDone, WaitForCollectorStart, ReclaimCollectibleObjects, ReclamationReason], SDDefs USING [SD, sGFTLength], ShowTime: TYPE USING [GetMark, Microseconds], Space, VFonts USING [StringWidth], ViewerMenus: TYPE USING [Close, Grow, Move], ViewerOps: TYPE USING [CreateViewer, DestroyViewer, RegisterViewerClass, PaintViewer, SetOpenHeight], ViewerClasses: TYPE, ViewerSpecs: TYPE, ViewerTools: TYPE USING [MakeNewTextViewer], Volume: TYPE USING [PageCount, systemID, GetAttributes]; Watch: MONITOR IMPORTS Buttons, CIFSFeedback, Convert, Graphics, Labels, Menus, Process, RTProcess, Rope, SafeStorage, ShowTime, Space, VFonts, ViewerMenus, ViewerOps, ViewerSpecs, ViewerTools, Volume = BEGIN OPEN Process, Rope, ViewerClasses, ViewerSpecs; entryHeight: CARDINAL = 15; heightSoFar: CARDINAL _ 0; container: ViewerClasses.Viewer _ NIL; ---- ---- ---- ---- ---- ---- ---- collectorArg: ViewerClasses.Viewer _ NIL; -- the text argument freeMdsGfi: ViewerClasses.Viewer _ NIL; totalFaultsLabel: ViewerClasses.Viewer _ NIL; cifsStatusLabel: ViewerClasses.Viewer _ NIL; mdsPages: CARDINAL _ 0; remGFI: CARDINAL _ 0; diskPages: Volume.PageCount _ 0; Decimal: PROC [int: INT] RETURNS [ROPE] = { RETURN[Convert.ValueToRope[[signed[int, 10]]]]}; SetCollectorInterval: Buttons.ButtonProc = { newInt: LONG INTEGER _ 16384; argRope: ROPE _ NARROW[collectorArg.class.get[collectorArg]]; newInt _ Convert.IntFromRope [argRope ! ANY => CONTINUE]; newInt _ MAX[newInt, 1000]; newInt _ MIN[newInt, 1000000]; argRope _ Decimal[newInt]; collectorArg.class.set[collectorArg, argRope, NOT container.iconic]; [] _ SafeStorage.SetCollectionInterval[newInt]; }; BuildCollectorIntervalEntry: PROC = { startVal: ROPE _ "16384"; cifsLabel: Labels.Label; faultsLabel: Labels.Label _ Labels.Create [info: [name: "faults ?????? ", wy: heightSoFar, wh: entryHeight, parent: container, border: FALSE], paint: FALSE]; mdsLabel: Labels.Label _ Labels.Create [info: [name: "mds ??? gfi ??? disk ????? ", wx: faultsLabel.wx + faultsLabel.ww, wy: heightSoFar, wh: entryHeight, parent: container, border: FALSE], paint: FALSE]; collectorButton: Buttons.Button _ Buttons.Create [info: [name: "GC interval _ ", wx: mdsLabel.wx + mdsLabel.ww, wy: heightSoFar, wh: entryHeight, parent: container, border: FALSE], fork: TRUE, proc: SetCollectorInterval, paint: FALSE]; collectorArg _ ViewerTools.MakeNewTextViewer [info: [parent: container, wx: collectorButton.wx + collectorButton.ww, wy: heightSoFar+2, ww: 100, wh: entryHeight, data: startVal, scrollable: FALSE, border: FALSE]]; heightSoFar _ collectorButton.wy + collectorButton.wh; freeMdsGfi _ mdsLabel; totalFaultsLabel _ faultsLabel; cifsLabel _ Labels.Create [info: [name: "", wy: heightSoFar, ww: VFonts.StringWidth["0"]*67, wh: entryHeight, parent: container, border: FALSE], paint: FALSE]; heightSoFar _ heightSoFar + cifsLabel.wh; cifsStatusLabel _ cifsLabel; }; ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- mark: ShowTime.Microseconds _ 0; words, ticks: LONG CARDINAL _ 0; maxTicks: REAL _ 0; minTicks: REAL _ Real.LargestNumber; PaintLabel: PROC = {ViewerOps.PaintViewer[cifsStatusLabel, all]}; UpdateCifsStatus: PROC [r: ROPE] = BEGIN -- the paint process is forked in case CIFS calls out from init'ing a Tioga viewer. IF r.Length[] = 0 THEN Labels.Set[cifsStatusLabel, "CIFS is idle", FALSE] ELSE Labels.Set[cifsStatusLabel, r, FALSE]; Process.Detach[FORK PaintLabel]; END; SampleProcess: PROC = BEGIN Increment: ENTRY PROC = INLINE {ticks _ ticks + 1}; -- just sits there counting as fast as it can Process.SetPriority[LOOPHOLE[0]]; -- run only when nothing else wants to UNTIL quit DO Process.Yield[]; Increment[]; ENDLOOP; -- forever END; UpdateThingsPerSecond: PROC = { nextWords: LONG CARDINAL; nextMark: ShowTime.Microseconds; faults, numFaults: LONG CARDINAL _ 0; deltaTime, deltaWords, deltaFaults, realTicks: REAL; pause: CARDINAL _ 5; -- seconds between updates Inner: ENTRY PROC = { -- this proc determines words/sec, faults/sec for the graphs -- and the remaining mds pages and gfi slots msg: ROPE _ NIL; insertNum: PROC [num: INT] = { pos: INT _ msg.SkipTo[0, "?"]; msg _ msg.Replace[pos, 1, Convert.ValueToRope[[signed[num]]]]}; IF quit THEN RETURN; nextMark _ ShowTime.GetMark[]; deltaTime _ (nextMark - mark)*1.0E-6; nextWords _ SafeStorage.NWordsAllocated[]; deltaWords _ nextWords - words; numFaults _ RTProcess.GetTotalPageFaults[]; deltaFaults _ numFaults - faults; realTicks _ ticks/deltaTime; maxTicks _ MAX[realTicks, maxTicks]; minTicks _ MIN[realTicks, minTicks]; GraphSet[gcCounter, deltaWords/deltaTime, IF maxTicks=minTicks THEN 0 ELSE 1-(realTicks-minTicks)/(maxTicks-minTicks), deltaFaults/deltaTime]; ticks _ 0; {newMdsPages: CARDINAL _ 0; newRemGFI: CARDINAL _ 0; newDiskPages: Volume.PageCount _ Volume.GetAttributes[Volume.systemID].freePageCount; firstMdsPage: CARDINAL _ Space.VMPageNumber[Space.mds]; FOR page: CARDINAL IN [firstMdsPage..firstMdsPage + 256) DO IF Space.GetHandle[page] = Space.mds THEN newMdsPages _ newMdsPages + 1; ENDLOOP; FOR i: CARDINAL DECREASING IN [1..SDDefs.SD[SDDefs.sGFTLength]) DO item: PrincOpsRuntime.GFTItem _ PrincOpsRuntime.GFT[i]; IF item.data # 0 THEN EXIT; newRemGFI _ newRemGFI + 1; ENDLOOP; IF newMdsPages # mdsPages OR newRemGFI # remGFI OR newDiskPages # diskPages THEN {msg _ "mds ? gfi ? disk ? "; insertNum[mdsPages _ newMdsPages]; insertNum[remGFI _ newRemGFI]; insertNum[diskPages _ newDiskPages]; Labels.Set[freeMdsGfi, msg, TRUE]; }; IF numFaults # faults THEN {msg _ "faults ?"; insertNum[LOOPHOLE[(faults _ numFaults), INT]]; Labels.Set[totalFaultsLabel, msg, TRUE]; }; }; words _ nextWords; mark _ nextMark; faults _ numFaults; }; labelSep: CARDINAL = 14; W2: PROC [r: ROPE] RETURNS [INTEGER] = INLINE {RETURN[VFonts.StringWidth[r]/2]}; gcLabel: Labels.Label _ Labels.Create [info: [name: "Words/Sec ", parent: container, wy: heightSoFar, wh: entryHeight, border: FALSE], paint: FALSE]; lLabel: Labels.Label _ Labels.Create [info: [name: "CPU Load ", parent: container, wy: heightSoFar+gcLabel.wh-1, wh: entryHeight, border: FALSE], paint: FALSE]; fLabel: Labels.Label _ Labels.Create [info: [name: "Faults/Sec ", parent: container, wy: heightSoFar+labelSep+entryHeight, wh: entryHeight, border: FALSE], paint: FALSE]; xTemp: CARDINAL _ MAX[gcLabel.ww, fLabel.ww] + 10; gcCounter: ViewerClasses.Viewer _ ViewerOps.CreateViewer [flavor: $BarGraph, info: [parent: container, wx: xTemp, wy: heightSoFar + labelSep, ww: openRightWidth - xTemp - 5, wh: 17, data: NEW[GraphDataRec _ [[fullScale: 5], [fullScale: -1], [fullScale: 2]]]], paint: FALSE]; xTemp _ gcCounter.ww/5; [] _ Labels.Create [info: [name: "1", parent: container, wx: gcCounter.wx - W2["1"], wy: heightSoFar, wh: entryHeight, border: FALSE], paint: FALSE]; [] _ Labels.Create [info: [name: "10", parent: container, wx: gcCounter.wx + xTemp - W2["10"], wy: heightSoFar, wh: entryHeight, border: FALSE], paint: FALSE]; [] _ Labels.Create [info: [name: "100", parent: container, wx: gcCounter.wx + 2*xTemp - W2["100"], wy: heightSoFar, wh: entryHeight, border: FALSE], paint: FALSE]; [] _ Labels.Create [info: [name: "1000", parent: container, wx: gcCounter.wx + 3*xTemp - W2["1000"], wy: heightSoFar, wh: entryHeight, border: FALSE], paint: FALSE]; [] _ Labels.Create [info: [name: "10000", parent: container, wx: gcCounter.wx + 4*xTemp - W2["10000"], wy: heightSoFar, wh: entryHeight, border: FALSE], paint: FALSE]; heightSoFar _ heightSoFar + labelSep + entryHeight; xTemp _ gcCounter.ww/4; [] _ Labels.Create [info: [name: "1", parent: container, wx: gcCounter.wx - W2["1"], wy: heightSoFar, wh: entryHeight, border: FALSE], paint: FALSE]; [] _ Labels.Create [info: [name: "3", parent: container, wx: gcCounter.wx + xTemp - W2["3"], wy: heightSoFar, wh: entryHeight, border: FALSE], paint: FALSE]; [] _ Labels.Create [info: [name: "10", parent: container, wx: gcCounter.wx + xTemp*2 - W2["10"], wy: heightSoFar, border: FALSE, wh: entryHeight], paint: FALSE]; [] _ Labels.Create [info: [name: "30", parent: container, wx: gcCounter.wx + xTemp*3 - W2["30"], wy: heightSoFar, wh: entryHeight, border: FALSE], paint: FALSE]; heightSoFar _ fLabel.wy + fLabel.wh - 1; words _ SafeStorage.NWordsAllocated[]; mark _ ShowTime.GetMark[]; waitingBuild _ FALSE; WHILE ~start DO Process.Pause[Process.MsecToTicks[200]]; ENDLOOP; WHILE NOT quit DO Pause[SecondsToTicks[pause]]; Inner[]; ENDLOOP }; ---- ---- ---- ---- ---- ---- ---- -- Create a bar-graph viewer class 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]; GraphPaint: ViewerClasses.PaintProc = { OPEN Graphics; myGrey: CARDINAL = 122645B; data: GraphData _ NARROW[self.data]; IF whatChanged = NIL THEN data.bottom.updateHint _ data.middle.updateHint _ data.top.updateHint _ bigger; IF data.top.updateHint = bigger THEN {SetStipple[context, myGrey]; DrawBox[context, [0, 2*self.ch/3, data.top.value, self.ch]]} ELSE IF data.top.updateHint = smaller THEN {SetColor[context, white]; DrawBox[context, [data.top.value, 2*self.ch/3, self.cw, self.ch]]}; IF data.middle.updateHint = bigger THEN {SetStipple[context, myGrey]; DrawBox[context, [0, self.ch/3, data.middle.value, 2*self.ch/3]]} ELSE IF data.middle.updateHint = smaller THEN {SetColor[context, white]; DrawBox[context, [data.middle.value, self.ch/3, self.cw, 2*self.ch/3]]}; IF data.bottom.updateHint = bigger THEN {SetStipple[context, myGrey]; DrawBox[context, [0, 0, data.bottom.value, self.ch/3]]} ELSE IF data.bottom.updateHint = smaller THEN {SetColor[context, white]; DrawBox[context, [data.bottom.value, 0, self.cw, self.ch/3]]}; SetColor[context, black] }; Log10: --Fast-- PROC [x: REAL] RETURNS [lx: REAL] = { -- truncated for values of [1..inf), 3-4 good digits -- algorithm from Abramowitz: Handbook of Math Functions, p. 68 sqrt10: REAL = 3.162278; t: REAL; lx _ 0; WHILE x > 10 DO x _ x/10; lx _ lx + 1 ENDLOOP; -- scale to [1..10] IF x > sqrt10 THEN {x _ x/sqrt10; lx _ lx + 0.5}; -- scale to [1..1/sqrt10] -- magic cubic approximation t _ (x - 1)/(x + 1); lx _ lx + 0.86304*t + 0.36415*(t*t*t) }; -- use this routine to set the bar graph to new values GraphSet: PROC [graph: ViewerClasses.Viewer, t, m, b: REAL] = { tempR: REAL; myData: GraphData _ NARROW[graph.data]; 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 ViewerOps.PaintViewer[graph, client, FALSE, $Update] }; ---- ---- ---- ---- ---- ---- ---- CauseGCHit: Buttons.ButtonProc = { Buttons.SetDisplayStyle[viewer, $BlackOnGrey]; SafeStorage.ReclaimCollectibleObjects[TRUE, ~redButton]; Buttons.SetDisplayStyle[viewer, $BlackOnWhite]; }; CollectorWatcher: PROC = { active: ROPE = "ACTIVE: "; inactive: ROPE = "inactive."; collectorStatusLabel: Buttons.Button _ Buttons.Create [info: [name: "GC", wy: heightSoFar, wh: entryHeight, parent: container, border: FALSE], fork: TRUE, proc: CauseGCHit, paint: FALSE]; collectorStatus: Labels.Label _ Labels.Create [info: [name: inactive, parent: container, wx: collectorStatusLabel.wx + collectorStatusLabel.ww, wy: heightSoFar, ww: openRightWidth, wh: entryHeight, border: FALSE], paint: FALSE]; SetCollectorStatus: ENTRY PROC [status: ROPE] = { IF NOT quit THEN Labels.Set[collectorStatus, status, NOT container.iconic] }; heightSoFar _ collectorStatusLabel.wy + collectorStatusLabel.wh; waitingBuild _ FALSE; 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; SetCollectorStatus[Rope.Concat[active, cReasons[r]]]; [incarnation: GCnumber, reason: r, wordsReclaimed: wrds, objectsReclaimed: objs] _ SafeStorage.WaitForCollectorDone[]; IF quit THEN EXIT; msg _ msg.Cat [" (GC#", Decimal[GCnumber], " got ", Decimal[LOOPHOLE[wrds]].Concat[" words, "], Decimal[LOOPHOLE[objs]].Concat[" objs)"]]; SetCollectorStatus[msg] ENDLOOP }; ---- ---- ---- ---- ---- ---- ---- quit: BOOLEAN _ FALSE; -- watched by various process to quit waitingBuild, start: BOOL _ FALSE; -- change flags for builders (Who did this crock? -SM) MyDestroy: ENTRY Menus.MenuProc = { CIFSFeedback.Register[NIL]; quit _ TRUE; ViewerOps.DestroyViewer[viewer] }; ---- ---- ---- ---- ---- ---- ---- Builder: PROC = { graphClass: ViewerClasses.ViewerClass _ NEW[ViewerClasses.ViewerClassRec _ [paint: GraphPaint]]; watcherMenu: Menus.Menu _ Menus.CreateMenu[]; ViewerOps.RegisterViewerClass[$BarGraph, graphClass]; Menus.InsertMenuEntry[watcherMenu, "Destroy", MyDestroy]; Menus.InsertMenuEntry[watcherMenu, "<-->", ViewerMenus.Move]; Menus.InsertMenuEntry[watcherMenu, "Grow", ViewerMenus.Grow]; Menus.InsertMenuEntry[watcherMenu, "Close", ViewerMenus.Close]; -- build enclosing viewer container _ ViewerOps.CreateViewer[flavor: $Container, info: [name: "Watch", column: right, menu: watcherMenu, scrollable: FALSE]]; waitingBuild _ TRUE; Detach[FORK SampleProcess[]]; Detach[FORK UpdateThingsPerSecond[]]; WHILE waitingBuild DO Process.Pause[Process.MsecToTicks[200]]; ENDLOOP; waitingBuild _ TRUE; heightSoFar _ heightSoFar + 1; Detach[FORK CollectorWatcher]; WHILE waitingBuild DO Process.Pause[Process.MsecToTicks[200]]; ENDLOOP; BuildCollectorIntervalEntry[]; start _ TRUE; UpdateCifsStatus[""]; -- set an aesthetically sized open window ViewerOps.SetOpenHeight[container, heightSoFar + 3]; IF NOT container.iconic THEN ViewerOps.PaintViewer[container, all]; CIFSFeedback.Register[UpdateCifsStatus]; RTProcess.StartWatchingFaults[]}; Process.Detach[FORK Builder]; END. Ê÷– "Mesa" style˜IprocšÎÏcùœÏk œ žœžœ@žœžœžœžœ)žœžœ;žœžœ!žœžœUžœžœKžœžœžœ žœžœžœ<žœžœšžœžœžœžœ-žœžœžœ$žœžœhžœžœžœžœ žœžœ/žœžœÍžœžœ>žœžœ.žœœœœœœœœ)žœœ%žœ-žœ,žœžœžœ,Ïnœžœžœžœžœ žœižœžœžœžœlžœžœžœžœfžœVŸœžœžœêžœžœýžœžœõžœžœ9žœ‘žœžœËžœžœ^œœœœœœœœœœœœœœ6žœžœžœžœŸ œžœ2ŸœžœžœžœTœžœžœ-žœžœ žœžœžœŸ œžœžœŸ œžœžœžœ.œžœ'œžœžœžœ œžœŸœžœžœžœ@žœžœ:žœžœœŸœžœžœ =œ-œ žœžœžœžœžœjžœžœžœ¾žœ(žœNžœžœžœsžœžœxžœ*žœžœžœ$žœ žœ#žœ9žœ žœžœž œžœ žœžœ=žœžœžœžœ3žœ žœžœžœ#žœØžœžœžœ3žœžœ1žœžœ Ÿœžœžœžœžœžœžœ°žœ žœ£žœ žœ®žœ žœžœžœûžœVžœ´žœ žœ¡žœ žœ¥žœ žœ©žœ žœ«žœ žœížœ žœ¡žœ žœ’žœžœ£žœ žœ‘žœžœžœ*žœžœžœžœ<žœœœœœœœœ#œžœžœžœžœžœœ;žœ3œžœ-žœžœVžœžœ"žœžœžœžœ^žœ&žœyžœ žœžœ€žœ)žœ~žœ žœ"žœ…žœ)žœtžœ žœ"žœ¡Ÿœœžœžœžœžœ 5œ@œ žœžœžœžœ$žœœžœ žœ%œœQ7œŸœžœ(žœžœžœžœžœžœJžœžœ žœžœžœ žœ3žœžœžœPžœžœ žœžœžœ žœ6žœžœžœPžœžœ žœžœžœ žœ.žœžœžœ.žœœœœœœœœ…žœOŸœžœžœžœÓžœžœ/žœ žœžœŸœžœžœ žœ žœžœžœ/žœtžœžœžœžœžœžœžœäžœžœžœ žœVžœžœžœÍžœžœžœ`žœ2žœ@žœœœœœœœœ žœžœ&œžœžœ7œžœ?žœ0œœœœœœœŸœžœ8žœ¹œ„žœžœ žœžœžœžœ*žœžœ1žœžœžœ*žœ1žœ!*œ>žœžœžœžœžœ˜ÂŽ—…—GDNA