IL2CPP: Debugging and Profiling

Post on 16-Apr-2017

486 views 2 download

Transcript of IL2CPP: Debugging and Profiling

IL2CPP: Profiling and Debugging

Jonathan Chambers andJosh Peterson

Agenda

The Abridged Version

IL2CPP

Where is IL2CPP?

Creating IL2CPP

How do we make IL2CPP?

Fundamental principle: Test first• Unit tests - C++ and C# (~500)• Integration tests (~2000)• Platform integration tests (~1000)

Code conversion (il2cpp.exe) - C#Runtime (libil2cpp) - C++

How do we make IL2CPP?

Tools we use

• We debug with an IL2CPP standalone player

• We check build time and size against real projects

Internal tools

Internal organization of libil2cpp code

Internal Calls

Generated Code

PALVM

iOS

Windows

Other Platform

Our goal: move fast

Photo credit: Alvesgaspar (CC BY-SA 3.0)

Debugging script code with IL2CPP

Best option: Debug code in the editor

Acceptable option: Debug on device with Mono backend

Debugging script code with IL2CPP

Most fun option: Debug the generated C++ code!

When to debug generated C++ code

An exception occurs only on the device Marshaling

Interaction with native code

Deep dive: Debugging a managed exception in generated C++ code

• The converted code is the IL code, not C# code• Filter underscore characters from names• Sanity check often• Understand managed type layouts in native code

Principles for debugging generated code

• Debugging generated C++ code is probably not a technique to use often.

• Generated code will change in newer versions.• Generated C++ code can give Xcode problems.

Caveats

But for certain situations, this is a great skill to use!

Check out our IL2CPP Internals blog series!

Debugging tips for generated code - http://blogs.unity3d.com/2015/05/20/il2cpp-internals-debugging-tips-for-generated-code/

More information

Performance and Profiling

We make things fast for you!

The Good News

Make it small and make it fast!

Speed *and* Size

Make your code fast in general

.Net Profiler

Make your code fast in Unity

Unity Profiler

Make your code fast on device

Native Profiler

var md5 = MD5.Create(); var values = new byte[1024*1024]; var random = new Random(100); random.NextBytes(values); TimeAction (() => md5.ComputeHash(values));

Example

MD5 Hash

0ms

25ms

50ms

75ms

100ms

iPod 4G

Unity Mono IL2CPP

MD5 Hash

0ms

25ms

50ms

75ms

100ms

iPod 4G iPhone 6

Unity Mono IL2CPP

struct Vector2 { public float X; public float Y; public Vector2(float x, float y) { X = x; Y = x; } public float Magnitude() { return (float)Math.Sqrt(X*X + Y*Y); } }

Example 2

const int kNumItems = 1000000; var vals = new Vector2[kNumItems]; for (var i = 0; i < values.Length; i++) values[i] = new Vector2(i, values.Length - i); TimeAction (() => Array.Sort (vals, new Vector2Comparer ()));

Example 2 - cont’d

class Vector2Comparer : IComparer { public int Compare(object x, object y) { var v1 = (Vector2) x; var v2 = (Vector2) y; var mag1 = v1.Magnitude(); var mag2 = v2.Magnitude(); if (mag1 > mag2) return 1; if (mag1 < mag2) return -1; return 0; } }

IComparer

Instruments

class Vector2Comparer_v2 : IComparer<Vector2>{ public int Compare(Vector2 v1, Vector2 v2) { var mag1 = v1.Magnitude(); var mag2 = v2.Magnitude(); if (mag1 > mag2) return 1; if (mag1 < mag2) return -1; return 0; } }

IComparer<T>

Interface - iPod 4G

0s

10s

20s

30s

40s

IComparer IComparer<T>

IL2CPP

static int CompareVector2 (Vector2 v1, Vector2 v2){ var mag1 = v1.Magnitude(); var mag2 = v2.Magnitude(); if (mag1 > mag2) return 1; if (mag1 < mag2) return -1; return 0; }

Delegate v1

static int CompareVector2_v2(Vector2 v1, Vector2 v2){ var mag1 = Math.Sqrt(v1.X * v1.X + v1.Y * v1.Y); var mag2 = Math.Sqrt(v2.X * v2.X + v2.Y * v2.Y); if (mag1 > mag2) return 1; if (mag1 < mag2) return -1; return 0; }

Delegate v2

Delegate Optimization? - iPod 4G

0s

2s

4s

6s

8s

Method Call Inline

IL2CPP

static int CompareVector2_v2(Vector2 v1, Vector2 v2){ var mag1 = Math.Sqrt(v1.X * v1.X + v1.Y * v1.Y); var mag2 = Math.Sqrt(v2.X * v2.X + v2.Y * v2.Y); if (mag1 > mag2) return 1; if (mag1 < mag2) return -1; return 0; } // Our function we inlined public float Magnitude() { return (float)Math.Sqrt(X*X + Y*Y); }

Delegate v2 - What’s going on?

static int CompareVector2_v2(Vector2 v1, Vector2 v2){ var mag1 = (float)Math.Sqrt(v1.X * v1.X + v1.Y * v1.Y); var mag2 = (float)Math.Sqrt(v2.X * v2.X + v2.Y * v2.Y); if (mag1 > mag2) return 1; if (mag1 < mag2) return -1; return 0; }

Delegate v2 - Corrected

Delegate - iPod 4G

0s

2s

4s

6s

8s

Method Call Inline Inline Fixed

IL2CPP

static int CompareVector2_v3(Vector2 v1, Vector2 v2){ var mag1 = v1.X * v1.X + v1.Y * v1.Y; var mag2 = v2.X * v2.X + v2.Y * v2.Y; if (mag1 > mag2) return 1; if (mag1 < mag2) return -1; return 0; }

Delegate v3

Delegate - iPod 4G

0s

1.5s

3s

4.5s

6s

Method Call Inline No Sqrt

IL2CPP

Vector2 Sort by Magnitude - iPod 4G

0s

35s

70s

105s

140s

IComparable IComparable<T> Delegate 1 Delegate 2 Delegate 3

Unity Mono IL2CPP

Two More Things

Fast and Unsafe

public float Magnitude() { Debug.Log ("Let's slow things down!"); return (float)Math.Sqrt(X*X + Y*Y); }

One Time Initialization

public float Magnitude() { Debug.Log ("Let's slow things down!"); return (float)Math.Sqrt(X*X + Y*Y); }

// Generated C++ prologue static bool s_Il2CppMethodIntialized; if (!s_Il2CppMethodIntialized) { _stringLiteral0 = il2cpp_codegen_string_literal_from_index(0); s_Il2CppMethodIntialized = true; }

One Time Initialization

Thank you!

@jon_cham@petersonjm1

Questions?