:- module(port_profiler).
:- export port_profile / 2.
:- tool(port_profile / 2, port_profile_ / 3).
:- export port_profile / 1.
:- export last_port_profile / 1.
:- comment(categories, ["Development Tools"]).
:- comment(summary, "Port Counting Profiler").
:- comment(author, "Joachim Schimpf, IC-Parc").
:- comment(copyright, "Cisco Systems, Inc").
:- comment(date, "$Date: 2012/02/06 13:24:43 $").
:- comment(desc, html("<P>\n    This is a performance analysis tool based on counting of events during\n    program execution. The events that are counted are defined in terms\n    of the 'box model' of execution (the same model that the debugger uses).\n    In this box model, predicates are entered though call, redo or resume\n    ports, and exited through exit, fail or leave ports. In addition, other\n    interesting events are indicated by ports as well (next, else, delay).\n    </P><P>\n    The usage is as follows:\n    <OL>\n    <LI>Compile your program in debug mode, as you would normally do during\n    program development, e.g.\n    <PRE>\n    \t?- compile(queen).\n    </PRE>\n    <LI>Load the port_profiler library\n    <PRE>\n    \t?- lib(port_profiler).\n    </PRE>\n    <LI>Run the query which you want to examine, using port_profile/2:\n    <PRE>\n    \t?- port_profile(queen([1,2,3,4],Out), []).\n    </PRE>\n    This will print the results in a table.\n    </OL>\n    The default output you get looks like this:\n    <PRE>\n\tPREDICATE       CALLER               call     exit     fail    *exit     redo\n\tstore_set   /3  nodiag      /3        106      106        .        .        .\n\t-           /3  nodiag      /3         46       46        .        .        .\n\t=\\=         /2  nodiag      /3         46       45        1        .        .\n\tqperm       /2  qperm       /2         30       28        .       16       14\n\tqdelete     /4  qperm       /2         20       18        .       12       10\n\tnodiag      /3  nodiag      /3         17       14        3        .        .\n\tnodiag      /3  safe        /1         17        7       10        .        .\n\t+           /3  nodiag      /3         17       17        .        .        .\n\tqdelete     /4  qdelete     /4         10        9        .        3        2\n\tqperm       /2  queen       /2          1        .        .       11       10\n\tsafe        /1  queen       /2         11        1       10        .        .\n\tsafe        /1  safe        /1          7        4        3        .        .\n\tqueen       /2  trace_body  /2          1        .        .        1        .\n    </PRE>\n    The port counts give information about\n    <UL>\n    <LI>what are the most frequently called predicates (call ports)\n    <LI>whether predicates failed unexpectedly (fail ports)\n    <LI>whether predicates exited nondeterministically (*exit ports), i.e.\n    \twhether they left behind any choice-points for backtracking.\n    <LI>whether nondeterministically exited predicates were ever re-entered\n\tto find alternative solutions (redo ports).\n    <LI>whether predicates did internal backtracking (next ports) in order\n    \tto find the right clause. This may indicate suboptimal indexing.\n    <LI>how often predicates were delayed and resumed.\n    </UL>\n    By default, statistics are collected separately for each predicate-caller\n    pair, i.e. multiple lines appear for a predicate when it is called from\n    different caller predicates. This feature can be disabled so that predicates\n    are not distingushed by their caller. It is also possible to restrict\n    data collection to predicates with a spy point only (less time consuming).\n    </P><P>\n    Other options allow output in different formats, e.g. as an html file,\n    with a subset or different order of the ports, or with module information.\n    For details, see the description of port_profile/2.\n    </P><P>\n    Related, but different tools are:\n    <UL>\n    <LI>The sampling profiler (profile/1,2 from lib(profile)): this works\n\teven on optimized, non-traceable code and gives timing information.\n\tIt does not give information about the caller predicate.\n    <LI>The coverage analyzer (see lib(coverage)): this is also based on\n\tcounting, but has counters for every program point and is probably\n\tless useful for performance analysis.\n    </UL>\n</P>")).
:- comment(last_port_profile / 1, [amode : last_port_profile(++), args : ["Options" : "A list of OptionName:OptionValue structures"], see_also : [port_profile / 2], summary : "Output another port profile for the most recently profiled goal", desc : html("    This allows to output (again) the results of the previous call to\n    port_profile/2, possibly in a different format. The options are\n    the same as in port_profile/2. Note that the show_caller option can\n    only be given if it was on in the corresponding call to port_profile/2,\n    otherwise the corresponding information is not available.\n    ")]).
:- comment(port_profile / 2, [amode : port_profile(+, ++), args : ["Goal" : "A callable goal (atom or compound term)", "Options" : "A list of OptionName:OptionValue structures"], see_also : [library(port_profiler), library(coverage), profile / 1, last_port_profile / 1], summary : "Create a (box model) port profile for the given Goal execution", desc : html("    \tExecutes Goal and creates a (box model) port profile for this execution.\n\tThe ports are the ports as defined for the debugger's box model and\n\tinclude:\n\t<DL>\n\t<DT>call</DT> <DD>predicate invocation</DD>\n\t<TR>\n\t<DT>exit</DT> <DD>deterministic predicate success</DD>\n\t</TR>\n\t<TR>\n\t<DT>fail</DT> <DD>predicate failure</DD>\n\t</TR>\n\t<TR>\n\t<DT>*exit</DT> <DD>nondeterministic predicate success</DD>\n\t</TR>\n\t<TR>\n\t<DT>redo</DT> <DD>reentering a predicate on backtracking</DD>\n\t</TR>\n\t<TR>\n\t<DT>next</DT> <DD>going to the next clause of a predicate</DD>\n\t</TR>\n\t<TR>\n\t<DT>else</DT> <DD>going to an alternative within a predicate</DD>\n\t</TR>\n\t<TR>\n\t<DT>leave</DT> <DD>leaving a predicate with throw/1</DD>\n\t</TR>\n\t<TR>\n\t<DT>delay</DT> <DD>delaying a predicate</DD>\n\t</TR>\n\t<TR>\n\t<DT>resume</DT> <DD>reentering a predicate on waking</DD>\n\t</TR>\n\t</DL>\n\t<P>\n    \tThe available options are:\n\t<DL>\n\t<DT>format (default:txt)</DT> <DD>output format, txt or html</DD>\n\t    <DL>\n\t    <DT>txt</DT> <DD>prints an ascii table, taking width-option into account</DD>\n\t    <DT>html</DT> <DD>prints an html table, taking border-option into account</DD>\n\t    <DT>raw</DT> <DD>prints the raw results as lines of the form\n\t\t<PRE>\n\t\t[M:F/A from PM:PF/PA, Port, Count].\n\t\t</PRE>\n\t\tif the show_caller-option is on, and\n\t\t<PRE>\n\t\t[M:F/A, Port, Count].\n\t\t</PRE>\n\t\tif the show_caller-option is off. These are valid Prolog\n\t\tterms which can be read back using read/2.\n\t    </DD>\n\t    </DL>\n\t<DT>border (default:0)</DT> <DD>table border width for html output</DD>\n\t<DT>output (default:default)</DT><DD>\n\t    where to put the result: possible values are\n\t    <DL>\n\t    <DT>file(File)</DT> <DD>where File is a file name</DD>\n\t    <DT>stream(Stream)</DT> <DD>where Stream is an Eclipse stream identifier</DD>\n\t    <DT>dir(Dir)</DT> <DD>where Dir is a directory in which files with generated names will be placed</DD>\n\t    <DT>default</DT> <DD>either dir(profiler) for html format, or stream(output) otherwise</DD>\n\t    </DL>\n\t    </DD>\n\t<DT>ports (default:all)</DT> <DD>the atom 'all' or a list of port names</DD>\n\t<DT>predicates (default:all)</DT> <DD>the atom 'all' or 'spied_only'.\n\t    The latter means that only predicates with a spy point have their\n\t    ports counted.</DD>\n\t<DT>show_caller (default:on)</DT> <DD>whether to show and distinguish\n\t    predicates by their calling predicate (on or off). This is the\n\t    only option that affects data collection as well as presentation.</DD>\n\t<DT>show_module (default:off)</DT> <DD>whether to show the predicate's\n\t    definition modules in the output table (on or off)</DD>\n\t<DT>width (default:80)</DT> <DD>page width for txt output</DD>\n\t</DL>\n\tNote: Any choicepoints that are left behind by Goal will be cut, i.e.\n\tport_profile/2 behaves like once/1.\n    ")]).
