[InternalBufferCapacity( )] query Capacity at runtime

Hi,

I get that it’s a compile time value for the attribute, that’s no problem. But I want to query the buffer’s capacity at runtime once during setup (to allocate a non Entities array for other purposes) without having to create an entity first, add the buffer then query the Capacity.

Surely an easier way exists than this code?

        //due to attributes, wastefully figure out the capacity
        Entity e = EntityManager.CreateEntity();
        EntityManager.AddBuffer<SomeElement>(e);
        var buffer = GetBuffer<SomeElement>(e);

        //do something with buffer.Capacity number

        EntityManager.DestroyEntity(e);

Sorry to make your eyes bleed with this code, but I tend to just gravitate to the nearest thing that works, and now it’s time to improve this bit. Thanks!

You should be able to get the initial value off TypeManager.

int capacity = TypeManager.GetTypeInfo<SomeElement>().BufferCapacity;

From looking at the package sources, TypeManager handles the attribute read when it initializes all the TypeInfo.
(Internal implementation uses TypeManager.DefaultBufferCapacityNumerator / UnsafeUtility.SizeOf(type) right now by default for buffer elements without the attribute, if that’s of interest)
Also, EntityManager.AddBuffer<SomeElement>(e); itself returns the created buffer, you wouldn’t need to do a separate GetBuffer if you’ve been doing that in other places.

2 Likes

Ah yeah! Thanks a lot, very helpful.

Just to make sure, you are aware that a dynamic buffer can be larger than the InternalBufferCapacity, right?

Yep, and I want to make sure I don’t go over, so I can keep it local to the entity for better perf. This is really all so I don’t have to put the same constant amount in multiple locations in the codebase, which is a pain.

In my tests this is mostly not the case because the buffer, even with unused elements reduces the chunk capacity. And a small chunk capacity is the bane of Entities.
That said, it totally depends how much data you are having in the archetype. If it’s anywhere < 30-40 use InternalBufferCapacity(0) instead so it is allocated outside of chunk memory.

TBH, the performance increases you get for staying inside chunk data are marginal, very hard to measure and most of the times even a downgrade. You’d have to have vectorized code to really take advantage of it. With no vectorized code, don’t bother, design for a slim archetype.

1 Like

Vectorized code would not help at all. You’d still have to walk over the header. There are situations where having buffers in chunk is helpful, but they are rare and you would never want the default size (which is just awkward). Chunks are already smaller than I would like. Ideally each component array would have 4 kB to work with, since most hardware prefetching works in 4 kB pages.

2 Likes

My buffer is a float3 and the amount of elements would be between 2 and 16 (so I set initial capacity for 16).

So you are basically saying I might as well leave it at 0, auto grow/shrink etc?

If the entities this is on have rendering or child buffers, probably. Though if you have a non-zero minimum, it might be a wash. Really the only way to know is by profiling.

1 Like

Oh! Right …
Can you give a good example where it might make sense because I’m pretty much stumped where it would be useful and where no better solutions exist.

And hard agree on the chunk size! Pretty offtopic but I’d like your thoughts on the 128 chunk capacity limit that Unity is planning. Any opinion yet?

The use case I have is with the animation system I am working on. Each skeleton can have skinned meshes bound to it, and it keeps them stored in a system state buffer. Now it is possible for a skeleton to have no meshes bound, or multiple. But the common case is that there is exactly one mesh bound to the skeleton. So I set InternalBufferCapacity(1).

There might be some uses cases in AI where there is a conventional size for an action queue, but under special circumstances could be enlarged. But I haven’t explored that enough to tell you if that’s really a good idea or not.

I’m pretty fine with it actually, especially if they are going to stick to 16 kB chunks. I rarely have an entity without either a LocalToWorld or a FixedString64Bytes. And that by itself limits the maximum chunk capacity to a little under 256 entities. Add a few more components and 128 starts to look like a sweet spot. In fact, I’ve been using MaxChunkCapacity(128) for a lot of components in my animation system. Hard-capping the capacity lets me do cool things with chunk components that often lead to massive speedups. Sometimes I wonder if I am the only one outside of Unity that has really tapped into their potential.

3 Likes

You mention chunk components quite often. If you have the time, It’d be great if you could share how and when you are using chunk components. Like you say, me and many others probably don’t know about their potential yet.

1 Like

I’ve got something planned for this after I finish my animation system. Although progress on that is being badly impeded by lack of discussion and testing. I’m already cutting a lot of features just to try and get something out there.

I have used them (long ago) for collision / rendering stuff. Help if you do chunk iteration and want to optimize. Example, you have write access to a chuck (and version is bumped without actual write) you can keep this info in chunk component and early out. Or you can use a bit mask as chunk component to save per entity info of the chunk in the chunk component…

1 Like