平滑传感器数据。数组是 readings(nstation, ntime),站点在前,因为数据文件就是这样排布的,其他工具也要读。对站点做一层循环,每个站点调用一次 running_mean:
do i = 1, nstation
call running_mean(readings(i, :), ntime, window, smooth(i, :))
end do
模块里是这样:
subroutine running_mean(x, n, w, y)
integer, intent(in) :: n, w
real(dp), intent(in) :: x(n)
real(dp), intent(out) :: y(n)
规模是 1500 个站点,20000 个采样点,窗口 32。大约耗时 1.9 s,Release,-O2,gfortran 来自 Homebrew,Apple silicon。每个采样点的计算量很小,所以这个速度太慢了。
我复制了一份程序,把数组改成 (ntime, nstation),其他都没动。结果快了好几倍。
性能分析器显示大部分时间花在类似 memmove/memcpy 的调用上,而不是 running_mean 里。我想不通。running_mean 里的循环是按 k 顺序走的,外面只有一层循环。我试过改 -O2 和 CMake 的 profile,没有效果。内存占用看起来也比我预期的高,不过我没测过。
时间到底花在哪了?我能保留 (nstation, ntime) 的布局吗?
从英语翻译·查看原文Smoothing sensor data. Array is readings(nstation, ntime), station first, because the data file is laid out so and other tools read it. One loop over stations, call running_mean for each:
do i = 1, nstation
call running_mean(readings(i, :), ntime, window, smooth(i, :))
end do
and in the module:
subroutine running_mean(x, n, w, y)
integer, intent(in) :: n, w
real(dp), intent(in) :: x(n)
real(dp), intent(out) :: y(n)
Sizes: 1500 stations, 20000 samples, window 32. Takes about 1.9 s, Release, -O2, gfortran from Homebrew, Apple silicon. Arithmetic per sample is tiny, so this is too slow.
I made a copy of the program with the array as (ntime, nstation). Nothing else changed. It ran several times faster.
Profiler shows big share in memmove/memcpy-like calls, not in running_mean. I do not understand this. Loop in running_mean walks k in order, only one loop outside. I tried changing -O2 and the CMake profile, no effect. Memory use also looks higher than I expect, but I did not measure it.
Where does the time really go? Can I keep the (nstation, ntime) layout?