Re: Array performance with 2.0.0-beta10 versus git HEAD

  • From: Peter Colberg <peter@xxxxxxxxxxx>
  • To: luajit@xxxxxxxxxxxxx
  • Date: Tue, 28 Aug 2012 16:16:26 -0400

On Tue, Aug 28, 2012 at 07:27:36PM +0200, Mike Pall wrote:
> Anyway, I'm sure there are plenty of examples for FFI vector and
> array classes out there, that don't suffer from this problem. E.g.
> properly unrolled arithmetic metamethods, no 1-based indexing,
> structs instead of tables as wrappers, bounds checks dynamically
> compiled only for debugging, etc.

Thanks for the pointer to use a struct. This solves the problem of
adding attributes such as .size without degrading the performance of
the __index metamethod. Further the array can be passed directly to
C functions, and the malloc'ed pointer is kept alive as an upvalue
of the function passed to ffi.gc().

The plan is to implement core algorithms of a molecular simulation
using OpenCL (on the GPU) or C (on the host) code, therefore the
convenience of bound checking and 1-based indexing in the LuaJIT
part should outweigh the performance penalty.

Peter

-- array.lua
local ffi = require("ffi")

ffi.cdef[[
void *malloc(size_t size);
void free(void *ptr);
typedef struct vec3_array { vec3 *data; size_t size; } vec3_array;
]]

local mt = {}

function mt:__len()
    return tonumber(self.size)
end

function mt:__index(i)
    if i < 1 or i > self.size then
        return error("index out of bounds")
    end
    return self.data[i - 1]
end

function mt:__newindex(i, v)
    if i < 1 or i > self.size then
        return error("index out of bounds")
    end
    self.data[i - 1] = v
end

local vec3_array = ffi.metatype("vec3_array", mt)

local function array_new(self, size)
    local nbyte = size * ffi.sizeof("vec3")
    local data = ffi.C.malloc(nbyte)
    if data == nil then
        return error("out of memory")
    end
    local array = vec3_array(data, size)
    ffi.gc(array, function() ffi.C.free(data) end)
    return array
end

return setmetatable({}, {__call = array_new})

Other related posts: