【问题标题】:Improve performance of point cloud bounding box computation in Clojure提高 Clojure 中点云边界框计算的性能
【发布时间】:2018-03-22 07:51:58
【问题描述】:

我正在 Clojure 中计算 3d 点云的边界框。点云表示为 Java 原始浮点数组,点云中的每个点都使用 4 个浮点数存储,其中最后一个浮点数未使用。像这样:

[x0 y0 z0 u0  x1 y1 z1 u1 .... ]

点云的大小为19200,即阵列中4*19200个浮点数。

其中一些值可能不是有限的(它们是无限的或 NaN)。因此,任何包含非有限值的点都应完全排除在计算之外。我已经在 J​​ava 和 Clojure 中实现了这种计算,但由于某种原因,Clojure 版本仍然慢了大约 4 到 5 倍。

Clojure 代码如下所示:

(defn good-compute-bbox [^floats data]
  (let [n (alength data)]
    (loop [i (int 0)
           minx (float (aget data 0))
           maxx (float (aget data 0))
           miny (float (aget data 1))
           maxy (float (aget data 1))
           minz (float (aget data 2))
           maxz (float (aget data 2))]
      (if (< i n)
        (let [x (float (aget data (unchecked-add i 0)))
              y (float (aget data (unchecked-add i 1)))
              z (float (aget data (unchecked-add i 2)))]
          (if (and (Float/isFinite x)
                   (Float/isFinite y)
                   (Float/isFinite z))
            (recur (unchecked-add-int i (int 4))
                   (min minx x)
                   (max maxx x)
                   (min miny y)
                   (max maxy y)
                   (min minz z)
                   (max maxz z))
            (recur (unchecked-add-int i (int 4))
                   minx
                   maxx
                   miny
                   maxy
                   minz
                   maxz
                   ))
          )
        [minx maxx miny maxy minz maxz]))))

这就是 Java 代码的样子:

public class BBox {

    public static float[] computeBBox(float[] data) {
        long n = data.length;
        float[] result = new float[6];

        float minx = data[0];
        float maxx = data[0];
        float miny = data[1];
        float maxy = data[1];
        float minz = data[2];
        float maxz = data[2];
        for (int i = 0; i < n; i += 4) {
            float x = data[i + 0];
            float y = data[i + 1];
            float z = data[i + 2];
            if (java.lang.Float.isFinite(x) &&
                java.lang.Float.isFinite(y) &&
                java.lang.Float.isFinite(z)) {

                minx = x < minx? x : minx;
                maxx = x > maxx? x : maxx;

                miny = y < miny? y : miny;
                maxy = y > maxy? y : maxy;

                minz = z < minz? z : minz;
                maxz = z > maxz? z : maxz;
            }
        }

        result[0] = minx;
        result[1] = maxx;
        result[2] = miny;
        result[3] = maxy;
        result[4] = minz;
        result[5] = maxz;

        return result;
    }
};

我的问题是:我可以对我的 Clojure 代码进行哪些更改以使其运行速度与 Java 代码一样快?如果您测试了您的代码并测量了加速,则可以加分。

如果你想重现实验和published on my Github repository here

【问题讨论】:

    标签: performance clojure geometry clojure-java-interop


    【解决方案1】:

    这里的罪魁祸首——正如我从你已经怀疑的代码中看到的那样——是min。它适用于各种类型,而且速度不是那么快。

    您可以通过使用 Apache 的 commons fast math 获得 10% 以内的 Java:

    (defn primitive-compute-bbox-new [^floats data]
      (let [n (alength data)]
        (loop [i (int 0)
               minx (aget data 0)
               maxx (aget data 0)
               miny (aget data 1)
               maxy (aget data 1)
               minz (aget data 2)
               maxz (aget data 2)]
          (if (< i n)
            (let [x (aget data (unchecked-add i 0))
                  y (aget data (unchecked-add i 1))
                  z (aget data (unchecked-add i 2))]
              (if (and (Float/isFinite x)
                       (Float/isFinite y)
                       (Float/isFinite z))
                (recur (unchecked-add-int i 4)
                       (FastMath/min (float minx) x)
                       (FastMath/max (float maxx) x)
                       (FastMath/min (float miny) y)
                       (FastMath/max (float maxy) y)
                       (FastMath/min (float minz) z)
                       (FastMath/max (float maxz) z))
                (recur (unchecked-add-int i 4)
                       minx
                       maxx
                       miny
                       maxy
                       minz
                       maxz)))
            [minx maxx miny maxy minz maxz]))))
    

    部门:

    [org.apache.commons/commons-math3 "3.6.1"]
    

    【讨论】:

    • 非常感谢您抽出宝贵时间回答这个问题。我将您的答案与此提交合并:github.com/jonasseglare/pc-test/commit/…。但是,我没有观察到任何显着的性能改进,使用我添加的基准函数(运行基准)。但我不知道,这当然可能是我的基准测试在某种程度上存在缺陷。还是谢谢。
    • 您是否多次运行基准测试功能?第一次运行不具有代表性。当我反复运行您的基准代码时,上述版本在 Java 版本的 5-10% 范围内。
    • 我确实运行了几次,但它似乎稳定在 java-version "Elapsed time: 20.761929 ms" good-compute-bbox "Elapsed time: 80.856727 ms" original-compute-bbox-new “经过的时间:99.636311 毫秒”但是可能有很多原因导致您的差异较小……例如 JDK 版本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-08
    • 2011-04-10
    • 1970-01-01
    • 2022-12-12
    • 1970-01-01
    • 2023-01-20
    • 2013-05-16
    相关资源
    最近更新 更多