Chinaunix首页 | 论坛 | 博客
  • 博客访问: 10799
  • 博文数量: 7
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-03 01:26
文章分类

全部博文(7)

文章存档

2013年(7)

我的朋友

分类: 架构设计与优化

2013-11-23 14:39:35

对于只是实现简单功能的c语言程序,不用考虑代码reorder问题。
现在才发现原来在编译程序的时候,通过gcc -O0来避免编译时,编译器将不会对指令重排。但是
这样仍然无法避免在运行的时候CPU对指令进行重排。所以使用内存屏障是非常重要的,也是无法避免的。
这里我有一个疑问,是否在java中也会遇到指令重排的问题呢?
上面是对指令重排问题的一点探讨,下面对CPU cache进行分析。
下面的这个链接里面 讲述了如何用c语言观察CPU 的cache行为:对于**的阻拦,最好的方法就是通过在线代理服务器的方式访问入口 

第一个程序

点击(此处)折叠或打开

  1. int[] arr = new int[64 * 1024 * 1024];

  2. // Loop 1
  3. for (int i = 0; i < arr.Length; i++) arr[i] *= 3;

  4. // Loop 2
  5. for (int i = 0; i < arr.Length; i += 16) arr[i] *= 3;
Loop1与Loop2的执行时间是几乎相同的,CPU取内存中的数据都是以Cache Liine的方式取,大小为64Byte。由于顺序访问,访问到同一cache line的速度非常快,几乎可以忽略不计,所以上面的两个Loop的执行时间大体相同。

第二个程序

点击(此处)折叠或打开

  1. for (int i = 0; i < arr.Length; i += K) arr[i] *= 3;


前面一段访问时间都是大体相同,因为都在一个cacheline里面,而后由于k的增大,循环次数明显变少,所以时间会越来越小。

程序三

点击(此处)折叠或打开

  1. int steps = 64 * 1024 * 1024; // Arbitrary number of steps 
  2. int lengthMod = arr.Length - 1;
  3. for (int i = 0; i < steps; i++)
  4. {
  5.     arr[(i * 16) & lengthMod]++; // (x & lengthMod) is equal to (x % arr.Length) }


这里面,L1 cache的大小为32KB,L2的大小为4M,所以可以看到当数组的大小逐渐增加时,每个元素的平均访问时间会越来越大,因为L1Cache不住就会访问L2Cache,以此类推。


程序四:
private static int[] s_counter = new int[1024]; private void UpdateCounter(int position)
{ for (int j = 0; j < 100000000; j++)
    {
        s_counter[position] = s_counter[position] + 3;
    }
}
程序四是为测试Cache的一致性而设计的,当CacheLine里面的某一个元素被修改了,那么对应内存地址的整行cache-line就会失效。
对于多核而言,其他的core里面的数据也会失效。这样会降低cache的失效率。作者测试参数为0,1,2,3为参数的时候,运行四个不同的线程进行测试,发现花费了4.3s。如果参数为16,32,48,测试的结果为0.28s。
因为后面的测试,这些数据都不是在同一个cache line里面的,所以不会造成cache miss而导致的多个核心之间会相互影响。
阅读(472) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~