核心内容摘要
如何通过UndertaleModTool实现GameMaker游戏深度定制:面向独立开发者的二进制解析与内容创作指南
正文大家好我是bug菌~1问题背景最近由于项目指标的需求查了下程序各个部分的运行效率发现一直用的环形缓冲区在耗时占比中还挺突出于是过了一遍代码并尝试着去优化一下没想到改动不大却得到了较大的效率提升。
如下是之前环形缓冲区的一些代码片段:#define BUFFER_SIZE 512 uint16_t buffer[BUFFER_SIZE]; uint16_t index 0; ...... index (index
% BUFFER_SIZE; ......当程序高频率的调用含有取模的运算接口时执行时间超出了设计预期同时在低优化等级(毕竟如果编译器进行了各种优化那就不好聊下去了)下对取模运算进行了相关sysclock的测量确实也是效率不高于是我打算用更高效的运算方式把它替换掉。
2与运算代替取模当然了与运算至少全面替代取模运算没那么容易毕竟如果能够完全替代也不会有人用取模了当时对于嵌入式行业我觉得最有意思的是它并不需要非常的通用嵌入式只需要在特定的领域特定的工况下能做到极致就可以了有取舍才能在有限的资源下把平台充分利用起来。
同样的思路取模运算确实很强大但是我并不需要利用它所覆盖的方方面面所以当除数是2的幂(即n 2^k)时与运算同样可以满足我的需求// 当 n 是 2 的幂n 2^k时 a % n a (n -
// 等价的情况n是2的幂 a % 8 a 7 // 8 2^3 a % 16 a 15 // 16 2^4 a % 32 a 31 // 32 2^5我们知道% 运算通常需要除法指令开销较大而 运算只需要按位与速度快很多。
所以对应环形缓存区只需要优化下#define BUFFER_SIZE 512 // 必须为2的幂 #define BUFFER_MASK (BUFFER_SIZE -
// 511 0x1FF uint16_t buffer[BUFFER_SIZE]; uint16_t index 0; ...... index (index
BUFFER_MASK; // 快速回绕 ......3再细致一点聊到这里来龙去脉应该讲清楚了其实不管了是在这一次的环形缓存区的优化中有所感悟这种方法只要是在当除数是2的幂时这种方式都能大大提高效率特别是一些实时性应用场景,一通百通。
比如说你要进行ADC窗口滑动:samples[sample_index] adc_read(); ...... // sample_index (sample_index
% WINDOW_SIZE; //直接方式 sample_index (sample_index
WINDOW_MASK; ......一些限制和风险我们也要非常有数一些bug大部分都是因为我们没有提前想到
在性能关键路径且除数是2的幂时才考虑使用与运算替代取模运算其他地方其实无关痛痒也没必要替换所以可以做一些防御性检测:#ifndef IS_POWER_OF_TWO #define IS_POWER_OF_TWO(x) (((x) ((x) -
)
#endif #define QUEUE_SIZE 128 #if !IS_POWER_OF_TWO(QUEUE_SIZE) #error QUEUE_SIZE must be power of two for optimization #endif #define QUEUE_MASK (QUEUE_SIZE -
1)
如果是处理负数大概率会出问题要留意。
最后好了今天就跟大家分享这么多了如果你觉得有所收获一定记得点个赞~唯