#Spawing Performance

1 messages · Page 1 of 1 (latest)

fossil geode
#

Trying to figure out optimal Instantiate and Destroy

little sky
#

yeah it's as i thought, you haven't bursted compiled your system

#

you're missing [BurstCompile] OnUpdate

#

[BurstCompile] on the struct does nothing (this only works on jobs)

#

i see you have tried to burst compile the specific function

fossil geode
#

I need to read up on that
I did try spamming it on every class/struct and method before though

#

never seemed to make a difference, in fact I got the same timings without any [BurstCompile]
~200ms with Burst->Enable Compilation off
~40ms with it on

little sky
#

do you have safety off?

#

(side note, Profiler.Begin sample doesn't work in burst - you need to use profile markers)

fossil geode
#

Ok, I replaced those
Safety also doesn't seem to make a difference

#

I'm new to Unity, but have used profilers like these in C++ before
Seems to me there's simply one malloc happening per entity when spawning or deleting all entities, I've not found any method that does not do that
Maybe this is just my machine? Using Unity 6 (6000.0.37f1)

#

I'd be interested (assuming you Instantiate in a similar way) what your profiler says for the when hovering over any allocs -> UnsafeUtility.Malloc/Free X instances on thread

#

The blue on the right is my InitJob, which is quite fast

#

https://discussions.unity.com/t/when-where-and-why-to-put-burstcompile-with-mild-under-the-hood-explanation/896228
I don't need [BurstCompile] it seems

    SystemBase / ISystem → .Run / .Schedule / .ScheduleParallel - Burst Compiled by default, no need to mark static methods if those are called from ForEach / IJobs (in some cases would actually throw errors!). Unless .WithoutBurst()
    Static methods can be burst compiled even when called outside Entities context when marked as [BurstCompile] (-> results in a function pointer)
    Jobs can be marked with [BurstCompile] to be bursted from non-system context;
    If in doubt - check Burst Inspector.
little sky
#

The blue on the right is my InitJob, which is quite fast
blue means its not burst compiled

#

burst compiled is green

#

blue is mono

#

also what od you mean you don't need [BurstCompile]

#

what's just saying is you don't need to mark a method that's in burst already with burst

#
[BurstCompile] // this is required
public void OnUpdate(ref SystemState state)
{
    SomeOtherMethod();
}

[BurstCompile] // this is not required
private static void SomeOtherMethod()```
#

do you have a dynamic buffer on your archetype?

#

(i didn't have 100k allocations, it was like 25 or something)

fossil geode
fossil geode
#

thanks a lot for your input until now

little sky
#

mines from baking

#

is the top archetype the one you're instantiating

#

i actually suspect it has to allocate the linkedentitygroup buffer

#

i'm running a forked entities which stops forcing this buffer on unless required

fossil geode
#

It's both, since the MeshLODGroupComponent entity needs the children entities

fossil geode
little sky
#

oh you have children?

#

oh wait you tested cube as well

little sky
#

it's pointless to me

#

(it also forces dynamic transform which i dont always want)

fossil geode
#

what's LEG?

#

I'm pretty sure that for my project I'm going to create a custom LOD implementation as well
Pretty sure I can do it with very few components

#

I'd also like to implement a system where I can render prop meshes attached to entities without those props needing to exist as entities
Probably requires a custom renderer anyway

#

Probably also not going to use baking, since I want to load assets at runtime, for user generated content

little sky
fossil geode
#

got cha

#

Only 23 Mallocs when I do CreateEntity(prefab_arch, s.SpawnCount, Allocator.Temp) with prefab_arch = CreateArchetype(typeof(LocalTransform))
So it really is due to something in the Prefab Entity

little sky
#

it's most likely the LEG

heavy iron
#

Did you have any expectation that [EntityIndexInQuery] should only match your recently spawned entities by that system?

#

We already have the entity array after bulk instantiation, we can directly process that array via IJobFor rather than using IJE.

little sky
#

We already have the entity array after bulk instantiation, we can directly process that array via IJobFor rather than using IJE
yeah but then you have to use lookups

#

and risk doing work on the same chunk across multiple threads

#

it only took me 0.2ms to initialize the localtransform data in 100k entities in IJE

#

i didnt bother posting it because he didn't seem to have issues with that

heavy iron
#

If we use a initialization component to filter the entites on that chunk, would it be slower?

little sky
#

i don't think so as these entities will all be created in the same chunks if i recall

#

and not added to existing chunks

#

so the whole chunk will always be enabled avoiding having to check the actual individual entity bits

heavy iron
#

What if the component is enableable?

little sky
#

that's exactly what i just replied about

#

sorry when you said intialization i just assumed enableable

heavy iron
#

Me too

heavy iron
little sky
#

say you have 1 entity in a chunk

#

and you call bulk instantiate and create 50 more entities

#

i don't believe these 50 entities will be put in the existing chunk

#

and instead all be put in a new chunk

#

(it's been a long time since i looked at source code, so there is a chance this would have changed, however i believe it remains true)

#

so you'll have 2 chunks now
1 with 1 entity
1 with 50 entities

#

the 50 entities will all have their initialization component enabled, so it doesn't need to do enable component checks

#

it just goes through the fast path of iterating them all

#

(bulk instantiate is one of the reason fragmentation can occur i believe, the other more critical one is chunk components)

#

(that said, we should test this again been ages)

heavy iron
#

interesting, thanks again

fossil geode
fossil geode
#

Does the system leave holes at the end of chunks when destroying entities, or just at the last chunk (does it swap in within a chunk or from different chunks)
If bulk CreateEntity/Instantiate always create 'contiguous' entities I imagine IJobFor would be fine, it would just repeat the lookup per entity like you said
(though I don't understand yet how to get around the This container does not support parallel writing)

#

Surely simply writing normal component data from threads is perfectly fine

little sky
#

If you go look at manual chunk and component iteration you get a linear array of data

#

If there were holes you'd have issues

#

But a chunk won't get filled from another chunk if you destroy an entity

fossil geode
#

so bulk CreateEntity in theory could return a list of chunks that each have arrays of contiguous new entities

#

I've only gotten IJobEntity to work for initialization, I'm actually completely lost on how to do it with IJobFor, I always get 'does not support parallel writing'
Why is this a thing? The lookup Entity->memory address of its component should be perfectly safe, right?
You just need to be careful not to write to the same entity from two threads at once like aways with multithreading, is unity trying to prevent user mistakes?

little sky
#

Yes but unity didn't know you aren't accessing the same entity in multiple threads

#

You have to promise it that your aren't then you can do it

#

With the disable parallel write safety attribute

#

Ije is going to be faster here anyway

fossil geode
#

Did you have any expectation that [EntityIndexInQuery] should only match your recently spawned entities by that system?
It has this issue though, Should I use a temporary Init Tag?

little sky
#

yeah can use an enable component or just add it to all missing objects vs a build query operation which is super fast

fossil geode
#

I can't seem to easily find info on this?
Would you like to link me an example?

#

The idea is to allow to query exactly the newly spawned entities by using a empty component = tag for this
but if you need to remove this after that causes structural changes (even for tags?), so instead we use enable components, which can be disabled?

little sky
#

better off doing the opposite imo as you dont have to worry about adding it via baking (thought here are merits of doing it how you suggest)

#

can just put a component inside the system hidden from world
private struct Initialized : IComponentData {}

#

and just add it to things that don't have it

#

and query on that

#

alternative you can add an enablable component to the entities in baking

#

and then disable/enable it in the initialization

#

both have pros/cons

fossil geode
#

that makes sense

#

Though I will say that this kind of thing seems like a workaround, Why is there no official way of doing something simple like bulk initializing
We even get a NativeArray<Entity> which can just ignore

little sky
#

i personally use enable components and i have a signle instantiation group with multiple systems of instantiation

#

that all sources of instantiation use