Live data from Hacker News

Printf debugging is ok

polymonster.co.uk

101–110 of 152 posts

Re: Printf debugging is ok

#101
I found this interesting:

> I know for some people this is often a terrible UX because of the performance of debug builds, so a prerequisite here is fast debug builds.

The reasons debug builds perform badly are kind of mixed, in my experience looking at other people's set ups:

Building without optimisations

It's fairly common to believe that debug builds have to be built with -O0 (no optimisations) but this isn't true (at least, not on the most common platforms out there). There's no need to build something that's too slow to be useful.

You can always add debug info by using -g (on gcc / clang). Use -g3 to get the maximum level. This is independent of optimisation.

You can build with any level of optimisation you want and the debugger will do its best to provide you a sensible interpretation - at higher optimisation levels this can give some unintuitive behaviours but, fundamentally, the debugger will still work.

Gcc provides the "-Og" optimisation level, which attempts to balance reasonably intuitive behaviour under the debugger with decent performance (clang also supports this but, last I checked, it's just an alias to -O1.

Doing a ton of self-checks

People often add a load of self-checking, stress testing behaviours and other things "I might want when looking for a bug" to their code and gate it on the NDEBUG macro.

The logic here is reasonable - you have a build that people use for debugging, so over time that build accumulates loads of behaviours that might help find a bug.

The trouble is, this can give you a build that's too slow / weird in its behaviours to actually be representative. And then it's no use for finding some of your bugs anymore!

I think it would be better here to have a separate "dimension" for self-checking (e.g. have a separate macro you define to activate it), rather than forcing "debug build" to mean so many things.

Re: Printf debugging is ok

#102
> You could use a conditional breakpoint within the debugger, but they can be slow and for me historically unreliable, but this little snippet gives you your own conditional breakpoint that works without fail.

In theory, you can make conditional breakpoints very fast using an in-process agent. For GDB (for instance) this gives the ability to evaluate conditional breakpoints within the process itself, rather than switching back to GDB: https://sourceware.org/gdb/current/onlinedocs/gdb.html/In_00...

I've always found the GDB documentation to be a bit vague about how you set up the in-process agent but I found this: (see 20.3.4 "Tracepoints support in gdbserver") https://sourceware.org/gdb/current/onlinedocs/gdb.html/Serve...

When we implemented in-process evaluation of conditional breakpoints in UDB (https://undo.io/products/udb/) it made the software run about 3000x faster than bare GDB with a frequently-hit conditional breakpoint in place. In principle, with a setup that just uses GDB and in-process evaluation you should do even better.

Re: Printf debugging is ok

#103
You shouldn't have to go back and modify a program's source-code just to find out what some part does when run. That's just plainly obvious to me as a principle.

If we have no other option then sometimes we have to use non-ideal approaches, but I don't get the impulse to start saying that tooling/observability poverty is actually good.

Re: Printf debugging is ok

#104
post #5

I've gotten an OS to run on a new platform with a debugging tool portfolio consisting of a handful of LEDs and a pushbutton. After getting to the point where I could printf() to the console felt like more than anyone could ever ask for. Anecdote aside, it certainly doesn't hurt to be able to debug things without a debugger if it comes to that.

Since most of my work is in distributed systems, I find the advice to never printf downright laughable. "Oh sure, lemme just set a breakpoint on this network service. Hm... Looks like my error is 'request timed out', how strange." That having been said: there are some very clever solutions in cloud-land for "printf" debugging. (Edit: forgot this changed names) Snapshot Debugger ( https://github.com/GoogleCloudPlatfor…

> "Oh sure, lemme just set a breakpoint on this network service. Hm... Looks like my error is 'request timed out', how strange."

Time travel debugging (https://en.wikipedia.org/wiki/Time_travel_debugging) can help with this because it separates "recording" (i.e. reproducing the bug) from "replaying" (i.e. debugging).

Breakpoints only need to be set in the replay phase, once you've captured a recording of the bug.

Re: Printf debugging is ok

#105

Earlier quoted context omitted.

GDB is a dog shit trash debugger. I keep forgetting that Linux and Mac have shit tools. I suppose if the only debugger available to me were GDB I would also prefer printf debugging! The typical modern dev loves to shit on Windows. But Visual Studio (the adult version, not VSCode) is still a best-in-class debugger. Xcode is bloated as hell but did help me last week. Linux has… poor bastards.

I've spent plenty of time with various debuggers for various platforms and languages, both graphical and CLI-based, and it really doesn't matter to what I said. A debugger may be someone's preferred tool anyway, sure, but the cases where it's actually non-trivially improving workflow are relatively rare. Most of the time it just makes you a bit faster, if at all.

I could not possibly disagree more strongly. But hey you do you.

Re: Printf debugging is ok

#107
post #49

If you have a reproducible test case that runs reasonably quickly, then I think printf debugging is usually just as good as a "real" debugger, and a lot easier. I typically have my test output log open in one editor frame. I make a change to the code in another frame, save it, my build system immediately re-runs the test, and the test log immediately refreshes. So when the test isn't working, I just keep adding print…

Adding print statements, rebuilding and rerunning the program and figuring out where in the logs the bug showed up this time can a lot more tedious than setting a (possibly conditional) breakpoint in a reverse-execution debugger and doing "reverse-continue".

Re: Printf debugging is ok

#108

As with so many categorical guidelines, there are circumstances to use it and circumstances to not. The key insight is that printf() is a heavyweight operation ("What, you want to build a string? A human readable string? Okay, one second, lemme just pull in the locale library..."). If you're debugging something at the business-logic layer, it's probably fine. If you're debugging a memory leak, calling a function that…

> If you're debugging a memory leak, calling a function that's going to make a deep-dive on the stack and move a lot of memory around is likely to obscure your bug.

shudder memories of my early days in kernel-level programming where using a printf used to just "fix" some bugs.

That came down to an uninitialised variable (which calling printf was helpfully initialising by using the stack).

As a result of that early experience, when I'm in the headspace of very low-level bugs, I find it helps to think of printf both as "this will tell me some variable values" and as a source of other clues: if it makes a weird value disappear or change then you might have uninitialised data on your stack, if it makes a flaky behaviour become stable (either disappear or become repeatable) then it's probably a race condition, etc.

A reference to James Mickens' "The Night Watch" feels appropriate here: https://www.usenix.org/system/files/1311_05-08_mickens.pdf

Re: Printf debugging is ok

#110
post #49

If you have a reproducible test case that runs reasonably quickly, then I think printf debugging is usually just as good as a "real" debugger, and a lot easier. I typically have my test output log open in one editor frame. I make a change to the code in another frame, save it, my build system immediately re-runs the test, and the test log immediately refreshes. So when the test isn't working, I just keep adding print…

The crashes/bugs I deal with are rarely straight down failures, they are often the 1 out of 100 runs kind, so printf debugging is the only way to go really. And I used to be big on using debuggers, but now I’m horribly out of practice.

Record-and-replay debuggers are often better than anything else for debugging intermittent failures: run the program with recording many times until you eventually get the bug, then debug that recording at your leisure; you'll never have to waste time reproducing it again.
Post reply on HN