http://blog.csdn.net/noahzuo/article/details/51496500

这篇博客翻译自Robert Troughton的博客Using the Disassembler to Highlight Optimization Targets,已征得原作者同意。

This post is translated from English. You can find the original English language version here: http://coconutlizard.co.uk/blog/ue4/using-the-disassembler/

UE4中有很多的字符串处理的函数,这些函数会在UE4中的各种情况下被调用 —— 例如无论在编辑器、cooking或者运行游戏时,都会有一大堆的字符串函数被调用。

在最近的测试中,我们着重测试了一下FPaths::IsRelative()函数,这个函数可以在Paths.cpp中被找到:

bool FPaths::IsRelative(const FString& InPath)
{const bool IsRooted = InPath.StartsWith(TEXT("\\"), ESearchCase::CaseSensitive)   ||InPath.StartsWith(TEXT("/"), ESearchCase::CaseSensitive)  ||InPath.StartsWith(TEXT("root:/")) |(InPath.Len() >= 2 && FChar::IsAlpha(InPath[0]) && InPath[1] == TEXT(':'));return !IsRooted;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

以上的代码看起来是无害的,只是一些很普通的字符串测试来判定InPath是相对路径(eg. “../engine/myfile.uasset”) 还是绝对路径 (eg. “c:\myfile.uasset”)。

为了研究这段代码,我启动Debugger,在函数中设置了断点并且查看其汇编代码。此时发生了非常恐怖的事,以下只是汇编代码中的一小段:

00007FF6DFF97B4E  mov         ecx,2
00007FF6DFF97B53  xor         edi,edi
00007FF6DFF97B55  xor         edx,edx
00007FF6DFF97B57  mov         r8d,ecx
00007FF6DFF97B5A  mov         qword ptr [rsp+70h],rbx
00007FF6DFF97B5F  mov         dword ptr [rbp+28h],edi
00007FF6DFF97B62  mov         qword ptr [rbp-10h],rdi
00007FF6DFF97B66  mov         qword ptr [rbp-8],2
00007FF6DFF97B6E  call        DefaultCalculateSlack (07FF6DFEC7DD0h)
00007FF6DFF97B73  movsxd      rcx,eax
00007FF6DFF97B76  mov         rax,qword ptr [rbp-10h]
00007FF6DFF97B7A  mov         dword ptr [rbp-4],ecx
00007FF6DFF97B7D  test        rax,rax
00007FF6DFF97B80  jne         FPaths::IsRelative+46h (07FF6DFF97B86h)
00007FF6DFF97B82  test        ecx,ecx
00007FF6DFF97B84  je          FPaths::IsRelative+5Bh (07FF6DFF97B9Bh)
00007FF6DFF97B86  mov         rdx,rcx
00007FF6DFF97B89  xor         r8d,r8d
00007FF6DFF97B8C  mov         rcx,rax
00007FF6DFF97B8F  add         rdx,rdx
00007FF6DFF97B92  call        FMemory::Realloc (07FF6DFF04CB0h)
00007FF6DFF97B97  mov         qword ptr [rbp-10h],rax
00007FF6DFF97B9B  lea         rdx,[ToUpperAdjustmentTable+2ABCh (07FF6E1EFFB9Ch)]
00007FF6DFF97BA2  mov         r8d,4
00007FF6DFF97BA8  mov         rcx,rax
00007FF6DFF97BAB  call        FGenericPlatformString::Memcpy (07FF6DFED3CA0h)
00007FF6DFF97BB0  lea         rdx,[rbp-10h]
00007FF6DFF97BB4  xor         r8d,r8d
00007FF6DFF97BB7  mov         rcx,rsi
00007FF6DFF97BBA  mov         ebx,1
00007FF6DFF97BBF  call        FString::StartsWith (07FF6DFEDD440h)
00007FF6DFF97BC4  test        al,al
00007FF6DFF97BC6  jne         FPaths::IsRelative+1BBh (07FF6DFF97CFBh)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

以上仅仅是整个函数的汇编代码的冰山一角,而整个函数也只有一行cpp代码,这简直是恐怖。

此外,这个代码不仅仅只是长而已,你应该可以看到有FMemory::Realloc()函数的调用。在整个汇编代码中,FMemory::Realloc()函数调用了3次。与之对应的,FMemory::Free()函数也出现了多次。

还有,StartsWith()函数也不是一个很便宜的函数(注意StartsWith()只有一个关于FString的Implementation)。

因此,我做了如下事:

  1. 减少了StartsWith()函数的调用,转而使用更为直接的字符比较。
  2. 移除了runtime的TEXT()区块,取而代之的是在外部直接创建。
  3. 将其中RootPrefix测试设为在编辑器中才有效。

因此,我最终的代码如下:

// Paths.cpp#if WITH_EDITORFString FPaths::RootPrefix = TEXT("root:/");#endif // WITH_EDITORbool FPaths::IsRelative(const FString& InPath){const uint32 PathLen = InPath.Len();const bool IsRooted = PathLen &&((InPath[0] == '/') ||(PathLen >= 2 && (((InPath[0] == '\\') && (InPath[1] == '\\'))|| (InPath[1] == ':' && FChar::IsAlpha(InPath[0]))#if WITH_EDITOR|| (InPath.StartsWith(RootPrefix))#endif // WITH_EDITOR)));return !IsRooted;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

对于.h文件,添加内容如下:

// Paths.hprivate:#if WITH_EDITORstatic FString RootPrefix;#endif // WITH_EDITOR
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

重新编译后,最终的汇编代码如下:

    00007FF7147B695A  mov         edx,dword ptr [r8+8]  00007FF7147B695E  mov         rsi,rcx  00007FF7147B6961  test        edx,edx  00007FF7147B6963  je          FPaths::ConvertRelativePathToFull+67h (07FF7147B6997h)  00007FF7147B6965  dec         edx  00007FF7147B6967  je          FPaths::ConvertRelativePathToFull+67h (07FF7147B6997h)  00007FF7147B6969  mov         rax,qword ptr [r8]  00007FF7147B696C  movzx       ecx,word ptr [rax]  00007FF7147B696F  cmp         cx,2Fh  00007FF7147B6973  je          FPaths::ConvertRelativePathToFull+0A9h (07FF7147B69D9h)  00007FF7147B6975  cmp         edx,2  00007FF7147B6978  jb          FPaths::ConvertRelativePathToFull+67h (07FF7147B6997h)  00007FF7147B697A  cmp         cx,5Ch  00007FF7147B697E  jne         FPaths::ConvertRelativePathToFull+56h (07FF7147B6986h)  00007FF7147B6980  cmp         word ptr [rax+2],cx  00007FF7147B6984  je          FPaths::ConvertRelativePathToFull+0A9h (07FF7147B69D9h)  00007FF7147B6986  cmp         word ptr [rax+2],3Ah  00007FF7147B698B  jne         FPaths::ConvertRelativePathToFull+67h (07FF7147B6997h)  00007FF7147B698D  call        qword ptr [__imp_iswalpha (07FF716557B48h)]  00007FF7147B6993  test        eax,eax  00007FF7147B6995  jne         FPaths::ConvertRelativePathToFull+0A9h (07FF7147B69D9h)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

以上的汇编代码是在non-editor模式中的整个函数的汇编代码,我相信你我都能同意以上代码的性能要好得多。

优化这段代码还带来了一个很好的副作用:编译器会将这段逻辑进行inline操作,我们甚至不需要声明FORCEINLINE或者INLINE宏!

我的最终测试表明这段代码的性能快了将近20倍,而代码资源占用量只是原来的10%。

Unreal Engine 4 —— 使用反汇编来确定该进行优化的地方相关推荐

  1. 虚幻引擎的数学知识学习教程 Math for Unreal Engine (Early Preview)

    通过做真实世界的 Unreal Engine项目来学习数学 你会学到什么 理解游戏开发对数学的基本需求 将数学直接应用到用例中,而不是钻研理论(用我们的示例项目进行实践) 正确编辑短视频,节省您的时间 ...

  2. 在UE4中创建CG动画 How to create a movie in Unreal Engine 4 using Metahuman

    MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz 语言:英语+中英文字幕(根据原英文字幕机译更准确)|大小解压后:1.55 GB |时长:1h 16m 你会学到什么 如何在 ...

  3. Revit和Unreal Engine真实的建筑可视化视频教程

    Revit和Unreal Engine真实的建筑可视化视频教程 Lynda – Revit and Unreal Engine: Real-Life Architectural Visualizati ...

  4. Blender 和Unreal Engine中的模块化3D建筑技能学习视频教程

    Blender 和Unreal Engine中的模块化3D建筑技能学习视频教程 流派:电子学习| MP4 |视频:h264,1280×720 |音频:AAC,48.0 KHz 语言:英语+中英文字幕( ...

  5. ue4中面部动画制作视频教程 Facial Animation More In Unreal Engine 4

    ue4中面部动画制作视频教程 Facial Animation & More In Unreal Engine 4 时长4h 包含项目文件 1920X1080 MP4 大小解压后:5.75G ...

  6. ue5新手零基础学习教程 Unreal Engine 5 Beginner Tutorial - UE5 Starter Course

    ue5新手零基础学习教程 Unreal Engine 5 Beginner Tutorial - UE5 Starter Course! 教程大小解压后:4.96G 语言:英语+中英文字幕(机译)时长 ...

  7. 虚幻引擎C++终极射手教程 Unreal Engine C++ The Ultimate Shooter Course

    虚幻引擎C++终极射手教程 Unreal Engine C++ The Ultimate Shooter Course MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz,2 ...

  8. Unreal Engine+Houdini创造程序性游戏场景视频教程

    Unreal Engine+Houdini创造程序性游戏场景视频教程 大小解压后:27.4G 持续时间14小时30分 包括项目文件 1920X1080 高清视频 程序游戏环境--虚幻引擎和Houdin ...

  9. Unreal Engine 4 优化教程

    本教程旨在帮助开发人员提升基于虚幻引擎(Unreal Engine*4 (UE4))开发的游戏性能.在教程中,我们对引擎内部及外部使用的一系列工具,以及面向编辑器的最佳实践加以概述,还提供了有助于提高 ...

最新文章

  1. 公众号留言-2020-4-1
  2. python网络编程(苦肝一夜,近万字)
  3. java跳转_java 跳转语句
  4. iPhone的UDID与push中使用的device token的关系
  5. android中ScrollView嵌套ListView或GridView显示位置问题
  6. 解决scrollViewDidScroll do not work的方法
  7. html输入密码跳转页面_【小乔锦囊】角色/仓库密码无法清除,怎么办?
  8. 使用OmniDB数据库管理工具,管理Oracle/MariaDB/PostgreSQL等关系型数据库
  9. bzoj1875 [SDOI2009]HH去散步 偏移+化边+矩乘
  10. 200 多个 npm 包被攻击,Azure 开发者请注意
  11. python_selenium简单的滑动验证码
  12. [Aaronyang] 写给自己的WPF4.5 笔记10[层次数据需求处理,TreeView绿色文章1/4]
  13. asp.net图书馆管理系统
  14. PBRT的程序运行流程
  15. 【交换基础】交换基础知识总结
  16. 设计模式7-适配器模式
  17. 阿里的简历多久可以投递一次?次数多了有没有影响?可以同时进行吗?
  18. vue配置favicon.ico图标
  19. Node模块--chalk
  20. 笔记本计算机作文,我的笔记本电脑作文600字

热门文章

  1. Java环境搭建一个小型网页
  2. wifi android手机版下载地址,手机随身wifi下载-手机随身WiFi 安卓版v1.6.3-PC6安卓网...
  3. 计算机中i o接口,计算机组成原理 输入输出(I/O)I/O 接口(I/O 控制器)
  4. Java练习01 输出质数(素数) 使用及不使用标签Lable
  5. 服务器性能评价体系,基于ServerScope平台TPCW性能评价
  6. ROS入门笔记(六): ROS系统架构
  7. html语言 大全,HTML语言大全
  8. JUnit5基本用法
  9. c语言中嵌套循环的作用,C语言中n层循环嵌套实现
  10. c语言对c99标准声明,C语言中C89与C99的区别