From 61b8b79066b0e93923baf0b6f50eebb5662a8d3f Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Fri, 1 Sep 2017 09:23:03 +0000 Subject: [PATCH 01/11] lj_trace.c: Clear penalty slot after successful trace Clear the penalty slot associated with a bytecode after it is traced successfully. This prevents penalties from accumulating for bytecodes that are traced frequently, such as branchy subroutines that are called from many different root traces and will need to record a side-trace for each. Especially intended to handle the special case when applications are generating code at runtime that creates a "fairly large" number of root traces and that need correspondingly many side-traces to be recorded without prematurely and unproductively blacklisting things. --- lib/luajit/src/lj_trace.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/luajit/src/lj_trace.c b/lib/luajit/src/lj_trace.c index 80a7f024af..1ccccd2765 100644 --- a/lib/luajit/src/lj_trace.c +++ b/lib/luajit/src/lj_trace.c @@ -473,6 +473,7 @@ static void trace_stop(jit_State *J) TraceNo traceno = J->cur.traceno; GCtrace *T = J->curfinal; lua_State *L; + int i; switch (op) { case BC_FORL: @@ -524,6 +525,11 @@ static void trace_stop(jit_State *J) J->postproc = LJ_POST_NONE; trace_save(J, T); + /* Clear any penalty after successful recording. */ + for (i = 0; i < PENALTY_SLOTS; i++) + if (mref(J->penalty[i].pc, const BCIns) == pc) + J->penalty[i].val = PENALTY_MIN; + L = J->L; lj_vmevent_send(L, TRACE, setstrV(L, L->top++, lj_str_newlit(L, "stop")); From 007eecef8efb26c606d2acca24603fef76bcbe6c Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Fri, 1 Sep 2017 09:49:00 +0000 Subject: [PATCH 02/11] lj_jit.h: Increase HOTCOUNT_MAX and expand HotPenalty.val Increase HOTCOUNT_MAX so that the JIT will make more attempts to trace a bytecode before it blacklists. Expand the HotPenalty.val from 16-bit to 32-bit to accommodate the larger value. HOTCOUNT_MAX is increased from 60,000 to 6,000,000. This is a 100x increase but the effect should be much smaller, log2(100) times, because the penalty value is increased exponentially. I don't entirely understand the existing design of the hotcount penalty: - Why initialize HOTCOUNT_MIN at 36*2? - Why increase the penalty exponentially instead of incrementally? - Why add random entropy to the increases? So I only hope that this patch doesn't break any important properties. --- lib/luajit/src/lj_jit.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/luajit/src/lj_jit.h b/lib/luajit/src/lj_jit.h index 92054e3df6..f66d2d75ee 100644 --- a/lib/luajit/src/lj_jit.h +++ b/lib/luajit/src/lj_jit.h @@ -277,13 +277,13 @@ static LJ_AINLINE MSize snap_nextofs(GCtrace *T, SnapShot *snap) /* Round-robin penalty cache for bytecodes leading to aborted traces. */ typedef struct HotPenalty { MRef pc; /* Starting bytecode PC. */ - uint16_t val; /* Penalty value, i.e. hotcount start. */ + uint32_t val; /* Penalty value, i.e. hotcount start. */ uint16_t reason; /* Abort reason (really TraceErr). */ } HotPenalty; #define PENALTY_SLOTS 64 /* Penalty cache slot. Must be a power of 2. */ #define PENALTY_MIN (36*2) /* Minimum penalty value. */ -#define PENALTY_MAX 60000 /* Maximum penalty value. */ +#define PENALTY_MAX 6000000 /* Maximum penalty value. */ #define PENALTY_RNDBITS 4 /* # of random bits to add to penalty value. */ /* Round-robin backpropagation cache for narrowing conversions. */ From 95daadb17661cbe22d9016558c3ae897f1347050 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Fri, 1 Sep 2017 10:32:36 +0000 Subject: [PATCH 03/11] fixup! lj_jit.h: Increase HOTCOUNT_MAX and expand HotPenalty.val --- lib/luajit/src/lj_trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/luajit/src/lj_trace.c b/lib/luajit/src/lj_trace.c index 1ccccd2765..34f202e968 100644 --- a/lib/luajit/src/lj_trace.c +++ b/lib/luajit/src/lj_trace.c @@ -392,7 +392,7 @@ static void penalty_pc(jit_State *J, GCproto *pt, BCIns *pc, TraceError e) J->penaltyslot = (J->penaltyslot + 1) & (PENALTY_SLOTS-1); setmref(J->penalty[i].pc, pc); setpenalty: - J->penalty[i].val = (uint16_t)val; + J->penalty[i].val = val; J->penalty[i].reason = e; hotcount_set(J2GG(J), pc+1, val); } From dab64f773f6e256439c3c606ff5178c16ac10217 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Fri, 1 Sep 2017 13:22:52 +0000 Subject: [PATCH 04/11] lj_trace.c: Reset hotcount table after flush --- lib/luajit/src/lj_trace.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/luajit/src/lj_trace.c b/lib/luajit/src/lj_trace.c index 34f202e968..e4a10aa5c3 100644 --- a/lib/luajit/src/lj_trace.c +++ b/lib/luajit/src/lj_trace.c @@ -293,6 +293,8 @@ int lj_trace_flushall(lua_State *L) J->freetrace = 0; /* Clear penalty cache. */ memset(J->penalty, 0, sizeof(J->penalty)); + /* Reset hotcounts. */ + lj_dispatch_init_hotcount(J2G(J)); /* Free the whole machine code and invalidate all exit stub groups. */ lj_mcode_free(J); memset(J->exitstubgroup, 0, sizeof(J->exitstubgroup)); From b34622715ee84c8c5866f008729d8cf5d64ed10a Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Mon, 4 Sep 2017 12:07:11 +0000 Subject: [PATCH 05/11] lj_record.c: Relax heuristic for root trace meeting JIT loop --- lib/luajit/src/lj_record.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/luajit/src/lj_record.c b/lib/luajit/src/lj_record.c index b2abed08f0..2d2510a736 100644 --- a/lib/luajit/src/lj_record.c +++ b/lib/luajit/src/lj_record.c @@ -595,7 +595,8 @@ static void rec_loop_interp(jit_State *J, const BCIns *pc, LoopEvent ev) /* Handle the case when an already compiled loop op is hit. */ static void rec_loop_jit(jit_State *J, TraceNo lnk, LoopEvent ev) { - if (J->parent == 0 && J->exitno == 0) { /* Root trace hit an inner loop. */ + /* Root trace hit an inner loop. */ + if (J->parent == 0 && J->exitno == 0 && !innerloopleft(J, J->startpc)) { /* Better let the inner loop spawn a side trace back here. */ lj_trace_err(J, LJ_TRERR_LINNER); } else if (ev != LOOPEV_LEAVE) { /* Side trace enters a compiled loop. */ From aaeacfef5d97a1c5c6b7a49543c67eb5461131cf Mon Sep 17 00:00:00 2001 From: Rajkumar Date: Tue, 3 Oct 2017 18:31:47 +0530 Subject: [PATCH 06/11] jit_loop app --- src/apps/jit_loop/ipv4_apps.lua | 31 ++++++++++++++++++++++++++ src/program/jit_loop/jit_loop.lua | 37 +++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/apps/jit_loop/ipv4_apps.lua create mode 100644 src/program/jit_loop/jit_loop.lua diff --git a/src/apps/jit_loop/ipv4_apps.lua b/src/apps/jit_loop/ipv4_apps.lua new file mode 100644 index 0000000000..9d1f2381e5 --- /dev/null +++ b/src/apps/jit_loop/ipv4_apps.lua @@ -0,0 +1,31 @@ +module(..., package.seeall) + +local ethernet = require("lib.protocol.ethernet") +local receive, transmit = link.receive, link.transmit + +ChangeMAC = {} + +function ChangeMAC:new(conf) + local o = setmetatable({}, {__index=ChangeMAC}) + o.conf = conf + o.src_eth = ethernet:pton(conf.src_eth) + o.dst_eth = ethernet:pton(conf.dst_eth) + o.eth_pkt = ethernet:new({}) + return o +end + +function ChangeMAC:push() + local i, o = self.input.input, self.output.output + for _ = 1, link.nreadable(i) do + local p = receive(i) + local data, length = p.data, p.length + if length > 0 then + local eth_pkt = self.eth_pkt:new_from_mem(data, length) + eth_pkt:src(self.src_eth) + eth_pkt:dst(self.dst_eth) + transmit(o, p) + else + packet.free(p) + end + end +end diff --git a/src/program/jit_loop/jit_loop.lua b/src/program/jit_loop/jit_loop.lua new file mode 100644 index 0000000000..ee5b6aece6 --- /dev/null +++ b/src/program/jit_loop/jit_loop.lua @@ -0,0 +1,37 @@ +module(..., package.seeall) + +local lib = require("core.lib") +local logger = lib.logger_new({ rate = 32, module = 'minapp' }); +local intel = require("apps.intel_mp.intel_mp") +local ipv4_apps = require("apps.jit_loop.ipv4_apps") + +function run (parameters) + local north_pci_address = "0000:01:00.1" + local south_pci_address = "0000:01:00.0" + local north_mac = "08:35:71:02:6a:63" + local south_mac = "08:35:71:02:6a:62" + local north_next_hop_mac = "08:35:71:00:97:15" + local south_next_hop_mac = "08:35:71:00:97:14" + + local south_if_config = {pciaddr=south_pci_address, rxq = 0, txq = 0} + local north_if_config = {pciaddr=north_pci_address, rxq = 0, txq = 0} + + local north_mac_config = {src_eth = north_mac, dst_eth = north_next_hop_mac} + local south_mac_config = {src_eth = south_mac, dst_eth = south_next_hop_mac} + + local c = config.new() + config.app(c, "south_if", intel.Intel, south_if_config) + config.app(c, "north_if", intel.Intel, north_if_config) + config.app(c, "north_setmac", ipv4_apps.ChangeMAC, north_mac_config) + config.app(c, "south_setmac", ipv4_apps.ChangeMAC, south_mac_config) + + config.link(c, "south_if.output -> north_setmac.input") + config.link(c, "north_setmac.output -> north_if.input") + + config.link(c, "north_if.output -> south_setmac.input") + config.link(c, "south_setmac.output -> south_if.input") + + engine.configure(c) + logger:log ("Engine ready to start processing") + engine.main({report = {showlinks=true, showapps=true}}) +end From a26821215056ed101240a53072023c9d4b5b4f09 Mon Sep 17 00:00:00 2001 From: Rajkumar Date: Wed, 4 Oct 2017 19:52:43 +0530 Subject: [PATCH 07/11] Increase luajit tuneables to avoid failed to allocate mcode memory --- lib/luajit/src/lj_jit.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/luajit/src/lj_jit.h b/lib/luajit/src/lj_jit.h index f66d2d75ee..ff3aee2de0 100644 --- a/lib/luajit/src/lj_jit.h +++ b/lib/luajit/src/lj_jit.h @@ -97,11 +97,11 @@ /* Optimization parameters and their defaults. Length is a char in octal! */ #define JIT_PARAMDEF(_) \ - _(\010, maxtrace, 1000) /* Max. # of traces in cache. */ \ - _(\011, maxrecord, 4000) /* Max. # of recorded IR instructions. */ \ + _(\010, maxtrace, 2000) /* Max. # of traces in cache. */ \ + _(\011, maxrecord, 6000) /* Max. # of recorded IR instructions. */ \ _(\012, maxirconst, 500) /* Max. # of IR constants of a trace. */ \ - _(\007, maxside, 100) /* Max. # of side traces of a root trace. */ \ - _(\007, maxsnap, 500) /* Max. # of snapshots for a trace. */ \ + _(\007, maxside, 200) /* Max. # of side traces of a root trace. */ \ + _(\007, maxsnap, 1000) /* Max. # of snapshots for a trace. */ \ _(\011, minstitch, 0) /* Min. # of IR ins for a stitched trace. */ \ \ _(\007, hotloop, 56) /* # of iter. to detect a hot loop/call. */ \ @@ -116,7 +116,7 @@ /* Size of each machine code area (in KBytes). */ \ _(\011, sizemcode, JIT_P_sizemcode_DEFAULT) \ /* Max. total size of all machine code areas (in KBytes). */ \ - _(\010, maxmcode, 512) \ + _(\010, maxmcode, 4096) \ /* End of list. */ enum { From b7b14ccea8833c9760813ff0f7de6d4fe0264ffc Mon Sep 17 00:00:00 2001 From: Rajkumar Date: Wed, 4 Oct 2017 20:06:32 +0530 Subject: [PATCH 08/11] Adding a lpm based tiny router to the mix. --- src/apps/jit_loop/ipv4_apps.lua | 53 +++++++++++++++++++++++++++++++ src/program/jit_loop/jit_loop.lua | 7 ++-- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/apps/jit_loop/ipv4_apps.lua b/src/apps/jit_loop/ipv4_apps.lua index 9d1f2381e5..abf05b4e53 100644 --- a/src/apps/jit_loop/ipv4_apps.lua +++ b/src/apps/jit_loop/ipv4_apps.lua @@ -2,6 +2,8 @@ module(..., package.seeall) local ethernet = require("lib.protocol.ethernet") local receive, transmit = link.receive, link.transmit +local lpm4 = require("lib.lpm.lpm4_trie").LPM4_trie +local ipv4 = require("lib.protocol.ipv4") ChangeMAC = {} @@ -29,3 +31,54 @@ function ChangeMAC:push() end end end + +RouteNorth = {} +local IP_TYPE = 0x0800 +local ARP_TYPE = 0x0806 +local IPICMP_TYPE = 0x01 +local ETH_SIZE = ethernet:sizeof() + +function RouteNorth:new (conf) + local o = {lpm_hash = lpm4:new(), + arp_table = {}, + src_eth = ethernet:pton(conf.src_eth), + eth_pkt = ethernet:new({}), + ippkt = ipv4:new({})} + o.lpm_hash:add_string("16.0.0.1/24", 1) + o.lpm_hash:build() + o.arp_table[1] = ethernet:pton("08:35:71:00:97:14") + return setmetatable(o, {__index = self}) +end + +function RouteNorth:push() + local i = assert(self.input.input, "input port not found") + local o = assert(self.output.output, "output port not found") + + while not link.empty(i) do + local p = link.receive(i) + local result = self:process_packet(p, o) + end +end + +function RouteNorth:process_packet(p, o) + local eth_pkt = self.eth_pkt:new_from_mem(p.data, p.length) + if eth_pkt:type() == IP_TYPE then + local ippkt = self.ippkt:new_from_mem(p.data+ETH_SIZE, ipv4:sizeof()) + if ippkt:protocol() == IPICMP_TYPE then + packet.free(p) + end + local client_ip = ippkt:dst() + local gw_idx = self.lpm_hash:search_string(ipv4:ntop(client_ip)) + if gw_idx == nil then + logger:log("Freeing a packet as index is nil") + packet.free(p) + else + local lookedup_mac = self.arp_table[gw_idx] + eth_pkt:src(self.src_eth) + eth_pkt:dst(lookedup_mac) + link.transmit(o,p) + end + else + packet.free(p) + end +end diff --git a/src/program/jit_loop/jit_loop.lua b/src/program/jit_loop/jit_loop.lua index ee5b6aece6..22aa76f62e 100644 --- a/src/program/jit_loop/jit_loop.lua +++ b/src/program/jit_loop/jit_loop.lua @@ -19,17 +19,20 @@ function run (parameters) local north_mac_config = {src_eth = north_mac, dst_eth = north_next_hop_mac} local south_mac_config = {src_eth = south_mac, dst_eth = south_next_hop_mac} + local south_rt_config = {src_eth = south_mac} + local c = config.new() config.app(c, "south_if", intel.Intel, south_if_config) config.app(c, "north_if", intel.Intel, north_if_config) config.app(c, "north_setmac", ipv4_apps.ChangeMAC, north_mac_config) config.app(c, "south_setmac", ipv4_apps.ChangeMAC, south_mac_config) + config.app(c, "south_rt", ipv4_apps.RouteNorth, south_rt_config) config.link(c, "south_if.output -> north_setmac.input") config.link(c, "north_setmac.output -> north_if.input") - config.link(c, "north_if.output -> south_setmac.input") - config.link(c, "south_setmac.output -> south_if.input") + config.link(c, "north_if.output -> south_rt.input") + config.link(c, "south_rt.output -> south_if.input") engine.configure(c) logger:log ("Engine ready to start processing") From c2da4ae4044acf43f0bc554742c6cda2e510b8ed Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Sun, 5 Nov 2017 08:40:15 +0000 Subject: [PATCH 09/11] Add jit.tracebarrier() primitive Create an execution barrier that a JIT trace cannot cross. During recording, the current trace must end when it reaches a barrier and then a new root trace starts immediately afterwards. This is implemented as a simple "nop" C library function. The existing "trace stitching" mechanism provides the required semantics i.e. stop current trace, call nop function, start new trace with linkage. --- lib/luajit/src/lib_jit.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/luajit/src/lib_jit.c b/lib/luajit/src/lib_jit.c index 1e29d79e05..a6ba770c9a 100644 --- a/lib/luajit/src/lib_jit.c +++ b/lib/luajit/src/lib_jit.c @@ -141,6 +141,12 @@ LJLIB_CF(jit_attach) return 0; } +/* Calling this forces a trace stitch. */ +LJLIB_CF(jit_tracebarrier) +{ + return 0; +} + LJLIB_PUSH(top-5) LJLIB_SET(os) LJLIB_PUSH(top-4) LJLIB_SET(arch) LJLIB_PUSH(top-3) LJLIB_SET(version_num) From bfc8612d437fdf9b8cb3b971645419db3f483833 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Sun, 5 Nov 2017 08:53:15 +0000 Subject: [PATCH 10/11] core.engine: jit.tracebarrier() before each app callback --- src/core/app.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/app.lua b/src/core/app.lua index 9ea416797c..e101db8224 100644 --- a/src/core/app.lua +++ b/src/core/app.lua @@ -82,6 +82,7 @@ end -- Run app:methodname() in protected mode (pcall). If it throws an -- error app will be marked as dead and restarted eventually. function with_restart (app, method) + jit.tracebarrier() -- don't mix engine and apps in traces local status, result if use_restart then -- Run fn in protected mode using pcall. From e8c0808f3315cf28c3a9fa3ecc665f8570d3ad39 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Sun, 5 Nov 2017 13:45:18 +0000 Subject: [PATCH 11/11] core.engine: jit.tracebarrier() after each app callback too --- src/core/app.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/app.lua b/src/core/app.lua index e101db8224..893e251036 100644 --- a/src/core/app.lua +++ b/src/core/app.lua @@ -96,6 +96,7 @@ function with_restart (app, method) else status, result = true, method(app) end + jit.tracebarrier() return status, result end