最初の版はLua 5.0を対象にして書かれました。その後のバージョンでも大部分は関連がありますが、いくつかの相違点があります。
4番目の版はLua 5.3を対象としており、Amazonおよび他の書店から入手できます。
この本を購入することで、Luaプロジェクトをサポートすることにも協力していただけます。


23.3 – プロファイル

デバッグライブラリという名前にもかかわらず、デバッグ以外のタスクにも有用です。このような一般的なタスクとして、プロファイリングがあります。時間を計るプロファイルの場合は、Cインターフェイスを使用することをお勧めします。各フックのLuaの呼び出しのオーバーヘッドが高すぎるため、通常は測定が無効になります。ただし、プロファイルの数を数える場合は、Luaコードが適切に機能します。このセクションでは、実行時にプログラム内の各関数を呼び出した回数をリストする、基本的なプロファイラを開発します。

プログラムのメインデータ構造は、関数を呼び出しカウンターに関連付けるテーブル、関数をその名前に関連付けるテーブルです。これらのテーブルのインデックスは関数それ自身です。

    local Counters = {}
    local Names = {}
プロファイリング後に名前データを取得することもできますが、関数のアクティブ時にその名前を取得するとより良い結果が得られることを覚えておいてください。そうすれば、Luaは関数を呼び出しているコードを見てその名前を見つけることができるからです。

ここでフック関数を定義します。その役割は、呼び出されている関数を取得し、対応するカウンタを増やすことです。また、関数名も収集します

    local function hook ()
      local f = debug.getinfo(2, "f").func
      if Counters[f] == nil then    -- first time `f' is called?
        Counters[f] = 1
        Names[f] = debug.getinfo(2, "Sn")
      else  -- only increment the counter
        Counters[f] = Counters[f] + 1
      end
    end
次の手順は、このフックを使用してプログラムを実行することです。プログラムのメインチャンクはファイル内にあり、ユーザーがプロファイラにこのファイル名を引数として指定すると想定します。
    prompt> lua profiler main-prog
このスキームを使用すると、ファイル名がarg[1]になり、フックをオンにして、ファイルを実行します
    local f = assert(loadfile(arg[1]))
    debug.sethook(hook, "c")  -- turn on the hook
    f()   -- run the main program
    debug.sethook()   -- turn off the hook
最後の手順は結果を表示することです。次の関数は関数の名前を作成します。Luaの関数名は不確実なことが多いので、各関数にその場所をペアのファイル:行として追加します。関数が名前を持っていない場合は、その場所だけを使います。関数がC関数の場合、名前だけを使います(場所はありません)。
    function getname (func)
      local n = Names[func]
      if n.what == "C" then
        return n.name
      end
      local loc = string.format("[%s]:%s",
                                n.short_src, n.linedefined)
      if n.namewhat ~= "" then
        return string.format("%s (%s)", loc, n.name)
      else
        return string.format("%s", loc)
      end
    end
最後に、各関数をそのカウンタと一緒に印刷します
    for func, count in pairs(Counters) do
      print(getname(func), count)
    end

セクション10.2で開発したmarkovの例にプロファイラを適用すると、次のような結果が得られます

    [markov.lua]:4 884723
    write   10000
    [markov.lua]:0 (f)     1
    read    31103
    sub     884722
    [markov.lua]:1 (allwords)      1
    [markov.lua]:20 (prefix)       894723
    find    915824
    [markov.lua]:26 (insert)       884723
    random  10000
    sethook 1
    insert  884723
つまり、4行目の匿名関数(allwordsの内で定義されたイテレータ関数)は884,723回呼び出され、write(io.write)は10,000回呼び出されました。

このプロファイラには、出力をソートしたり、より良い関数名を出力したり、出力形式を改善したりと、加えられる改善点がいくつかあります。それにもかかわらず、この基本的なプロファイラはそのままでも役立ち、より高度なツールのためのベースとして使用できます。