SjLj-EH 遅すぎ
どうもプロファイリングのやり方がマズかったようです。
VC++でもg++でも似た傾向になるだろうと考えていたのですが、Cygwin/MinGWのSjLj例外処理が非常に遅く、プログラム全体のパフォーマンスを低下させていました。
特にCygwinの場合は異常に遅いです。おそらくpthreadエミュレーション絡みの問題だと思います。
というわけで、プロファイラに頼るのは諦めて、地道に調整することに、、、。
昨日の1文字read()に対する最適化は結構効いたので、その辺りをメインでやりました。
Boost.Iostreamsで1文字読み出す場合、boost::iostreams::get()という関数があります。
これは、
srcの型 | 動作 |
---|---|
istream | src.get() |
streambuf | src.sbumpc() |
Source | src.read(s,1) |
という動作になっていて、通常はカスタマイズできません。
どうしてもカスタマイズしたい場合は、
namespace boost { namespace iostreams { template<> struct operations<hamigaki::iostreams::file_source> { static std::char_traits<char>::int_type get(hamigaki::iostreams::file_source& t) { return t.get(); } static std::streamsize read(hamigaki::iostreams::file_source& t, char* s, std::streamsize n) { return t.read(s, n); } static std::streampos seek( hamigaki::iostreams::file_source& t, stream_offset off, BOOST_IOS::seekdir way, BOOST_IOS::openmode) { return t.seek(off, way); } static void close( hamigaki::iostreams::file_source& t, BOOST_IOS::openmode which) { detail::close_impl<closable_tag>::close(t, which); } }; } } // End namespaces iostreams, boost.
のようにすればできますが、このSourceにアダプタを被せたとたん、get()を呼んでくれなくなります。
これは、Boost.Iostreamsがget()のカスタマイズを想定していない(getable_tagのようなものがない)ので、どうしようもありません。
このため、実質boost::iostreams::get()は使い物にならず、1文字ずつ処理したい場合は、自前でバッファリングすることが必要になります。
bit_filter.hppの差分
これで1秒短縮できました。
ツール | 時間 |
---|---|
UNLHA32.DLL | 2.2秒 |
lzh_file_source(昨日のバージョン) | 5.2秒 |
lzh_file_source(バッファリング版) | 4.2秒 |
試しに入力ファイルの内容を全部メモリに読み込んで、null_sinkに書き出すテストをしてみましたが、タイムはほとんど変わらず、I/O周りではこれ以上縮みそうにありません。
Boost.Iostreamsの作り上、この辺りが限界かもしれません。
ちなみに、なぜかFedoraCore5 on VMwareだと2.7秒でした。謎です。