C++ 为什么combine7的性能优于combine5?
我测试了以下7个函数,我不明白为什么combine7比combine5好。因为它们只是在“()”的位置不同 有人能给我解释一下吗 这是我的密码:C++ 为什么combine7的性能优于combine5?,c++,visual-studio-2010,algorithm,visual-c++,stl,C++,Visual Studio 2010,Algorithm,Visual C++,Stl,我测试了以下7个函数,我不明白为什么combine7比combine5好。因为它们只是在“()”的位置不同 有人能给我解释一下吗 这是我的密码: #include "Common.h" #define PLUS #ifdef PLUS #define INDENT 0 #define OP + #else #define INDENT 1 #define OP * #endif typedef int data_t; typedef struct { long int len;
#include "Common.h"
#define PLUS
#ifdef PLUS
#define INDENT 0
#define OP +
#else
#define INDENT 1
#define OP *
#endif
typedef int data_t;
typedef struct
{
long int len;
data_t *data;
}vec_rec, *vec_ptr;
vec_ptr new_vec(long int len)
{
vec_ptr result = (vec_ptr)malloc(sizeof(vec_rec)); //Allocate header structure
if(!result) return NULL;
result->len = len;
if(len > 0) //Allocate array
{
data_t* data = (data_t*)calloc(len, sizeof(data_t));
if(!data)
{
free((void*)result);
return NULL;
}
result->data = data;
}
else result->data = NULL;
return result;
}
int get_vec_element(vec_ptr v, long int index, data_t * dest)
{
if(index < 0 || index >= v->len) return 0;
*dest = v->data[index];
return 1;
}
long int vec_length(vec_ptr v)
{
return v->len;
}
data_t* get_vec_start(vec_ptr v)
{
return v->data;
}
void combine5(vec_ptr v, data_t* dest)
{
long int i;
long int length = vec_length(v);
long int limit = length - 1;
data_t* data = get_vec_start(v);
data_t acc = INDENT;
for(i = 0; i < limit; i += 2)
{
acc = (acc OP data[i]) OP data[i + 1];
}
for(; i < length; i++)
acc = acc OP data[i];
*dest = acc;
}
void combine7(vec_ptr v, data_t* dest)
{
long int i;
long int length = vec_length(v);
long int limit = length - 1;
data_t* data = get_vec_start(v);
data_t acc = INDENT;
for(i = 0; i < limit; i += 2)
{
acc = acc OP (data[i] OP data[i + 1]);
}
for(; i < length; i++)
acc = acc OP data[i];
*dest = acc;
}
std::mt19937 gen;
int roll_die() {
std::uniform_int_distribution<> dist(1, 6);
return dist(gen);
}
int main()
{
const size_t len = 10000000;
auto vec_pointer = new_vec(len);
std::generate(vec_pointer->data, vec_pointer->data + vec_pointer->len, roll_die);
std::cout << "Initialized datas..." << std::endl;
/*std::copy(vec_pointer->data, vec_pointer->data + vec_pointer->len,
std::ostream_iterator<int>(std::cout, "\t"));*/
data_t dest = 0;
utility::CStopwatch stopwatch5;
combine5(vec_pointer, &dest);
std::cout << "combine5 elapsed time(microseconds): " << stopwatch5.NowInMicro() << std::endl;
utility::CStopwatch stopwatch7;
combine7(vec_pointer, &dest);
std::cout << "combine7 elapsed time(microseconds): " << stopwatch7.NowInMicro() << std::endl;
}
如果您真的对找出不同函数执行不同的原因感兴趣,那么分析编译器生成的汇编代码可能是一个好主意。这些函数非常简单,可以在汇编中读取,即使通常不熟悉这些函数 在函数3中在每次迭代中取消引用:
for(i = 0; i < length; i ++)
{
*dest = *dest OP data[i];
}
for(i=0;i
在函数4中,您仅在末尾取消引用:
for(i = 0; i < length; i ++)
{
acc = acc OP data[i];
}
*dest = acc;
for(i=0;i
函数5速度更快,因为它只迭代了一半的迭代次数。参见:acc=(acc OP data[i])OP data[i+1]代码>自然比
acc=acc OP(数据[i]OP数据[i+1])代码>
因为在第一种情况下,您尝试在不同的操作中访问数据元素data[i]和data[i+1],这会导致很大的开销,而在第二种情况下,您尝试在操作的同时访问它们(data[i]OP data[i+1])
因为它们是相邻的内存位置,相互迭代的速度比在单独的瞬间访问它们要快。不太清楚为什么它们会有很大的不同(当然,fatih_k的解释不能说服我)。由于运算符是可交换的,编译器可能仍希望更改顺序(取决于编译器标志)。您是否试验过不同的编译器标志(特别是优化标志)和不同的编译器(clang、gcc、icpc)
此外,以下形式的环体运行情况如何
{
acc *= data[i];
acc *= data[i+1];
}
旁注:避免使用那些蹩脚的宏。改为编写模板代码。请提出具体问题。这有(72)个答案。猜6是打字错误?不应该是acc0=acc0 OP data[i];acc1=acc1操作数据[i+1]代码>?您使用的优化级别是什么?我认为,在某些情况下,通过适当的优化(例如循环去冷),时间差会更小。但是,也许我希望有更多的表单编译器?我仍然想知道为什么解引用会产生不同,我认为优化编译器只会在循环中使用寄存器进行加法,并在循环/函数的末尾写回结果?ted优化器可以做很多事情,但因为我们没有被告知任何关于优化级别的信息,我认为取消引用似乎是一个合乎逻辑的罪魁祸首。我从MSVC2010获得的示例程序集输出表明,如果不启用优化,将解引用移到循环之外确实会产生影响。但是是的,这应该是一个微小的变化,并且只有在构建时没有优化时才可见。:)
{
acc *= data[i];
acc *= data[i+1];
}