<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class="">Kenneth, Rickard,</div><div class=""><br class=""></div><div class="">Let me give you a bit of context. </div><div class=""><br class=""></div><div class="">I’m working on a runtime verification (RV) tool that focusses on components systems in an asynchronous setting. I’ve chosen Erlang because it nicely models this setting and also facilitates certain aspects in the development of said tool. Very briefly, in RV, the concept is that of instrumenting the system with other processes (called monitors in the RV community, but have nothing to do with Erlang monitors) that analyse the parts of the system (e.g., one process or a group of them, which I will refer to as a "system component") to detect and flag the infringement of some property specified over the component.</div><div class=""><br class=""></div><div class="">These properties (which are written using a high-level logic such as Linear Temporal Logic, Hennessy-Milner Logic, etc.), define things like “Process P cannot send message M to Q when such and such condition arises” or “Process P must exit when a particular message M is sent to it”, etc. A monitor, or rather, the monitor source code, is synthesised from a property and “attached” to the component to be monitored. The following is more or less the general workflow:</div><div class=""><br class=""></div><div class="">1. A property is written in a text file using one of the logics mentioned;</div><div class="">2. The property is parsed and compiled to generate the monitor (in Erlang source code, in my particular case);</div><div class="">3. The monitor is spawned as a process that analyses a system component of interest as this executes.</div><div class=""><br class=""></div><div class="">The monitor needs to somehow acquire the runtime events emitted by processes, and this it does via the built-in Erlang tracing (i.e., the monitor is itself a tracer process). The important thing to note is that the monitors, despite being processes themselves, may be considered as a meta-layer over the system, and therefore, do not technically form part of the “ordinary” implementation of the system. This means that monitors can be introduced or removed from the system as needed, and merely function as a second layer that strives to observe the system with *minimal* interference. </div><div class=""><br class=""></div><div class="">This brings me to Kenneth’s point, that tracing is a tool intended for debugging/profiling purposes. I agree, and in fact, RV might be considered as a flavour of debugging or profiling that is done at runtime. It differs (amongst other things) from debugging and profiling, in that monitors are the product of autogenerated code resulting from *formal* logical properties. From what I gather, debugging or profiling obtains trace events in a similar way to the one I’m using for monitoring. I also understand and agree with you Kenneth that, if a system process is being monitored by one of my monitors, then it cannot be profiled or debugged due to the one-tracer limit imposed by the EVM. </div><div class=""><br class=""></div><div class="">Also, the reason I’m not using ‘dbg' but 'erlang:trace/3’ directly is that I want the full flexibility of tracing (I might require it in later stages of my research). Way back when I started the project I was not aware of the extent of the functionality ‘dbg’ offers, and so to play it safe (and after reading Francesco and Simon’s book), I decided to go for the tracing BIFs.</div><div class=""><br class=""></div><div class="">Finally, the reason I require different tracers (in my case, monitors) for different system processes (or groups) is that it makes the specification of correctness properties much more manageable. The gist of the idea is that it is far easier to specify a property over a restricted set of processes (e.g., just one process which exhibits *sequential* execution) than it is for a large number of processes, as then the property needs to account for all the possible interleavings of trace events exhibited by different processes. So in a sense, different monitors over different system components allow me to partition and view the otherwise whole trace of the system as a collection of separate traces for different components. Naturally, the monitors generated from smaller properties tend to be small and lightweight themselves, and are easier to work with. Moreover, this allows me to switch off certain monitors dynamically at runtime for system components that might not require monitoring anymore, while leaving others on. </div><div class=""><br class=""></div><div class="">Since a system can be viewed as always starting from one root process, I attach (i.e., start tracing) a special root monitor to this system root process. The root monitor creates new monitors on the fly for certain child processes that are spawned by the root system process. Now, to collect trace events without loss, the root monitor is configured with ’set_on_spawn’, meaning that new children of the root system process are automatically traced by the root monitor at first. To spawn a dedicated monitor ‘Mon_C' for some child process ‘C’, the following is executed:</div><div class=""><br class=""></div><div class="">1. Root monitor ‘Mon_R’ is currently tracing the new child process ‘C’ ('set_on_spawn' flag was set on 'Mon_R');</div><div class="">2. The new monitor ‘Mon_C’ created for child process ‘C’ switches tracing *off* for ‘C’ (i.e., erlang:trace(Pid_C, false, ..)), so the (previous) monitor ‘Mon_R' stops being the tracer of ‘C’;</div><div class="">3. New monitor ‘Mon_C’ switches tracing back *on* for child process ‘C’ and becomes its new tracer.</div><div class=""><br class=""></div><div class="">To minimise trace event loss between steps 2 and 3, I was thinking of suspending child process ‘C' before step 2, and resuming it after step 3 This way, ‘C’ is at least blocked, and cannot spawn new processes itself or send messages. I cannot however prevent other processes from sending ‘C' messages, meaning that there might be a chance of ‘receive’ events being lost in the space of time between steps 2 and 3. Therefore, my suggestion still does not banish the problem but merely mitigates it, as steps 2 and 3 do not happen atomically. I wonder whether such a BIF could be realisable, such that the ownership of tracing can be transferred atomically between tracers without incurring any loss of trace events (between monitors ‘Mon_R’ and ‘Mon_C’ in my case).</div><div class=""><br class=""></div><div class="">FYI, much of the work I’ve discussed has already been published in a previous paper we’ve written in the past. The paper can be found here: <a href="http://staff.um.edu.mt/afra1/papers/sefm17.pdf" class="">http://staff.um.edu.mt/afra1/papers/sefm17.pdf</a>. If you’re interested please let me know.</div><div class=""><br class=""></div><div class="">Many thanks for your help!</div><div class="">Duncan</div><div class=""><br class=""></div><div class=""><br class=""></div><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On 02 Oct 2019, at 09:11, Kenneth Lundin <<a href="mailto:kenneth@erlang.org" class="">kenneth@erlang.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">As a follow up on Rickards answer I think it would be interesting if you can explain why you want different tracers per process?<div class="">If we know what problem you want to solve we can most probably come with better suggestions.</div><div class=""><br class=""></div><div class="">I also recommend that you use tracing via the dbg module which is intended to be a more user friendly API towards tracing. The trace BIFs might give some more detailed control but dbg has support for most use cases and makes it easier to do the right thing, at least that is the intention.</div><div class=""><br class=""></div><div class="">Also worth mentioning is that the tracing mechanisms are really not intended to use to achieve a certain functionality which is part of the application, they are intended to be used temporarily for debugging/profiling purposes. Since there is only one tracer at the time the use of tracing as part of the "ordinary" implementation of an application there will be conflicts as soon as any tracing or profiling is needed and probably the intended functionality of the application will then be broken.</div><div class=""><br class=""></div><div class="">/Kenneth, Erlang/OTP Ericsson</div></div><br class=""><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Oct 1, 2019 at 10:07 PM Rickard Green <<a href="mailto:rickard@erlang.org" class="">rickard@erlang.org</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr" class=""><div class=""><br class=""><br class="">On Mon, Sep 30, 2019 at 1:57 PM Duncan Paul Attard <<a href="mailto:duncan.attard.01@um.edu.mt" target="_blank" class="">duncan.attard.01@um.edu.mt</a>> wrote:<br class="">><br class="">> I am tracing an Erlang process, say, `P` by invoking the BIF `erlang:trace(Pid_P, true, [set_on_spawn, procs, send, 'receive'])` from some process. As per the Erlang docs, the latter process becomes the tracer for `P`, which I shall call `Trc_Q`.<br class="">><br class="">> Suppose now, that process `P` spawns a new process `Q`. Since the flag `set_on_spawn` was specified in the call to `erlang:trace/3` above, `Q` will automatically be traced by `Trc_P` as well.<br class="">><br class="">> ---<br class="">><br class="">> I want to spawn a **new** tracer, `Trc_Q`, and transfer the ownership of tracing `Q` to it, so that the resulting configuration will be that of process `P` being traced by tracer `Trc_P`, `Q` by `Trc_Q`.<br class="">><br class=""><br class=""></div>Unfortunately I do not have any ideas on how to accomplish this.<br class=""><div class=""><br class="">> However, Erlang permits **at most** one tracer per process, so I cannot achieve said configuration by invoking `erlang:trace(Pid_Q, true, ..)` from `Trc_Q`. The only way possible is to do it in two steps:<br class="">><br class="">> 1. Tracer `Trc_Q` calls `erlang:trace(Pid_Q, false, ..)` to stop `Trc_P` from tracing `Q`;<br class="">> 2. `Trc_Q` calls `erlang:trace(Pid_Q, true, ..)` again to start tracing `Q`.<br class="">><br class="">> In the time span between steps **1.** and **2.** above, it might be possible that trace events by process `Q` are **lost** because at that moment, there is no tracer attached. One way of mitigating this is to perform the following:<br class="">><br class="">> 1. Suspend process `Q` by calling `erlang:suspend_process(Pid_Q)` from `Trc_Q` (note that as per Erlang docs, `Trc_Q` remains blocked until `Q` is eventually suspended by the VM);<br class="">> 2. `Trc_Q` calls `erlang:trace(Pid_Q, false, ..)` to stop `Trc_P` from tracing `Q`;<br class="">> 3. `Trc_Q` calls `erlang:trace(Pid_Q, true, ..)` again to start tracing `Q`;<br class="">> 4. Finally, `Trc_Q` calls `erlang:resume_process(Pid_Q)` so that `Q` can continue executing.<br class="">><br class="">> From what I was able to find out, while `Q` is suspended, messages sent to it are queued, and when resumed, `Trc_Q` receives the `{trace, Pid_Q, receive, Msg}` trace events accordingly without any loss.<br class="">><br class=""><br class="">This is not a feature, it is a bug (introduced in erts 10.0, OTP 21.0) that will be fixed. The trace message should have been delivered even though the receiver was suspended.<br class=""><br class="">You cannot even rely on this behavior while this bug is present. If you (or any process in the system) send the suspended process a non-message signal (monitor, demonitor, link, unlink, exit, process_info, ...), the bug will be bypassed and the trace message will be delivered.<br class=""><br class="">> However, I am hesitant to use suspend/resume, since the Erlang docs explicitly say that these are to be used for *debugging purposes only*.<br class=""><br class="">Mission accomplished! :-)<br class=""><br class="">> Any idea as to why this is the case?<br class="">><br class=""><br class="">The language was designed with other communication primitives intended for use. Suspend/Resume was explicitly introduced for debugging purposes only, and not for usage by ordinary Erlang programs. They will most likely not disappear, but debug functionality in general are not treated as carefully by us at OTP as other ordinary functionality with regards to compatibility, etc. We for example removed the automatic deadlock prevention in suspend_process() that existed prior to erts 10.0 due to performance reasons.<br class=""><br class="">Regards,<br class="">Rickard<br class="">--<br class="">Rickard Green, Erlang/OTP, Ericsson AB</div></div>
_______________________________________________<br class="">
erlang-questions mailing list<br class="">
<a href="mailto:erlang-questions@erlang.org" target="_blank" class="">erlang-questions@erlang.org</a><br class="">
<a href="http://erlang.org/mailman/listinfo/erlang-questions" rel="noreferrer" target="_blank" class="">http://erlang.org/mailman/listinfo/erlang-questions</a><br class="">
</blockquote></div>
_______________________________________________<br class="">erlang-questions mailing list<br class=""><a href="mailto:erlang-questions@erlang.org" class="">erlang-questions@erlang.org</a><br class="">http://erlang.org/mailman/listinfo/erlang-questions<br class=""></div></blockquote></div><br class=""></body></html>