PlayableDirector.Evaluate and duration generates GC

I am currently using Timeline to control individual characters in a fighting game, and must manually control and evaluate multiple timelines per frame. Any given timeline may be stepped or evaluated multiple times per FixedUpdate, due to needing to support rollback netplay. It is working well, but it is generating a lot of garbage. Each call to PlayableDirector.duration and PlayableDirector.Evaluate both generate 80 bytes of garbage per Timeline. With up to 8 timelines in use and potentially 60 ticks to fast forward as a result of rollback netplay, that can generate 76.8kb of garbage in one (Fixed)Update. My question: is this garbage necessary? and if it isn’t, can this be removed?

Tangentially related: is it possible to run these evaluations as a part of the C# Jobs system?

There should not be any GC allocs coming from Evaluate(), unless the instance is getting rebuilt for some reason (I can’t see why it would).

What types of tracks is the timeline composed of? Any hints from the profiler about where the garbage is coming from?

C# Job system in timeline → not yet, but in progress. C# jobs and playables are a perfect fit together.

The timeline, for the most part, is only composed of two animation tracks that are targeting the same Animator.

Here’s what the profiler is showing on every update made. Also correction, it seems to be allocating 40 bytes per Director used.

Here’s the code called to evaluate the state. Both the call to duration and Evaluate seem to be generating GC here.

    if (timeline != Director.playableAsset) {
      Director.Play(timeline);
      stateDuration = Director.duration;
    }
    Director.time = state.StateTime % stateDuration;
    Director.Evaluate();

Ah, thanks! Which version of Unity is this? I’ll look into it.

It’s the latest 2017.3 release. It should be noted that I do swap out the playable asset on occasion as a part of a state machine I built around the Director, and it is rebuilding the timeline playable at transition points, but this GC is happening at every update tick, not just the ones where the timeline is changed.

I haven’t been able to reproduce this. Do you get the allocations if the timeline just plays without the script that forces an evaluation?

If I disable the forced evaluation, it still allocs GC.

Here are the Inspector settings

3381856--265501--upload_2018-2-5_23-22-52.png

I’m able to reproduce it under the .NET 4.6 Scripting Runtime. Is that what you are using as well?

We’ll look into that and get a fix out ASAP.

1 Like

Yes, I am using the new runtime, I probably should have mentioned that from the get-go.

1 Like

It’s often more efficient for UT if you attach a project to reproduce the issue. The easier it’s for UT to reproduce an issue, the more likely it’s that they’re actually going to look at it.

As an alternative to this, I’m experimenting with try to create a single playable graph instead of swapping out timelines. I have a large number of timelines, on the order of 80-200 per object playing it. The end result is something similar to a code-based Animation Controller, except with the base elements based on Timelines instead of simple Motions. With only one or two of the timelines having non-zero weight, are there potential performance issues if I attempt to merge all of those timelines under a single playable graph?

I don’t think there will be any difference in performance. We get asked frequently questions like ‘how many timelines/playable graphs can be played at once’ and the answer is it’s less about the number of graphs and more about the number of outputs (i.e. tracks) in total. Each output has a subgraph that is traversed and processed.

E.g. Having 25 animation tracks running is roughly equivalent to having 25 animation controller playing. The cost will be dependent on what is being animated.

Was there a fix for this?

Possibly. There have been a few related fixes since that time. Are you still seeing allocations in PrepareFrame?