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;
Free line labels
diskLabel, gfiLabel, mdsLabel, freeVMLabel, maxFreeLabel: Label ← NIL;
FS watcher labels
readFSlabel, writeFSlabel, flushFSlabel: Label ← NIL;
NreadFSlabel, NwriteFSlabel, NflushFSlabel: Label ← NIL;
Disk read/write labels
diskPercentQueuedLabel, diskActiveSecsLabel, diskTotalSecsLabel: Label ← NIL;
diskReadLabel, diskWriteLabel, diskReadPgsLabel, diskWritePgsLabel: Label ← NIL;
VM labels
vmFaultsLabel, vmReadOnlyLabel: Label ← NIL;
vmPinnedPagesLabel, vmCheckoutConflictsLabel: Label ← NIL;
Replacement labels
rmAllocPassesLabel, rmReclamationsLabel: Label ← NIL;
rmFreeListLabel, rmOldCleanLabel, rmNewCleanLabel, rmDirtyLabel: Label ← NIL;
Laundry labels
rmCleanPassesLabel, laundryWakeupsLabel, pagesCleanedLabel: Label ← NIL;
panicLaundryWakeupsLabel, pagesCleanedPanicLabel: Label ← NIL;
uselessLaundryWakeupsLabel, laundryCleanCallsLabel: Label ← NIL;
SwapIn labels
swapInCallsLabel, swapInVirtualRunsLabel, swapInPhysicalRunsLabel: Label ← NIL;
swapInPagesLabel, swapInAlreadyInLabel: Label ← NIL;
swapInNoReadLabel, swapInReadsLabel: Label ← NIL;
swapInDirtyVictimsLabel, swapInFailedToCleanVictimsLabel: Label ← NIL;
FileStats labels
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]];
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
[] ← AddLabel["Free "];
diskLabel ← AddLabel["disk", 5];
gfiLabel ← AddLabel["gfi", 3];
mdsLabel ← AddLabel["mds", 3];
freeVMLabel ← AddLabel["VM", 5];
maxFreeLabel ← AddLabel["VM run", 5, TRUE];
line 2: gc interval, button & status
[] ← 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]];
};
line 3: sample button and FS status
[] ← 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];
set an aesthetically sized open window
newOpenHeight ← oldOpenHeight ← smallerOpenHeight ← nextY + gapY - 1;
ViewerOps.SetOpenHeight[container, oldOpenHeight];
Add labels below this line for the BIG size of Watch.
line 4: file being flushed
[] ← AddLabel["Flushing "];
flushFSlabel ← AddLabel[
"(FS file being flushed)", 0, TRUE, ViewerSpecs.openRightWidth];
Containers.ChildXBound[container, flushFSlabel];
line 5: file being stored
[] ← AddLabel["Storing "];
writeFSlabel ← AddLabel[
"(FS file being stored)", 0, TRUE, ViewerSpecs.openRightWidth];
Containers.ChildXBound[container, writeFSlabel];
line 6: FS counts
[] ← AddLabel["FS "];
NreadFSlabel ← AddLabel["fetches", 5];
NflushFSlabel ← AddLabel["flushes", 5];
NwriteFSlabel ← AddLabel["stores", 5, TRUE];
line 7: Disk stats
[] ← 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];
line 8: VM stats
[] ← AddLabel["VM "];
vmFaultsLabel ← AddLabel["faults", 7];
vmReadOnlyLabel ← AddLabel["readOnly", 5];
vmPinnedPagesLabel ← AddLabel["pinned", 5];
vmCheckoutConflictsLabel ← AddLabel["conflicts", 4, TRUE];
line 9: replacement stats
[] ← 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];
line 10: laundry stats
[] ← 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];
line 11: SwapIn stats
[] ← 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;
initialize measurments
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
Get the time delta
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;
Update the idle rate data
idleRate ← (watchStats.idleCount-lastIdle) / deltaMillis;
lastIdle ← watchStats.idleCount;
IF idleRate > maxIdleRate
THEN {
IF deltaMillis > 100 THEN maxIdleRate ← idleRate ELSE idleRate ← maxIdleRate;
};
Update the disk numbers
[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;
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;
};
millisSinceLastBigBang ← MIN[longPause, millisSinceLastBigBang + deltaMillis];
Sample the new numbers
{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 {
Calculate the stats for the VM usage (but only if they will be displayed)
millisSinceLastBigBang ← 0;
[] ←
VM.Allocate[pagesInPartition+pagesInPartition
! VM.CantAllocate => {maxFreeVM ← bestInterval.count; CONTINUE};
];
Calculate the # of GFIs free
newGFI ← CountGFI[];
};
};
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;
mds, gfi, disk, freeVM
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];
gc interval, button & status
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 {
Disk stats
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];
VM stats
SetLabel[vmFaultsLabel, VMStatistics.pageFaults];
SetLabel[vmReadOnlyLabel, VMStatistics.readOnlyPages];
SetLabel[vmPinnedPagesLabel, VMStatistics.pinnedPages];
SetLabel[vmCheckoutConflictsLabel, VMStatistics.checkoutConflicts];
Replacement stats
SetLabel[rmAllocPassesLabel, VMStatistics.rmAllocPasses];
SetLabel[rmReclamationsLabel, VMStatistics.rmReclamations];
SetLabel[rmFreeListLabel, VMStatistics.rmFreeList];
SetLabel[rmOldCleanLabel, VMStatistics.rmOldClean];
SetLabel[rmNewCleanLabel, VMStatistics.rmNewClean];
SetLabel[rmDirtyLabel, VMStatistics.rmDirty];
Laundry stats
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];
SwapIn stats
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];
};
};
Lastly, wait for the pause interval
vmWanted ← WaitForUpdate[];
ENDLOOP;
GO TO done;
EXITS done => {quit ← TRUE};
};