Значит ли это, когда sethook установлен на пустую функцию?

Я пишу небольшую библиотеку профилирования для своего кода lua, основанную на хуках, потому что я не могу использовать ни одну из существующих (политики компании).

Я рассматриваю, имеет ли смысл разрешать всегда работать профилированием по требованию для всех моих сценариев, просто устанавливая для переменной значение true, например.

function hook(event)
  if prof_enabled then
    do_stuff()
  end
end

--(in main context)
debug.sethook(hook, "cr")

Итак, вопрос в том, стоит ли ожидать значительного снижения производительности, если prof_enabled = false и хук всегда установлен? Я не ожидаю точного ответа, а скорее некоторые идеи (может быть, например, переводчик lua ​​будет оптимизировать его в любом случае?)

Я знаю, что лучшим решением было бы установить хук только тогда, когда это необходимо, но я не могу сделать это здесь.

1 ответ

Есть способы сделать это без хуков. Один из способов - заменить интересующие функции "сгенерированной" функцией, которая выполняет профилирование (например, подсчет количества вызовов), а затем вызывает "реальную" функцию. Как это:

-- set up profiling

local profile = {}

-- stub function to profile an existing function

local function make_profile_func (fname, f)
  profile [fname] = { func = f, count = 0 }

  return function (...)
     profile [fname].count = profile [fname].count + 1
     local results = { f (...) }  -- call original function
     return unpack (results)  -- return results
  end -- function
end -- make_profile_func

function pairsByKeys (t, f)
  local a = {}
  -- build temporary table of the keys
  for n in pairs (t) do
    table.insert (a, n)
  end
  table.sort (a, f)  -- sort using supplied function, if any
  local i = 0        -- iterator variable
  return function () -- iterator function
    i = i + 1
    return a[i], t[a[i]]
  end  -- iterator function
end -- pairsByKeys

-- show profile, called by alias

-- non-profiled functions
local npfunctions = {
  string_format = string.format,
  string_rep = string.rep,
  string_gsub = string.gsub,
  table_insert = table.insert,
  table_sort = table.sort,
  pairs = pairs,

  }

function show_profile (name, line, wildcards)

  print (npfunctions.string_rep ("-", 20), "Function profile - alpha order",
         npfunctions.string_rep ("-", 20))
  print ""
  print (npfunctions.string_format ("%25s %8s", "Function", "Count"))
  print ""
  for k, v in pairsByKeys (profile) do
    if v.count > 0 then
      print (npfunctions.string_format ("%25s %8i", k, v.count))
    end -- if
  end -- for
  print ""

  local t = {}
  for k, v in npfunctions.pairs (profile) do
    if v.count > 0 then
      npfunctions.table_insert (t, k)
    end -- if used
  end -- for

  npfunctions.table_sort (t, function (a, b) return profile [a].count > profile [b].count end )

  print (npfunctions.string_rep ("-", 20), "Function profile - count order",
         npfunctions.string_rep ("-", 20))
  print ""
  print (npfunctions.string_format ("%25s %8s", "Function", "Count"))
  print ""
  for _, k in ipairs (t) do
      print (npfunctions.string_format ("%25s %8i", k, profile [k].count))
  end -- for
  print ""

end -- show_profile


-- replace string functions by profiling stub function

for k, f in pairs (string) do
  if type (f) == "function" then
    string [k] = make_profile_func (k, f)
  end -- if
end -- for

-- test

for i = 1, 10 do
  string.gsub ("aaaa", "a", "b")
end -- for
for i = 1, 20 do
  string.match ("foo", "f")
end -- for

-- display results
show_profile  ()

В этом конкретном тесте я вызывал string.gsub 10 раз и string.match 20 раз. Теперь вывод:

--------------------    Function profile - alpha order  --------------------

                 Function    Count

                     gsub       10
                    match       20

--------------------    Function profile - count order  --------------------

                 Function    Count

                    match       20
                     gsub       10

Вы могли бы делать другие вещи, такие как функции времени, если у вас был высокоточный таймер.

Я адаптировал это из поста на форуме MUSHclient, где я также получил точное время.


Какие make_profile_func "Делать" - это сохранять копию исходного указателя функции в повышенном значении и возвращать функцию, которая добавляет ее к счетчику вызовов, вызывает исходную функцию и возвращает ее результаты. Прелесть этого в том, что вы можете опустить накладные расходы, просто не заменяя функции их сгенерированными аналогами.

Другими словами, пропустите эти строки и не будет никаких накладных расходов:

for k, f in pairs (string) do
  if type (f) == "function" then
    string [k] = make_profile_func (k, f)
  end -- if
end -- for

В коде есть некоторая путаница с использованием непрофилированных версий функций, которые используются при создании профилей (в противном случае вы получите немного вводящее в заблуждение чтение).

Другие вопросы по тегам