2016-04-15 51 views
0

以下是简单的C源代码,其中char x[2048]是一个全局变量和func1thread1叫,func2thread2称为:焦X [2048]和高速缓存行的问题

char x[2048]={0} , y[16]={0}; 

void func1(){ 
    strcpy(x,y); 
} 

void func2(){ 
    printf("(%s)\n",x); 
} 

int main(int argc, char **argv){ 
    strncpy(y,argv[1],sizeof(y)-1); 
} 

在Intel的CPU ,一个高速缓存行中有64个字节,所以x应占32个 的高速缓存行,我的问题是:

  1. thread1电话func1,应人l 32个高速缓存线可用于该CPU高速缓存,直到然后做strcpy? (或)编译器知道只有一个缓存行就足以完成这项工作?

  2. 虽然thread2请致电func2,那么所有32个高速缓存线都可用于该CPU高速缓存,直到那时做printf? (或)编译器可以识别一个缓存行就够了?

+0

https://en.wikipedia.org/wiki/CPU_cache – user3386109

+2

编译器通常是完全不知道的硬件高速缓存的细节。 – molbdnilo

+0

“do'strcpy/printf'”是什么意思?缓存行不做任何事情,它只是存在(或不)。什么是“可用于该CPU”? – Leeor

回答

4

我建议你阅读维基百科页面:https://en.wikipedia.org/wiki/CPU_cache

一些背景资料:

  1. 通常情况下,高速缓存行($ L)是透明的程序。因此,大多数程序员不直接处理缓存行(将其引入,将其踢出)。 CPU一旦发现代码/数据不在$ L内,就会阻止这样的内存访问,并按要求带入$ L。
  2. 虽然有编码技术可以将数据导入代码中的缓存行(例如通过预取指令),但通常编译器不会为您执行该操作,因为它可能会预取得太早(所以在$ L已经被踢掉了),或者已经太迟了(CPU仍然不得不停止存储器访问)。

回答你的问题:

  1. 号编译器不知道$ LS需要多少在被带到(怎么会知道一个数据是否已在$ L或不,所以只是安全一面,而不是智取本身)。编译器只需执行,例如MOV指令和CPU,在执行此指令时发现操作数不在$中,因此会按需提供。由于您只将副本编入'\ 0',因此$ L也会在那里停止。
  2. 与#1相同。只有被读取的$ Ls会被带入,编译器与此无关。

更多信息:

  1. CPU预取器可能会带来额外的$ LS除了目前所需要的那些。例如,它可能带来下一个$ L,希望获得数据局部性。
  2. 某些高级程序使用预取指令来提高程序性能。假设你知道你的代码将在不久的将来访问某个位置,你可以预取它,并且在你需要它的时候,它已经存在了,所以不会招致$ L错失的惩罚。但是很难做到这一点(你必须知道你的代码的内存访问模式,并在正确的位置插入预取指令。一些高性能的代码设计软件流水线来做到这一点,但它又是一个高级话题)。

https://en.wikipedia.org/wiki/Instruction_prefetch

0

在x86和x64(以及现代ARM和其他常见CPU)上,缓存对用户模式程序完全透明。

因此,strcpy执行第一次读取,CPU自动拉入一个缓存行,strcpy退出\0并完成。与printf("%s",x)一样。