Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

For a 2x speed up, I am not sure I would be willing to sacrifice legibility as in the example. The OOP method definition reads like english.

The article suggests the true benefits of DOP aren't all that great unless you understand the target architecture.

I feel like the pendulum is at its new zenith.



As always, it depends on the problem you're solving.

A 2x speedup in the inner loops of a game can be a very big deal. And for business workloads, I occasionally spend time babysitting clusters running batch jobs. A 2x performance increase in the right inner loop might save a couple hundred dollars per run.

So certainly, profile before you optimize, as the article demonstrates. But 2x speedups can be worth applying a "struct of arrays" transform.


The interesting thing to me from these patterns is the possibility of using proc_macros to write code in the "array of structs" style while the code gets desugared to "struct of arrays". I don't know how beneficial that would be, but having it as an option would make this pattern more approachable to people that would otherwise not use it, due to verbosity, mental model mismatch or any other reason people might have not to do this.

I don't think Rust itself will ever incorporate this feature into the language, just like it doesn't transparently wrap a `dyn Trait` into a `Box<dyn Trait>`, but I would expect that it will never put active roadblocks for libraries to extend the language in such a way. (The regular proc_macros caveats would apply, of course.)


It seems likely to me that Rust will use ECS queries as the idiomatic way to write struct-of-arrays code.

In archetype-based ECS libraries (which the ecosystem seems to be converging on or near) you write a query asking for a particular subset of "component" types, where each type is stored in its own array(s), and then for each iteration of the query you get back one reference to each component type.

As a result, all the extra zipping (which I'm assuming is what people find less readable about the article's example) is handled in the query implementation, and you get this sort of hybrid between the two, syntactically speaking:

    for (location, velocity, acceleration) in players.query::<(Location, Velocity, Acceleration)>() {
        *location = (
            location.0 + velocity.0,
            location.1 + velocity.1,
        );
        *velocity = (
            velocity.0 + acceleration.0,
            velocity.1 + acceleration.1,
        );
    }
Some libraries even let you write a query as a struct with a #[derive] on it, rather than a tuple, so you can use essentially the same syntax as the "OOP" example from the article, rather than destructing the "fields" up front.


Tiny nitpick: that turbofish syntax wouldn't be possible due to lack of support for variadic type parameters, but otherwise this seems reasonable.


Whoops- the actual libraries I'm thinking of wrap those args in a tuple. I've updated the example.


> The interesting thing to me from these patterns is the possibility of using proc_macros to write code in the "array of structs" style while the code gets desugared to "struct of arrays".

This is not possible in the general case, because you can have a general pointer/reference to a single struct in an "array of structs" but a "struct of arrays" can only be accessed by indexing each array separately. So only very simple and self-contained programs can possibly be "desugared" in this way.


In "struct of arrays" all the arrays have the same size and indexing, so the array index into "array of structs" is the same as the index into each array in "struct of arrays".

A general pointer/reference type that might point to a single struct in "array of structs" can be transformed to a "wide pointer" representation as pointer/reference to the array and index into the array.

If analysis can't prove the pointer is constant, then the representation will be an opaque wide token outside the transformed code, which is fine. If it can prove the pointer is constant, the run time representation does not need to be wide, as it's just the index, also opaque outside the transformed code.

There's no need to have a representation as a regular pointer, because there's no way the struct pointer/reference type can be dereferenced outside of transformed code anyway, only passed around.


This is Jonathan Blow's goal with his in-development language Jai, see for example this video:

https://www.youtube.com/watch?v=YGTZr6bmNmk


I think the data-oriented version is very appropriate for a game, where performance is king and there's not that much maintenance afterwards once its done. Perhaps I'm wrong but games seem to be very much a finish and toss it over the wall sort of project. Much less iteration than other contexts.


That is changing over time as post launch support grows and some games shift to games as a service


Are the "games as a service" games adding significant code after launch? I think most of the performance critical stuff is in the engine and core game loops. Content packs and seasons aren't likely to change those core bits, and instead be more assets and scripting intensive.


Destiny 2 just had to announce a complete re-do of how they're doing content now and in the future, because the game is significantly held down by technical debt from previous content.

https://www.bungie.net/en/Explore/Detail/News/49189


Yes they do quite often. A certain amount of maintainance (bugfixing and optimisation) is required but also you are improving core systems to enable new capabilities and increase other developers productivity.


I think DoD can be ergonomic, actually, if you're doing it just for the architecture reasons vs. the optimizations reasons, to the point that you choose DoD due to them. At least I personally have found that eg. an ECS architecture can lead to separations and structurings of logic code that were helpful, while still defining data in ways that I could just make accessible to tooling and so on.

In this talk on their architecture for Overwatch: https://youtu.be/W3aieHjyNvw (highly recommend) you can see that the wins / concerns they talk about have to do with architecture more than perf. Big insights at 8:00 in the video.




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

Search: