123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- <!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-2012, 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></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-2012 Mike Pall
- <span class="noprint">
- ·
- <a href="contact.html">Contact</a>
- </span>
- </div>
- </body>
- </html>
|