我是使用 valgrind 和 cachegrind 分析代码的新手,最近我开始使用这些工具来查看我的代码在缓存利用率方面的表现。我发现一个简单的 if 语句似乎几乎每次执行都会导致缓存未命中。例如,我在 Fortran 程序中使用了以下派生类型:
type :: particle
real(pr), dimension(3) :: r = 0.0_pr ! position
real(pr), dimension(3) :: p = 0.0_pr ! momentum
end type particle
type :: rcell ! position cell
integer, dimension(6) :: bpoints = 0 ! cell grid points
integer :: np = 0 ! number of particles in cell
type(particle), dimension(50) :: parts ! particles in cell
end type rcell
type(rcell), dimension(:), allocatable :: rbin ! position space bins
allocate(rbin(100))
此示例表示位置空间中的 100 个单元格,其中最多可以包含 50 个由其位置和动量描述的粒子。该代码使用一个简单的粒子移动器来更新粒子在给定时间步的位置和动量。为了实现这一点,我使用如下循环:
do i = 1, numcells
if (rbin(i)%np == 0) cycle ! skip cells with no particles
...
end do
通过包含 if 语句,我认为当给定单元格中没有粒子时,我将通过循环循环来加速代码。但是,我使用 valgrind 和 cachegrind 工具对我的代码进行了一些分析,发现这个简单的 if 语句几乎总是会导致缓存未命中。--auto=yes
以下是使用 cg_annotate 并启用选项的 if 语句的结果示例:
Ir: 21,600,000
I1mr: 0
ILmr: 0
Dr: 4,320,000
D1mr: 4,319,057
DLmr: 4,318,979
Dw: 0
D1mw: 0
DLmw: 0
几乎每次执行时,这似乎都是缓存未命中。在循环单元格时,我在我的代码中经常这样做,我认为这会导致速度大幅下降。这是使用派生类型的结果吗?有没有办法提高这里的缓存利用率,或者一般来说使用派生类型?
为了完整起见,我使用 gfortran 4.8.3 进行编译并使用以下标志:-g -O3 -ffast-math -mcmodel=medium -fdefault-real-8