Posted 2018-09-29 19:35:02 GMT
今月も月末にSBCLの新バージョンがリリースされましたが、リリースノートに、
enhancement: identical code (at the machine instruction level)
can now be shared between functions, if explicitly requested.
とあり、どんな機能か気になったので調べてみました。
ちょっと調べても説明もなく良く分からなかったので、githubのコミットログを眺めましたが、fold-identical-code
とかいうのが、その機能のようです。
どう使うのかは、良く分かりませんが、
fold-identical-code
が定義されているsrc/code/icf.lisp
に
;;;; Identical Code Folding (similar to what might be done by a C linker)
とあるのでコードサイズの縮小あたりが狙いなのかもしれません。
とりあえず、下記のような同じ内容の関数を定義してみてからfold-identical-code
を実行してみると、
(progn
(defun foo (x) (+ 42 x))
(defun bar (x) (+ 42 x))
(defun baz (x) (+ 42 x)))(fold-identical-code :aggressive t :print t)
以下のようにずらっと結果が表示されますが、
#<code id=154F2 [1] baz {53FD93CF}> = #<code id=154F0 [1] foo {53FD92AF}>
#<code id=154F1 [1] bar {53FD933F}> = #<code id=154F0 [1] foo {53FD92AF}>
bar
とbaz
はfoo
にまとめられているようです。
使用メモリの削減具合を確認するためにイメージをダンプしてみましたが、135MiBのイメージが、ダンプ時にfold-identical-code
を実行してからダンプすると、134MiBに縮みました。
1%も縮まっていない感じですが、C++等のリンカの最適化を解説しているページによると、重複の削除によって1〜2%縮むと書いてあるものが多いようなので、そんなものなのでしょう。
今の所ドキュメントは整備されておらず、src/code/icf.lispsrc/code/icf.lisp
を読むしかない感じですが、今後整備されていくと思うので期待して待ちたいです。
ちなみに当初自分が期待していたのは、disassemble
した時のインストラクションが同一になるかどうか確かめるユーティリティだったのですが、下記のようにfold-identical-code
の部品であるsb-vm::code-equivalent-p
を使って判定できるようです。
(defun fun-code-equivalent-p (f g)
(sb-vm::code-equivalent-p (list (sb-c::fun-code-header f))
(list (sb-c::fun-code-header g))))(fun-code-equivalent-p #'foo #'bar)
;=> t
ごくたまに欲しい時があって、disassemble
関数の中身を使って自作していましたが、sb-vm::code-equivalent-p
を使った方が正確に判定できるようなので、今後はこちらを使おうかなと思っています。
■
HTML generated by 3bmd in LispWorks 7.0.0