Skip to content

Instantly share code, notes, and snippets.

@kornman00
Created April 12, 2016 17:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kornman00/f0fb11d315d510de71f9cc74f03b0651 to your computer and use it in GitHub Desktop.
Save kornman00/f0fb11d315d510de71f9cc74f03b0651 to your computer and use it in GitHub Desktop.
The power of per-frame GC analysis blog source
// #IMPL: If you change the underlying type, update ProtoSomething.ComparerImpl too!
public enum HardCodedThing : byte
{
Some,
Thing,
Something,
Darkside
cMaxCount,
};
public sealed class ProtoSomething
{
// I don't make this private, in the event that IL2CPP can generate code without virtual dispatching when the actual type is known
public sealed class ComparerImpl
: IComparer<HardCodedThing>
, IEqualityComparer<HardCodedThing>
{
// if ProtoSomething were a struct you'd want to
// define this in here since static ctors in structs are fuzzy in behavior.
// They also have infectious codegen in the containing type, due to statics in .NET being lazy loaded
// See this article for more: http://kornnerstudios.blogspot.com/2015/12/seeing-sharp-c-behind-il2cpp-magic-of.html
public static readonly ComparerImpl sInstance = new ComparerImpl();
public int Compare(HardCodedThing x, HardCodedThing y)
{
return (int)x - (int)y;
}
public bool Equals(HardCodedThing x, HardCodedThing y)
{
return x == y;
}
public int GetHashCode(HardCodedThing obj)
{
// Casting to the underlying type then calling get hash code shouldn't result in a box...
return ((byte)obj).GetHashCode();
}
};
/// <summary>ALWAYS use this in your Dictionary ctors which use HardCodedThing as a key</summary>
public static ComparerImpl Comparer { get { return ComparerImpl.sInstance; } }
};
We can make this file beautiful and searchable if this error is corrected: It looks like row 2 should actually have 3 columns, instead of 1. in line 1.
// Excerpt from our CSV report...although really a TSV, since we use tabs, thanks to generic types including commas
// The avg allocs and frees are computed from the TOTAL counts divided by the TOTAL frames (I eventually added support to divide just by the count of frames the type actually appeared in). Garbage percent is (avg_frees / avg_allocations) * 100.0f
// The 'frees skipped' is from types previously allocated before the frame we started at. 'allocs skipped' is from potential erronous cases, which this type had none
name avg allocs avg frees garbage percent allocs skipped frees skipped
UnityEngine.AnimatorControllerParameter 118.311119 112.544075 95.125526 0 2937
// Except from our blame report matching the .csv file in this gist
// SomeSecretObjectUX:SetAnimFloat checks that a given parameter name/nameHash exists on the Unity Animator and returns false when it doesn't.
// This behavior was later changed to only Debug.Log and return false in UNITY_EDITOR builds, since every time UnityEngine.Animator:get_parameters is called it creates managed memory
**** Type: UnityEngine.AnimatorControllerParameter
Unique backtraces 13
142340 (%63.121670) // how many allocations this specific backtrace contributed, and the overall percentage of allocs it accounts for
(wrapper managed-to-native) UnityEngine.Animator:get_parameters
UnityExtensions:HasParameter
SomeSecretObjectUX:SetAnimFloat
SomeSecretMonoBehaviour:Update
(wrapper runtime-invoke) object:runtime_invoke_void__this__
45876 (%20.344034)
(wrapper managed-to-native) UnityEngine.Animator:get_parameters
UnityExtensions:HasParameter
SomeSecretObjectUX:SetAnimFloat
SomeSecretMonoBehaviour:Update
(wrapper runtime-invoke) object:runtime_invoke_void__this__
26780 (%11.875779)
(wrapper managed-to-native) UnityEngine.Animator:get_parameters
UnityExtensions:HasParameter
SomeSecretObjectUX:SetAnimFloat
SomeSecretMonoBehaviour:Update
(wrapper runtime-invoke) object:runtime_invoke_void__this__
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment