help with function utilising "extended life-time" words ..
[1/7] from: petr:krenzelok:trz:cz at: 1-Oct-2003 18:44
Hello,
I am currently working with some databases and I do some steps in my
script, which I measure currently for its duration time. I use something
like:
start: now/time/precise .... do something ... print now/time/precise -
start start: now/time/precise
I wanted to write myself short logger function, which will save me from
repeating above sequences, as the script becomes a bit messy then. So I
wanted to have following interface:
>> how-long? "Some task ..."
Total: 0:1:32 This: 0:0:1 Some task ....
- Simply put - requested function should not require sending any time
information, only a text message ...
- it should start counter when first called
- it should be possible to reset counter with /reset refinement ...
I looked at some past threads and tried Joel's solution:
foo: func [arg [string!] /reset /report /local ncalls][
ncalls: [0]
if reset [return ncalls/1: 0]
if report [return ncalls/1]
ncalls/1: ncalls/1 + 1
rejoin ["call # " ncalls/1 " with " arg]
]
... but when I define something like "timer: reduce [now/time/precise
0]", it seems to me, that 'reduce causes reinitialisation of block
values with each function call, while I would like to store "first run"
time value somewhere to be able to count total task run time ...
Anyone?
Thank you very much,
-pekr-
[2/7] from: ingo:2b1 at: 1-Oct-2003 19:09
Hi Pekr,
Petr Krenzelok wrote:
> Hello,
<...>
> start: now/time/precise .... do something ... print now/time/precise -
> start start: now/time/precise
>
> I wanted to write myself short logger function, which will save me from
> repeating above sequences, as the script becomes a bit messy then. So I
> wanted to have following interface:
<...>
Maybe this script will help a little, I normally use only
profiler/test [a short snip I want to test] 10000
but it "should" be possible to set different profiler marks in your
script, and test them later, but that's not tested.
I hope that helps,
Ingo
-- Attached file included as plaintext by Ecartis --
-- File: profiler.r
REBOL [
Title: "Rebol Profiler"
Author: "Ingo Hohmann"
]
profiler: context [
markers: []
mark: func [
"adds a profiler mark"
marker [word!]
] [
insert tail markers reduce [ marker now/time/precise ]
]
show: func [
"shows time since setting a profiler mark"
marker [word!]
/local t walk ret-val last-val tmp-val
] [
ret: copy []
t: now/time/precise
if walk: find markers marker [
walk: next walk
last-val: first walk
while [walk: find walk marker] [
walk: next walk
append ret (first walk) - last-val
last-val: first walk
]
]
ret
]
test: func [
{tests a block for speed *!* clears the markers block *!*}
block [block!]
times [integer!]
] [
block: copy/deep block
clear
mark 't
loop times [do block]
mark 't
show 't
]
clear: func [
"Clears all markers"
/only marker [word!]
/local walk
] [
either only [
walk: find markers marker
until [
remove/part walk 2
not found? find walk marker
]
] [
system/words/clear markers
]
]
next-marker: 1
_func: function!
;
; ToDo:
; create a list of marks, find a way to name the functions
;
profiling-func: func [
{Adds profiling data to a normal function}
[catch]
spec [block!] {Help string (opt) followed by arg words (and opt type and string)}
body [block!] "The body block of the function"
/local pre post
][
pre: copy [catch/name ]
post: copy ['profiling-return]
insert body compose [profiler/mark (to-word join 'm next-marker)]
next-marker: next-marker + 1
insert tail insert/only tail pre body post
probe pre
]
install: func [
{Installs a profiling 'func
every new func after this will create a profiling function}
][
_func: :func
func: :profiling-func
]
]
[3/7] from: maximo:meteorstudios at: 1-Oct-2003 14:02
> -----Original Message-----
> From: Petr Krenzelok []
>
> start: now/time/precise .... do something ... print
> now/time/precise -
> start start: now/time/precise
try this:
it expects a block of code and even returns the value from it (and returns none for no
value functions like print)... but it can easily be tweaked to work differently?
;-----------------------------------------------------
rebol []
how-long?: function [codeblk [block! none!] /reset /quiet /log log-message log-string
][rval timestart timeend timelen][
if ((reset = true) OR (not value? 'how-long-accumulator)) [
how-long-accumulator: 0:00
]
if codeblk [
timestart: now/time/precise
if (error? try [rval: do codeblk ]) [rval: none]
timeend: now/time/precise
timelen: (timeend - timestart)
how-long-accumulator: how-long-accumulator + timelen
if not quiet [
print ["performed in: " timelen ]
print ["accumulated: " how-long-accumulator ]
]
if log [
append log-string log-message
append log-string rejoin [" > time: " timelen " accumulated: " how-long-accumulator
"^/"]
]
]
return rval
]
log-string: copy ""
how-long?/log [loop 1000000 [34.0 / 2.556] ] "test-block-A() " log-string
how-long?/log [loop 1000000 [34.0 / 2.556] ] "test-block-B() " log-string
how-long?/log [loop 1000000 [34.0 / 2.556] ] "test-block-C() " log-string
how-long?/log [loop 1000000 [34.0 / 2.556] ] "test-block-D() " log-string
print log-string
[4/7] from: joel:neely:fedex at: 1-Oct-2003 13:44
Hi, Petr,
Here are a couple of simple approaches (which you can complicate
as desired for more functionality ;-)
-jn-
Petr Krenzelok wrote:
> start: now/time/precise .... do something ... print now/time/precise -
> start start: now/time/precise
>
> I wanted to write myself short logger function, which will save me from
> repeating above sequences, as the script becomes a bit messy then. So I
> wanted to have following interface:
>
> >> how-long? "Some task ..."
>
Single-task timing doesn't require any tricky state:
how-long?: func [msg [string!] to-do [block!] /local timing] [
timing: now/time/precise
do to-do
timing: to-decimal now/time/precise - timing
print [timing msg]
]
Which behaves as in the following transcript:
(begin transcript)
>> how-long? "count to one million" [for i 1 1000000 1 []]
3.195 count to one million
>> how-long? "count to one hundred thousand ten times" [
[ loop 10 [
[ how-long? "count to one hundred thousand" [for i 1 100000 1[]]
[ ]
[ ]
0.33 count to one hundred thousand
0.321 count to one hundred thousand
0.31 count to one hundred thousand
0.321 count to one hundred thousand
0.31 count to one hundred thousand
0.321 count to one hundred thousand
0.32 count to one hundred thousand
0.321 count to one hundred thousand
0.31 count to one hundred thousand
0.32 count to one hundred thousand
3.184 count to one hundred thousand ten times
>>
(end transcript)
If you want accumulation of times across multiple calls, just
wrap the total in a block (per the tricky approach you quoted)
or do The Right Thing and represent stateful timing accumulators
with objects:
time-accumulator: make object! [
message: "no message?"
total: 0.0
reset: func [][total: 0.0]
time-this: func [to-do [block!] /local timing] [
timing: now/time/precise
do to-do
timing: to-decimal now/time/precise - timing
total: total + timing
print ["Total:" total "This:" timing message]
]
]
which can be used as follows:
>> stopwatch1: make time-accumulator [message: "Watch 1"]
>> stopwatch1/time-this [for i 1 1000000 1 []]
Total: 3.155 This: 3.155 Watch 1
>> stopwatch2: make time-accumulator [message: "smaller chunks"]
>> loop 10 [stopwatch2/time-this [for i 1 100000 1 []]]
Total: 0.32 This: 0.32 smaller chunks
Total: 0.631 This: 0.311 smaller chunks
Total: 0.941 This: 0.31 smaller chunks
Total: 1.262 This: 0.321 smaller chunks
Total: 1.582 This: 0.32 smaller chunks
Total: 1.893 This: 0.311 smaller chunks
Total: 2.203 This: 0.31 smaller chunks
Total: 2.514 This: 0.311 smaller chunks
Total: 2.834 This: 0.32 smaller chunks
Total: 3.144 This: 0.31 smaller chunks
>>
I prefer to represent stateful entities via objects rather than
functions. Among other reasons, stateful functions depend on aspects
of REBOL (persistence of mutations to "literal" series values) that
are very mysterious to REBOL newbies. There's no point in being
obscure, just for the sake of obscurity! ;-)
-jn-
--
----------------------------------------------------------------------
Joel Neely joelDOTneelyATfedexDOTcom 901-263-4446
Counting lines of code is to software development as
counting bricks is to urban development.
[5/7] from: petr::krenzelok::trz::cz at: 1-Oct-2003 21:42
Thanks all for answers! I was just thinking in a bit different way - I
did not want to enclose measured task into special block to prevent
myself from forgetting to include ending bracket :-) So, my initial
intention was to have how-long? just marking current time substracted
from last function call ... From the various aproaches I saw I like
object based the most probably ... do not why though :-)
Cheers,
-pekr-
[6/7] from: maximo:meteorstudios at: 1-Oct-2003 15:54
man, just swap the variable names and our example are almost identical...
;-)
I didn't use an object, just because I tought he really just wanted a function... it
uses one global word for accumulated do times... it also safely returns a value, which
can be cool if you also wish to test the validity of returned data in addition to speed
gains.
for example, you could more easily trap floating point problems... when testing different
floating point tricks, cause you can then compare the value...
-MAx
---
You can either be part of the problem or part of the solution, but in the end, being
part of the problem is much more fun.
[7/7] from: joel:neely:fedex at: 2-Oct-2003 7:04
Hi, Petr,
Petr Krenzelok wrote:
> Thanks all for answers! I was just thinking in a bit different way - I
> did not want to enclose measured task into special block to prevent
> myself from forgetting to include ending bracket :-)
>
However, the presence of explicit brackets makes it clear precisely
what you mean when inserting or removing a call to the timer.
Without that hint, presence/absence of a call could affect the results
of other calls in hard-to-track-down ways.
> So, my initial intention was to have how-long? just marking current time
> substracted from last function call ... From the various aproaches I saw
> I like object based the most probably ... do not why though :-)
>
I prefer to use objects to manage persistent state precisely because
that is what objects were intended for in the first place. The amount
of state can scale up gracefully as one's design evolves (e.g. add one
more attribute to the object) without requiring lots of tricky digital
plumbing (e.g. the REDUCE... issue at the beginning of this thread).
Just MHO, of course! ;-)
-jn-