forked from mia/Aegisub
332 lines
10 KiB
HTML
332 lines
10 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
|
<html>
|
|
<head>
|
|
<title>FFI Library</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
<meta name="Author" content="Mike Pall">
|
|
<meta name="Copyright" content="Copyright (C) 2005-2017, Mike Pall">
|
|
<meta name="Language" content="en">
|
|
<link rel="stylesheet" type="text/css" href="bluequad.css" media="screen">
|
|
<link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print">
|
|
</head>
|
|
<body>
|
|
<div id="site">
|
|
<a href="http://luajit.org"><span>Lua<span id="logo">JIT</span></span></a>
|
|
</div>
|
|
<div id="head">
|
|
<h1>FFI Library</h1>
|
|
</div>
|
|
<div id="nav">
|
|
<ul><li>
|
|
<a href="luajit.html">LuaJIT</a>
|
|
<ul><li>
|
|
<a href="http://luajit.org/download.html">Download <span class="ext">»</span></a>
|
|
</li><li>
|
|
<a href="install.html">Installation</a>
|
|
</li><li>
|
|
<a href="running.html">Running</a>
|
|
</li></ul>
|
|
</li><li>
|
|
<a href="extensions.html">Extensions</a>
|
|
<ul><li>
|
|
<a class="current" href="ext_ffi.html">FFI Library</a>
|
|
<ul><li>
|
|
<a href="ext_ffi_tutorial.html">FFI Tutorial</a>
|
|
</li><li>
|
|
<a href="ext_ffi_api.html">ffi.* API</a>
|
|
</li><li>
|
|
<a href="ext_ffi_semantics.html">FFI Semantics</a>
|
|
</li></ul>
|
|
</li><li>
|
|
<a href="ext_jit.html">jit.* Library</a>
|
|
</li><li>
|
|
<a href="ext_c_api.html">Lua/C API</a>
|
|
</li><li>
|
|
<a href="ext_profiler.html">Profiler</a>
|
|
</li></ul>
|
|
</li><li>
|
|
<a href="status.html">Status</a>
|
|
<ul><li>
|
|
<a href="changes.html">Changes</a>
|
|
</li></ul>
|
|
</li><li>
|
|
<a href="faq.html">FAQ</a>
|
|
</li><li>
|
|
<a href="http://luajit.org/performance.html">Performance <span class="ext">»</span></a>
|
|
</li><li>
|
|
<a href="http://wiki.luajit.org/">Wiki <span class="ext">»</span></a>
|
|
</li><li>
|
|
<a href="http://luajit.org/list.html">Mailing List <span class="ext">»</span></a>
|
|
</li></ul>
|
|
</div>
|
|
<div id="main">
|
|
<p>
|
|
|
|
The FFI library allows <b>calling external C functions</b> and
|
|
<b>using C data structures</b> from pure Lua code.
|
|
|
|
</p>
|
|
<p>
|
|
|
|
The FFI library largely obviates the need to write tedious manual
|
|
Lua/C bindings in C. No need to learn a separate binding language
|
|
— <b>it parses plain C declarations!</b> These can be
|
|
cut-n-pasted from C header files or reference manuals. It's up to
|
|
the task of binding large libraries without the need for dealing with
|
|
fragile binding generators.
|
|
|
|
</p>
|
|
<p>
|
|
The FFI library is tightly integrated into LuaJIT (it's not available
|
|
as a separate module). The code generated by the JIT-compiler for
|
|
accesses to C data structures from Lua code is on par with the
|
|
code a C compiler would generate. Calls to C functions can
|
|
be inlined in JIT-compiled code, unlike calls to functions bound via
|
|
the classic Lua/C API.
|
|
</p>
|
|
<p>
|
|
This page gives a short introduction to the usage of the FFI library.
|
|
<em>Please use the FFI sub-topics in the navigation bar to learn more.</em>
|
|
</p>
|
|
|
|
<h2 id="call">Motivating Example: Calling External C Functions</h2>
|
|
<p>
|
|
It's really easy to call an external C library function:
|
|
</p>
|
|
<pre class="code mark">
|
|
<span class="codemark">①
|
|
②
|
|
|
|
|
|
③</span>local ffi = require("ffi")
|
|
ffi.cdef[[
|
|
<span style="color:#00a000;">int printf(const char *fmt, ...);</span>
|
|
]]
|
|
ffi.C.printf("Hello %s!", "world")
|
|
</pre>
|
|
<p>
|
|
So, let's pick that apart:
|
|
</p>
|
|
<p>
|
|
<span class="mark">①</span> Load the FFI library.
|
|
</p>
|
|
<p>
|
|
<span class="mark">②</span> Add a C declaration
|
|
for the function. The part inside the double-brackets (in green) is
|
|
just standard C syntax.
|
|
</p>
|
|
<p>
|
|
<span class="mark">③</span> Call the named
|
|
C function — Yes, it's that simple!
|
|
</p>
|
|
<p style="font-size: 8pt;">
|
|
Actually, what goes on behind the scenes is far from simple: <span
|
|
style="color:#4040c0;">③</span> makes use of the standard
|
|
C library namespace <tt>ffi.C</tt>. Indexing this namespace with
|
|
a symbol name (<tt>"printf"</tt>) automatically binds it to the
|
|
standard C library. The result is a special kind of object which,
|
|
when called, runs the <tt>printf</tt> function. The arguments passed
|
|
to this function are automatically converted from Lua objects to the
|
|
corresponding C types.
|
|
</p>
|
|
<p>
|
|
Ok, so maybe the use of <tt>printf()</tt> wasn't such a spectacular
|
|
example. You could have done that with <tt>io.write()</tt> and
|
|
<tt>string.format()</tt>, too. But you get the idea ...
|
|
</p>
|
|
<p>
|
|
So here's something to pop up a message box on Windows:
|
|
</p>
|
|
<pre class="code">
|
|
local ffi = require("ffi")
|
|
ffi.cdef[[
|
|
<span style="color:#00a000;">int MessageBoxA(void *w, const char *txt, const char *cap, int type);</span>
|
|
]]
|
|
ffi.C.MessageBoxA(nil, "Hello world!", "Test", 0)
|
|
</pre>
|
|
<p>
|
|
Bing! Again, that was far too easy, no?
|
|
</p>
|
|
<p style="font-size: 8pt;">
|
|
Compare this with the effort required to bind that function using the
|
|
classic Lua/C API: create an extra C file, add a C function
|
|
that retrieves and checks the argument types passed from Lua and calls
|
|
the actual C function, add a list of module functions and their
|
|
names, add a <tt>luaopen_*</tt> function and register all module
|
|
functions, compile and link it into a shared library (DLL), move it to
|
|
the proper path, add Lua code that loads the module aaaand ... finally
|
|
call the binding function. Phew!
|
|
</p>
|
|
|
|
<h2 id="cdata">Motivating Example: Using C Data Structures</h2>
|
|
<p>
|
|
The FFI library allows you to create and access C data
|
|
structures. Of course the main use for this is for interfacing with
|
|
C functions. But they can be used stand-alone, too.
|
|
</p>
|
|
<p>
|
|
Lua is built upon high-level data types. They are flexible, extensible
|
|
and dynamic. That's why we all love Lua so much. Alas, this can be
|
|
inefficient for certain tasks, where you'd really want a low-level
|
|
data type. E.g. a large array of a fixed structure needs to be
|
|
implemented with a big table holding lots of tiny tables. This imposes
|
|
both a substantial memory overhead as well as a performance overhead.
|
|
</p>
|
|
<p>
|
|
Here's a sketch of a library that operates on color images plus a
|
|
simple benchmark. First, the plain Lua version:
|
|
</p>
|
|
<pre class="code">
|
|
local floor = math.floor
|
|
|
|
local function image_ramp_green(n)
|
|
local img = {}
|
|
local f = 255/(n-1)
|
|
for i=1,n do
|
|
img[i] = { red = 0, green = floor((i-1)*f), blue = 0, alpha = 255 }
|
|
end
|
|
return img
|
|
end
|
|
|
|
local function image_to_grey(img, n)
|
|
for i=1,n do
|
|
local y = floor(0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue)
|
|
img[i].red = y; img[i].green = y; img[i].blue = y
|
|
end
|
|
end
|
|
|
|
local N = 400*400
|
|
local img = image_ramp_green(N)
|
|
for i=1,1000 do
|
|
image_to_grey(img, N)
|
|
end
|
|
</pre>
|
|
<p>
|
|
This creates a table with 160.000 pixels, each of which is a table
|
|
holding four number values in the range of 0-255. First an image with
|
|
a green ramp is created (1D for simplicity), then the image is
|
|
converted to greyscale 1000 times. Yes, that's silly, but I was in
|
|
need of a simple example ...
|
|
</p>
|
|
<p>
|
|
And here's the FFI version. The modified parts have been marked in
|
|
bold:
|
|
</p>
|
|
<pre class="code mark">
|
|
<span class="codemark">①
|
|
|
|
|
|
|
|
|
|
|
|
②
|
|
|
|
③
|
|
④
|
|
|
|
|
|
|
|
|
|
|
|
|
|
③
|
|
⑤</span><b>local ffi = require("ffi")
|
|
ffi.cdef[[
|
|
</b><span style="color:#00a000;">typedef struct { uint8_t red, green, blue, alpha; } rgba_pixel;</span><b>
|
|
]]</b>
|
|
|
|
local function image_ramp_green(n)
|
|
<b>local img = ffi.new("rgba_pixel[?]", n)</b>
|
|
local f = 255/(n-1)
|
|
for i=<b>0,n-1</b> do
|
|
<b>img[i].green = i*f</b>
|
|
<b>img[i].alpha = 255</b>
|
|
end
|
|
return img
|
|
end
|
|
|
|
local function image_to_grey(img, n)
|
|
for i=<b>0,n-1</b> do
|
|
local y = <b>0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue</b>
|
|
img[i].red = y; img[i].green = y; img[i].blue = y
|
|
end
|
|
end
|
|
|
|
local N = 400*400
|
|
local img = image_ramp_green(N)
|
|
for i=1,1000 do
|
|
image_to_grey(img, N)
|
|
end
|
|
</pre>
|
|
<p>
|
|
Ok, so that wasn't too difficult:
|
|
</p>
|
|
<p>
|
|
<span class="mark">①</span> First, load the FFI
|
|
library and declare the low-level data type. Here we choose a
|
|
<tt>struct</tt> which holds four byte fields, one for each component
|
|
of a 4x8 bit RGBA pixel.
|
|
</p>
|
|
<p>
|
|
<span class="mark">②</span> Creating the data
|
|
structure with <tt>ffi.new()</tt> is straightforward — the
|
|
<tt>'?'</tt> is a placeholder for the number of elements of a
|
|
variable-length array.
|
|
</p>
|
|
<p>
|
|
<span class="mark">③</span> C arrays are
|
|
zero-based, so the indexes have to run from <tt>0</tt> to
|
|
<tt>n-1</tt>. One might want to allocate one more element instead to
|
|
simplify converting legacy code.
|
|
</p>
|
|
<p>
|
|
<span class="mark">④</span> Since <tt>ffi.new()</tt>
|
|
zero-fills the array by default, we only need to set the green and the
|
|
alpha fields.
|
|
</p>
|
|
<p>
|
|
<span class="mark">⑤</span> The calls to
|
|
<tt>math.floor()</tt> can be omitted here, because floating-point
|
|
numbers are already truncated towards zero when converting them to an
|
|
integer. This happens implicitly when the number is stored in the
|
|
fields of each pixel.
|
|
</p>
|
|
<p>
|
|
Now let's have a look at the impact of the changes: first, memory
|
|
consumption for the image is down from 22 Megabytes to
|
|
640 Kilobytes (400*400*4 bytes). That's a factor of 35x less! So,
|
|
yes, tables do have a noticeable overhead. BTW: The original program
|
|
would consume 40 Megabytes in plain Lua (on x64).
|
|
</p>
|
|
<p>
|
|
Next, performance: the pure Lua version runs in 9.57 seconds (52.9
|
|
seconds with the Lua interpreter) and the FFI version runs in 0.48
|
|
seconds on my machine (YMMV). That's a factor of 20x faster (110x
|
|
faster than the Lua interpreter).
|
|
</p>
|
|
<p style="font-size: 8pt;">
|
|
The avid reader may notice that converting the pure Lua version over
|
|
to use array indexes for the colors (<tt>[1]</tt> instead of
|
|
<tt>.red</tt>, <tt>[2]</tt> instead of <tt>.green</tt> etc.) ought to
|
|
be more compact and faster. This is certainly true (by a factor of
|
|
~1.7x). Switching to a struct-of-arrays would help, too.
|
|
</p>
|
|
<p style="font-size: 8pt;">
|
|
However the resulting code would be less idiomatic and rather
|
|
error-prone. And it still doesn't get even close to the performance of
|
|
the FFI version of the code. Also, high-level data structures cannot
|
|
be easily passed to other C functions, especially I/O functions,
|
|
without undue conversion penalties.
|
|
</p>
|
|
<br class="flush">
|
|
</div>
|
|
<div id="foot">
|
|
<hr class="hide">
|
|
Copyright © 2005-2017 Mike Pall
|
|
<span class="noprint">
|
|
·
|
|
<a href="contact.html">Contact</a>
|
|
</span>
|
|
</div>
|
|
</body>
|
|
</html>
|