openlang

running_mean이 느려요, 시간이 산술 연산이 아니라 memmove에 쓰여요

센서 데이터를 평활화하고 있어요. 배열은 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) 배치를 그대로 유지할 수 있을까요?

영어에서 번역원문 보기

이어지는 대화 1

서로의 근거를 따라
  1. 고유 링크

    복사 때문이에요. readings(i, :)는 stride가 있는 슬라이스인데 explicit-shape x(n)은 연속된 메모리가 필요해서, gfortran이 호출할 때마다 임시 배열에 패킹하고 끝나면 y를 다시 복사해 넣어요. assumed-shape x(:), y(:)로 해 보세요. -Warray-temporaries로 확인할 수 있어요.

    영어에서 번역원문 보기

같은 질문의 다른 갈래

  1. 단순한 루프가 너무 느려요, gfortran, 200000 x 64 배열

    작은 보정 도구인데 코드는 아래에 있어요. 출력은 맞는데 너무 느려요. detrend+clip은 몇 초씩 걸리고, rms도 원래보다 느려요. 요소당 곱셈 한 번, 덧셈 한 번뿐인데도요. -O3랑 -march=native를 써…

    답글 2최근 활동 fortran
  2. 어느 빌드 시간을 말하는 건가

    크레이트 분리 이야기는 늘 누군가 빌드 시간 하나를 올리는 것으로 끝난다. 숫자는 두 개고, 움직이는 방향도 다르다. 클린 빌드는 빈 target에서 시작하는 전체 빌드다. 크레이트를 나누면 이쪽은 오히려 조금 나빠질 수 있…

    답글 2최근 활동 rust
  3. 이 큐에 개수를 캐시하는 필드가 필요할까요?

    호출자가 이 큐에 묻는 건 List.length items > 8 하나뿐이고, 그걸 계속 반복해서 물어요. 큐는 불변 OCaml 리스트 하나이고, 갱신할 때마다 새 큐를 돌려줘요. 선택지는 두 가지예요. 정확한 개수를 들고…

    답글 2최근 활동 ocaml