Cache Miss对Java程序的影响

在前一篇文章Java的大内存分页支持,曾经谈及Java矩阵乘法程序效率低下的两个原因,Cache Miss和TLB Miss。在那篇文章中,我们通过使用大内存分页,消除了TLB Miss对性能的影响,性能因而提高了60%以上(76秒 -> 45 秒)。但Cache Miss对性能的影响依旧存在。

 

CPU的一级数据缓存(L1 Data Cache)通常采用组相联的方式来缓存数据,数据缓存是以Cache Line为单位进行的,即缓存不命中时,相邻的一组数据将被载入Cache Line,而不仅仅是当前数据。Core 2架构处理器L1 Data Cache是8路组相联的缓存,每个Cache Line大小为64字节,总共是32K字节。所以,为减少Cache Miss的出现,每个程序指令读取的数据最好是相邻的。而在传统的矩阵乘法程序中,却恰恰违背了这一点。

 

 

for (int i = 0; i < 2048; i++)
	for (int j = 0; j < 2048; j++)
		for (int k = 0; k < 2048; k++)
			res[i][j] += mul1[i][k] * mul2[k][j];

 

每次乘法运算中,mul1二维数组所取的值都与上一次乘法中所取的值相距8KB(2048*4)之远。显然,几乎每次乘法运算中都将出现一次Cache Miss。通过改进算法,我们可以保证每次取值都相邻,从而大大减少Cache Miss的可能。

 

 

for (int i = 0; i < 2048; i++)
	for (int k = 0; k < 2048; k++)
		for (int j = 0; j < 2048; j++)
			res[i][j] += mul1[i][k] * mul2[k][j];

 

很简单,只需将循环中J和K的位置调换一下,就能够保证所有的数组(res, mul1, mul2)每次取值都与上一次相邻。最终,程序因为Cache Miss的大大减少而效率大增。改进后的程序,运行时间为13秒,性能比使用大内存页的情况还提高了两倍多(45秒 -> 13秒)。实际上,改进后的程序还带来另外一个影响,即由于读取的数据位置相邻,TLB Miss的频率也大为下降。经测试,同样的程序在大内存页(2M)和普通内存页(4K)的情况下,运行性能是一样的,均耗时13秒。

 

Cache Miss和TLB Miss的解决似乎都很简单,但要如何发现这些问题却不容易,许多Java性能监控工具通常也不能给出相关的分析。接下来的文章,将介绍如何发现这些微妙的Java性能问题。

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值