Как улучшить производительность функции, работающей с двумя массивами в ближайшем будущем - PullRequest
7 голосов
/ 08 декабря 2011

У меня есть набор небольшого количества функций.Две функции выполняют математическую операцию наложения (определенную на http://docs.gimp.org/en/gimp-concepts-layer-modes.html,, но немного внизу - просто ищите «наложение», чтобы найти математику) по-разному.Теперь эта операция - то, что Gimp выполняет очень быстро, менее чем за секунду, но я не могу оптимизировать свой код, чтобы получить что-то похожее на удаленно похожее время.

(Мое приложение - это приложение с графическим интерфейсом, чтобы помочья вижу и сравниваю различные комбинации наложения большого количества файлов. Интерфейс слоя Gimp на самом деле делает довольно сложным просто выбрать два изображения для наложения, затем выбрать другое два и т. д.)

Вот код:

(set! *warn-on-reflection* true )

(defn to-8-bit [v]
  (short (* (/ v 65536) 256)))

(defn overlay-sample [base-p over-p]
  (to-8-bit 
    (* (/ base-p 65536) 
       (+ base-p
          (* (/ (* 2 over-p) 65536)
             (- 65536 base-p))))))

(defn overlay-map [^shorts base ^shorts over]
  (let [ovl (time (doall (map overlay-sample ^shorts base ^shorts over)))]
    (time (into-array Short/TYPE ovl))))

(defn overlay-array [base over]
  (let [ovl (time (amap base
                        i
                        r
                        (int (overlay-sample (aget r i)
                                             (aget over i)))))]
    ovl))

overlay-map и overlay-array выполняют одну и ту же операцию разными способами.Я написал и другие версии этой операции.Однако overlay-map, безусловно, самый быстрый из всех, что у меня есть.

base и over, в обеих функциях - это 16-битные целочисленные массивы.Фактический размер каждого составляет 1 276 800 сэмплов (изображение 800 x 532 с 3 сэмплами на пиксель).Конечный результат должен быть одним и тем же массивом, но уменьшенным до 8 бит.

Мои результаты операции (времени) довольно последовательны.overlay-map выполняет фактическую математическую операцию примерно за 16 или 17 секунд, затем тратит еще 5 секунд, копируя полученную последовательность обратно в целочисленный массив.

overlay-array занимает около 111 секунд.

Я много читал об использовании массивов, подсказок типов и т. Д., Но моя операция только с Java-массивом удивительно медленная!amap, aget и т. д. должны были быть быстрыми, но я прочитал код, и нет ничего похожего на оптимизацию скорости, и мои результаты согласуются.Я даже пробовал другие компьютеры и видел примерно такую ​​же разницу.

Теперь, 16-17 секунд, на самом деле довольно болезненно для этого набора данных, но я кеширую результаты, чтобы я мог легко переключатьсяназад и вперед.Эта же операция заняла бы ужасно много времени, если бы я увеличил размер набора данных до чего-то похожего на полноразмерное изображение (4770x3177).И есть и другие операции, которые я тоже хочу делать.

Итак, есть предложения, как это ускорить?Что мне здесь не хватает?

ОБНОВЛЕНИЕ: Я только что сделал весь проект, относящийся к этому коду, общедоступным, чтобы вы могли видеть текущую версию всего скрипта, который я использую для тестов скорости, на https://bitbucket.org/savannidgerinel/hdr-darkroom/src/62a42fcf6a4b/scripts/speed_test.clj.Не стесняйтесь загружать его и пробовать на своем оборудовании, но перед запуском явно измените пути к файлу изображения.

1 Ответ

1 голос
/ 03 января 2012

Поскольку ваши функции являются чисто математическими, вы можете захотеть проверить памятку

(def fast-overlay (memoize overlay-sample))

(time (fast-overlay 1000 2000))
"Elapsed time: 1.279 msecs"
(time (fast-overlay 1000 2000))
"Elapsed time: 0.056 msecs"

Здесь происходит кэширование аргументов в качестве ключа, а возвращаемое значение - это значение.Если значение уже вычислено, возвращается значение, а не выполняемая функция.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...