davet@oakhill.UUCP (Dave Trissel) (11/20/85)
The following program installs a trace routine and instruction frequency table. It can write the table out in a compressed format on the disk for later evaluation (see comments indicating compressed format.) -- Dave Trissel Motorola Semiconductor Inc., Austin, Texas {ihnp4,seismo}!ut-sally!oakhill!davet ; ***************** PROFILE ********************** ; Program to collect 68k instruction counts by dynamic frequency ; D3-D6/A2-A6 safe (A5 reserved) include QuickEquX.D include SysEquX.D include ToolEquX.D include MacTraps.D ; following SFPutFile macro system copied from PackMacs.txt .MACRO _SFPutFile _PackCall #SFPutFile,_Pack3 .ENDM .MACRO _PackCall MOVE.W %1,-(SP) %2 .ENDM sfPutFile EQU 1 ;Equates dupFNErr equ -48 ;(From SysErr.Txt) File already exists Aline equ 40 ;68k a-line vector Trace equ 36 ;68k trace vector inKey equ $13243546 ;key indicating table installed ; QDstore := NewPtr (Size):Ptr Get nonreloc memory for Quickdraw area Start MOVE.L #grafSize,D0 ;size _NewPtr LEA QDstore,A1 ;where to store MOVE.L A0,(A1) ; remember it PEA grafSize-4(A0) ;Point to it ;PROCEDURE InitGraf (globalPtr: QDPtr); _InitGraf ;Init Quickdraw _InitFonts ;Init Font Manager _InitWindows ;Init Window Manager _InitMenus ;Init Menu Manager ; InitDialogs (restartProc: ProcPtr); pea Start ;Restart if Store Table into File error _InitDialogs ;Init Dialog Manager _TEInit ;Init Text Edit _InitCursor ;init cursor ; FlushEvents(everyEvent,0) move.l #$0000FFFF,D0 ;clear all events _FlushEvents ; Setup Apple Menu ; NewMenu(1,'Apple'): Handle SUB #4,SP ;return parm MOVE #1,-(SP) ;column PEA MenT1 ;Apple symbol title _NewMenu ;_NewMenu LEA Men1Hndl,A2 ;store handle MOVE.L (SP)+,(A2) ; here ; AppendMenu(Menuhndl,'About...;(-;Desk Accs') MOVE.L (A2),-(SP) ;pass handle PEA 'Profile - by Trissel;(-;Do not run with;Macsbug or Switcher;(-' ;about and null line _AppendMenu ;_AppendMenu ; AddResMenu(MenuHndl,Type); {add desktop stuff} MOVE.L (A2),-(SP) ;pass handle MOVE.L #'DRVR',-(SP) ;type name _AddResMenu ;_AddResMenu ; InsertMenu(MenuHndl,beforeID); MOVE.L (A2),-(SP) ;menu handle CLR -(SP) ;at front _InsertMenu ;_InsertMenu ;setup File menu ; NewMenu(2,'File'):MenHndl; SUB #4,SP ;parm return area MOVE #2,-(SP) ;menu id PEA 'File' ;title _NewMenu ;_NewMenu LEA Men2Hndl,A2 ;handle area MOVE.L (SP)+,(A2) ; stored here move.l BufPtr,A0 ;? is table already installed cmp.l #inkey,(A0) beq.s enough ;br if so, no need to check ;If not enough memory or running switcher only allow a quit ; MaxMem(VAR grow:Size):Size; {return zone free space and max growth} _MaxMem cmp.l #$40000,A0 ;? at least 256k available for growth bhi.s enough ;yes ; AppendMenu(MenuHndl,'Items...'); MOVE.L (A2),-(SP) ;menu handle PEA '(Store Table...;Quit - Not Enough Memory or Switcher Running' _AppendMenu ;_AppendMenu ; InsertMenu(MenuHndl,Pos); MOVE.L (A2),-(SP) ;menu handle CLR -(SP) ;append _InsertMenu ; DisableItem(MenuHandle;item); { disable entire Apple menu } move.l men1hndl,-(SP) ;menu handle clr.w -(SP) ;all items _DisableItem ; DrawMenuBar; _DrawMenuBar bra Event ;only allow a quit ; AppendMenu(MenuHndl,'Items...'); enough MOVE.L (A2),-(SP) ;menu handle PEA 'Store Table ...;Quit' ;list _AppendMenu ;_AppendMenu ; InsertMenu(MenuHndl,Pos); MOVE.L (A2),-(SP) ;menu handle CLR -(SP) ;append _InsertMenu ;install Control menu ; NewMenu(3,'Control'):MenHndl; SUB #4,SP ;parm return area MOVE #3,-(SP) ;menu id PEA 'Control' ;title _NewMenu ;_NewMenu LEA Men3Hndl,A2 ;handle area MOVE.L (SP)+,(A2) ; stored here ; AppendMenu(MenuHndl,'Items...'); MOVE.L (A2),-(SP) ;menu handle PEA 'Install Table;Reset Table' ;list _AppendMenu ;_AppendMenu ; InsertMenu(MenuHndl,Pos); MOVE.L (A2),-(SP) ;menu handle CLR -(SP) ;append _InsertMenu ; DrawMenuBar; _DrawMenuBar ; Activate and Deactive Menues according to table status. setmenu ; SetItem (MenuHandle;item;string); {Set to "Quit"} move.l men2hndl,-(SP) ;menu handle move.w #2,-(SP) ;second item pea 'Quit' ;title _SetItem move.l BufPtr,A0 ;find top of memory cmp.l #inKey,(A0) ;? table been installed beq.s Tablein ;yes, continue ; table not installed ; SetItem (MenuHandle;item;string); {Set to "Install Table"} move.l men3hndl,-(SP) ;menu handle move.w #1,-(SP) ;first item pea 'Install Table' ;title _SetItem notready ; DisableItem(MenuHandle;item); { disable Store Table... } move.l men2hndl,-(SP) ;menu handle move.w #1,-(SP) ;first item [Store Table...] _DisableItem ; DisableItem(MenuHandle;item); {Disable Reset menu} move.l men3hndl,-(SP) ;menu handle move.w #2,-(SP) ;second item (Reset Table) _DisableItem bra.s Event ;Table is in so set "Remove Table" and highlight Save and Reset Tablein ; SetItem (MenuHandle;item;string); {Set to "Remove Table"} move.l men3hndl,-(SP) ;menu handle move.w #1,-(SP) ;first item pea 'Remove Table' ;title _SetItem ; EnableItem(MenuHandle;item); {Enable Reset menu} move.l men3hndl,-(SP) ;menu handle move.w #2,-(SP) ;second item (Reset Table) _EnableItem ; EnableItem(MenuHandle;item); {Enable Store Table...} move.l men2hndl,-(SP) ;menu handle move.w #1,-(SP) ;second item (Reset Table) _EnableItem move.l BufPtr,A0 ;reload stub base tst.b flag-stub(A0) ;? Table have data bpl.s Event ;yes, all set ; SetItem (MenuHandle;item;string); {Set to "Quit - Will Profile"} move.l men2hndl,-(SP) ;menu handle move.w #2,-(SP) ;second item pea 'Quit and Profile Next Application' ;title _SetItem bra notready ;and reset reset and store ;---MAIN EVENT LOOP--- Event _SystemTask ;allow timed events ; _GetNextEvent(Mask,Var Eventrec):ours:boolean SUB #2,SP ;boolean return MOVE #$FFFF,-(SP) ;all events PEA EvRecord ;event record _GetNextEvent TST.B (SP)+ ;? for us BEQ Event ;loop if not MOVE Evntype,D0 ;get type BEQ Event ;ignore if null CMP #mButDwnEvt,D0 ;? mousedown 1 BEQ MouseDwn ;br if so BRA Event ;ignore all else ;Mouse is down ; _FindWindow(Mousepos:point,VAR Window):where:int MouseDwn SUB #2,SP ;int return MOVE.L EvMpos,-(SP) ;Mouse Position PEA Windparm ;Window returned _FindWindow MOVE (SP)+,D0 ;get where CMP #inMenuBar,D0 ;? Menu Bar 1 BEQ inMenu ;br if so CMP #inSysWindow,D0 ;? System Window 2 BEQ inSystem ;br if so BRA Event ;ignore all others ;in a system window ; _SystemClick(Event,Window); inSystem PEA EvRecord ;pass event record MOVE.L Windparm,-(SP) ;pass window involved _SystemClick BRA Event ;and continue ;Click in a Menu ; _MenuSelect(Mousepos):Biresult inMenu SUB #4,SP ;Lint return MOVE.L EvMpos,-(SP) ;Mouse position _MenuSelect MOVE (SP)+,D3 ;Menu number MOVE (SP)+,D4 ;Menu item CMP #1,D3 ;? Apple Menu BEQ.s Applemenu ;br if so CMP #2,D3 ;? File Menu BEQ.s Filemenu ;br if so cmp #3,D3 ;? Control Menu beq Contmenu ;br if so BRA Event ;MENU=ID=0 no menu picked Applemenu CMP #1,D4 ;? About... BEQ hilite ;br if so ;Must be Desk Accessary ; _GetItem(Menuhndl,item,VAR chars); isDA MOVE.L Men1Hndl,-(SP) ;Apple Menu handle MOVE D4,-(SP) ;Menu item PEA Deskname ;return area _GetItem ; _OpenDeskAcc(Name:str255):resultint; SUB #2,SP ;result PEA Deskname ;and name _OpenDeskAcc ADD #2,SP ;throw away result bra hilite ;unhilite menues ;File menu hit Filemenu cmp.w #1,D4 ;Store Table beq.s store ;yes cmp.w #2,D4 ;Quit beq.s quit ;must be quit bra hilite ;cannot not happen ;Store Table... store ; SFPutFile(where;prompt;origName;dlgHook;VAR reply); move.w #80,-(SP) move.w #100,-(SP) ;point pea 'Save table as:' ;prompt pea '' ;no original name pea 0 ;use standard dialog box pea SFReply ;reply record _SFPutFile ;check if cancel given move.b good,D0 ;? OK beq.s hilite ;ignore output if CANCEL bsr createfile ;call create subroutine bra.s hilite ;now continue ;Continue menu Contmenu cmp #1,D4 ;Install or Remove table beq.s change ;yes cmp #2,D4 ;reset ? beq.s doreset ;br if so bra.s hilite ;can't happen ;Install or remove change move.l BufPtr,A0 ;install or remove cmp.l #inKey,(A0) ;? is this our table beq.s remove ;yes, remove it bsr.s install ;install table bra.s hilite ;clear up menu ;remove the table remove move.l StoBufPtr-stub(A0),BufPtr ; replace old top of memory ;restore current values of A-LINE and TRACE exceptions move.l StoAline-stub(A0),Aline move.l StoTrace-stub(A0),Trace bra.s hilite ;hilite menu back ;Reset menu doreset move.l BufPtr,A0 ;prepare table to be reused st.b flag-stub(A0) ;set to -1 hilite ; _HiLiteMenu(0) CLR -(SP) ;clear any hilighted menu _HiLiteMenu bra setmenu ;go reset-up menues ; TERMINATE Quit ; DisposMenu(Menuhndl); MOVE.L Men1Hndl,-(SP) ;Apple menu _DisposMenu MOVE.L Men2Hndl,-(SP) ;File menu _DisposMenu MOVE.L Men3Hndl,-(SP) ;Control menu _DisposMenu ; DisposPtr (QDstore); {Free QD area} MOVE.L QDstore,A0 ;load Ptr _DisposPtr ; Exit to shell _exitToShell ; **** Install The Table Subroutine **** ; allocate a 64K 24-bit entry table (3 X 64k = 192K) Install move.l A0,D0 ;get current top of memory sub.l #$30100,D0 ;room for 64k entries and 256 byte stub and.w #$F000,D0 ;insure 2k boundary move.l D0,A1 ;base it lea StoBufPtr,A2 ;store position move.l A0,0(A2) ;remember old value move.l A1,BufPtr ;change Macintosh top memory limit ;copy over current values of A-LINE and TRACE exceptions lea StoAline,A6 move.l Aline,(A6) lea StoTrace,A6 move.l Trace,(A6) ; move in code and header move.w #$256-1,D0 ;len-1 move.l A1,A3 ;copy source lea stub,A2 ;start area mvloop move.b (A2)+,(A3)+ ;next byte dbra D0,mvloop ;loop till done ;install our own A-line and trace lea StAline-Stub(A1),A2 ; Aline entry point move.l A2,Aline ;replace A-LINE lea StTrace-Stub(A1),A2 ; Trace entry point move.l A2,Trace ;replace trace rts ;return to caller ; ****** STUB ********* ; ; all code must be relocatable. stub dc.l inkey ;keyword to indicate installation done flag dc.b $FF ;-1 for initial flag dc.b 0,0,0 ;spare StoAline dc.l 0 ;old Aline vector StoTrace dc.l 0 ;old Trace vector StoBufPtr dc.l 0 ;old Top of Memory StTcount dc.l 0 ;Total instructions traced count ;TRACE entry point - 68k trace entry point StTrace move.b flag,-1(SP) ;? tracing on bne.s traceoff ;br if not movem.l D0/A0,-(SP) ;work registers lea StTcount,A0 addq.l #1,(A0) ;up total trace count move.l 4+4+2(SP),A0 ;caller's PC move.w (A0),D0 ;load opcode mulu.w #3,D0 ;find table offset lea stub+256+2,A0 ;table base + low byte entry offset addq.b #1,(A0,D0.L) ;increment low byte by one bcc.s noofl ;branch no overflow addq.b #1,-1(A0,D0.L) ;increment next byte bcc.s noofl ;branch no overflow addq.b #1,-2(A0,D0.L) ;increment next byte bcc.s noofl ;branch no overflow st.b (A0,D0.L) ;back up to maximum st.b -1(A0,D0.L) ;back up to maximum st.b -2(A0,D0.L) ;back up to maximum noofl movem.l (SP)+,D0/A0 ;restore registers traceoff rte ;continue user ;A-LINE entry point - interception to detect Launches and I/O calls ; ; For Launch increment the flag and if zero (1st call) clear count table. ; Happens when Finder launches next application after table installed. ; For A-LINE inhibit tracing for I/O and Enqueue calls. Otherwise if profiling then ; set caller's trace bit on and ours as well before continueing. StAline move.l StoAline,-(SP) ;setup to pass to Mac A-line movem.l D0/A0,-(SP) ;save work regs move.l 4+4+4+2(SP),A0 ;caller's PC move.b 1(A0),D0 ;second byte of a-line cmp.b #$6F,D0 ;? Enqueue call beq.s passthru ; yes let right on through cmp.b #$F2,D0 ;? launch bne.s notlaunch ;br if not lea flag,A0 add.b #1,(A0) ;increment flag bne.s notlaunch ; zero out table as we are starting to trace move.b D0,-(SP) ;save a-line index move.l #$30000,D0 ;bytes to clear (64k*3) lsr.l #2,D0 ;Div by 4 lea stub+256,A0 ;start of table clrloop clr.l (A0)+ ;next entry subq.l #1,D0 ;count down bne clrloop ;br till done move.b (SP)+,D0 ;restore a-line index notlaunch cmp.b #$F4,D0 ;exit to shell bne.s notexit ;br not ; if we have just been tracing then increment the flag lea flag,A0 ;base ourselves tst.b (A0) ;? tracing bne.s noincr ;br if not add.b #1,(A0) ;increment flag to stop tracing noincr bclr.b #7,12(SP) ;stop tracing from caller notexit move.b flag,-1(SP) ;? we tracing bne.s passthru ;no - pass through cmp.b #5,D0 ;? not I/O bhi.s dotrace ;yes, allow trace cmp.b #2,D0 ;open or close blo.s dotrace ;yes, trace them passthru movem.l (SP)+,D0/A0 ;restore work rts ;to Mac A-line dotrace movem.l (SP)+,D0/A0 ;restore work regs bset.b #7,4(SP) ;force caller to trace move.w SR,-(SP) ;store status register bset.b #7,(SP) ;force this routine to trace rte ;to normal A-line ; *******end of Stub******* ; *** Output Table Subroutine *** ; ;The table consists of a longword header which is a count of the total ;instructions traced for this profile. Following the header is ;the table proper with 64k entries each 3 bytes in length. Entry one is ;for instruction opcode $0000, entry two for $0001 etc. If an entry count ;went over the 24 bits it is kept at $FFFFFF. The amount of overflows ;can be computed by adding up all the table entries and comparing to the ;header count which is exact. ; ;The format of the block of memory representing the header and table ;on the disk is a series of compressed records with the format: ; ; BYTE 1 = number of zero bytes (0 to $FE, FF = EOF) ; BYTE 2 = 1st of 2 literal byte values ; BYTE 3 = 2nd of 2 literal byte values ; ;Recreating the table is as simple as reading each record, adding the number ;of zero bytes specified (from zero to $FE) then adding the 2 specific bytes, ;and stopping when the next zero byte count reaches $FF. Note: the ;rebuilding may overflow the table by a few bytes so leave an extra ;longword at the end. createfile lea Param,A0 ;I/O param block clr.l ioCompletion(A0) ; no asynch I/O lea fName,A1 ;file name from SFGetFile move.l A1,ioFileName(A0) ; store ptr in move.w vRefNum,ioVRefNum(A0) ; volume no. from SFGetFile clr.b ioFileType(A0) ;no version no. _Create cmp.w #dupFNErr,D0 ;? File already created beq.s ignoredup ;yes, just overwrite it tst.w D0 ;? error bne doError ;br yes ;Get File info to update Finder stuff ignoredup clr.w ioFDirIndex(A0) ;indicate to use File name _GetFileInfo bne doError ;br yes ;Set Type='PROF', creator='????', and in disk window move.l #'PROF',ioFlUsrWds+fdType(A0) move.l #'????',ioFlUsrWds+fdCreator(A0) clr.w ioFlUsrWds+fdFlags(A0) ; leave visible and unprotected clr.l ioFlUsrWds+fdLocation(A0) ; corner of disk window clr.w ioFlUsrWds+fdFldr(A0) ; in the disk window _SetFileInfo bne doError ;br yes ;open the file move.b #fsWrPerm,ioPermssn(A0) ; write permission clr.l ioOwnBuf(A0) ;no special buffer _Open bne doError ;br yes ; *** write table out *** ; D0 = zero byte count ; A0-> Paramblock ; A2-> current byte position in table ; A3-> last byte past end of table move.l BufPtr,A3 ;stub address lea 256-4(A3),A2 ;A2->header in front of table (table-4) move.l StTcount-stub(A3),(A2) ; move total count at table front add.l #$30100,A3 ;A3->byte past end of table ;zero byte count processing zerocnt clr.b D0 ;start counting zero value bytes zerotst cmp.l A2,A3 ;? to out of table addr bls.s endbuf ;yes - send end of file mark cmp.b #$FE,D0 ;? top limit of zero byte count beq.s notzero ;yes - treat as non-zero byte hit tst.b (A2) ;? non-zero byte hit bne.s notzero ;br if so add.b #1,D0 ;count this zero byte add.l #1,A2 ;to next entry in table bra zerotst ;and continue ;process zero count and 2 literal bytes notzero bsr.s wrtrec ;write the record out bra zerocnt ;start on the next zero count ;end of buffer reached endbuf tst.b D0 ;any zero bytes? beq.s doeof ;no - no need for final record bsr.s wrtrec ;write record with count and 2 garbage bytes doeof move.b #$FF,D0 ;setup end of table mark bsr.s wrtrec ;write end of table and 2 garbage bytes ;close file _Close bne.s doError ;br yes rts ;return done to caller ;set in zero and next two literals then write record out wrtrec lea outrec,A1 ;point to record move.b D0,(A1) ;zero count move.b (A2)+,1(A1) ;1st literal move.b (A2)+,2(A1) ;2nd literal move.l A1,ioBuffer(A0) ;start at front of record move.l #3,ioByteCount(A0) ;record length move.w #fsAtMark,ioPosMode(A0) ;no seek clr.l ioPosOffset(A0) ;no offset from mark _Write bne.s doError ;br yes rts ;return to caller ;Error occured. Bomb system for now with error code doError neg.w D0 ;turn to positive number for msg display _SysError ;Code will show in error window ;---- DATA ---- EvRecord Evntype DC 0 ;type of event Evmsg DC.L 0 ;message Evtstamp DC.L 0 ;time stamp EvMpos DC.L 0 ;mouse position Evmod DC 0 ;modifier bits Windparm DC.L 0 ;Window mouse in parm Deskname DCB 16,0 ;desk menu item text (no spec chars) MenT1 DC.B 1,20 ;Apple symbol Men1Hndl DC.L 0 ;Menu1 handle Men2Hndl DC.L 0 ;Menu2 handle Men3Hndl DC.L 0 ;Menu2 handle QDstore DC.L 0 ;Ptr to QD storage SFReply good dc.b 0 ;good reply dc.b 0 ;unused fType dc.l 0 ;file type vRefNum dc.w 0 ;volume reference version dc.w 0 ;version fName dcb.b 64,0 ;file name Param dcb.b ioFQElSize,0 ;largest I/O block is GetFileInfo outrec dc.l 0 ;3 byte output record END