1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
|
<!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>
|