当给变量赋值时,数据会不会马上被写到内存

kakarot23 2009-04-03 04:17:22

当我们读一个变量的值时,有时候因为编译器的优化原因,不会直接从内存读取,
而是从寄存器读取之前的备份.

所以请问一下,当给变量赋值时,数据会不会马上写到相应的内存里,还是只是暂时先保存在寄存器上.
...全文
652 35 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
35 条回复
切换为时间正序
请发表友善的回复…
发表回复
fly_new 2009-04-05
  • 打赏
  • 举报
回复
简单说吧,第一次运行的时候,你的代码不命中,会去内存取;第一次运行时,可能你的某个变量也不命中,会到内存取。
第二次和后面几次命中,执行时间肯定会小很多。

你查一下存储器的局部性,数据和指令都存在局部性概念。
liliangbao 2009-04-05
  • 打赏
  • 举报
回复
变量赋值应该直接写入内存的~
kakarot23 2009-04-05
  • 打赏
  • 举报
回复
第一次1和第一次0的时间都比后面七次的长
dongpy 2009-04-05
  • 打赏
  • 举报
回复
所以请问一下,当给变量赋值时,数据会不会马上写到相应的内存里,还是只是暂时先保存在寄存器上.
================================================================
如果是被编译器优化为寄存器的局部变量,那就不涉及内存操作。

否则,给变量赋值时,会有类似MOV [BX],AX的指令,即有从寄存器到内存的数据传输。
如果高速缓存(CACHE)命中,那么数据通过内部数据总线传输到CACHE,否则直接写入外存。
Paradin 2009-04-05
  • 打赏
  • 举报
回复
学习
ies_sweet 2009-04-05
  • 打赏
  • 举报
回复
楼上2位所言即是,学习了。
继续关注
kakarot23 2009-04-05
  • 打赏
  • 举报
回复
[Quote=引用 31 楼 ies_sweet 的回复:]
引用 7 楼 yyyapple 的回复:
CPU和主内存之间有个Cache,应该不会被立即写到相应内存


应该是这样,这个和硬件相关度就比较大了
Cache也可以是分多级的
不过,如果不是考虑硬实时的嵌入式系统
就不必关心这些底层的实现细节了。

楼上有的朋友提到了volatile,
这个是可以的
此关键字告知编译器不要对此变量进行存储格式优化。
不保留寄存器副本,不保留缓冲区副本。
[/Quote]

volatile这个声明貌似只告诉编译器不要从寄存器取数据,但并不确定它是直接从内存取还是从cache中取.也不确定会否实时写进内存吧
fly_new 2009-04-05
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 kakarot23 的回复:]
你的意思是不是指我所遇到的问题是Icache造成的,而不是Dcache.
因为如果是Dcache的问题,那我第一次置0时, 由于之前已经置1,所以置0时数据已经在cache中,花费的时间会较少,跟我所碰到的问题有出入.[/Quote]
Dcache和Icache一起影响你的结果。关于设置你的GPIO寄存器为1和0的问题,你先确认GPIO寄存器的地址,在cache设置上,能不能“过”

[Quote=引用 31 楼 ies_sweet 的回复:]
引用 7 楼 yyyapple 的回复:
楼上有的朋友提到了volatile,
这个是可以的
此关键字告知编译器不要对此变量进行存储格式优化。
不保留寄存器副本,不保留缓冲区副本。
[/Quote]
使用volatile修饰的变量,编译器不光对存储的时候有要求,另外一个,也是大家很少注意的是,编译器不会重新排序你的指令。你使用一般编译器,你不感觉,当你使用某些特殊编译器(比如要编译一个能在乱序处理器上运行的程序的时候,使用专门的编译器)上编译时,就知道这个的重要性了。
不保留缓冲区副本,除非硬件有特殊支持(目前没见过),那:要么每写完一次后用指令去刷出去,要么就写之前用指令先禁止cache,要么就干脆这个变量所在的一个页都不过cache。
所以,使用volatile不能根本解决cache和内存同步的问题。
ies_sweet 2009-04-05
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 yyyapple 的回复:]
CPU和主内存之间有个Cache,应该不会被立即写到相应内存
[/Quote]

应该是这样,这个和硬件相关度就比较大了
Cache也可以是分多级的
不过,如果不是考虑硬实时的嵌入式系统
就不必关心这些底层的实现细节了。

楼上有的朋友提到了volatile,
这个是可以的
此关键字告知编译器不要对此变量进行存储格式优化。
不保留寄存器副本,不保留缓冲区副本。
kakarot23 2009-04-05
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 fly_new 的回复:]
首先,你检查下GPIO的模式,具体我记不清楚了,如果模式没问题的话,再看我下面的意见。
你其实只是想测试,一个循环的每次循环的时间开销。如果抛开你的GPIO操作不看。下面我们讨论有cache(ARM如果是哈佛架构的话,分Dcache和Icache,即数据高速缓存和指令高速缓存)的情况。那第一次执行时间肯定会长于后面的执行时间。你加入了GPIo的测试代码,那当然第一次也是长于其他次了。不管你的GPIO测试代码是否用到cache,如果用到了,那更是后面的执行时间短。另外,GPIO的寄存器读取,这段内存,你们肯定会设置为不能过cache的(当然也不能带write-buff),你可以去确认下。所以,不管你读取还是写GPIO的寄存器,其实时间是差不多的(抛开总线冲突等因素)。所以你不管是设置1还是0,只要是第一次设置,那就是比后面的时间长。
如果你是整个系统都不开mmu,cache和write-buff,在所有代码和引用数据都一样的情况下,那循环的每次执行时间是一样的(假设指令预测和外界的因素不考虑)。这就跟最老土的一些机器一样了。
[/Quote]

你的意思是不是指我所遇到的问题是Icache造成的,而不是Dcache.
因为如果是Dcache的问题,那我第一次置0时, 由于之前已经置1,所以置0时数据已经在cache中,花费的时间会较少,跟我所碰到的问题有出入.
kakarot23 2009-04-05
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 fly_new 的回复:]
老兄,ARM板上的ARM型号说出来看看,操作系统和含不含cache没关系,它顶多是用不用cache的。据我看目前的ARM,应该是含cache的。你可以在ARM的CP15里去看看cache的设置,这个你可以把型号说出来,或者把手册发出来看看就知道了。另外,如果有MMU和cache,对数据的读写其实是 不 一样的。目前的ARM,很多会带write-buff,这个东东,会影响你第一次写数据的时候,如果数据不在cache里,就直接写到这里,然后它找个机会去同步cache…
[/Quote]

ARM型号忘了.那些文档啥的都只放在公司.等周二去上班再发型号.
kostion 2009-04-05
  • 打赏
  • 举报
回复
会直接写,用编译器的调试器看一下就知道了,编译器会显示相应变量的内存地址,可以看到里面的值
fly_new 2009-04-05
  • 打赏
  • 举报
回复
老兄,ARM板上的ARM型号说出来看看,操作系统和含不含cache没关系,它顶多是用不用cache的。据我看目前的ARM,应该是含cache的。你可以在ARM的CP15里去看看cache的设置,这个你可以把型号说出来,或者把手册发出来看看就知道了。另外,如果有MMU和cache,对数据的读写其实是 一样的。目前的ARM,很多会带write-buff,这个东东,会影响你第一次写数据的时候,如果数据不在cache里,就直接写到这里,然后它找个机会去同步cache和内存。

漏了一个字,呵呵!
cxxer 2009-04-05
  • 打赏
  • 举报
回复
不一定.
fly_new 2009-04-05
  • 打赏
  • 举报
回复
谢谢楼上各位高手的分析. 
我开发的板子是ARM板, 系统用的是UCLINUX, 不含MMU.
请问下UCLINUX有没有cache这个东东?


老兄,ARM板上的ARM型号说出来看看,操作系统和含不含cache没关系,它顶多是用不用cache的。据我看目前的ARM,应该是含cache的。你可以在ARM的CP15里去看看cache的设置,这个你可以把型号说出来,或者把手册发出来看看就知道了。另外,如果有MMU和cache,对数据的读写其实是一样的。目前的ARM,很多会带write-buff,这个东东,会影响你第一次写数据的时候,如果数据不在cache里,就直接写到这里,然后它找个机会去同步cache和内存。


如果是cache的问题, 
具体要怎么关闭这个功能呢?

参见指令MRC和MCR指令,以及手册,看看哪个字段是关cache的,注意如果有Icache也同时关闭。关cache容易,如果是开很麻烦。不过关cache只是为了你验证你的问题,正是代码肯定不能关。

而且还有个问题,如果是cache的问题,那么我第一次置1时,会从内存读取,然后放在cache中,这个时候花费的时间会比较长. 
但是当第一次置0时, 应该就会直接从cache中取数据,而不需要从内存中取,这个时间会比较短.

可是现在却是第一次置1和置0都比较…

首先,你检查下GPIO的模式,具体我记不清楚了,如果模式没问题的话,再看我下面的意见。
你其实只是想测试,一个循环的每次循环的时间开销。如果抛开你的GPIO操作不看。下面我们讨论有cache(ARM如果是哈佛架构的话,分Dcache和Icache,即数据高速缓存和指令高速缓存)的情况。那第一次执行时间肯定会长于后面的执行时间。你加入了GPIo的测试代码,那当然第一次也是长于其他次了。不管你的GPIO测试代码是否用到cache,如果用到了,那更是后面的执行时间短。另外,GPIO的寄存器读取,这段内存,你们肯定会设置为不能过cache的(当然也不能带write-buff),你可以去确认下。所以,不管你读取还是写GPIO的寄存器,其实时间是差不多的(抛开总线冲突等因素)。所以你不管是设置1还是0,只要是第一次设置,那就是比后面的时间长。
如果你是整个系统都不开mmu,cache和write-buff,在所有代码和引用数据都一样的情况下,那循环的每次执行时间是一样的(假设指令预测和外界的因素不考虑)。这就跟最老土的一些机器一样了。
kakarot23 2009-04-05
  • 打赏
  • 举报
回复
谢谢楼上各位高手的分析.
我开发的板子是ARM板, 系统用的是UCLINUX, 不含MMU.
请问下UCLINUX有没有cache这个东东?


如果是cache的问题,
具体要怎么关闭这个功能呢?

而且还有个问题,如果是cache的问题,那么我第一次置1时,会从内存读取,然后放在cache中,这个时候花费的时间会比较长.
但是当第一次置0时, 应该就会直接从cache中取数据,而不需要从内存中取,这个时间会比较短.

可是现在却是第一次置1和置0都比较长.
Oversense 2009-04-05
  • 打赏
  • 举报
回复
看情况了。
morris88 2009-04-05
  • 打赏
  • 举报
回复
51单片机貌似没有cache这个概念吧。

至于volatile,只是指明编译器不要将这个变量优化到寄存器(即用寄存器来表示),是不能回避cache问题的!
fly_new 2009-04-05
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 morris88 的回复:]
引用 16 楼 fly_new 的回复:

简单说吧,第一次运行的时候,你的代码不命中,会去内存取;第一次运行时,可能你的某个变量也不命中,会到内存取。
第二次和后面几次命中,执行时间肯定会小很多。

你查一下存储器的局部性,数据和指令都存在局部性概念。



貌似这个跟CPU体系有很大关系。假如 LZ 采用的是 51单片机,也会这样么?
[/Quote]

LZ的代码所在的内存和引用的数据所在的内存允许cache就会发生。

volatile 不能解决所有问题。一样会被cache。只是编译器一般不会打乱你的代码顺序,也可能会把你安排到内存,但是你的变量有没被cache,你是不知道的。要使内存的数据和cache的数据一致,要莫把这段内存设置成不能cache,要莫你处理器引见架构设计的时候考虑数据同步,还可以每次写了后执行刷cache的指令。。
morris88 2009-04-05
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 fly_new 的回复:]

简单说吧,第一次运行的时候,你的代码不命中,会去内存取;第一次运行时,可能你的某个变量也不命中,会到内存取。
第二次和后面几次命中,执行时间肯定会小很多。

你查一下存储器的局部性,数据和指令都存在局部性概念。

[/Quote]

貌似这个跟CPU体系有很大关系。假如 LZ 采用的是 51单片机,也会这样么?
加载更多回复(15)

70,029

社区成员

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

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