diff options
| author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-06-04 14:31:53 +0200 |
|---|---|---|
| committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-06-04 14:31:53 +0200 |
| commit | 20e551590b4491dade12191caf94411e7ec67dd9 (patch) | |
| tree | 7168db69a4972f0d2ac6697d619fe870f7bca4f5 | |
| parent | 011593650caa66457694fc46352208b8607d8994 (diff) | |
| download | lanes-20e551590b4491dade12191caf94411e7ec67dd9.tar.gz lanes-20e551590b4491dade12191caf94411e7ec67dd9.tar.bz2 lanes-20e551590b4491dade12191caf94411e7ec67dd9.zip | |
Refactored keeper implementation of linda:get()
| -rw-r--r-- | src/keeper.cpp | 40 | ||||
| -rw-r--r-- | tests/basic.lua | 23 | ||||
| -rw-r--r-- | tests/linda_perf.lua | 35 |
3 files changed, 74 insertions, 24 deletions
diff --git a/src/keeper.cpp b/src/keeper.cpp index eba184f..f1079e4 100644 --- a/src/keeper.cpp +++ b/src/keeper.cpp | |||
| @@ -125,15 +125,23 @@ void KeyUD::prepareAccess(KeeperState const K_) | |||
| 125 | 125 | ||
| 126 | // in: fifo | 126 | // in: fifo |
| 127 | // out: ...|nothing | 127 | // out: ...|nothing |
| 128 | // expects exactly 1 value on the stack! | 128 | // pops the fifo, push as much data as is available (up to the specified count) without consuming it |
| 129 | // function assumes that there is enough data in the fifo to satisfy the request | ||
| 130 | void KeyUD::peek(KeeperState const K_, int const count_) | 129 | void KeyUD::peek(KeeperState const K_, int const count_) |
| 131 | { | 130 | { |
| 132 | //LUA_ASSERT(K_, KeyUD::GetPtr(K_, 1) == this); | 131 | LUA_ASSERT(K_, KeyUD::GetPtr(K_, -1) == this); |
| 133 | STACK_GROW(K_, count_); | 132 | if (count <= 0) { // no data is available |
| 134 | for (int const _i : std::ranges::iota_view{ 0, count_ }) { | 133 | lua_pop(K_, 1); // K_: |
| 135 | lua_rawgeti(K_, 1, first + _i); | 134 | return; |
| 135 | } | ||
| 136 | |||
| 137 | // read <count_> value off the fifo | ||
| 138 | prepareAccess(K_); // K_: fifo | ||
| 139 | int const _at{ lua_gettop(K_) }; | ||
| 140 | for (int const _i : std::ranges::iota_view{ 1, std::min(count_, count) }) { // push val2 to valN | ||
| 141 | lua_rawgeti(K_, 1, first + _i); // K_: fifo val2..N | ||
| 136 | } | 142 | } |
| 143 | lua_rawgeti(K_, 1, first); // push val1 // K_: fifo val2..N val1 | ||
| 144 | lua_replace(K_, _at); // replace fifo by val1 to get the output properly ordered // K_: val1..N | ||
| 137 | } | 145 | } |
| 138 | 146 | ||
| 139 | // ################################################################################################# | 147 | // ################################################################################################# |
| @@ -518,23 +526,21 @@ int keepercall_get(lua_State* const L_) | |||
| 518 | KeeperState const _K{ L_ }; | 526 | KeeperState const _K{ L_ }; |
| 519 | int _count{ 1 }; | 527 | int _count{ 1 }; |
| 520 | if (lua_gettop(_K) == 3) { // _K: linda key count | 528 | if (lua_gettop(_K) == 3) { // _K: linda key count |
| 521 | _count = static_cast<int>(lua_tointeger(_K, 3)); | 529 | _count = static_cast<int>(lua_tointeger(_K, 3)); // linda:get() made sure _count >= 1 |
| 522 | lua_pop(_K, 1); // _K: linda key | 530 | lua_pop(_K, 1); // _K: linda key |
| 523 | } | 531 | } |
| 524 | PushKeysDB(_K, 1); // _K: linda key KeysDB | 532 | PushKeysDB(_K, 1); // _K: linda key KeysDB |
| 525 | lua_replace(_K, 1); // _K: KeysDB key | 533 | lua_replace(_K, 1); // _K: KeysDB key |
| 526 | lua_rawget(_K, 1); // _K: KeysDB KeyUD | 534 | lua_rawget(_K, 1); // _K: KeysDB KeyUD |
| 535 | lua_remove(_K, 1); // _K: KeyUD | ||
| 527 | KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; | 536 | KeyUD* const _key{ KeyUD::GetPtr(_K, -1) }; |
| 528 | if (_key != nullptr && _key->count > 0) { | 537 | if (_key != nullptr) { |
| 529 | _key->prepareAccess(_K); // _K: KeysDB fifo | 538 | _key->peek(_K, _count); // _K: val... |
| 530 | lua_remove(_K, 1); // _K: fifo | 539 | } else { |
| 531 | _count = std::min(_count, _key->count); | 540 | // no fifo was ever registered for this key, or it is empty |
| 532 | // read <count> value off the fifo | 541 | lua_pop(_K, 1); // _K: |
| 533 | _key->peek(_K, _count); // _K: fifo ... | 542 | } |
| 534 | return _count; | 543 | return lua_gettop(_K); |
| 535 | } | ||
| 536 | // no fifo was ever registered for this key, or it is empty | ||
| 537 | return 0; | ||
| 538 | } | 544 | } |
| 539 | 545 | ||
| 540 | // ################################################################################################# | 546 | // ################################################################################################# |
diff --git a/tests/basic.lua b/tests/basic.lua index fff19ed..ecd93fc 100644 --- a/tests/basic.lua +++ b/tests/basic.lua | |||
| @@ -249,7 +249,26 @@ assert(type(linda) == "userdata" and tostring(linda) == "Linda: communications") | |||
| 249 | -- ["->"] master -> slave | 249 | -- ["->"] master -> slave |
| 250 | -- ["<-"] slave <- master | 250 | -- ["<-"] slave <- master |
| 251 | 251 | ||
| 252 | local function PEEK() return linda:get("<-") end | 252 | WR "test linda:get/set..." |
| 253 | linda:set("<->", "x", "y", "z") | ||
| 254 | local x,y,z = linda:get("<->", 1) | ||
| 255 | assert(x == "x" and y == nil and z == nil) | ||
| 256 | local x,y,z = linda:get("<->", 2) | ||
| 257 | assert(x == "x" and y == "y" and z == nil) | ||
| 258 | local x,y,z = linda:get("<->", 3) | ||
| 259 | assert(x == "x" and y == "y" and z == "z") | ||
| 260 | local x,y,z,w = linda:get("<->", 4) | ||
| 261 | assert(x == "x" and y == "y" and z == "z" and w == nil) | ||
| 262 | local k, x = linda:receive("<->") | ||
| 263 | assert(k == "<->" and x == "x") | ||
| 264 | local k,y,z = linda:receive(linda.batched, "<->", 2) | ||
| 265 | assert(k == "<->" and y == "y" and z == "z") | ||
| 266 | linda:set("<->") | ||
| 267 | local x,y,z,w = linda:get("<->", 4) | ||
| 268 | assert(x == nil and y == nil and z == nil and w == nil) | ||
| 269 | WR "ok\n" | ||
| 270 | |||
| 271 | local function PEEK(...) return linda:get("<-", ...) end | ||
| 253 | local function SEND(...) linda:send("->", ...) end | 272 | local function SEND(...) linda:send("->", ...) end |
| 254 | local function RECEIVE() local k,v = linda:receive(1, "<-") return v end | 273 | local function RECEIVE() local k,v = linda:receive(1, "<-") return v end |
| 255 | 274 | ||
| @@ -259,7 +278,7 @@ SEND(1); WR("main ", "1 sent\n") | |||
| 259 | SEND(2); WR("main ", "2 sent\n") | 278 | SEND(2); WR("main ", "2 sent\n") |
| 260 | SEND(3); WR("main ", "3 sent\n") | 279 | SEND(3); WR("main ", "3 sent\n") |
| 261 | SEND(setmetatable({"should be ignored"},{__lanesignore=true})); WR("main ", "__lanesignore table sent\n") | 280 | SEND(setmetatable({"should be ignored"},{__lanesignore=true})); WR("main ", "__lanesignore table sent\n") |
| 262 | for i=1,100 do | 281 | for i=1,40 do |
| 263 | WR "." | 282 | WR "." |
| 264 | SLEEP(0.0001) | 283 | SLEEP(0.0001) |
| 265 | assert(PEEK() == nil) -- nothing coming in, yet | 284 | assert(PEEK() == nil) -- nothing coming in, yet |
diff --git a/tests/linda_perf.lua b/tests/linda_perf.lua index a50e906..4d35380 100644 --- a/tests/linda_perf.lua +++ b/tests/linda_perf.lua | |||
| @@ -62,12 +62,13 @@ local lane_gobbler_gen = lanes.gen( "*", {priority = 3}, gobbler) | |||
| 62 | local function ziva( preloop, loop, batch) | 62 | local function ziva( preloop, loop, batch) |
| 63 | -- prefill the linda a bit to increase fifo stress | 63 | -- prefill the linda a bit to increase fifo stress |
| 64 | local top = math.max( preloop, loop) | 64 | local top = math.max( preloop, loop) |
| 65 | local l, lane = lanes.linda() | 65 | local l = lanes.linda() |
| 66 | local t1 = lanes.now_secs() | 66 | local t1 = lanes.now_secs() |
| 67 | for i = 1, preloop do | 67 | for i = 1, preloop do |
| 68 | l:send( "key", i) | 68 | l:send( "key", i) |
| 69 | end | 69 | end |
| 70 | 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") |
| 71 | local lane | ||
| 71 | if batch > 0 then | 72 | if batch > 0 then |
| 72 | if l.batched then | 73 | if l.batched then |
| 73 | lane = lane_gobbler_gen( l, top, batch) | 74 | lane = lane_gobbler_gen( l, top, batch) |
| @@ -103,6 +104,28 @@ local function ziva( preloop, loop, batch) | |||
| 103 | end | 104 | end |
| 104 | 105 | ||
| 105 | -- ################################################################################################# | 106 | -- ################################################################################################# |
| 107 | do | ||
| 108 | print "############################################ tests get/set" | ||
| 109 | -- linda:get throughput | ||
| 110 | local l = lanes.linda("get/set") | ||
| 111 | local batch = {} | ||
| 112 | for i = 1,1000 do | ||
| 113 | table.insert(batch, i) | ||
| 114 | end | ||
| 115 | for _,size in ipairs{1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987 } do | ||
| 116 | l:set("<->", table_unpack(batch)) | ||
| 117 | local count = 20000000//size | ||
| 118 | print("START", "get("..size..") " .. count, " times") | ||
| 119 | local t1 = lanes.now_secs() | ||
| 120 | for i = 1, 2000000/math.sqrt(size) do | ||
| 121 | l:get("<->", size) | ||
| 122 | end | ||
| 123 | print("DURATION = " .. lanes.now_secs() - t1 .. "\n") | ||
| 124 | end | ||
| 125 | end | ||
| 126 | |||
| 127 | do return end | ||
| 128 | -- ################################################################################################# | ||
| 106 | 129 | ||
| 107 | TEST1 = TEST1 or 1000 | 130 | TEST1 = TEST1 or 1000 |
| 108 | PREFILL1 = PREFILL1 or 10000 | 131 | PREFILL1 = PREFILL1 or 10000 |
| @@ -118,8 +141,9 @@ local tests1 = | |||
| 118 | { PREFILL1, FILL1, 8}, | 141 | { PREFILL1, FILL1, 8}, |
| 119 | { PREFILL1, FILL1, 13}, | 142 | { PREFILL1, FILL1, 13}, |
| 120 | { PREFILL1, FILL1, 21}, | 143 | { PREFILL1, FILL1, 21}, |
| 121 | { PREFILL1, FILL1, 44}, | 144 | { PREFILL1, FILL1, 34}, |
| 122 | { PREFILL1, FILL1, 65}, | 145 | { PREFILL1, FILL1, 55}, |
| 146 | { PREFILL1, FILL1, 89}, | ||
| 123 | } | 147 | } |
| 124 | print "############################################ tests #1" | 148 | print "############################################ tests #1" |
| 125 | for i, v in ipairs( tests1) do | 149 | for i, v in ipairs( tests1) do |
| @@ -194,8 +218,9 @@ local tests2 = | |||
| 194 | { PREFILL2, FILL2, 8}, | 218 | { PREFILL2, FILL2, 8}, |
| 195 | { PREFILL2, FILL2, 13}, | 219 | { PREFILL2, FILL2, 13}, |
| 196 | { PREFILL2, FILL2, 21}, | 220 | { PREFILL2, FILL2, 21}, |
| 197 | { PREFILL2, FILL2, 44}, | 221 | { PREFILL2, FILL2, 34}, |
| 198 | { PREFILL2, FILL2, 65}, | 222 | { PREFILL2, FILL2, 55}, |
| 223 | { PREFILL2, FILL2, 89}, | ||
| 199 | } | 224 | } |
| 200 | 225 | ||
| 201 | print "############################################ tests #2" | 226 | print "############################################ tests #2" |
