diff options
Diffstat (limited to 'erts/doc')
-rw-r--r-- | erts/doc/src/Makefile | 15 | ||||
-rw-r--r-- | erts/doc/src/erl_nif.xml | 3 | ||||
-rw-r--r-- | erts/doc/src/erl_tracer.xml | 324 | ||||
-rw-r--r-- | erts/doc/src/erlang.xml | 46 | ||||
-rw-r--r-- | erts/doc/src/match_spec.xml | 11 | ||||
-rw-r--r-- | erts/doc/src/ref_man.xml | 1 | ||||
-rw-r--r-- | erts/doc/src/specs.xml | 1 |
7 files changed, 365 insertions, 36 deletions
diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile index e02e89238e..b96cbbce40 100644 --- a/erts/doc/src/Makefile +++ b/erts/doc/src/Makefile @@ -50,12 +50,14 @@ XML_REF1_FILES = epmd.xml \ XML_REF3_EFILES = \ erl_prim_loader.xml \ erlang.xml \ + erl_tracer.xml \ init.xml \ zlib.xml XML_REF3_FILES = \ driver_entry.xml \ erl_nif.xml \ + erl_tracer.xml \ erl_driver.xml \ erl_prim_loader.xml \ erlang.xml \ @@ -154,18 +156,9 @@ clean: rm -f $(SPECDIR)/* rm -f errs core *~ -$(SPECDIR)/specs_driver_entry.xml: +$(SPECDIR)/specs_%.xml: escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ - -o$(dir $@) -module driver_entry -$(SPECDIR)/specs_erl_nif.xml: - escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ - -o$(dir $@) -module erl_nif -$(SPECDIR)/specs_erl_driver.xml: - escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ - -o$(dir $@) -module erl_driver -$(SPECDIR)/specs_erts_alloc.xml: - escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ - -o$(dir $@) -module erts_alloc + -o$(dir $@) -module $(patsubst $(SPECDIR)/specs_%.xml,%,$@) # ---------------------------------------------------- # Release Target diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 5f56d8b595..7546f7ef81 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -566,8 +566,7 @@ typedef struct { <code type="none"> typedef void ErlNifResourceDtor(ErlNifEnv* env, void* obj); </code> - <p>The function prototype of a resource destructor function. - A destructor function is not allowed to call any term-making functions.</p> + <p>The function prototype of a resource destructor function.</p> </item> <tag><marker id="ErlNifCharEncoding"/>ErlNifCharEncoding</tag> <item> diff --git a/erts/doc/src/erl_tracer.xml b/erts/doc/src/erl_tracer.xml new file mode 100644 index 0000000000..1e8e78b25f --- /dev/null +++ b/erts/doc/src/erl_tracer.xml @@ -0,0 +1,324 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2016</year><year>2016</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + </legalnotice> + + <title>erl_tracer</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>erl_tracer</module> + <modulesummary>Erlang Tracer Behaviour</modulesummary> + <description> + <p>A behaviour module for implementing the back end of the erlang + tracing system. The functions in this module will be called whenever + a trace probe is triggered. Both the <c>enabled</c> and <c>trace</c> + functions are called in the context of the entity that triggered the + trace probe. + This means that the overhead by having the tracing enabled will be + greatly effected by how much time is spent in these functions. So do as + little work as possible in these functions.</p> + <note> + <p>All functions in this behaviour have to be implemented as NIF's. + This is a limitation that may the lifted in the future. + There is an <seealso marker="#example">example tracer module nif</seealso> + implementation at the end of this page.</p> + </note> + <warning> + <p>Do not send messages or issue port commands to the <c>Tracee</c> + in any of the callbacks. Doing so is not allowed and can cause all + sorts of strange behaviour, including but not limited to infinite + recursions.</p> + </warning> + </description> + + <datatypes> + <datatype> + <name name="trace_tag" /> + <desc> + <p>The different trace tags that the tracer will be called with. + Each trace tag is described in greater detail in + <seealso marker="#trace">Module:trace/6</seealso> + </p> + </desc> + </datatype> + <datatype> + <name name="tracee" /> + <desc> + <p>The process or port that the trace belongs to. + </p> + </desc> + </datatype> + <datatype> + <name name="trace_opts" /> + <desc> + <p>The options for the tracee. + <taglist> + <tag><c>timestamp</c></tag> + <item>If not set to <c>undefined</c>, the tracer has been requested to + include a timestamp.</item> + <tag><c>match_spec_result</c></tag> + <item>If not set to <c>true</c>, the tracer has been requested to + include the output of a match specification that was run.</item> + <tag><c>scheduler_id</c></tag> + <item>Set to a number of the scheduler id is to be included by the tracer. + Otherwise it is set to <c>undefined</c>.</item> + </taglist> + </p> + </desc> + </datatype> + <datatype> + <name name="tracer_state" /> + <desc> + <p> + The state which is given when calling + <seealso marker="erlang#trace-3"><c>erlang:trace(PidPortSpec,true,[{tracer,Module,TracerState}])</c></seealso>. + The tracer state is an immutable value that is passed to erl_tracer callbacks and should + contain all the data that is needed to generate the trace event. + </p> + </desc> + </datatype> + </datatypes> + + <section> + <title>CALLBACK FUNCTIONS</title> + <p>The following functions + should be exported from a <c>erl_tracer</c> callback module.</p> + </section> + <marker id="enabled"></marker> + <funcs> + <func> + <name>Module:enabled(TraceTag, TracerState, Tracee) -> Result</name> + <fsummary>Check if a trace event should be generated.</fsummary> + <type> + <v>TraceTag = <seealso marker="#type-trace_tag">trace_tag()</seealso> | trace_status</v> + <v>TracerState = term()</v> + <v>Tracee = <seealso marker="#type-trace_tag">tracee()</seealso></v> + <v>Result = trace | discard | remove</v> + </type> + <desc> + <p>This callback will be called whenever a trace point is triggered. It + allows the tracer to decide whether a trace should be generated or not. + This check is made as early as possible in order to limit the amount of + overhead associated with tracing. If <c>trace</c> is returned the + necessary trace data will be created and the trace call-back of the tracer + will be called. If <c>discard</c> is returned, this trace call + will be discarded and no call to trace will be done. If + <c>remove</c> is returned, the VM will attempt to remove this tracer + from the tracee, together with any trace flags set on the tracee. + </p> + <p><c>trace_status</c> is a special type of <c>TraceTag</c> which is used + to check if the tracer should still be active. It is called in multiple + scenarios, but most significantly it is used when tracing is started + using this tracer.</p> + <p>This function may be called multiple times per trace point, so it + is important that it is both fast and side effect free.</p> + </desc> + </func> + <marker id="trace"></marker> + <func> + <name>Module:trace(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name> + <fsummary>Check if a trace event should be generated.</fsummary> + <type> + <v>TraceTag = <seealso marker="#type-trace_tag">trace_tag()</seealso></v> + <v>TracerState = term()</v> + <v>Tracee = <seealso marker="#type-trace_tag">tracee()</seealso></v> + <v>FirstTraceTerm = term()</v> + <v>SecondTraceTerm = term() | undefined</v> + <v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v> + <v>Result = ok</v> + </type> + <desc> + <p>This callback will be called when a trace point is triggered and + the <seealso marker="#enabled">Module:enabled/3</seealso> + callback returned <c>trace</c>. In it any side effects needed by + the tracer should be done. The trace point payload is located in + the <c>FirstTraceTerm</c> and <c>SecondTraceTerm</c>. The content + of the TraceTerms depends on which <c>TraceTag</c> has been triggered. + The <c>FirstTraceTerm</c> and <c>SecondTraceTerm</c> correspond to the + fourth and fifth slot in the trace tuples described in + <seealso marker="erlang#trace_3_trace_messages">erlang:trace/3</seealso>. + If the tuple only has four elements, <c>SecondTraceTerm</c> will be + <c>undefined</c>.</p> + </desc> + </func> + <func> + <name name="trace">Module:trace(seq_trace, TracerState, Label, SeqTraceInfo, undefined, Opts) -> Result</name> + <fsummary>Check if a sequence trace event should be generated.</fsummary> + <type> + <v>TracerState = term()</v> + <v>Label = term()</v> + <v>SeqTraceInfo = term()</v> + <v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v> + <v>Result = ok</v> + </type> + <desc> + <p>The <c>TraceTag</c> <c>seq_trace</c> is handled a little bit + differently. There is not <c>Tracee</c> for seq_trace, instead the + <c>Label</c> associated with the seq_trace event is given. + For more info on what <c>Label</c> and <c>SeqTraceInfo</c> can be + see the <seealso marker="kernel:seq_trace">seq_trace</seealso> manual.</p> + </desc> + </func> + </funcs> + <section> + <marker id="example"></marker> + <title>Erl Tracer Module example</title> + <p>In the example below a tracer module with a nif backend sends a message + for each <c>send</c> trace tag containing only the sender and receiver. + Using this tracer module, a much more lightweight message tracer is + used that only records who sent messages to who.</p> + <p>Here is an example session using it on Linux.</p> + <pre> +$ gcc -I erts-8.0/include/ -fPIC -shared -o erl_msg_tracer.so erl_msg_tracer.c +$ erl +Erlang/OTP 19 [DEVELOPMENT] [erts-8.0] [source-ed2b56b] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] + +Eshell V8.0 (abort with ^G) +1> c(erl_msg_tracer), erl_msg_tracer:load(). +ok +2> Tracer = spawn(fun F() -> receive M -> io:format("~p~n",[M]), F() end end). +<0.37.0> +3> erlang:trace(new, true, [send,{tracer, erl_msg_tracer, Tracer}]). +0 +{<0.39.0>,<0.27.0>} +4> {ok, D} = file:open("/tmp/tmp.data",[write]). +{trace,#Port<0.486>,<0.40.0>} +{trace,<0.40.0>,<0.21.0>} +{trace,#Port<0.487>,<0.4.0>} +{trace,#Port<0.488>,<0.4.0>} +{trace,#Port<0.489>,<0.4.0>} +{trace,#Port<0.490>,<0.4.0>} +{ok,<0.40.0>} +{trace,<0.41.0>,<0.27.0>} +5> + </pre> + <p>erl_msg_tracer.erl</p> + <pre> +-module(erl_msg_tracer). + +-export([enabled/3, trace/6, load/0]). + +load() -> + erlang:load_nif("erl_msg_tracer", []). + +enabled(_, _, _) -> + error. + +trace(_, _, _,_, _, _) -> + error. + </pre> + <p>erl_msg_tracer.c</p> + <pre> +#include "erl_nif.h" + +/* NIF interface declarations */ +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info); +static void unload(ErlNifEnv* env, void* priv_data); + +/* The NIFs: */ +static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + +static ErlNifFunc nif_funcs[] = { + {"enabled", 3, enabled}, + {"trace", 6, trace} +}; + +ERL_NIF_INIT(erl_msg_tracer, nif_funcs, load, NULL, upgrade, unload) + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + *priv_data = NULL; + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, + ERL_NIF_TERM load_info) +{ + if (*old_priv_data != NULL || *priv_data != NULL) { + return -1; /* Don't know how to do that */ + } + if (load(env, priv_data, load_info)) { + return -1; + } + return 0; +} + +/* + * argv[0]: Trace Tag + * argv[1]: TracerState + * argv[2]: Tracee + */ +static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifPid to_pid; + if (enif_get_local_pid(env, argv[1], &to_pid)) + if (!enif_is_process_alive(env, &to_pid)) + /* tracer is dead so we should remove this trace point */ + return enif_make_atom(env, "remove"); + + /* Only generate trace for when tracer != tracee */ + if (enif_is_identical(argv[1], argv[2])) + return enif_make_atom(env, "discard"); + + /* Only trigger trace messages on 'send' */ + if (enif_is_identical(enif_make_atom(env, "send"), argv[0])) + return enif_make_atom(env, "trace"); + + /* Have to answer trace_status */ + if (enif_is_identical(enif_make_atom(env, "trace_status"), argv[0])) + return enif_make_atom(env, "trace"); + + return enif_make_atom(env, "discard"); +} + +/* + * argv[0]: Trace Tag, should only be 'send' + * argv[1]: TracerState, process to send {argv[2], argv[4]} to + * argv[2]: Tracee + * argv[3]: Message, ignored + * argv[4]: Recipient + * argv[5]: Options, ignored + */ +static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifPid to_pid; + + if (enif_get_local_pid(env, argv[1], &to_pid)) { + ERL_NIF_TERM msg = enif_make_tuple3(env, enif_make_atom(env, "trace"), argv[2], argv[4]); + enif_send(env, &to_pid, NULL, msg); + } + + return enif_make_atom(env, "ok"); +} + </pre> + </section> +</erlref> diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index ef577c82bf..86bdb1dfe6 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -8371,7 +8371,7 @@ timestamp() -> <taglist> <tag><c>all</c></tag> <item> - <p>Sets all trace flags except <c>{tracer, Tracer}</c> and + <p>Sets all trace flags except <c>tracer</c> and <c>cpu_timestamp</c>, which are in their nature different than the others.</p> </item> @@ -8529,12 +8529,20 @@ timestamp() -> <item> <p>Specifies where to send the trace messages. <c>Tracer</c> must be the process identifier of a local process - or the port identifier - of a local port. If this flag is not given, trace - messages are sent to the process that called - <c>erlang:trace/3</c>.</p> + or the port identifier of a local port.</p> + </item> + <tag><c>{tracer, TracerModule, TracerState}</c></tag> + <item> + <p>Specifies that a tracer module should be called + instead of sending a trace message. The tracer module + can then ignore or change the trace message. For more details + on how to write a tracer module see <seealso marker="erl_tracer"> + erl_tracer</seealso> + </p> </item> </taglist> + <p>If no <c>tracer</c> is given, the calling process + will be receiving all of the trace messages</p> <p>The effect of combining <c>set_on_first_link</c> with <c>set_on_link</c> is the same as having <c>set_on_first_link</c> alone. Likewise for @@ -8706,9 +8714,9 @@ timestamp() -> garbage collection.</p> </item> </taglist> - <p>If the tracing process dies, the flags are silently - removed.</p> - <p>Only one process can trace a particular process. Therefore, + <p>If the tracing process/port dies or the tracer module returns + <c>remove</c>, the flags are silently removed.</p> + <p>Each process can only be traced by one tracer. Therefore, attempts to trace an already traced process fail.</p> <p>Returns: A number indicating the number of processes that matched <c><anno>PidSpec</anno></c>. @@ -8716,7 +8724,7 @@ timestamp() -> identifier, the return value is <c>1</c>. If <c><anno>PidSpec</anno></c> is <c>all</c> or <c>existing</c>, the return value is - the number of processes running, excluding tracer processes. + the number of processes running. If <c><anno>PidSpec</anno></c> is <c>new</c>, the return value is <c>0</c>.</p> <p>Failure: <c>badarg</c> if the specified arguments are @@ -8750,7 +8758,7 @@ timestamp() -> has not been traced by someone, but if this is the case, <em>no</em> trace messages have been delivered when the <c>trace_delivered</c> message arrives.</p> - <p>Notice that that <c><anno>Tracee</anno></c> must refer + <p>Notice that <c><anno>Tracee</anno></c> must refer to a process currently, or previously existing on the same node as the caller of <c>erlang:trace_delivered(<anno>Tracee</anno>)</c> resides on. @@ -8801,7 +8809,8 @@ timestamp() -> </item> <tag><c>tracer</c></tag> <item> - <p>Returns the identifier for process or port tracing this + <p>Returns the identifier for process, port or a tuple containing + the tracer module and tracer state tracing this process. If this process is not being traced, the return value is <c>[]</c>.</p> </item> @@ -8830,8 +8839,8 @@ timestamp() -> </item> <tag><c>meta</c></tag> <item> - <p>Returns the meta-trace tracer process or port for this - function, if it has one. If the function is not + <p>Returns the meta-trace tracer process, port or trace module + for this function, if it has one. If the function is not meta-traced, the returned value is <c>false</c>. If the function is meta-traced but has once detected that the tracer process is invalid, the returned value is [].</p> @@ -8999,13 +9008,12 @@ timestamp() -> the process, a <c>return_to</c> message is also sent when this function returns to its caller.</p> </item> - <tag><c>meta | {meta, <anno>Pid</anno>}</c></tag> + <tag><c>meta | {meta, <anno>Pid</anno>} | {meta, <anno>TracerModule</anno>, <anno>TracerState</anno>}</c> + </tag> <item> <p>Turns on or off meta-tracing for all types of function - calls. Trace messages are sent to the tracer process - or port <c><anno>Pid</anno></c> whenever any of the specified - functions are called, regardless of how they are called. - If no <c><anno>Pid</anno></c> is specified, + calls. Trace messages are sent to the tracer whenever any of + the specified functions are called. If no tracer is specified, <c>self()</c> is used as a default tracer process.</p> <p>Meta-tracing traces all processes and does not care about the process trace flags set by <c>trace/3</c>, @@ -9013,7 +9021,7 @@ timestamp() -> <c>[call, timestamp]</c>.</p> <p>The match specification function <c>{return_trace}</c> works with meta-trace and sends its trace message to the - same tracer process.</p> + same tracer.</p> </item> <tag><c>call_count</c></tag> <item> diff --git a/erts/doc/src/match_spec.xml b/erts/doc/src/match_spec.xml index 975f01cf2c..b49e1483aa 100644 --- a/erts/doc/src/match_spec.xml +++ b/erts/doc/src/match_spec.xml @@ -287,7 +287,7 @@ can <em>not</em> be one of the atoms <c><![CDATA[all]]></c>, <c><![CDATA[new]]></c> or <c><![CDATA[existing]]></c> (unless, of course, they are registered names). <c><![CDATA[P2]]></c> can <em>not</em> be <c><![CDATA[cpu_timestamp]]></c> nor - <c><![CDATA[{tracer,_}]]></c>. + <c><![CDATA[tracer]]></c>. Returns <c><![CDATA[true]]></c> and may only be used in the <c><![CDATA[MatchBody]]></c> part when tracing. </p> @@ -298,7 +298,7 @@ be either a process identifier or a registered name and is given as the first argument to the match_spec function. <c><![CDATA[P2]]></c> can <em>not</em> be <c><![CDATA[cpu_timestamp]]></c> nor - <c><![CDATA[{tracer,_}]]></c>. Returns + <c><![CDATA[tracer]]></c>. Returns <c><![CDATA[true]]></c> and may only be used in the <c><![CDATA[MatchBody]]></c> part when tracing. </p> @@ -308,11 +308,14 @@ disable list is applied first, but effectively all changes are applied atomically. The trace flags are the same as for <c><![CDATA[erlang:trace/3]]></c> not including - <c><![CDATA[cpu_timestamp]]></c> but including <c><![CDATA[{tracer,_}]]></c>. If a + <c><![CDATA[cpu_timestamp]]></c> but including <c><![CDATA[tracer]]></c>. If a tracer is specified in both lists, the tracer in the enable list takes precedence. If no tracer is specified the same tracer as the process executing the match spec is - used. With three parameters to this function the first is + used. When using a <seealso marker="erl_tracer">tracer module</seealso> + the module has to be loaded before the match specification is executed. + If it is not loaded the match will fail. + With three parameters to this function the first is either a process identifier or the registered name of a process to set trace flags on, the second is the disable list, and the third is the enable list. Returns diff --git a/erts/doc/src/ref_man.xml b/erts/doc/src/ref_man.xml index aa245ec08a..e45402a397 100644 --- a/erts/doc/src/ref_man.xml +++ b/erts/doc/src/ref_man.xml @@ -56,5 +56,6 @@ <xi:include href="driver_entry.xml"/> <xi:include href="erts_alloc.xml"/> <xi:include href="erl_nif.xml"/> + <xi:include href="erl_tracer.xml"/> </application> diff --git a/erts/doc/src/specs.xml b/erts/doc/src/specs.xml index 41a3984659..ed6be650e5 100644 --- a/erts/doc/src/specs.xml +++ b/erts/doc/src/specs.xml @@ -2,6 +2,7 @@ <specs xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include href="../specs/specs_erl_prim_loader.xml"/> <xi:include href="../specs/specs_erlang.xml"/> + <xi:include href="../specs/specs_erl_tracer.xml"/> <xi:include href="../specs/specs_init.xml"/> <xi:include href="../specs/specs_zlib.xml"/> </specs> |