diff options
| author | Benoit Germain <bnt period germain arrobase gmail period com> | 2014-01-20 17:37:50 +0100 |
|---|---|---|
| committer | Benoit Germain <bnt period germain arrobase gmail period com> | 2014-01-20 17:37:50 +0100 |
| commit | 57ccc40847716069053a68e9d6079355dd5a1795 (patch) | |
| tree | 3499458dc894502407bfda347a6fdfee7319c29b | |
| parent | d92a2ca2a43c68854011e2f84ce0a75802d854be (diff) | |
| download | lanes-57ccc40847716069053a68e9d6079355dd5a1795.tar.gz lanes-57ccc40847716069053a68e9d6079355dd5a1795.tar.bz2 lanes-57ccc40847716069053a68e9d6079355dd5a1795.zip | |
linda performance improvement
slightly improve linda performance when the producer/consumer scenario
leaves leave the key empty
| -rw-r--r-- | CHANGES | 3 | ||||
| -rw-r--r-- | src/keeper.c | 14 | ||||
| -rw-r--r-- | tests/linda_perf.lua | 130 |
3 files changed, 66 insertions, 81 deletions
| @@ -1,5 +1,8 @@ | |||
| 1 | CHANGES: | 1 | CHANGES: |
| 2 | 2 | ||
| 3 | CHANGE 93: BGe 20-Jan-14 | ||
| 4 | * slightly improve linda performance when the producer/consumer scenario leaves leave the key empty | ||
| 5 | |||
| 3 | CHANGE 92: BGe 20-Jan-14 | 6 | CHANGE 92: BGe 20-Jan-14 |
| 4 | * version 3.8.1 | 7 | * version 3.8.1 |
| 5 | * new function lane:get_debug_threadname() | 8 | * new function lane:get_debug_threadname() |
diff --git a/src/keeper.c b/src/keeper.c index b0db8b4..1a696aa 100644 --- a/src/keeper.c +++ b/src/keeper.c | |||
| @@ -127,14 +127,14 @@ static void fifo_peek( lua_State* L, keeper_fifo* fifo, int count_) | |||
| 127 | 127 | ||
| 128 | // in: fifo | 128 | // in: fifo |
| 129 | // out: remove the fifo from the stack, push as many items as required on the stack (function assumes they exist in sufficient number) | 129 | // out: remove the fifo from the stack, push as many items as required on the stack (function assumes they exist in sufficient number) |
| 130 | static void fifo_pop( lua_State* L, keeper_fifo* fifo, int _count) | 130 | static void fifo_pop( lua_State* L, keeper_fifo* fifo, int count_) |
| 131 | { | 131 | { |
| 132 | int fifo_idx = lua_gettop( L); // ... fifo | 132 | int fifo_idx = lua_gettop( L); // ... fifo |
| 133 | int i; | 133 | int i; |
| 134 | // each iteration pushes a value on the stack! | 134 | // each iteration pushes a value on the stack! |
| 135 | STACK_GROW( L, _count + 2); | 135 | STACK_GROW( L, count_ + 2); |
| 136 | // skip first item, we will push it last | 136 | // skip first item, we will push it last |
| 137 | for( i = 1; i < _count; ++ i) | 137 | for( i = 1; i < count_; ++ i) |
| 138 | { | 138 | { |
| 139 | int const at = fifo->first + i; | 139 | int const at = fifo->first + i; |
| 140 | // push item on the stack | 140 | // push item on the stack |
| @@ -151,8 +151,12 @@ static void fifo_pop( lua_State* L, keeper_fifo* fifo, int _count) | |||
| 151 | lua_rawseti( L, fifo_idx, at); // ... fifo vals val | 151 | lua_rawseti( L, fifo_idx, at); // ... fifo vals val |
| 152 | lua_replace( L, fifo_idx); // ... vals | 152 | lua_replace( L, fifo_idx); // ... vals |
| 153 | } | 153 | } |
| 154 | fifo->first += _count; | 154 | { |
| 155 | fifo->count -= _count; | 155 | // avoid ever-growing indexes by resetting each time we detect the fifo is empty |
| 156 | int const new_count = fifo->count - count_; | ||
| 157 | fifo->first = (new_count == 0) ? 1 : (fifo->first + count_); | ||
| 158 | fifo->count = new_count; | ||
| 159 | } | ||
| 156 | } | 160 | } |
| 157 | 161 | ||
| 158 | // in: linda_ud expected at *absolute* stack slot idx | 162 | // in: linda_ud expected at *absolute* stack slot idx |
diff --git a/tests/linda_perf.lua b/tests/linda_perf.lua index 9348f71..1d92c8e 100644 --- a/tests/linda_perf.lua +++ b/tests/linda_perf.lua | |||
| @@ -6,7 +6,9 @@ local table_unpack = unpack or table.unpack | |||
| 6 | 6 | ||
| 7 | -- this lane eats items in the linda one by one | 7 | -- this lane eats items in the linda one by one |
| 8 | local eater = function( l, loop) | 8 | local eater = function( l, loop) |
| 9 | local key, val = l:receive( "go") | 9 | -- wait for start signal |
| 10 | l:receive( "go") | ||
| 11 | -- eat data one by one | ||
| 10 | for i = 1, loop do | 12 | for i = 1, loop do |
| 11 | local val, key = l:receive( "key") | 13 | local val, key = l:receive( "key") |
| 12 | --print( val) | 14 | --print( val) |
| @@ -18,7 +20,9 @@ end | |||
| 18 | 20 | ||
| 19 | -- this lane eats items in the linda in batches | 21 | -- this lane eats items in the linda in batches |
| 20 | local batched = function( l, loop, batch) | 22 | local batched = function( l, loop, batch) |
| 21 | local key, val = l:receive( "go") | 23 | -- wait for start signal |
| 24 | l:receive( "go") | ||
| 25 | -- eat data in batches | ||
| 22 | for i = 1, loop/batch do | 26 | for i = 1, loop/batch do |
| 23 | l:receive( l.batched, "key", batch) | 27 | l:receive( l.batched, "key", batch) |
| 24 | end | 28 | end |
| @@ -30,6 +34,7 @@ end | |||
| 30 | local lane_eater_gen = lanes.gen( "*", eater) | 34 | local lane_eater_gen = lanes.gen( "*", eater) |
| 31 | local lane_batched_gen = lanes.gen( "*", batched) | 35 | local lane_batched_gen = lanes.gen( "*", batched) |
| 32 | 36 | ||
| 37 | -- main thread writes data while a lane reads it | ||
| 33 | local function ziva( preloop, loop, batch) | 38 | local function ziva( preloop, loop, batch) |
| 34 | -- prefill the linda a bit to increase fifo stress | 39 | -- prefill the linda a bit to increase fifo stress |
| 35 | local top = math.max( preloop, loop) | 40 | local top = math.max( preloop, loop) |
| @@ -38,8 +43,8 @@ local function ziva( preloop, loop, batch) | |||
| 38 | for i = 1, preloop do | 43 | for i = 1, preloop do |
| 39 | l:send( "key", i) | 44 | l:send( "key", i) |
| 40 | end | 45 | end |
| 41 | print( l:count( "key")) | 46 | print( "stored " .. l:count( "key") .. " items in the linda before starting consumer lane") |
| 42 | if batch then | 47 | if batch > 0 then |
| 43 | if l.batched then | 48 | if l.batched then |
| 44 | lane = lane_batched_gen( l, top, batch) | 49 | lane = lane_batched_gen( l, top, batch) |
| 45 | else | 50 | else |
| @@ -49,12 +54,21 @@ local function ziva( preloop, loop, batch) | |||
| 49 | else | 54 | else |
| 50 | lane = lane_eater_gen( l, top) | 55 | lane = lane_eater_gen( l, top) |
| 51 | end | 56 | end |
| 52 | -- tell the lanes they can start eating data | 57 | -- tell the consumer lane it can start eating data |
| 53 | l:send("go", "go") | 58 | l:send( "go", true) |
| 54 | -- send the remainder of the elements while they are consumed | 59 | -- send the remainder of the elements while they are consumed |
| 60 | -- create a function that can send several values in one shot | ||
| 61 | batch = math.max( batch, 1) | ||
| 62 | local batch_values = {} | ||
| 63 | for i = 1, batch do | ||
| 64 | table.insert( batch_values, i) | ||
| 65 | end | ||
| 66 | local batch_send = function() | ||
| 67 | l:send( "key", table_unpack( batch_values)) | ||
| 68 | end | ||
| 55 | if loop > preloop then | 69 | if loop > preloop then |
| 56 | for i = preloop + 1, loop do | 70 | for i = preloop + 1, loop, batch do |
| 57 | l:send( "key", i) | 71 | batch_send() |
| 58 | end | 72 | end |
| 59 | end | 73 | end |
| 60 | l:send( "done" ,"are you happy?") | 74 | l:send( "done" ,"are you happy?") |
| @@ -62,33 +76,25 @@ local function ziva( preloop, loop, batch) | |||
| 62 | return lanes.now_secs() - t1 | 76 | return lanes.now_secs() - t1 |
| 63 | end | 77 | end |
| 64 | 78 | ||
| 65 | local tests = | 79 | local tests1 = |
| 66 | { | 80 | { |
| 67 | --[[{ 2000000, 0}, | 81 | --[[ |
| 68 | { 3000000, 0}, | 82 | { 10000, 2000000, 0}, |
| 69 | { 4000000, 0}, | 83 | { 10000, 2000000, 1}, |
| 70 | { 5000000, 0}, | 84 | { 10000, 2000000, 2}, |
| 71 | { 6000000, 0},]] | 85 | { 10000, 2000000, 3}, |
| 72 | --[[{ 1000000, 2000000}, | 86 | { 10000, 2000000, 5}, |
| 73 | { 2000000, 3000000}, | 87 | { 10000, 2000000, 8}, |
| 74 | { 3000000, 4000000}, | 88 | { 10000, 2000000, 13}, |
| 75 | { 4000000, 5000000}, | 89 | { 10000, 2000000, 21}, |
| 76 | { 5000000, 6000000},]] | 90 | { 10000, 2000000, 44}, |
| 77 | --[[{ 4000000, 0}, | 91 | --]] |
| 78 | { 4000000, 0, 1}, | ||
| 79 | { 4000000, 0, 2}, | ||
| 80 | { 4000000, 0, 3}, | ||
| 81 | { 4000000, 0, 5}, | ||
| 82 | { 4000000, 0, 8}, | ||
| 83 | { 4000000, 0, 13}, | ||
| 84 | { 4000000, 0, 21}, | ||
| 85 | { 4000000, 0, 44},]] | ||
| 86 | } | 92 | } |
| 87 | print "tests #1" | 93 | print "############################################\ntests #1" |
| 88 | for k, v in pairs( tests) do | 94 | for k, v in pairs( tests1) do |
| 89 | local pre, loop, batch = v[1], v[2], v[3] | 95 | local pre, loop, batch = v[1], v[2], v[3] |
| 90 | print( "testing", pre, loop, batch) | 96 | print( "testing", pre, loop, batch) |
| 91 | print( pre, loop, batch, "duration = " .. ziva( pre, loop, batch)) | 97 | print( pre, loop, batch, "duration = " .. ziva( pre, loop, batch) .. "\n") |
| 92 | end | 98 | end |
| 93 | 99 | ||
| 94 | --[[ | 100 | --[[ |
| @@ -124,6 +130,7 @@ end | |||
| 124 | ziva( 4000000, 0, 44) -> 2s | 130 | ziva( 4000000, 0, 44) -> 2s |
| 125 | ]] | 131 | ]] |
| 126 | 132 | ||
| 133 | -- sequential write/read (no parallelization involved) | ||
| 127 | local function ziva2( preloop, loop, batch) | 134 | local function ziva2( preloop, loop, batch) |
| 128 | local l = lanes.linda() | 135 | local l = lanes.linda() |
| 129 | -- prefill the linda a bit to increase fifo stress | 136 | -- prefill the linda a bit to increase fifo stress |
| @@ -154,6 +161,7 @@ local function ziva2( preloop, loop, batch) | |||
| 154 | for i = 1, preloop, step do | 161 | for i = 1, preloop, step do |
| 155 | batch_send() | 162 | batch_send() |
| 156 | end | 163 | end |
| 164 | print( "stored " .. (l:count( "key") or 0) .. " items in the linda before starting consumer lane") | ||
| 157 | -- loop that alternatively sends and reads data off the linda | 165 | -- loop that alternatively sends and reads data off the linda |
| 158 | if loop > preloop then | 166 | if loop > preloop then |
| 159 | for i = preloop + 1, loop, step do | 167 | for i = preloop + 1, loop, step do |
| @@ -170,16 +178,8 @@ end | |||
| 170 | 178 | ||
| 171 | local tests2 = | 179 | local tests2 = |
| 172 | { | 180 | { |
| 173 | --[[{ 2000000, 0}, | 181 | -- prefill, then consume everything |
| 174 | { 3000000, 0}, | 182 | --[[ |
| 175 | { 4000000, 0}, | ||
| 176 | { 5000000, 0}, | ||
| 177 | { 6000000, 0}, | ||
| 178 | { 1000000, 2000000}, | ||
| 179 | { 2000000, 3000000}, | ||
| 180 | { 3000000, 4000000}, | ||
| 181 | { 4000000, 5000000}, | ||
| 182 | { 5000000, 6000000},]] | ||
| 183 | { 4000000, 0}, | 183 | { 4000000, 0}, |
| 184 | { 4000000, 0, 1}, | 184 | { 4000000, 0, 1}, |
| 185 | { 4000000, 0, 2}, | 185 | { 4000000, 0, 2}, |
| @@ -189,44 +189,22 @@ local tests2 = | |||
| 189 | { 4000000, 0, 13}, | 189 | { 4000000, 0, 13}, |
| 190 | { 4000000, 0, 21}, | 190 | { 4000000, 0, 21}, |
| 191 | { 4000000, 0, 44}, | 191 | { 4000000, 0, 44}, |
| 192 | --]] | ||
| 193 | -- alternatively fill and consume | ||
| 194 | { 0, 4000000}, | ||
| 195 | { 0, 4000000, 1}, | ||
| 196 | { 0, 4000000, 2}, | ||
| 197 | { 0, 4000000, 3}, | ||
| 198 | { 0, 4000000, 5}, | ||
| 199 | { 0, 4000000, 8}, | ||
| 200 | { 0, 4000000, 13}, | ||
| 201 | { 0, 4000000, 21}, | ||
| 202 | { 0, 4000000, 44}, | ||
| 192 | } | 203 | } |
| 193 | 204 | ||
| 194 | print "tests #2" | 205 | print "\n############################################\ntests #2" |
| 195 | for k, v in pairs( tests2) do | 206 | for k, v in pairs( tests2) do |
| 196 | local pre, loop, batch = v[1], v[2], v[3] | 207 | local pre, loop, batch = v[1], v[2], v[3] |
| 197 | print( "testing", pre, loop, batch) | 208 | print( "testing", pre, loop, batch) |
| 198 | print( pre, loop, batch, "duration = " .. ziva2( pre, loop, batch)) | 209 | print( pre, loop, batch, "duration = " .. ziva2( pre, loop, batch) .. "\n") |
| 199 | end | 210 | end |
| 200 | |||
| 201 | --[[ | ||
| 202 | V 2.1.0: | ||
| 203 | ziva( 20000, 0) -> 3s ziva( 10000, 20000) -> 3s | ||
| 204 | ziva( 30000, 0) -> 8s ziva( 20000, 30000) -> 7s | ||
| 205 | ziva( 40000, 0) -> 15s ziva( 30000, 40000) -> 14s | ||
| 206 | ziva( 50000, 0) -> 24s ziva( 40000, 50000) -> 22s | ||
| 207 | ziva( 60000, 0) -> 34s ziva( 50000, 60000) -> 33s | ||
| 208 | |||
| 209 | SIMPLIFIED: | ||
| 210 | ziva( 20000, 0) -> 4s ziva( 10000, 20000) -> 3s | ||
| 211 | ziva( 30000, 0) -> 8s ziva( 20000, 30000) -> 7s | ||
| 212 | ziva( 40000, 0) -> 14s ziva( 30000, 40000) -> 14s | ||
| 213 | ziva( 50000, 0) -> 23s ziva( 40000, 50000) -> 22s | ||
| 214 | ziva( 60000, 0) -> 33s ziva( 50000, 60000) -> 32s | ||
| 215 | |||
| 216 | FIFO: | ||
| 217 | ziva( 2000000, 0) -> 9s ziva( 1000000, 2000000) -> 14s | ||
| 218 | ziva( 3000000, 0) -> 14s ziva( 2000000, 3000000) -> 23s | ||
| 219 | ziva( 4000000, 0) -> 19s ziva( 3000000, 4000000) -> 23s | ||
| 220 | ziva( 5000000, 0) -> 24s ziva( 4000000, 5000000) -> 32s | ||
| 221 | ziva( 6000000, 0) -> 29s ziva( 5000000, 6000000) -> 33s | ||
| 222 | |||
| 223 | FIFO BATCHED: | ||
| 224 | ziva( 4000000, 0, 1) -> 19s | ||
| 225 | ziva( 4000000, 0, 2) -> 11s | ||
| 226 | ziva( 4000000, 0, 3) -> s | ||
| 227 | ziva( 4000000, 0, 5) -> s | ||
| 228 | ziva( 4000000, 0, 8) -> s | ||
| 229 | ziva( 4000000, 0, 13) -> s | ||
| 230 | ziva( 4000000, 0, 21) -> s | ||
| 231 | ziva( 4000000, 0, 44) -> s | ||
| 232 | ]] | ||
