Followers 0

Go language use in performance-critical code

16 posts in this topic

Coming from a C/C++ perspective, Go looks like a really nice language. I would really like to try it out. I'm curious though if anyone has considered it for game development?

Other than a lack of library support (which will improve over time), my main concern with the language is how it handles memory management. It has a GC, and appears to have a lot of dynamic data types. I can only assume that this means it will be doing memory allocation at runtime. At least, that's what a C/C++ program would be doing. It is possible that Go is structured differently internally to allow seeming-dynamic features within a fixed memory allocation. But I don't know, and so hesitate to try it in performance-critical code, like games.

Does anyone have any insight into how Go handles memory management? Has anyone experimented with Go in performance-critical code and have feedback on how it performed?
0

Share on other sites
[quote name='kunos' timestamp='1354989701' post='5008545']
I don't understand what you mean for "dynamic types".. Go has no dynamic types, it's a very simple language statically typed... actually it is very strict about types, requiring explicit casts everywhere. Maybe you are confused by interfaces and duck typing.. but those aren't strictly "dynamic" features... most of them are evaluated at compile time.
[/quote]
What I mean is, things like strings and maps, which are variable in size. They don't have a fixed memory footprint at compile time.

[quote name='kunos' timestamp='1354989701' post='5008545']
Memory management is not very different from C like languages, so, from a performance point of view, the same rules are valid.. avoid creating things on the heap if you can... that's about it... the best way to optimize on a GC is to avoid triggering it.
[/quote]
I guess part of my question is wondering how you avoid it. I haven't read much on how Go handles it's memory management, and it seems a lot less transparent than it was in C/C++.

In C++, if you avoid malloc() and new, and don't use objects which are known to do runtime allocation, then you're good. With Go, I don't know what that set is. As great as Go looks, I'm curious how much of the language you have to avoid using if you want to keep tight control over what memory allocation occurs. There is probably a document out there somewhere that talks about this, but I haven't seen it.

[quote name='kunos' timestamp='1354989701' post='5008545']
Performance wise, from my tests on Windows (game oriented stuff like graph traversals and basic math) is in the same ballpark with C# using the standard go compiler. On Linux you can use the gccgo compiler built over the gcc complier and that's pretty damn fast... and runtime performances are only going to get better due the nature of the language.
[/quote]
Do you mean that gccgo compiles really fast, or that the resulting code is much faster than the standard go compiler? Do you have (or know of) any benchmarks?

[quote name='kunos' timestamp='1354989701' post='5008545']
[/quote]
Good to know! I hadn't considered that bit. But definitely worth considerign still, given all of the other language benefits.
0

Share on other sites
[quote name='Nairou' timestamp='1354990643' post='5008549']
What I mean is, things like strings and maps, which are variable in size. They don't have a fixed memory footprint at compile time.
[/quote]

Unlike C++, which uses no strings or maps or variable size structures in non-trivial programs...
0

Share on other sites
[quote=http://www.ferrousmoon.com/forums/viewtopic.php?p=14287#p14287]
With today's release of Go, I thought I would write a version of GenPrime for it, one because I wanted to see if it was really as speedy as it says and two to practice this new language.
First, the C version as a comparison:
Code:
eddie@ganglion:~/dev/genprime$./genprime-c 250000 1000000 Found 250000 primes in 5.75923 seconds (last was 3497861) Found 500000 primes in 16.15777 seconds (last was 7368787) Found 750000 primes in 29.94442 seconds (last was 11381621) Found 1000000 primes in 46.37428 seconds (last was 15485863) Now for Go: Code: eddie@ganglion:~/dev/genprime$ ./genprime-go 250000 1000000
Found 250000 primes in 4.253223 seconds (last was 3497861)
Found 500000 primes in 12.105688 seconds (last was 7368787)
Found 750000 primes in 22.779920 seconds (last was 11381621)
Found 1000000 primes in 34.426428 seconds (last was 15485863)

I compiled the Go version with the Plan 9 compiler (6g). Apparently there is a GCC port that is reported to produced more optimized code in some cases, so if anyone wants to test this code with the GCC port I'd be interested to see the results.
I'll be committing my code to my GitHub fork of GenPrime.[/quote]

So not lagging too far behind plain C in that particular test case.

I can't recall where but I vaguely remember finding a .pdf with a few more test cases with very similar results.

There is also this page I found but I don't really know whats going on here: http://golang.org/test/bench/shootout/
0

Share on other sites
[quote name='Telastyn' timestamp='1354994045' post='5008570']
[quote name='Nairou' timestamp='1354990643' post='5008549']
What I mean is, things like strings and maps, which are variable in size. They don't have a fixed memory footprint at compile time.
[/quote]

Unlike C++, which uses no strings or maps or variable size structures in non-trivial programs...
[/quote]In case anyone hadn't picked up on this, the above was clearly sarcasm.

Also, GC is not a memory leak panacea. Our newer client software at work which is written in C#, "leaks" far worse than the older C++ client.
0

Share on other sites
[quote name='Telastyn' timestamp='1354994045' post='5008570']
[quote name='Nairou' timestamp='1354990643' post='5008549']
What I mean is, things like strings and maps, which are variable in size. They don't have a fixed memory footprint at compile time.
[/quote]
Unlike C++, which uses no strings or maps or variable size structures in non-trivial programs...
[/quote]
Well in C++ those are just part of STL, not build into the language. You can choose to use a std::string, or you can just use a char array. You aren't forced to use a string, because it isn't actually part of the language. In Go, you just have a string, and it's a part of the language, so they expect you to use it. Which is fine, I just want to understand what's going on behind the scenes.

[quote name='iMalc' timestamp='1355006316' post='5008619']
Also, GC is not a memory leak panacea. Our newer client software at work which is written in C#, "leaks" far worse than the older C++ client.
[/quote]
Exactly. I have more memory leaks in my C# applications than I do in my C++ applications. I want to have some level of control over memory management, especially in a game. I just don't know enough about Go yet to know if it gives that level of control.
-1

Share on other sites
Sorry, the STL hasn't been around for years. The C++ standard library is part of the language, and that includes strings.

To be explicit, you need not worry about those things in go for performance concerns. Frankly, it sounds as though you worry about using them due to performance in C++, which is absurd.
1

Share on other sites
[quote name='Nairou' timestamp='1354990643' post='5008549']
Do you mean that gccgo compiles really fast, or that the resulting code is much faster than the standard go compiler? Do you have (or know of) any benchmarks?
[/quote]

gccgo compile times are not as fast as the standard go compiler but still way faster than C++ code. I was refering to runtime performances where gccgo is surprisingly fast.

I don't understand your obsession with dynamic memory. Every language needs it. Strings, maps, vectors in C++ are all implemented with dynamic memory behind the scenes. Go doesn't move stuff into dynamic memory behind your back. So you know that callig "new" will be a dynamic allocation, calling make will be a dynamic allocation, returing the address of a stack created object will be a dinamic allocation.. and operations like "append" or adds to a map might be dynamic allocs... this is all EXACTLY what you get in every other language.
0

Share on other sites
I work with Go on a daily basis, but never in game development. I've never done any benchmarking but it's definitely performant enough for any web server (Google does use it for production web servers) and the amazingly speedy compile time alone is enough to make up for any minor performance downfalls IMO.

To comment on your specific question about string vs char[], you can have fixed-size byte arrays in Go and cast between them and strings. In general I find Go a great language, but the libraries for it are still very immature.
1

Share on other sites
I've not seen the 2 (or 3) compared but .net and the JVM both manage to do ok on modern hardware and they must be far slower than Go. I think the only issue with Go is the lack of libraries, a problem which can be resolved.
0

Share on other sites
[quote name='Nairou' timestamp='1355017834' post='5008661']
[quote name='Telastyn' timestamp='1354994045' post='5008570']
[quote name='Nairou' timestamp='1354990643' post='5008549']
What I mean is, things like strings and maps, which are variable in size. They don't have a fixed memory footprint at compile time.
[/quote]

Unlike C++, which uses no strings or maps or variable size structures in non-trivial programs...
[/quote]

Well in C++ those are just part of STL, not build into the language. You can choose to use a std::string, or you can just use a char array. You aren't forced to use a string, because it isn't actually part of the language. In Go, you just have a string, and it's a part of the language, so they expect you to use it. Which is fine, I just want to understand what's going on behind the scenes.
[/quote]

To expand on Telastyn's response: [font=courier new,courier,monospace]std::string[/font], [font=courier new,courier,monospace]std::map[/font], [font=courier new,courier,monospace]std::vector[/font], etc. [url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3376.pdf"]absolutely are part of the language[/url] (see section 21 for the Strings library, section 23 for the Containers library, etc.). They just aren't [url="http://en.wikipedia.org/wiki/Primitive_data_type"]primitive data types[/url].

As for "STL"... The "[url="http://en.wikipedia.org/wiki/Standard_Template_Library"]Standard Template Library[/url]" was written before C++ was ever actually standardized, and is different from the [url="http://en.wikipedia.org/wiki/C%2B%2B_Standard_Library"]C++ Standard Library[/url]. When C++ was finally standardized in 1998, it incorporated parts (but not the whole thing!) of the popular STL into the standard itself (and the C++ standard defines what we call the "standard library"). The STL is not, however, fully incorporated into the standard library (for example, the STL's [url="http://www.sgi.com/tech/stl/Rope.html"]rope[/url] never made it into the standard library), and there are some differences between the STL and the standard library (aside from the fact that the standard library adds more than was originally in the STL). Instead of saying "the STL is the standard library," we should say "the STL influenced the creation of the standard library." Unless you're specifically referring to the Standard Template Library that was written by Alexander Stepanov and Meng Lee before C++ was ever standardized, you probably mean (and should say) the C++ Standard Library [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img] Edited by Cornstalks
0

Share on other sites
[quote name='6677' timestamp='1355004138' post='5008612']
There is also this page I found but I don't really know whats [u][b]GO[/b][/u]ing on here: [url="http://golang.org/test/bench/shootout/"]http://golang.org/test/bench/shootout/[/url]
[/quote]
har har
1

Share on other sites
[quote name='Cornstalks' timestamp='1355261588' post='5009546']
To expand on Telastyn's response: [font=courier new,courier,monospace]std::string[/font], [font=courier new,courier,monospace]std::map[/font], [font=courier new,courier,monospace]std::vector[/font], etc. [url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3376.pdf"]absolutely are part of the language[/url] (see section 21 for the Strings library, section 23 for the Containers library, etc.). They just aren't [url="http://en.wikipedia.org/wiki/Primitive_data_type"]primitive data types[/url].

As for "STL"... The "[url="http://en.wikipedia.org/wiki/Standard_Template_Library"]Standard Template Library[/url]" was written before C++ was ever actually standardized, and is different from the [url="http://en.wikipedia.org/wiki/C%2B%2B_Standard_Library"]C++ Standard Library[/url]. When C++ was finally standardized in 1998, it incorporated parts (but not the whole thing!) of the popular STL into the standard itself (and the C++ standard defines what we call the "standard library"). The STL is not, however, fully incorporated into the standard library (for example, the STL's [url="http://www.sgi.com/tech/stl/Rope.html"]rope[/url] never made it into the standard library), and there are some differences between the STL and the standard library (aside from the fact that the standard library adds more than was originally in the STL). Instead of saying "the STL is the standard library," we should say "the STL influenced the creation of the standard library." Unless you're specifically referring to the Standard Template Library that was written by Alexander Stepanov and Meng Lee before C++ was ever standardized, you probably mean (and should say) the C++ Standard Library [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]
[/quote]
Very interesting!

The point I was trying to make is that, being part of the standard library and not a core part of the language itself, they are optional. You can use a std::string if you want, with it's pro's and con's, or you can use a char*. The latter is a direct part of the language, and is very explicit and simple, while the former is part of a library and can have side effects (i.e. dynamic memory allocation behind the scenes). Once you understand how std::string works, it isn't a big deal. It's memory allocation is just a part of it's pros/cons list. But it's something to be learned.

Likewise, as someone who doesn't know Go very well, I was curious about which parts of the Go language have these sorts of memory allocation side effects. While std::string is an optional library component in C++, it appears to be a core part of the language in Go (you don't need to import anything to use a string). This makes it harder, on the surface, to know where these side effects are.

(And to those who think I'm being obsessive, [url="http://gamesfromwithin.com/start-pre-allocating-and-stop-worrying"]read this[/url].)
-1

Share on other sites
How heavy is your world simulation though? The difference between 1k and 10k players on a server isn't necessarily linear, especially if you have any nontrivial simulation being done per-tick. Keep in mind that a lot of other factors can grow nonlinearly as well, such as dispatching socket traffic to various handlers. Especially as thread contention for shared resources increases, things can degrade at very unpredictable points.

In short, I'd caution heavily against assuming that 10% CPU at 1k players implies 10k potential players. 10k is a very, very ambitious target unless your game simulation is borderline trivial. I'd strongly recommend doing genuine load tests: the fun part of network systems is that they tend to fall over in ways you did not anticipate. Usually that means sooner than you hoped ;-)
2

Create an account

Register a new account