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 {
Find out if it is for the Cedar VM file.
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] => {
We believe that the boot file is the first we see.
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 {
we just passed over a free run of VM pages
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 {
the last run of VM pages was free
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;
};
};
At this point we have a leaf space, so add it to the counts.
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;
};
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;
build enclosing viewer
container ← Containers.Create[
info: [name: "Watch", iconic: TRUE, column: right, scrollable: FALSE]];
line 0: bar graphs
ViewerOps.RegisterViewerClass[$BarGraph, graphClass];
graph ← CreateGraph[];
line 1: mds, gfi, disk, freeVM
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];
line 2: gc interval, button & status
[] ← 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]];
};
line 3: sample button and CIFS status
[] ← 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];
set an aesthetically sized open window
newOpenHeight ← oldOpenHeight ← smallerOpenHeight ← nextY + gapY - 1;
ViewerOps.SetOpenHeight[container, oldOpenHeight];
line 4: other mapped VM stuff
mappedPagesLabel ← AddLabel["mapped", 5];
toBootLabel ← AddLabel["boot", 4];
anonPagesLabel ← AddLabel["anon", 4];
cedarVMLabel ← AddLabel["Cedar", 4];
inZonesLabel ← AddLabel["zones", 4, TRUE];
line 5: unmapped VM stuff
unmappedPagesLabel ← AddLabel["unmapped", 4];
unmappedFullLabel ← AddLabel["full", 4];
unmappedPartLabel ← AddLabel["part", 4];
unmappedMDSLabel ← AddLabel["mds", 2, TRUE];
line 6: RC table stats
usedNormalLabel ← AddLabel["normalRC", 5];
finalizeNormalLabel ← AddLabel["finalize", 4];
pinnedNormalLabel ← AddLabel["pinned", 4];
freeNormalLabel ← AddLabel["free", 5, TRUE];
line 7: RC table stats
usedOverflowLabel ← AddLabel["overflowRC", 5];
chainsOverflowLabel ← AddLabel["chains", 4];
freeOverflowLabel ← AddLabel["free", 5, TRUE];
biggerOpenHeight ← nextY + gapY - 1;
initialize measurments
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
Get the time delta
delta ← ShowTime.GetMark[] - mark;
deltaMillis ← (delta + 500) / 1000;
IF deltaMillis = 0 THEN LOOP;
mark ← mark + delta;
Update the idle rate data
idleRate ← (idleCount-lastIdle) / deltaMillis;
lastIdle ← idleCount;
IF idleRate > maxIdleRate
THEN
{ IF deltaMillis > 100 THEN maxIdleRate ← idleRate ELSE idleRate ← maxIdleRate };
Update the fault data
deltaFaults ← RTProcess.GetTotalPageFaults[] - faults;
faults ← faults + deltaFaults;
faultRate ← (deltaFaults * 1000 + 500) / deltaMillis;
Update the alloc data
deltaWords ← SafeStorage.NWordsAllocated[] - words;
words ← words + deltaWords;
wordsRate ← (deltaWords * 1000 + 500) / deltaMillis;
IF container.iconic
THEN {
The user really does not want to see the data now. We performed the above calculations just so we don't overflow various numbers if the user keeps this tool iconic for a long time.
Process.Pause[Process.SecondsToTicks[1]];
LOOP;
};
Sample the new numbers
newGFI ← CountGFI[];
newDiskReq ← DiskDriverSharedImpl.totalNumberOfRequests;
newDisk ← CountDisk[];
IF vmWanted
AND NOT container.iconic
THEN {
Calculate the stats for the VM usage (but only if they will be displayed)
[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[];
We also try to get RC table stats here, but only if they will be seen!
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]];
};
Update the display (only where necessary)
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];
Lastly, wait for the pause interval
vmWanted ← WaitForUpdate[];
ENDLOOP;
quit ← TRUE;
RTProcess.StopWatchingFaults[];
EXITS
done => {RTProcess.StopWatchingFaults[]};
};