Open benibela opened 3 years ago
I agree this would be useful, although there is a danger of misuse. Saxon offers this capability as saxon:timestamp(). Perhaps the name fn:dateTimeStamp(), to align with the XSD 1.1 type name, would be appropriate.
eXist also uses util:system-dateTime()
: https://exist-db.org/exist/apps/fundocs/index.html?q=util:system-dateTime.
I have only used saxon:timestamp()
rarely, but I have been very greatful for it when I have.
I could live easily with either fn:dateTimeStamp()
or fn:system-dateTime()
.
I had a go at speccing this up, which was going fine until I started writing the notes giving advice on how to use it for performance instrumentation, avoiding the hazards of variable inlining and lazy evaluation in a construct like
let $start := system-dateTime();
let $doc := doc('abc.xml')
let $totalTime = system-dateTime() - $start;
and I found it very difficult to give advice on how to do this in a way that had a good chance of working with all implementations.
So it occurred to me that a better solution might be a function
fn:monitor(doc('abc.xml')) as record(value, startTime, endTime)
which returns a map containing fields value
- the value of the first argument, plus the start time and end time, or perhaps just their difference.
There's still a bit of an assumption that the implementation is capable of getting the start time before the first argument is evaluated, which implies some kind of lazy evaluation, but that's putting the onus on the implementor, not on the user, and I would think there's a reasonable prospect of getting it interoperable.
Would we want this as well as system-dateTime()
, or in place of it?
Would we want to return start and end time, or just duration? If duration, then as an xs:duration
or as a number?
Note that there's still a degree of non-determinism, in that two calls on fn:monitor() with the same argument value are expected to return different results. And there's still a danger of optimization invalidating any measurements, e.g. if
avg(1 to 1000 ! (monitor(my:f('foo'))?duration) )
does any unexpected loop-lifting. But those difficulties seem more manageable than the problems with order of evaluation of independent local variables.
Exactly my thoughts. We advise our users against using non-deterministic functions for doing performance measurements. Instead, we provide prof:time
, which output the runtime similar to fn:trace
, and prof:track
, which returns the runtime of an expression along with the result. In practice, because of suppressed optimizations, the returned time may deviate a lot from the runtime without monitoring, so the results need to be interpreted accordingly.
I also encountered cases which don’t revolve about performance. For example, if you write logs during a time-consuming process, it can be important to have the exact timestamp when a particular subprocess was finished.
@benibela Which use cases did you have in mind when proposing the function?
I don't recall wanting a timestamp specifically for performance testing, so I don't think fn:monitor
is a really good replacement for system-dateTime
. If, in the interest of minimizing the number of functions in the library, we decide that it should be a replacement, it's going to be important that it return the start time since that might be the only bit I care about!
Would a design something like random-number-generator
have any value? I'm thinking of a function that returns a start time, a duration (initially 0), and a function that when called will return a new start time, the duration since the last call, and another function to repeat the process.
I think there's still a use-case for system-dateTime in constructing the output of fn:trace()
or xsl:message
; but perhaps that can be achieved with mechanisms specific to that function/instruction.
Things users wanted to do:
At the f2f, we discussed some of the details and seemed to be favoring the idea that it would be easiest to make the eager evaluation a quality of implementation issue.
The
current-date/Time
functions are deterministic, so they always return the same time, which is very confusing to everyoneThere could be
actual-current-date/Time
functions that return the actual time non-deterministically. Or call itwall-date/Time
orsystem-date/Time