const char p_lua[] =
"----------------------------------------------------------------------------\n"
"-- LuaJIT profiler.\n"
"--\n"
"-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.\n"
"-- Released under the MIT license. See Copyright Notice in luajit.h\n"
"----------------------------------------------------------------------------\n"
"--\n"
"-- This module is a simple command line interface to the built-in\n"
"-- low-overhead profiler of LuaJIT.\n"
"--\n"
"-- The lower-level API of the profiler is accessible via the \"jit.profile\"\n"
"-- module or the luaJIT_profile_* C API.\n"
"--\n"
"-- Example usage:\n"
"--\n"
"--   luajit -jp myapp.lua\n"
"--   luajit -jp=s myapp.lua\n"
"--   luajit -jp=-s myapp.lua\n"
"--   luajit -jp=vl myapp.lua\n"
"--   luajit -jp=G,profile.txt myapp.lua\n"
"--\n"
"-- The following dump features are available:\n"
"--\n"
"--   f  Stack dump: function name, otherwise module:line. Default mode.\n"
"--   F  Stack dump: ditto, but always prepend module.\n"
"--   l  Stack dump: module:line.\n"
"--   <number> stack dump depth (callee < caller). Default: 1.\n"
"--   -<number> Inverse stack dump depth (caller > callee).\n"
"--   s  Split stack dump after first stack level. Implies abs(depth) >= 2.\n"
"--   p  Show full path for module names.\n"
"--   v  Show VM states. Can be combined with stack dumps, e.g. vf or fv.\n"
"--   z  Show zones. Can be combined with stack dumps, e.g. zf or fz.\n"
"--   r  Show raw sample counts. Default: show percentages.\n"
"--   a  Annotate excerpts from source code files.\n"
"--   A  Annotate complete source code files.\n"
"--   G  Produce raw output suitable for graphical tools (e.g. flame graphs).\n"
"--   m<number> Minimum sample percentage to be shown. Default: 3.\n"
"--   i<number> Sampling interval in milliseconds. Default: 10.\n"
"--\n"
"----------------------------------------------------------------------------\n"
"\n"
"-- Cache some library functions and objects.\n"
"local jit = require(\"jit\")\n"
"assert(jit.version_num == 20100, \"LuaJIT core/library version mismatch\")\n"
"local profile = require(\"jit.profile\")\n"
"local vmdef = require(\"jit.vmdef\")\n"
"local math = math\n"
"local pairs, ipairs, tonumber, floor = pairs, ipairs, tonumber, math.floor\n"
"local sort, format = table.sort, string.format\n"
"local stdout = io.stdout\n"
"local zone -- Load jit.zone module on demand.\n"
"\n"
"-- Output file handle.\n"
"local out\n"
"\n"
"------------------------------------------------------------------------------\n"
"\n"
"local prof_ud\n"
"local prof_states, prof_split, prof_min, prof_raw, prof_fmt, prof_depth\n"
"local prof_ann, prof_count1, prof_count2, prof_samples\n"
"\n"
"local map_vmmode = {\n"
"  N = \"Compiled\",\n"
"  I = \"Interpreted\",\n"
"  C = \"C code\",\n"
"  G = \"Garbage Collector\",\n"
"  J = \"JIT Compiler\",\n"
"}\n"
"\n"
"-- Profiler callback.\n"
"local function prof_cb(th, samples, vmmode)\n"
"  prof_samples = prof_samples + samples\n"
"  local key_stack, key_stack2, key_state\n"
"  -- Collect keys for sample.\n"
"  if prof_states then\n"
"    if prof_states == \"v\" then\n"
"      key_state = map_vmmode[vmmode] or vmmode\n"
"    else\n"
"      key_state = zone:get() or \"(none)\"\n"
"    end\n"
"  end\n"
"  if prof_fmt then\n"
"    key_stack = profile.dumpstack(th, prof_fmt, prof_depth)\n"
"    key_stack = key_stack:gsub(\"%[builtin#(%d+)%]\", function(x)\n"
"      return vmdef.ffnames[tonumber(x)]\n"
"    end)\n"
"    if prof_split == 2 then\n"
"      local k1, k2 = key_stack:match(\"(.-) [<>] (.*)\")\n"
"      if k2 then key_stack, key_stack2 = k1, k2 end\n"
"    elseif prof_split == 3 then\n"
"      key_stack2 = profile.dumpstack(th, \"l\", 1)\n"
"    end\n"
"  end\n"
"  -- Order keys.\n"
"  local k1, k2\n"
"  if prof_split == 1 then\n"
"    if key_state then\n"
"      k1 = key_state\n"
"      if key_stack then k2 = key_stack end\n"
"    end\n"
"  elseif key_stack then\n"
"    k1 = key_stack\n"
"    if key_stack2 then k2 = key_stack2 elseif key_state then k2 = key_state end\n"
"  end\n"
"  -- Coalesce samples in one or two levels.\n"
"  if k1 then\n"
"    local t1 = prof_count1\n"
"    t1[k1] = (t1[k1] or 0) + samples\n"
"    if k2 then\n"
"      local t2 = prof_count2\n"
"      local t3 = t2[k1]\n"
"      if not t3 then t3 = {}; t2[k1] = t3 end\n"
"      t3[k2] = (t3[k2] or 0) + samples\n"
"    end\n"
"  end\n"
"end\n"
"\n"
"------------------------------------------------------------------------------\n"
"\n"
"-- Show top N list.\n"
"local function prof_top(count1, count2, samples, indent)\n"
"  local t, n = {}, 0\n"
"  for k in pairs(count1) do\n"
"    n = n + 1\n"
"    t[n] = k\n"
"  end\n"
"  sort(t, function(a, b) return count1[a] > count1[b] end)\n"
"  for i=1,n do\n"
"    local k = t[i]\n"
"    local v = count1[k]\n"
"    local pct = floor(v*100/samples + 0.5)\n"
"    if pct < prof_min then break end\n"
"    if not prof_raw then\n"
"      out:write(format(\"%s%2d%%  %s\\n\", indent, pct, k))\n"
"    elseif prof_raw == \"r\" then\n"
"      out:write(format(\"%s%5d  %s\\n\", indent, v, k))\n"
"    else\n"
"      out:write(format(\"%s %d\\n\", k, v))\n"
"    end\n"
"    if count2 then\n"
"      local r = count2[k]\n"
"      if r then\n"
"\tprof_top(r, nil, v, (prof_split == 3 or prof_split == 1) and \"  -- \" or\n"
"\t\t\t    (prof_depth < 0 and \"  -> \" or \"  <- \"))\n"
"      end\n"
"    end\n"
"  end\n"
"end\n"
"\n"
"-- Annotate source code\n"
"local function prof_annotate(count1, samples)\n"
"  local files = {}\n"
"  local ms = 0\n"
"  for k, v in pairs(count1) do\n"
"    local pct = floor(v*100/samples + 0.5)\n"
"    ms = math.max(ms, v)\n"
"    if pct >= prof_min then\n"
"      local file, line = k:match(\"^(.*):(%d+)$\")\n"
"      if not file then file = k; line = 0 end\n"
"      local fl = files[file]\n"
"      if not fl then fl = {}; files[file] = fl; files[#files+1] = file end\n"
"      line = tonumber(line)\n"
"      fl[line] = prof_raw and v or pct\n"
"    end\n"
"  end\n"
"  sort(files)\n"
"  local fmtv, fmtn = \" %3d%% | %s\\n\", \"      | %s\\n\"\n"
"  if prof_raw then\n"
"    local n = math.max(5, math.ceil(math.log10(ms)))\n"
"    fmtv = \"%\"..n..\"d | %s\\n\"\n"
"    fmtn = (\" \"):rep(n)..\" | %s\\n\"\n"
"  end\n"
"  local ann = prof_ann\n"
"  for _, file in ipairs(files) do\n"
"    local f0 = file:byte()\n"
"    if f0 == 40 or f0 == 91 then\n"
"      out:write(format(\"\\n====== %s ======\\n[Cannot annotate non-file]\\n\", file))\n"
"      break\n"
"    end\n"
"    local fp, err = io.open(file)\n"
"    if not fp then\n"
"      out:write(format(\"====== ERROR: %s: %s\\n\", file, err))\n"
"      break\n"
"    end\n"
"    out:write(format(\"\\n====== %s ======\\n\", file))\n"
"    local fl = files[file]\n"
"    local n, show = 1, false\n"
"    if ann ~= 0 then\n"
"      for i=1,ann do\n"
"\tif fl[i] then show = true; out:write(\"@@ 1 @@\\n\"); break end\n"
"      end\n"
"    end\n"
"    for line in fp:lines() do\n"
"      if line:byte() == 27 then\n"
"\tout:write(\"[Cannot annotate bytecode file]\\n\")\n"
"\tbreak\n"
"      end\n"
"      local v = fl[n]\n"
"      if ann ~= 0 then\n"
"\tlocal v2 = fl[n+ann]\n"
"\tif show then\n"
"\t  if v2 then show = n+ann elseif v then show = n\n"
"\t  elseif show+ann < n then show = false end\n"
"\telseif v2 then\n"
"\t  show = n+ann\n"
"\t  out:write(format(\"@@ %d @@\\n\", n))\n"
"\tend\n"
"\tif not show then goto next end\n"
"      end\n"
"      if v then\n"
"\tout:write(format(fmtv, v, line))\n"
"      else\n"
"\tout:write(format(fmtn, line))\n"
"      end\n"
"    ::next::\n"
"      n = n + 1\n"
"    end\n"
"    fp:close()\n"
"  end\n"
"end\n"
"\n"
"------------------------------------------------------------------------------\n"
"\n"
"-- Finish profiling and dump result.\n"
"local function prof_finish()\n"
"  if prof_ud then\n"
"    profile.stop()\n"
"    local samples = prof_samples\n"
"    if samples == 0 then\n"
"      if prof_raw ~= true then out:write(\"[No samples collected]\\n\") end\n"
"      return\n"
"    end\n"
"    if prof_ann then\n"
"      prof_annotate(prof_count1, samples)\n"
"    else\n"
"      prof_top(prof_count1, prof_count2, samples, \"\")\n"
"    end\n"
"    prof_count1 = nil\n"
"    prof_count2 = nil\n"
"    prof_ud = nil\n"
"  end\n"
"end\n"
"\n"
"-- Start profiling.\n"
"local function prof_start(mode)\n"
"  local interval = \"\"\n"
"  mode = mode:gsub(\"i%d*\", function(s) interval = s; return \"\" end)\n"
"  prof_min = 3\n"
"  mode = mode:gsub(\"m(%d+)\", function(s) prof_min = tonumber(s); return \"\" end)\n"
"  prof_depth = 1\n"
"  mode = mode:gsub(\"%-\?%d+\", function(s) prof_depth = tonumber(s); return \"\" end)\n"
"  local m = {}\n"
"  for c in mode:gmatch(\".\") do m[c] = c end\n"
"  prof_states = m.z or m.v\n"
"  if prof_states == \"z\" then zone = require(\"jit.zone\") end\n"
"  local scope = m.l or m.f or m.F or (prof_states and \"\" or \"f\")\n"
"  local flags = (m.p or \"\")\n"
"  prof_raw = m.r\n"
"  if m.s then\n"
"    prof_split = 2\n"
"    if prof_depth == -1 or m[\"-\"] then prof_depth = -2\n"
"    elseif prof_depth == 1 then prof_depth = 2 end\n"
"  elseif mode:find(\"[fF].*l\") then\n"
"    scope = \"l\"\n"
"    prof_split = 3\n"
"  else\n"
"    prof_split = (scope == \"\" or mode:find(\"[zv].*[lfF]\")) and 1 or 0\n"
"  end\n"
"  prof_ann = m.A and 0 or (m.a and 3)\n"
"  if prof_ann then\n"
"    scope = \"l\"\n"
"    prof_fmt = \"pl\"\n"
"    prof_split = 0\n"
"    prof_depth = 1\n"
"  elseif m.G and scope ~= \"\" then\n"
"    prof_fmt = flags..scope..\"Z;\"\n"
"    prof_depth = -100\n"
"    prof_raw = true\n"
"    prof_min = 0\n"
"  elseif scope == \"\" then\n"
"    prof_fmt = false\n"
"  else\n"
"    local sc = prof_split == 3 and m.f or m.F or scope\n"
"    prof_fmt = flags..sc..(prof_depth >= 0 and \"Z < \" or \"Z > \")\n"
"  end\n"
"  prof_count1 = {}\n"
"  prof_count2 = {}\n"
"  prof_samples = 0\n"
"  profile.start(scope:lower()..interval, prof_cb)\n"
"  prof_ud = newproxy(true)\n"
"  getmetatable(prof_ud).__gc = prof_finish\n"
"end\n"
"\n"
"------------------------------------------------------------------------------\n"
"\n"
"local function start(mode, outfile)\n"
"  if not outfile then outfile = os.getenv(\"LUAJIT_PROFILEFILE\") end\n"
"  if outfile then\n"
"    out = outfile == \"-\" and stdout or assert(io.open(outfile, \"w\"))\n"
"  else\n"
"    out = stdout\n"
"  end\n"
"  prof_start(mode or \"f\")\n"
"end\n"
"\n"
"-- Public module functions.\n"
"return {\n"
"  start = start, -- For -j command line option.\n"
"  stop = prof_finish\n"
"}\n"
"\n"
""
;
