This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] 编译器/TMS320C6657:循环优化

Guru**** 2595805 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/624797/compiler-tms320c6657-loop-optimization

部件号:TMS320C6657

工具/软件:TI C/C++编译器

我尝试优化以下循环:

对于(j=0;j<L_SUBFR;j++){
	pG729A解码器->Postfilt.scal_res2[j]= pG729A解码器->Postfilt.res2[j]>2;
} 

其中L_SUBFR为40。 以下是管道信息:

如果我在scal_res2和res2上尝试restrict关键字,这就是我得到的不会减少周期数的结果:

我还尝试了必须迭代和解卷pragma (具有不同的解卷系数),但循环计数只会增加。

是否有方法优化此循环? 如果有任何建议,我将不胜感激!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Negin 说:
    如果我在scal_res2和res2上尝试restrict关键字,这就是我得到的,不会减少周期数:

    尝试创建scal_res2和res2局部变量,并限制修改它们。  如果这不起作用,请提交一个我可以编译的测试案例。  它不必运行。  按照文章 How to Submit a Compiler Test Case中的说明进行操作

    谢谢,此致,

    -George

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    双手投票赞成George的建议。 嵌套取消引用是第一件要删除的事情。 我确实确认,在我过去的经验中,类似的数组是嵌套结构的成员,使用限制限定条件创建指向实际数据的本地指针,这对我有很大帮助。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    george mock 说:
    尝试创建scal_res2和res2局部变量,并限制修改它们。

    这确实为我节省了很多周期!

    下面是我所做的:

    Word16 * restrict pres2;
    Word16 * restrict pscal_res2;
    
    pres2 = pG729A解码器->Postfilt.res2;
    pscal_res2 = pG729A解码器->Postfilt.scal_res2;
    
    。
    。
    。
    
    用于(j=0;j<L_SUBFR;j++)
    {
    	pscal_res2[j]= pres2[j]>>2;
    } 

    根据性能分析信息,我可以验证包含循环的函数的周期数是否已减少。 但是,在进行此修改后,.asm文件不会显示此循环的任何软件管道信息。  

    您知道为什么会发生这种情况吗?

    谢谢!

    Negin  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    NegIN 说:
    您知道发生这种情况的原因吗?[/QUOT]

    很遗憾,不是  请提交我上一篇文章中描述的测试案例。

    谢谢,此致,

    -George

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    没有一种简单的方法可以猜测为什么不应用流水线,需要查看选项和输出,这在“提及testcase提交指南”中有更好的描述。

    继续优化此循环可能会获得更多效果。 使用本地指针可以省略不必要的取消引用操作,使用限制限定条件可以告诉编译器的源和目标不重叠,从而使其具有更大的灵活性。 但您可以做更多的事情。 您可以使用SIMD指令,因为您的16位数据可以打包方式加载,处理和保存。 为此,您需要确保并告知编译器您的数据指针已对齐。 据我所知,结构的成员根据其类型要求最小对齐,但数组对齐且边界更大,C66 IIRC上为16B。 因此,不用担心,告诉编译器数据与nassert对齐是安全的。 我预计编译器可能会发出SHR2指令来成对处理您的数据。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    George Mock 说:
    请提交我上一篇文章中描述的测试案例。[/QUOT]


    我已附加预处理文件。

    编译器版本:8.1 .................................................................4.

    编译器选项:

    c:\\ti\\csv6\\utils\\bin\\gme"-k src="/POSTFILT.obj"building
    file: c:/.../POSTFsrc.C'
    'invoking: C6000 Compiler'
    "C:/ti/ccsvsv6/tools/ti-CGt_pg_pg_premot_ipel=-f6600_compt_profilel_-c_ipel_ipel_in=-f_ipf_intr_ipel_f=-f=-f_j_f_ji_f_ji=-c=-fi_c=-fi_compt_c=-fi_c_jipel_f_f_f_f_c=-f6600_c_c_c_julf_c_c=-f_c_jipel_c_c=f_julf_c=-f_c_c_c_rebipio/f_c_c_c_c_c_c=-f_c_julf_c_c_c_ 8.1 8.1
    (性能)如果您知道此循环将始终以<20>的倍数且至少<20>次执行,请尝试在循环之前添加"#pragma must迭代(20,20)"。
    "C:/.../POSTFILT.C",第158行:建议#3.0009万:(性能)如果您知道此循环将始终以<42>的倍数且至少<42>次执行,请尝试在循环之前添加"#pragma must迭代(42,42)"。
    '完工建筑:C:/.../POSTFILT.C'
    '' 

    谢谢!

    Negin

    e2e.ti.com/.../POSTFILT.txt

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    rrlagic 说:
    为此,您需要确保并告知编译器您的数据指针已对齐。

    感谢您的评论! 我尝试按照您的建议使用nassert:

    _nassert (((Word16) pres2 % 8 == 0);
    _nassert(((Word16) pscal_res2 % 8 ==0);
    #pragma must迭代(40,40,40)
    #pragma展开(8) 
    用于(j=0;j<L_SUBFR;j++) { pscal_res2[j]= pres2[j]>>2; }

    不添加pragma和nassert的函数的平均循环数为2031。

    添加nassert后,它增加到2115,但包括pragma (使用nassert)后,它减少到1940。

    我仍然无法在.asm文件中看到任何软件管道信息(甚至不是“不合格循环”),这就好像连循环都不被识别为循环。

    您认为我可以进一步优化环路吗? 我已在上一篇帖子中提交了测试案例,并希望您提供建议。

    谢谢!

    Negin

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    NegIN 说:
    我尝试按照您的建议使用nassert [/QUOT]

    实际上,这会导致函数产生错误的结果。 我还收到以下警告:

    #770-D从指针转换为较小的整数 

    如何解决此问题有什么想法?

    谢谢!

    Negin

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    指针是否为16位?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Keith Barkley 说:
    指针是否为16位?[/QUOT]

    它们是32位:

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    然后,您可能应该在类型转换中使用Word32,而不是Word16。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [报价用户="NegIN"]

    根据性能分析信息,我可以验证包含循环的函数的周期数是否已减少。 但是,在进行此修改后,.asm文件不会显示此循环的任何软件管道信息。  

    您知道为什么会发生这种情况吗?

    [/引述]

    是的。  因为此循环...

    Negin 说:
    for (j=0;j<L_SUBFR;j++)

    { pscal_res2[j]= pres2[j]>>2;}

    ...完全展开。  所有这些操作都是作为一个直线代码块来实现的。

    谢谢,此致,

    -George

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    正如George建议的那样,循环可能会完全展开。 我无法在测试中再现这种情况。 但是,循环计数报告是由函数的其余部分而不是所考虑的循环引起的。 加载,移动,存储-是非常简单的顺序,并受益于SIMD的使用。 我期待着SHR2的指示,但我已经老了,现在事情变得更好了。 考虑片段:

    #pragma FUNC_Cannot内联( mytest );
    #pragma function_options ( mytest,"--opt_level3--opt_for_speed5");
    
    void mytest(void)
    {
    const Int16 * restrict src =(Int16 *) mysrc;
    Int16 *限制DST =(Int16 *) mydst;
    int i;
    
    _nassert (((int) src % 8 ==0);
    _nassert (((int) dst % 8 ==0);
    #pragma must迭代(40,40,40)
    
    对于(i = 0;i < 40;I++)
    DST[I]= src [I]>> 2;
    } 

    此零件的装配体如下所示:

    我的测试:
    ;**------------------ *;*
    1304--------------------------- 	C1美元=有源;;*1304------------------
    	src =(int (*)[14][1200])C1美元+1.9712万;;;*1305---------------</s>1305
    	dst =(int (*)[14][1200])C1美元+2.4512万;;;**-----------
    	U15美元 =(短持续时间(*)[4]) src;
    ;**------------------ 	U18美元 =(短(*)[4])DST;
    ;*1312	--------------------------- L1美元=10;;**------------------
    	#pragma must迭代(10,10,10)
    ;**	--------------------------- //以下循环按系数(4)展开
    ;**------------------ 	#pragma loop_flags(4098u)
    ;**------------------ 	G2:
    ;* 13.1313万--------------- 	*U18美元++{8}=_dshr2(*U15美元++{8},2);
    ;*1312	--------------------------- 如果( L1美元 = L1美元-1 )转到G2;;;**------------------
    	返回; 

    大家可以看到,循环的结构非常简单,这一点通过流水线信息得到了确认

    ;* 循环展开多个 :4x
    ;* 已知最小行程计数 :10.
    ;* 已知最大行程计数 :10.
    ;* 已知最大跳闸计数因子 :10
    ;* 循环带依赖关系绑定(^):0
    ;* 未分区的资源绑定 :1
    ;* 分区资源绑定(*):1;*
    资源分区:
    ;* A侧B侧
    ;* .L单位 0 0
    ;* .S单位 0 1*;*
    D单位 1* 1*;*
    M单位 0 0
    ;* X交叉路径 0 1*;*
    .T地址路径 1* 1*;*
    长读取路径 0 0
    ;* 长写入路径 0 0
    ;* 逻辑操作(.lS) 0 0 (.L或.S单位)
    ;* 附加操作(.LSD) 0 0 (.L或.S或.D单位)
    ;* Bound (.L .S .LS) 0 1*;*
    Bound (.L .S .D .LS .LSD) 1* 1*;*;*
    
    正在搜索软件管道计划...
    ;* II =1并联7次迭代的计划
    ;* 完成
    ;*;*
    循环将被上载
    ;* 折叠的脱毛阶段 :0
    ;* 折叠的Prologue阶段 :0
    ;* 所需的最小内存垫:0字节
    ;*
    ;* 最小安全跳闸计数 :1 (展开后)
    ;*------------------ *
    $C$L43:;管道循环PROLOGUE
    
    SPLOOPD 1. ;7. ;(P)||
    MVC S2 B7,ILC
    
    ;**------------------ *
    $C$L44:;管道循环内核
    $C$DW$L$mytest3美元$B:
    LDDW .d1T1 * A3++,A5:A4 ;|1313|(P)<0,0>
    无操作 4.
    DSHR2 .S2X A5:A4,2,B5:B4 ;|1313|(P)<0,5>
    
    SPKERNEL 6,0||
    STDW .d2T2 B5:B4,* B6++ ;|1313|<0,6>$C$DW$L$mytest3美元$E:;**------------------
    
    
    *$C$L45:
    ;管道环EPILOGUE;**------------------
    * 

    我希望它能成对运行,但它只需四个步骤就能处理它们! 因此,对于10个未滚动的行程计数,应该只需几十个周期即可完成。 未滚动的版本可能会更快。 我会检查其他功能的性能。

    至于您看到的警告,它与_nassert()中的类型转换有关。 如果按住Ctrl键并单击以查找其声明,您将看到

    extern _code_access void _nassert (int); 

    这是警告的根本原因。 您必须转换到(int)。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好,

    循环:已完全展开,作为10 DSHR2 *(64位= 4字16 * 10 = 40)的序列实施

    转换警告:_nassert将32位值强制转换为Word16。 nassert与指针有关,而不是其指向的类型:
    _nassert (((int) pres2 % 8 ==0);//使用"int"- sizeof(int)== sizeof(Word16*)

    警告:声明前提条件可能是假的。 据我所知,16字节的阵列对齐仅适用于顶层对齐。 在结构中,约束是元素的类型(在您的情况下为2个字节)。

    要保证8字节对齐,您必须在数组声明之前放置一个(可能是虚拟)带有对齐限制的文件8字节(或使用__attribute__)。

    请注意,在以下情况下也会遵守约束:
    1.该结构至少包含一个8字节类型
    2.(数组前面的字段的sizeof())% 8 ==0。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    结构
    {
    字符A;
    字符b;
    
    双重虚拟; //强制8B对齐
    短数组[size];//已对齐数组。 

    我似乎在给出未经验证的关于对齐的建议。 数组作为结构成员似乎会根据其各自类型的要求进行对齐,除非前面有较大的对齐要求的成员。 这可能是您在修改后看到错误数字的原因。 确保对齐的一种方法是放置所需对齐的伪射野,如