ものがたり(旧)

atsushieno.hatenablog.com に続く

XPath optimization

先週はXSLTバグフィックスをやっているはずだったんだけど、どう考えてもXPath最適化の方が仕事になっていた気がする。

まずこの辺を見て、CurrentをClone()しまくっているところを全部MoveTo()に置き換え。これでメモリ使用量が半分くらいになった。すごい。ていうかもともとのmonoのIteratorのXPathNodeIteratorを継承するという今の設計は、明らかにMSのそれより劣っている。この辺は何とかしたいところだ。っていっても、次の最適化の手の届かないところでは、結局Clone()は大増殖しているわけだけど…

次にここにあるpeer & subtree最適化。しかし実際にはコレは期待していたほど効き目は無かった(メモリが2%最適化された)。最初、mono --profileでXSLTMarkした結果を見たら、3GBの使用メモリが230MBになってて「うぉー」と思ったんですが、よくよく見てみたらむしろメモリ使用量が増えてプロファイラの結果がオーバーフローしてたという…

peer & subtree最適化は、簡単に言えば A/B という式について(1)Aをiterateして、(2)そのAの下にあるBをiterateした結果を全て集める、という方式でiterateすることなのだけど、これが問題なく成立する状況は限られているので、問題のない場合だけそれを行いなさい、という話(ていうか説明書きが簡単なだけで内容は全然簡単じゃねーし)。

で、何でこれがさほど効かなかったかというと、僕の既存の実装(もう実にうまそうなスパゲティ)がより幅広いターゲットで最適化を試みていたからだ。既存のコードでは、Aを進めてBがiterateしても、問答無用で次のAを見に行って、それをもとにBをiterateして、ノードが存在したら、この位置関係を比較して、先にある方を返す、という方法をとっている。これだとAとBがid()やkey()のようなunorderedな式でもない限り、問題なくノードが回収できる。

この方式の問題は、スパゲティなので非常にerror-proneであるということと、1回のiterationにかかるコストは、Clone()しない点を除いてはあまり宜しくないということか。

しかしpeer&subtreeが2%程度しかメモリ効率を改善できなかったことと、この方式でpeer&subtreeがサポートしない範囲(たとえばA//B/C)が最適化出来ていることを考えると、それほど悪くないアイディアであったかもしれない。

で、昨日はさらにconstant foldingも実装していたのだけど、まだ全然最適化されていない。思うにこれはXSLTのinstructionレベルでも最適化しないと、つまり<xsl:if test="true()">みたいなのも最適化しないと、実質的にはほとんど意味がないだろう。これはXPathExpressionのレベルだけではなく、XsltContext(というかXslTransform用の内部コンテキスト)を使わないと、xsl:variableのconstant foldingが出来ないから、まだ先の話だ。

しかし何つーか、XPathExpression.SetContext()っていう設計はどうにかならなかったんか。これ、参照が残るからすげーGCによろしくないと思うんですけど。