Live data from Hacker News

The unreasonable effectiveness of print debugging

buttondown.email

221–230 of 366 posts

Re: The unreasonable effectiveness of print debugging

#221
For me this isn't an either or.

I constantly use both together. For problems that a quickly and reliably reproducible I'll often just use the debugger (if rr is suitable, even better).

But there's plenty problems that take a while to reproduce, involve many threads / processes, etc. Where the initial set of potential issues is too wide to easily target with a debugger. There sprinkling printfs around can provide data at a lower overhead than doable with a debugger.

Just yesterday I was debugging something where rr didn't finish replaying a workload that originally takes 10s within an hour (loads of io). Switching to print debugging I pinpointed the issue in < 10min.

Re: The unreasonable effectiveness of print debugging

#222
With the Jetbrains products breakpoint debugging is so easy that i use it for development all the time. Evaluating expressions inside a breakpoint while developing provides many answers in a mich tighter feedback loop, even with go or something equally fast. If i don't have the jetbrains tools i default to print debugging because everything else is too much of a hassle.

Re: The unreasonable effectiveness of print debugging

#223

Earlier quoted context omitted.

But with print statements if the first place I put them doesn't work, I can start doing bisects and quickly find the right place to print. As you note, debugger breakpoints aren't magically better than print statements when I'm investigating a hypothesis – I'm no more likely to put them the right place than I would have put print statements. And then there's a class of problems that neither debugger nor print stateme…

> But with print statements if the first place I put them doesn't work, I can start doing bisects and quickly find the right place to print. Can't I also bisect with breakpoints?

You can, but the comment was talking specifically about stepping through the code line-by-line.

Re: The unreasonable effectiveness of print debugging

#224

Personally, I think my biggest reason for using print debugging is.. it works. In C++ I often find the debugger doesn't find symbols on projects built with configure/Make. If I have a Java Gradle project I have no idea how to get it into a debugger. Python debuggers always seem fragile. Rust requires I install and use a "rust-gdb" script -- except on my current machine that doesn't work and I don't know why. I'm sure…

Python easily has the best debugger I've ever seen in a language. ``` import pdb; pdb.set_trace() ``` that's literally all you have to do at any point in your code. Run your code in the foreground of a terminal, and boom you have a debugger exactly where you want it.

Fwiw, it's not too hard to approximate that in c/c++. Print out the pid (I often print out "gdb -p %d") and then sleep (and perhaps send SIGSTOP to other processes in more complicated scenarios).

Re: The unreasonable effectiveness of print debugging

#225
post #160
post #121

Earlier quoted context omitted.

In a world with perfect optimizing compilers that never introduce bugs, we should never "need" print debugging. But that's not where I live, so I'll keep using print debugging. On the other hand... adding print statements can also invalidate certain optimizations (an excellent source of heisenbugs), so I'll never stop using debuggers either

Print debugging is essential in distributed systems. Sitting in the debugger waiting for human input often leads to timeouts and not covering the case you want. Of course, sometimes adding the prints, or even just collecting values to be printed later also changes execution flow, but like do the best you can.

[deleted]

Re: The unreasonable effectiveness of print debugging

#226
post #209

Print debugging is not that different from setting logging level to DEBUG and those logging calls should already be there in code and give meaningful insight so I don't get printing being often ridiculed. For over ten years of commercial work I used a debugger only a couple of times and in most cases it was against someone else's code, usually when things were completely broken and I needed to get backtraces from mul…

Actually, using the UART interface to send text breadcrumbs out the port is a standard technique in embedded, too ...

The article hits the point of print debugging, you get to see the backward in time.

By the time you hit "the problem", the pointer is NULL, the memory is trashed, the system is deadlocked, etc. You need to reason about how you got there.

There is a reason why the next step up from basic debugging embedded is "streaming trace"--effectively print on steroids.

Re: The unreasonable effectiveness of print debugging

#227
post #214

Earlier quoted context omitted.

What Python debuggers you are talking about? have you tried the built-in CLI debugger? Just drop breakpoint() in your code and you're in. Have been using it daily for over a decade and really happy with it - it's actually one of my favorite features of the language, amongst the many super useful features that Python and its excellent stdlib have to offer.

Only thing I hate about this .... regular point of code review: remove the debugger breakpoint you left in your code! We haven't had one hit production yet, but it came close. Print statement is a lot more harmless.

[deleted]

Re: The unreasonable effectiveness of print debugging

#228
post #215

Most under appreciated aspect of proper debuggers is not about the code line of interest but the context they give you about the whole application, ie: the stack frames and their state. When handed a new codebase I often fire up the debugger and attach and set various breakpoints in interesting places and then execute the application to see where / when they get hit. It's a great way to learn a codebase - things that…

The problem with async programming nowadays is that stack traces become meaningless.

That depends on your tooling! Lots of async programming has debuggers that tracks what you might consider to be synthetic but more useful backtrace.

Re: The unreasonable effectiveness of print debugging

#229

Another aspect, where printf debugging can be better than debuggers are use-cases where timing is relevant. Some bugs don't occur when break points stop the program at certain points in time. For completeness is should be added, that there are also cases where the printf can change the performance and make it impossible to find a bug. I think the two methods are complementary and should be use in combination. However…

Debuggers don't have to halt execution on hitting a breakpoint. They can do other things, like print the contents of memory, letting the host system handle the formatting. They're actually usually better for timing-sensitive prints than printf debugging. That said, most people don't know this is possible (the learning curve issue you mentioned), even though it's an important part of how to use debuggers!

In my experience, GDB running commands on a breakpoint is generally much, much slower and more prone to materially changing the timing of things than printf.

Re: The unreasonable effectiveness of print debugging

#230
post #216

I'm working on Swift interpreter and the codebase is fairly difficult to debug. There's a lot of reused bits. So if you put a debug point somewhere trying to capture one behavior, odds are that that line will run 10 times for other work before the relevant part uses it. So I tend to write a LOT of print statements that flush of debug variables right before I where I want to debug. Then I set a conditional breakpoint…

Why not just add an action to the conditional breakpoint that prints the value?
Post reply on HN