Live data from Hacker News

Show HN: Dlg – Zero-cost printf-style debugging for Go

github.com

11–20 of 42 posts

Re: Show HN: Dlg – Zero-cost printf-style debugging for Go

#11
post #8

How does the dead code elimination work when using args to Printf? If static strings are fed into an empty function, I can imagine it does nothing. However, this I have less of a firm grip upon dlg.Printf("the thing.Something is %+v", thing.Something()) since surely golang will still call Something, and still call Printf And don't misunderstand me: it's a grave pet peeve of mine to do action inside the args to Printf…

This is a thing I had a little "are you sure?" itch in my brain about, but you've expressed so clearly in four lines of comment, and this is me showing gratitude for the comment and the untangling of my brain.

ETA: Presumably if there was at least an option for passing a closure that would provide a way to address this? Since the closure will only uselessly compile, and not actually uselessly run?

Re: Show HN: Dlg – Zero-cost printf-style debugging for Go

#14

it doesn't appear to truly be zero cost if you log variables that can't be eliminated. The only way (I believe) to implement zero cost is some type of macro system which go does not support.

Yeah I want a log package where the log statements that don't log also don't have their arguments evaluated. Half of my gc pressure is little strings created to call the log package that don't get logged.

Re: Show HN: Dlg – Zero-cost printf-style debugging for Go

#15
post #8

How does the dead code elimination work when using args to Printf? If static strings are fed into an empty function, I can imagine it does nothing. However, this I have less of a firm grip upon dlg.Printf("the thing.Something is %+v", thing.Something()) since surely golang will still call Something, and still call Printf And don't misunderstand me: it's a grave pet peeve of mine to do action inside the args to Printf…

In short: You're right - Go will still evaluate argument expressions. In hindsight, I should've made that more obvious, not calling this out initially was an expert blind spot on my part, not an intent to mislead.

If we consider this example:

  func risky() error {
    return fmt.Errorf("unexpected error")
  }

  func risky2() error{
    return fmt.Errorf("also an error")
  }

  func main() {
    fmt.Printf("something failed: %v", risky())
    dlg.Printf("something failed: %v", risky2())
  }
And look at the disassembly:

  0x10009f354  d503201f  NOOP                ; Dead code of dlg.Printf
  0x10009f358  b0000000  ADRP 4096(PC), R0   ; Load "also an error" string address
  0x10009f35c  9124ec00  ADD $2363, R0, R0   ; Calculate exact string address
  0x10009f360  d28001a1  MOVD $13, R1        ; Set string length=13 (R1)
  0x10009f364  aa1f03e2  MOVD ZR, R2         ; Clear R2
  0x10009f368  aa1f03e3  MOVD ZR, R3         ; Clear R3
  0x10009f36c  aa0303e4  MOVD R3, R4         ; Clear R4
  0x10009f370  97ffd890  CALL fmt.Errorf(SB) ; Call fmt.Errorf
What disappears is the logging work (formatting, interface/slice plumbing, I/O) and the call itself. Go cannot eliminate calls to functions inside of Printf because they could produce side-effects. Eliminating functions calls like this would be very expensive to do and would clashes with Go's focus on fast compilation times.

I'll add a section to the README that explains this. Thanks for pointing it out.

Re: Show HN: Dlg – Zero-cost printf-style debugging for Go

#16
post #14

it doesn't appear to truly be zero cost if you log variables that can't be eliminated. The only way (I believe) to implement zero cost is some type of macro system which go does not support.

Yeah I want a log package where the log statements that don't log also don't have their arguments evaluated. Half of my gc pressure is little strings created to call the log package that don't get logged.

So what you want is slog, found in the standard library? The doc.go file found in the package even goes into detail about what you (seem to) describe and how it avoids that problem.

Re: Show HN: Dlg – Zero-cost printf-style debugging for Go

#17

I'm curious why you prefer this over writing tests.

I do write tests but I'm not a fan of aiming for 100% coverage because it's incredibly tedious to achieve, and the gains in my experience are marginal.

That being said even with 100% coverage your code may still contain bugs. If you've never had to debug code with extensive tests then hats off to you.

Re: Show HN: Dlg – Zero-cost printf-style debugging for Go

#18

it doesn't appear to truly be zero cost if you log variables that can't be eliminated. The only way (I believe) to implement zero cost is some type of macro system which go does not support.

> it doesn't appear to truly be zero cost if you log variables that can't be eliminated.

I'd say it is fair to call it zero cost, if the costs you are seeing are due to the way you are using it. If the values being logged are values you are already computing and storing, constants, or some mix of the two (concatenated via its printf function), by my understanding (caveat: I've never actually used Go myself) all the logging code should be stripped out as dead code in the link stage.

Obviously if you are performing extra computations with intermediate values to produce the log messages, your code there might produce something that is not reliably detected as eliminable dead code so there would be cost there.

> The only way (I believe) to implement zero cost is some type of macro system which go does not support.

That looks to be effectively what it is doing, just at the link stage instead of in a preprocessor. Where C & friends would drop the code inside #ifdef when the relevant value is not set (so it won't be compiled at all) this should throw it out later in the process if DLG_STACKTRACE isn't set at compile time.

So there will always be a compile-time cost (unlike with a preprocessor macro, something will be produced then thrown away and the analysis of what to throw away will take longer with more code present), but not a run-time cost if the logging is not enabled, assuming you don't have any logic in the trace lines beside the calls to this module.

Re: Show HN: Dlg – Zero-cost printf-style debugging for Go

#19
post #2

Very cool! Just one thought: I don't think your stack traces need to include the lines inside Printf itself and it adds to the noise a bit. Maybe just go up to the line where the call to Printf is made?

Thank you!

You're absolutely right, it annoys me as well.

It's a bit finicky to do so, but I'm currently in an exploratory phase of providing an even more fine grained stack tracing feature and filtering out dlg itself is definitly on my todo list.

Re: Show HN: Dlg – Zero-cost printf-style debugging for Go

#20

I'm curious why you prefer this over writing tests.

I do write tests but I'm not a fan of aiming for 100% coverage because it's incredibly tedious to achieve, and the gains in my experience are marginal. That being said even with 100% coverage your code may still contain bugs. If you've never had to debug code with extensive tests then hats off to you.

When you write a test you see the cute little "debug test" button show up beside it in your editor. If you press it, your logpoints spill the logging information you seek without having to modify the code.

I expect that is what the parent is really asking about: What does this meaningfully offer over the "built-in" debug logging?

Post reply on HN