-- File: PerfRoutines.mesa last edited by
-- Sandman on September 3, 1980 4:17 PM
-- Karlton on Jun 25, 1980 2:31 AM
DIRECTORY
BcdDefs USING [Base, CTIndex, MTIndex],
BcdOps USING [BcdBase, CTHandle, MTHandle, NameString],
DebugUsefulDefs USING [
GFHandle, Name, ShortCopyREAD, ShortCopyWRITE, ShortREAD, ShortWRITE],
DLoadState USING [
Acquire, AcquireBcd, Invalid, MapRealToConfig, Release, ReleaseBcd],
Event USING [AddNotifier, Item, Masks, Notifier],
FormSW USING [DisplayItem, EnumeratedNotifyProcType, NotifyProcType],
Gf USING [GFI, Handle, Original],
MachineDefs USING [ConfigIndex, GFHandle, GFTIndex, NullConfig],
MsgSW USING [Post],
PerfCommonOps USING [cmdSW, ConditionBreaks, herald, logSW, msgSW],
PerfOps USING [
AddHistogram, AddLeg, addMode, ClearTables, CollectNodes, DeleteHistogram,
DeleteLeg, Error, GetDeleteLeg, GetFromNode, GetToNode, monitorOn, ParamIndex,
PerfMessage, PrintHistogram, PrintLegTable, PrintNodeTable, PrintTables,
process, SetProcess, trackMode, ZeroCounts],
PerfPrivate USING [
HistBase, HistSpaceSize, LegTab, NodeTab, PCR, PerfControlRecord, ReadWrite,
VersionID],
Put USING [CR, Line, Text],
SDDefs USING [sBreak, SD, sPerfMonitor],
Storage USING [FreeWords, Words],
Strings USING [AppendSubString, SubStringDescriptor],
Time USING [Append, Current, Unpack],
UserInput USING [ResetUserAbort, userAbort],
Window USING [Handle];
PerfRoutines: PROGRAM
IMPORTS
DebugUsefulDefs, Event, FormSW, Gf, DLoadState, MsgSW, PerfCommonOps, PerfOps,
Put, Strings, Storage, Time, UserInput
EXPORTS PerfOps =
PUBLIC
BEGIN OPEN PerfOps, PerfPrivate, DebugUsefulDefs;
perfRecord: PerfControlRecord;
pCR: PCR ← @perfRecord;
nodeTab: POINTER TO NodeTab;
legTab: POINTER TO LegTab;
histBase: HistBase;
Table: TYPE = {hist, leg, node, pcr};
haveTable, dirtyTable: PACKED ARRAY Table OF BOOLEAN ←
[FALSE, FALSE, FALSE, FALSE];
GetHistBase: PROCEDURE [mode: ReadWrite] RETURNS [HistBase] =
BEGIN OPEN DebugUsefulDefs;
IF ~haveTable[hist] THEN
BEGIN
[] ← GetPCR[read];
histBase ← Storage.Words[HistSpaceSize];
ShortCopyREAD[to: histBase, from: pCR.histBase, nwords: HistSpaceSize];
haveTable[hist] ← TRUE;
END;
IF mode = write THEN dirtyTable[hist] ← TRUE;
RETURN[histBase];
END;
GetLegTable: PROCEDURE [mode: ReadWrite] RETURNS [POINTER TO LegTab] =
BEGIN OPEN DebugUsefulDefs;
IF ~haveTable[leg] THEN
BEGIN
[] ← GetPCR[read];
legTab ← Storage.Words[SIZE[LegTab]];
ShortCopyREAD[to: legTab, from: pCR.legTable, nwords: SIZE[LegTab]];
haveTable[leg] ← TRUE;
END;
IF mode = write THEN dirtyTable[leg] ← TRUE;
RETURN[legTab];
END;
GetNodeTable: PROCEDURE [mode: ReadWrite] RETURNS [POINTER TO NodeTab] =
BEGIN OPEN DebugUsefulDefs;
IF ~haveTable[node] THEN
BEGIN
[] ← GetPCR[read];
nodeTab ← Storage.Words[SIZE[NodeTab]];
ShortCopyREAD[to: nodeTab, from: pCR.nodeTable, nwords: SIZE[NodeTab]];
haveTable[node] ← TRUE;
END;
IF mode = write THEN dirtyTable[node] ← TRUE;
RETURN[nodeTab];
END;
GetPCR: PROCEDURE [mode: ReadWrite] RETURNS [PCR] =
BEGIN OPEN DebugUsefulDefs;
IF ~haveTable[pcr] THEN
BEGIN
perf: PCR ← ShortREAD[@SDDefs.SD[SDDefs.sPerfMonitor]];
ShortCopyREAD[to: pCR, from: perf, nwords: SIZE[PerfControlRecord]];
haveTable[pcr] ← TRUE;
END;
IF mode = write THEN dirtyTable[pcr] ← TRUE;
RETURN[pCR];
END;
TablesExist: PROCEDURE RETURNS [BOOLEAN] =
BEGIN
RETURN[DebugUsefulDefs.ShortREAD[@SDDefs.SD[SDDefs.sPerfMonitor]] # NIL];
END;
TablesCorrectVersion: PROCEDURE RETURNS [BOOLEAN] =
BEGIN RETURN[GetPCR[read].version = VersionID]; END;
PutTables: PRIVATE PROCEDURE [flush: BOOLEAN] =
BEGIN OPEN DebugUsefulDefs;
perf: PCR ← ShortREAD[@SDDefs.SD[SDDefs.sPerfMonitor]];
IF flush AND haveTable[pcr] AND dirtyTable[pcr] THEN
ShortCopyWRITE[to: perf, from: pCR, nwords: SIZE[PerfControlRecord]];
IF haveTable[node] THEN
BEGIN
IF flush AND dirtyTable[node] THEN
ShortCopyWRITE[to: pCR.nodeTable, from: nodeTab, nwords: SIZE[NodeTab]];
Storage.FreeWords[nodeTab];
END;
IF haveTable[leg] THEN
BEGIN
IF flush AND dirtyTable[leg] THEN
ShortCopyWRITE[to: pCR.legTable, from: legTab, nwords: SIZE[LegTab]];
Storage.FreeWords[legTab];
END;
IF haveTable[hist] THEN
BEGIN
IF flush AND dirtyTable[hist] THEN
ShortCopyWRITE[to: pCR.histBase, from: histBase, nwords: HistSpaceSize];
Storage.FreeWords[histBase];
END;
haveTable ← dirtyTable ← [FALSE, FALSE, FALSE, FALSE];
END;
TurnOn: PROCEDURE =
BEGIN OPEN DebugUsefulDefs, SDDefs;
[] ← GetPCR[write];
pCR.saveBreakHandler ← ShortREAD[@SD[sBreak]];
ShortWRITE[@SD[sBreak], pCR.self];
END;
TurnOff: PROCEDURE RETURNS [BOOLEAN] =
BEGIN OPEN DebugUsefulDefs, SDDefs;
[] ← GetPCR[write];
IF pCR.saveBreakHandler # NIL AND pCR.self = ShortREAD[@SD[sBreak]] THEN
BEGIN
ShortWRITE[@SD[sBreak], pCR.saveBreakHandler];
pCR.measuringNow ← FALSE;
RETURN[TRUE]
END;
RETURN[FALSE];
END;
NoContext: SIGNAL = CODE;
GetConfigAndModuleName: PROCEDURE [
frame: MachineDefs.GFHandle, config, module: STRING] =
BEGIN OPEN DLoadState;
bcd: BcdOps.BcdBase;
c: MachineDefs.ConfigIndex ← MachineDefs.NullConfig;
cgfi: MachineDefs.GFTIndex;
ssb: BcdOps.NameString;
ss: Strings.SubStringDescriptor;
[] ← Acquire[ ! Invalid => SIGNAL NoContext];
BEGIN
ENABLE UNWIND => Release[];
DebugUsefulDefs.Name[module, frame]; --now get config name
frame ← Gf.Original[frame];
[cgfi: cgfi, config: c] ← MapRealToConfig[Gf.GFI[frame]];
IF c # MachineDefs.NullConfig THEN
BEGIN OPEN BcdDefs;
bcd ← AcquireBcd[c];
ssb ← LOOPHOLE[bcd + bcd.ssOffset];
config.length ← 0;
IF bcd.nConfigs # 0 THEN
BEGIN
cth: BcdOps.CTHandle = @LOOPHOLE[bcd + bcd.ctOffset, Base][
FIRST[BcdDefs.CTIndex]];
ss ← [base: @ssb.string, offset: cth.name, length: ssb.size[cth.name]];
END
ELSE
BEGIN
mth: BcdOps.MTHandle = @LOOPHOLE[bcd + bcd.mtOffset, Base][
FIRST[BcdDefs.MTIndex]];
ss ← [base: @ssb.string, offset: mth.name, length: ssb.size[mth.name]];
END;
Strings.AppendSubString[config, @ss];
ReleaseBcd[bcd];
END
ELSE SIGNAL NoContext;
END; -- ELBANE
Release[];
RETURN;
END;
handle: Window.Handle ← PerfCommonOps.logSW;
PostError: PROCEDURE [error: Error] =
BEGIN
MsgSW.Post[
PerfCommonOps.msgSW,
SELECT error FROM
notOn => "!Please Start PerfMonitor and then try again"L,
goofUp =>
"!Goofed up PerfMonitor by use of Worry on/off during measurements"L,
syntaxError => "!Syntax Error in Input"L,
badLeg => "!Bad Leg Index Specified"L,
badChar => "!Illegal Character"L,
noLegRoom => "!No More Room in Leg Table"L,
badNode => "!Bad Node Index Specified"L,
version => "!PerfTool has Incorrect Version"L,
noContext => "!No Context"L,
badProcess => "!Invalid Process specified"L,
ENDCASE => "?"L];
END;
PutMessage: PROCEDURE [message: PerfMessage] =
BEGIN
Put.Text[
handle,
SELECT message FROM
totalTime => "Total Elapsed Time of Measurements = "L,
elapsedTime => "Elapsed Time less PerfMonitor Overhead = "L,
totalOverhead => "Total Overhead of PerfMonitor Breaks = "L,
nBreaks => "Total number of Perf Breaks handled = "L,
avgOverhead => "Average Overhead per Perf Break = "L,
percentInMont => "% of Total Time spent in PerfMonitor = "L,
tooSmall => "Too many breakpoints!"L,
aborted => "... aborted"L,
ENDCASE => "?"L];
IF message = aborted OR message = tooSmall THEN Put.CR[handle];
END;
WriteNodeTableHeader: PROCEDURE =
BEGIN
Put.Line[
handle,
" - - - - - - N O D E T A B L E C O N T E N T S - - - - - - - - - -"L];
IF UserInput.userAbort THEN RETURN;
Put.Line[handle, "Node Global Program Number of Config Module"L];
IF UserInput.userAbort THEN RETURN;
Put.Line[handle, " Id Frame Counter References Name Name"L];
IF UserInput.userAbort THEN RETURN;
Put.Line[handle, "---- ------ ------- ---------- -------- --------"L];
END;
WriteLegTableHeader: PROCEDURE =
BEGIN
Put.Line[
handle,
"- - - - - - - L E G T A B L E C O N T E N T S - - - - - - - - -"L];
IF UserInput.userAbort THEN RETURN;
Put.Line[
handle,
"Leg From To # of Times Total Time Average Time % of"L];
IF UserInput.userAbort THEN RETURN;
Put.Line[
handle,
"Id Node Node Referenced sec.msec:usec sec.msec:usec Time"L];
IF UserInput.userAbort THEN RETURN;
Put.Line[
handle,
"--- ---- ---- ---------- ------------- ------------- -----"L];
END;
PutHerald: PROCEDURE =
BEGIN OPEN Time;
s: STRING ← [22];
Put.Line[handle, PerfCommonOps.herald];
Append[s, Unpack[Current[]]];
s.length ← s.length - 3;
Put.Line[handle, s];
Put.CR[handle];
RETURN
END;
SetDefaults: PROCEDURE [index: ParamIndex] =
BEGIN
pcr: PCR ← GetPCR[write];
IF index # mon THEN
BEGIN
monitorOn ← FALSE;
FormSW.DisplayItem[PerfCommonOps.cmdSW, LOOPHOLE[ParamIndex[mon]]];
END;
IF index # track THEN
BEGIN
trackMode ← pcr.trackLeg ← all;
FormSW.DisplayItem[PerfCommonOps.cmdSW, LOOPHOLE[ParamIndex[track]]];
END;
IF index # add THEN
BEGIN
addMode ← pcr.addLeg ← none;
FormSW.DisplayItem[PerfCommonOps.cmdSW, LOOPHOLE[ParamIndex[add]]];
END;
IF index # setProcess THEN
BEGIN
IF process # NIL THEN process.length ← 0;
FormSW.DisplayItem[PerfCommonOps.cmdSW, LOOPHOLE[ParamIndex[process]]];
END;
pcr.newSession ← FALSE;
PutHerald[];
RETURN
END;
ParamNotify: FormSW.NotifyProcType =
BEGIN
MsgSW.Post[PerfCommonOps.msgSW, ""L];
IF ~TablesExist[] THEN GOTO noTables;
IF ~TablesCorrectVersion[] THEN GOTO badVersion;
[] ← GetPCR[read];
IF pCR.newSession THEN SetDefaults[LOOPHOLE[index, ParamIndex]];
SELECT LOOPHOLE[index, ParamIndex] FROM
mon => IF monitorOn THEN TurnOn[] ELSE IF ~TurnOff[] THEN PostError[goofUp];
collect => CollectNodes[];
init => ClearTables[];
zero => ZeroCounts[];
condition => PerfCommonOps.ConditionBreaks[];
printtables => PrintTables[];
printnodes => PrintNodeTable[];
printlegs => PrintLegTable[];
addleg => AddLeg[from: GetFromNode[], to: GetToNode[]];
delete => DeleteLeg[index: GetDeleteLeg[]];
setProcess => SetProcess[];
add => GetPCR[write].addLeg ← addMode;
track => GetPCR[write].trackLeg ← trackMode;
addhist => AddHistogram[];
delhist => DeleteHistogram[];
printhist => PrintHistogram[];
ENDCASE;
UserInput.ResetUserAbort[];
EXITS noTables => PostError[notOn]; badVersion => PostError[version];
END;
ParamEnumNotify: FormSW.EnumeratedNotifyProcType = {
ParamNotify[sw, item, index]};
Cleanup: Event.Notifier = {PutTables[why = resumeDebuggee]};
-- Mainline code
cleanupItem: Event.Item ←
[link:, eventMask: Event.Masks[resumeDebuggee] + Event.Masks[abortSession],
eventProc: Cleanup];
Event.AddNotifier[@cleanupItem];
END.