记一次UnityProfiler入门—重点说说UI,UIDetail

Posted avi9111

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次UnityProfiler入门—重点说说UI,UIDetail相关的知识,希望对你有一定的参考价值。

整个Profiler入门都会重头说说,重点UI

Profiler是官方提供的一个性能监控工具,甚至可以远程连接手机测试;不过这么多年过去了,连接功能还是和几年前一样,一样废,就不要指望了

重点说UI部分,因为最容易入门

 如上图,好的

已经说完了,谢谢阅读

===================================================

其实网上也说很多了,+上我这个文章,是不是觉得说了等于没说呢

其实Unity这个工具也是如此,网上的,官方的资料一大堆,说的很详细

但实际用起来,用了等于没用,关键点,具体问题的产生原因官方文档压根就没说

网上关于Unity Profiler 很多说法,做法,实践到底能用不??其实和成功学一样,都是靠个人摸出来,对别人可能有滴点用处,对你肯定没用

这里只是按个人理解的Profiler,随便说说

DC

用一个脚本做个小测试,以下脚本代码不全,用了一个Easy Buttons组件,请自行斟酌使用

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using EasyButtons;
/// <summary>
/// 测试DC用
/// </summary>
public class GenMoreUIs : MonoBehaviour
{
    public Transform genRoot;
    public List<GameObject> uis;

    public int GenCount=10;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    [EasyButtons.Button("GenMoreUIs")]
    public void GenMore()
    {
        foreach (var ui in uis)
        {
            for (int i = 0; i < GenCount; i++)
            {
                Instantiate(ui,genRoot,false);
            }
        }
    }
}

增加drawcall除了在Status观察到,也可以在Profiler - UI 显示

 其中

Batch Count 列也就是DC,很多年前Unity已经改成这个名字,可能大家还是习惯叫DrawCall吧

但是,总结几点

1.即使增加1W个DC(实际上你也不会这么干)只有增加那一刻会有峰值

2.即使DC很多,很快就已经恢复render的效率,这应该得益于Unity框架自身的剔除渲染,原理之后再分析吧

3.实际中也没听过过那个团队靠减低DC,达成优化的目的,更多时候说给老板听而已

4.所在的团队是碰过某些很特定(必然触发)的情况有render超出,但已经是极少的情况,有点类似内存溢出,是难定位,收益少,出现几率很低的BUG了】

5.没看出(观察到)Ui的DC增加对GPU,CPU的影响

实际上,UNITY官方已经兑现承诺,将UnityEngine.UI开源了,我们可以从中了解更多

腾讯XLUA都开源了,其实没什么不能开源的

 已失效的开源地址:https://bitbucket.org/Unity_Technologies/ui/

OverDraw

(待补充)

Layout(Rebuild)

从大师2017的视频的结论(原理请自行看源码,CSDN好像有一个小哥分析了整个UnityUI源码):

即使你不使用layout系统,但一个你用到UIElement,也就是UI.Text或者UI.Image,也仅仅是enable这样简单的操作,也会使得整个layout重建,这是相当耗时的,原因一是:

AllComponents.Get(),原因二是:LayoutGroup会在每次layout call调用,每多一个LayoutGroup更会多一次,HorizantalLayout或GirdLayout,这些滚动控件也是国内使用大户,非常耗时;

 

 再做一个小小测试

*还是缺easybuttons控件,想直接用下面代码,请科学上网搜索并下载 Standard Assets 的easybuttons 资源

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
using Random = System.Random;

/// <summary>
/// 测试UnityEngine.UI RebuildLayout Queue
/// </summary>
[ExecuteInEditMode]
public class GenLayoutRebuild : MonoBehaviour
{
    public Transform rootTransform;
    public Text changeText;
    public Image changeImage;

    [Range(0.001f, 0.5f)] [FormerlySerializedAs("TickInterval")] [Header("定时器")]
    public float tickInterval = 1f;

    public Coroutine tickCoroutine;
    public bool isTryRunning;

    public enum ChangeStuff
    {
        ChangeText,
        Disable,
    }

    public ChangeStuff changeStuffType;

    public GameObject SlotScrollViewContent;
    public GameObject SlotPrefab;
    private void OnEnable()
    {
        if (rootTransform == null)
            rootTransform = transform;
    }

    [EasyButtons.Button]
    public void AttachLayoutElements()
    {
        var children = rootTransform.GetComponentsInChildren<Transform>();
        foreach (var chi in children)
        {
            if (chi.GetComponent<LayoutElement>() == null)
                chi.gameObject.AddComponent<LayoutElement>();
        }

    }

    [EasyButtons.Button]
    public void TryChangeText()
    {
        changeStuffType = ChangeStuff.ChangeText;
        if (tickCoroutine == null)
        {
            tickCoroutine = StartCoroutine(EverySecTick());
        }
    }

    [EasyButtons.Button]
    public void TryDisablText()
    {
        changeStuffType = ChangeStuff.Disable;
        if (tickCoroutine == null)
        {
            tickCoroutine = StartCoroutine(EverySecTick());
        }
    }



    [EasyButtons.Button]
    public void StopTry()
    {
        if (tickCoroutine != null)
            StopCoroutine(tickCoroutine);

        isTryRunning = false;
        tickCoroutine = null;
    }

    [EasyButtons.Button("测试所有子节点disable,样例太少")]
    public void TryAllDisable()
    {
        if (rootTransform.childCount == 0) return;

        var act = rootTransform.GetChild(0).gameObject.activeSelf;
        var trans = rootTransform.GetComponentsInChildren<Transform>(); //只能找到不隐藏的对象
        foreach (var tran in trans)
        {
            tran.gameObject.SetActive(!act);
        }
    }
    [EasyButtons.Button("填充ScrollView,测layout")]
    public void ShowScrollViewContent()
    {
        Cleanup();
        
        List<string> recipes = new List<string>();
        for (int i = 0; i < 20; i++)
        {
            recipes.Add("" + i);
        }

        foreach (string s in recipes)
        {
            GameObject go = Instantiate(SlotPrefab);
            go.transform.SetParent(SlotScrollViewContent.transform);
        }
    }

    IEnumerator EverySecTick()
    {
        while (true)
        {
            isTryRunning = true;
            if (changeText != null)
            {
                if (changeStuffType == ChangeStuff.ChangeText)
                {
                    string[] strs = {"fff", "bbb", "ccc"};
                    var rand = new Random();
                    int i = rand.Next(0, strs.Length);
                    changeText.text = strs[i];
                }
                else if (changeStuffType == ChangeStuff.Disable)
                {
                    changeText.gameObject.SetActive(!changeText.gameObject.activeSelf);
                }
            }

            yield return new WaitForSeconds(tickInterval);
        }

    }

    private void OnDestroy()
    {
        if (tickCoroutine != null)
            StopCoroutine(tickCoroutine);
    }

    void Cleanup()
    {
        if(SlotScrollViewContent!=null)
            for (int i = SlotScrollViewContent.transform.childCount - 1; i >= 0; i--)
            {
                DestroyImmediate(SlotScrollViewContent.transform.GetChild(i).gameObject);
            }
    }


}

尽管2017的大神,说的很重要

 但是,

但是,

实测一轮下来

Render Queue 所耗时 ms 比  RebuildLayout Queue 多太多了

(可能也不排除是没有合批的原因,但无论如何layout rebuild所花时间并没有理论上的多)

所以,

我要解决的是ui render

粒子render

animation render

物理系统 Render

render,render,还是render

附上:2个canvas 的 cpu 对比

 

Render

这里就结合我之前分享的billboard ui; 动态ui做一些测试

(待补充)

但其实发现这个损耗比rebuild要多

合批

如下图,可能是Different Material Instance,可能是Different Texture导致不能

总之,找到这些问,并解决。。。

 UI动画

(待补充)

RenderTexture

(待补充)

对象池

(待补充,可减少GC)

参考:

没什么实用价值的入门Profiler资料

Unity Profiler性能分析全解析_Tokyo_2024的博客-CSDN博客

官方手册

UI 和 UI Details Profiler - Unity 手册 (unity3d.com)

UIDRAwCall 优化参考,多1~n个角度

针对Unity中UI的DrawCall的优化_yunjianxi0000的博客-CSDN博客

以上是关于记一次UnityProfiler入门—重点说说UI,UIDetail的主要内容,如果未能解决你的问题,请参考以下文章

Unity记一次Profiler连真机测试优化实践

记一次BurstJob入门

记一次和阿里某总监对话引发的思考:说说你框架的设计思路和优点亮点!

记一次和阿里某总监对话引发的思考:说说你框架的设计思路和优点亮点!

记一次渲染引擎入门

记一次Unity Brust入门