<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On 13 Jan 2015, at 13:36, Vlad Dumitrescu <<a href="mailto:vladdu55@gmail.com" class="">vladdu55@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">The main reason I use the debugger is to check that the intermediary values in a computation are the expected ones. The alternative (which works without messing up timeouts) is to print out values at points of interest, but it is messy (there's a lot of boilerplate to type and the interesting code becomes hard to read).</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">So, I thought, what if, instead of interpreting a module in order to debug it, we compile it with a special parse transform that inserts tracing calls after each expression in the code, automatically keeping track of the variables visible in the scope and their values?</div></div></blockquote><br class=""></div><div>Hmm…</div><div><br class=""></div><div>I don’t consider myself qualified to discuss the details of a bytecode-level debugger, but it seems to me as if it would be a very difficult thing to get right, balancing usability during debugging with efficiency of bytecode while not debugging (not to mention the effects of aggressive compile-time optimizations).</div><div><br class=""></div><div>Then again, anything written after â€œI dont consider myself qualified… but” can probably safely be ignored.</div><div><br class=""></div><div>In terms of writing debuggable code, there are some things that can be done without hacking the VM:</div><div><br class=""></div><div>* Write many small functions</div><div>* Separate out side-effects, keeping as many functions as possible side-effect free</div><div>After this, tracing can help you capture function inputs, and you can then single-step through a troublesome function at your leisure.</div><div>* If your functions take records as input, use the shell function rr(Module) so you can use record syntax from the shell.</div><div><br class=""></div><div>For me, this takes care of the vast majority of cases where single-stepping can come into play. Possibly due to my own personal bent, I always end up trying to debug distributed coordination logic, in which case, this is would be my current recommendation:</div><div><br class=""></div><div>* Instead of io:format() debugging, call an empty function that can be traced when needed</div><div>I’ve been using this when debugging the â€˜locks’ application, and while it didn’t make debugging leader election during netsplits exactly easy, it helped a great deal. Example below.</div><div><br class=""></div><div>In the locks application, I wrote a module, locks_ttb.erl, which is a thin wrapper around the trace tool ttb.</div><div>To begin with, I use a debug macro I call ?event() in the code:</div><div><br class="">-define(event(E), event(?LINE, E, none)).<br class="">-define(event(E, S), event(?LINE, E, S)).</div><div><br class=""></div><div>The event/3 function itself is as light as possible:</div><div><br class="">event(_Line, _Event, _State) -><br class="">    ok.<br class=""><br class=""></div><div> It contains a convenient function for starting a multi-node trace on my strategic â€˜debug functions’. Another function, locks_ttb:format(File, OutFile) takes a merged trace log (containing timestamped traces from all nodes) and pretty-prints the traces, not least checking for record field metadata and using record syntax if possible.</div><div><br class=""></div><div>In particular, I use this in the unit test for leader_election with netsplit:</div><div><a href="https://github.com/uwiger/locks/blob/master/test/locks_leader_tests.erl#L73" class="">https://github.com/uwiger/locks/blob/master/test/locks_leader_tests.erl#L73</a></div><div><br class=""></div><div>The setup call to locks_ttb enables tracing on the test nodes as well as the test function itself (which also uses â€˜event’ function debug entries). The trace data is collected only if the test fails. It can then be analyzed with the help of locks_ttb:format/2.</div><div><br class=""></div><div>I’ve actually been meaning to test this style of trace/debug for years, but never quite got around to it. There are quite a few things that could be done beyond this - those to remember the PROTEST project may recall a few more or less wild ideas. What I’ve done in â€˜locks' is actually quite basic.</div><div><br class=""></div><div>I’ve been thinking about taking this a step further, writing it up and perhaps giving a presentation about it, but I’ve been having too much fun.</div><div>The only thing locks-specific in locks_ttb.erl, BTW, is the function default_pattern/0.</div><div><br class=""></div><div>BR,</div><div>Ulf W</div><br class=""><div apple-content-edited="true" class="">
<span class="Apple-style-span" style="border-collapse: separate; border-spacing: 0px;"><div class=""><div class="">Ulf Wiger, Co-founder & Developer Advocate, Feuerlabs Inc.</div><div class=""><a href="http://feuerlabs.com" class="">http://feuerlabs.com</a></div></div><div class=""><br class=""></div></span><br class="Apple-interchange-newline">

</div>
<br class=""></body></html>