Unity IL2CPP - увеличение производительности

Да, IL2CPP до сих пор медленнее MONO в общих случаях, хотя ситуация постепенно улучшается. Мы можем как-то улучшить производительность прямо сейчас?

Частично, да. Официальная документация говорит, что мы можем отключить часть внутренних проверок для генерируемого IL2CPP нейтивного кода. Давайте проверим потенциал данных улучшений на LeoECS фреймворке.

Код теста (без IL2CPP-оптимизаций)

Почему тесты делаются таким способом можно прочитать в “Тесты производительности Event, ActionList, Observer, InterfaceObserver“.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System.Collections;
using UnityEngine;
namespace LeopotamGroup.Ecs.Tests {
class Test8 : MonoBehaviour, IEcsInitSystem {
class C8_1 { }
class C8_2 { }

EcsWorld _world = null;

IEnumerator Start () {
yield return new WaitForSeconds (2f);
var systems = new EcsSystems (new EcsWorld ()).Add (this);
systems.Initialize ();
systems.Destroy ();
}

void IEcsInitSystem.Initialize () {
const int TESTS = 40;
const int T = 10000000;
var sw = new System.Diagnostics.Stopwatch ();
var result = 0;
var entity = _world.CreateEntity ();
_world.AddComponent<C8_1> (entity);
_world.AddComponent<C8_2> (entity);
_world.ProcessDelayedUpdates ();

for (var test = 0; test < TESTS; test++) {
sw.Reset ();
sw.Start ();
for (var i = 0; i < T; i++) {
_world.GetComponent<C8_1> (entity);
_world.GetComponent<C8_2> (entity);
}
sw.Stop ();
result += sw.Elapsed.Milliseconds;
}
Debug.LogFormat ("GetComponent: {0}", result / (float) TESTS);
}

void IEcsInitSystem.Destroy () { }
}
}

Код теста (с IL2CPP-оптимизацией)

Отличие от предыдущего кода одно - наличие атрибута Il2CppSetOption на классе (и всех внутренних классах LeoECS фреймворка):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
using System.Collections;
using UnityEngine;

// Unity IL2CPP performance optimization attribute.
namespace Unity.IL2CPP.CompilerServices {
enum Option {
NullChecks = 1,
ArrayBoundsChecks = 2
}

[AttributeUsage (
AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property,
Inherited = false,
AllowMultiple = true)]
class Il2CppSetOptionAttribute : Attribute {
public Option Option { get; private set; }
public object Value { get; private set; }

public Il2CppSetOptionAttribute (Option option, object value) {
Option = option;
Value = value;
}
}
}

namespace LeopotamGroup.Ecs.Tests {
[Unity.IL2CPP.CompilerServices.Il2CppSetOption (Unity.IL2CPP.CompilerServices.Option.NullChecks, false)]
[Unity.IL2CPP.CompilerServices.Il2CppSetOption (Unity.IL2CPP.CompilerServices.Option.ArrayBoundsChecks, false)]
class Test8 : MonoBehaviour, IEcsInitSystem {
class C8_1 { }
class C8_2 { }

EcsWorld _world = null;

IEnumerator Start () {
yield return new WaitForSeconds (2f);
var systems = new EcsSystems (new EcsWorld ()).Add (this);
systems.Initialize ();
systems.Destroy ();
}

void IEcsInitSystem.Initialize () {
const int TESTS = 40;
const int T = 10000000;
var sw = new System.Diagnostics.Stopwatch ();
var result = 0;
var entity = _world.CreateEntity ();
_world.AddComponent<C8_1> (entity);
_world.AddComponent<C8_2> (entity);
_world.ProcessDelayedUpdates ();

for (var test = 0; test < TESTS; test++) {
sw.Reset ();
sw.Start ();
for (var i = 0; i < T; i++) {
_world.GetComponent<C8_1> (entity);
_world.GetComponent<C8_2> (entity);
}
sw.Stop ();
result += sw.Elapsed.Milliseconds;
}
Debug.LogFormat ("GetComponent: {0}", result / (float) TESTS);
}

void IEcsInitSystem.Destroy () { }
}
}

Результаты

  • MONO: 168ms
  • IL2CPP без оптимизаций: 293ms
  • IL2CPP с оптимизацией: 194ms

Результаты показывают неплохое ускорение (порядка 30%), но IL2CPP все еще медленнее, чем MONO.

Вы можете оформить подписку:
Или просто сказать спасибо: