센서 데이터를 평활화하고 있어요. 배열은 readings(nstation, ntime)이고, station이 먼저예요. 데이터 파일이 그렇게 배치돼 있고 다른 도구들도 읽기 때문이에요. station에 대해 루프를 한 번 돌면서 각각 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)
크기는 station 1500개, 샘플 20000개, window 32예요. Release, -O2, Homebrew의 gfortran, Apple silicon에서 1.9초쯤 걸려요. 샘플당 산술은 아주 작아서 이건 너무 느려요.
배열을 (ntime, nstation)으로 바꾼 복사본 프로그램을 만들었어요. 다른 건 하나도 안 바꿨고요. 몇 배 더 빠르게 돌았어요.
프로파일러에서는 running_mean이 아니라 memmove/memcpy 비슷한 호출이 큰 비중을 차지해요. 이해가 안 돼요. running_mean 안의 루프는 k를 순서대로 돌고, 바깥에는 루프가 하나뿐이에요. -O2와 CMake 프로파일을 바꿔 봤는데 효과가 없었어요. 메모리 사용량도 예상보다 높아 보이는데, 재 보지는 않았어요.
시간이 실제로 어디에 쓰이는 걸까요? (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?