Download presentation
Presentation is loading. Please wait.
1
游戏的优化 不仅仅是帧速率
2
我们将谈论什么? 何时何地需要做优化? C 和 C++ 的比较 C++中的性能问题 算法优先 我们需要 C++ 的高级特性吗?
3
优化无处不在 最好的优化器是你的大脑,而不是编译器 评测而不是臆测 Windows 游戏不应该有特权 专家的选择是不优化
Windows 游戏首先是一个 Windows 程序 每一点资源的节省都将是有意义的 专家的选择是不优化 Popo龙珠的例子: 热点在python 接口的调用而不是一开始认为的图象显示
4
FPS? 提高了 10 fps 表示什么含义? 最高帧速率和平均帧速率 Loading 时间 关心一下 CPU 占用率
10fps->20fps 100fps->120fps 最高帧速率和平均帧速率 Loading 时间 关心一下 CPU 占用率 了解 Windows 多一点
5
记时器 TimeGetTime QueryPerformanceCounter RDTSC 精度 多任务环境的影响 流水线 测不准原则
RDTSC 精度没有想象的高,而且受流水线影响(调用 cpuid)
6
微观和宏观 微观上的优化 宏观上的优化 CPU指令、流水线吞吐量、等待时间 有限的硬件优化 有限的编译器优化 算法和代码结构的改进
减少需要处理的数据量,减少处理的频率和次数 吞吐量 throughput 等待时间 latency 硬件优化掉部分操作,保证逻辑正确
7
C 与 C++ 微观上的比较 C 比 C++ 快 10%? C++ 编译器的改进 不要迷信书本 证据? 更合理的参数传递方式 Inline
堆栈和函数调用 静态变量的使用 Thiscall, stdcall, 函数返回 add esp,xxx 堆栈的起源,CPU 指令针对主流语言的优化
8
C++提供更强的语言特性 new/delete malloc/free C++ exception setjmp/longjmp
虚函数 函数指针数组 Template 宏 标准库 函数重载等方便开发者写出质量更高的代码 C++ 多采用空间换取时间的策略 几乎在所有情况下,时间效率都大过 C
9
C 的优势 简单 可移植性更强 接口简洁 更少的二义性 CRT 开销小 编译速度快 C 的目标代码普遍小于 C++
10
C++ 需要了解更多
11
STL 最被人喜爱的容器 大多数情况他们没有被正确的使用 std::map std::string std::vector
std::list 大多数情况他们没有被正确的使用
12
std::map 插入是很慢的 O(log(N)) 有额外的内存消耗 (三个指针+颜色) 大多数情况,我们需要的只是查找
数组+二分查找 Hash map 通常可以提高效率,但不绝对 还有更多的优化手段 lua 的实现 大话西游的实现 Vc 7.1 每个node要消耗 14字节 参考:《effctive c++》 Lua 的 map
13
std::string 还有一种字符串叫作 const char * const std::string &
不要依赖 COW (copy-on-write) 考虑多线程环境 良好的设计下,cow 通常多余 Lua 如何处理字符串?
14
std::vector std::vector 并不仅仅是数组 通常我们把 vector 作为数组使用
Vector::push_back() 常引起内存重分配 vector::reserve() vector::clear() 不一定释放内存 POD 类型的优化 记住:从 C 语言开始,就支持了数组 VC 里 100 次 push_back 会引起 13 次内存重新分配
15
std::list std::list 是一个双向链表 std::list 有内存的额外开销
链表可以在常数时间插入,而当 N 不大的时候,优势并不明显。
16
正确的使用STL STL 是 C++ 提供的强有力的工具 STL 的使用都是有开销的 STL 并不能解决我们所有的问题
让代码达到最佳的性能,需要用我们的大脑
17
重新发明轮子? 不要因为你能够做到而重新实现 STL
几乎所有的 MyVector MyString MyMap 都不如 std::vector std::string std::map 更多的了解 STL 更多的了解 C++
18
CRT 的使用 sprintf(s,”%d”,n); sprintf(s,””); printf 与 puts 不要忽略 CRT 的开销
为什么不用 itoa ? sprintf(s,””); 为什么不用 s[0]=‘\0’; printf 与 puts 不要忽略 CRT 的开销
19
重写 CRT? 优化 memcpy:MMX 版本、SSE 版本… 重写 string 库,MyStrlen MyStrcmp …
任何小于 64k 数据复制的优化都没有意义 重写 string 库,MyStrlen MyStrcmp … CRT 可以做的更好 Intrinsic 函数 #pragma intrinsic()
20
内存优化 展开循环,消除数据相关性 数据并行处理 减少数据结构的尺寸,让数据尽量紧凑的放在一起 数据对齐 了解内存的工作方式
更进一步的讨论超出了本次的讨论范围
21
内存管理优化 C++ 提供了更灵活的内存管理机制 new/delete 不一定是最好的方式(STL就不用) 自定义内存分配器 方便调试
分配速度和内存碎片同样重要 注意分离模块的问题 DLL 最容易出错 多种分配方式。
22
算法 C++ 更适合实现更复杂的游戏引擎 引擎的复杂度提升,层次的增加,会降低效率 更高的复杂度是为了宏观上的优化
24
脏矩形
26
问题 脏矩形的合并算法并不简单 合并后的脏区域并不是一个矩形,不方便做图片裁减 有许多的物体在屏幕上移动 卷动屏幕 图像引擎设计的复杂度
27
改进的脏矩形 分格处理 渲染管道 绘图操作对象化
33
滚动优化 更大的back buffer 破碎的分格
38
覆盖优化
41
C++的高级特性 天使还是恶魔?
42
Template 避免重复的代码 template <bool mask_blit>
void _blit(pixel *dst,const pixel *src,size_t s,bool mask_blit) { for (size_t i=s;i!=0;--i,++dst,++src) { if (!mask_blit || *src!=mask_color) *dst=*src; } template <bool mask_blit> void _blit(pixel *dst,const pixel *src,size_t s)
43
void blit(pixel *dst,const pixel *src,size_t s)
{ _blit<false>(dst,src,s); } void mask_blit(pixel *dst,const pixel *src,size_t s) _blit<true>(dst,src,s);
44
矩阵运算 Matrix A,B,C; A=B+C; 如何避免临时对象的返回? 转化为 A=B; A+=C;
Matrix operator+(const Matrix &lhs,const Matrix &rhs); Matrix & my_type::operator=(const Matrix &v); 如何避免临时对象的返回? 转化为 A=B; A+=C;
45
Expression Templates template<typename T> class add_type {
const T& _lhs; const T& _rhs; public: add_type(const T &lhs,const T &rhs) :_lhs(lhs),_rhs(rhs) {} T& calculate(T &result) const { result=_lhs; result+=_rhs; return result; } }; template <typename T> add_type<T> operator+(const T &a,const T &b) { return add_type<T>(a,b);
46
class Matrix { /* ... */ Matrix& operator+=(const Matrix &v); Matrix& operator=(const add_type<Matrix> &v) { return v.calculate(*this); }
47
编译时计算 template<int N> class factorial { public:
enum { value = N * factorial<N-1>::value }; }; template<> class factorial<1> { enum { value = 1 };
48
冒泡排序 inline void compare_swap(int &a,int &b) { if (a>b) { int t=a;
b=t; } void sort(int *data,int n) for (int i=0;i<n-1;i++) { for (int j=i+1;j<n;j++) { compare_swap(data[i],data[j]);
49
template<int N>
struct inner_loop { static inline void expand(int* data) { compare_swap(*data, data[N]); inner_loop<N-1>::expand(data); } }; template<> struct inner_loop<0> { static inline void expand(int*) {} struct sort { sort<N-1>::expand(++data); template<> struct sort<1> { static inline void expand(int* data) {}
50
int main() { int a[]={3,2,1}; const int len=sizeof(a)/sizeof(a[0]); sort<len>::expand(a); for (int i=0;i<len;i++) { printf("%d,",a[i]); } // sort<len>::expand(a) 展开后的代码 compare_swap(*data,data[2]); compare_swap(*data,data[1]); ++data;
51
尽可能的在编译时运算? 还有更多的 template 技巧 滥用 template 的后果 编译速度下降 模块间耦合度增加
《Modern C++ Design - Generic Programming and Design Pattens Applied》 滥用 template 的后果 编译速度下降 模块间耦合度增加 对开发伙伴要求增加 调试不便
52
编译效率同样重要 尽可能的,正确的,使用动态连接库 允许的话,用 .c 编写部分代码 减少 .h 依赖 简单的东西更具有美感
预编译头文件是万恶之源 简单的东西更具有美感
53
Q&A
Similar presentations