summaryrefslogtreecommitdiff
path: root/pod/luajit-2.1/ext_ffi.pod
blob: e0c6841b1f47f9456040a97289265fe5f208d5b9 (plain)
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
=pod

LuaJIT

=head1 FFI Library

=over

=item * LuaJIT

=over

=item * Download E<rchevron>

=item * Installation

=item * Running

=back

=item * Extensions

=over

=item * FFI Library

=over

=item * FFI Tutorial

=item * ffi.* API

=item * FFI Semantics

=back

=item * jit.* Library

=item * Lua/C API

=item * Profiler

=back

=item * Status

=over

=item * Changes

=back

=item * FAQ

=item * Performance E<rchevron>

=item * Wiki E<rchevron>

=item * Mailing List E<rchevron>

=back

The FFI library allows B<calling external C functions> and B<using C
data structures> from pure Lua code.

The FFI library largely obviates the need to write tedious manual Lua/C
bindings in C. No need to learn a separate binding language E<mdash>
B<it parses plain C declarations!> 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.

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.

This page gives a short introduction to the usage of the FFI library.
I<Please use the FFI sub-topics in the navigation bar to learn more.>

=head2 Motivating Example: Calling External C Functions

It's really easy to call an external C library function:

 ①
 ②
 
 
 ③local ffi = require("ffi")
 ffi.cdef[[
 int printf(const char *fmt, ...);
 ]]
 ffi.C.printf("Hello %s!", "world")

So, let's pick that apart:

Load the FFI library.

Add a C declaration for the function. The part inside the
double-brackets (in green) is just standard C syntax.

Call the named C function E<mdash> Yes, it's that simple!

Actually, what goes on behind the scenes is far from simple: makes use
of the standard C library namespace C<ffi.C>. Indexing this namespace
with a symbol name (C<"printf">) automatically binds it to the standard
C library. The result is a special kind of object which, when called,
runs the C<printf> function. The arguments passed to this function are
automatically converted from Lua objects to the corresponding C types.

Ok, so maybe the use of C<printf()> wasn't such a spectacular example.
You could have done that with C<io.write()> and C<string.format()>,
too. But you get the idea ...

So here's something to pop up a message box on Windows:

 local ffi = require("ffi")
 ffi.cdef[[
 int MessageBoxA(void *w, const char *txt, const char *cap, int type);
 ]]
 ffi.C.MessageBoxA(nil, "Hello world!", "Test", 0)

Bing! Again, that was far too easy, no?

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 C<luaopen_*> 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!

=head2 Motivating Example: Using C Data Structures

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.

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.

Here's a sketch of a library that operates on color images plus a
simple benchmark. First, the plain Lua version:

 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

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 ...

And here's the FFI version. The modified parts have been marked in
bold:

 ①
 
 
 
 
 
 ②
 
 ③
 ④
 
 
 
 
 
 
 ③
 ⑤local ffi = require("ffi")
 ffi.cdef[[
 typedef struct { uint8_t red, green, blue, alpha; } rgba_pixel;
 ]]
 
 local function image_ramp_green(n)
   local img = ffi.new("rgba_pixel[?]", n)
   local f = 255/(n-1)
   for i=0,n-1 do
     img[i].green = i*f
     img[i].alpha = 255
   end
   return img
 end
 
 local function image_to_grey(img, n)
   for i=0,n-1 do
     local y = 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

Ok, so that wasn't too difficult:

First, load the FFI library and declare the low-level data type. Here
we choose a C<struct> which holds four byte fields, one for each
component of a 4x8 bit RGBA pixel.

Creating the data structure with C<ffi.new()> is straightforward
E<mdash> the C<'?'> is a placeholder for the number of elements of a
variable-length array.

C arrays are zero-based, so the indexes have to run from C<0> to
C<n-1>. One might want to allocate one more element instead to simplify
converting legacy code.

Since C<ffi.new()> zero-fills the array by default, we only need to set
the green and the alpha fields.

The calls to C<math.floor()> 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.

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).

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).

The avid reader may notice that converting the pure Lua version over to
use array indexes for the colors (C<[1]> instead of C<.red>, C<[2]>
instead of C<.green> 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.

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.

----

Copyright E<copy> 2005-2017 Mike Pall E<middot> Contact

=cut

#Pod::HTML2Pod conversion notes:
#From file ext_ffi.html
# 10336 bytes of input
#Mon May 14 13:19:16 2018 agentzh
# No a_name switch not specified, so will not try to render <a name='...'>
# No a_href switch not specified, so will not try to render <a href='...'>