Jump to content

  • Log In with Google      Sign In   
  • Create Account


#ActualHodgman

Posted 07 August 2012 - 09:41 PM

N.B. Not trying to put a damper on these awesome ideas here, just pointing out some pitfalls to be aware of:
Two issues with supporting changes to data-structures (which implies serialization/deserializaiton) is that many game engines are (1) very specific about how their utilize their RAM, and (2) also very limited in the amount of RAM they can use.

(2) isn't an issue on PCs, and console dev-kits usually have double the retail-version's amount of RAM, so it's likely only a minor problem affecting some of your SKUs.

(1) complicates matters though. Even with a general-purpose allocator, when freeing 10,000 objects and then allocating 10,000 slightly larger objects, it's possible that the original allocations aren't contiguous (so they become little bubbles in your address space), and the new allocations are too big to fit in those "bubbles". This fragmentation of RAM can have the same effect as if you'd simply leaked the original allocations (until you free the used-space around them, probably at the end of the level), which can make it much more likely to hit the RAM limits from (2).

Further, optimised engines don't use global, general-purpose global allocators (i.e. new/malloc) for everything. To construct a certain kind of object, you might need to specify which allocation area to construct it in, and you might not be able to free that allocation at a random time (e.g. perhaps bulk-deallocation of the whole area is used).

For example, when allocating an object in our renderer, depending on which systems are likely to access it and it's required lifetime, the user will specify 1 allocator out of a possible 4 different stacks and 4 different heaps that could be used. i.e. the same object could be constructed within 8 different areas of RAM, but choosing the right one is important based on usage.
If the object is allocated in one of the stack areas, it's can't be freed at will; it's lifetime is bound to the lifetime of the stack. Reallocating with a larger size means 'leaking' the original and adding a new object on the top of the stack (which there might not be space for). Alternatively, it means serializing the entire stack and re-allocating the whole thing from the bottom-up to avoid these holes (and then patching any other objects that held pointers into this stack).

These aren't un-solvable problems, but a class-layout-patching solution that's applicable for every engine would have to be very flexible in regards to allocations, and may end up having to serialize/deserialze hundreds of megs of data per 'reload'.

That said, gameplay code is usually less performance-critical than engine code, so maybe you just don't support this feature on your critical engine systems ;)

#1Hodgman

Posted 07 August 2012 - 09:27 PM

N.B. Not trying to put a damper on these awesome ideas here, just pointing out some pitfalls to be aware of:
Two issues with supporting changes to data-structures (which implies serialization/deserializaiton) is that many game engines are (1) very specific about how their utilize their RAM, and (2) also very limited in the amount of RAM they can use.

(2) isn't an issue on PCs, and console dev-kits usually have double the retail-version's amount of RAM, so it's likely only a minor problem affecting some of your SKUs.

(1) complicates matters though. Even with a general-purpose allocator, when freeing 10,000 objects and then allocating 10,000 slightly larger objects, it's possible that the original allocations aren't contiguous (so they become little bubbles in your address space), and the new allocations are too big to fit in those "bubbles". This fragmentation of RAM can have the same effect as if you'd simply leaked the original allocations (until you free the used-space around them, probably at the end of the level), which can make it much more likely to hit the RAM limits from (2).

Further, optimised engines don't use global, general-purpose global allocators (i.e. new/malloc) for everything. To construct a certain kind of object, you might need to specify which allocation area to construct it in, and you might not be able to free that allocation at a random time (e.g. perhaps bulk-deallocation of the whole area is used).

For example, when allocating an object in our renderer, depending on which systems are likely to access it and it's required lifetime, the user will specify 1 allocator out of a possible 4 different stacks and 4 different heaps that could be used. i.e. the same object could be constructed within 8 different areas of RAM, but choosing the right one is important based on usage.
If the object is allocated in one of the stack areas, it's can't be freed at will; it's lifetime is bound to the lifetime of the stack. Reallocating with a larger size means 'leaking' the original and adding a new object on the top of the stack (which there might not be space for). Alternatively, it means serializing the entire stack and re-allocating the whole thing from the bottom-up to avoid these holes (and then patching any other objects that held pointers into this stack).

These aren't un-solvable problems, but a class-layout-patching solution that's applicable for every engine would have to be very flexible in regards to allocations, and may end up having to serialize/deserialze hundreds of megs of data per 'reload'.

PARTNERS