UnityRuntimeProfiler

一.插件

1.uwa

https://www.uwa4d.com/

一个账号一个月有一次免费使用的机会,还没用过。

----------------------

2.SRDebugger

一个视频教程看到的,

https://assetstore.unity.com/packages/tools/gui/srdebugger-console-tools-on-device-27688

淘宝上有

 

 

 

3.Advanced FPS Counter

https://assetstore.unity.com/packages/tools/utilities/advanced-fps-counter-14656

淘宝有

4.Mesh Profiler

https://assetstore.unity.com/packages/tools/modeling/mesh-profiler-158255

淘宝没找到,不是Runtime

 

2.2020.2的新特性

Capturing Profiler Stats at Runtime

官方教程:https://resources.unity.com/unitenow/onlinesessions/capturing-profiler-stats-at-runtime

在官方的基础上封装了一下,添加新的性能参数会方便一点

using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using UnityEngine;
using Unity.Profiling;
using Unity.Profiling.LowLevel.Unsafe;
using UnityEngine.Profiling;

public class ProfilerController : MonoBehaviour
{
    /************************************************************************************************************
    * Source: https://docs.unity3d.com/2020.2/Documentation/ScriptReference/Unity.Profiling.ProfilerRecorder.html
    *************************************************************************************************************/
    
    //public static ProfilerMarker UpdatePlayerProfilerMarker = new ProfilerMarker("Player.Update");

    string statsText;
    //ProfilerRecorder mainThreadTimeRecorder;
    //ProfilerRecorder drawCallsCountRecorder;

    static double GetRecorderFrameAverage(ProfilerRecorder recorder)
    {
        var samplesCount = recorder.Capacity;
        if (samplesCount == 0)
            return 0;

        double r = 0;
        var samples = new List<ProfilerRecorderSample>(samplesCount);
        recorder.CopyTo(samples);
        for (var i = 0; i < samples.Count; ++i)
            r += samples[i].Value;
        r /= samplesCount;

        return r;
    }

    private Dictionary<string,StatInfo> statDict;

    private Dictionary<StatInfo,ProfilerRecorder> Recorders=new Dictionary<StatInfo,ProfilerRecorder>();

    private void AddProfiler(string statName){
        if(statDict==null){
            statDict=GetAvailableProfilerStats.EnumerateProfilerStats();
        }
        if(statDict.ContainsKey(statName))
        {
            StatInfo info=statDict[statName];
            //Debug.Log("AddProfiler:"+statName)
            ProfilerRecorder recorder = ProfilerRecorder.StartNew(info.Cat, statName);
            Recorders.Add(info,recorder);
        }
        else{
            Debug.LogError("No StatName:"+statName);
        }
    }

    private void AddMemoryProfiler(string statName){
        AddProfiler(statName,ProfilerCategory.Memory,ProfilerMarkerDataUnit.Bytes);
    }

    private void AddProfiler(string statName,ProfilerCategory pc,ProfilerMarkerDataUnit unit){
        if(statDict==null){
            statDict=GetAvailableProfilerStats.EnumerateProfilerStats();
        }
        if(statDict.ContainsKey(statName))
        {
            StatInfo info=statDict[statName];
            //Debug.Log("AddProfiler:"+statName)
            ProfilerRecorder recorder = ProfilerRecorder.StartNew(info.Cat, statName);
            Recorders.Add(info,recorder);
        }
        else{
            // StatInfo info=new StatInfo
            // {
            //     Name="*"+statName,
            //     Cat=pc,
            //     Unit=unit
            // };
            // ProfilerRecorder recorder = ProfilerRecorder.StartNew(info.Cat, statName);
            // Recorders.Add(info,recorder);
            Debug.LogError("No StatName:"+statName);
        }
    }

    void OnEnable()
    {
        //systemMemoryRecorder = ProfilerRecorder.StartNew(new ProfilerCategory("Memory"), "System Used Memory");
        // gcReservedMemoryRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "GC Reserved Memory");
        // gcUsedMemoryRecorder= ProfilerRecorder.StartNew(ProfilerCategory.Memory, "GC Used Memory");
        // totalReservedMemoryRecorder=ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Total Reserved Memory");
        // totalUsedMemoryRecorder=ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Total Used Memory");
        //mainThreadTimeRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Internal, "Main Thread", 15);
        //Recorders.Add(info,mainThreadTimeRecorder);
        //drawCallsCountRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Draw Calls Count");
        InitProfilers();
    }

    private void InitProfilers()
    {
        statDict = GetAvailableProfilerStats.EnumerateProfilerStats();
        AddMemoryProfiler("System Used Memory");
        AddMemoryProfiler("Total Reserved Memory");
        AddMemoryProfiler("Total Used Memory");
        AddMemoryProfiler("GC Reserved Memory");
        AddMemoryProfiler("GC Used Memory");
        AddMemoryProfiler("Gfx Used Memory");
        AddProfiler("Texture Count", ProfilerCategory.Memory, ProfilerMarkerDataUnit.Count);
        AddMemoryProfiler("Texture Memory");
        AddProfiler("Material Count", ProfilerCategory.Memory, ProfilerMarkerDataUnit.Count);
        AddMemoryProfiler("Material Memory");
        AddProfiler("Mesh Count", ProfilerCategory.Memory, ProfilerMarkerDataUnit.Count);
        AddMemoryProfiler("Mesh Memory");
        AddMemoryProfiler("Profiler Used Memory");
        AddProfiler("GameObject Count", ProfilerCategory.Memory, ProfilerMarkerDataUnit.Count);
        AddProfiler("Object Count", ProfilerCategory.Memory, ProfilerMarkerDataUnit.Count);
        AddProfiler("Asset Count", ProfilerCategory.Memory, ProfilerMarkerDataUnit.Count);
        AddProfiler("Scene Object Count", ProfilerCategory.Memory, ProfilerMarkerDataUnit.Count);

        AddProfiler("Draw Calls Count", ProfilerCategory.Render, ProfilerMarkerDataUnit.Count);
        AddProfiler("Batches Count", ProfilerCategory.Render, ProfilerMarkerDataUnit.Count);
        AddProfiler("SetPass Calls Count", ProfilerCategory.Render, ProfilerMarkerDataUnit.Count);
        AddProfiler("Triangles Count", ProfilerCategory.Render, ProfilerMarkerDataUnit.Count);
        AddProfiler("Vertices Count", ProfilerCategory.Render, ProfilerMarkerDataUnit.Count);
        AddProfiler("Used Buffers Count", ProfilerCategory.Render, ProfilerMarkerDataUnit.Count);
        AddProfiler("Used Buffers Bytes", ProfilerCategory.Render, ProfilerMarkerDataUnit.Bytes);
        AddProfiler("Main Thread", ProfilerCategory.Render, ProfilerMarkerDataUnit.TimeNanoseconds);
        AddProfiler("Camera.Render", ProfilerCategory.Render, ProfilerMarkerDataUnit.TimeNanoseconds);
        AddProfiler("RenderLoop.Draw", ProfilerCategory.Render, ProfilerMarkerDataUnit.TimeNanoseconds);
    }

    void OnDisable()
    {
        //mainThreadTimeRecorder.Dispose();
        //drawCallsCountRecorder.Dispose();

        foreach(StatInfo info in Recorders.Keys)
        {
            ProfilerRecorder recorder=Recorders[info];
            recorder.Dispose();
        }
        Recorders.Clear();
    }


    void Update()
    {
        var sb = new StringBuilder(500);
        foreach(StatInfo info in Recorders.Keys)
        {
            ProfilerRecorder recorder=Recorders[info];
            if(info.Unit==ProfilerMarkerDataUnit.Bytes)
                sb.AppendLine($"{info.Name}: {recorder.LastValue / (1024f * 1024f):F2} MB");
            else if (info.Unit == ProfilerMarkerDataUnit.TimeNanoseconds)
                sb.AppendLine($"{info.Name}: {GetRecorderFrameAverage(recorder) * (1e-6f):F2} ms");
            else
                sb.AppendLine($"{info.Name}: {recorder.LastValue} ");
        }
        //sb.AppendLine($"-----");
        //sb.AppendLine($"Frame Time: {GetRecorderFrameAverage(mainThreadTimeRecorder) * (1e-6f):F1} ms");
        // sb.AppendLine($"GC Reserved Memory: {gcReservedMemoryRecorder.LastValue / (1024 * 1024)} MB");
        // sb.AppendLine($"GC Used Memory: {gcUsedMemoryRecorder.LastValue / (1024 * 1024)} MB");
        // sb.AppendLine($"System Used Memory: {systemMemoryRecorder.LastValue / (1024 * 1024)} MB");
        // sb.AppendLine($"Total Reserved Memory: {totalReservedMemoryRecorder.LastValue / (1024 * 1024)} MB");
        // sb.AppendLine($"Total Used Memory: {totalUsedMemoryRecorder.LastValue / (1024 * 1024)} MB");
        //sb.AppendLine($"Draw Calls: {drawCallsCountRecorder.LastValue}");
        statsText = sb.ToString();
    }

    void OnGUI()
    {
        GUI.TextArea(new Rect(310, 10, 240, 500), statsText);
    }
}

打包后:

或者如下,*的都是打包后不支持的性能参数。为什么不支持?GameObject Count这种的都不支持?

3.Profiler.GetRuntimeMemorySizeLong(Unity.Object obj)

官方:https://docs.unity3d.com/ScriptReference/Profiling.Profiler.GetRuntimeMemorySizeLong.html

测试:

using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Profiling;

public class MemoryController : MonoBehaviour
{
    public List<UnityEngine.Object> TestObjects = new List<UnityEngine.Object>();

    public List<Mesh> meshes = new List<Mesh>();


    string runtimeMemoryText;

    private string GetObjectsRuntimeMemory()
    {
        var sb = new StringBuilder(500);
        foreach (var obj in TestObjects)
        {
            if (obj != null)
            {
                long size = Profiler.GetRuntimeMemorySizeLong(obj);
                sb.AppendLine($"{obj.GetType()}_{obj.name}: {GetSizeString(size)}");
            }
        }

        foreach (var mesh in meshes)
        {
            long size = Profiler.GetRuntimeMemorySizeLong(mesh);
            sb.AppendLine($"{mesh.GetType()}_{mesh.name}: {GetSizeString(size)}");
        }
        runtimeMemoryText = sb.ToString();
        return runtimeMemoryText;
    }



    // Start is called before the first frame update
    void Start()
    {
        GetObjectsRuntimeMemory();
    }

    // Update is called once per frame
    void OnGUI()
    {
        GUI.TextArea(new Rect(10, 10, 300, 500), runtimeMemoryText);
    }

    public static string GetSizeString(long size)
    {
        if (size < 1024)
        {
            return $"{size} B";
        }
        else if (size < 1048576)//1024*1024
        {
            return $"{size / (1024f):F2} KB";
        }
        else
        {
            return $"{size / (1048576f):F2} MB";
        }
    }
}

发现空的GameObject是288B,非空的GameObject是320B,GameObject中的Render中的Mesh要另外计算,它不会自动把一个GameObject相关的内存空间都计算上。

基本上Unity中的大部分类都是Unity.Object的子类。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值