Live data from Hacker News

Why I Write Games in C (yes, C)

jonathanwhiting.com

181–190 of 556 posts

Re: Why I Write Games in C (yes, C)

#181
post #89

Earlier quoted context omitted.

That's true, and it's why the alternative to GC is generally not "malloc and free" or "RAII" but "custom allocators." Games are very friendly to that approach- with a bit of thought you can use arenas and object pools to cover 99% of what you need, and cut out all of the failure modes of a general purpose GC or malloc implementation.

Interestingly, it's fully possible to disable the automatic garbage collection in Go to achieve this. Disable the garbage collector: debug.SetGCPercent(-1) Trigger garbage collection: runtime.GC() It is also possible to allocate a large block of memory and then manage it yourself.

Due the low throughput of Go's GC (which trades a lot of it in favor of short pause duration), you risk running out if memory if you have a lot of allocations and you don't run your GC enough times.

Re: Why I Write Games in C (yes, C)

#182
post #46

> The stop-the-world garbage collection is a big pain for games, stopping the world is something you can't really afford to do. I love this opinion from games programmers because they never qualify it and talk about what their latency budgets are and what they do in lieu of a garbage collector. They just hand wave and say "GC can't work". The reality is you still have to free resources, so it's not like the garbage c…

Almost a decade ago I was writing a desktop toolkit in Lua 5.1 and gdk/cairo bindings. Let’s say for fun, because it never seen the light in planned business. But it had animations and geometry dynamics (all soft, no hw accel). While GC seems to be fast and data/widget count was small, it suddenly froze every dozen of seconds for a substantial amount of time. First thing I tried was to trigger a [partial] collection after every event, but what happened was (I believe) incremental^ steps still accumulated into one big stop. Also I followed all critical paths and made allocations static-y. It got better, but never resolved completely. I didn’t investigate it further, and my hw was far from bleeding edge, thus no big conclusion. But since then I’ll think twice before doing something frametime-critical with GC. Each specific implementation requires a handful of wild tests at least before considering as an option in my book.

As others probably already mentioned, worst side of gc is that it is unpredictable and hard to be forced in a way that matches your specific pattern. With manual/raii mm you can make pauses predictable and non-accumulating collection debt and fit before “retrace” perfectly. Also simply relying on automatic storage in time critical paths is usually “can not” in gc envs.

^ if any, I can’t recall if 5.1 actually implemented true incremental gc back then

Re: Why I Write Games in C (yes, C)

#183
post #104
post #83

Earlier quoted context omitted.

If by safe pointers you mean unique_ptr etc, I'm pretty sure those are classes: https://en.cppreference.com/w/cpp/memory/unique_ptr So by definition require OOP?

OOP is such a nebulous thing. Just because the word 'class' is used doesn't mean something is OOP. Those smart pointers don't use inheritance, they don't implement any interfaces, no virtual methods...

I would call that using a subset of OOP features[1], not avoiding it entirely.

But I guess there's no point in arguing over semantics.

[1] As Wikipedia defines OOP: "a programming paradigm based on the concept of "objects", which can contain data, in the form of fields (often known as attributes or properties), and code, in the form of procedures (often known as methods)." https://en.wikipedia.org/wiki/Object-oriented_programming

Re: Why I Write Games in C (yes, C)

#184
post #46

> The stop-the-world garbage collection is a big pain for games, stopping the world is something you can't really afford to do. I love this opinion from games programmers because they never qualify it and talk about what their latency budgets are and what they do in lieu of a garbage collector. They just hand wave and say "GC can't work". The reality is you still have to free resources, so it's not like the garbage c…

I used to work on realtime graphics code which was used in flight simulators for the FAA and USAF, then moved into the games industry and led the design of a couple of game engines, to give you an idea where I'm coming from. The military grade flight sims actually had contract requirements like, "you may never miss a single frame in a week of usage", etc, so solving this problem was critical. When working on code suc…

> C++ is as complex as you want to make it

I second that. I always find the attitude of “C++ is bad so I’m going to stick to C” really bizarre. You can use C++ as a better C.

- use type inference and references instead of pointers. Writing C style code with these features makes it more readable.

- Don’t like OO programming. Stick to struct with all members public. It’s going to be a lot better than doing the same thing in C and you shall not have void* casts.

- use exceptions instead of return code for errors, so that your code is not peppered with if statements at every line you call. With an exception you’ll get additional info about crashes in dumps.

I wrote for an embedded system where the C++ standard library was not available, in a previous life. I ended up writing my code in C++ and “re-inventing” a couple of useful classes like std::string and std::vector. For the most part my code was very C like...

Re: Why I Write Games in C (yes, C)

#185
post #46

> The stop-the-world garbage collection is a big pain for games, stopping the world is something you can't really afford to do. I love this opinion from games programmers because they never qualify it and talk about what their latency budgets are and what they do in lieu of a garbage collector. They just hand wave and say "GC can't work". The reality is you still have to free resources, so it's not like the garbage c…

Not a game developer, but I used to write UI addons for World of Warcraft. WoW allows you to customize your UI heavily with these Lua plugins ("addons") and Lua is garbage collected. It's a reasonable incremental GC so it shouldn't be too bad in theory.

But in practice it can be horrible. You end up writing all kinds of weird code just to avoid allocations in certain situations. And yeah, GC pauses due to having lots of addons is definitely very noticable for players.

Also leads to fun witch hunts on addons using "too much" memory, people consider a few megabytes a lot because they confuse high memory usage with high allocation rate... Our stuff started out as "lightweight" but it grew over the years. We are probably at over 5 MB of memory with Deadly Boss Mods (many WoW players can attest that it's certainly not considered lightweight nowadays, but I did try to keep it low back then). But I think we still do a reasonable job at avoiding allocations and recycling objects...

The point is: I had to spent a lot of time thinking about memory allocations and avoiding them in a system that promised me to handle all that stuff for me. Frame drops are very noticable. But there are languages with better GCs than Lua out there...

Somewhat related: I recently wrote about garbage collectors and latency in network drivers in high-level languages: https://github.com/ixy-languages/ixy-languages Discussed here: https://news.ycombinator.com/item?id=20945819

That's a scenario were short GC pauses matter even more as the hardware usually only buffers a few milliseconds worth of data at high speeds.

Re: Why I Write Games in C (yes, C)

#186

Earlier quoted context omitted.

Interestingly, it's fully possible to disable the automatic garbage collection in Go to achieve this. Disable the garbage collector: debug.SetGCPercent(-1) Trigger garbage collection: runtime.GC() It is also possible to allocate a large block of memory and then manage it yourself.

> It is also possible to allocate a large block of memory and then manage it yourself. At which point you're mostly just writing C in Go.

You’re writing in a much improved C. Strong type system (including closures/interfaces/arrays/slices/maps), sane build tooling (including dead simple cross compilation), no null-terminated strings, solid standard library, portability, top notch parallelism/concurrency implementation, memory safety (with far fewer caveats, anyway), etc. Go has it’s own issues and C is still better for many things, but “Go with manually-triggered GC” is still far better than C for 99.9% of use cases.

Re: Why I Write Games in C (yes, C)

#187
post #46

> The stop-the-world garbage collection is a big pain for games, stopping the world is something you can't really afford to do. I love this opinion from games programmers because they never qualify it and talk about what their latency budgets are and what they do in lieu of a garbage collector. They just hand wave and say "GC can't work". The reality is you still have to free resources, so it's not like the garbage c…

Not a game developer, but I used to write UI addons for World of Warcraft. WoW allows you to customize your UI heavily with these Lua plugins ("addons") and Lua is garbage collected. It's a reasonable incremental GC so it shouldn't be too bad in theory. But in practice it can be horrible. You end up writing all kinds of weird code just to avoid allocations in certain situations. And yeah, GC pauses due to having lots…

yeah the Go garbage collector is a LOT more sophisticated than Lua. I might be playing WoW Classic right now ...

Re: Why I Write Games in C (yes, C)

#188
post #176

Earlier quoted context omitted.

Are you saying that there are more go developers than c developers? Is there a user survey that shows such things? I'm curious what the ratio is.

I'd be willing to wager that C programmers would be more comfortable working with a Golang codebase than Golang programmers would be working with a C codebase. There may be more "C programmers" by number but a Golang codebase is going to be more accessible to a wider pool of applicants.

In my experience it takes a few days for a moderate programmer to come up to speed on Go, whereas it takes several months for C. You need to hire C programmers for a C position, you can hire any programmers for a Go position.

Re: Why I Write Games in C (yes, C)

#189
post #177

Earlier quoted context omitted.

No. Security is a full-stack endeavor. At all levels it is incumbent upon software professionals to build secure and resilient systems, any time they're exposed to a network. The OS should backstop your efforts, not replace them.

I disagree. As a user, I want to be able to run weird software without having it impact the rest of my system. Browsers and mobile OSs get this much more right than desktop OSs.

This does not meaningfully follow. What you "want" is orthogonal to the responsibility of the vendors of software.

The OS should protect where it can. So should software, lest your networked game nuke, say, the parts of your home directory to which it has permissions because without those permissions it can't do something it needs to.

This is just defense-in-depth. It's super basic stuff and HN is literally the only place I see people galaxy-braining about the idea that you have an obligation to not write shit code.

Re: Why I Write Games in C (yes, C)

#190
post #86

Earlier quoted context omitted.

Disclaimer: I'm not a game developer; but, I've worked on a lot of projects with tight frame time requirements in my time at Netflix on the TVUI team. I also have no experience in Go so I can't comment on the specifics of that garbage collector vs. V8. I don't think it's necessarily that it "can't" work as much as it takes away a critical element of control from the game developers and the times you find yourself "at…

> and the times you find yourself "at the mercy" of the garbage collector is pretty damn frustrating. You're still at the mercy of the malloc implementation. I've seen some fairly nasty behaviour involving memory leaks and weird pauses on free coming from a really hostile allocation pattern causing fragmentation in jemalloc's internal data.

Which is why you generally almost never use the standard malloc to do your piecemeal allocations. A fair number of codebases I've seen allocate their big memory pools at startup, and then have custom allocators which provide memory for (often little-'o') objects out of that pool. You really aren't continually asking the OS for memory on the heap.

In fact, doing that is often a really bad idea in general because of the extreme importance of cache effects. In a high-performance game engine, you need to have a fine degree of control over where your game objects get placed, because you need to ensure your iterations are blazingly fast.

Post reply on HN