使用UE4/UE5的stat监控Lua的性能

3

主题

4

帖子

10

积分

新手上路

Rank: 1

积分
10
发表于 2023-4-6 20:28:58 | 显示全部楼层
stat是虚幻引擎提供的性能统计和优化工具,比较类似于Unity的Profiler,通过在代码中埋指定的函数或宏,就可以将需要的信息监控起来。前面会简单介绍在C++中怎么用,以及stat实现原理,后面会介绍怎样在Lua中使用。如果对stat很了解了,只想看Lua使用方法,可以翻到最后。顺便说一下,Lua的使用方法是我自己实现的,目前网上都没有类似教程或做法,各种第三方Lua插件或其他语言的支持插件都没有对应的支持,所以我觉得比较有参考价值。
stat下面就简单讲一点点。网上的资料,包括知乎上都有非常多教程,也可以参考官方文档:
UE本身已经在引擎中埋好了非常多的点,什么都不加,在游戏控制台中只要输入stat startfile,stat stopfile,就可以记录下来游戏在start和stop之间的性能数据,包括每个监控代码块的耗时,内存,各种计数等信息。


记录信息保存在Saved/Profiling文件夹下,以ue4stats作为后缀的文件(UE5是uestats,很睿智的做法,毕竟大版本升级了,这里去掉了4,后缀不同所以不兼容老版本,但其实本质没什么变化)


通过SessionFrontend打开


如果只想看统计信息,不想开引擎,也可以到引擎目录下找UnrealFrontend.exe独立程序打开看。


我们项目基本上都是测试同学抓stat数据,开发进行性能分析。因为平时我也在写代码,写一半了测试发来stat文件要分析,这时因为刚写一半的引擎或游戏代码还没编译或编译不过,肯定开不了引擎,那么就没法从引擎里面打开SessionFrontend了。但这时直接用这个独立程序看,就可以不重新编译,写代码和分析性能两件事都不耽误,还是很方便的。


比如这里能看到游戏线程以及内部每个加了统计的代码块平均耗时,或者单帧耗时等。具体看官方文档,这里不细说。
在自己的代码中使用

在自己的代码中使用,UE也提供了教程,写的很详细
比如PlayerController Tick


在代码中用宏来声明:


使用的时候也有对应的宏


具体原理

这里是CycleCounter,也就是统计每帧被这个宏包含的代码块耗时的。可以看到用起来非常简单。我们查看源码:




可以看到,就是构造的时候Start,析构的时候Stop,因此在函数局部代码块里定义一个这个类的对象,当出了作用域就会析构,自然的就记录的开始和结束的时间。
Start和Stop都是调用FThreadStats的AddMessage函数,发了两个事件。


进去看,里面构造Message的时候,就从PlatformTime上取了Cycles()得到开始和结束的时间,证明了猜测的正确。


当然除了耗时外,也可以统计其他信息,比如自定义整数,浮点数,字符串等。他们都是通过FThreadStats::AddMessage发送给stat线程的,stat线程收到后就会展示到屏幕或者写文件。这里的stat信息,其实最终都构造成了一个很长的FName字符串,每一段信息都有固定前缀,拼接到一起成为一个LongName,大概如下面这样(这里只说明原理,可以自行查看源码)


所以,stat文件里,记录的就是很多条这样的信息。
至于stat创建,必须在代码里某个位置,用宏来声明。可以看到,其实就是定义了一个static变量,一般都是在全局范围的。


如果你比较细心,就会发现stat全部都是用宏来定义的,依赖于C++的静态编译,把需要统计的stat定义以及对应代码,通过编译推导,导出给引擎,那么对于lua这样的动态语言,比如想统计lua中某个函数的耗时,因为lua是解释执行的,并不能在编译期知道lua代码中定义的stat信息。因此C++提供的这些宏,在Lua中就完全用不了了,即使硬着头皮先定义好,但在lua中统计性能还得让C++不停的编译,就变成了一个非常麻烦的事情,也失去了使用Lua来高效开发的意义。所以我接下来做的事情,就是封装一套接口,可以让stat在运行时定义以及统计,这样Lua就可以方便的使用stat来统计性能了。
在运行时定义和使用stat

首先,做这件事,我们就要清楚Stat到底做了什么。前面也说了,统计时本质就是AddMessage到stat线程,但是AddMessage需要StatId这样的参数,需要先构造。C++是通过全局对象构造的,而运行时构造StatId的是要解决的问题,接下来会说。但总之,只要搞定了在运行时构造stat id和调用stat统计这两件事,就达到了目的。
构造stat

只要你一层一层的扒开stat中封装的宏,最终你会看到,这个statid是通过DoSetup这个函数,如下图这样构造出来的,显然这个函数即使运行时调用也没什么不可以。至于怎么调用到这里的具体过程就不细说了,可以自行看源码。


所以,这段代码就是我要封装的构造stat函数,把各个参数都暴露出来


这里简单讲一下具体每个参数的意义:
StatName,就是统计的Stat程序内部用的名字,StatDesc是一个友好可读的名字。


就像上图,我们在宏里写的一样,对应这两个参数
然后下面的Group,因为我这里只是统计Lua,所以就直接在C++预定义好了,所有Lua都使用同一个Group。这里就不通过参数传进来了


接下来是比较重要的4个参数:
bool bShouldClearEveryFrame:是否每帧都清除,如果为true,这里面的值每帧就清理成0了
EStatDataType::Type InStatType:stat数据类型,有int64,double,FName几种
bool bCycleStat:这个是CycleCounter专用,CycleCounter这个要打开
FPlatformMemory::EMemoryCounterRegion MemRegion:这个是内存专用
直接用这个函数非常丑,所以我就包装了几个和stat宏差不多的:


对于统计来说,lua不像CycleCounter有构造函数和析构函数,那么我们就只能给lua中封装两个函数Start和Stop,让lua手动调用(也很方便,比较像Unity的Profiler用法),当然除了CycleCounter外,还有其他的stat,比如加值,减值,设值等,本质上都是AddMessage给stat线程,这个封装就很简单了,我也照着stat宏封装了一些方便的函数


最后,lua要使用,肯定要包装成lua的格式导出到Lua


这样,就可以在lua中愉快的使用stat了


最后,附上具体源码,我是用的UnLua,其他Lua做法类似,可以自行修改使用。
github:
补充一点,对于Lua5.4,可以使用close语法来做到和析构函数一样得效果,有需要可以自行实现
回复

举报 使用道具

0

主题

2

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2023-4-6 20:29:53 | 显示全部楼层
lua stat这个误差会不会很大?lua跟C++的交互成本挺大的,插入stat调用感觉会比较影响原性能喔
回复

举报 使用道具

0

主题

5

帖子

0

积分

新手上路

Rank: 1

积分
0
发表于 2023-4-6 20:30:37 | 显示全部楼层
基本上没有影响,这里没有特别的参数构造,lua和C++交互成本不大,估计比stat本身开销还小的多。性能问题可能就因为这几个函数是_G的全局函数,可以提前把这几个函数在文件内local一下,就几乎没开销了
回复

举报 使用道具

1

主题

2

帖子

3

积分

新手上路

Rank: 1

积分
3
发表于 2023-4-6 20:31:11 | 显示全部楼层
嗯,这个做法挺好的,我花点时间也接入我们项目。 另外建议最好可以在lua这边根据是否是shipping版本用空lua function覆盖一下. 避免性能浪费
回复

举报 使用道具

2

主题

6

帖子

11

积分

新手上路

Rank: 1

积分
11
发表于 2023-4-6 20:31:45 | 显示全部楼层
如果你们能改lua源码的话,shipping包可以在生成字节码的时候过滤掉,我就这么做的
回复

举报 使用道具

1

主题

4

帖子

5

积分

新手上路

Rank: 1

积分
5
发表于 2023-4-6 20:32:30 | 显示全部楼层
epic官方不出个脚本语言,真讨厌
回复

举报 使用道具

4

主题

7

帖子

14

积分

新手上路

Rank: 1

积分
14
发表于 2023-4-6 20:33:18 | 显示全部楼层
出不出无所谓的,正常游戏开发该做的事情,都要做一遍
回复

举报 使用道具

3

主题

8

帖子

12

积分

新手上路

Rank: 1

积分
12
发表于 2023-4-6 20:33:28 | 显示全部楼层
如果是你这篇文章所做的事情,倒不是每个脚本语言都要做。比如puerts用的是v8,v8自带了基于采样的cpu profiler。[捂嘴]
回复

举报 使用道具

4

主题

9

帖子

18

积分

新手上路

Rank: 1

积分
18
发表于 2023-4-6 20:34:28 | 显示全部楼层
[赞]v8厉害了,我这个只是利用了一下UE4的工具,这样可以让lua和引擎的stat数据合在一起看性能问题
回复

举报 使用道具

1

主题

4

帖子

4

积分

新手上路

Rank: 1

积分
4
发表于 2023-4-6 20:34:52 | 显示全部楼层
如果是要达到和引擎的stat数据一起展示这目的,倒确实“都要做一遍”。
回复

举报 使用道具

您需要登录后才可以回帖 登录 | 立即注册
快速回复 返回顶部 返回列表