为什么通过缓存c ++访问静态ram会有明显的速度下降?

Fan*_*Fox 15 c++ powerpc rtems

背景

我一直在研究可能使用MPC5200静态RAM空间作为便笺式存储器.我们有16Kb未使用的内存出现在处理器总线()上.

现在一些重要的实施说明是:

  1. 这个存储器由BestComm DMA控制器使用,在RTEMS此基本上将在SRAM的开始处设置一个任务表,其中包含一组16个任务,可以作为外设接口,I2C,以太网等的缓冲区运行.为了使用这个空间没有冲突并且知道我们的系统只使用大约2Kb的以太网驱动程序缓冲区,我将SRAM的起始偏移了8Kb,所以现在我们知道8Kb的内存不会被系统使用.

  2. RTEMS 定义一个指向静态内存的数组,如下所示:

(来源)

typedef struct {
    ...
    ...
    volatile uint8_t    sram[0x4000];
 } mpc5200_t;

 extern volatile mpc5200_t mpc5200;
Run Code Online (Sandbox Code Playgroud)

我知道sram数组指向静态内存,因为当我编辑第一部分并打印出内存块(MBAR + 0x8000 源代码)时

所以从这里我可以说以下,我有RTEMS定义访问SRAM通道mpc5200.sram[0 -> 0x2000].这意味着我可以开始对我可以摆脱它的速度进行一些测试.


测试

为了评估速度,我设置了以下测试:

int a; // Global that is separate from the test. 

**TEST**

// Set up the data.
const unsigned int listSize = 0x1000;
uint8_t data1[listSize];
for (int k = 0; k < listSize; ++k) {
    data1[k] = k;
    mpc5200.sram[k] = k;
}

// Test 1, data on regular stack.
clock_t start = clock();
for (int x = 0; x < 5000; ++x) {
    for (int y = 0; y < 0x2000; ++y) {
        a = (data1[y]);
    }
}
double elapsedTime = static_cast<double>(clock() - start) / CLOCKS_PER_SEC;
printf("elapsed dynamic: %f\n" ,elapsedTime);

// Test 2, get data from the static memory.
start = clock();
for (int x = 0; x < 5000; ++x) {
    for (int y = 0; y < 0x2000; ++y) {
        a = (mpc5200.sram[y]);
    }
}
elapsedTime = static_cast<double>(clock() - start) / CLOCKS_PER_SEC;
printf("elapsed static: %f\n" ,elapsedTime);    
Run Code Online (Sandbox Code Playgroud)

非常简单,概念是我们在可用空间上进行迭代并设置全局空间.我们应该期望静态内存应该具有相同的大致时间.


结果

所以我们得到以下内容:

elapsedDynamic = 1.415
elapsedStatic = 6.348
Run Code Online (Sandbox Code Playgroud)

所以这里有一些东西,因为静态几乎比缓存慢6倍.


假设

所以我有三个想法,为什么这是:

  1. 缓存未命中,我想也许是因为我们正在混合动态和静态ram,发生了一些奇怪的事情.所以我尝试了这个测试:

.

// Some pointers to use as incrementers
uint8_t *i = reinterpret_cast<uint8_t*>(0xF0000000+0x8000+0x1000+1);
uint8_t *j = reinterpret_cast<uint8_t*>(0xF0000000+0x8000+0x1000+2);
uint8_t *b = reinterpret_cast<uint8_t*>(0xF0000000+0x8000+0x1000+3);


// I replaced all of the potential memory accesses with the static ram
// variables. That way the tests have no interaction in terms of 
// memory locations. 
start = clock();
// Test 2, get data from the static memory.
for ((*i) = 0; (*i) < 240; ++(*i)) {
    for ((*j) = 0; (*j) < 240; ++(*j)) {
        (*b) = (mpc5200.sram[(*j)]);
    }
}
elapsedTime = static_cast<double>(clock() - start) / CLOCKS_PER_SEC;
printf("elapsed static: %f\n" ,elapsedTime);
Run Code Online (Sandbox Code Playgroud)

我们有以下结果:

elapsedDynamic = 0.0010
elapsedStatic = 0.2010
Run Code Online (Sandbox Code Playgroud)

那现在它慢了200倍?所以我想这与此无关?

  1. 静态记忆与正常情况不同,我认为接下来的事情可能是因为这条线路可能与我认为不会相互影响:

    MPC5200包含16KB的片上SRAM.BestComm DMA单元可直接访问此存储器.它主要用作BestComm DMA用于将外围数据移入和移出SDRAM或其他位置的任务表和缓冲区描述符的存储.这些描述符必须在启动时下载到SRAM.该SRAM位于MPC5200内部寄存器空间中,也可由处理器内核访问.因此,它可以用于其他目的,例如便笺式存储.16kBytes SRAM从位置MBAR + 0x8000开始.

(来源)

我不确定如何确认或否认这一点?

  1. 较慢的静态时钟,也许静态内存运行在较慢的时钟上,就像某些系统一样?

通过查看手册可以证明这一点:

在此输入图像描述

(来源)

SRAM和处理器在同一时钟上XLB_CLK运行,处理器基频()


可能导致这种情况的原因是,是否有理由不使用SRAM进行便笺式存储?我知道在现代处理器上甚至不会考虑这个,但这是一个较旧的嵌入式处理器,我们正在努力争取速度和空间.


额外的测试

所以在下面的评论后我进行了一些额外的测试:

  1. 添加volatile到堆栈成员以查看速度是否更相等:

.

elapsedDynamic = 0.98
elapsedStatic = 5.97
Run Code Online (Sandbox Code Playgroud)

所以仍然要快得多,并没有真正的变化与波动

  1. 反汇编代码,看看发生了什么

.

// original code
int a = 0;
uint8_t data5[0x2000];
void assemblyFunction(void) {
    int * test = (int*) 0xF0008000;
    mpc5200.sram[0] = a;
    data5[0] = a;
    test[0] = a;
}
Run Code Online (Sandbox Code Playgroud)
void assemblyFunction(void) {
// I think this is to load up A
0:  3d 20 00 00     lis     r9,0
8:  80 09 00 00     lwz     r0,0(r9)
 14:    54 0a 06 3e     clrlwi  r10,r0,24

    mpc5200.sram[0] = a;   
    1c: 3d 60 00 00     lis     r11,0
  20:   39 6b 00 00     addi    r11,r11,0
  28:   3d 6b 00 01     addis   r11,r11,1 // Where do these come from?
  2c:   99 4b 80 00     stb     r10,-32768(r11)

test[0] = a;
   c:   3d 20 f0 00     lis     r9,-4096 // This should be the same as above??
  10:   61 29 80 00     ori     r9,r9,32768
  24:   90 09 00 00     stw     r0,0(r9)

    data5[0] = a;
    4:  3d 60 00 00     lis     r11,0
    18: 99 4b 00 00     stb     r10,0(r11)
Run Code Online (Sandbox Code Playgroud)

我不是特别擅长互穿汇编程序,但也许我们在这里有问题?从全局访问和设置内存似乎需要更多的指令SRAM

  1. 从上面的测试看来,指针的指令似乎较少,所以我添加了这个:

.

uint8_t *p = (uint8_t*)0xF0008000;

// Test 3, get data from static with direct pointer.
for (int x = 0; x < 5000; ++x) {
    for (int y = 0; y < 0x2000; ++y) {
        a = (p[y]);
    }
}
Run Code Online (Sandbox Code Playgroud)

我得到以下结果:

elapsed dynamic: 0.952750
elapsed static: 5.160250
elapsed pointer: 5.642125
Run Code Online (Sandbox Code Playgroud)

因此指针需要更长时间!我原以为它会完全一样吗?这只是变得陌生.

Fan*_*Fox 1

所以看起来有几个因素可能会导致这种情况。

  1. 我不再确定 SRAM 是否以与处理器相同的时钟速度运行。正如@user58697 所指出的,SRAM尽管看起来总线采用的是 XLB 时间,但它采用的是 IPB 时钟时间。最上面有这个图:

在此输入图像描述来源

这似乎表明内存时钟位于 XLB 路径上,但 XLB 路径的频率低于 CORE 时钟。这可以在这里确认:

在此输入图像描述

来源

这表明 XLB_Bus 的运行速度比处理器慢。

  1. 为了测试 SRAM 至少比动态 RAM 快,我进行了以下测试:

// Fill up the cache with pointless stuff
for (int i = 0; i < 4097; ++i) {
    a = (int)TSin[i];
}

// 1. Test the dynamic RAM access with a cache miss every time. 
ticks = timer_now();
// += 16 to ensure a cache line miss.
for (int y = 0; y < listSize; y += 16) {
    a = (data1[y]);
}
elapsedTicks = timer_now() - ticks;

// Fill up the cache with pointless stuff again ...

ticks = timer_now();
// Test 2, do the same cycles but with static memory.
for (int y = 0; y < listSize; y += 16) {
    a = (mpc5200.sram[y]);
}
elapsedTicks = timer_now() - ticks;
Run Code Online (Sandbox Code Playgroud)

这样我们得到以下结果:

elapsed dynamic:  294.84 uS
elapsed static:  57.78 uS
Run Code Online (Sandbox Code Playgroud)

所以我们在这里可以说的是,静态 RAM 比动态 RAM 更快(预期),但是当动态 RAM 加载到高速缓存中时,访问静态 RAM 的速度要慢得多,因为高速缓存访​​问是以处理器速度进行的,而静态 RAM 速度是比这个少得多。