[ Reference Manual | Alphabetic Index ]

library(instrument)

Generic tool for code instrumentation   [more]

Predicates

defined_modules(+File, -Modules)
Retrieve the modules defined by a file.
erase_all_templates
Erase all instrument template stores.
erase_file_templates(+File)
Erase the file local instrument template store for a specific file.
erase_module_templates
Erase all instrument template stores for a specific module.
file_callsites(+File, ?StartId, ?EndId)
Retrieve start and end callsite identifiers for named file.
file_result(+File)
Pretty-print a file, including any instrumentation results
file_result(+File, +OptionList)
Pretty-print a file, including any instrumentation results
get_callsite_data(+SiteId, ?UserData)
Retrieve data associated with an instrumentation callsite from its non-logical store.
instrument(+File, +ITemplates)
Compile a file, inserting predicate instrumentation
instrument(+File, +ITemplates, +OptionList)
Compile a file, inserting predicate instrumentation
instrument_control(+Mode, +InstrumentPredSpec)
Insert or remove instrumentation predicates dynamically at runtime.
module_callsites(?StartId, ?EndId)
Retrieve module start and end callsite identifiers.
module_result
Pretty-print all files in a module, including any instrumentation results
module_result(+OptionList)
Pretty-print all files in a module, including any instrumentation results
set_callsite_data(+SiteId, ?UserData)
Associate arbitrary data with an instrumentation callsite in a non-logical store.

Structures

struct itemplate(clause_start, clause_end, clause_fail, clause_redo, block_start, block_end, block_fail, block_redo, subgoal_start, subgoal_end, subgoal_fail, subgoal_redo, call_start, call_end, call_fail, call_redo, fact, inbetween, result, meta_args, exclude, code_weaver, asserted, module_scope, file_local, goal_expansion)
The template used to guide predicate instrumentation

Description

The instrument library is a tool that enables predicate definitions or all calls to a specific predicate to be annotated with user-defined predicates. These instrumentation predicates are free to perform such actions as collect program statistics or write debugging data to a stream during program execution. Additionally, the instrumentation can be inserted and removed dynamically as the program executes.

The usage is as follows:

  1. Load the instrument library
       ?- lib(instrument).
       
  2. Compile your program with the instrument compiler
       ?- instrument:instrument(my_program, Templates).
       
  3. Run the query for which you wish to generate instrumentation data
       ?- my_query(X,Y,Z).
       
  4. Generate an html file containing the results. E.g. the following will create the result file instrument/my_program.html:
       ?- instrument:results(my_program).
       
  5. View the result file using any browser. The result file contains a pretty-printed form of the source, annotated with the instrumentation results.

The following is an example of very basic use of the tool. Consider instrumenting a simple path finding program saved in a file called 'instrument_example.ecl.

   list_member(X, [X | _Tail]).
   list_member(X, [_ | Tail]):-
   list_member(X, Tail).
 
   all_edges(Graph, Source, Outgoing):-
       findall((Source-Next),list_member((Source-Next), Graph), Outgoing).
 
   path(_Graph, Source, Source, []).
   path(Graph, Source, Sink, [(Source-Next) | Path]):-
       all_edges(Graph, Source, Outgoing),
       list_member((Source-Next), Outgoing),
       path(Graph, Next, Sink, Path).
 
   test(Path):-
       path([1-2, 1-3, 2-4, 3-4, 4-5, 4-6, 5-7, 5-8, 6-7,
             1-8, 8-9, 8-10, 9-10, 9-11, 10-11],
             1,
             7,
             Path).
   
The simplest way to instrument your code is to insert predicates around every call in the source. The following code demonstrates how to print the CPU time before and after every predicate call:
   get_time(Cpu):-
       statistics(times, [Cpu, _Sys, _Real]).
 
   time_point:-
       get_time(T),
       writeln(error, T).
 
   go:-
       File = instrument_example,
       GlobalTemplate = itemplate{subgoal_start:time_point/0,
                                         subgoal_end:time_point/0},
       instrument(File, GlobalTemplate),
       test(Path).
   
Note the same predicate time_point/0 is specified before and after goal calls. If we wished to instrument all calls except those to list_member/2, the following call to instrument/2 is made:
        instrument(File, GlobalTemplate - [list_member/2])
   
In general any number of goals may be specified in this 'exclusion list'.

The following code demonstrates alternative instrumentation for this excluded predicate:

   :-lib(instrument).

   :-export time_point/0, special_point/0.

   get_time(Cpu):-
       statistics(times,[Cpu, _Sys, _Real]).        

   time_point:-
       get_time(T),
       writeln(error, T).

   special_point:-
       writeln(error, 'start, end, redo or fail').

   go:-
       File = instrument_example,
       GlobalTemplate = itemplate{subgoal_start:time_point/0,
                                        subgoal_end:time_point/0},
       SpecialTemplate = itemplate{call_start:special_point/0,
                                         call_end:special_point/0,
                                         call_fail:special_point/0
                                         call_redo:special_point/0},
       instrument(File,[GlobalTemplate - [list_member/2],
                        (list_member/2) = SpecialTemplate]),
       test(Path).
   
Notice how the special_point/0 predicate is assigned to the call_start, call_end, call_fail and call_redo points in this example. This ensures that the special_point predicate is called if list_member/2 fails, or if resatisfiable, executed at the redo.

Using arity-1 predicates (i.e. one argument predicates) unique identification of the callsite can be obtained:

   :-lib(instrument).

   get_time(Cpu):-
       statistics(times, [Cpu, _Sys, _Real]).        

   time_point(CallSite):-
       get_time(T),
       writeln(error,['Time', T, 'at callsite', CallSite]).

   go:-
       File = instrument_example,
       GlobalTemplate = itemplate{subgoal_start:time_point/1,
                                        subgoal_end:time_point/1},
       instrument(File, GlobalTemplate),
       test(Path).
   

By supplying a predicate to the result field of a template one can specify terms to be printed within a copy of the source code. Using this feature along with the utility predicates get_callsite_data/2 and set_callsite_data/2 one can create quite varied and useful output.

   :-lib(instrument).

   get_time(Cpu):-
       statistics(times, [Cpu, _Sys, _Real]).        

   time_point(CallSite):-
       get_time(T),
       set_callsite_data(CallSite, T).

   result(CallSite, _Type, _Module, Goal, NewGoal):-
       get_callsite_data(CallSite, Time),
       NewGoal='instrument:point_before'(Time, Goal).
   go:-
       File = instrument_example,
       GlobalTemplate = itemplate{subgoal_start:time_point/1,
                                        result:result/5},
       instrument(File, GlobalTemplate),
       test(Path),
       file_result(File).
   
No data is printed during the running of the test(Path) call, but the file_result(File) call causes the source code to be emitted (color coded) with the given callsite data embedded.

About


Generated from instrument.eci on 2022-09-03 14:26