-- 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.