You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Fortran列主序数组访问性能异常变慢的原因排查

Fortran列主序访问反而更慢的原因分析

结合你的测试场景和结果,核心问题出在循环顺序与内存存储布局的不匹配,以及由此引发的缓存命中率、内存复制开销问题,具体拆解如下:

1. 循环嵌套顺序与列主序存储的错位导致缓存命中率暴跌

Fortran的列主序意味着多维数组的列元素连续存储:对于array_2d(sub_len, data_len),内存中先存储第1列的sub_len个元素(array_2d(1,1), array_2d(2,1), ..., array_2d(sub_len,1)),再存储第2列,以此类推。

你的计算逻辑是先循环数据集(1:5),再循环数据长度(1:data_len),即访问array_2d(i, j)(i为数据集索引,j为元素索引)。此时:

  • 当sub_len远大于5时,array_2d(i,j)和array_2d(i,j+1)在内存中的地址间隔为sub_len * 元素字节数(比如float类型就是sub_len*4)。当sub_len=1000时,间隔达到4000字节,远超CPU缓存行(通常64字节),每次访问都会触发缓存失效,需要从主存读取数据,性能急剧下降。
  • 而你所谓的“行主序访问”(array_2d(data_len, sub_len)),实际是将数据集索引放在列维度:访问array_2d(j, i)时,j从1到data_len是连续遍历同一列的元素,内存地址连续,缓存命中率接近100%,CPU缓存预取器也能高效工作,大幅降低内存访问延迟。

2. 数据收集阶段的内存复制开销差异

你需要将5个一维数组存入二维数组:

  • 列主序布局下,array_2d(i,:) = data_i是将一维数组复制到二维数组的行,但行元素在内存中是分散在不同列的(每个元素间隔sub_len个位置),属于随机内存写入,开销远大于连续写入。
  • 行主序布局下,array_2d(:,i) = data_i是将一维数组复制到二维数组的列,列元素连续存储,属于连续内存写入,CPU可以用SIMD指令批量处理,复制速度更快。这也是你观察到“数据获取部分行主序更优”的直接原因。

3. 补充测试结果的对应解释

  • 当数据集数量等于sub_len时,求和部分列主序更快:此时如果求和循环改为先列后行(j从1到data_len,i从1到sub_len),访问array_2d(i,j)是连续遍历列元素,缓存命中率高,所以求和性能提升。但数据收集阶段的随机写入开销仍存在,整体性能还是被行主序拉开。
  • 初始化数组后列主序性能提升:初始化操作会将数组整体加载到CPU缓存中,暂时掩盖了缓存失效的问题,但后续循环的大跨度内存访问还是会不断触发缓存未命中,因此仍慢于行主序。

优化建议

  • 调整数组维度顺序:将数据集索引放在列维度(即array_2d(data_len, sub_len)),保持循环顺序与存储布局匹配,确保连续内存访问。
  • 调整循环嵌套顺序:如果必须保留当前数组维度,将循环改为先data_len后数据集(j从1到data_len,i从1到5),这样访问array_2d(i,j)时是连续遍历列元素,利用列主序的优势。

内容的提问来源于stack exchange,提问作者Swari du

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:48:26