openlang

running_mean тормозит, время уходит на memmove, а не на арифметику

Сглаживаю данные датчиков. Массив 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 с, Release, -O2, gfortran из Homebrew, Apple silicon. Арифметики на отсчёт совсем немного, так что это слишком медленно.

Я сделал копию программы с массивом (ntime, nstation). Больше ничего не менял. Работает в несколько раз быстрее.

Профайлер показывает большую долю в вызовах вроде memmove/memcpy, а не в running_mean. Я этого не понимаю. Цикл в running_mean идёт по k по порядку, снаружи только один цикл. Пробовал менять -O2 и профиль CMake, без эффекта. Расход памяти тоже выглядит выше, чем я ожидаю, но я его не измерял.

Куда на самом деле уходит время? Можно ли оставить раскладку (nstation, ntime)?

Переведено с английскогоПоказать оригинал

Разговор продолжается 1

Следуя доводам
  1. Ссылка на ответ

    Это копирование. readings(i, :) идёт с шагом, а явный размер x(n) требует непрерывной памяти, поэтому gfortran на каждый вызов упаковывает временный массив и потом копирует y обратно. Попробуйте assumed-shape x(:), y(:). -Warray-temporaries это покажет.

    Переведено с английскогоПоказать оригинал

Другие стороны того же вопроса

  1. простые циклы очень медленные, gfortran, массив 200000 x 64

    Небольшая утилита для калибровки, код ниже. Результат правильный, но слишком медленно. detrend+clip занимает несколько секунд…

    Ответы 2Последняя активность fortran
  2. Какое время сборки вы приводите?

    Каждая тема про разбиение крейтов заканчивается тем, что кто-то выкладывает одно время сборки. Чисел два, и меняются они в ра…

    Ответы 2Последняя активность rust
  3. Нужен ли этой очереди сохранённый счётчик?

    Вызывающий код спрашивает у этой очереди только List.length items > 8, зато спрашивает постоянно. Очередь представлена одним…

    Ответы 2Последняя активность ocaml