Short version:

When I call prof:track(...) with an expression as argument, I get the
results I would expect.  When I assign prof:track#1 to a variable and
then call it with an expression by referring to that variable, the time
shown is always 0.  Is this the expected behavior?


Details:

Consider the following XQuery module:

    let $f := function($s as xs:string) { 
                  trace('hi'), 
                  prof:sleep(2000), 
                  trace($s) 
              },
        $pt := (function-lookup(
                  QName('http://basex.org/modules/prof',
                        'track'),
                  1),
                  function($item) {
                      map {'time':'?', 'value': $item}
                  }
               )[1]
    
    return (prof:track($f('world')), $pt($f('friends!')) )

It defines two variables:

  - $f, a function that produces output (so I can see that it ran) and
    calls prof:sleep (so it takes more than a couple of ms), and

  - $pt, which will be the prof:track() function if it exists (as it
    will in BaseX) or a substitute function which just evaluates the
    expression but does not provide any timing information.

It then calls function $f twice, once wrapped in prof:track() and once
wrapped in $pt().  The output follows:

    map {
      "memory": 0,
      "time": 2.00069e3,
      "value": ("hi", "world")
    }
    map {
      "memory": 0,
      "time": 0.0e0,
      "value": ("hi", "friends!")
    }

As may be seen, the 'time' value in the map is 0.

Conjecture:

I suspect that this has to do with the fact that prof:track() is not a
normal function -- in Lisp or Scheme, it would have to be implemented as
a macro or 'special form', meaning that the arguments to the call are
not evaluated before calling the function.  I wonder whether what is
happening here is that when the call to $pt($f('friends')) is handled,
the argument is being evaluated (producing the sequence ('hi',
'friends!')) and then prof:track() is being called.  Since it has no
work to do, prof:track() then just returns the result, accurately
showing a time cost of 0.  

Background:

In a test harness I use to run tests for an XQuery program I am writing,
I initially used prof:track() to keep track of how long each test takes
to run.  Recently, as part of an effort to ensure that the program is
implementation-neutral, I rewrote the test harness so that it could run
under other XQuery engines as well -- hence the indirection and the
definition of $pt.

I realize that I could get the BaseX version to work by saying something
like

  let $prof-track := function-lookup(...)
  let $fall-back := function(...)

  if (exists($prof-track))
  then prof:track(...)
  else $fall-back(...)

but my recollection is that I tried this first and it provoked fatal
errors in other engines, since prof:track() is not available in the
static context in those engines.

Is there any way to write a single module so that prof:track() is used
(and produces useful information) if available, and the fallback
function is used otherwise?  I would really like to avoid generating
different versions of the test harness for different XQuery engines.

Many thanks for any thoughts or advice anyone on this list can provide.

Michael Sperberg-McQueen

-- 
C. M. Sperberg-McQueen
Black Mesa Technologies LLC
http://blackmesatech.com

Reply via email to