图形引擎实战:Unity性能分析工具原理介绍

news2024/11/17 0:29:26

最近在维护一个Unity性能分析工具,类似UPR,客户端采集信息,WEB端显示数据。下面简单介绍下原理。

数据来源

  • Profiler数据 熟悉Unity的同学对Profiler一定不会陌生,我们的性能数据主要来源于它,主要包含函数耗时,GC等等等等
  • 自定义数据 除了Profiler数据外,我们还需要一些其他数据,比如手机温度,PSS大小,lua GC,缓存池的使用情况,等等

一系列你想要,而profiler没有的

数据传输

Unity构建的时候勾选Development Build,在设备上启动后,Profiler就已经启动,并在某个端口进行监听,我们只需要

连接上这个端口就能够和Profiler进行通信,从而获得性能数据,就是平时在Profiler Window看到的那些。

之所以说某个端口,是因为这个端口并不是固定的,在Android和iOS平台,端口以55000开始,55495结束。

下图就是Unity对端口进行扫描,通过建立连接并设置连接超时时间特别短(10ms)来快速判断该端口是否在监听。

虽然端口设置的范围比较大,但一般情况下前面十多个就够用了,从55000开始listen,bind失败换下一个端口。

根据上面的介绍,我们连接Unity Profiler的思路就是,通过短超时连接扫描端口,在能够连接的情况下既确定了监听端口,也连接了Profiler。

连接上Profiler之后,需要给Profiler发送消息,告诉它你要采集信息,它就开始发送茫茫多的消息过来。

把这些消息处理或者直接转发给Web端(根据不同需求定夺)。直接转发数据量巨大,一个正常的游戏峰值可以达到10+M/s的传输。优点是不需要客户端进行处理,不会给CPU带来额外负担,缺点是对发热,耗电,都带来不小的影响,对公司网速也带来不小的影响,单个服务器能够承受的客户端连接也少的可怜。

消息解析

消息头(伪代码),消息头我们都不陌生,一般都包含消息id,消息体大小,这个只是比平常的多了一个magicnumber

struct MessageHeader
{
  UINT32 MagicNumber
  UGUID MessageId
  UINT32 Size
}

MagicNumber 值为 0x67A54E8F

MesasgeId 是一个结构体, 4个INT长,可转化为字符串 ,举个例子 c58d77184f4b4b59b3fffc6f800ae10e

struct UGUID
{
  UINT32 data[4]
}

Size 接下来消息体的大小

下面是一个简单的消息体的结构

LogMessage MessageId "394ada038ba04f26b0011a6cdeb05a62"

struct LogMessage
{
  UINT32 logType
  BYTE[] message
}

Log的消息体比较简单,只包含了log类型,和字符串数组,这两部分就组成了一个完整的消息,log并不是我们关心的消息,接下来就是一个比较复杂的消息了

ProfilerDataMessage  MessageId "c58d77184f4b4b59b3fffc6f800ae10e"

[Header] [[BlockHeader[Message ... Message]BlockFooter] ... [BlockHeader[Message ... Message]BlockFooter]]

这是一个消息体的结构,比较复杂,对涉及到的结构进行简要说明

struct Header
{
  UINT32 signature
  UINT8 isLittleEndian
  UINT8 isAlignedMemoryAccess
  UINT16 platform
  UINT32 version
  UINT64 timeNumerator
  UINT64 timeDenominator
  UINT64 mainThreadId
}

该Head不要和MessgeHead搞混淆,它是属于 ProfilerDataMessage的,并且它在一次连接中,只出现一次,附带了一些初始的信息,其中isLittleEndian与isAlignedMemoryAccess比较重要,对我们后续内容的解析影响比较大。

接下来是Block,Block里又包含了BlockHeader,BlockFooter,在中间又包含了多个Message,这些Message就不包含头和尾了,只包含了消息类型和内容 而处理这些message就是我们的重点了

struct BlockHeader
{
  UINT32 signature
  UINT32 blockId
  UINT64 threadId
  UINT32 length
}
struct BlockFooter
{
  UINT32 nextBlockId
  UINT32 signature
}

这些结构的成员通过命名我们就能理解,这里提一个比较有意思的地方,就是BlockHeader和BlockFooter的signature

BlockHeader 的 signature为0xB10C7EAD

BlockFooter的signature为0xB10CF007

不知道大家看出来了么

threadId,用于标识这个消息是关于哪个线程的,blockid和nextBlockid,是为了判断是否出错的,比如说某一个特定线程上次处理的blockdi 为1,这次处理blockid为3,那说明中间有丢失,就无法继续处理了。

Block中的Message

enum MessageType
{
    ...
    MarkerInfo = 1,
    ...
    GlobalMessagesCount = 32,
    ThreadInfo = GlobalMessagesCount + 1,
    Frame = GlobalMessagesCount + 2,
    ...
    BeginSample = GlobalMessagesCount + 4,
    EndSample = GlobalMessagesCount + 5,
    Sample = GlobalMessagesCount + 6,
    ...
    GCAlloc = GlobalMessagesCount + 20,
    ...

}

由于消息数量比较多,列举了一些比较重要的,其他的就省略了,真实的情况要比下面讲的要复杂的多

  • Session数据解析

BlockHeader的threadId表明了该消息所属的线程,其中有一个GlobalThread,id为-1,它并不是真实纯在的线程,而是标识该数据包含了全局数据。 这些数据对应的消息主要类型有 MarkerInfo , ThreadInfo 等

struct MarkerInfo
  {
    UINT16 messageType
    UINT32 samplerId;
    ...
    STRING name;
    ...
  }

name该采样的名字,一般情况下就是函数名,每个名字对应一个id,方便后面只发送id,不发送名字来减少包体大小。

struct ThreadInfo
  {
    UINT16 messageType
    UINT32 flags;
    STRING group;
    STRING name;
    ULONG startTime;
    ULONG threadID;
  }

线程的信息,主要有Main Thread, Render Thread 等,这些都是全局信息,解析后保存在字典中,方便后面的检索

  • Thread数据解析

全局信息发送完之后就是真实线程的消息了,主要讲解BeginSample和EndSample

struct Sample
  {
    UINT16 messageType
    INT8 flags;
    UINT32 id;
    ULONG Time;
  }

BeginSample和EndSample的结构是一样的,通过messageType来判断是Begin还是End,id就是MarkerInfo的sampleId,可以通过该id查找到函数名,Time是该sample采样的时间。

举一个简单的例子,假设我们有如下函数调用

fun A                // sampleId 100
    B()
  end

  fun B               // sampleId 101
  end

  A()               // main Thread id 1000000

收到BlockerHeader threadid 为 -1的消息,进入Session数据处理阶段,其中包含MarkerInfo, ThreadInfo

struct MarkerInfo
  {
    UINT16 messageType    1
    UINT32 samplerId;     100
    ...
    STRING name;          A
    ...
  }

  struct MarkerInfo
  {
    UINT16 messageType    1
    UINT32 samplerId;     101
    ...
    STRING name;          B
    ...
  }

  struct ThreadInfo
  {
    UINT16 messageType    33
    UINT32 flags;
    STRING group;
    STRING name;          Main Thread
    ULONG startTime;
    ULONG threadID;       1000000
  }

收到BlockHeader threadid 为 1000000的消息,这是一个主线程消息进入线程消息处理阶段,其中包含BeginSample,EndSample

struct Sample
  {
    UINT16 messageType   36
    INT8 flags;
    UINT32 id;           100
    ULONG Time;          0 
  }

  struct Sample
  {
    UINT16 messageType   36
    INT8 flags;
    UINT32 id;           101
    ULONG Time;          10 
  }

  struct Sample
  {
    UINT16 messageType   37
    INT8 flags;
    UINT32 id;           101
    ULONG Time;          20
  }

  struct Sample
  {
    UINT16 messageType   37
    INT8 flags;
    UINT32 id;           100
    ULONG Time;          30 
  }

上面消息的意思是 A 开始,时间0,B开始,时间10, B结束,时间20,A结束 时间30

那我们就可以计算函数的调用时间了,B耗时10 = 20 -10, A耗时 30 = 30-0, A self 耗时 20 = 30(A耗时) - 10(B耗时)

总结

上面简单介绍下性能工具如何通过Profiler获取数据,希望起到抛砖引砖的作用。 通过该工具,在测试人员跑游戏的同时,无感的上传性能数据,

并通过Web的形式展现出来,使得我们能够实时了解游戏的性能状态,及时发现问题,及时解决问题。

欢迎加入我们!

感兴趣的同学可以投递简历至:CYouEngine@cyou-inc.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1956227.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux基础操作(下)

软件安装,CentOS系统和Ubuntu是使用不同的包管理器 CentOS使用yum管理器,Ubuntu使用apt管理器 在CentOS系统中,使用yum命令联网管理软件安装 yum语法: yum [-y] [install | remove | search ] 软件名称 在Ubuntu系统中,使用apt命…

如何跨越 LangChain 应用研发的最后一公里

说 [LangChain] 是现在最流行的 AI 应用开发框架,应该没有人出来反对吧。LangChain 的出现极大地简化了基于大型语言模型(LLM)的 AI 应用构建难度,如果把 AI 应用比作一个人的话,那么 LLM 相当于这个人的“大脑”&…

FRP配置内网穿透52版本以上适用

简述 适用frp配置内网穿透来说我们需要进行简单的区分,具有公网IP的服务器我们简称为服务端,内网的服务器我们可以简称为客户端,frp需要针对不同的服务器配置不同的文件 下载安装包 Linux下载地址 https://github.com/fatedier/frp/relea…

数据丢失不用愁!这四款数据恢复大师免费版助你找回珍贵回忆

我们在办公或者是生活中常常会遇到不小心将手机设备或者计算机当中的重要数据误删除/格式化/或其他不小心丢失的情况,但是不用紧张,这篇文章就是给大家分享如何恢复他们,以下带来除易我数据恢复外的其他好用的数据恢复软件: 第一…

后端笔记(2)--JDBC

1.JDBC简介 *JDBC(Java DataBase Connectivity)就是使用java语言操作关系型数据库的一套API *JDBC本质:(可以使用同一套代码,操作不同的关系型数据库) ​ *官方定义的一套操作所有关系型数据库的规则,即接口 ​ *各…

2024年巴黎奥运会奖牌榜数据源:各国选手为荣誉而战!

奥运会是全球瞩目的盛会,每四年举办一次,汇集了来自超过200个国家的优秀运动员参与夏季和冬季的400多场比赛。这是一项真正的全球综合性运动会,各个国家选手为了荣誉和国家的面子而激烈竞争。2024年的巴黎奥运会将是一场令人期待的盛宴&#…

C语言——选择结构

C语言——选择结构 关系运算符及关系表达式关系运算符关系表达式 逻辑运算符和逻辑表达式逻辑运算符逻辑表达式 选择语句if语句条件运算符switch case语句 关系运算符及关系表达式 关系运算符 关系运算实际上是比较运算,C语言提供了六种关系运算符分别为&#xff…

Go语言教程(一看就会)

全篇文章 7000 字左右, 建议阅读时长 1h 以上。 Go语言是一门开源的编程语言,目的在于降低构建简单、可靠、高效软件的门槛。Go平衡了底层系统语言的能力,以及在现代语言中所见到的高级特性。它是快速的、静态类型编译语言。 第一个GO程序…

一篇文章带你入门爬虫并编写自己的第一个爬虫程序

一、引言 目前我们处在一个信息快速迭代更新的时代,海量的数据以大爆炸的形式出现在网络之中,相比起过去那个通过广播无线电、书籍报刊等传统媒介获取信息的方式,我们现在通过网络使用搜索引擎几乎可以获得任何我们需要的信息资源。 但与此同…

Python3网络爬虫开发实战(7)JavaScript 动态渲染页面爬取

文章目录 一、Selenium1. 基本安装2. 基本使用3. 声明浏览器对象4. 访问页面5. 查找节点6. 节点交互7. 动作链8. 执行 JavaScript9. 获取节点信息10. 切换 Frame11. 延时等待12. 前进后退13. Cookies14. 选项卡管理15. 异常处理16. 反屏蔽17. 无头模式18. Pyppeteer&#xff0c…

《遥远的救世主》读后感

未完待续。。。。 未完待续。。。。 未完待续。。。。 【经典语录】 01. 我们这个民族总是以有文化自居,却忘了问一句:是有什么文化?是真理真相的文化还是弱势文化?是符合事物规律的文化还是违背事物规律的文化?任何…

shell脚本与sed基本语法

Day11 一、shell 基础 1、shell 概念 shell 英文翻译过来是外壳的意思,作为计算机语言来理解可以认为它是 操作系统的外壳。可以通过shell 命令来操作和控制操作系统,比如 Linux中的shell命令就包括 ls、cd、pwd 等等。 2、shell 在内核的基础上编写的…

第一个设计模式——单例模式

目录 一、特点: 二、实现单例模式步骤 三、饿汉式 四、懒汉式 五、双重检查锁 六、静态内部类 七、枚举 八、可能被反序列化和反射破坏什么意思? 九、如何解决呢? 一、特点: 唯一性,单例模式确保程序中只有一…

甘肃粉条:一口爽滑,满心欢喜

在甘肃的美食世界里,粉条是一道独具特色的存在,它以其爽滑的口感和多样的烹饪方式,赢得了无数人的喜爱。甘肃食家巷粉条,选用当地优质的土豆或红薯为原料,经过一系列精细的加工工艺,最终成就了这一根根晶莹…

SSRF (服务端请求伪造)

🎼个人主页:金灰 😎作者简介:一名简单的大一学生;易编橙终身成长社群的嘉宾.✨ 专注网络空间安全服务,期待与您的交流分享~ 感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持!❤️ 🍊易编橙终身成长社群&#…

2-48 基于matlab的EM算法聚类可视化程序

基于matlab的EM算法聚类可视化程序,通过期望最大化算法(EM)优化类别间距,使得类别间距最大、类内间距最小。输出聚类前后结果及收敛曲线。程序已调通,可直接运行。 2-48 期望最大化算法(EM) 聚类…

6/9-axis imu sensor/姿态传感器 学习板/开发板 开源 MPU6500 QMC5883 加速度 陀螺仪 地磁传感器

1-应用领域: 游戏交互、3D模型控制、机器人、设备姿态检测、翻转状态检测、无人机、无人船、无人车、VR/AR、AHRS、姿态算法研究与分析,短距无效姿态测量、车辆调平系统,机器震动检测 2-产品硬件规格: 尺寸: 蓝牙:5.0 电池:默认150ma&…

TCP程序设计

TCP概述 建立连接 客户端和服务器端在建立连接时: 服务端是典型的监听接受连接的模式,就是ListenAccept 客户端是主动建立连接的模式,就是Dial Go语言中使用 net包实现网络的相关操作,包括我们TCP的操作。 用于建立连接的典型…

tusiart吐司艺术图像生成、LoRA 模型的使用和训练网站

文章目录 前言一、Tusiart(吐司艺术)是什么二、Tusiart(吐司艺术)主要功能三、Tusiart(吐司艺术) 网站图片四、Tusiart(吐司艺术) 相关地址总结 前言 每天分享一个关于AI项目或者网…

【系统架构设计师】二十、云原生架构设计理论与实践①

目录 一、云原生架构内涵 二、云原生的原则 三、主要架构模式 四、典型的云原生架构反模式 相关推荐 一、云原生架构内涵 云原生架构是基于云原生技术的一组架构原则和设计模式的集合,旨在将云应用中的非业务代码部分进行最大化的剥离,从而让云设施…