diff options
| author | Mike Pall <mike> | 2011-01-20 22:14:17 +0100 |
|---|---|---|
| committer | Mike Pall <mike> | 2011-01-20 22:14:17 +0100 |
| commit | e985aeda84d8af63c4bfaa176c3312dfb2f7f230 (patch) | |
| tree | 8a68df0aac6779db0972bb9dc07fbbe0c7629bc7 /doc/ext_ffi.html | |
| parent | 8396c3cdbc26e08fdf9dea204efb641dd6ad1f91 (diff) | |
| download | luajit-e985aeda84d8af63c4bfaa176c3312dfb2f7f230.tar.gz luajit-e985aeda84d8af63c4bfaa176c3312dfb2f7f230.tar.bz2 luajit-e985aeda84d8af63c4bfaa176c3312dfb2f7f230.zip | |
FFI: Add preliminary FFI documentation (still incomplete).
Diffstat (limited to 'doc/ext_ffi.html')
| -rw-r--r-- | doc/ext_ffi.html | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/doc/ext_ffi.html b/doc/ext_ffi.html new file mode 100644 index 00000000..e8e2a62b --- /dev/null +++ b/doc/ext_ffi.html | |||
| @@ -0,0 +1,280 @@ | |||
| 1 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> | ||
| 2 | <html> | ||
| 3 | <head> | ||
| 4 | <title>FFI Library</title> | ||
| 5 | <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> | ||
| 6 | <meta name="Author" content="Mike Pall"> | ||
| 7 | <meta name="Copyright" content="Copyright (C) 2005-2011, Mike Pall"> | ||
| 8 | <meta name="Language" content="en"> | ||
| 9 | <link rel="stylesheet" type="text/css" href="bluequad.css" media="screen"> | ||
| 10 | <link rel="stylesheet" type="text/css" href="bluequad-print.css" media="print"> | ||
| 11 | </head> | ||
| 12 | <body> | ||
| 13 | <div id="site"> | ||
| 14 | <a href="http://luajit.org"><span>Lua<span id="logo">JIT</span></span></a> | ||
| 15 | </div> | ||
| 16 | <div id="head"> | ||
| 17 | <h1>FFI Library</h1> | ||
| 18 | </div> | ||
| 19 | <div id="nav"> | ||
| 20 | <ul><li> | ||
| 21 | <a href="luajit.html">LuaJIT</a> | ||
| 22 | <ul><li> | ||
| 23 | <a href="install.html">Installation</a> | ||
| 24 | </li><li> | ||
| 25 | <a href="running.html">Running</a> | ||
| 26 | </li></ul> | ||
| 27 | </li><li> | ||
| 28 | <a href="extensions.html">Extensions</a> | ||
| 29 | <ul><li> | ||
| 30 | <a class="current" href="ext_ffi.html">FFI Library</a> | ||
| 31 | <ul><li> | ||
| 32 | <a href="ext_ffi_tutorial.html">FFI Tutorial</a> | ||
| 33 | </li><li> | ||
| 34 | <a href="ext_ffi_api.html">ffi.* API</a> | ||
| 35 | </li><li> | ||
| 36 | <a href="ext_ffi_int64.html">64 bit Integers</a> | ||
| 37 | </li><li> | ||
| 38 | <a href="ext_ffi_semantics.html">FFI Semantics</a> | ||
| 39 | </li></ul> | ||
| 40 | </li><li> | ||
| 41 | <a href="ext_jit.html">jit.* Library</a> | ||
| 42 | </li><li> | ||
| 43 | <a href="ext_c_api.html">Lua/C API</a> | ||
| 44 | </li></ul> | ||
| 45 | </li><li> | ||
| 46 | <a href="status.html">Status</a> | ||
| 47 | <ul><li> | ||
| 48 | <a href="changes.html">Changes</a> | ||
| 49 | </li></ul> | ||
| 50 | </li><li> | ||
| 51 | <a href="faq.html">FAQ</a> | ||
| 52 | </li><li> | ||
| 53 | <a href="http://luajit.org/performance.html">Performance <span class="ext">»</span></a> | ||
| 54 | </li><li> | ||
| 55 | <a href="http://luajit.org/download.html">Download <span class="ext">»</span></a> | ||
| 56 | </li></ul> | ||
| 57 | </div> | ||
| 58 | <div id="main"> | ||
| 59 | <p> | ||
| 60 | The FFI library allows calling external C functions and the use | ||
| 61 | of C data structures from pure Lua code. | ||
| 62 | </p> | ||
| 63 | <p> | ||
| 64 | The FFI library largely obviates the need to write tedious manual | ||
| 65 | Lua/C bindings in C. It doesn't require learning a separate binding | ||
| 66 | language — it parses plain C declarations, which can be | ||
| 67 | cut-n-pasted from C header files or reference manuals. It's up to | ||
| 68 | the task of binding large libraries without the need for dealing with | ||
| 69 | fragile binding generators. | ||
| 70 | </p> | ||
| 71 | <p> | ||
| 72 | The FFI library is tightly integrated into LuaJIT (it's not available | ||
| 73 | as a separate module). The code generated by the JIT-compiler for | ||
| 74 | accesses to C data structures from Lua code is on par with the | ||
| 75 | code a C compiler would generate. Calls to C functions can | ||
| 76 | be inlined in the JIT-compiled code, unlike calls to functions bound | ||
| 77 | via the classic Lua/C API. | ||
| 78 | </p> | ||
| 79 | <p> | ||
| 80 | This page gives a short introduction to the usage of the FFI library. | ||
| 81 | Please use the FFI sub-topics in the navigation bar to learn more. | ||
| 82 | </p> | ||
| 83 | |||
| 84 | <h2 id="call">Motivating Example: Calling External C Functions</h2> | ||
| 85 | <p> | ||
| 86 | It's really easy to call an external C library function: | ||
| 87 | </p> | ||
| 88 | <pre class="code"> | ||
| 89 | <span style="color:#000080;">local ffi = require("ffi")</span> | ||
| 90 | ffi.cdef[[ | ||
| 91 | <span style="color:#00a000;font-weight:bold;">int printf(const char *fmt, ...);</span> | ||
| 92 | ]] | ||
| 93 | <span style="color:#c06000;font-weight:bold;">ffi.C</span>.printf("Hello %s!", "world") | ||
| 94 | </pre> | ||
| 95 | <p> | ||
| 96 | So, let's pick that apart: the first line (in blue) loads the FFI | ||
| 97 | library. The next one adds a C declaration for the function. The | ||
| 98 | part between the double-brackets (in green) is just standard | ||
| 99 | C syntax. And the last line calls the named C function. Yes, | ||
| 100 | it's that simple! | ||
| 101 | </p> | ||
| 102 | <p style="font-size: 8pt;"> | ||
| 103 | Actually, what goes on behind the scenes is far from simple: the first | ||
| 104 | part of the last line (in orange) makes use of the standard | ||
| 105 | C library namespace <tt>ffi.C</tt>. Indexing this namespace with | ||
| 106 | a symbol name (<tt>"printf"</tt>) automatically binds it to the the | ||
| 107 | standard C library. The result is a special kind of object which, | ||
| 108 | when called, runs the <tt>printf</tt> function. The arguments passed | ||
| 109 | to this function are automatically converted from Lua objects to the | ||
| 110 | corresponding C types. | ||
| 111 | </p> | ||
| 112 | <p> | ||
| 113 | Ok, so maybe the use of <tt>printf()</tt> wasn't such a spectacular | ||
| 114 | example. You could have done that with <tt>io.write()</tt> and | ||
| 115 | <tt>string.format()</tt>, too. But you get the idea ... | ||
| 116 | </p> | ||
| 117 | <p> | ||
| 118 | So here's something to pop up a message box on Windows: | ||
| 119 | </p> | ||
| 120 | <pre class="code"> | ||
| 121 | local ffi = require("ffi") | ||
| 122 | ffi.cdef[[ | ||
| 123 | int MessageBoxA(void *w, const char *txt, const char *cap, int type); | ||
| 124 | ]] | ||
| 125 | ffi.C.MessageBoxA(nil, "Hello world!", "Test", 0) | ||
| 126 | </pre> | ||
| 127 | <p> | ||
| 128 | Bing! Again, that was far too easy, no? | ||
| 129 | </p> | ||
| 130 | <p style="font-size: 8pt;"> | ||
| 131 | Compare this with the effort required to bind that function using the | ||
| 132 | classic Lua/C API: create an extra C file, add a C function | ||
| 133 | that retrieves and checks the argument types passed from Lua and calls | ||
| 134 | the actual C function, add a list of module functions and their | ||
| 135 | names, add a <tt>luaopen_*</tt> function and register all module | ||
| 136 | functions, compile and link it into a shared library (DLL), move it to | ||
| 137 | the proper path, add Lua code that loads the module aaaand ... finally | ||
| 138 | call the binding function. Phew! | ||
| 139 | </p> | ||
| 140 | |||
| 141 | <h2 id="call">Motivating Example: Using C Data Structures</h2> | ||
| 142 | <p> | ||
| 143 | The FFI library allows you to create and access C data | ||
| 144 | structures. Of course the main use for this is for interfacing with | ||
| 145 | C functions. But they can be used stand-alone, too. | ||
| 146 | </p> | ||
| 147 | <p> | ||
| 148 | Lua is built upon high-level data types. They are flexible, extensible | ||
| 149 | and dynamic. That's why we all love Lua so much. Alas, this can be | ||
| 150 | inefficient for certain tasks, where you'd really want a low-level | ||
| 151 | data type. E.g. a large array of a fixed structure needs to be | ||
| 152 | implemented with a big table holding lots of tiny tables. This imposes | ||
| 153 | both a substantial memory overhead as well as a performance overhead. | ||
| 154 | </p> | ||
| 155 | <p> | ||
| 156 | Here's a sketch of a library that operates on color images plus a | ||
| 157 | simple benchmark. First, the plain Lua version: | ||
| 158 | </p> | ||
| 159 | <pre class="code"> | ||
| 160 | local floor = math.floor | ||
| 161 | |||
| 162 | local function image_ramp_green(n) | ||
| 163 | local img = {} | ||
| 164 | local f = 255/(n-1) | ||
| 165 | for i=1,n do | ||
| 166 | img[i] = { red = 0, green = floor((i-1)*f), blue = 0, alpha = 255 } | ||
| 167 | end | ||
| 168 | return img | ||
| 169 | end | ||
| 170 | |||
| 171 | local function image_to_grey(img, n) | ||
| 172 | for i=1,n do | ||
| 173 | local y = floor(0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue) | ||
| 174 | img[i].red = y; img[i].green = y; img[i].blue = y | ||
| 175 | end | ||
| 176 | end | ||
| 177 | |||
| 178 | local N = 400*400 | ||
| 179 | local img = image_ramp_green(N) | ||
| 180 | for i=1,1000 do | ||
| 181 | image_to_grey(img, N) | ||
| 182 | end | ||
| 183 | </pre> | ||
| 184 | <p> | ||
| 185 | This creates a table with 160.000 pixels, each of which is a table | ||
| 186 | holding four number values in the range of 0-255. First an image with | ||
| 187 | a green ramp is created (1D for simplicity), then the image is | ||
| 188 | converted to greyscale 1000 times. Yes, that's silly, but I was in | ||
| 189 | need of a simple example ... | ||
| 190 | </p> | ||
| 191 | <p> | ||
| 192 | And here's the FFI version. The modified parts have been marked in | ||
| 193 | bold: | ||
| 194 | </p> | ||
| 195 | <pre class="code"> | ||
| 196 | <b>local ffi = require("ffi") | ||
| 197 | ffi.cdef[[ | ||
| 198 | typedef struct { uint8_t red, green, blue, alpha; } rgba_pixel; | ||
| 199 | ]]</b> | ||
| 200 | |||
| 201 | local function image_ramp_green(n) | ||
| 202 | <b>local img = ffi.new("rgba_pixel[?]", n)</b> | ||
| 203 | local f = 255/(n-1) | ||
| 204 | for i=<b>0,n-1</b> do | ||
| 205 | <b>img[i].green = i*f</b> | ||
| 206 | <b>img[i].alpha = 255</b> | ||
| 207 | end | ||
| 208 | return img | ||
| 209 | end | ||
| 210 | |||
| 211 | local function image_to_grey(img, n) | ||
| 212 | for i=<b>0,n-1</b> do | ||
| 213 | local y = <b>0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue</b> | ||
| 214 | img[i].red = y; img[i].green = y; img[i].blue = y | ||
| 215 | end | ||
| 216 | end | ||
| 217 | |||
| 218 | local N = 400*400 | ||
| 219 | local img = image_ramp_green(N) | ||
| 220 | for i=1,1000 do | ||
| 221 | image_to_grey(img, N) | ||
| 222 | end | ||
| 223 | </pre> | ||
| 224 | <p> | ||
| 225 | Ok, so that wasn't too difficult: first, load the FFI library and | ||
| 226 | declare the low-level data type. Here we choose a <tt>struct</tt> | ||
| 227 | which holds four byte fields, one for each component of a 4x8 bit | ||
| 228 | RGBA pixel. | ||
| 229 | </p> | ||
| 230 | <p> | ||
| 231 | Creating the data structure with <tt>ffi.new()</tt> is straightforward | ||
| 232 | — the <tt>'?'</tt> is a placeholder for the number of elements | ||
| 233 | of a variable-length array. C arrays are zero-based, so the | ||
| 234 | indexes have to run from <tt>0</tt> to <tt>n-1</tt> (one might | ||
| 235 | allocate one more element instead to simplify converting legacy | ||
| 236 | code). Since <tt>ffi.new()</tt> zero-fills the array by default, we | ||
| 237 | only need to set the green and the alpha fields. | ||
| 238 | </p> | ||
| 239 | <p> | ||
| 240 | The calls to <tt>math.floor()</tt> can be omitted here, because | ||
| 241 | floating-point numbers are already truncated towards zero when | ||
| 242 | converting them to an integer. This happens implicitly when the number | ||
| 243 | is stored in the fields of each pixel. | ||
| 244 | </p> | ||
| 245 | <p> | ||
| 246 | Now let's have a look at the impact of the changes: first, memory | ||
| 247 | consumption for the image is down from 22 Megabytes to | ||
| 248 | 640 Kilobytes (400*400*4 bytes). That's a factor of 35x less! So, | ||
| 249 | yes, tables do have a noticeable overhead. BTW: The original program | ||
| 250 | would consume 40 Megabytes in plain Lua (on x64). | ||
| 251 | </p> | ||
| 252 | <p> | ||
| 253 | Next, performance: the pure Lua version runs in 9.57 seconds (52.9 | ||
| 254 | seconds with the Lua interpreter) and the FFI version runs in 0.48 | ||
| 255 | seconds on my machine (YMMV). That's a factor of 20x faster (110x | ||
| 256 | faster than with plain Lua). | ||
| 257 | </p> | ||
| 258 | <p style="font-size: 8pt;"> | ||
| 259 | The avid reader may notice that converting the pure Lua version over | ||
| 260 | to use array indexes for the colors (<tt>[1]</tt> instead of | ||
| 261 | <tt>.red</tt>, <tt>[2]</tt> instead of <tt>.green</tt> etc.) ought to | ||
| 262 | be more compact and faster. This is certainly true (by a factor of | ||
| 263 | ~1.7x), but the resulting code would be less idiomatic and rather | ||
| 264 | error-prone. And it still doesn't get even close to the performance of | ||
| 265 | the FFI version of the code. Also, high-level data structures cannot | ||
| 266 | be easily passed to other C functions, especially I/O functions, | ||
| 267 | without undue conversion penalties. | ||
| 268 | </p> | ||
| 269 | <br class="flush"> | ||
| 270 | </div> | ||
| 271 | <div id="foot"> | ||
| 272 | <hr class="hide"> | ||
| 273 | Copyright © 2005-2011 Mike Pall | ||
| 274 | <span class="noprint"> | ||
| 275 | · | ||
| 276 | <a href="contact.html">Contact</a> | ||
| 277 | </span> | ||
| 278 | </div> | ||
| 279 | </body> | ||
| 280 | </html> | ||
