[MLton-devel] Effect of -exn-history true on performance

Matthew Fluet Matthew Fluet <fluet@CS.Cornell.EDU>
Sun, 25 Aug 2002 10:53:38 -0400 (EDT)


> Can -exn-history true possibly have an effect on performance ? I
> am not sure I understand how it is implemented. Thanks.

The implementation of -exn-history true is at
mlton/xml/implement-exceptions.fun

Essentially, with -exn-history true the raised exception type is 
(string list ref * exn) while with -exn-history false the raised exception
type is just exn.  Something like

raise (Fail "foo")

becomes

let
  val history = ref nil 
  val exn = (history, Fail "foo")
in
  history := (<file pos>)::(!history);
  raise exn
end

while an exception passing through a handler has it's history extended;
i.e.,

handle Overflow => 0

becomes

handle e => let (history,exn) = e
            in
              case exn of
                Overflow => 0
              | _ => (history := (<file pos>)::(!history);
                      raise e)
            end


At least, that's my naive understanding.  You'd expect the only
performance impact to be proportional to the number of handlers passed
through.  Note, you still pay for extending the history even if you handle
the exception eventually and don't look at the history.

Unfortunately, it looks like some of the XML optimizations aren't as
effective in the presence of -exn-history true.  If you compare
regression/exnHistory.sml with -exn-history true and -exn-history false,
you see that the function f with -exn-history true is passed two extra
arguments.  One of these arguments turns out to be the Overflow exception,
which really should be globalized.  But implement-exceptions.fun has an
"optimization" that if the exception isn't value carrying, it is
constructed at the "exception Foo" declaration and should be shared by all
raises.  Under -exn-history true, this constructed exception includes the
string list ref, which isn't globalized in the XML simplifications.

In any event, I don't think that that "optimization" is valid, depending
on one's interpretation of -exn-history true.  For example, the following
program:

exception FOO

fun f x =
   if x = 0
      then raise FOO
   else f (x - 1) handle Overflow => 13

val _ = (f 10; ()) handle e => (List.app (fn s => print (concat [s, "\n"]))
				(SMLofNJ.exnHistory e))
val _ = print "ZZZ\n"
val _ = (f 10; ()) handle e => (List.app (fn s => print (concat [s, "\n"]))
				(SMLofNJ.exnHistory e))

when compiled with -exn-history true yields:

[fluet@lennon temp]$ ./exnHistory.true
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:5.18
ZZZ
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:5.18
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:6.26
exnHistory.true.sml:5.18

That is, a "freshly" raised (non-value carrying) exception carries the
history of previous raises, which doesn't seem correct to me.  So, I think
I'm wrong about how the translation is being done (instead, it's the
allocation of Fail "foo" that creates the string list ref, not the raise),
but I don't know why it's being done this way.

I think the plan was that the implementations of -exn-history true was
supposed to be as lightweight as possible.  I'm not sure why Stephen is
using a string list ref instead of a string list and reraising with a new
history list.  Yes, that means the reraised exception is not pointer equal
to the originally raised exception, but exceptions don't admit equality;
you have to pattern match, which means extracting the "real" exception
from the history.

So, Alain, in short -- there does seem to be a performance impact of using
-exn-history true; in particular, there are extra arguments being passed
around that should be globalized.  That's going to slow down all function
calls, etc.  But, I can't explain why such a performance cost needs to be
there.




-------------------------------------------------------
This sf.net email is sponsored by: OSDN - Tired of that same old
cell phone?  Get a new here for FREE!
https://www.inphonic.com/r.asp?r=sourceforge1&refcode1=vs3390
_______________________________________________
MLton-devel mailing list
MLton-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mlton-devel