[MLton] Question on profile.fun

Stephen Weeks MLton@mlton.org
Thu, 26 May 2005 19:39:18 -0700


> The discussion and improvements to  -const 'Exn.keepHistory true'  had me 
> thinking about other improvements to the profiling infra-structure.  I had 
> the idea of adding the flags:
> 
>   -profile-exclude <regexp>  exclude files matching <regexp> from profile
>   -profile-lib <regexp>  include library files matching <regexp> in profile

I wonder if these might work well as annotations?

> But, I have to admit I'm a little confused about the relationship
> between 
>   keepSource : SourceInfo.t -> bool	(line 182)
> and
>   enter : Push.t list * SourceInfo.t -> Push.t list * bool	(line 316)
> 
> In particular, I don't understand what the complicated condition at 
> line 332 is trying to accomplish. 

That condition started small and grew over time as I looked at profile
call graphs and decided what should appear and what shouldn't.  It's
not based on any hard logic; rather it's based on what I think people
usually want to see.  So, one way to understand it is to take out
various clauses and see how the graphs change.

In summary, the condition decides whether or not a source info (si) 
is relevant, taking into account the source info (si') of its calling
context.  So, assuming we've decided we probably want si ("keepSource
si"),  we will look at the context to see if we will actually use it.
Here's a walkthrough.

 * (!Control.profileBasis)

   In this case, we are seeking maximum profiling information, so we
   want it.
				
 * orelse (equals (si', unknown))

   In this case, the caller was unknown, so it will be helpful to at
   least provide the information we have.

 * (not
    (equals (si, gcArrayAllocate)
     orelse isBasis si
     orelse (isC si andalso (isBasis si' orelse equals (si', main)))))

   The first clause rules out calls to the C function GC_arrayAllocate
   on the premise that it's more informative to split out the array
   allocation ticks to the various callers of GC_arrayAllocate.

   The second clause rules out calls to basis functions.

   The third clause rules out calls to C functions, unless the caller
   is a basis function or main.  We would rather not allocate ticks to
   main because that's not very informative.  If you're calling C
   functions from within user code, then you want the time allocated
   to the C function.  If you're calling C functions from within the
   basis, then you want to hide the fact that some of the basis is
   implemented via C, and allocate the ticks to the basis code, which
   will make the results more palatable to the user.  One especially
   good reason for this is the IntInf code in the basis, where it's
   much nicer to see the time spent in IntInf.+ than to see it split
   between the SML code and the C function IntInf_add.

   So, I guess a third thing that one might like to control is whether
   certain SML code should count time spent in FFI calls, or the time
   should be attributed to the underlying C function.