Thanks to visit codestin.com
Credit goes to github.com

Skip to content

perf: improve render performance#17

Merged
tkan145 merged 4 commits into
masterfrom
perf
Jun 4, 2026
Merged

perf: improve render performance#17
tkan145 merged 4 commits into
masterfrom
perf

Conversation

@tkan145

@tkan145 tkan145 commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

What

Small refactoring to improve performance

Perf script

Details
local root = require('pl.path').currentdir()
package.path = root .. '/?.lua;' ..
               root .. '/gateway/src/?.lua;' ..
               root .. '/gateway/src/apicast/policy/3scale_batcher/?.lua;' ..
               package.path

local monotonic_msec = require("resty.core.time").monotonic_msec
local collectgarbage = collectgarbage
local update_time = ngx.update_time
local sleep = ngx.sleep
local print = print

ngx.var = {
  uri = '/api/v1/users',
  path = '/api/v1/users',
  host = 'localhost',
  remote_addr = '127.0.0.1',
  remote_port = '12345',
  scheme = 'http',
  server_addr = '127.0.0.1',
  server_port = '8080',
  request_id = '0',
}

local stub_headers = { ["Content-Type"] = "application/json" }
ngx.req.get_headers = function() return stub_headers end
ngx.req.get_method = function() return "GET" end

local TemplateString = require('apicast.template_string')

local ITERATIONS = 1000000
local s, e

local function bench(name, fn)
    -- warmup
    for i = 1, math.min(ITERATIONS, 50) do fn(i) end

    collectgarbage()
    collectgarbage()
    collectgarbage()
    sleep(1)

    update_time()
    s = monotonic_msec()
    for i = 1, ITERATIONS do
      fn(i)
    end
    update_time()
    e = monotonic_msec()
    print(string.format("  %s: ", name), e - s, " ms")
end

require('resty.core')
for _ = 1, 2 do

  -- -------------------------------------------------------
  -- 1. TemplateString.new (parse) cost
  -- -------------------------------------------------------

  print("\n--- TemplateString.new parse cost ---")

  bench('TemplateString.new plain', function()
    return TemplateString.new('/api/v1/users', 'plain')
  end)

  bench('TemplateString.new liquid (simple)', function()
    return TemplateString.new('{{ uri }}', 'liquid')
  end)

  bench('TemplateString.new liquid (filter)', function()
    return TemplateString.new('{{ uri | md5 }}', 'liquid')
  end)

  -- -------------------------------------------------------
  -- 2. Plain template render
  -- -------------------------------------------------------

  local plain_tpl = TemplateString.new('/api/v1/users', 'plain')

  bench('plain: render', function()
    return plain_tpl:render()
  end)

  -- -------------------------------------------------------
  -- 3. End-to-end: TemplateString render via public API
  -- -------------------------------------------------------

  print("\n--- end-to-end TemplateString:render ---")

  local ts_plain = TemplateString.new('/static/path', 'plain')
  local ts_simple = TemplateString.new('{{ uri }}', 'liquid')
  local ts_filter = TemplateString.new('{{ uri | md5 }}', 'liquid')
  local ts_multi = TemplateString.new('{{ name }}-{{ uri }}-{{ header }}-{{ request_id }}', 'liquid')

  bench('TemplateString:render plain', function()
    return ts_plain:render()
  end)

  bench('TemplateString:render liquid simple', function()
    return ts_simple:render(ctx)
  end)

  bench('TemplateString:render liquid+filter', function()
    return ts_filter:render(ctx)
  end)

  bench('TemplateString:render liquid multi-field', function()
    return ts_multi:render(ctx)
  end)
-- end)
end

Result

Before

--- TemplateString.new parse cost ---
  TemplateString.new plain: 0 ms
  TemplateString.new liquid (simple): 5228 ms
  TemplateString.new liquid (filter): 7338 ms

--- end-to-end TemplateString:render ---
  TemplateString:render plain: 24 ms
  TemplateString:render liquid simple: 1500 ms
  TemplateString:render liquid+filter: 2110 ms
  TemplateString:render liquid multi-field: 2930 ms

After

--- TemplateString.new parse cost ---
  TemplateString.new plain: 1 ms
  TemplateString.new liquid (simple): 2849 ms
  TemplateString.new liquid (filter): 3836 ms

--- end-to-end TemplateString:render ---
  TemplateString:render plain: 1 ms
  TemplateString:render liquid simple: 605 ms
  TemplateString:render liquid+filter: 1558 ms
  TemplateString:render liquid multi-field: 1668 ms

tkan145 added 4 commits June 2, 2026 11:15
The current code use many string.sub to manipulate string,
We can use string.byte to optimize check first/last char,
It is better than string.sub and does not generate temporary string
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants