ProcessWatchInstantaneously.Mesa
Spreitzer, April 22, 1986 6:12:06 pm PST
DIRECTORY BasicTime, Commander, Icons, Imager, ImagerBackdoor, ImagerColor, IO, MessageWindow, PrincOps, PrincOpsUtils, Process, ProcessWatch, ProcessWatchPrinting, Real, RealFns, Rope, TIPUser, ViewerClasses, ViewerOps;
ProcessWatchInstantaneously: CEDAR MONITOR
IMPORTS BasicTime, Commander, Icons, Imager, ImagerBackdoor, ImagerColor, IO, MessageWindow, PrincOpsUtils, Process, ProcessWatch, ProcessWatchPrinting, Real, RealFns, TIPUser, ViewerOps
= {
ROPE: TYPE = Rope.ROPE;
PsbIndex: TYPE = PrincOps.PsbIndex;
UsefulPsbIndex: TYPE = ProcessWatch.UsefulPsbIndex;
nUsefulPsbs: CARDINAL = ProcessWatch.nUsefulPsbs;
Viewer: TYPE = ViewerClasses.Viewer;
ReadyVector: TYPE = ProcessWatch.ReadyVector;
ProcessWatcher: TYPE = REF ProcessWatcherPrivate;
ProcessWatcherPrivate: TYPE = RECORD [
ch, cw, rows, cols, lastFullColumn, width, height, dx, dy, ox, oy: INT ← 0,
pds: ARRAY UsefulPsbIndex OF ProcessData ← ALL[[]]
];
ProcessData: TYPE = RECORD [
color: MyColor ← dormant,
lastTill: BasicTime.Pulses ← 0];
MyColor: TYPE = {active, recent, past, old, dormant};
colorCode: ARRAY MyColor OF Imager.ConstantColor ← [
active: Imager.white,
recent: ImagerColor.ColorFromRGB[[1.0, 1.0, 0]],
past: ImagerColor.ColorFromRGB[[1.0, 0, 0]],
old: ImagerColor.ColorFromRGB[[0.25, 0, 0.25]],
dormant: Imager.black
];
xor: Imager.Color = ImagerBackdoor.invert;
Million: LONG CARDINAL = 1000000;
DecayingColor: TYPE = MyColor[recent .. old];
colorPersistance: ARRAY DecayingColor OF BasicTime.Pulses ← [
recent: BasicTime.MicrosecondsToPulses[666*Million/10],
past: BasicTime.MicrosecondsToPulses[66*Million],
old: BasicTime.MicrosecondsToPulses[60*Million]
];
CreateCmd: PROC [cmd: Commander.Handle] RETURNS [result: REFNIL, msg: ROPENIL] --Commander.CommandProc-- = {
[] ← CreateProcessWatcher[[name: "Instantaneous Process Watcher"]];
};
CreateProcessWatcher: PROC [viewerData: ViewerClasses.ViewerRec ← [], paint: BOOLTRUE] RETURNS [pwv: Viewer] = {
pwv ← ViewerOps.CreateViewer[pwFlavor, viewerData, paint];
SetPWV[pwv];
};
pwFlavor: ATOM = $InstantaneousProcessWatcher;
pwClass: ViewerClasses.ViewerClass ← NEW [ViewerClasses.ViewerClassRec ← [
flavor: pwFlavor,
paint: PaintProcessWatcher,
init: InitProcessWatcher,
destroy: DestroyProcessWatcher,
tipTable: TIPUser.InstantiateNewTIPTable["ProcessWatcher.TIP"],
notify: NotifyProcessWatcher,
icon: Icons.NewIconFromFile["ProcessWatcher.icons", 0]
]];
gray: Imager.Color ← Imager.MakeGray[0.5];
lifetime: BasicTime.Pulses ← BasicTime.MicrosecondsToPulses[1000000];
paintTime: BasicTime.Pulses ← BasicTime.MicrosecondsToPulses[300000];
doGray: BOOLTRUE;
InitProcessWatcher: PROC [self: Viewer] --ViewerClasses.InitProc-- = {
pw: ProcessWatcher = NEW [ProcessWatcherPrivate ← []];
self.data ← pw;
};
DestroyProcessWatcher: PROC [self: Viewer] --ViewerClasses.DestroyProc-- = {
SetPWV[NIL];
};
counts: REF Counts ← NEW [Counts ← ALL[0]];
Counts: TYPE = ARRAY MyColor OF INT;
debug: BOOLFALSE;
CARD: TYPE = LONG CARDINAL;
PaintProcessWatcher: PROC [self: Viewer, context: Imager.Context, whatChanged: REF, clear: BOOL] RETURNS [quit: BOOLFALSE] --ViewerClasses.PaintProc-- = {
ENABLE UNWIND => painting ← FALSE;
pw: ProcessWatcher = NARROW[self.data];
now: BasicTime.Pulses = BasicTime.GetClockPulses[];
paintAllowance: BasicTime.Pulses = now + paintTime;
laters: ARRAY DecayingColor OF BasicTime.Pulses;
latest: BasicTime.Pulses;
reset: BOOL = lastPaint >= paintAllowance;
FOR dc: DecayingColor IN DecayingColor DO
laters[dc] ← now + colorPersistance[dc];
ENDLOOP;
latest ← laters[FIRST[DecayingColor]];
IF painting THEN RETURN;
painting ← TRUE;
IF whatChanged # $Sample OR pw.ch # self.ch OR pw.cw # self.cw OR reset THEN {
lastPaint ← now;
pw.ch ← self.ch;
pw.cw ← self.cw;
FOR side: INT ← Real.Fix[RealFns.SqRt[REAL[pw.ch]*REAL[pw.cw]]], side - 1 DO
IF side = 0 THEN {pw.rows ← pw.cols ← 16; EXIT};
pw.rows ← pw.ch/side;
pw.cols ← pw.cw/side;
WHILE (pw.rows-1) * pw.cols >= nUsefulPsbs DO
pw.rows ← pw.rows - 1;
ENDLOOP;
WHILE (pw.cols-1) * pw.rows >= nUsefulPsbs DO
pw.cols ← pw.cols - 1;
ENDLOOP;
IF pw.rows * pw.cols >= nUsefulPsbs THEN EXIT;
ENDLOOP;
pw.lastFullColumn ← nUsefulPsbs - (pw.rows-1)*pw.cols;
pw.dx ← pw.cw / pw.cols;
pw.dy ← pw.ch / pw.rows;
pw.width ← pw.dx * pw.cols;
pw.height ← pw.dy * pw.rows;
pw.ox ← (pw.cw - pw.width)/2;
pw.oy ← (pw.ch - pw.height)/2;
Imager.SetColor[context, colorCode[dormant]];
Imager.MaskRectangle[context, [0, 0, pw.cw, pw.ch]];
Imager.TranslateT[context, [pw.ox, pw.oy]];
Imager.SetColor[context, colorCode[active]];
FOR row: INT IN [0 .. pw.rows] DO
y: INT = row * pw.dy;
w: INT = IF row = pw.rows THEN pw.lastFullColumn*pw.dx ELSE pw.width;
Imager.MaskVector[context, [0, y], [w, y]];
ENDLOOP;
FOR col: INT IN [0 .. pw.cols] DO
x: INT = col * pw.dx;
h: INT = IF col > pw.lastFullColumn THEN pw.height-pw.dy ELSE pw.height;
Imager.MaskVector[context, [x, 0], [x, h]];
ENDLOOP;
FOR psbi: UsefulPsbIndex IN UsefulPsbIndex DO
IF reset THEN pw.pds[psbi].lastTill ← 0;
pw.pds[psbi].color ← dormant;
ENDLOOP;
}
ELSE Imager.TranslateT[context, [pw.ox, pw.oy]];
--now paint incrementally:--{
row, col: NAT ← 0;
lastPaint ← now;
FOR psbi: UsefulPsbIndex IN UsefulPsbIndex DO
ready: BOOL = displayedVectors[psbi];
pd: ProcessData = pw.pds[psbi];
PaintIt: PROC [mc: MyColor] = INLINE {
x: INT = col*pw.dx+1;
y: INT = row*pw.dy+1;
pw.pds[psbi].color ← mc;
IF debug THEN {
counts[mc] ← counts[mc] + 1;
Imager.SetColor[context, ImagerBackdoor.invert];
Imager.MaskRectangle[context, [x, y, pw.dx-1, pw.dy-1]];
};
Imager.SetColor[context, colorCode[mc]];
Imager.MaskRectangle[context, [x, y, pw.dx-1, pw.dy-1]];
};
IF ready THEN {
IF pd.color # active THEN PaintIt[active];
pw.pds[psbi].lastTill ← latest;
}
ELSE {
rightColor: MyColor ← dormant;
IF pd.lastTill > now THEN FOR dc: DecayingColor DECREASING IN DecayingColor DO
IF pd.lastTill <= laters[dc] THEN {
rightColor ← dc; EXIT;
};
ENDLOOP;
IF pd.color # rightColor THEN PaintIt[rightColor];
};
IF (col ← col + 1) = pw.cols THEN {col ← 0; row ← row + 1};
ENDLOOP;
};
painting ← FALSE;
};
lastPaint: BasicTime.Pulses ← 0;
painting: BOOLFALSE;
ReadPI: PROC RETURNS [pi: PsbIndex] = TRUSTED INLINE {
pi ← PrincOpsUtils.PsbHandleToIndex[PrincOpsUtils.ReadPSB[]]};
NotifyProcessWatcher: PROC [self: Viewer, input: LIST OF REF ANY] --ViewerClasses.NotifyProc-- = {
pw: ProcessWatcher = NARROW[self.data];
notifier: PsbIndex = ReadPI[];
who: UsefulPsbIndex ← 0;
valid: BOOLFALSE;
WHILE input # NIL DO
first: REF ANY = input.first;
input ← input.rest;
WITH first SELECT FROM
mc: TIPUser.TIPScreenCoords => {
y: INT = mc.mouseY - pw.oy;
x: INT = mc.mouseX - pw.ox;
row: INT = y / pw.dy;
col: INT = x / pw.dx;
index: INT = row * pw.cols + col;
valid ← y IN [0 .. pw.height) AND x IN [0 .. pw.width) AND (NOT (y >= pw.height - pw.dy AND x >= pw.lastFullColumn*pw.dx));
IF valid THEN who ← index;
};
a: ATOM => SELECT a FROM
$Select => {
MessageWindow.Append[
message: IF valid
THEN IO.PutFR["Process %g (%bB, %xH)%g", [cardinal[who]], [cardinal[who]], [cardinal[who]], [rope[IF notifier = who THEN " --- the notifier!" ELSE NIL]]]
ELSE "Out of range",
clearFirst: TRUE];
};
$ShowTop => {
IF valid THEN TRUSTED {Process.Detach[FORK ProcessWatchPrinting.ShowTop[who]]};
};
$ShowStack => {
IF valid THEN TRUSTED {Process.Detach[FORK ProcessWatchPrinting.ShowStack[who]]};
};
$Unselect => NULL;
ENDCASE => ERROR;
ENDCASE => ERROR;
ENDLOOP;
};
me: ProcessWatch.Consumer = [ConsumeReadyList];
pwv: Viewer ← NIL;
sample: CONDITION;
notedVectors, displayedVectors: ProcessWatch.ReadyVector;
SetPWV: ENTRY PROC [v: Viewer] = {
diff: BOOL = (pwv = NIL) # (v = NIL);
pwv ← v;
IF diff THEN {
IF pwv = NIL THEN ProcessWatch.RemoveConsumer[me] ELSE ProcessWatch.AddConsumer[me];
};
};
ConsumeReadyList: ENTRY PROC [REF ANY] = {
notedVectors ← ProcessWatch.readyVector;
BROADCAST sample;
};
PaintIt: PROC = {
Wait: ENTRY PROC RETURNS [v: Viewer] = {
DO
WAIT sample;
displayedVectors ← notedVectors;
IF pwv # NIL THEN RETURN [pwv];
ENDLOOP;
};
DO
ViewerOps.PaintViewer[Wait[], client, FALSE, $Sample];
ENDLOOP;
};
Start: PROC = TRUSTED {
ViewerOps.RegisterViewerClass[pwFlavor, pwClass];
Process.InitializeCondition[@sample, 0];
Process.DisableTimeout[@sample];
Process.Detach[FORK PaintIt[]];
Commander.Register["InstantaneousProcessWatcher", CreateCmd, "Create an Instantaneous Process Watcher"];
};
Start[];
}.