我找到了什么:
我打印golang副本的时间成本,它显示内存复制的第一次很慢。但即使我在不同的内存地址上运行“复制”,第二次也要快得多。
这是我的测试代码:
func TestCopyLoop1x32M(t *testing.T) {
copyLoopSameDst(32*1024*1024, 1)
}
func TestCopyLoopOnex32M(t *testing.T) {
copyLoopSameDst(32*1024*1024, 1)
}
func copyLoopSameDst(size, loops int) {
in := make([]byte, size)
out := make([]byte, size)
rand.Seed(0)
fillRandom(in) // insert random byte into slice
now := time.Now()
for i := 0; i < loops; i++ {
copy(out, in)
}
cost := time.Since(now)
fmt.Println(cost.Seconds() / float64(loops))
}
func TestCopyDiffLoop1x32M(t *testing.T) {
copyLoopDiffDst(32*1024*1024, 1)
}
func copyLoopDiffDst(size, loops int) {
ins := make([][]byte, loops)
outs := make([][]byte, loops)
for i := 0; i < loops; i++ {
out := make([]byte, size)
outs[i] = out
in := make([]byte, size)
rand.Seed(0)
fillRandom(in)
ins[i] = in
}
now := time.Now()
for i := 0; i < loops; i++ {
copy(outs[i], ins[i])
}
cost := time.Since(now)
fmt.Println(cost.Seconds() / float64(loops))
}
结果(在i5-4278U上):
TestCopyLoop1x32M:0.023s
TestCopyLoopOnex32M:0.0038s
TestCopyDiffLoop1x32M:0.0038s
TestCopyLoop1x32M:0.023s
TestCopyLoopOnex32M:0.0038s
TestCopyLoop1x32M:0.023s
TestCopyLoop1x32M:0.023s
我的问题:
他们有不同的内存地址和不同的数据,下一个案例如何从第一个案例中受益?
为什么Result3与Result2不同?他们不是做同样的事吗?
如果我在“copyLoopSameDst”中添加循环,我知道下次因为缓存会更快,但是我的cpu的L3 Cache只有3MB,我无法解释这个巨大的改进
< / LI>为什么“copyLoopDiffDst”会在两个案例后加速?
我的猜测:
指令缓存有助于提高性能,但无法解释question2
cpu缓存超出了我的想象,但无法解释问题2
答案 0 :(得分:0)
经过更多的研究和测试,我想我可以回答部分问题。
缓存在下一个测试用例中工作的原因是Golang(也许其他语言会做同样的事情,因为malloc内存是一个系统调用)内存分配。
当数据很大时,内核将重用刚刚释放的块。
我打印输入和输出[]字节的地址(在Golang中,切片的前8个字节是它的内存地址,所以我写了一个程序集来获取地址):
地址:[0 192 8 32 196 0 0 0] [0 192 8 34 196 0 0 0]
费用:0.019228028
地址:[0 192 8 36 196 0 0 0] [0 192 8 32 196 0 0 0]
费用:0.003770281
地址:[0 192 8 34 196 0 0 0] [0 192 8 32 196 0 0 0]
费用:0.003806502
你会发现程序重用了一些内存地址,因此在下一次复制操作中会发生写入命中。
如果我创建输入/输出功能,重复使用将不会发生,并且速度会慢下来。
但是如果你将块设置得非常小(例如,在32KB以下)你会发现再次加速,尽管内核给你一个新的内存地址。在我看来,主要原因是数据没有对齐64字节,因此下一个循环数据(它的位置在第一个附近)将被捕获到缓存中,同时,第一个循环浪费了很多时间来填充缓存。并且下一个循环可以获取指令缓存和其他数据缓存以运行该函数。当数据很小时,这些小缓存会产生很大的影响。
我仍然感到惊讶,数据大小是我的cpu缓存大小的10倍,但缓存仍然可以帮助很多。无论如何,这是另一个问题。