clojure

Clojure implementation about five times slower than Java implementation


This is the Java code:

public static FloatBuffer createInterleavedVertexBuffer(AIMesh mesh) {
    FloatBuffer buffer = BufferUtils.createFloatBuffer(mesh.mNumVertices() * 8);
    for (int i = 0; i < mesh.mNumVertices(); i++) {
        var vertex = mesh.mVertices().get(i);
        buffer.put(vertex.x());
        buffer.put(vertex.y());
        buffer.put(vertex.z());

        var normal = mesh.mNormals().get(i);
        buffer.put(normal.x());
        buffer.put(normal.y());
        buffer.put(normal.z());

        var texCoords = mesh.mTextureCoords(0).get(i);
        buffer.put(texCoords.x());
        buffer.put(texCoords.y());
    }
    return buffer.flip();
}

And this is (as far as I can tell) equivalent Clojure code:

(defn create-vertex-buffer
  [mesh]
  (let [buffer (BufferUtils/createFloatBuffer (* (.mNumVertices mesh) 8))]
    (doseq [index (range (.mNumVertices mesh))]
      (let [vertex (.get (.mVertices mesh) index)
            normal (.get (.mNormals mesh) index)
            tex-coords (.get (.mTextureCoords mesh 0) index)]
        (.put buffer (.x vertex))
        (.put buffer (.y vertex))
        (.put buffer (.z vertex))
        (.put buffer (.x normal))
        (.put buffer (.y normal))
        (.put buffer (.z normal))
        (.put buffer (.x tex-coords))
        (.put buffer (.y tex-coords))))
    (.flip buffer)))

However, the Clojure version runs about five times longer than the Java version.

Why is this?

Is there a way to improve the performance of the Clojure version?


Solution

  • Explicit type hinting might accelerate the execution:

    (import [java.nio FloatBuffer]
            [org.lwjgl.assimp AIMesh AIVector3D]
            [org.lwjgl.system BufferUtils])
    
    (defn create-vertex-buffer-optimized
      [^AIMesh mesh]
      (let [num-vertices (.mNumVertices mesh)
            ^FloatBuffer buffer (BufferUtils/createFloatBuffer (* num-vertices 8))]
        (dotimes [index num-vertices]
          (let [^AIVector3D vertex   (.get (.mVertices mesh) index)
                ^AIVector3D normal   (.get (.mNormals mesh) index)
                ^AIVector3D tex-coords (.get (.mTextureCoords mesh 0) index)]
            (.put buffer (.x vertex))
            (.put buffer (.y vertex))
            (.put buffer (.z vertex))
            (.put buffer (.x normal))
            (.put buffer (.y normal))
            (.put buffer (.z normal))
            (.put buffer (.x tex-coords))
            (.put buffer (.y tex-coords))))
        (.flip buffer)))