Want Some Help, Qu?

Announcements and infodumps from the Species dev team.
Post Reply
Yushatak
Posts: 3
Joined: Thu Jan 24, 2019 2:36 pm

Want Some Help, Qu?

Post by Yushatak » Thu Jan 24, 2019 2:40 pm

I've been working on an evolution simulator in 2D with a custom neural network library and my own engine built on top of C# and MonoGame (XNA4 OSS clone if you're unfamiliar). I've got complex neural networks running in parallel at thousands of simulation frames per second with plenty of creatures, and I noticed you're trying to do multithreading for Species.. I was wondering if you'd like to join forces! While I'd love to officially join the dev team and work for ya full time, I don't know what the situation is with how much money Species is pulling in or if it's just you at your house in your spare time, so if that'd be untenable I get it. I'd love to collaborate either way, though - I love working on stuff like this and it would be cool to compare notes and maybe help each other fix/implement a thing or two if nothing else. :D

Edit: My focus has been trying to get behavior to evolve from literally nothing but random possibilities. I suspect Species uses some preprogrammed behavior and evolves from there since it seems so difficult to make it occur naturally, but I'd love to chat about it. I have insights that could save you upward of 20-50% on performance:

- Don't use properties and interfaces, almost at all. I know it might be unintuitive to do this from a language and code hygiene perspective but I've seen as much as a 15-20% increase in speed from heavy property use and interfaces to fields and traditional inheritance.

- I've messed with multithreading a lot both in games and in commercial/government software writing, and have a good grasp on which tools to use where that might save you some time, such as when to use the Parallel class vs. the Task class, etc..

I don't mean to imply that you definitely don't know these things but am using them as examples of things that matter which you might not.

I'll give you access to poke around my project at https://yushatak.visualstudio.com/Charybdis if you'd like it. I'd appreciate being able to see some of your code but since you've got a commercial release I understand if you're hesitant to share (I'd sign paperwork/NDAs if that'd help put you at ease).

Edit 2: To give you an idea of my coding chops:
I post some articles on my Tumblr regarding code I'm working on or code-related topics occasionally: http://yushatak.tumblr.com/

Here's a video I made to demo an early version of my terrain generator to Garry (I was pitching it to him for Rust, but he didn't think he needed it - he did respond though, so that's cool): https://www.youtube.com/watch?v=AV8AgU0DMbw

Zephandrypus
Posts: 5
Joined: Sat May 16, 2015 12:33 am
Location: US, North Carolina

Re: Want Some Help, Qu?

Post by Zephandrypus » Thu Jan 24, 2019 4:33 pm

Eyyyyy, what a coincidence, I'm looking to join in on the fun too.

I'm also working on building a neural network library from scratch. None of the other C# libraries seemed to be working for me, and besides, I wanted to ensure it was thoroughly optimized.

On your performance suggestions:

- I thought properties were optimized to fields if having a property was unnecessary.
- I haven't seen much use for interfaces beyond compatibility with structs.
- I've actually been looking to figure out when/how to use those multithreading classes.

My own performance suggestions (there has to be something new you can learn, right?):

- Remember to use only the largest datatypes you need.
- Bools are a single byte. If you have multiple, use flags to make better use of that byte.
- Structs are faster than classes, if you have data that can fit into 16 bytes or less.
- Knowing the CPU cache sizes, and trying to limit reads/writes to them as much as possible, can make an insane difference.
- Be incredibly meticulous when figuring out how to encode data into a file. It's like playing Rummikub, in a way.

Edit: And if any of you want to get in contact, my Discord is Zephandrypus#0611

And I wouldn't mind poking around your project. My email is Zachary99Johnson912@gmail.com

Yushatak
Posts: 3
Joined: Thu Jan 24, 2019 2:36 pm

Re: Want Some Help, Qu?

Post by Yushatak » Thu Jan 24, 2019 4:59 pm

Zephandrypus wrote:
Thu Jan 24, 2019 4:33 pm
On your performance suggestions:
Had some responses to these.
- I thought properties were optimized to fields if having a property was unnecessary.
Yes, but it depends on your optimization level, the complexity of the code (it will fail to understand and decide not to optimize in more complex scenarios if I'm not mistaken), and whether you're using accessors with code in them (which prevents optimizing them away entirely).

Also it will make it hard to debug if the code chugs when unoptimized and it's something like an evolution simulator!
- I haven't seen much use for interfaces beyond compatibility with structs.
Interfaces make for very elegant code where you can decouple the code that operates on things from the things themselves and make multiple classes that implement the interface be usable by the same bits of code. It's much slower, though, so in performance situations it's much better to do this with inheritance. It's not something you *must* do, but if you do want reusable/modular code like this it's best to avoid interfaces in demanding code.
- I've actually been looking to figure out when/how to use those multithreading classes.
Let's talk about this on Discord, can chat and share some code snippets. This is very use-case-specific stuff.
- Remember to use only the largest datatypes you need.
There's a caveat to the datatype thing - it's actually faster to use INT32 than other datatypes in many cases since modern processors are optimized in hardware for handling these values far more than INT16, for example (difference may be negligible in many cases but everything helps and if it occurs a lot it adds up).
- Bools are a single byte. If you have multiple, use flags to make better use of that byte.
And you can use flags/enum on other datatypes to do the same, most efficient being the INT32 due to the thing I mentioned earlier about datatypes. The code for checking "HasFlag" by the way is suboptimal in .NET, use this instead (In this case LoggingPoint is an INT32 enum):
/// <summary>
/// Checking the enum this way is about 10x as fast as Enum.HasFlag.
/// </summary>
protected bool HasLoggingPoint(LoggingPoint lp)
{
return (_loggingPoints & lp) == lp;
}

It is necessary to write a method like this for each enum or just directly do the bitwise & and == in each spot to get maximal speed.
- Structs are faster than classes, if you have data that can fit into 16 bytes or less.
Make sure you don't treat them like classes at large sizes, though, since they are handled differently in C#. Structs are literal data whereas classes are references, which means a lot when dealing with a ton of either in memory depending on the situation. Haven't found a situation where I've needed to store <16B in a struct, myself, where I didn't just end up using a ulong or something built-in.
- Knowing the CPU cache sizes, and trying to limit reads/writes to them as much as possible, can make an insane difference.
I haven't thought much about CPU caching as I figured .NET would be handling that at some level of its JIT, do you have any examples where that has made a difference?
- Be incredibly meticulous when figuring out how to encode data into a file. It's like playing Rummikub, in a way.
I've only done a bit of this, but I definitely agree. It's all a balance between efficiency of execution and efficiency of space usage and when to focus on which how much.

User avatar
Quasar
Site Admin
Posts: 1732
Joined: Tue May 29, 2012 2:04 am

Re: Want Some Help, Qu?

Post by Quasar » Thu Jan 24, 2019 11:05 pm

Hi Yushatak(and Zephandrypus),

I appreciate the offer and I'd love to collaberate, but you should know I don't think I'm quite ready to employ someone yet, certainly not full-time (I only work on it part-time). On the other I could really use someone with your experience right now, so you'll have to give me some time to take a look at your links and think on it.

Incidentally, Species is also made in C#/Monogame.
Don't use properties and interfaces, almost at all. I know it might be unintuitive to do this from a language and code hygiene perspective but I've seen as much as a 15-20% increase in speed from heavy property use and interfaces to fields and traditional inheritance.
I have also encountered this, and some of the optimizations on steam were exactly this. However I'm not discounting the possibility that this is an issue specific to debug mode and the code analysis tool I'm using, which obviously add a certain amount of time to method calls.I haven't really tested it in release mode, but if I can get a code hygiene advantage in debug mode without significant cost in release mode, I'll more than happily embrase a sluggish debug build.

In my work on multithreading I've actually ended up re-introducing a lot of properties, because I am extremely cautious about race conditions and wanted to build a defensive architecture to prevent them as much as possible. I'll optimize where I can once the implementation works.
- I've messed with multithreading a lot both in games and in commercial/government software writing, and have a good grasp on which tools to use where that might save you some time, such as when to use the Parallel class vs. the Task class, etc..
Truth be told, at the level of Task and Parallel my multithreading implementation is extremely simple.Each frame I use Task.Factory.StartNew() to start X threads, where X is the number of processors. Each of these threads processes a percentage of the creatures behavioral response while the main thread continues simulating the world.All the complicated stuff happens under the hood, preventing the main thread and other creatures from stepping on each others behavioral responses.
- I haven't seen much use for interfaces beyond compatibility with structs.
Aside from the performance cost, interfaces are the best things ever. The interface I use most commonly in Species is IEdible.Anything that implements IEdible can be consumed by creatures, without the creature needing to implement different routines for consuming creatures vs trees vs grazespots vs any other food source I may implement.

Another valuable one is ISelectable, which allows any entity it's implemented on to be selected in the UI.

This is all technically achievable with the Entity base class, but a) I'd need an "isSelectable" and "isEdible" boolean flag for entity types that aren't selectable or edible, and b) the Entity base class would need to include if (this is Creature) / else if (this is TreeObject) / etc statements to create differences in implementation, which would suck. Might be faster, but would definately suck.
Let's talk about this on Discord, can chat and share some code snippets. This is very use-case-specific stuff.
Link me in on the conversation, I'd be interested to read what you both have to say.

Yushatak
Posts: 3
Joined: Thu Jan 24, 2019 2:36 pm

Re: Want Some Help, Qu?

Post by Yushatak » Fri Jan 25, 2019 8:44 pm

Sent a link in PM.

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest