demo: add performance demo

This commit is contained in:
mob-sakai
2022-06-14 13:39:13 +09:00
parent d9e7eb9732
commit 6b11e7c588
54 changed files with 17264 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Coffee.NanoMonitor
{
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(CustomMonitorItem))]
internal sealed class CustomMonitorItemDrawer : PropertyDrawer
{
public override void OnGUI(Rect p, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 0, p.width, 16), property.FindPropertyRelative("m_Text"));
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 1, p.width, 16), property.FindPropertyRelative("m_Format"));
EditorGUI.indentLevel++;
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 2, p.width, 16), property.FindPropertyRelative("m_Arg0"));
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 3, p.width, 16), property.FindPropertyRelative("m_Arg1"));
EditorGUI.PropertyField(new Rect(p.x, p.y + 18 * 4, p.width, 16), property.FindPropertyRelative("m_Arg2"));
EditorGUI.indentLevel--;
property.serializedObject.ApplyModifiedProperties();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return (EditorGUIUtility.singleLineHeight + 2) * 5;
}
}
#endif
[System.Serializable]
public class CustomMonitorItem
{
[SerializeField] private MonitorUI m_Text = null;
[SerializeField] private string m_Format = "";
[SerializeField] private NumericProperty m_Arg0 = null;
[SerializeField] private NumericProperty m_Arg1 = null;
[SerializeField] private NumericProperty m_Arg2 = null;
public void UpdateText()
{
if (m_Text)
m_Text.SetText(m_Format, m_Arg0.Get(), m_Arg1.Get(), m_Arg2.Get());
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5c50c6434f4ad4488bfc5b0928dbb4c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,199 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.Serialization;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Coffee.NanoMonitor
{
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(NumericProperty))]
internal sealed class NumericPropertyDrawer : PropertyDrawer
{
private static Action<PropertyInfo> s_OnMenuSelected;
private static GenericMenu s_PropertyMenu;
private static readonly Dictionary<Type, string> s_SupportedTypes = new Dictionary<Type, string>
{
{typeof(bool), "bool"},
{typeof(sbyte), "sbyte"},
{typeof(short), "short"},
{typeof(int), "int"},
{typeof(long), "long"},
{typeof(byte), "byte"},
{typeof(ushort), "ushort"},
{typeof(uint), "uint"},
{typeof(ulong), "ulong"},
{typeof(float), "float"},
{typeof(double), "double"},
{typeof(decimal), "decimal"},
};
private static void Init()
{
if (s_PropertyMenu != null) return;
var properties = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(assembly => assembly.GetTypes())
.SelectMany(type => type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetProperty))
.Where(pi => pi.GetMethod != null && s_SupportedTypes.ContainsKey(pi.PropertyType))
.OrderBy(pi => ConvertToMenuItem(pi, false))
.ToArray();
s_PropertyMenu = new GenericMenu();
s_PropertyMenu.AddItem(new GUIContent("No Property"), false, arg => s_OnMenuSelected?.Invoke(arg as PropertyInfo), null);
s_PropertyMenu.AddItem(new GUIContent("(Non Public Properties)/"), false, ()=>{});
s_PropertyMenu.AddSeparator("");
foreach (var pi in properties)
{
s_PropertyMenu.AddItem(new GUIContent(ConvertToMenuItem(pi, true)), false, arg => s_OnMenuSelected?.Invoke(arg as PropertyInfo), pi);
}
}
private static string ConvertToMenuItem(PropertyInfo p, bool propertyType)
{
var type = p.DeclaringType;
if (type == null) return "";
var category = p.GetMethod.IsPublic && type.IsPublic ? "" : "(Non Public Properties)/";
var typeName = type.FullName;
var asmName = type.Assembly.GetName().Name;
if (asmName == "UnityEngine.CoreModule")
asmName = "UnityEngine";
return propertyType
? $"{category}{asmName}/{typeName}/{s_SupportedTypes[p.PropertyType]} {p.Name}"
: $"{category}{asmName}/{typeName}/{p.Name}";
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
Init();
label = EditorGUI.BeginProperty(position, label, property);
var path = property.FindPropertyRelative("m_Path");
var split = path.stringValue.Split(';', ' ', ',');
var name = split.Length == 4 ? $"{split[0]}.{split[3]}" : "No Property";
position = EditorGUI.PrefixLabel(position, label);
if (GUI.Button(position, name, EditorStyles.popup))
{
s_OnMenuSelected = p =>
{
path.stringValue = p == null ? "" : $"{p.DeclaringType?.FullName}, {p.DeclaringType?.Assembly.GetName().Name};{p.Name}";
property.serializedObject.ApplyModifiedProperties();
};
s_PropertyMenu.DropDown(position);
}
EditorGUI.EndProperty();
}
}
#endif
[Serializable]
public class NumericProperty : ISerializationCallbackReceiver
{
//################################
// Serialized Members.
//################################
[SerializeField] private string m_Path = "";
//################################
// Public Members.
//################################
public double Get()
{
return _get?.Invoke() ?? -1;
}
//################################
// Private Members.
//################################
private Func<double> _get = null;
private static PropertyInfo GetPropertyInfo(string path)
{
var p = path.Split(';');
if (p.Length != 2) return null;
var type = Type.GetType(p[0]);
if (type == null)
{
UnityEngine.Debug.LogException(new Exception($"Type '{p[0]}' is not found"));
return null;
}
var pInfo = type.GetProperty(p[1], BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Static);
if (pInfo == null)
{
UnityEngine.Debug.LogException(new Exception($"Member '{p[1]}' is not found in type '{type}'"));
}
return pInfo;
}
private static Func<double> CreateFunc(MethodInfo mInfo)
{
if (mInfo == null) return null;
switch (Type.GetTypeCode(mInfo.ReturnType))
{
case TypeCode.Boolean:
var f_bool = (Func<bool>) mInfo.CreateDelegate(typeof(Func<bool>));
return () => f_bool() ? 1 : 0;
case TypeCode.Byte:
var f_byte = (Func<byte>) mInfo.CreateDelegate(typeof(Func<byte>));
return () => f_byte();
case TypeCode.SByte:
var f_sbyte = (Func<sbyte>) mInfo.CreateDelegate(typeof(Func<sbyte>));
return () => f_sbyte();
case TypeCode.UInt16:
var f_ushort = (Func<ushort>) mInfo.CreateDelegate(typeof(Func<ushort>));
return () => f_ushort();
case TypeCode.UInt32:
var f_uint = (Func<uint>) mInfo.CreateDelegate(typeof(Func<uint>));
return () => f_uint();
case TypeCode.UInt64:
var f_ulong = (Func<ulong>) mInfo.CreateDelegate(typeof(Func<ulong>));
return () => f_ulong();
case TypeCode.Int16:
var f_short = (Func<short>) mInfo.CreateDelegate(typeof(Func<short>));
return () => f_short();
case TypeCode.Int32:
var f_int = (Func<int>) mInfo.CreateDelegate(typeof(Func<int>));
return () => f_int();
case TypeCode.Int64:
var f_long = (Func<long>) mInfo.CreateDelegate(typeof(Func<long>));
return () => f_long();
case TypeCode.Decimal:
var f_decimal = (Func<decimal>) mInfo.CreateDelegate(typeof(Func<decimal>));
return () => (double) f_decimal();
case TypeCode.Double:
var f_double = (Func<double>) mInfo.CreateDelegate(typeof(Func<double>));
return f_double;
case TypeCode.Single:
var f_float = (Func<float>) mInfo.CreateDelegate(typeof(Func<float>));
return () => f_float();
default:
UnityEngine.Debug.LogException(new Exception(string.Format("Method '{1}.{0}' is not supported.", mInfo.Name, mInfo.DeclaringType)));
return null;
}
}
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
var pInfo = GetPropertyInfo(m_Path);
_get = CreateFunc(pInfo?.GetMethod);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 87fefa9f373e8411596b00238a65f3c3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,236 @@
using System;
using System.Runtime.CompilerServices;
using System.Text;
[assembly: InternalsVisibleTo("Coffee.NanoMonitor.Tests")]
namespace Coffee.NanoMonitor
{
internal static class StringBuilderExtensions
{
public static bool IsEqual(this StringBuilder sb, string other)
{
if (sb == null || other == null) return false;
if (sb.Length != other.Length) return false;
for (var i = 0; i < sb.Length; i++)
{
if (sb[i] != other[i]) return false;
}
return true;
}
public static void AppendFormatNoAlloc(this StringBuilder sb, string format, double arg0 = 0, double arg1 = 0, double arg2 = 0, double arg3 = 0)
{
for (var i = 0; i < format.Length; i++)
{
var c = format[i];
// Append formatted value
if (c == '{')
{
i = GetFormat(format, i, out var argIndex, out var padding, out var precision, out var alignment);
switch (argIndex)
{
case 0:
sb.AppendDouble(arg0, padding, precision, alignment);
break;
case 1:
sb.AppendDouble(arg1, padding, precision, alignment);
break;
case 2:
sb.AppendDouble(arg2, padding, precision, alignment);
break;
case 3:
sb.AppendDouble(arg3, padding, precision, alignment);
break;
}
continue;
}
// Append character
sb.Append(c);
}
}
internal static void AppendInteger(this StringBuilder sb, double number, int padding, int precision, int alignment)
{
number = Math.Truncate(number);
var sign = number < 0;
number = sign ? -number : number;
var startIndex = sb.Length;
do
{
var n = Math.Truncate(number % 10);
number /= 10;
sb.Append((char) (n + 48));
} while (1 <= number || (sb.Length - startIndex) < padding);
if (sign)
{
sb.Append('-');
}
var endIndex = sb.Length - 1;
sb.Reverse(startIndex, endIndex);
sb.Alignment(alignment, startIndex, endIndex);
}
internal static void AppendDouble(this StringBuilder sb, double number, int padding, int precision, int alignment)
{
var integer = Math.Truncate(number);
var startIndex = sb.Length;
sb.AppendInteger(integer, padding, precision, 0);
if (0 < precision)
{
sb.Append('.');
number -= integer;
number = Math.Round(number, precision);
for (var p = 0; p < precision; p++)
{
number *= 10;
integer = (long) number;
sb.Append((char) (integer + 48));
number -= integer;
number = Math.Round(number, precision);
}
}
sb.Alignment(alignment, startIndex, sb.Length - 1);
}
internal static void Reverse(this StringBuilder sb, int start, int end)
{
while (start < end)
{
var c = sb[start];
sb[start] = sb[end];
sb[end] = c;
start++;
end--;
}
}
internal static void Alignment(this StringBuilder sb, int alignment, int start, int end)
{
if (alignment == 0) return;
var len = end - start + 1;
if (0 < alignment && len < alignment)
{
sb.Append(' ', alignment - len);
for (var i = 0; i < len; i++)
{
var c = sb[end - i];
sb[end - i] = sb[start + alignment - i - 1];
sb[start + alignment - i - 1] = c;
}
}
else if (alignment < 0 && len < -alignment)
{
sb.Append(' ', -alignment - len);
}
}
internal static int GetFormat(string format, int i, out int argIndex, out int padding, out int precision, out int alignment)
{
argIndex = -1;
padding = 0;
precision = 0;
alignment = 0;
var alignmentSign = false;
var readFlag = 0;
for (; i < format.Length; i++)
{
var c = format[i];
// End format
if (c == '}')
{
return i;
}
// Start format
if (c == '{')
{
readFlag = 1;
}
// After '{': Read argument index and format
else if (readFlag == 1)
{
if ('0' <= c && c <= '3')
{
argIndex = c - 48;
}
else if (c == ',')
{
readFlag = 2;
}
else if (c == ':')
{
readFlag = 3;
}
}
//After ',': Read alignment value
else if (readFlag == 2)
{
if ('0' <= c && c <= '9')
{
alignment = alignment * 10 + (alignmentSign ? 48 - c : c - 48);
}
else if (c == '-')
{
alignmentSign = true;
}
else if (c == ':')
{
readFlag = 3;
}
}
// After ':': Read format for integral
else if (readFlag == 3)
{
if (c == '.')
{
precision = 0;
readFlag = 4;
}
else if (c == '0')
{
padding++;
}
// Legacy mode
else if ('1' <= c && c <= '9')
{
precision = c - 48;
}
}
// After '.': Read decimal precision value
else if (readFlag == 4)
{
if (c == '0')
{
precision++;
}
}
}
argIndex = -1;
return i;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 23b4d6d0f5b8644b0981a065d7e47478
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- m_Material: {fileID: 2100000, guid: 4da4639f724144ddead57bffca64e71f, type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: