From a9695f51c4152090c01c027627053f2a34f0b550 Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Wed, 25 May 2016 13:57:42 +0200 Subject: [PATCH] Add get_mempolicy, set_mempolicy NUMA syscalls Calling get_mempolicy() will return an object with "mode" and "mask" keys, corresponding to the two output arguments of the get_mempolicy function. The mask is implemented along the lines of cpu_set, except that it can hold any number of bits, defaulting to the size of a long. set_mempolicy(mode, mask) imposes a mode and possibly a mask as well. --- syscall/linux/c.lua | 7 ++++ syscall/linux/constants.lua | 17 ++++++++++ syscall/linux/syscalls.lua | 12 +++++++ syscall/linux/types.lua | 68 +++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+) diff --git a/syscall/linux/c.lua b/syscall/linux/c.lua index 1ae62cee..841e212b 100644 --- a/syscall/linux/c.lua +++ b/syscall/linux/c.lua @@ -347,6 +347,13 @@ function C.sched_setparam(pid, param) return syscall(sys.sched_setparam, int(pid), void(param)) end +function C.get_mempolicy(mode, mask, maxnode, addr, flags) + return syscall(sys.get_mempolicy, void(mode), void(mask), ulong(maxnode), ulong(addr), ulong(flags)) +end +function C.set_mempolicy(mode, mask, maxnode) + return syscall(sys.set_mempolicy, int(mode), void(mask), ulong(maxnode)) +end + -- in librt for glibc but use syscalls instead of loading another library function C.clock_nanosleep(clk_id, flags, req, rem) return syscall(sys.clock_nanosleep, int(clk_id), int(flags), void(req), void(rem)) diff --git a/syscall/linux/constants.lua b/syscall/linux/constants.lua index c1776f2b..2a968dbf 100644 --- a/syscall/linux/constants.lua +++ b/syscall/linux/constants.lua @@ -3360,6 +3360,23 @@ c.IPT_SO_GET = strflag { REVISION_TARGET = IPT_BASE_CTL + 3, } +c.MPOL_MODE = multiflags { + DEFAULT = 0, + PREFERRED = 1, + BIND = 2, + INTERLEAVE = 3, + LOCAL = 4, + -- TODO: Only the following two flags can be ORed. + STATIC_NODES = 0x80000000, + RELATIVE_NODES = 0x40000000, +} + +c.MPOL_FLAG = multiflags { + NODE = 1, + ADDR = 2, + MEMS_ALLOWED = 4 +} + c.SCHED = multiflags { NORMAL = 0, OTHER = 0, diff --git a/syscall/linux/syscalls.lua b/syscall/linux/syscalls.lua index 261040fa..7f0d9a6e 100644 --- a/syscall/linux/syscalls.lua +++ b/syscall/linux/syscalls.lua @@ -457,6 +457,18 @@ function S.sched_setaffinity(pid, mask, len) -- note len last as rarely used return retbool(C.sched_setaffinity(pid or 0, len or s.cpu_set, mktype(t.cpu_set, mask))) end +function S.get_mempolicy(mode, mask, addr, flags) + mode = mode or t.int1() + mask = mktype(t.bitmask, mask) + local ret, err = C.get_mempolicy(mode, mask.mask, mask.size, addr, c.MPOL_FLAG[flags]) + if ret == -1 then return nil, t.error(err or errno()) end + return { mode=mode[0], mask=mask } +end +function S.set_mempolicy(mode, mask) + mask = mktype(t.bitmask, mask) + return retbool(C.set_mempolicy(c.MPOL_MODE[mode], mask.mask, mask.size)) +end + function S.sched_get_priority_max(policy) return retnum(C.sched_get_priority_max(c.SCHED[policy])) end function S.sched_get_priority_min(policy) return retnum(C.sched_get_priority_min(c.SCHED[policy])) end diff --git a/syscall/linux/types.lua b/syscall/linux/types.lua index efff0a14..21f2feb6 100644 --- a/syscall/linux/types.lua +++ b/syscall/linux/types.lua @@ -1016,6 +1016,74 @@ mt.cpu_set = { addtype(types, "cpu_set", "struct cpu_set_t", mt.cpu_set) +local ulong_bit_count = ffi.sizeof('unsigned long') * 8 +local function ulong_index_and_bit(n) + local i = math.floor(n / ulong_bit_count) + local b = bit.lshift(1ULL, n - i * ulong_bit_count) + return i, b +end + +mt.bitmask = { + index = { + zero = function(mask) ffi.fill(mask, s.bitmask) end, + set = function(mask, node) + if type(node) == "table" then -- table is an array of node numbers eg {1, 2, 4} + for i = 1, #node do mask:set(node[i]) end + return mask + end + if node >= mask.size then error("numa node too large " .. node) end + local i, b = ulong_index_and_bit(node) + mask.mask[i] = bit.bor(mask.mask[i], b) + return mask + end, + clear = function(mask, node) + if type(node) == "table" then -- table is an array of node numbers eg {1, 2, 4} + for i = 1, #node do mask:clear(node[i]) end + return mask + end + if node < mask.size then + local i, b = ulong_index_and_bit(node) + mask.mask[i] = bit.band(mask.mask[i], bit.bnot(b)) + end + return mask + end, + get = function(mask, node) + local i, b = ulong_index_and_bit(node) + if node >= mask.size then return false end + return bit.band(mask.mask[i], b) ~= 0 + end, + }, + __index = function(mask, k) + if mt.bitmask.index[k] then return mt.bitmask.index[k] end + if type(k) == "number" then return mask:get(k) end + error("invalid index " .. k) + end, + __newindex = function(mask, k, v) + if type(k) ~= "number" then error("invalid index " .. k) end + if v then mask:set(k) else mask:clear(k) end + end, + __new = function(tp, tab, size) + -- Round size to multiple of ulong bit count. + if size then + size = bit.band(size + ulong_bit_count - 1, bit.bnot(ulong_bit_count - 1)) + else + size = ulong_bit_count + end + local mask = ffi.new(tp, size / ulong_bit_count, size) + if tab then mask:set(tab) end + return mask + end, + __tostring = function(mask) + local tab = {} + for i = 0, tonumber(mask.size - 1) do + if mask:get(i) then tab[#tab + 1] = i end + end + return "{" .. table.concat(tab, ",") .. "}" + end, +} + +addtype_var(types, "bitmask", "struct {unsigned long size; unsigned long mask[?];}", mt.bitmask) + mt.mq_attr = { index = { flags = function(mqa) return tonumber(mqa.mq_flags) end,