5 ms·
The key thing about print debugging for me, that I've never seen a typical debugger handle well, is what I like to think of as "temporal debugging": Taking a p
by a_e_k 4y ago
The key thing about print debugging for me, that I've never seen a typical debugger handle well, is what I like to think of as "temporal debugging":
Taking a program trace from the print debug statements, grepping through it repeatedly to filter down to certain events of interest, looking at the interleaving of those events, and figuring out the order that things happened in to cause it to go off the rails. That sort of thing. (To be fair, time-travel debuggers can start to get at this, but those are pretty uncommon. Traces, as you say, work almost everywhere.)
Or better yet, compare the traces between working and non-working runs to see how they differ. I've looked at diffs of traces this way before. (Sometimes I'll first use a small script to renumber pointers in traces by order of appearance.)
I've also used this sort of strategy before for debugging rare threading or other non-deterministic issues. Have the shell run the program in a loop, saving each run's trace and results to a different file, go off and get lunch, come back and see if anything failed. Then look to see if any of the runs failed and look for the structural differences between the working and non-working traces.
I can't imagine sitting and stepping through in a debugger 100+ times in the hopes that maybe this time, it will be the run that's just different enough to trigger the bug and that the debugger itself won't prevent the issue from manifesting. Not to mention, trying to remember the steps from all the good runs and spotting where the bad run goes bad before you've stepped to far. No thank you.
I think people really underestimate print debugging. Debuggers are fast and easy for simple bugs, sure, but there's powerful stuff that you can only really do with printed traces.
- Serow225 4y ago> I can't imagine sitting and stepping through in a debugger 100+ times in the hopes that maybe this time, it will be the run that's just different enough to trigger the bug Isn’t that where things like breakpoint conditions, data breakpoints (“break whenever X value/field changes”), and dependent breakpoints, work pretty dang well? You just set up the appropriate situation and let it run until it breaks
- a_e_k 4y agoThose help in some situations, sure. I'm talking about the non-deterministic things like unusual race conditions, where the problem only manifests rarely. Conditional breakpoints could certainly help you detect when things have broken, but you'll often be well downstream of the root cause by then. Though I suppose tracepoints could help with that. So I'll concede that you could probably do something similar in a powerful enough debugger with sufficient effort. But one thing that I have found helpful in the past has been aggregating the information from the traces across runs. Comparing good with good and bad with bad to classify the commonalities, and then compare good with bad to see how they differ.