请教一个很有难度的优化问题

bloublou 2011-05-25 09:34:53
核心算法很简单,就是从一个数组中挑出所有非0元素,按照原数组的顺序,排成新的数组。如下所写的方法已经耗时较少,我用Vtune测了一下,L2 miss和分支预测损失都很小,CPI也不大。
但是我很想再优化一下。
有什么方法呢?位运算?simd指令?sse指令?难度很大吧?呵呵

short arraysrc[W] = {0};
short arraydst[W] = {0};
int index = 0;
int i = 0;

/*省略arraysrc赋值语句*/

for(i=0; i<W; i++)
{
if(arraysrc[i] != 0)
{
arraydst[index] = arraysrc[i];
index++;
}
}
...全文
134 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
CandPointer 2011-05-26
  • 打赏
  • 举报
回复
循环展开,Intel ia-32 平台高性能手册



//原始
sum = 0;
for (i = 0; i<1000;i++)
{
sum += array[i];
}

//减少代码的数据相关
t1 = t2 = t3 = t4 =0;
for (i=0; i<1000; i+=4)
{
t1 += array[i];
t2 += array[i+1];
t3 += array[i+2];
t4 += array[i+3];
}

sum = t1 + t2 + t3 + t4;
//这样子,很好





LZ的问题,可一步一步,按照 qvec-report的提示,根据手册上的提示,修改循环,
CandPointer 2011-05-26
  • 打赏
  • 举报
回复
[Quote=引用楼主 bloublou 的回复:]
核心算法很简单,就是从一个数组中挑出所有非0元素,按照原数组的顺序,排成新的数组。如下所写的方法已经耗时较少,我用Vtune测了一下,L2 miss和分支预测损失都很小,CPI也不大。
但是我很想再优化一下。
有什么方法呢?位运算?simd指令?sse指令?难度很大吧?呵呵

short arraysrc[W] = {0};
short arraydst[W] = {0};
int ……
[/Quote]


用 Intel 编译器?
Intel Parallel Studio 2011 XE?

那就,把优化开起来, QxSSE4.2 或者 QxHost (或者 Qax)
然后,吧 Qvec-repot 开到最高,获得最多的提示
它会自动把代码 用SSE,avx等矢量化, report会提示你,那些代码,上下文的原因等,不能成功矢量化。————你根据提示,重新 修改调整循环和数据结构。,以便符合 矢量化的要求


majia2011 2011-05-26
  • 打赏
  • 举报
回复
这有什么可详细说明的,movsd,基本功,没难度,也不是什么优化
bloublou 2011-05-25
  • 打赏
  • 举报
回复
to luciferisnotsatan
确实有效,提高了5%,谢谢!

to cobras
我用的是intel编译器,对齐问题可以忽略;

to majia2011
能否详细说明一下?
majia2011 2011-05-25
  • 打赏
  • 举报
回复
给lz个提示,DWORD

64位系统,注意一下
luciferisnotsatan 2011-05-25
  • 打赏
  • 举报
回复
32位机器上,通常展开超过4层,效率就开始下降了。具体展开多少层最优,需要测试后才知道。
cobras 2011-05-25
  • 打赏
  • 举报
回复
至于对齐的问题,就交给编译器来优化吧
cobras 2011-05-25
  • 打赏
  • 举报
回复
我的是对的,边界就退出
luciferisnotsatan 2011-05-25
  • 打赏
  • 举报
回复
short arraysrc[W] = {0};
short arraydst[W] = {0};
short *psrc = arraysrc, *ptar = arraysrc;
short *psrc_end1 = arraysrc + W - 4;
short *psrc_end2 = arraysrc + W;
short temp;

while (psrc < psrc_end1)
{
if((temp = *psrc++) != 0)
{
*ptar++ = temp;
}
if((temp = *psrc++) != 0)
{
*ptar++ = temp;
}
if((temp = *psrc++) != 0)
{
*ptar++ = temp;
}
if((temp = *psrc++) != 0)
{
*ptar++ = temp;
}
}

while (psrc < psrc_end2)
{
if((temp = *psrc++) != 0)
{
*ptar++ = temp;
}
}

bloublou 2011-05-25
  • 打赏
  • 举报
回复
short *psrc_end = arraysrc + W;
OR?
short *psrc_end = arraysrc + W -1;
cobras 2011-05-25
  • 打赏
  • 举报
回复

short arraysrc[W] = {0};
short arraydst[W] = {0};
short *psrc = arraysrc, *ptar = arraytar;
short *psrc_end = arraysrc + W;
short temp;

while (psrc != psrc_end)
{
if((temp = *psrc++) != 0)
{
*ptar++ = temp;
}
}


cobras 2011-05-25
  • 打赏
  • 举报
回复
有点错误,修改一下

short arraysrc[W] = {0};
short arraydst[W] = {0};
short *psrc = arraysrc, *ptar = arraytar;
short *psrc_end = arraysrc + W;
short temp;

while (psrc != psrc_end)
{
if((temp = *psrc++) != 0)
{
*ptar++ = temp;
}
}


cobras 2011-05-25
  • 打赏
  • 举报
回复
还可再优化一下

short arraysrc[W] = {0};
short arraydst[W] = {0};
short *psrc = arraysrc, *ptar = arraysrc;
short *psrc_end = arraysrc + W;
short temp;

while (psrc != psrc_end)
{
if((temp = *psrc++) != 0)
{
*ptar++ = temp;
}
}


luciferisnotsatan 2011-05-25
  • 打赏
  • 举报
回复
for循环展开。具体展开层数可以自己测下。展开多并不一定比展开少块。

for(int i=0; i<W;i++)
{
arr[i]++;
}


展开后就是
int i;
int n = W-4;
for(i = 0; i < n;i += 4)
{
arr[i]++;
arr[i+1]++;
arr[i+2]++;
arr[i+3]++;
}

for(;i<W;i++)
{
arr[i]++;
}
cobras 2011-05-25
  • 打赏
  • 举报
回复
用指针吧

short arraysrc[W] = {0};
short arraydst[W] = {0};
short *psrc = arraysrc, *ptar = arraysrc;
short temp;
int i = 0;

for(i=0; i<W; i++)
{
if((temp = *psrc++) != 0)
{
*ptar++ = temp;
}
}
我真的是琦琦 2011-05-25
  • 打赏
  • 举报
回复
我没有想出其它的办法。。。。。
再想想。。。。
bloublou 2011-05-25
  • 打赏
  • 举报
回复
没人看?

69,324

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧