Что такое clojure.lang.Var.getRawRoot и почему он называется? - PullRequest
4 голосов
/ 01 марта 2012

Я писал функцию, которая проверяет, могут ли две точки видеть друг друга на двумерной сетке для алгоритма поиска пути. После профилирования кода я обнаружил, что он проводит 60% своего времени в clojure.lang.Var.getRawRoot (). Почему эта функция занимает так много времени и я могу ее оптимизировать?

(defn line-of-sight-helper [^Maze maze [x0 y0] [x1 y1]]
  "Determines if there is a line of sight from [x0 y0] to [x1 y1] in maze."
  (let [dy (int (- y1 y0))
        dx (int (- x1 x0))
        sy (int (if (neg? dy) -1 1))
        sx (int (if (neg? dx) -1 1))
        dy (int (* sy dy))
        dx (int (* sx dx))
        bias-x (int (if (pos? sx) 0 -1))
        bias-y (int (if (pos? sy) 0 -1))
        x-long (boolean (>= dx dy))
        [u0 u1 du su bias-u] (if x-long
                               [(int x0) (int x1) dx sx bias-x]
                               [(int y0) (int y1) dy sy bias-y])
        [v0 v1 dv sv bias-v] (if x-long
                               [(int y0) (int y1) dy sy bias-y]
                               [(int x0) (int x1) dx sx bias-x])
        grid (if x-long
               #(blocked? maze [%1 %2])
               #(blocked? maze [%2 %1]))]
    (loop [u0 u0
             v0 v0
             error (int 0)]
      (if (not= u0 u1)
        (let [error (+ error dv)
              too-much-error? (> error du)
              next-blocked? (grid (+ u0 bias-u) (+ v0 bias-v))
              branch3 (and too-much-error? (not next-blocked?))
              v0 (int (if branch3
                        (+ v0 sv)
                        v0))
              error (if branch3
                      (int (- error du))
                      (int error))]
          (if (and too-much-error? next-blocked?)
            false
            (if (and (not (zero? error)) next-blocked?)
              false
              (if (and (zero? dv)
                       (grid (+ u0 bias-u)
                             v0)
                       (grid (+ u0 bias-u)
                             (- v0 1)))
                false
                (recur (int (+ u0 su))
                       v0
                       error)))))
       true))))

1 Ответ

4 голосов
/ 01 марта 2012

Что происходит с getVarRoot?

Я действительно удивлен, что любая программа тратит много времени в getRawRoot ().Все, что делает этот метод, это возвращает одно поле из Var, согласно источнику в clojure.lang.Var :

final public Object getRawRoot(){
    return root;
}

Кроме того, это небольшой финальный метод, поэтому он должен бытьвстроенный любым современным JIT-компилятором ..... в основном любые вызовы getRawRoot должны быть безумно быстрыми.

Я подозреваю, что с вашим профилировщиком происходит что-то странное: возможно, это добавляет отладочный код в getRawRoot (), которыйзанимает много времени.Поэтому я бы посоветовал сравнить ваш код без профилировщика и с помощью java -server, чтобы увидеть, как на самом деле работает эта функция.

Другие советы по производительности

Убедитесь, что вы используете Clojure 1.3 + , поскольку есть некоторые оптимизации для доступа к var, которые вы почти наверняка захотитевоспользуйтесь этим видом низкоуровневого кода.

Если бы я предположил, что на самом деле является самым большим узким местом в этом коде, то я думаю, что это будет тот факт, что функция сетки #(blocked? maze [%1 %2]) создает новый вектор каждый раз, когда он вызывается для проверки квадрата сетки.Было бы намного лучше, если бы вы могли реорганизовать это так, чтобы он не нуждался в векторе, и тогда вы могли бы просто использовать #(blocked? maze %1 %2) напрямую.Создание новых коллекций обходится дороже по сравнению с простыми математическими операциями, поэтому вы хотите делать это экономно во внутренних циклах.

Вы также хотите убедиться, что вы используете примитивные операции везде, где это возможно, и с(set! *unchecked-math* true).Убедитесь, что вы объявили свои локальные объекты как примитивы, поэтому вам понадобится, например, (let [u0 (int (if x-long x0 y0)) .....] .....) и т. Д. Основная причина сделать это - избежать накладных расходов примитивов в штучной упаковке, что опять-таки подразумевает распределение памяти, которое вы хотите избежать во внутренних циклах.

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