Hacker News new | past | comments | ask | show | jobs | submit login

Did you at all find that the printf methodology of debugging got in the way of the gamedev? I've been keeping an eye on Go, but have been hesitant to approach it seriously because of that debugging approach.



I'll be honest -- I hate working without a debugger. Go's gdb support was never great, and the team appears to have decided it's a fool's errand. On the other hand, the Delve project looks like it's serious about building a "real" debugger for Go (https://news.ycombinator.com/item?id=8595407). Supposedly it works on Linux, but I'm waiting on Mac support, which I understand is held up on Linux/Mach/Darwin differences.

In the meantime, I've gotten pretty good at printf() debugging (I worked on embedded systems in a past life, so it's a skill I've had to develop). I'm also considering adding some more structured log/trace/metrics stuff (perhaps exposed via a simple web UI) that would allow me to escape the "tyranny of the ever-scrolling console".

But in the end, I'll consider Go dead for game development (at least for me) if the debugger situation doesn't get fixed. I'm just betting that it will.


In my hobby game programming, the first thing I got nailed down was writing messages to the screen.

Not as good as debugger, but invaluable when you need to see the specific value (position, etc) of an object right next to the object on screen.

I'd also usually have a key bound to spit out a frequently change buffer of debug information that I could call up at any time.


I have worked with GDB and Go before; it's not intractable, just more difficult to interpret.

Printf frequently works very well for most debugging, especially server side. I use the regular logging module pointed at stdout instead of printf specifically, and increasing the debugging level works most of the time.

Its also nice that with a bit of metaprogramming and goroutines/channels, you can make log printing nearly free. I once saw a technique where you simply write your really detailed log messages to a ring buffer (using a lockfree algorithm), and spit them out when you fail. This is even easier to do in Go, since you can just send the messages over a channel and not have to worry about properly implementing a lock free algorithm, and spit them out in a `recover()` function surrounding your main (or look at them in GDB).


> I once saw a technique where you simply write your really detailed log messages to a ring buffer

While this is incredibly cool, my initial concern was mostly this:

> I have worked with GDB and Go before; it's not intractable, just more difficult to interpret. > Printf frequently works very well for most debugging, especially server side.

The thing about your non-niche dev is that, unless you are debugging prod (gasp), you can control the influx of data/output of data. E.g. If you want to debug a specific webpage you can simply hit that webpage in the browser yourself, and you are guaranteed to only see code executing that has to do with that request.

The problem with gamedev is that things are happening 60 times a second. There is a firehose of data and there is nothing you can do about that. Logging is definitely used, but it is more useful on client machines once you have actually shipped a working product.

I guess what you could do is force a fail once a condition is met, to access the last data in the ringbuffer (and pray that it is still there, 60 times a second is 60 times a second).


All that makes sense to me. That said, thanks to goroutines and channels, you can be writing out that firehose and not have to worry too much about loosing your 60 FPS (with caveats, of course, but with buffering you can do, say, 6000 log writes a second and not have to worry about overwhelming your disks too much).

> and pray that it is still there, 60 times a second is 60 times a second

Great thing about memory, most gaming and development machines have gobs of it. You could allocate upwards of 600mb to the ring buffer and not feel the pinch. That's a lot of data, especially if you want to get creative and store pointers in there to other large structures in memory (such as a copy of a texture or mesh).

Ultimately, though, I agree. Full GDB support would be better; logging like this is just a stopgap.


> You could allocate upwards of 600mb to the ring buffer and not feel the pinch.

Touche.

> Ultimately, though, I agree. Full GDB support would be better; logging like this is just a stopgap.

Looks like one of us will need to man up one of these days and make a decent debugging experience. I'm just worried that the people at the helm of Go aren't taking this seriously enough. I've seen one or two quotes with them indicating that they believe printf is enough.

If you want Windows developer mindshare (keeping in mind that a fair amount of gamedevs are Windows/VS users) you're going to need some competitive tooling, they will give you tons of leniency, but if you ask them to printf they will go running back into the arms of the Visual Studio debugger.


Yes, this. I've often advocated for the importance of having a good debugger when developing any kind of UI, game, or simulation code. It can be really damned hard to make sense out of subtle bugs that are the result of accumulated state, using log messages alone. When I was writing games in C++, I routinely would just keep the game running in a debugger all the time, so I could break and inspect whenever anything got weird (which could often be difficult to reproduce). I'm writing server code in Go in my day job, and I agree that it's simply a different beast, and doesn't bother me as much.

With respect to the issue brought up elsewhere about debuggers and goroutines, I don't believe it would be as much of an issue with games. In practice, I only have a handful of fixed goroutines -- simulation, rendering, network, etc -- and am only debugging one of them at a time.


> once saw a technique where you simply write your really detailed log messages to a ring buffer (using a lockfree algorithm), and spit them out when you fail. This is even easier to do in Go, since you can just send the messages over a channel and not have to worry about properly implementing a lock free algorithm, and spit them out in a `recover()` function surrounding your main (or look at them in GDB).

Do you know of a library that facilitates this?


I'm afraid not; I found this originally on a blog which specialized in lockfree concurrency, and adapted it for use in my Go programs.

EDIT: The gist of the non-go formula was to have an array of fixed size character buffers, with a next-write pointer into that array. To write, you copy the pointer and use CAS to increment the next-write pointer (taking care to wrap at the end of the array), and write your data. If you have a particularly small buffer, you may have to be concerned about two threads writing to the same location due to the buffer wrapping, but it could be resolved with other mechanisms (or the buffer size increased).

Thanks to the Go `sync/atomic` package, you could implement the same thing, or just set up a goroutine which just reads from a channel into that ring buffer.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: