Windows で Qt5 を使ってみて遅くなったと感じたことはありませんか。Qt Quick 2 を使っていて遅い場合は ANGLE が問題になっていることも多いのですが、Widget ベースのアプリではどうでしょうか。qt-project.org の interest メーリングリストで Qt5 が Qt4 に比べて明らかに遅くなっていたという話題が出てましたので、ちょっと紹介してみます。
それからもう一つ、Qt5 に限らないと思いますが MinGW 版のバイナリが Visual Studio 版よりも遅いことについての話とその対策案も紹介します。
Qt 5.0 は Qt 4.8 よりも遅い?
元々の話題はこちら。
QWidget を使ったプログラムが Windows の特にデバッグモードにおいて Qt 4.8 で動かしたときに比べて Qt 5.0.2 では顕著(数倍以上)に遅くなると言うことでした。同様の報告もいくつかあり、Mac 等では発生しない Windows 特有の問題であること、描画の問題ではないことなどが分かりました。
で、肝心の原因はと言うと、どうやら Qt5 で新しくなった QAccessible にあったようです。QAccessible::queryAccessibleInterface() での処理を無くしてみると Qt4 と同様のスピードになったそうです。これに対して、おそらくデバッグ用の出力が影響しているだろう事と、Qt 5.1 で整理しており 5.1 アルファでも改善しているはずと言うことが 返信 されています。Windows 版でパフォーマンスの低下が生じている方はまずは Qt 5.1 系を試してみてはどうでしょうか。
MinGW 版が遅いわけ
Qt4 の時代(あるいはもっと前?)から MinGW 版の Qt のバイナリは Visual Studio 版に比べて遅いことはよく知られていました。これは Qt が使用する MinGW のバイナリ形式(正確には例外のハンドリング形式)に関係があります。これまで、Qt のバイナリパッケージでは SJLJ(SetJump/LongJump) という形式の例外処理方法の MinGW を使用してきました。Windows ではこの他に DW2(DWARF2)-EH(Exception Handling) と SEH(Structured Exception Handling) といった例外処理方法がありますが、SJLJ 方式は例外を throw を使用していない場合でもパフォーマンスに影響が出るため、パフォーマンスが悪いという特徴があります。DW2-EH は DWARF2 というデバッグ用のデータ形式をテーブルとして例外を処理する方法でパフォーマンスは throw が無い場合のパフォーマンスへの影響などはないものの、別の例外処理形式のオブジェクトと混ぜて使用することが出来ないという欠点があります。SEH は Windows のネイティブの例外処理形式なため、gcc では 4.8/x64 でしか対応していません(gcc/x86 で対応していないのは Borland の特許が原因だと言うことですが)。なお、MinGW では SJLJ 形式の場合でもデバッグ情報は DWARF 形式を使用しています。(また、SJLJ, DW2-EH は Windows 特有の形式ではありません)
SJLJ ではパフォーマンスは悪いのですが、DW2-EH でクラッシュするよりもましなため(また SEH は利用できないため)、これまでは SJLJ を使用してきました。これを DWARF or SEH に変更する事への提案が(4月のことですが) development ML でなされています。(きちんと確認は出来ていませんが、5.1.0 beta のバイナリパッケージでは変更されていないようなので、5.1 では変更されないかもしれませんが。)
- [Development] Switch of MinGW toolchain for Qt 5.1
- MinGW-w64 – for 32 and 64 bit Windows
- QTBUG-29653: Significant performance regression in Qt 5.0.1 compiled with MinGW
ちなみに、MinGW 版のバイナリパッケージが大きい原因の一つに DWARF2 のデバッグデータも関連しているようで、これが今後 DWARF4 に置き換わることで MSVC 版とのサイズの差も縮まっていくそうです。
関連事項としまして、MSVCでCDBを使ったデバッグ実行が遅い件について補足させていただききます。
MSVCでビルドした実行ファイルをCDBを使ってデバッグする場合で、
ブレイクポイントで一時停止したりステップ実行するたびに
長い時間待たされる場合は、proファイルに下記の行を追加して
デバッグ時インクリメンタルビルドをオフにすると改善されるケースがあります。
QMAKE_LFLAGS_DEBUG += /INCREMENTAL:NO
詳細は下記の記事(英語)の「Tips & Tricks」を参照ください。
http://wiki.qt.io/Qt_Creator_Windows_Debugging