Как повысить производительность функции, которая работает с двумя массивами в clojure

У меня есть набор небольшое количество функций. Две функции выполняют операцию математического наложения (определенную на 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 и более в обеих функциях представляют собой массивы 16-битных целых чисел. Фактический размер каждого составляет 1 276 800 сэмплов (изображение 800 x 532 с 3 сэмплами на пиксель). Конечным результатом должен быть один такой же массив, но уменьшенный до 8 бит.

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

оверлей-массив занимает около 111 секунд.

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

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

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

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

7
задан Savanni D'Gerinel 9 December 2011 в 15:54
поделиться