\ portable RUNTIME PROFILER  Version 1.05 hs10.12.96
\ USE:  -- runtime-profiling of colon definitions.
\ mini manual:
\ 1) load the cpu specific runtimer file, this file should be loaded automatically.
\       fload extend\??cpu??\runtimer.fth
\       fload extend\runtime.fth
\ 2) From now on all colon definitions have an internal time measuring code part which is
\       executed by calling the word.
\ 3) Glossary:
\ new ( -- )
\       clear all timing information
\ .times ( -- )
\       display timing information
\ profile ( -- ) name
\       the word name is executed and the timing takes place. name could be a "benchmark" or
\       the timing critical part of your application.       
\ see   is patched, it will give correct information and knows about the timer information data
\       structure
\
\ 4) example
\ : test1       dup dup dup ;
\ : test2       drop drop drop ;
\ : test3       swap swap swap ;
\ : test4       test1 test3 test2 test1 test3 test2 ;
\ : test5       10000 0 do test4 test4 loop ;
\ profile test5 .times

\
\ User words of runtimer Version 1.0
\       new (-- )             set all calls and ticks to 0
\       .times ( -- )         print runtimes
\       profile  name ( -- )  make a runtime profile of word name)
\ Lit.  [1] "Laufzeitmessung von Forthworten", Bernd Pennemann, VD2/87
\       [2] Forthmacs User's Guide, Mitch Bradley/Hanno Schwalm 
\
\ After loading the runtimer every colon definition is linked by an extra
\ link-list for easy finding of all words.

\ Structure of new colon definition:
\       timer-link-list long
\       standard forthmacs header
\       apf parameter field address of word
\        0 (time
\        4 calls
\        8 #time
\       12 compiled code continues ......

only forth also hidden also definitions  decimal

[ifdef]	profile		\ this file shouldn't be compiled twice
        ??cr .( runtimer already loaded)
        cr fexit
[then]

[ifndef] du/mod		\ double math library required
	?cr .( Forthmacs kernel with extended double library required)
	cr fexit
[then]

[ifndef] (time		\ defined in cpu-specific file
        ??cr .( runtimer needs cpu-specific timer definition-file first)
        cr fexit
[then]

variable used-time
variable timer-link             \ base of link-list bound to 0
        here timer-link link!  0 ,
defer scan-action               \ ( anf -- )

: scan-all      \ ( -- ) scan-action is done with all timer-linked words
	timer-link
	begin	link@ dup link@  exit? not and
	while	dup cell+  l>name   scan-action
	repeat	drop ;

: ticker-data   \ ( anf -- adr-timer adr-data )
	name> >body cell+ dup cell+ swap ;
: new-data      \ ( anf -- ) Call-nr und Time-nr  = 0
	ticker-data off off  used-time off ;
: legal-data    \ ( anf -- )
	ticker-data drop @ 2-  used-time @ >
	if used-time off then ;
: .percent      \ ( n-ticks -- )
	100 used-time @ */ ?dup if 4 .r else ."   <1" then ." %" ;

: .nsec         \ ( d-nsec -- )
	30000000. 2over  du<	if 1000000 um/mod nip		8 u.r ."  msec" exit then
	30000.    2over  du<	if 1000 um/mod nip		8 u.r ."  sec" exit then
	drop 50	  over  u>	if drop ."      <50" else 	8 u.r then ."  nsec" ;
: .one-data     \ ( anf -- ) prints data of one word
	dup ticker-data @  swap @ swap
	dup 0=  ( anf #time calls flag )
	if 2drop drop exit then
	rot .id  20 to-column
	2dup 8 .r ."  Calls"    nsec/tick um* .nsec
	( ticks calls )
	2dup >r nsec/tick  um* r> s>d  du/mod .nsec ." /call" 2drop
	drop  used-time @
	if  .percent else drop then ??cr ;

\ support for the decompiler
[ifdef] see
	: .runtime-info		( ip -- ip' )
		+indent .." \ <-- profiler-information available, "
		cell+ dup @ .d ." calls, " cell+ dup @ .d ." ticks." cell+ -indent ;
	: skip-runtime-info     ( ip -- ip' )
		cell+ cell+ cell+ ;
	' (time ' .runtime-info  ' skip-runtime-info  install-decomp
[then]

: (bye		remove-ticker (bye ;                
: (forget       true abort" forget is not supported with profiler loaded!" ;
: (save-forth   true abort" save-forth is not supported with profiler loaded!" ;
        ' (forget     ' forget >body token!
        ' (save-forth ' save-forth >body token!
        ' (bye is bye
forth definitions

variable runtimer  runtimer off     \ on -> the runtimer code is compiled
: new           \ ( -- ) set all ticks and calls to 0
        ['] new-data is scan-action  scan-all ;
: .times        \ ( -- ) prints data of all words
        ??cr cr ." Runtime profiler V 1.05  1993,94,96 Hanno Schwalm"
        cr rmargin @ 0 do [char] _ emit loop cr cr
        ['] legal-data is scan-action scan-all
        ['] .one-data is scan-action
        push-decimal scan-all  pop-base
        cr rmargin @ 0 do [char] _ emit loop cr cr ;

: profile       \ name ( -- ) make runtime-profile of name
        new '
        get-ticks >r execute get-ticks r> -  used-time ! ;

: :             \ name ( -- ) redefined colon, using runtimer
        runtimer @ 0= if postpone :  exit then
        timer-link link-here
        postpone :			\ make a colon definition
        postpone (time 0 , 0 , ; immediate

only  forth also  definitions  decimal
runtimer on
