Skip to content

Instantly share code, notes, and snippets.

@hnakamur
Created November 30, 2019 21:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hnakamur/bb6f6dec5ea043417cc0b382a5a4cf76 to your computer and use it in GitHub Desktop.
Save hnakamur/bb6f6dec5ea043417cc0b382a5a4cf76 to your computer and use it in GitHub Desktop.
OpenResty lua split benchmarkを自分でも試してみた
## オリジナル
https://github.com/toritori0318/Dockerfiles/tree/b82cb44834e33f0777b42d5f9b799b230c3e3237/openresty-split-bench
http://toritori0318.hatenadiary.jp/entry/20191201/1575141320
## 改変
/lua/lua_split_f は私が追加しました。固定数でないと使えないので split と同列ではないのですが、参考として。
## Run Server
```
docker build -t local/openresty-split-bench .
docker run -it -p 89:80 local/openresty-split-bench
```
## Benchmark
```
# curl
curl 'http://localhost:89/lua/lua_split_a?c=10'
```
FROM openresty/openresty:1.15.8.1-3-alpine-fat
ADD nginx.conf /usr/local/openresty/nginx/conf/nginx.conf
#daemon off;
worker_processes 1;
error_log /dev/stdout warn;
events {
worker_connections 1024;
}
pcre_jit on;
http {
init_by_lua_block {
function clock_time(title, block)
local st = os.clock()
block()
local ed = os.clock()
ngx.say(title .. ": " .. ed-st.. " sec")
end
}
server {
listen 80;
location / {
index index.html;
}
location /lua {
default_type text/html;
content_by_lua_block {
ngx.say("hello, lua")
}
}
location = /lua/ngx_re_split {
default_type text/html;
content_by_lua_block {
local ngx_re = require "ngx.re"
-- ngx_re.opt("jit_stack_size", 128 * 1024)
local params = ngx.req.get_uri_args()
local c = params["c"] or 1
local d = "aaaaaaa,bbbbbbbbbbb,ccccccccccccc,ddddddddddddddd,eeeeeeeeeeeeee,f,ggggg,hhh,iii,jjjjjjj,k"
clock_time("ngx_re_split", function()
for i = 1, c do
local t, err = ngx_re.split(d, ",")
if err then
ngx.log(ngx.ERR, string.format("err: %s", err))
else
-- ngx.log(ngx.WARN, string.format("t: %d", #t))
end
end
end)
}
}
location = /lua/lua_split_a {
default_type text/html;
content_by_lua_block {
local function csplit(str,sep)
local ret={}
local n=1
for w in str:gmatch("([^"..sep.."]*)") do
ret[n] = ret[n] or w -- only set once (so the blank after a string is ignored)
if w=="" then
n = n + 1
end -- step forwards on a blank but not a string
end
return ret
end
local params = ngx.req.get_uri_args()
local c = params["c"] or 1
local d = "aaaaaaa,bbbbbbbbbbb,ccccccccccccc,ddddddddddddddd,eeeeeeeeeeeeee,f,ggggg,hhh,iii,jjjjjjj,k"
clock_time("lua_split_a", function()
for i = 1, c do
local t = csplit(d, ",")
-- ngx.log(ngx.WARN, string.format("t: %d", #t))
end
end)
}
}
location = /lua/lua_split_b {
default_type text/html;
content_by_lua_block {
local function gsplit(s,sep)
local i, done, g = 1, false, s:gmatch('(.-)'..sep..'()')
local function pass(...)
if ... == nil then
done = true
return s:sub(i)
end
i = select(select('#',...),...)
return ...
end
return function()
if done then
return
end
if s == '' or sep == '' then
done = true
return s
end
return pass(g())
end
end
local params = ngx.req.get_uri_args()
local c = params["c"] or 1
local d = "aaaaaaa,bbbbbbbbbbb,ccccccccccccc,ddddddddddddddd,eeeeeeeeeeeeee,f,ggggg,hhh,iii,jjjjjjj,k"
clock_time("lua_split_b", function()
for i = 1, c do
local t={} for c in gsplit(d, ",") do table.insert(t,c) end
-- ngx.log(ngx.WARN, string.format("t: %d", #t))
end
end)
}
}
location = /lua/lua_split_c {
default_type text/html;
content_by_lua_block {
function string.gsplit(s, sep, plain)
local start = 1
local done = false
local function pass(i, j, ...)
if i then
local seg = s:sub(start, i - 1)
start = j + 1
return seg, ...
else
done = true
return s:sub(start)
end
end
return function()
if done then
return
end
if sep == '' then
done = true
return s
end
return pass(s:find(sep, start, plain))
end
end
local params = ngx.req.get_uri_args()
local c = params["c"] or 1
local d = "aaaaaaa,bbbbbbbbbbb,ccccccccccccc,ddddddddddddddd,eeeeeeeeeeeeee,f,ggggg,hhh,iii,jjjjjjj,k"
clock_time("lua_split_c", function()
for i = 1, c do
local t={} for c in d:gsplit(",") do table.insert(t,c) end
-- ngx.log(ngx.WARN, string.format("t: %d", #t))
end
end)
}
}
location = /lua/lua_split_d {
default_type text/html;
content_by_lua_block {
local strfind = string.find
local strsub = string.sub
local tinsert = table.insert
local function strsplit(delimiter, text, plain)
plain = plain or false
local list = {}
local pos = 1
if strfind("", delimiter, 1, plain) then -- this would result in endless loops
error("delimiter matches empty string!")
end
while 1 do
local first, last = strfind(text, delimiter, pos, plain)
if first then -- found?
tinsert(list, strsub(text, pos, first-1))
pos = last+1
else
tinsert(list, strsub(text, pos))
break
end
end
return list
end
local params = ngx.req.get_uri_args()
local c = params["c"] or 1
local d = "aaaaaaa,bbbbbbbbbbb,ccccccccccccc,ddddddddddddddd,eeeeeeeeeeeeee,f,ggggg,hhh,iii,jjjjjjj,k"
clock_time("lua_split_d", function()
for i = 1, c do
local t = strsplit(",", d)
-- ngx.log(ngx.WARN, string.format("t: %d", #t))
end
end)
}
}
location = /lua/lua_split_e {
default_type text/html;
content_by_lua_block {
local function split(str, pat)
local t = {} -- NOTE: use {n = 0} in Lua-5.0
local fpat = "(.-)" .. pat
local last_end = 1
local s, e, cap = str:find(fpat, 1)
while s do
if s ~= 1 or cap ~= "" then
table.insert(t,cap)
end
last_end = e+1
s, e, cap = str:find(fpat, last_end)
end
if last_end <= #str then
cap = str:sub(last_end)
table.insert(t, cap)
end
return t
end
local params = ngx.req.get_uri_args()
local c = params["c"] or 1
local d = "aaaaaaa,bbbbbbbbbbb,ccccccccccccc,ddddddddddddddd,eeeeeeeeeeeeee,f,ggggg,hhh,iii,jjjjjjj,k"
clock_time("lua_split_e", function()
for i = 1, c do
local t = split(d, ",")
-- ngx.log(ngx.WARN, string.format("t: %d", #t))
end
end)
}
}
location = /lua/lua_split_f {
default_type text/html;
content_by_lua_block {
local params = ngx.req.get_uri_args()
local c = params["c"] or 1
local d = "aaaaaaa,bbbbbbbbbbb,ccccccccccccc,ddddddddddddddd,eeeeeeeeeeeeee,f,ggggg,hhh,iii,jjjjjjj,k"
clock_time("lua_split_e", function()
for i = 1, c do
local t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11 = string.match(d, '([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*)')
-- ngx.log(ngx.WARN, string.format("t11: %s", t11))
end
end)
}
}
}
}
$ curl 'http://localhost:89/lua/lua_split_f?c=10'
lua_split_e: 0.000276 sec
$ curl 'http://localhost:89/lua/lua_split_f?c=10'
lua_split_e: 7.2e-05 sec
$ curl 'http://localhost:89/lua/ngx_re_split?c=10'
ngx_re_split: 0.000731 sec
$ curl 'http://localhost:89/lua/lua_split_a?c=10'
lua_split_a: 0.000443 sec
$ curl 'http://localhost:89/lua/lua_split_b?c=10'
lua_split_b: 0.000394 sec
$ curl 'http://localhost:89/lua/lua_split_c?c=10'
lua_split_c: 0.000434 sec
$ curl 'http://localhost:89/lua/lua_split_d?c=10'
lua_split_d: 0.00029 sec
$ curl 'http://localhost:89/lua/lua_split_e?c=10'
lua_split_e: 0.000162 sec
$ curl 'http://localhost:89/lua/lua_split_f?c=10'
lua_split_e: 5.4e-05 sec
$ curl 'http://localhost:89/lua/ngx_re_split?c=10'
ngx_re_split: 0.000418 sec
$ curl 'http://localhost:89/lua/lua_split_a?c=10'
lua_split_a: 0.000256 sec
$ curl 'http://localhost:89/lua/lua_split_b?c=10'
lua_split_b: 0.000174 sec
$ curl 'http://localhost:89/lua/lua_split_c?c=10'
lua_split_c: 0.000317 sec
$ curl 'http://localhost:89/lua/lua_split_e?c=10'
lua_split_e: 0.000196 sec
$ curl 'http://localhost:89/lua/lua_split_f?c=10'
lua_split_e: 4.3999999999999e-05 sec
$ curl 'http://localhost:89/lua/ngx_re_split?c=10000000'
ngx_re_split: 28.056177 sec
$ curl 'http://localhost:89/lua/lua_split_a?c=10000000'
lua_split_a: 41.272921 sec
$ curl 'http://localhost:89/lua/lua_split_b?c=10000000'
lua_split_b: 61.272173 sec
$ curl 'http://localhost:89/lua/lua_split_c?c=10000000'
lua_split_c: 19.150326 sec
$ curl 'http://localhost:89/lua/lua_split_d?c=10000000'
lua_split_d: 11.329389 sec
$ curl 'http://localhost:89/lua/lua_split_e?c=10000000'
lua_split_e: 40.524021 sec
$ curl 'http://localhost:89/lua/lua_split_f?c=10000000'
lua_split_e: 13.989293 sec
$ curl 'http://localhost:89/lua/lua_split_f?c=10000000'
lua_split_e: 14.0411 sec
$ curl 'http://localhost:89/lua/lua_split_f?c=10'
lua_split_e: 5.7999999995673e-05 sec
$ curl 'http://localhost:89/lua/lua_split_f?c=100'
lua_split_e: 0.00018199999999524 sec
$ curl 'http://localhost:89/lua/ngx_re_split?c=100'
ngx_re_split: 0.00036599999998543 sec
$ curl 'http://localhost:89/lua/lua_split_d?c=100'
lua_split_d: 0.00029900000001248 sec
$ curl 'http://localhost:89/lua/lua_split_a?c=100'
lua_split_a: 0.0012230000000102 sec
$ curl 'http://localhost:89/lua/lua_split_b?c=100'
lua_split_b: 0.00065299999999979 sec
$ curl 'http://localhost:89/lua/lua_split_c?c=100'
lua_split_c: 0.00089599999998313 sec
$ curl 'http://localhost:89/lua/lua_split_d?c=100'
lua_split_d: 0.00037800000001198 sec
$ curl 'http://localhost:89/lua/lua_split_e?c=100'
lua_split_e: 0.00061199999998962 sec
$ curl 'http://localhost:89/lua/lua_split_f?c=100'
lua_split_e: 0.00015500000000657 sec
$ curl 'http://localhost:89/lua/ngx_re_split?c=10000'
ngx_re_split: 0.035384999999991 sec
$ curl 'http://localhost:89/lua/lua_split_a?c=10000'
lua_split_a: 0.048181999999997 sec
$ curl 'http://localhost:89/lua/lua_split_b?c=10000'
lua_split_b: 0.069175999999999 sec
$ curl 'http://localhost:89/lua/lua_split_c?c=10000'
lua_split_c: 0.02699100000001 sec
$ curl 'http://localhost:89/lua/lua_split_d?c=10000'
lua_split_d: 0.020365999999996 sec
$ curl 'http://localhost:89/lua/lua_split_e?c=10000'
lua_split_e: 0.04945699999999 sec
$ curl 'http://localhost:89/lua/lua_split_f?c=10000'
lua_split_e: 0.022514999999999 sec
@hnakamur
Copy link
Author

READMEにも書いてますがオリジナルは
http://toritori0318.hatenadiary.jp/entry/20191201/1575141320
です。
/lua/lua_split_f は私が追加しました。固定数でないと使えないので split と同列ではないのですが、参考として。

試してみてわかったのですが回数によって順位が変動するんですね。実行した順に関係するかもしれないので並び変えずそのままにしています。
私は Core i5 に換装した Express5800 で試しました。
string.match (/lua/lua_split_f) 方式は10回だと最速でしたが、10000000 回だと他のLua実装のほうが速いことがわかりました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment