From fb0ad986fcc40adcdbca6263ca6b80269f5ce169 Mon Sep 17 00:00:00 2001 From: Michal Cichra Date: Thu, 17 May 2018 10:20:16 +0200 Subject: [PATCH] [wip] optimize benchmark-ips to be more JITable --- benchmark/ips.lua | 31 ++++++++++++--- benchmark/regexpify.lua | 88 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 benchmark/regexpify.lua diff --git a/benchmark/ips.lua b/benchmark/ips.lua index 1c3ff6155..eb675072d 100644 --- a/benchmark/ips.lua +++ b/benchmark/ips.lua @@ -6,6 +6,7 @@ local Timing = { } local ffi = require 'ffi' +local tab_new = require "table.new" ffi.cdef [[ typedef int clockid_t; @@ -17,8 +18,10 @@ struct timespec { }; int clock_gettime(clockid_t clk_id, struct timespec *tp); +char *strerror(int errnum); ]] +local C = ffi.C local CLOCK = { REALTIME = 0, @@ -32,10 +35,16 @@ local CLOCK = { local ts = ffi.new("struct timespec[1]") +local function ffi_error() + return C.strerror(ffi.errno()) +end + -- Get an object that represents now in nanoseconds function Timing.now() - assert(ffi.C.clock_gettime(clock or CLOCK.MONOTONIC_RAW, ts) == 0, - "clock_gettime() failed: "..ffi.errno()) + if C.clock_gettime(CLOCK.MONOTONIC_RAW, ts) ~= 0 then + return nil, ffi_error() + end + return tonumber(ts[0].tv_sec * 1e9 + ts[0].tv_nsec) end @@ -229,6 +238,16 @@ local map = function(t, f) return m end +local function stats_samples(measurements_ns, cycles) + local samples = tab_new(#measurements_ns, 0) + + for i, time_ns in ipairs(measurements_ns) do + samples[i] = iterations_per_sec(cycles, time_ns) + end + + return samples +end + function IPS:run_benchmark() for _,item in ipairs(self.items) do self:notify('running', item.label, self.time) @@ -266,8 +285,7 @@ function IPS:run_benchmark() local final_time = after local measured_ns = sum(measurements_ns) - local samples = map(measurements_ns, function(time_ns) return iterations_per_sec(cycles, time_ns) end) - + local samples = stats_samples(measurements_ns, cycles) local rep = self.full_report:add_entry(item.label, measured_ns, iter, Stats:new(samples), cycles) self:notify('report_entry', rep) @@ -353,7 +371,10 @@ end local function stat_variance(samples, m) local mean = m or stat_mean(samples) - local total = sum(map(samples, function(n) return math.pow(n - mean, 2) end)) + local total = 0 + for _,n in ipairs(samples) do + total = total + math.pow(n - mean, 2) + end return total / #samples end diff --git a/benchmark/regexpify.lua b/benchmark/regexpify.lua new file mode 100644 index 000000000..51e87fdc7 --- /dev/null +++ b/benchmark/regexpify.lua @@ -0,0 +1,88 @@ +local re_gsub = ngx.re.gsub + +require('resty.core') +require('benchmark.ips')(function(b) + b.time = 5 + b.warmup = 2 + + local gsub = string.gsub + + local ffi_re_gsub = ngx.re.gsub + + local transforms = { + { '?.*', '' }, + { "{.-}", [[([\w-.~%%!$&'()*+,;=@:]+)]] }, + { "%.", [[\.]] }, + } + + local function loop(pattern) + for i=1, #transforms do + pattern = gsub(pattern, transforms[i][1], transforms[i][2]) + end + return pattern + end + + local function closure(pattern) + pattern = gsub(pattern, '?.*', '') + pattern = gsub(pattern, "{.-}", [[([\w-.~%%!$&'()*+,;=@:]+)]]) + pattern = gsub(pattern, "%.", "\\.") + + return pattern + end + + local function global(pattern) + -- as per the RFC: https://tools.ietf.org/html/rfc3986#section-3.3 + local wildcard_regex = [[([\w-.~%%!$&'()*+,;=@:]+)]] -- using long Lua brackets [[...]], escaping `%` + return pattern:gsub('?.*', ''):gsub("{.-}", wildcard_regex):gsub("%.", "\\.") + end + + local function pcre(pattern) + pattern = re_gsub(pattern, [[\?.*]], '') + pattern = re_gsub(pattern, [[\{.+?\}]], [[([\w-.~%!$$&'()*+,;=@:]+)]]) + pattern = re_gsub(pattern, [[\.]], [[\.]]) + + return pattern + end + + local function pcre_jit(pattern) + pattern = re_gsub(pattern, [[\?.*]], '', 'oj') + pattern = re_gsub(pattern, [[\{.+?\}]], [[([\w-.~%!$$&'()*+,;=@:]+)]], 'oj') + pattern = re_gsub(pattern, [[\.]], [[\.]], 'oj') + + return pattern + end + + local function ffi_pcre(pattern) + pattern = ffi_re_gsub(pattern, [[\?.*]], '') + pattern = ffi_re_gsub(pattern, [[\{.+?\}]], [[([\w-.~%!$$&'()*+,;=@:]+)]]) + pattern = ffi_re_gsub(pattern, [[\.]], [[\.]]) + + return pattern + end + + local function ffi_pcre_jit(pattern) + pattern = ffi_re_gsub(pattern, [[\?.*]], '', 'oj') + pattern = ffi_re_gsub(pattern, [[\{.+?\}]], [[([\w-.~%!$$&'()*+,;=@:]+)]], 'oj') + pattern = ffi_re_gsub(pattern, [[\.]], [[\.]], 'oj') + + return pattern + end + + local str = '/tfgoodosod/{foo}/sdsd?asdasdd' + + print('loop: ' , loop(str)) + print('closure:' , closure(str)) + print('global: ' , global(str)) + print('pcre: ' , pcre(str)) + + b:report('loop', function() return loop(str) end) + b:report('gsub', function() return closure(str) end) + b:report('string.gsub', function() return global(str) end) + b:report('re.gsub', function() return pcre(str) end) + b:report('re.gsub jit', function() return pcre_jit(str) end) + + b:report('ffi re.gsub', function() return ffi_pcre(str) end) + b:report('ffi re.gsub jit', function() return ffi_pcre_jit(str) end) + + b:compare() +end)