awk でプロファイリング

OCamlでプロファイリング - みずぴー日記からですが、gawk には簡単にプロファイリングできる pgawk が付属しています。 これを使うことで簡単にプロファイリングできます。 例えば、ここでは以下のようなプログラムを用意します。

#! /usr/bin/gawk -f
# fact_profile.awk

BEGIN {
    print fact(10);
}

# fact():   階乗を計算する
#   in:     数値
#   out:    入力された数値の階乗を返す
function fact(n) {
    if (n >= 2) {
        return n * fact(n - 1);
    } else {
        return 1;
    }
}

これを実行した際のプロファイリングは以下のようにして取得します。

$ pgawk -f fact_profile.awk
3628800

$ cat awkprof.out
    # gawk profile, created Sun May 17 00:34:54 2009

    # BEGIN block(s)

    BEGIN {
     1      print fact(10)
    }

    # Functions, listed alphabetically

    10  function fact(n)
    {
    10      if (n >= 2) { # 9
     9          return n * fact(n - 1)
     1      } else {
     1          return 1
        }
    }

gawk 以外の場合には経典である「プログラミング言語AWK」に掲載されていますが、以下のプログラムを用意します。 これらはBrian Kernighan から入手できます。

# makeprof - prepare profiling version of an awk program
#   usage:  awk -f makeprof awkprog >awkprog.p
#   running awk -f awkprog.p data creates a
#       file prof.cnts of statement counts for awkprog

    { if ($0 ~ /{/) sub(/{/, "{ _LBcnt[" ++_numLB "]++; ")
      print
    }

END { printf("END { for (i = 1; i <= %d; i++)\n", _numLB)
      printf("\t\t print _LBcnt[i] > \"prof.cnts\"\n}\n")
    }

もうひとつあります。

# printprof - print profiling counts
#     usage:  awk -f printprof awkprog
#     prints awkprog with statement counts from prof.cnts

BEGIN { while (getline < "prof.cnts" > 0) cnt[++i] = $1 }
/{/   { printf("%5d", cnt[++j]) }
      { printf("\t%s\n", $0) }

では実行してみましょう。

$ nawk -f makeprof.awk fact_profile.awk > awkprog.p

$ echo 'awk is good' | nawk -f printprof.awk fact_profile.awk
	#! /usr/bin/gawk -f
	# fact_profile.awk
	
    1	BEGIN {
	    print fact(10);
	}
	
	# fact():   階乗を計算する
	#   in:     数値
	#   out:    入力された数値の階乗を返す
   10	function fact(n) {
    9	    if (n >= 2) {
	        return n * fact(n - 1);
    1	    } else {
	        return 1;
	    }
	}

生成される awkprog.p に END ブロックが含まれるため、echo で標準入力を渡しているだけですので、別に "Awk is better than Perl" でも構いませんが、プロファイリングの内容は '{' の位置にカウンターを仕込んでカウントしているだけのものです。 仕組みとしては単純ですが、こうしたもので十分なプロファイリングができる場合もありますので、プログラムは統一した記述をした方が良さそうです。

プログラミング格言集に Brian Kernighan の言葉があります。 "Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." (デバッグは最初にコードを書くのに比べると倍大変なことだ。つまりできるだけ優れたコードを書いても、簡単にデバッグできるとは限らない。) という言葉ですが、逆に言えばコードをちゃんと書かなければ、デバッグはもっと苦労するということではないでしょうか。

tag_nawk.pngtag_nawk.pngtag_nawk.pngtag_nawk.png