From a99fc516c088ab31b756ba69fefbf5820dd73efb Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Tue, 25 Oct 2016 20:47:29 +0000 Subject: [PATCH 1/2] core.lib: Added specialize(fn) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From the included documentation: — Function **lib.specialize** *function* Returns a clone of the given function with a shallow copy of its function definition. The clone function has a separate bytecode definition and any JIT traces that start in the clone will be aggressively specialized by LuaJIT for the environment of the clone. This can lead to especially efficient machine code when: - The function being specialized contains a loop (`for` or `while` or `repeat`) directly in its source code (not in a subroutine because the bytecode cloning is shallow). - The function will benefit from being compiled separately from other uses, for example because the way the clone will be called is expected to lead to a peculiar flow of control. - The function refers to values in its closure environment, which the JIT will treat more like constants than variables. See background information at [LuaJIT/LuaJIT#208](https://github.com/LuaJIT/LuaJIT/issues/208). --- src/README.md | 13 +++++++++++++ src/core/lib.lua | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/README.md b/src/README.md index 283f64a27f..d6e2bf86e5 100644 --- a/src/README.md +++ b/src/README.md @@ -909,6 +909,19 @@ lib.parse({foo=42, bar=43}, {foo={required=true}, bar={}, baz={default=44}}) => {foo=42, bar=43, baz=44} ``` +— Function **lib.specialize** *function* + +Returns a clone of the given function with a shallow copy of its +function definition. The clone function has a separate bytecode +definition and any JIT traces that start in the clone will be +aggressively specialized by LuaJIT for the environment of the clone. + +This can lead to especially efficient machine code when: +- The function being specialized contains a loop (`for` or `while` or `repeat`) directly in its source code (not in a subroutine because the bytecode cloning is shallow). +- The function will benefit from being compiled separately from other uses, for example because the way the clone will be called is expected to lead to a peculiar flow of control. +- The function refers to values in its closure environment, which the JIT will treat more like constants than variables. + +See background information at [LuaJIT/LuaJIT#208](https://github.com/LuaJIT/LuaJIT/issues/208). ## Main diff --git a/src/core/lib.lua b/src/core/lib.lua index 68f782a3dd..25df8b6584 100644 --- a/src/core/lib.lua +++ b/src/core/lib.lua @@ -738,6 +738,24 @@ function parse (arg, config) return ret end +-- Return a clone of the given function with separate bytecode. +-- (Code taken from http://leafo.net/guides/function-cloning-in-lua.html) +function specialize (fn) + local dumped = string.dump(fn) + local cloned = loadstring(dumped) + local i = 1 + while true do + local name = debug.getupvalue(fn, i) + if not name then + break + end + debug.upvaluejoin(cloned, i, fn, i) + i = i + 1 + end + return cloned +end + + function selftest () print("selftest: lib") print("Testing equal") From 85d2cd4724bb17360f4dc984417c5da6ce114de0 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Tue, 25 Oct 2016 20:48:10 +0000 Subject: [PATCH 2/2] engine: specialize() pull and push methods This is an experimental optimization. Call lib.specialize() on the pull and push method of each app instance. Subject to certain other considerations this will cause each app instance to have its own specially JITed machine code that can do nifty things like compile configuration parameters as if they were constants. Have to do some experimentation to better understand under which circumstances this will be effective. (Can also be that the JIT has been doing this for certain apps already.) --- src/core/app.lua | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/core/app.lua b/src/core/app.lua index 50f05d991a..41ba4b1544 100644 --- a/src/core/app.lua +++ b/src/core/app.lua @@ -196,6 +196,7 @@ function apply_config_actions (actions, conf) app.shm.dtime = {counter, C.get_unix_time()} app.shm = shm.create_frame("apps/"..name, app.shm) end + specialize(app) end function ops.restart (name) ops.stop(name) @@ -209,6 +210,7 @@ function apply_config_actions (actions, conf) new_app_table[name] = app table.insert(new_app_array, app) app_name_to_index[name] = #new_app_array + specialize(app) else ops.restart(name) end @@ -252,6 +254,13 @@ function apply_config_actions (actions, conf) end end +-- Specialize an app so that its pull and push methods can be JITed +-- into instance-specific machine code. +function specialize (app) + if app.pull then app.pull = lib.specialize(app.pull) end + if app.push then app.push = lib.specialize(app.push) end +end + -- Call this to "run snabb switch". function main (options) options = options or {}