我正在努力让我的代码更快一些,并且我试图通过更好地管理存储在对象和内容中的数组来找出是否可以获得一些性能。
因此,背后的基本思想是我倾向于为临时和永久状态保留单独的数组。这意味着它们必须在每次我想要使用它们时必须单独编制索引,必须明确地写出正确的成员名称。
这是具有此类数组的特定类的样子:
class solution
{
public:
//Costs
float *cost_array;
float *temp_cost_array;
//Cost trend
float *d_cost_array;
float *temp_d_cost_array;
...
}
现在,由于我有根据输入参数处理临时或永久状态的函数/方法,因此它们如下所示:
void do_stuff(bool temp){
if (temp)
work_on(this->temp_cost_array);
else
work_on(this->cost_array);
}
这些分支是非常简单的例子。这些数组可以在代码中单独索引。所以完全是因为这样的东西到处都是,我认为这是将所有内容组合在一起的另一个原因,这样我就可以摆脱代码分支。
所以我将课程改为:
class solution
{
public:
//Costs
float **cost_array;
//Cost trend
float **d_cost_array;
...
}
这些双数组的大小为2,每个元素都是一个float *数组。这些在程序开始时在对象创建期间仅动态分配一次,并在程序结束时删除。
所以在那之后我也转换了我的代码的所有临时分支:
void do_stuff(bool temp){
work_on(this->cost_array[temp]);
}
它看起来比以前更优雅,但由于某些原因,性能比以前更差(差不多2倍),我真的不明白为什么会发生这种情况。
所以,作为第一个见解,我真的很想听听更有经验的人,如果我的代码优化背后的理由是否有效。
访问每个阵列所需的额外索引是否会引入如此重要的性能影响以克服所有if分支和内容?当然,这取决于整个事情是如何工作的,但代码是一个野兽,我不知道如何正确地描述这个东西。
由于
编辑:
环境设置: 在Windows 10,VS 2017上运行,启用完全优化(/ Ox)
答案 0 :(得分:1)
如此巨大的性能下降的原因可能是随着更改我们引入了另一个间接层,访问可能会显着减慢程序的速度。
更改前的对象:
*array -> data[]
*temp_array -> data[]
假设对象(即this
)在CPU缓存中,在更改之前您有一个缓存未命中:从缓存(缓存命中)中获取任一指针并访问冷数据(缓存未命中)。
更改后的对象:
**array -> * -> data[]
* -> data[]
现在我们必须访问指向数组的指针(缓存命中),然后索引冷数据(缓存未命中),然后访问冷数据(另一个缓存未命中)。
当然,这是上面描述的最糟糕的情况,但可能就是这种情况。
修复非常简单:使用float *cost_array[2]
在对象中分配这些指针,而不是动态地分配,即:
*array[2] -> data[]
-> data[]
因此,在存储和间接级别方面,这与更改之前的原始数据结构完全对应,并且应该表现得非常相似。