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.

[参考译文] TMDSSMK6455:从内存读取需要太长的时间

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

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/821893/tmdsmdsk6455-reading-from-memory-takes-too-long

器件型号:TMDSK6455

大家好、我正在开始我的 DSP 编程之旅。 我有一个 DSK6455、我将优化以下代码。

#pragma MUST_ITERATE (number_for_columns、number_for_columns、1)
#pragma UNROLL (2)
(col = 0;col < number_for_columns;+col)
{
int16_t CURRENT_Cost = 0;
for (row = 0;row < number_for_rows;++row)
{
int16_t lookup_data_row]

= 10.0[t_lookup];[t_row_lookup_data]
(row_row_lookup_data_row_lookup])

if (Current_Cost > Current_max)
{
Current_max = Current_Cost;
Current_max_INDEX = col;
}

T1 = TSCL; 

我尝试逐行对这段代码进行配置、并注意到从存储器读取(例如 DATA_lookup_table[row][col])并将其存储在临时变量中、需要80到120个时钟。 我观看了 C6000优化视频系列、其中有人说从存储器读取需要4个时钟。 我弄错了吗? 我可以更快地完成该程序吗?

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

    您好!

    所呈现的代码片段不足以得出某些结论。 不过,有一些问题需要考虑。

    第一、您将数据和查找表放置在何处。 这是 L2、您的号码看起来非常可疑。 如果是外部存储器、则接下来要考虑高速缓存。

    我们看不到 DATA_lookup_table 的分配方式。 如果这是静态2D 数组或指针数组、则在这种行的组织元素中、是内存中的邻居、而列的元素则不是。 根据行长度的不同、按列访问矩阵可能会导致高速缓存缺失、读取速度慢的多周期性能。

    接下来、我们看不到 DATA_lookup_table 中的数据类型、为什么如果将结果分配为 short、则乘以浮点10.0很重要。

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

    感谢您的回复。 这是我的整个代码。 (数据已收发)

    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define NUMBER_ON_ROWS 6
    #define NUMBER_ON_COLUMNS 100
    
    static const Int16_t DATA_lookup_table[NUMBER_ON_ROWS ][NUMBER_ON_COLUM]={
    977,973,969,979,974,969,980,975,970,980,975,969,978,982,982,975,969、……
    -1783、-1789、-1796、-1778、-1786、-1795、-1776、-1786、-1794、-1775、-1785、...
    -1080、-1089、-1099、-1075、-1087、-1100、-1073、-1087、-1099、-1074、-1088、...
    16、37、58、78、98、117、140、158、179、201、221、240、261、279、303、320、339、362、...
    -1778、1797、1773、1773、1749、1724、1724、1698、1673、1672、1646、1620、1619、...
    -1090、-1131、-1171、-1177、-1218、-1259、-1267、-1308、-1350、-1359、-1401、...
    };
    
    #define SINMAX 9000
    静态 uint8_t sinlut[SINMAX + 1];
    void SinCreate (
    
    ){int i;
    双角、angleinc;
    
    angleinc = 3.1415926535 / 2.0 /(SINMAX);
    for (i = 0、angle = 0.0;i <= SINMAX;++I、angle +
    ={angleinc)
    sinlut[i]= cos (角度)* 100;
    }
    }
    
    void ALG (int which _column)
    {
    SinCreate ();
    int row、col;
    int current_max_index = 0;
    int16_t current_max = 0;
    unsigned int t0、t1;
    
    TSCL = 0;
    T0 = TSCL;
    
    #pragma MUST_ITERATE (number_of 列、number_of 列、1)
    针对
    (col = 0;col < number_of 列;+col)
    {
    int16_t CURRENT_Cost = 0;
    for (row = 0;row < number_of 行;+col < number_of 列;+col)
    =[t
    lookup_row]{int16_t CURRENT_cost = 0;[t lookup_lookup_off]
    
    = t <number_row_lookup_row](<number_lookup_row_row_rows)*=[t +<number_lookup_row_row_data_lookup.[t)、[t
    
    
    if (current_cost > current_max)
    {
    current_max = current_cost;
    current_max_index = col;
    }
    
    T1 = TSCL;
    printf ("%d\n"、t1-t0);
    
    if (current_max_index = which _column)
    printf ("sceed\n"、t1-t0);
    
    
    
    
    
    
    
    
    if (current_max_index = which _column);else printf ("failed")(void 10);return (int)
    
    

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

    您好!

    您显示的是6*100*sizeof (short)= 1200字节,sinlut 为9001字节,因此数据总大小远低于 L1D 高速缓存的32KB 容量。

    接下来、您的数据表中有100列短路、即200字节。 由于 C64+上的缓存行仅为64字节、 (data_lookup_table[row][col] - data_lookup_table[row][which_column]) 因此根据括号大小差异的'which _column'值计算、可能位于相同的缓存行上、但可能不会。  

    如前所述、由于对数据表进行逐列访问、因此每个新行访问都将导致强制缺失。 因此、如果您的数据不是静态表、而是运行时传入的随机数据、那么组织和处理这些数据的方式可能不是最好的。

    但是、我的主要问题是您如何测量存储器访问时间、我们在您的代码中看不到这一点。

    我再进一步、举例来说、我在 C6670上补充了一些您的大小、编译和运行的散列数据、因为我的办公桌没有 C64+。

    第一次尝试时、我花费了39397个周期。 然后我将 SinCreate()移动到 main 中,并在 main 中使用不同的参数多次调用 ALG(),但仍然收到令人沮丧的39235个周期。 接下来我应用了-O3优化、它给出了1339、1170、1166个周期。

    接下来、我用整数10替换乘法10.0、因为您的数据是整数、现在可以向下扩展到823、672、667个周期。

    您没有告诉我们您的数据位于何处、因此我使用以下链接器命令文件确保了我的所有内容都位于 L2中:

    -c
    -heap 0x1000
    -stack 0xa000
    
    memory
    {
    L2SRAM (rwx):org = 0x0800000,len = 0x100000
    }
    
    
    SECTIONS
    {
    .sysmem > L2SRAM
    .cinit > L2SRAM
    .stack > L2SRAM
    *> L2SRAM
    }
    

    同样 、600次迭代的整个双循环花费的成本低于700个周期。 您的器件的效率会稍低一些。 不过、如果您坚持只需几分钟就能看到80到250个时钟、那么您的侧边就会出现严重错误。

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

    大家好、我非常感谢您的回答。 这是我的最终代码。 我用10取代了10.0,周期数从 105963减少到3400。 这不是奇怪吗?! 我还启用了-O3优化标志。 还有一个问题。 我应该将 您在上一个答案中提到的链接器命令文件放在何处? 我还应该做些什么吗? 感谢您的贡献。

    #include 
    #include 
    #include 
    #include 
    #include 
    
    #define NUMBER_ON_ROWS 6
    #define NUMBER_ON_COLUNS 100
    
    static const Int16_t DATA_lookup_table[NUMBER_ON_ROWS ]={977,973,969,979,974,969,980,985,970,9979,989,982,982,979,979,1006,1001,1001,1006,996,981,1006,1001,996,981,1001,1001,981,996,981,996,981,981,1006,1006,1006,1001,1006,1001,996,981,996,981,996,981,996,981,1001,1001,1001,1006,1006,1001,1001,996,981,1001,1001,1006,981,996,981,996,981,996,981,996,981,996,981,1001,1001,1006,981,1001,1001,1006,981,1001,1006,1006,1006,981,1001,1001,1001,996,981,1006,981,996,981,1001,996,981,996,981,996,981,996,981,1006,981,996,981,100
    
    
    
    
    
    1090、-1131、-1171、-1177、-1218、-1259、-1267、1308、-1350、-1359、-1401、-1444、-1453、-1496、-1507、-1550、-1594、-1606、-1651、-1663、-1709、-1452、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1072、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472、1472
    
    
    
    
    
    
    
    
    
    
    
    
    sinlut[i]= cos (角度)* 100;
    }
    
    
    }int ALG (int which _column)
    {
    int 行、col;
    int Current_max_index = 0;
    int16_t CURRENT_max = 0;
    
    #pragma MUST_ITERATE (number_of _columns、number_of _columns、1)
    #pragma UNROLL (2)
    对于(col = 0;col < number_of _columns;++col)
    {
    int16_t CURRENT_Cost = 0;
    对于(row = 0;row < number_for_rows;++row)
    {
    int16_t ix =(data_lookup_table[row][col]- data_lookup_table[row][which 列])* 10;
    
    Current_Cost += sinlut[ix];
    }
    
    如果(Current_Cost > Current_max)
    {
    Current_max = Current_Cost;
    Current_max_index = col;
    }
    }
    
    返回 CURRENT_MAX_INDEX;
    }
    
    int main (void)
    {
    SinCreate();
    
    unsigned int t0、t1;
    
    TSCL = 0;
    T0 = TSCL;
    内部电流= ALG (10);
    T1 = TSCL;
    printf ("当前:%d\n"、当前);
    printf ("%d\n"、t1-t0);
    返回0;
    }
    

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

    我找到了链接器命令文件:

    内存
    {
    L2RAM: O = 0x00800000 l = 0x00200000 // 2MB L2内部 SRAM */
    L1PRAM: O = 0x00E00000 l = 0x00008000 // 32kB L1程序 SRAM/cache */
    L1DRAM: O = 0x00F00000 l = 0x00008000 // 32kB L1数据 SRAM/cache */
    EMIFA_CE2:O = 0xA0000000 l = 0x00800000 // 8MB EMIFA CE2 *
    EMIFA_CE3:O = 0xB0000000 l = 0x00800000 // 8MB EMIFA CE2 *
    EMIFA_CE4:O = 0xC0000000 l = 0x00800000 // 8MB EMIFA CE2 *
    EMIFA_CE5:O = 0xD0000000 l = 0x00800000 // 8MB EMIFA CE2 *
    DDR2_ce0:O = 0xE0000000 l = 0x20000000 // 512MB EMIFB ce0 *
    }
    
    SECTIONS
    {
    .text > L2RAM
    堆栈 > L2RAM
    .bss > L2RAM
    .cio > L2RAM
    .const > L2RAM
    .data > L2RAM
    切换 > L2RAM
    sysmem > L2RAM
    .far > L2RAM
    .args > L2RAM
    .ppdinfo > L2RAM
    .ppdata > L2RAM
    
    /* COFF 段*/
    .pinit > L2RAM
    .cinit > L2RAM
    
    /* EABI SECTIONS *
    二进制文件 > L2RAM
    .init_array > L2RAM
    .neardata > L2RAM
    fardata > L2RAM
    rodata > L2RAM
    .c6xabi.exidx > L2RAM
    .c6xabi.extab > L2RAM
    } 

    我应该根据电路板规格更改它吗?  

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

    您好!

      rrlagic 的建议 是将代码/数据放入 L2存储器、以便比放入外部存储器(DDR)更快地进行访问。 存储器映射由上面显示的链接器命令文件给出。 您需要根据电路板修改 LCF。 乍一看、L2从大小为2MB 的0x0080_0000开始、看起来是正确的。

    此致、Eric