Finally something about this topic that isn't a 1hr talk from some random conference. Thank you!
@CoffeeBeforeArch
4 жыл бұрын
No problem! Glad you liked the video!
@Anon.G
4 жыл бұрын
Exactly what I was thinking
@andrespedraza8939
4 жыл бұрын
Are you referring to the Mike atcon conference and the cppcon?
@justadude8716
Жыл бұрын
Mike Acton talk is over hyped. Bad examples by even artificial standards and just high and mighty attitude. The talk on DOD on 2018 cppcon is far better.
@koktszfung
4 жыл бұрын
Great and intuitive explanation! It would be better if the volume is greater.
@RupertBruce
4 жыл бұрын
An excellent explanation of the motivation for DOD. Thank you!
@syrix5914
3 жыл бұрын
Nice and simple explanation! I like it.
@mehtubbhai9709
11 ай бұрын
A very concise presentation on DoD. Thank you!
@Detective_Jones
Жыл бұрын
as Humble java coder i recognize 1:38 as bad programming practice glad he is teaching people not to copy and paste their lines 100s of times and instead to use lists/arrays and loops i see people starting out doing this mistake rather then simplify and using good programming practices
@sashareinhard6645
Жыл бұрын
Making those ints into an array will not improve performance, at all. He just put those as place holders for what would normally be lots of fields of different types and unique names. His point was AoS vs SoA
@10e999
3 жыл бұрын
Good video. That said it's more a demonstration of array-of-struct vs struct-of-array, which is only one of the many pattern of DOD (vs OOP for example).
@MyNameIssaSimon
4 жыл бұрын
How would the performance be if you just access just one “employee” and update v0-15. Wouldn’t OO be faster?
@CoffeeBeforeArch
4 жыл бұрын
Yes, it would! I mention this at 10:48 in the video
@motbus3
3 жыл бұрын
this is the greatest power of this channel
@quant-prep2843
2 жыл бұрын
Somebody here doing gods work
@noxagonal
3 жыл бұрын
I can definitely see a lot of places where this is going to be useful. Mainly storing vertex data fields separately. Vertex Animation doesn't usually update much more than just the positions of vertices. Maybe normals, but that can have it's own update pass. Oop is still better front-end for the user but for internal data structures this should be pretty easy to do.
@Inf4mousKidGames
Жыл бұрын
hold on... structures can house functions? When was this a thing? neither of my C++ professors in college informed me of this. *Having an existential criss*
@CoffeeBeforeArch
Жыл бұрын
Structs and classes are identical in C++ apart from their default access specifier (public vs private respectively)
@harywhiteproductions
8 ай бұрын
You're a great teacher!
@sergeykolesnik1171
11 ай бұрын
Although this is a good demo, it reminds me of a South Park episode about gnomes. But with a slight modification in this case: "1. ??? 2.Use SaO 3.Profit". "Benchmarking SoA" video title would be a 100% descriptive in this case. But in no way it is a "Data-oriented Design". This video would have a lot more exclusive value if you showed at least a basic example of a real life problem. Becuase "if we had data stored in such a way to eliminate cache misses" is just a magic thinking. What about writing? What about sorting or filtering? What about concurrency and shared memory access? What about existing ways to abstract the data? Don't get me wrong, this material and video is valuable (alghough not unique). But when people search for "DoD Design in practice", this video title is false-advertising.
@mattzrsimon
3 жыл бұрын
as a former skeptic as of this video, i'd like to see that in a more robust application - or at least with more robust data and processing - to actually settle this discussion. looks promissing but i'm wondering if the complexity - or lack thereof - of this application skews the results towards dod. otherwise great video my dude.
@poryg5350
Жыл бұрын
It's not the lack of complexity that skews the results.If you increase the vector size to 1000 and the amount of objects to 1000, DOD will still be superior in this case. It's the misuse of OOP. DOD shines best when you have a large collection of the same data that needs to be manipulated at once. For instance, every frame advancing x and y coords would be fine. But it's terrible for when you only need to work with a segment of that data. For instance, in a combat system DOD would be no better than OOP. In OOP you'd load a player and enemy objects and the values relevant to calculate damage would be closely packed together. If you used DOD for that, you'd be jumping between HP arrays, attack arrays, defence arrays... and you'd pollute the cache with unnecessary data every time. Just like you're doing in the presented case with OOP where you're caching the entire object to access a single variable.
@rmmajd
3 жыл бұрын
thank you for the video it was very informative.
@CoffeeBeforeArch
3 жыл бұрын
Glad you enjoyed it!
@oracleoftroy
2 жыл бұрын
Honestly, only measuring the worst case makes this look a little deceptive. I'd be more interested in a more representative case, like say an array of vec4 vs struct of arrays of x, y, z, and w components where you might use 2 or 3 (or all 4) for a calculation. Or what about a struct of mixed fields (you mentioned an "employee", so how about names and salaries and departments and schedules and other mixed types), vs splitting those fields into separate arrays. You show the absolute worst case, but I think it would be more useful to show the typical case to better weight the cost in more realistic scenarios. In my own code, I tend toward an "object oriented" approach (which seems to mean different things to different people, so who knows how meaningful that term is), and thus I tend to have data that is used together in one struct. I avoid the "ball of mud" antipattern that dumps lots of unrelated data into one object. When I've toyed with DoD for my code, I haven't tended to see performance improvements, no doubt because all the data was needed for the calculations I was doing (which is why they were in one object in the first place) while unrelated data was called out in separate objects and thus not polluting the cache line. So this leaves me wondering what real advantage DoD has for those who follow OO mantras like single responsibility and inversion of control which tend towards smaller focused objects with the exact data needed.
@Fred1989
2 жыл бұрын
In your last paragraph, you wrote that you had unrelated data out in separate objects and asked what the real advantage DoD has but if you ask me that IS an actual advantage. What you tend to see in matured projects is that as the codebase grows (and its complexity) the inheritance tree of certain classes grows as well. And they bring in all their data members and methods, said data may be totally irrelevant to some method you called on that object that has inherited all that extra luggage. Now let's say you have a vector of those objects that may be inheriting from 5 other classes and you're doing some calculation on one or more of their data members, you'll definitely be introducing tons of cache misses. Removing that extra luggage would break other parts of your codebase that uses them... refactoring became too much work as time went on and would cost too much... and this is what you unfortunately tend to see in a strictly object oriented approach. The thing is that an object oriented design and data oriented design are just tools you have in your toolbox and strictly wanting to adhere to one is in my opinion always a mistake they both have their place, it's just that in my experience it's usually too late to change the design when you actually start noticing things slowing down. Simple benchmarks you see demonstrated in this video just point out problem areas. You could easily write an employee class where you have an array of employee ids vs. an array of employee objects which you use to calculate their salaries or whatever. However, in essence, it's pretty much the same and an array of object pointers will result in a lot of cache misses.
@oracleoftroy
2 жыл бұрын
@@Fred1989 Well, this speaks to a false dichotomy I see a lot. OOP doesn't mean everything is inherited, that's just one tool of several in the OOP toolbox. Nor is it DOD vs inheritance hierarchies. I use inheritance as often as I need to, and that usually means not at all. There are plenty of other ways to gain polymorphism that often work out better. "Composition over inheritance" has been a mantra for decades in the OO world after all. I'd point to std::vector as the perfect example of an object oriented type, it is an object that is generic exactly where it needs to be, it inherits exactly as many bases as it needs to achieve this generic behavior (zero), and it performs well for it. Such an approach focuses on objects that behave as values instead of as pointers. An array of objects following such an approach does not mean cache misses due to pointer chasing as there are no pointers being chased, or no more than a DOD approach would have (maybe less). Thus the key difference I would like to see explored is object locality vs separate arrays of data and arranging code in a way that encourages vectorized operations. Inheritance just seems like a red herring that makes an easy target, but doesn't really speak to the main issue as I see it.
@williamiiifarquhar4345
Жыл бұрын
Can someone help me to understand this: If a cache line is 16 integers long, then why is it that an array of structs with 16 integers each has cache misses in between each struct but a struct of arrays with 16 integers each has hardly any cache misses between the arrays? And also thank you for such a great video on this topic. Very concise and informative.
@CoffeeBeforeArch
Жыл бұрын
In the array of structs case, we're accessing integers that are spaced 16 integers apart from each other (because all of the data members of structs are stored next to each other in memory). In the struct of arrays case, we're storing all of the integers we're accessing next to each other in memory.
@williamiiifarquhar4345
Жыл бұрын
Thank you for the prompt reply. I totally get it now! Thanks again for such great content.
@miguelalbertooxa8699
2 жыл бұрын
Do "data oriented design" and "data oriented programming" are the same ??
@_myron
4 жыл бұрын
cool channel!
@CoffeeBeforeArch
4 жыл бұрын
Thanks! Glad you think so!
@juliusmazer6485
3 жыл бұрын
Awesome Video! Great Channel!
@CoffeeBeforeArch
3 жыл бұрын
Thanks! Glad you think so!
@androkon6920
4 жыл бұрын
What's preventing a compiler from just translating an OO design into a DO design? They already take advantage of stupid stuff like arrays being stepped thru backwards being faster on some machines.
@CoffeeBeforeArch
4 жыл бұрын
There are a couple of reasons. For one, the C++ standard says that the order in which data members are defined are the order in which the appear in memory. Second, it's quite a lot to be asking of your compiler to understand the semantics of you application and tune for specific hardware details (like cache size/associativity). Easier said than done I'm afraid.
@androkon6920
4 жыл бұрын
@@CoffeeBeforeArch Ahh. That's probably why it's in the standard: to prevent people like me from writing half-assed compilers that bastardize code.
@darkengine5931
3 жыл бұрын
@@androkon6920 It would be much easier if you attempted that in my opinion to start off with a language where users are forced to store everything in parallel arrays (an SoA rep by default), and instead of optimizing towards the SoA, optimize towards converting to the interleaved AoS in cases that benefit from it (like loops that involve a lot of random access patterns). Unfortunately, that language would probably be more procedural than object-oriented, and maybe more like FORTRAN than C++.
@user-lv6qm3fj2z
4 жыл бұрын
Thanks! Say, does this work for C# too?
@CoffeeBeforeArch
4 жыл бұрын
Good question! There’s no reason (that I can think of) why it shouldn’t. C# runs on the same processor with the same caches as the C++ code. Accessing adjacent pieces of data will be faster than those that are far apart, regardless of the high level abstraction you use.
@tomwhitcombe7621
4 жыл бұрын
In the popular Game Engine Unity they're creating a Data Oriented tech stack using a subset of C# they're dubbing 'High Performance C#'. Worth checking out
@darrengrant8598
4 жыл бұрын
The difference you may find in C# (particularly on Windows where the GC is very well tuned) is that the managed memory will use heuristics to somewhat adapt itself to data access patterns as code executes, to try and minimize the odds of cache misses. It is sort of like another set of caches! This works really well for dynamic, unpredictable payloads (say, the sort of problem servers might deal with), but generally expect it to be sub-optimal for the sorts of problems that data-oriented design techniques address using some careful thinking.
@Peter_Siri
3 жыл бұрын
... so just adopting DOD is an upgrade
@BExploit
4 жыл бұрын
I'm kind of confused. I mean I get the whole idea but aren't vectors more like lists and not arrays? Because I thought that in lists one item points to the next one, so they're technically not 'next to' each other in memory. Or does C++ somehow optimize this? Am I missing something?
@CoffeeBeforeArch
4 жыл бұрын
It sounds like you’re thinking of std::list, which is a linked list. std::vector stores a pointer to a contiguous range of elements stored on the heap (it’s just a dynamically allocated array underneath the hood)
@BExploit
4 жыл бұрын
@@CoffeeBeforeArch Thank you for your reply, but a vector can't grow in the same "spot" in memory can it? I guess they allocate the memory and if you push_back one item they allocate that amount of space and copy the data over to the new space and then free the old space. I could be wrong on this one it is just a guess. In that case wouldn't a fixed size array be more effecient?
@CoffeeBeforeArch
4 жыл бұрын
You right, it can't grow in the same spot. If you call push/emplace_back, and you don't have the capacity for another element, it will allocate and new piece of memory, and copy the elements over. There is a growth factor to the allocation that keeps this from happening on every call to push/emplace_back. For example, libstdc++ uses a power of 2 growth factor. When you push/emplace_back, and don't have the capacity, it will first allocate for 2^0 more elements. The next time it grows, it will allocate for 2^1, then 2^2, then 2^3 (and so on). You can treat a vector like a fixed-size array as well. If you know how many elements (let's say N) you want in your vector ahead of time, you can just create your vector (let's call it v1), and call v1.reserve(N). This will do a single allocation for enough space for N elements. Then, all subsequent calls to push/emplace_back will not cause re-allocation (unless you push/emplace_back more than N elements). In this use-case, it's a nicer way of creating a dynamically allocated array than using `new` and `delete` directly (you don't have to manually keep track of the number of elements, worry about freeing the memory, and you can easily use STL algorithms).
@BExploit
4 жыл бұрын
@@CoffeeBeforeArch Ah thank you. I never gave all of this much thought, but it makes a lot of sense. I mean I just came across this topic because a friend at work and I were talking about optimizing code and I kind of had Data Oriented Design in the back of my head. So we researched the topic and the only simple and good example we could find was your video so thank you for that. I mean there are a lot of videos and presentations about this topic, but no really straight forward examples, it's kind of a shame since I think this is really important.
@patrikjankovics2113
3 жыл бұрын
I would like to argue that at 5:58 ArrayOfStructs had to allocate the memory first, but StructOfArrays could just reuse it. What's the performance like if you swap the order of iteration (Tha tis, run StructOfArrays first)?
@bitw1se
3 жыл бұрын
No, SoA and AoS each allocate independently.
@tristunalekzander5608
3 жыл бұрын
What if the sizes of the vectors have to change constantly? And what if those vectors themselves hold vectors that have to change in size constantly? Wouldn't that mess the cache up? Thank you great video!
@sagitswag1785
2 жыл бұрын
I am not entirely sure if I understand the senario you described correctly, so forgive me if I am wrong, but I think what you describe would have a worst case senario equal to the worst case senario of the OO approach, so you will still be saving time as long as no resizing is taking place
@Kalificus
3 жыл бұрын
haha math make code go fast
@MyNameIssaSimon
4 жыл бұрын
In 3:10. Why do you use auto &i instead of auto i. Isnt getting the pointer and incrementing it that way the same as getting the value and incrementing but with more steps?
@CoffeeBeforeArch
4 жыл бұрын
Using auto i would be accessing by value, instead of by reference. That means something like i++ would be occurring on a temporary. Because the loop would not be updating the vector, and just updating a temporary that immediately goes out of scope, the compiler usually just optimizes things like that away (it did this for me).
@MyNameIssaSimon
4 жыл бұрын
CoffeeBeforeArch ahh that very true. How does the ”foreach” loop, or what its called in c++, compare performance wise to just using a normal forloop and accessing each element by index?
@CoffeeBeforeArch
4 жыл бұрын
@@MyNameIssaSimon It's almost always the same performance. A big part of C++ is the idea of a "zero-overhead abstraction". The assembly generated by both is typically identicle.
@nicolareiman9687
4 жыл бұрын
There is a little sideeffect in compile time(which might be a little bit longer than the normal for loop). But in the run time the performance is still the same.
@MyNameIssaSimon
4 жыл бұрын
CoffeeBeforeArch okay cool. I’m currently learning some lower level languages. Its really fascinating
Пікірлер: 66