优化提示

时间:2010-11-29 16:04:00

标签: c optimization

int *s;
allocate memory for s[100];
void func (int *a, int *b)
{
    int i;

    for (i = 0; i < 100; i++)
    {
        s[i] = a[i] ^ b[i];
    }
}

假设此特定代码段被调用1000次,这是我的代码中最耗时的操作。还假设每次更改a和b的地址。 's'是一个全局变量,用一组&amp;的不同值集更新。湾

据我所知,主要的性能瓶颈是内存访问,因为唯一的其他操作是XOR,这非常简单。

请您建议我如何以最佳方式优化我的代码?

我真的想问的问题,但我认为没有得到恰当的传达,例如,这个for循环包含10个这样的XOR操作,循环计数为100,函数调用1000次,点高内存访问。如果要在单个核心机器上执行代码,有哪些改进范围?

4 个答案:

答案 0 :(得分:9)

我已经测试了提出的解决方案,以及其他两个。由于保存到s []的结果不正确,我无法测试onemasse的提议。我也无法修复它。我不得不对moonshadow代码做一些改变。测量单位是时钟周期,因此越低越好。

原始代码:

#define MAX 100
void inline STACKO ( struct timespec *ts, struct timespec *te ){

    int i, *s, *a, *b;

    for (i = 0; i < MAX; ++i){
        s = (int *) malloc (sizeof (int)); ++s;
        a = (int *) malloc (sizeof (int)); ++a;
        b = (int *) malloc (sizeof (int)); ++b;
    }

    srand ( 1024 );
    for (i = 0; i < MAX; ++i){
        a[i] = ( rand() % 2 );
        b[i] = ( rand() % 2 );
    }

    rdtscb_getticks ( ts ); /* start measurement */

    for (i = 0; i < MAX; i++)
        s[i] = a[i] ^ b[i];

    rdtscb_getticks ( te ); /* end measurement */

/*
    printf("\n");
    for (i = 0; i < MAX; ++i)
        printf("%d", s[i]);
    printf("\n");
*/
}

新提案1:注册int

自:

int i, *s, *a, *b;

要:

register int i, *s, *a, *b;

新提案2:无数组表示法

s_end = &s[MAX];
for (s_ptr = &s[0], a_ptr = &a[0], b_ptr = &b[0]; \
   s_ptr < s_end; \
   ++s_ptr, ++a_ptr, ++b_ptr){
    *s_ptr = *a_ptr ^ *b_ptr;
}

moonshadow建议优化:

s_ptr = &s[0];
a_ptr = &a[0];
b_ptr = &b[0];

for (i = 0; i < (MAX/4); i++){

    s_ptr[0] = a_ptr[0] ^ b_ptr[0];
    s_ptr[1] = a_ptr[1] ^ b_ptr[1];
    s_ptr[2] = a_ptr[2] ^ b_ptr[2];
    s_ptr[3] = a_ptr[3] ^ b_ptr[3];
    s_ptr+=4; a_ptr+=4; b_ptr+=4;
}

moonshadow建议优化+注册int:

自:

int i, *s, ...

要:

register int i, *s, ...

Christoffer建议优化:

#pragma omp for
for (i = 0; i < MAX; i++)
{
    s[i] = a[i] ^ b[i];
}

结果:

Performance graph

Original Code   1036.727264
New Proposal 1  611.147928
New proposal 2  450.788845
moonshadow      713.3845
moonshadow2     452.481192
Christoffer     1054.321943

还有其他简单的方法可以优化生成的二进制文件。将-O2传递给gcc告诉您需要优化。要确切了解-O2的作用,请参阅gcc手册页。

启用-O2后: Performance graph

Original Code   464.233031
New Proposal 1  452.620255
New proposal 2  454.519383
moonshadow      428.651083
moonshadow2     419.317444
Christoffer     452.079057

源代码:http://goo.gl/ud52m

答案 1 :(得分:5)

不要使用循环变量来索引。 展开循环。

for (i = 0; i < (100/4); i++)
{
  s[0] = a[0] ^ b[0];
  s[1] = a[1] ^ b[1];
  s[2] = a[2] ^ b[2];
  s[3] = a[3] ^ b[3];
  s+=4; a+=4; b+=4;
}

了解如何在您的平台上执行SIMD XOR。

执行这些XOR作为显式步骤可能比作为另一个计算的一部分执行它们更昂贵:您必须从a和b读取并将结果存储在s中 - 如果再次读取s以进行更多计算,则通过在那里进行异或来保存每次迭代的读取和写入,以及所有函数调用和循环开销。同样,如果a和b是某些其他函数的输出,则可以通过在其中一个函数的末尾执行XOR来做得更好。

答案 2 :(得分:0)

int *s;
allocate memory for s[100];
void func (int *a, int *b)
{
    int i;

    #pragma omp for
    for (i = 0; i < 100; i++)
    {
        s[i] = a[i] ^ b[i];
    }
}

当然,对于只有一百个元素,您可能看不到任何特别的改进: - )

答案 3 :(得分:0)

这里只是一个猜测。如果这是一个缓存问题,你可以试试这个:

int *s;
allocate memory for s[100];
void func (int *a, int *b)
{
    int i;

    memcpy( s, a, 100 );

    for (i = 0; i < 100; i++)
    {
        s[i] = s[i] ^ b[i];
    }
}

memcpy,尽管如果size参数是常量,编译器通常会内联函数调用。循环展开可能在这里没有帮助,因为它可以由编译器自动完成。但你不应该相信我的话,在你的平台上验证。