[Tarantool-patches] [PATCH luajit v1 11/11] profile: introduce profile parser
Sergey Kaplun
skaplun at tarantool.org
Fri Dec 25 11:41:52 MSK 2020
Hi, Igor!
Thanks for the review!
On 25.12.20, Igor Munkin wrote:
> Sergey,
>
> Thanks for the patch! Please consider my comments below.
>
> On 16.12.20, Sergey Kaplun wrote:
<snipped>
>
> General notes for all comments in the sources below:
> * Write it above the code to be commented
> * Start it with a capital letter
> * End it with a dot
Fixed.
Side note: It seemed to me that we decided offline, to transfer
the code from LuaVela with minimal changes in order to avoid conflicts in
case of patching. I am sorry for my misunderstanding.
>
> >
> > diff --git a/test/misclib-memprof-lapi.test.lua b/test/misclib-memprof-lapi.test.lua
> > new file mode 100755
> > index 0000000..e3663bb
> > --- /dev/null
> > +++ b/test/misclib-memprof-lapi.test.lua
> > @@ -0,0 +1,125 @@
>
> <snipped>
>
> > +local path = arg[0]:gsub('/[^/]+%.test%.lua', '')
> > +local parse_suffix = '../tools/parse_memprof/?.lua;'
> > +package.path = ('%s/%s;'):format(path, parse_suffix)..package.path
>
> This is why I hate patching package.path in sources. There is a patchset
> where I move this suite to another place. Now I see that I need to patch
> this test. OK, we can do nothing with tests for now, so please add a
> FIXME note for these lines to fix the issue via environment variable.
Added, I suppose it should be done in case of this issue [1].
>
> > +
> > +local table_new = require "table.new"
> > +
> > +local bufread = require "bufread"
> > +local memprof = require "parse_memprof"
> > +local symtab = require "parse_symtab"
>
> Typo: Something is wrong with the whitespace above.
Fixed.
Side note: As I see from the Lua developer style guide [2] "also, you
may use alignment". So it's not forbidden. But I take a look inside
LuaJIT <jit.*.lua> modules, for example, and there is no alignment
there. So I suppose we should use LuaJIT internal code style here for
consistency.
P.S: I think it's a good idea to add luacheck-like linter and
clang-format checker (if it is possible to avoid a huge diff) to safe
reviewer's and reviewee's time and formalize LuaJIT coding style guide.
Thoughts?
>
> > +
> > +local TMP_BINFILE = arg[0]:gsub('[^/]+%.test%.lua', '%.%1.memprofdata.tmp.bin')
> > +local BAD_PATH = arg[0]:gsub('[^/]+%.test%.lua', '%1/memprofdata.tmp.bin')
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +
>
> <snipped>
>
> > +local tap = require('tap')
> > +
> > +local test = tap.test("misc-memprof-lapi")
> > +test:plan(6)
>
> Why is the test initialized *here*?
Good question. Moved to the top.
>
> > +
>
> <snipped>
>
> > +local function check_alloc_report(alloc, line, function_line, nevents)
> > + assert(string.format("@%s:%d", arg[0], function_line) == alloc[line].name)
> > + print(nevents, alloc[line].num)
>
> Do you need this print?
No, thank you, removed.
>
> > + assert(alloc[line].num == nevents)
> > + return true
> > +end
> > +
> > +-- Not a directory.
> > +local res, err = misc.memprof.start(BAD_PATH)
> > +test:ok(res == nil and err:match("Not a directory"))
>
> This case can also check so-called "system-dependent error code", right?
Yes, I've already added corresponding test to the branch.
>
> > +
>
> <snipped>
>
> > +local reader = bufread.new(TMP_BINFILE)
> > +local symbols = symtab.parse(reader)
> > +local events = memprof.parse(reader, symbols)
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +
>
> <snipped>
>
> > +-- 1 event -- alocation of table by itself + 1 allocation
> > +-- of array part as far it bigger then LJ_MAX_COLOSIZE (16).
> > +test:ok(check_alloc_report(alloc, 21, 19, 2))
> > +-- 100 strings allocations.
> > +test:ok(check_alloc_report(alloc, 26, 19, 100))
> > +
> > +-- Collect all previous allocated objects.
> > +test:ok(free.INTERNAL.num == 102)
>
> I guess you there is no need to name these magic numbers, but it's
> totally worth to leave a comment describing them.
Fixed.
>
> > +
> > +os.exit(test:check() and 0 or 1)
> > diff --git a/tools/luajit-parse-memprof b/tools/luajit-parse-memprof
> > new file mode 100755
> > index 0000000..b9b16d7
> > --- /dev/null
> > +++ b/tools/luajit-parse-memprof
>
> I believe it's better to implement runner to be installed to the system
> instead of the one to be used in sources. By the way, take a look on the
> way luajit.pc is installed.
Yes, as we discussed offline.
>
> > @@ -0,0 +1,20 @@
>
> <snipped>
>
> > diff --git a/tools/parse_memprof/bufread.lua b/tools/parse_memprof/bufread.lua
> > new file mode 100644
> > index 0000000..d48d6e8
> > --- /dev/null
> > +++ b/tools/parse_memprof/bufread.lua
> > @@ -0,0 +1,143 @@
>
> <snipped>
>
> > +local ffi_C = ffi.C
> > +local band = bit.band
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +
>
> <snipped>
>
> > +
> > +local function _read_stream(reader, n)
> > + local free_size
>
> Minor: It's better to declare this variable where it is used.
Fixed. Thanks!
>
> > + local tail_size = reader._end - reader._pos
>
> <snipped>
>
> > +function M.read_uleb128(reader)
> > + local value = ffi.new('uint64_t', 0)
> > + local shift = 0
> > +
> > + repeat
> > + local oct = M.read_octet(reader)
> > +
> > + if oct == nil then
> > + break
> > + end
>
> I guess this is an exceptional case, isn't it? If we hit this condition
> the ULEB128 value is misencoded, so it's worth to raise an error.
Done.
>
> > +
> > + -- Alas, bit library works only with 32-bit arguments:
> > + local oct_u64 = ffi.new('uint64_t', band(oct, 0x7f))
>
> Please do not use magic number in code.
Fixed. Thanks!
>
> > + value = value + oct_u64 * (2 ^ shift)
> > + shift = shift + 7
> > +
> > + until band(oct, 0x80) == 0
>
> Please do not use magic number in code.
Fixed. Thanks!
>
> > +
> > + return tonumber(value)
> > +end
>
> <snipped>
>
> > diff --git a/tools/parse_memprof/main.lua b/tools/parse_memprof/main.lua
> > new file mode 100644
> > index 0000000..9a161b1
> > --- /dev/null
> > +++ b/tools/parse_memprof/main.lua
> > @@ -0,0 +1,104 @@
>
> <snipped>
>
> > +local bufread = require "bufread"
> > +local memprof = require "parse_memprof"
> > +local symtab = require "parse_symtab"
> > +local view = require "view_plain"
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +
> > +local stdout, stderr = io.stdout, io.stderr
> > +local _s = string
>
> This variable looks excess: it is used once for the lookup below.
Fixed.
>
> > +local match, gmatch = _s.match, _s.gmatch
>
> <snipped>
>
> > +-- Parse arguments.
> > +local function parseargs(args)
> > + -- Process all option arguments.
> > + args.argn = 1
> > + repeat
> > + local a = args[args.argn]
> > + if not a then break end
> > + local lopt, opt = match(a, "^%-(%-?)(.+)")
> > + if not opt then break end
> > + args.argn = args.argn + 1
> > + if lopt == "" then
> > + -- Loop through short options.
> > + for o in gmatch(opt, ".") do parseopt(o, args) end
>
> Please make this loop multiline.
Fixed (and if-then-end blocks too).
>
> > + else
> > + -- Long option.
> > + parseopt(opt, args)
> > + end
> > + until false
> > +
> > + -- Check for proper number of arguments.
> > + local nargs = #args - args.argn + 1
> > + if nargs ~= 1 then
> > + opt_map.help()
> > + end
> > +
> > + -- Translate a single input file.
> > + -- TODO: Handle multiple files?
> > + return args[args.argn]
> > +end
> > +
> > +local inputfile = parseargs{...}
> > +
> > +local reader = bufread.new(inputfile)
> > +local symbols = symtab.parse(reader)
> > +local events = memprof.parse(reader, symbols)
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +
>
> <snipped>
>
> > diff --git a/tools/parse_memprof/parse_memprof.lua b/tools/parse_memprof/parse_memprof.lua
> > new file mode 100644
> > index 0000000..dc56fed
> > --- /dev/null
> > +++ b/tools/parse_memprof/parse_memprof.lua
> > @@ -0,0 +1,195 @@
>
> <snipped>
>
> > +local bit = require 'bit'
> > +local band = bit.band
> > +local lshift = bit.lshift
> > +
> > +local string_format = string.format
> > +
> > +local LJM_MAGIC = 'ljm'
> > +local LJM_CURRENT_VERSION = 2
> > +
> > +local LJM_EPILOGUE_HEADER = 0x80
> > +
> > +local AEVENT_ALLOC = 1
> > +local AEVENT_FREE = 2
> > +local AEVENT_REALLOC = 3
> > +
> > +local ASOURCE_INT = lshift(1, 2)
> > +local ASOURCE_LFUNC = lshift(2, 2)
> > +local ASOURCE_CFUNC = lshift(3, 2)
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +
>
> <snipped>
>
> > +local function link_to_previous(heap, e, oaddr)
> > + -- memory at oaddr was allocated before we started tracking:
> > + if heap[oaddr] then
> > + e.primary[heap[oaddr][2]] = heap[oaddr][3]
>
> Please leave the comment that the key is id and the value is location.
Done.
>
> > + end
> > +end
> > +
> > +local function parse_location(reader, asource)
>
> What about introducing another function for it?
> | local function id_location(addr, line)
> | return string_format('f%#xl%d', addr, line), {
> | addr = addr,
> | line = line,
> | }
> | end
> |
> | local function parse_location(reader, asource)
> | if asource == ASOURCE_INT then
> | return id_location(0, 0)
> | elseif asource == ASOURCE_CFUNC then
> | return id_location(reader:read_uleb128(), 0)
> | elseif asource == ASOURCE_LFUNC then
> | return id_location(reader:read_uleb128(), reader:read_uleb128())
> | end
> | error('Unknown asource '..asource)
> | end
Thanks, applied.
>
> <snipped>
>
> > + local e = events[id]
> > + e.num = e.num + 1
> > + e.alloc = e.alloc + nsize
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +
>
> <snipped>
>
> > + local e = events[id]
> > + e.num = e.num + 1
> > + e.free = e.free + osize
> > + e.alloc = e.alloc + nsize
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +
>
> <snipped>
>
> > + local e = events[id]
> > + e.num = e.num + 1
> > + e.free = e.free + osize
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +
>
> <snipped>
>
> > +local parsers = {
> > + [AEVENT_ALLOC] = {evname = 'alloc', parse = parse_alloc},
> > + [AEVENT_REALLOC] = {evname = 'realloc', parse = parse_realloc},
> > + [AEVENT_FREE] = {evname = 'free', parse = parse_free},
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +}
>
> <snipped>
>
> > +local function ev_header_is_epilogue(evh)
> > + return evh == LJM_EPILOGUE_HEADER
> > +end
>
> This function is excess. Just use this comparison in the condition.
Fixed.
>
> > +
>
> <snipped>
>
> > + local magic = reader:read_octets(3)
> > + local version = reader:read_octets(1)
> > + -- dummy-consume reserved bytes
> > + local _ = reader:read_octets(3)
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +
>
> <snipped>
>
> > diff --git a/tools/parse_memprof/parse_symtab.lua b/tools/parse_memprof/parse_symtab.lua
> > new file mode 100644
> > index 0000000..54e9337
> > --- /dev/null
> > +++ b/tools/parse_memprof/parse_symtab.lua
> > @@ -0,0 +1,88 @@
>
> <snipped>
>
> > +local band = bit.band
> > +local string_format = string.format
> > +
> > +local LJS_MAGIC = 'ljs'
> > +local LJS_CURRENT_VERSION = 2
> > +local LJS_EPILOGUE_HEADER = 0x80
> > +local LJS_SYMTYPE_MASK = 0x03
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +
>
> <snipped>
>
> > +-- Parse a single entry in a symtab: lfunc symbol
> > +local function parse_sym_lfunc(reader, symtab)
> > + local sym_addr = reader:read_uleb128()
> > + local sym_chunk = reader:read_string()
> > + local sym_line = reader:read_uleb128()
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +
>
> <snipped>
>
> > +function M.parse(reader)
> > + local symtab = {}
> > + local magic = reader:read_octets(3)
> > + local version = reader:read_octets(1)
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +
>
> <snipped>
>
> > +
> > + while not reader:eof() do
> > + local header = reader:read_octet()
> > + local is_final = band(header, LJS_EPILOGUE_HEADER) ~= 0
>
> Typo: Something is wrong with the whitespace above.
Fixed.
>
> > +
>
> <snipped>
>
> > --
> > 2.28.0
> >
>
> --
> Best regards,
> IM
[1]: https://github.com/tarantool/tarantool/issues/4862
[2]: https://www.tarantool.io/en/doc/2.5/dev_guide/lua_style_guide/
--
Best regards,
Sergey Kaplun
More information about the Tarantool-patches
mailing list