diff options
author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-04-11 15:14:52 +0200 |
---|---|---|
committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-04-11 15:14:52 +0200 |
commit | adaa36dbec1ce9aaafd61873b9d3d898a8c240cf (patch) | |
tree | 4c81e8f5983c3d696a636e2cc433ce7c0a9c3dd8 /tests | |
parent | 1d310e6ecb6e156598337612f16573d9cd284f5e (diff) | |
download | lanes-adaa36dbec1ce9aaafd61873b9d3d898a8c240cf.tar.gz lanes-adaa36dbec1ce9aaafd61873b9d3d898a8c240cf.tar.bz2 lanes-adaa36dbec1ce9aaafd61873b9d3d898a8c240cf.zip |
Bring all interesting fixes from the C++ implementation back into the C implementation
Diffstat (limited to 'tests')
-rw-r--r-- | tests/basic.lua | 14 | ||||
-rw-r--r-- | tests/cancel.lua | 212 | ||||
-rw-r--r-- | tests/errhangtest.lua | 15 | ||||
-rw-r--r-- | tests/fifo.lua | 42 | ||||
-rw-r--r-- | tests/keeper.lua | 63 | ||||
-rw-r--r-- | tests/linda_perf.lua | 165 | ||||
-rw-r--r-- | tests/protect_allocator.lua | 3 | ||||
-rw-r--r-- | tests/timer.lua | 12 |
8 files changed, 332 insertions, 194 deletions
diff --git a/tests/basic.lua b/tests/basic.lua index 385e22f..4b4fae6 100644 --- a/tests/basic.lua +++ b/tests/basic.lua | |||
@@ -154,7 +154,7 @@ PRINT(" "..st) | |||
154 | assert( st == "cancelled" ) | 154 | assert( st == "cancelled" ) |
155 | 155 | ||
156 | -- cancellation of lanes waiting on a linda | 156 | -- cancellation of lanes waiting on a linda |
157 | local limited = lanes.linda() | 157 | local limited = lanes.linda("limited") |
158 | limited:limit( "key", 1) | 158 | limited:limit( "key", 1) |
159 | -- [[################################################ | 159 | -- [[################################################ |
160 | limited:send( "key", "hello") -- saturate linda | 160 | limited:send( "key", "hello") -- saturate linda |
@@ -234,7 +234,7 @@ local chunk= function( linda ) | |||
234 | WR( "Lane ends!\n" ) | 234 | WR( "Lane ends!\n" ) |
235 | end | 235 | end |
236 | 236 | ||
237 | local linda= lanes_linda() | 237 | local linda= lanes_linda("communications") |
238 | assert( type(linda) == "userdata" ) | 238 | assert( type(linda) == "userdata" ) |
239 | -- | 239 | -- |
240 | -- ["->"] master -> slave | 240 | -- ["->"] master -> slave |
@@ -278,10 +278,12 @@ local complex_table = RECEIVE(); WR( type(complex_table).." received\n" ) | |||
278 | assert( complex_table[1] == complex_table[3] and complex_table[2] == complex_table[4]) | 278 | assert( complex_table[1] == complex_table[3] and complex_table[2] == complex_table[4]) |
279 | WR( table.concat( {complex_table[1][1],complex_table[2][1],complex_table[3][1],complex_table[4][1]},", ")) | 279 | WR( table.concat( {complex_table[1][1],complex_table[2][1],complex_table[3][1],complex_table[4][1]},", ")) |
280 | 280 | ||
281 | WR("collectgarbage") | ||
281 | t = nil | 282 | t = nil |
282 | collectgarbage() | 283 | collectgarbage() |
283 | -- wait | 284 | -- wait |
284 | linda: receive( 1, "wait") | 285 | WR("waiting 1s") |
286 | linda:receive( 1, "wait") | ||
285 | 287 | ||
286 | --############################################################## | 288 | --############################################################## |
287 | --############################################################## | 289 | --############################################################## |
@@ -336,6 +338,7 @@ for _, t in ipairs( stdlib_naming_tests) do | |||
336 | assert( f(t[1])[1] ) | 338 | assert( f(t[1])[1] ) |
337 | end | 339 | end |
338 | 340 | ||
341 | WR("collectgarbage") | ||
339 | collectgarbage() | 342 | collectgarbage() |
340 | 343 | ||
341 | --############################################################## | 344 | --############################################################## |
@@ -361,12 +364,13 @@ local tc= lanes_gen( "io", {gc_cb = gc_cb}, | |||
361 | end | 364 | end |
362 | ) | 365 | ) |
363 | 366 | ||
364 | local linda= lanes_linda() | 367 | local linda= lanes_linda("criss cross") |
365 | 368 | ||
366 | local a,b= tc(linda, "A","B"), tc(linda, "B","A") -- launching two lanes, twisted comms | 369 | local a,b= tc(linda, "A","B"), tc(linda, "B","A") -- launching two lanes, twisted comms |
367 | 370 | ||
368 | local _= a[1],b[1] -- waits until they are both ready | 371 | local _= a[1],b[1] -- waits until they are both ready |
369 | 372 | ||
373 | WR("collectgarbage") | ||
370 | a, b = nil | 374 | a, b = nil |
371 | collectgarbage() | 375 | collectgarbage() |
372 | 376 | ||
@@ -408,7 +412,7 @@ local function chunk2( linda ) | |||
408 | linda:send( "up", function() return ":)" end, "ok2" ) | 412 | linda:send( "up", function() return ":)" end, "ok2" ) |
409 | end | 413 | end |
410 | 414 | ||
411 | local linda= lanes.linda() | 415 | local linda= lanes.linda("linda") |
412 | local t2= lanes_gen( "debug,string,io", {gc_cb = gc_cb}, chunk2 )(linda) -- prepare & launch | 416 | local t2= lanes_gen( "debug,string,io", {gc_cb = gc_cb}, chunk2 )(linda) -- prepare & launch |
413 | linda:send( "down", function(linda) linda:send( "up", "ready!" ) end, | 417 | linda:send( "down", function(linda) linda:send( "up", "ready!" ) end, |
414 | "ok" ) | 418 | "ok" ) |
diff --git a/tests/cancel.lua b/tests/cancel.lua index 0d9d143..4e57184 100644 --- a/tests/cancel.lua +++ b/tests/cancel.lua | |||
@@ -1,36 +1,47 @@ | |||
1 | local lanes = require "lanes" .configure{ with_timers = false} | 1 | local which_tests, remaining_tests = {}, {} |
2 | 2 | for k,v in ipairs{...} do | |
3 | local linda = lanes.linda() | 3 | print("got arg:", type(v), tostring(v)) |
4 | which_tests[v] = true | ||
5 | remaining_tests[v] = true | ||
6 | end | ||
4 | 7 | ||
5 | --#################################################################### | 8 | --#################################################################### |
6 | print "\n\n####################################################################\nbegin genlock & genatomic cancel test\n" | ||
7 | |||
8 | -- get a lock and a atomic operator | ||
9 | local lock = lanes.genlock( linda, "lock", 1) | ||
10 | local atomic = lanes.genatomic( linda, "atomic") | ||
11 | |||
12 | -- check that cancelled lindas give cancel_error as they should | ||
13 | linda:cancel() | ||
14 | assert( linda:get( "empty") == lanes.cancel_error) | ||
15 | assert( lanes.genlock( linda, "any", 1) == lanes.cancel_error) | ||
16 | assert( lanes.genatomic( linda, "any") == lanes.cancel_error) | ||
17 | |||
18 | -- check that lock and atomic functions return cancel_error if the linda was cancelled | ||
19 | assert( lock( 1) == lanes.cancel_error) | ||
20 | assert( lock( -1) == lanes.cancel_error) | ||
21 | assert( atomic( 1) == lanes.cancel_error) | ||
22 | |||
23 | -- reset the linda so that the other tests work | ||
24 | linda:cancel( "none") | ||
25 | linda:limit( "lock", -1) | ||
26 | linda:set( "lock") | ||
27 | linda:limit( "atomic", -1) | ||
28 | linda:set( "atomic") | ||
29 | 9 | ||
10 | local lanes = require "lanes" .configure{ with_timers = false} | ||
11 | |||
12 | local linda = lanes.linda() | ||
30 | -- a numeric value to read | 13 | -- a numeric value to read |
31 | linda:set( "val", 33.0) | 14 | linda:set( "val", 33.0) |
32 | 15 | ||
33 | print "test OK" | 16 | --#################################################################### |
17 | if not next(which_tests) or which_tests.genlock then | ||
18 | remaining_tests.genlock = nil | ||
19 | print "\n\n####################################################################\nbegin genlock & genatomic cancel test\n" | ||
20 | |||
21 | -- get a lock and a atomic operator | ||
22 | local lock = lanes.genlock( linda, "lock", 1) | ||
23 | local atomic = lanes.genatomic( linda, "atomic") | ||
24 | |||
25 | -- check that cancelled lindas give cancel_error as they should | ||
26 | linda:cancel() | ||
27 | assert( linda:get( "empty") == lanes.cancel_error) | ||
28 | assert( lanes.genlock( linda, "any", 1) == lanes.cancel_error) | ||
29 | assert( lanes.genatomic( linda, "any") == lanes.cancel_error) | ||
30 | |||
31 | -- check that lock and atomic functions return cancel_error if the linda was cancelled | ||
32 | assert( lock( 1) == lanes.cancel_error) | ||
33 | assert( lock( -1) == lanes.cancel_error) | ||
34 | assert( atomic( 1) == lanes.cancel_error) | ||
35 | |||
36 | -- reset the linda so that the other tests work | ||
37 | linda:cancel( "none") | ||
38 | linda:limit( "lock", -1) | ||
39 | linda:set( "lock") | ||
40 | linda:limit( "atomic", -1) | ||
41 | linda:set( "atomic") | ||
42 | |||
43 | print "test OK" | ||
44 | end | ||
34 | --#################################################################### | 45 | --#################################################################### |
35 | 46 | ||
36 | local waitCancellation = function( h, expected_status) | 47 | local waitCancellation = function( h, expected_status) |
@@ -119,92 +130,115 @@ end | |||
119 | --#################################################################### | 130 | --#################################################################### |
120 | --#################################################################### | 131 | --#################################################################### |
121 | 132 | ||
122 | print "\n\n####################################################################\nbegin linda cancel test\n" | 133 | if not next(which_tests) or which_tests.linda then |
123 | h = lanes.gen( "*", laneBody)( "receive", nil) -- start an infinite wait on the linda | 134 | remaining_tests.linda = nil |
124 | 135 | print "\n\n####################################################################\nbegin linda cancel test\n" | |
125 | print "wait 1s" | 136 | h = lanes.gen( "*", laneBody)( "receive", nil) -- start an infinite wait on the linda |
126 | linda:receive( 1, "yeah") | ||
127 | |||
128 | -- linda cancel: linda:receive() returns cancel_error immediately | ||
129 | linda:cancel( "both") | ||
130 | 137 | ||
131 | -- wait until cancellation is effective. | 138 | print "wait 1s" |
132 | waitCancellation( h, "done") | 139 | linda:receive( 1, "yeah") |
133 | 140 | ||
134 | -- reset the linda so that the other tests work | 141 | -- linda cancel: linda:receive() returns cancel_error immediately |
135 | linda:cancel( "none") | 142 | print "cancelling" |
143 | linda:cancel( "both") | ||
136 | 144 | ||
137 | print "\n\n####################################################################\nbegin soft cancel test\n" | 145 | -- wait until cancellation is effective. |
138 | h = lanes.gen( "*", protectedBody)( "receive") -- start an infinite wait on the linda | 146 | waitCancellation( h, "done") |
139 | 147 | ||
140 | print "wait 1s" | 148 | -- reset the linda so that the other tests work |
141 | linda:receive( 1, "yeah") | 149 | linda:cancel( "none") |
150 | end | ||
142 | 151 | ||
143 | -- soft cancel, no awakening of waiting linda operations, should timeout | 152 | if not next(which_tests) or which_tests.soft then |
144 | local a, b = h:cancel( "soft", 1, false) | 153 | remaining_tests.soft = nil |
145 | -- cancellation should fail as the lane is still waiting on its linda | 154 | print "\n\n####################################################################\nbegin soft cancel test\n" |
146 | assert( a == false and b == "timeout") | 155 | h = lanes.gen( "*", protectedBody)( "receive") -- start an infinite wait on the linda |
147 | waitCancellation( h, "waiting") | ||
148 | 156 | ||
149 | -- soft cancel, this time awakens waiting linda operations, which returns cancel_error immediately, no timeout. | 157 | print "wait 1s" |
150 | h:cancel( "soft", true) | 158 | linda:receive( 1, "yeah") |
151 | 159 | ||
152 | -- wait until cancellation is effective. the lane will interrupt its loop and print the exit message | 160 | -- soft cancel, no awakening of waiting linda operations, should timeout |
153 | waitCancellation( h, "done") | 161 | local a, b = h:cancel( "soft", 1, false) |
162 | -- cancellation should fail as the lane is still waiting on its linda | ||
163 | assert( a == false and b == "timeout") | ||
164 | waitCancellation( h, "waiting") | ||
154 | 165 | ||
155 | -- do return end | 166 | -- soft cancel, this time awakens waiting linda operations, which returns cancel_error immediately, no timeout. |
167 | print "cancelling" | ||
168 | h:cancel( "soft", true) | ||
156 | 169 | ||
157 | print "\n\n####################################################################\nbegin hook cancel test\n" | 170 | -- wait until cancellation is effective. the lane will interrupt its loop and print the exit message |
158 | h = lanes.gen( "*", protectedBody)( "get", 300000) | 171 | waitCancellation( h, "done") |
159 | print "wait 2s" | 172 | end |
160 | linda:receive( 2, "yeah") | ||
161 | 173 | ||
162 | -- count hook cancel after 3 instructions | 174 | if not next(which_tests) or which_tests.hook then |
163 | h:cancel( "count", 300, 5.0) | 175 | remaining_tests.hook = nil |
176 | print "\n\n####################################################################\nbegin hook cancel test\n" | ||
177 | h = lanes.gen( "*", protectedBody)( "get", 300000) | ||
178 | print "wait 2s" | ||
179 | linda:receive( 2, "yeah") | ||
164 | 180 | ||
165 | -- wait until cancellation is effective. the lane will interrupt its loop and print the exit message | 181 | -- count hook cancel after some instruction instructions |
166 | waitCancellation( h, "cancelled") | 182 | print "cancelling" |
183 | h:cancel( "line", 300, 5.0) | ||
167 | 184 | ||
168 | print "\n\n####################################################################\nbegin hard cancel test\n" | 185 | -- wait until cancellation is effective. the lane will interrupt its loop and print the exit message |
169 | h = lanes.gen( "*", protectedBody)( "receive", nil) -- infinite timeout | 186 | waitCancellation( h, "cancelled") |
187 | end | ||
170 | 188 | ||
171 | -- wait 2s before cancelling the lane | 189 | if not next(which_tests) or which_tests.hard then |
172 | print "wait 2s" | 190 | remaining_tests.hard = nil |
173 | linda:receive( 2, "yeah") | 191 | print "\n\n####################################################################\nbegin hard cancel test\n" |
192 | h = lanes.gen( "*", protectedBody)( "receive", nil) -- infinite timeout | ||
174 | 193 | ||
175 | -- hard cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it | 194 | -- wait 2s before cancelling the lane |
176 | h:cancel() | 195 | print "wait 2s" |
196 | linda:receive( 2, "yeah") | ||
177 | 197 | ||
178 | -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error | 198 | -- hard cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it |
179 | waitCancellation( h, "cancelled") | 199 | print "cancelling" |
200 | h:cancel() | ||
180 | 201 | ||
181 | print "\n\n####################################################################\nbegin hard cancel test with unprotected lane body\n" | 202 | -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error |
182 | h = lanes.gen( "*", laneBody)( "receive", nil) | 203 | waitCancellation( h, "cancelled") |
204 | end | ||
183 | 205 | ||
184 | -- wait 2s before cancelling the lane | 206 | if not next(which_tests) or which_tests.hard_unprotected then |
185 | print "wait 2s" | 207 | remaining_tests.hard_unprotected = nil |
186 | linda:receive( 2, "yeah") | 208 | print "\n\n####################################################################\nbegin hard cancel test with unprotected lane body\n" |
209 | h = lanes.gen( "*", laneBody)( "receive", nil) | ||
187 | 210 | ||
188 | -- hard cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it | 211 | -- wait 2s before cancelling the lane |
189 | h:cancel() | 212 | print "wait 2s" |
213 | linda:receive( 2, "yeah") | ||
190 | 214 | ||
191 | -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error | 215 | -- hard cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it |
192 | waitCancellation( h, "cancelled") | 216 | print "cancelling" |
217 | h:cancel() | ||
193 | 218 | ||
194 | print "\n\n####################################################################\nbegin kill cancel test\n" | 219 | -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error |
195 | h = lanes.gen( "*", laneBody)( "busy", 50000000) -- start a pure Lua busy loop lane | 220 | waitCancellation( h, "cancelled") |
221 | end | ||
196 | 222 | ||
197 | -- wait 1/3s before cancelling the lane, before the busy loop can finish | 223 | if not next(which_tests) or which_tests.kill then |
198 | print "wait 0.3s" | 224 | remaining_tests.kill = nil |
199 | linda:receive( 0.3, "yeah") | 225 | print "\n\n####################################################################\nbegin kill cancel test\n" |
226 | h = lanes.gen( "*", laneBody)( "busy", 50000000) -- start a pure Lua busy loop lane | ||
200 | 227 | ||
201 | -- hard cancel with kill: the lane thread will be forcefully terminated | 228 | -- wait 1/3s before cancelling the lane, before the busy loop can finish |
202 | h:cancel( true) | 229 | print "wait 0.3s" |
230 | linda:receive( 0.3, "yeah") | ||
203 | 231 | ||
204 | -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error | 232 | -- hard cancel with kill: the lane thread will be forcefully terminated. kill timeout is pthread-specific |
205 | waitCancellation( h, "killed") | 233 | print "cancelling" |
234 | h:cancel( true, 1.0) | ||
206 | 235 | ||
236 | -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error | ||
237 | waitCancellation( h, "killed") | ||
238 | end | ||
207 | --#################################################################### | 239 | --#################################################################### |
208 | 240 | ||
209 | print "\ndone" | 241 | local unknown_test, val = next(remaining_tests) |
242 | assert(not unknown_test, tostring(unknown_test) .. " test is unknown") | ||
210 | 243 | ||
244 | print "\nTHE END" | ||
diff --git a/tests/errhangtest.lua b/tests/errhangtest.lua index 7286fa5..d26dcef 100644 --- a/tests/errhangtest.lua +++ b/tests/errhangtest.lua | |||
@@ -4,10 +4,19 @@ local linda = lanes.linda() | |||
4 | 4 | ||
5 | local coro = coroutine.create(function() end) | 5 | local coro = coroutine.create(function() end) |
6 | 6 | ||
7 | local fun = function() print "fun" end | ||
8 | local t_in = { [fun] = fun, fun = fun } | ||
9 | |||
10 | -- send a string | ||
11 | print( pcall(linda.send,linda, 'test', "oh boy")) | ||
12 | -- send a table that contains a function | ||
13 | print( pcall(linda.send,linda, 'test', t_in)) | ||
7 | -- we are not allowed to send coroutines through a lanes | 14 | -- we are not allowed to send coroutines through a lanes |
8 | -- however, this should raise an error, not hang the program... | 15 | -- however, this should raise an error, not hang the program... |
9 | print( pcall(linda.send,linda, 'test', "oh boy")) | ||
10 | print( pcall(linda.send,linda, 'test', coro)) | 16 | print( pcall(linda.send,linda, 'test', coro)) |
11 | k,res = linda:receive('test') | 17 | k,str = linda:receive('test') -- read the contents successfully sent |
12 | print( res) | 18 | print( str) -- "oh boy" |
19 | k,t_out = linda:receive('test') -- read the contents successfully sent | ||
20 | t_out.fun() -- "fun" | ||
13 | -- linda:send( 'test', coro) | 21 | -- linda:send( 'test', coro) |
22 | print "SUCCESS" \ No newline at end of file | ||
diff --git a/tests/fifo.lua b/tests/fifo.lua index bef60d5..498f540 100644 --- a/tests/fifo.lua +++ b/tests/fifo.lua | |||
@@ -6,24 +6,27 @@ | |||
6 | 6 | ||
7 | local lanes = require "lanes".configure{shutdown_timeout=3,with_timers=true} | 7 | local lanes = require "lanes".configure{shutdown_timeout=3,with_timers=true} |
8 | 8 | ||
9 | local linda = lanes.linda( "atom") | 9 | local atomic_linda = lanes.linda( "atom") |
10 | local atomic_inc= lanes.genatomic( linda, "FIFO_n") | 10 | local atomic_inc= lanes.genatomic( atomic_linda, "FIFO_n") |
11 | |||
12 | local fifo_linda = lanes.linda( "fifo") | ||
11 | 13 | ||
12 | assert( atomic_inc()==1) | 14 | assert( atomic_inc()==1) |
13 | assert( atomic_inc()==2) | 15 | assert( atomic_inc()==2) |
14 | 16 | ||
15 | local function FIFO() | 17 | local function FIFO() |
16 | local my_channel= "FIFO"..atomic_inc() | 18 | local my_channel= "FIFO_"..atomic_inc() |
17 | 19 | ||
18 | return { | 20 | return { |
19 | -- Giving explicit 'nil' timeout allows numbers to be used as 'my_channel' | 21 | -- Giving explicit 'nil' timeout allows numbers to be used as 'my_channel' |
20 | -- | 22 | -- |
21 | send = function(self, ...) | 23 | send = function(self, ...) |
22 | linda:send( nil, my_channel, ...) | 24 | fifo_linda:send( nil, my_channel, ...) |
23 | end, | 25 | end, |
24 | receive = function(self, timeout) | 26 | receive = function(self, timeout) |
25 | return linda:receive( timeout, my_channel) | 27 | return fifo_linda:receive( timeout, my_channel) |
26 | end | 28 | end, |
29 | channel = my_channel | ||
27 | } | 30 | } |
28 | end | 31 | end |
29 | 32 | ||
@@ -36,11 +39,38 @@ A:send( 1,2,3,4,5) | |||
36 | print "Sending to B.." | 39 | print "Sending to B.." |
37 | B:send( 'a','b','c') | 40 | B:send( 'a','b','c') |
38 | 41 | ||
42 | print "Dumping linda stats.. [1]" -- count everything | ||
43 | for key,count in pairs(fifo_linda:count()) do | ||
44 | print("channel " .. key .. " contains " .. count .. " entries.") | ||
45 | -- print(i, key_count[1], key_count[2]) | ||
46 | end | ||
47 | print "Dumping linda stats.. [2]" -- query count for known channels one at a time | ||
48 | print("channel " .. A.channel .. " contains " .. fifo_linda:count(A.channel) .. " entries.") | ||
49 | print("channel " .. B.channel .. " contains " .. fifo_linda:count(B.channel) .. " entries.") | ||
50 | print "Dumping linda stats.. [3]" -- query counts for a predefined list of keys | ||
51 | for key,count in pairs(fifo_linda:count(A.channel, B.channel)) do | ||
52 | print("channel " .. key .. " contains " .. count .. " entries.") | ||
53 | -- print(i, key_count[1], key_count[2]) | ||
54 | end | ||
55 | print "Dumping linda stats.. [4]" -- count everything | ||
56 | for key,contents in pairs(fifo_linda:dump()) do | ||
57 | print("channel " .. key .. ": limit=".. contents.limit, " first=" .. contents.first, " count=" .. contents.count) | ||
58 | for k,v in pairs(contents.fifo) do | ||
59 | print("[".. k.."] = " .. v) | ||
60 | end | ||
61 | end | ||
62 | |||
39 | print "Reading A.." | 63 | print "Reading A.." |
40 | print( A:receive( 1.0)) | 64 | print( A:receive( 1.0)) |
65 | print( A:receive( 1.0)) | ||
66 | print( A:receive( 1.0)) | ||
67 | print( A:receive( 1.0)) | ||
68 | print( A:receive( 1.0)) | ||
41 | 69 | ||
42 | print "Reading B.." | 70 | print "Reading B.." |
43 | print( B:receive( 2.0)) | 71 | print( B:receive( 2.0)) |
72 | print( B:receive( 2.0)) | ||
73 | print( B:receive( 2.0)) | ||
44 | 74 | ||
45 | -- Note: A and B can be passed between threads, or used as upvalues | 75 | -- Note: A and B can be passed between threads, or used as upvalues |
46 | -- by multiple threads (other parts will be copied but the 'linda' | 76 | -- by multiple threads (other parts will be copied but the 'linda' |
diff --git a/tests/keeper.lua b/tests/keeper.lua index f8c915d..3333938 100644 --- a/tests/keeper.lua +++ b/tests/keeper.lua | |||
@@ -4,7 +4,34 @@ | |||
4 | -- Test program for Lua Lanes | 4 | -- Test program for Lua Lanes |
5 | -- | 5 | -- |
6 | 6 | ||
7 | local lanes = require "lanes".configure{ with_timers = false, nb_keepers = 200} | 7 | local lanes = require "lanes".configure{ with_timers = false, nb_keepers = 1, keepers_gc_threshold = 500} |
8 | |||
9 | do | ||
10 | print "Linda names test:" | ||
11 | local unnamedLinda = lanes.linda() | ||
12 | local unnamedLinda2 = lanes.linda("") | ||
13 | local veeeerrrryyyylooongNamedLinda= lanes.linda( "veeeerrrryyyylooongNamedLinda", 1) | ||
14 | print(unnamedLinda, unnamedLinda2, veeeerrrryyyylooongNamedLinda) | ||
15 | print "GC deadlock test start" | ||
16 | -- store a linda in another linda (-> in a keeper) | ||
17 | unnamedLinda:set("here", lanes.linda("temporary linda")) | ||
18 | -- repeatedly add and remove stuff in the linda so that a GC happens during the keeper operation | ||
19 | for i = 1, 1000 do | ||
20 | for j = 1, 1000 do -- send 1000 tables | ||
21 | unnamedLinda:send("here", {"a", "table", "with", "some", "stuff"}) | ||
22 | end | ||
23 | unnamedLinda:set("here") -- clear everything | ||
24 | end | ||
25 | end | ||
26 | print "collecting garbage" | ||
27 | collectgarbage() | ||
28 | print "GC deadlock test done" | ||
29 | |||
30 | local print_id = 0 | ||
31 | local PRINT = function(...) | ||
32 | print_id = print_id + 1 | ||
33 | print("main", print_id .. ".", ...) | ||
34 | end | ||
8 | 35 | ||
9 | local function keeper(linda) | 36 | local function keeper(linda) |
10 | local mt= { | 37 | local mt= { |
@@ -25,23 +52,49 @@ local A= keeper( lindaA ) | |||
25 | local lindaB= lanes.linda( "B", 2) | 52 | local lindaB= lanes.linda( "B", 2) |
26 | local B= keeper( lindaB ) | 53 | local B= keeper( lindaB ) |
27 | 54 | ||
55 | local lindaC= lanes.linda( "C", 3) | ||
56 | local C= keeper( lindaC ) | ||
57 | print("Created", lindaA, lindaB, lindaC) | ||
58 | |||
28 | A.some= 1 | 59 | A.some= 1 |
29 | print( A.some ) | 60 | PRINT("A.some == " .. A.some ) |
30 | assert( A.some==1 ) | 61 | assert( A.some==1 ) |
31 | 62 | ||
32 | B.some= "hoo" | 63 | B.some= "hoo" |
64 | PRINT("B.some == " .. B.some ) | ||
33 | assert( B.some=="hoo" ) | 65 | assert( B.some=="hoo" ) |
34 | assert( A.some==1 ) | 66 | assert( A.some==1 ) |
67 | assert( C.some==nil ) | ||
35 | 68 | ||
36 | function lane() | 69 | function lane() |
70 | local print_id = 0 | ||
71 | local PRINT = function(...) | ||
72 | print_id = print_id + 1 | ||
73 | print("lane", print_id .. ".", ...) | ||
74 | end | ||
75 | |||
37 | local a= keeper(lindaA) | 76 | local a= keeper(lindaA) |
38 | print( a.some ) | 77 | PRINT("a.some == " .. a.some ) |
39 | assert( a.some==1 ) | 78 | assert( a.some==1 ) |
40 | a.some= 2 | 79 | a.some= 2 |
80 | assert( a.some==2 ) | ||
81 | PRINT("a.some == " .. a.some ) | ||
82 | |||
83 | local c = keeper(lindaC) | ||
84 | assert( c.some==nil ) | ||
85 | PRINT("c.some == " .. tostring(c.some)) | ||
86 | c.some= 3 | ||
87 | assert( c.some==3 ) | ||
88 | PRINT("c.some == " .. c.some) | ||
41 | end | 89 | end |
42 | 90 | ||
91 | PRINT("lane started") | ||
43 | local h= lanes.gen( "io", lane )() | 92 | local h= lanes.gen( "io", lane )() |
44 | h:join() | 93 | PRINT("lane joined:", h:join()) |
45 | 94 | ||
46 | print( A.some ) -- 2 | 95 | PRINT("A.some = " .. A.some ) |
47 | assert( A.some==2 ) | 96 | assert( A.some==2 ) |
97 | PRINT("C.some = " .. C.some ) | ||
98 | assert( C.some==3 ) | ||
99 | lindaC:set("some") | ||
100 | assert( C.some==nil ) \ No newline at end of file | ||
diff --git a/tests/linda_perf.lua b/tests/linda_perf.lua index a170b01..61b8f05 100644 --- a/tests/linda_perf.lua +++ b/tests/linda_perf.lua | |||
@@ -1,38 +1,62 @@ | |||
1 | local lanes = require "lanes" | 1 | local lanes = require "lanes" |
2 | lanes.configure{ with_timers = false} | 2 | lanes.configure{ with_timers = false, keepers_gc_threshold=30000 } |
3 | |||
4 | -- set TEST1, PREFILL1, FILL1, TEST2, PREFILL2, FILL2 from the command line | ||
3 | 5 | ||
4 | -- Lua 5.1/5.2 compatibility | 6 | -- Lua 5.1/5.2 compatibility |
5 | local table_unpack = unpack or table.unpack | 7 | local table_unpack = unpack or table.unpack |
6 | 8 | ||
9 | local finalizer = function(err, stk) | ||
10 | if err == lanes.cancel_error then | ||
11 | -- note that we don't get the cancel_error when running wrapped inside a protected call if it doesn't rethrow it | ||
12 | print(" laneBody after cancel" ) | ||
13 | elseif err then | ||
14 | print(" laneBody error: "..tostring(err)) | ||
15 | else | ||
16 | print(" laneBody finalized") | ||
17 | end | ||
18 | end | ||
19 | |||
20 | --################################################################################################## | ||
21 | |||
7 | -- this lane eats items in the linda one by one | 22 | -- this lane eats items in the linda one by one |
8 | local eater = function( l, loop) | 23 | local eater = function( l, loop) |
24 | set_finalizer(finalizer) | ||
9 | -- wait for start signal | 25 | -- wait for start signal |
10 | l:receive( "go") | 26 | l:receive( "go") |
11 | -- eat data one by one | 27 | -- eat data one by one |
12 | for i = 1, loop do | 28 | for i = 1, loop do |
13 | local val, key = l:receive( "key") | 29 | local key, val = l:receive( "key") |
14 | --print( val) | 30 | -- print("eater:", val) |
15 | end | 31 | end |
16 | -- print "loop is over" | 32 | -- print "loop is over" |
17 | key, val = l:receive( "done") | 33 | key, val = l:receive( "done") |
18 | -- print( val) | 34 | print("eater: done ("..val..")") |
19 | end | 35 | end |
20 | 36 | ||
37 | --################################################################################################## | ||
38 | |||
21 | -- this lane eats items in the linda in batches | 39 | -- this lane eats items in the linda in batches |
22 | local batched = function( l, loop, batch) | 40 | local gobbler = function( l, loop, batch) |
41 | set_finalizer(finalizer) | ||
23 | -- wait for start signal | 42 | -- wait for start signal |
24 | l:receive( "go") | 43 | l:receive( "go") |
25 | -- eat data in batches | 44 | -- eat data in batches |
26 | for i = 1, loop/batch do | 45 | for i = 1, loop/batch do |
27 | l:receive( l.batched, "key", batch) | 46 | l:receive( l.batched, "key", batch) |
47 | -- print("gobbler:", batch) | ||
28 | end | 48 | end |
29 | print "loop is over" | 49 | print "loop is over" |
30 | key, val = l:receive( "done") | 50 | key, val = l:receive( "done") |
31 | print( val) | 51 | print("gobbler: done ("..val..")") |
32 | end | 52 | end |
33 | 53 | ||
54 | --################################################################################################## | ||
55 | |||
34 | local lane_eater_gen = lanes.gen( "*", {priority = 3}, eater) | 56 | local lane_eater_gen = lanes.gen( "*", {priority = 3}, eater) |
35 | local lane_batched_gen = lanes.gen( "*", {priority = 3}, batched) | 57 | local lane_gobbler_gen = lanes.gen( "*", {priority = 3}, gobbler) |
58 | |||
59 | --################################################################################################## | ||
36 | 60 | ||
37 | -- main thread writes data while a lane reads it | 61 | -- main thread writes data while a lane reads it |
38 | local function ziva( preloop, loop, batch) | 62 | local function ziva( preloop, loop, batch) |
@@ -46,7 +70,7 @@ local function ziva( preloop, loop, batch) | |||
46 | print( "stored " .. l:count( "key") .. " items in the linda before starting consumer lane") | 70 | print( "stored " .. l:count( "key") .. " items in the linda before starting consumer lane") |
47 | if batch > 0 then | 71 | if batch > 0 then |
48 | if l.batched then | 72 | if l.batched then |
49 | lane = lane_batched_gen( l, top, batch) | 73 | lane = lane_gobbler_gen( l, top, batch) |
50 | else | 74 | else |
51 | print "no batch support in this version of Lanes" | 75 | print "no batch support in this version of Lanes" |
52 | lane = lane_eater_gen( l, top) | 76 | lane = lane_eater_gen( l, top) |
@@ -63,7 +87,9 @@ local function ziva( preloop, loop, batch) | |||
63 | for i = 1, batch do | 87 | for i = 1, batch do |
64 | table.insert( batch_values, i) | 88 | table.insert( batch_values, i) |
65 | end | 89 | end |
90 | local batch_send_log = "main: sending "..batch.." values" | ||
66 | local batch_send = function() | 91 | local batch_send = function() |
92 | -- print(batch_send_log) | ||
67 | l:send( "key", table_unpack( batch_values)) | 93 | l:send( "key", table_unpack( batch_values)) |
68 | end | 94 | end |
69 | if loop > preloop then | 95 | if loop > preloop then |
@@ -76,57 +102,35 @@ local function ziva( preloop, loop, batch) | |||
76 | return lanes.now_secs() - t1 | 102 | return lanes.now_secs() - t1 |
77 | end | 103 | end |
78 | 104 | ||
105 | --################################################################################################## | ||
106 | |||
107 | TEST1 = TEST1 or 1000 | ||
108 | PREFILL1 = PREFILL1 or 10000 | ||
109 | FILL1 = FILL1 or 2000000 | ||
110 | |||
79 | local tests1 = | 111 | local tests1 = |
80 | { | 112 | { |
81 | { 10000, 2000000, 0}, | 113 | { PREFILL1, FILL1, 0}, |
82 | { 10000, 2000000, 1}, | 114 | { PREFILL1, FILL1, 1}, |
83 | { 10000, 2000000, 2}, | 115 | { PREFILL1, FILL1, 2}, |
84 | { 10000, 2000000, 3}, | 116 | { PREFILL1, FILL1, 3}, |
85 | { 10000, 2000000, 5}, | 117 | { PREFILL1, FILL1, 5}, |
86 | { 10000, 2000000, 8}, | 118 | { PREFILL1, FILL1, 8}, |
87 | { 10000, 2000000, 13}, | 119 | { PREFILL1, FILL1, 13}, |
88 | { 10000, 2000000, 21}, | 120 | { PREFILL1, FILL1, 21}, |
89 | { 10000, 2000000, 44}, | 121 | { PREFILL1, FILL1, 44}, |
122 | { PREFILL1, FILL1, 65}, | ||
90 | } | 123 | } |
91 | print "############################################\ntests #1" | 124 | print "############################################ tests #1" |
92 | for k, v in pairs( tests1) do | 125 | for i, v in ipairs( tests1) do |
126 | if i > TEST1 then break end | ||
93 | local pre, loop, batch = v[1], v[2], v[3] | 127 | local pre, loop, batch = v[1], v[2], v[3] |
94 | print( "testing", pre, loop, batch) | 128 | print("-------------------------------------------------\n") |
95 | print( pre, loop, batch, "duration = " .. ziva( pre, loop, batch) .. "\n") | 129 | print("START", "prefill="..pre, "fill="..loop, "batch="..batch) |
130 | print("DURATION = " .. ziva( pre, loop, batch) .. "\n") | ||
96 | end | 131 | end |
97 | 132 | ||
98 | --[[ | 133 | --################################################################################################## |
99 | V 2.1.0: | ||
100 | ziva( 20000, 0) -> 4s ziva( 10000, 20000) -> 3s | ||
101 | ziva( 30000, 0) -> 8s ziva( 20000, 30000) -> 7s | ||
102 | ziva( 40000, 0) -> 15s ziva( 30000, 40000) -> 15s | ||
103 | ziva( 50000, 0) -> 24s ziva( 40000, 50000) -> 23s | ||
104 | ziva( 60000, 0) -> 34s ziva( 50000, 60000) -> 33s | ||
105 | |||
106 | SIMPLIFIED: | ||
107 | ziva( 20000, 0) -> 4s ziva( 10000, 20000) -> 3s | ||
108 | ziva( 30000, 0) -> 9s ziva( 20000, 30000) -> 8s | ||
109 | ziva( 40000, 0) -> 15s ziva( 30000, 40000) -> 15s | ||
110 | ziva( 50000, 0) -> 25s ziva( 40000, 50000) -> 24s | ||
111 | ziva( 60000, 0) -> 35s ziva( 50000, 60000) -> 35s | ||
112 | |||
113 | FIFO: | ||
114 | ziva( 2000000, 0) -> 9s ziva( 1000000, 2000000) -> 33s | ||
115 | ziva( 3000000, 0) -> 14s ziva( 2000000, 3000000) -> 40s | ||
116 | ziva( 4000000, 0) -> 20s ziva( 3000000, 4000000) -> 27s | ||
117 | ziva( 5000000, 0) -> 24s ziva( 4000000, 5000000) -> 42s | ||
118 | ziva( 6000000, 0) -> 29s ziva( 5000000, 6000000) -> 55s | ||
119 | |||
120 | FIFO BATCHED: | ||
121 | ziva( 4000000, 0, 1) -> 20s | ||
122 | ziva( 4000000, 0, 2) -> 11s | ||
123 | ziva( 4000000, 0, 3) -> 7s | ||
124 | ziva( 4000000, 0, 5) -> 5s | ||
125 | ziva( 4000000, 0, 8) -> 3s | ||
126 | ziva( 4000000, 0, 13) -> 3s | ||
127 | ziva( 4000000, 0, 21) -> 3s | ||
128 | ziva( 4000000, 0, 44) -> 2s | ||
129 | ]] | ||
130 | 134 | ||
131 | -- sequential write/read (no parallelization involved) | 135 | -- sequential write/read (no parallelization involved) |
132 | local function ziva2( preloop, loop, batch) | 136 | local function ziva2( preloop, loop, batch) |
@@ -159,7 +163,7 @@ local function ziva2( preloop, loop, batch) | |||
159 | for i = 1, preloop, step do | 163 | for i = 1, preloop, step do |
160 | batch_send() | 164 | batch_send() |
161 | end | 165 | end |
162 | print( "stored " .. (l:count( "key") or 0) .. " items in the linda before starting consumer lane") | 166 | print( "stored " .. (l:count( "key") or 0) .. " items in the linda before starting the alternating reads and writes") |
163 | -- loop that alternatively sends and reads data off the linda | 167 | -- loop that alternatively sends and reads data off the linda |
164 | if loop > preloop then | 168 | if loop > preloop then |
165 | for i = preloop + 1, loop, step do | 169 | for i = preloop + 1, loop, step do |
@@ -169,40 +173,39 @@ local function ziva2( preloop, loop, batch) | |||
169 | end | 173 | end |
170 | -- here, we have preloop elements still waiting inside the linda | 174 | -- here, we have preloop elements still waiting inside the linda |
171 | for i = 1, preloop, step do | 175 | for i = 1, preloop, step do |
172 | batch_read() | 176 | batch_read() |
173 | end | 177 | end |
174 | return lanes.now_secs() - t1 | 178 | return lanes.now_secs() - t1 |
175 | end | 179 | end |
176 | 180 | ||
181 | --################################################################################################## | ||
182 | |||
183 | TEST2 = TEST2 or 1000 | ||
184 | PREFILL2 = PREFILL2 or 0 | ||
185 | FILL2 = FILL2 or 4000000 | ||
186 | |||
177 | local tests2 = | 187 | local tests2 = |
178 | { | 188 | { |
179 | -- prefill, then consume everything | 189 | { PREFILL2, FILL2}, |
180 | --[[ | 190 | { PREFILL2, FILL2, 1}, |
181 | { 4000000, 0}, | 191 | { PREFILL2, FILL2, 2}, |
182 | { 4000000, 0, 1}, | 192 | { PREFILL2, FILL2, 3}, |
183 | { 4000000, 0, 2}, | 193 | { PREFILL2, FILL2, 5}, |
184 | { 4000000, 0, 3}, | 194 | { PREFILL2, FILL2, 8}, |
185 | { 4000000, 0, 5}, | 195 | { PREFILL2, FILL2, 13}, |
186 | { 4000000, 0, 8}, | 196 | { PREFILL2, FILL2, 21}, |
187 | { 4000000, 0, 13}, | 197 | { PREFILL2, FILL2, 44}, |
188 | { 4000000, 0, 21}, | 198 | { PREFILL2, FILL2, 65}, |
189 | { 4000000, 0, 44}, | ||
190 | --]] | ||
191 | -- alternatively fill and consume | ||
192 | { 0, 4000000}, | ||
193 | { 0, 4000000, 1}, | ||
194 | { 0, 4000000, 2}, | ||
195 | { 0, 4000000, 3}, | ||
196 | { 0, 4000000, 5}, | ||
197 | { 0, 4000000, 8}, | ||
198 | { 0, 4000000, 13}, | ||
199 | { 0, 4000000, 21}, | ||
200 | { 0, 4000000, 44}, | ||
201 | } | 199 | } |
202 | 200 | ||
203 | print "\n############################################\ntests #2" | 201 | print "############################################ tests #2" |
204 | for k, v in pairs( tests2) do | 202 | for i, v in ipairs( tests2) do |
203 | if i > TEST2 then break end | ||
205 | local pre, loop, batch = v[1], v[2], v[3] | 204 | local pre, loop, batch = v[1], v[2], v[3] |
206 | print( "testing", pre, loop, batch) | 205 | print("-------------------------------------------------\n") |
207 | print( pre, loop, batch, "duration = " .. ziva2( pre, loop, batch) .. "\n") | 206 | print("START", "prefill="..pre, "fill="..loop, "batch="..(batch or "no")) |
207 | print("DURATION = " .. ziva2( pre, loop, batch) .. "\n") | ||
208 | end | 208 | end |
209 | |||
210 | print "############################################" | ||
211 | print "THE END" \ No newline at end of file | ||
diff --git a/tests/protect_allocator.lua b/tests/protect_allocator.lua index 593261e..5cbb1d8 100644 --- a/tests/protect_allocator.lua +++ b/tests/protect_allocator.lua | |||
@@ -46,5 +46,8 @@ for i = 1, COUNT do | |||
46 | end | 46 | end |
47 | 47 | ||
48 | -- wait for completion | 48 | -- wait for completion |
49 | print "wait for completion" | ||
49 | linda:receive( linda.batched, "key", COUNT) | 50 | linda:receive( linda.batched, "key", COUNT) |
51 | print "waiting a bit more ..." | ||
52 | linda:receive( 1, "foo") | ||
50 | print "SUCCESS" | 53 | print "SUCCESS" |
diff --git a/tests/timer.lua b/tests/timer.lua index ec23cee..73ecb93 100644 --- a/tests/timer.lua +++ b/tests/timer.lua | |||
@@ -18,13 +18,14 @@ end | |||
18 | 18 | ||
19 | local T1= "1s" -- these keys can be anything... | 19 | local T1= "1s" -- these keys can be anything... |
20 | local T2= "5s" | 20 | local T2= "5s" |
21 | local PING_DURATION = 20 | ||
21 | 22 | ||
22 | local step= {} | 23 | local step= {} |
23 | 24 | ||
24 | lanes.timer( linda, T1, 1.0, 1.0 ) | 25 | lanes.timer( linda, T1, 1.0, 1.0 ) |
25 | step[T1]= 1.0 | 26 | step[T1]= 1.0 |
26 | 27 | ||
27 | PRINT( "\n*** Timers every second (not synced to wall clock) ***\n" ) | 28 | PRINT( "\n*** Starting 1s Timer (not synced to wall clock) ***\n" ) |
28 | 29 | ||
29 | local v_first | 30 | local v_first |
30 | local v_last= {} -- { [channel]= num } | 31 | local v_last= {} -- { [channel]= num } |
@@ -46,14 +47,15 @@ while true do | |||
46 | -- do not make measurements, first round is not 5secs due to wall clock adjustment | 47 | -- do not make measurements, first round is not 5secs due to wall clock adjustment |
47 | T2_first_round= false | 48 | T2_first_round= false |
48 | else | 49 | else |
49 | assert( math.abs(v-v_last[channel]- step[channel]) < 0.02 ) | 50 | local dt = math.abs(v-v_last[channel]- step[channel]) |
51 | assert( dt < 0.02, "channel " .. channel .. " is late: " .. dt) | ||
50 | end | 52 | end |
51 | end | 53 | end |
52 | 54 | ||
53 | if not v_first then | 55 | if not v_first then |
54 | v_first= v | 56 | v_first= v |
55 | elseif v-v_first > 3.0 and (not step[T2]) then | 57 | elseif v-v_first > 3.0 and (not step[T2]) then |
56 | PRINT( "\n*** Adding timers every 5 second (synced to wall clock) ***\n" ) | 58 | PRINT( "\n*** Starting 5s timer (synced to wall clock) ***\n" ) |
57 | 59 | ||
58 | -- The first event can be in the past (just cut seconds down to 5s) | 60 | -- The first event can be in the past (just cut seconds down to 5s) |
59 | -- | 61 | -- |
@@ -63,7 +65,7 @@ while true do | |||
63 | lanes.timer( linda, T2, date, 5.0 ) | 65 | lanes.timer( linda, T2, date, 5.0 ) |
64 | step[T2]= 5.0 | 66 | step[T2]= 5.0 |
65 | 67 | ||
66 | elseif v-v_first > 10 then -- exit condition | 68 | elseif v-v_first > PING_DURATION then -- exit condition |
67 | break | 69 | break |
68 | end | 70 | end |
69 | v_last[channel]= v | 71 | v_last[channel]= v |
@@ -80,7 +82,7 @@ PRINT( "\n*** Listing timers ***\n" ) | |||
80 | local r = lanes.timers() -- list of {linda, key, {}} | 82 | local r = lanes.timers() -- list of {linda, key, {}} |
81 | for _,t in ipairs( r) do | 83 | for _,t in ipairs( r) do |
82 | local linda, key, timer = t[1], t[2], t[3] | 84 | local linda, key, timer = t[1], t[2], t[3] |
83 | print( tostring( linda), key, timer[1], timer[2]) | 85 | print( tostring( linda), key, timer[1], timer[2]) |
84 | end | 86 | end |
85 | 87 | ||
86 | 88 | ||