Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[Caml-list] Name of currently executing function

6 views
Skip to first unread message

Dave Benjamin

unread,
Jul 14, 2008, 1:27:44 AM7/14/08
to caml...@yquem.inria.fr
Hello,

Is there any way to find out the name of the currently executing
function from within an OCaml program? I guess, technically, I'm
interested in the grandparent. Something that would allow this:

let log msg =
Printf.eprintf "%s: %s\n%!"
(get_caller_function_name ())
msg

I'm guessing the above is not possible, but perhaps there's some way to
accomplish this using some combination of camlp4, back traces,
profiling, or debugging?

Thanks,
Dave

_______________________________________________
Caml-list mailing list. Subscription management:
http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
Archives: http://caml.inria.fr
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

blue storm

unread,
Jul 14, 2008, 9:53:42 AM7/14/08
to Dave Benjamin, caml...@yquem.inria.fr
Here is a little camlp4 code for an ad-hoc solution :
http://bluestorm.info/camlp4/Camlp4GenericProfiler.ml

It's based upon the Camlp4Filters/Camlp4Profiler.ml from the camlp4
distribution.
The GenericMake functor will traverse your code and apply the
parametrized function to the body of each function declaration. You
can use it with a functor providing a (with_fun_name : string ->
Ast.expr -> Ast.expr), transforming the Ast to your liking, given the
function name.

I've written a small LoggingDecorator module that operates on the
__LOG__ identifier. Example code :
let __LOG_FUNC__ func msg = Printf.eprintf "in function %s: %s\n%!" func msg
let test_function p = if not p then __LOG__ "p is false !"

It will replace the __LOG__ identifier with a __LOG_FUNC__ "p".

You can change that behavior, in particular you could be interested
(for logging purpose) in the location of the function declaration, not
only his name : see how the initial Camlp4Profiler behavior (wich i
kept in the ProfilingDecorator) do that (Loc.dump).

Dave Benjamin

unread,
Jul 15, 2008, 2:14:13 AM7/15/08
to blue storm, caml...@yquem.inria.fr
blue storm wrote:
> Here is a little camlp4 code for an ad-hoc solution :
> http://bluestorm.info/camlp4/Camlp4GenericProfiler.ml

This works very well. Thank you very much for the example.

On a related note, I was trying to understand how these new syntax
filters work, and I am a bit confused by how I'm supposed to use
Camlp4Tracer. I tried compiling a simple test program with:

camlp4 -parser ocaml -filter tracer -printer ocaml

It complained about an unknown value "Debug.mode", which I figured out
was in the Camlp4 library, so I added that library and the line:

module Debug = Camlp4.Debug

to my program. Then it complained about an unbound value "exc". I looked
at the Camlp4Tracer.ml to discover that it expects an exception named
"exc" to be in scope with every function. I'm not sure what this is for,
but I was able to get it to compile by creating a toplevel variable. My
test program looks like the following now:

(*pp camlp4 -parser ocaml -filter tracer -printer ocaml *)

module Debug = Camlp4.Debug

let exc = Not_found

let test () =
print_endline "this is output"

let () =
test ()

And my Makefile looks like this:

OCAMLMAKEFILE := OCamlMakefile

SOURCES := main.ml
USE_CAMLP4 := yes
PACKS := camlp4.lib
RESULT := main

include $(OCAMLMAKEFILE)

Now, I can get tracing output:

% CAMLP4_DEBUG=* ./main
camlp4-debug: tracer: Not_found at File "main.ml", line 8, characters 16-32
this is output

So, is this the way it's supposed to work? Is this exception supposed to
be some sort of marker for logging purposes? It seems like maybe the
Printexc stuff was accidentally pasted in from the
Camlp4ExceptionTracer, but without any docs, it's hard to tell for sure.

Dave

Dave Benjamin

unread,
Jul 20, 2008, 12:18:04 PM7/20/08
to blue storm, caml...@yquem.inria.fr
Thanks again for your help, blue storm. I condensed this technique into
a simple example for PLEAC, which I just committed here:

http://pleac.cvs.sourceforge.net/pleac/pleac/pleac/pleac_ocaml.data?r1=1.151&r2=1.152

It allows you to write this:

(* An example named function. *)
let test_function () =
let str = "Hello, world!" in
let num = 42 in
LOG "str=\"%s\", num=%d" str num;
print_endline "test complete"

(* Some code to run at the toplevel. *)
let () =
LOG "not in a function";
test_function ()

And get the following output:

<toplevel>[main.ml]: not in a function
test_function[main.ml]: str="Hello, world!", num=42
test complete

Regards,
Dave

blue storm

unread,
Jul 20, 2008, 1:36:03 PM7/20/08
to Dave Benjamin, caml...@yquem.inria.fr
Your combination of Profiler and Macros is really clever. I tried to do
something with macros before coming to the Profiler solution, but i didn't
work out.

This solution is elegant because it integrates well with the other
program-wide macros ( __LOCATION__ and __FILE__ ), and more powerful than
the ad-hoc __LOG__ handling.

The idea of directly modifying the decorate_this_expr declaration seemed a
little awkward at first, but it actually is as useful as the functor
solution (because all we can get anyway is the function name), while a lot
simpler. I think you could even suggest it for inclusion in the main Camlp4
distribution (it should be doable to rebuild the old Camlp4Profiler features
on top of that).

Dave Benjamin

unread,
Jul 20, 2008, 7:42:08 PM7/20/08
to blue storm, caml...@yquem.inria.fr
blue storm wrote:
> Your combination of Profiler and Macros is really clever. I tried to do
> something with macros before coming to the Profiler solution, but i
> didn't work out.

Thanks! The idea of using macros didn't occur to me until this morning.
They certainly make it easier to work within the calling function's
environment.

> This solution is elegant because it integrates well with the other
> program-wide macros ( __LOCATION__ and __FILE__ ), and more powerful
> than the ad-hoc __LOG__ handling.

Glad you think so.

> The idea of directly modifying the decorate_this_expr declaration seemed
> a little awkward at first, but it actually is as useful as the functor
> solution (because all we can get anyway is the function name), while a
> lot simpler. I think you could even suggest it for inclusion in the main
> Camlp4 distribution (it should be doable to rebuild the old
> Camlp4Profiler features on top of that).

Well, I think you had the right idea in trying to generalize the
profiler code so that it can be used for multiple purposes. I opted for
the copy-and-modify approach mainly to keep the example small. My
knowledge of camlp4 is pretty limited, and I have to admit I don't
understand much of the profiler code. It's easier to suggest a slight
modification than to write a new functor from scratch and then try to
explain it.

Exposing __FILE__ isn't quite enough to reproduce the Camlp4Profiler's
functionality, since we also need a way to trigger some code to execute
at the start of every function. Either that, or we introduce a new
keyword (say, "PROFILE"), that has to be explicitly mentioned at the top
of each function to be profiled.

0 new messages