1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2019-2023, CWI, Amsterdam 7 SWI-Prolog Solutions b.v. 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 17 2. Redistributions in binary form must reproduce the above copyright 18 notice, this list of conditions and the following disclaimer in 19 the documentation and/or other materials provided with the 20 distribution. 21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34*/ 35 36:- module(prolog_trace, 37 [ trace/1, % :Spec 38 trace/2, % :Spec, +Ports 39 tracing/2, % :Spec, -Ports 40 list_tracing/0, 41 notraceall/0 42 ]). 43:- autoload(library(apply),[maplist/2]). 44:- autoload(library(error),[instantiation_error/1]). 45:- autoload(library(prolog_wrap),[wrap_predicate/4]). 46:- autoload(library(prolog_code), [pi_head/2]).
58:- meta_predicate 59 trace( ), 60 trace( , ), 61 tracing( , ). 62 63:- dynamic tracing_mask/2. 64:- volatile tracing_mask/2.
Module:Name/Arity
(or `//Arity for non-terminals),
both the module and arity may be omitted in which case Pred refers
to all matching predicates. PortSpec is either a single port
(call
, exit
, fail
or redo
), preceded with +
or -
or a
list of these. The predicate modifies the current trace
specification and then installs a suitable wrapper for the predicate
using wrap_predicate/4. For example:
?- trace(append). % lists:append/2: [all] % lists:append/3: [all] % append/1: [all] true. ?- append([a,b], [c], L). T [10] Call: lists:append([a, b], [c], _18032) T [19] Call: lists:append([b], [c], _19410) T [28] Call: lists:append([], [c], _20400) T [28 +0.1ms] Exit: lists:append([], [c], [c]) T [19 +0.2ms] Exit: lists:append([b], [c], [b, c]) T [10 +0.5ms] Exit: lists:append([a, b], [c], [a, b, c]) L = [a, b, c]. ?- trace(append, -all). % lists:append/2: Not tracing % lists:append/3: Not tracing % append/1: Not tracing
The text between [] indicates the call depth (first number) and for
all ports except the call
port the wall time since the start
(call port) in milliseconds. Note that the instrumentation and print
time is included in the time. In the example above the actual time
is about 0.00001ms on todays hardware.
108trace(Pred) :- 109 trace(Pred, +all). 110 111trace(Pred, Spec) :- 112 '$find_predicate'(Pred, Preds), 113 Preds \== [], 114 maplist(set_trace(Spec), Preds). 115 116set_trace(Spec, Pred) :- 117 ( tracing_mask(Pred, Spec0) 118 -> true 119 ; Spec0 = 0 120 ), 121 modify(Spec, Spec0, Spec1), 122 retractall(tracing_mask(Pred, _)), 123 ( Spec1 == [] ; Spec1 == 0 124 -> true 125 ; asserta(tracing_mask(Pred, Spec1)) 126 ), 127 mask_ports(Spec1, Ports), 128 pi_head(Pred, Head0), 129 ( predicate_property(Head0, imported_from(M)) 130 -> requalify(Head0, M, Head) 131 ; Head = Head0 132 ), 133 ( Spec1 == 0 134 -> unwrap_predicate(Head, trace), 135 print_message(informational, trace(Head, Ports)) 136 ; wrapper(Spec1, Head, Wrapped, Wrapper), 137 wrap_predicate(Head, trace, Wrapped, Wrapper), 138 print_message(informational, trace(Head, Ports)) 139 ). 140 141requalify(Term, M, M:Plain) :- 142 strip_module(Term, _, Plain). 143 144modify(Var, _, _) :- 145 var(Var), 146 !, 147 instantiation_error(Var). 148modify([], Spec, Spec) :- 149 !. 150modify([H|T], Spec0, Spec) :- 151 !, 152 modify(H, Spec0, Spec1), 153 modify(T, Spec1, Spec). 154modify(+Port, Spec0, Spec) :- 155 !, 156 port_mask(Port, Mask), 157 Spec is Spec0 \/ Mask. 158modify(-Port, Spec0, Spec) :- 159 !, 160 port_mask(Port, Mask), 161 Spec is Spec0 /\ \Mask. 162modify(Port, Spec0, Spec) :- 163 port_mask(Port, Mask), 164 Spec is Spec0 \/ Mask. 165 166port_mask(all, 0x0f). 167port_mask(call, 0x01). 168port_mask(exit, 0x02). 169port_mask(redo, 0x04). 170port_mask(fail, 0x08). 171 172mask_ports(0, []) :- 173 !. 174mask_ports(Pattern, [H|T]) :- 175 is_masked(Pattern, H, Pattern1), 176 mask_ports(Pattern1, T). 177 178wrapper(Ports, Head, Wrapped, Wrapper) :- 179 wrapper(Ports, Head, 180 #{frame:Frame, level:Level, start:Start}, 181 Wrapped, Wrapped1), 182 Wrapper = ( prolog_current_frame(Frame), 183 prolog_frame_attribute(Frame, level, Level), 184 get_time(Start), 185 Wrapped1 186 ). 187 188wrapper(0, _, _, Wrapped, Wrapped) :- 189 !. 190wrapper(Pattern, Head, Id, Wrapped, Call) :- 191 is_masked(Pattern, call, Pattern1), 192 !, 193 wrapper(Pattern1, Head, Id, Wrapped, Call0), 194 Call = ( print_message(debug, frame(Head, trace(call, Id))), 195 Call0 196 ). 197wrapper(Pattern, Head, Id, Wrapped, Call) :- 198 is_masked(Pattern, exit, Pattern1), 199 !, 200 wrapper(Pattern1, Head, Id, Wrapped, Call0), 201 Call = ( Call0, 202 print_message(debug, frame(Head, trace(exit, Id))) 203 ). 204wrapper(Pattern, Head, Id, Wrapped, Call) :- 205 is_masked(Pattern, redo, Pattern1), 206 !, 207 wrapper(Pattern1, Head, Id, Wrapped, Call0), 208 Call = ( call_cleanup(Call0, Det = true), 209 ( Det == true 210 -> true 211 ; true 212 ; print_message(debug, frame(Head, trace(redo, Id))), 213 fail 214 ) 215 ). 216wrapper(Pattern, Head, Id, Wrapped, Call) :- 217 is_masked(Pattern, fail, Pattern1), 218 !, 219 wrapper(Pattern1, Head, Id, Wrapped, Call0), 220 Call = call(( call_cleanup(Call0, Det = true), 221 ( Det == true 222 -> ! 223 ; true 224 ) 225 ; print_message(debug, frame(Head, trace(fail, Id))), 226 fail 227 )). 228 229is_masked(Pattern0, Port, Pattern) :- 230 port_mask(Port, Mask), 231 Pattern0 /\ Mask =:= Mask, 232 !, 233 Pattern is Pattern0 /\ \Mask.
239tracing(Spec, Ports) :-
240 tracing_mask(Spec, Mask),
241 mask_ports(Mask, Ports).
247list_tracing :- 248 PI = _:_, 249 findall(trace(Head, Ports), (tracing(PI, Ports), pi_head(PI, Head)), Tracing), 250 print_message(informational, tracing(Tracing)). 251 252:- multifile 253 prolog_debug_tools:debugging_hook/0. 254 255prolog_debug_toolsdebugging_hook :- 256 ( tracing(_:_, _) 257 -> list_tracing 258 ).
265notraceall :-
266 forall(tracing(M:Spec, _Ports),
267 trace(M:Spec, -all))
Print access to predicates
This library prints accesses to specified predicates by wrapping the predicate.