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)