コードの最適化
- 定義とプロパティ
- 最適化の種類とレベル
- 最適化するもの
- 最適化の良い結果と悪い結果
- 結論
- PVS-Studio
目次
定義とプロパティ
コードの最適化は、コードの品質と効率を向上させるためのコード変更の任意の方法です。 プログラムは、より小さいサイズになり、より少ないメモリを消費し、より迅速に実行し、またはより少ない入出力操作を実行するように最適化され
最適化方法が遵守すべき基本的な要件は、最適化されたプログラムが非最適化されたバージョンと同じ出力と副作用を持たなければならないという しかし、この要件は、最適化からの利益が、プログラムの動作の変化の可能性のある結果よりも重要であると推定される場合には無視されてもよい。
最適化のタイプとレベル
最適化は、自動オプティマイザまたはプログラマによって実行できます。 オプティマイザは、特殊なソフトウェアツールまたはコンパイラの組み込みユニット(いわゆる最適化コンパイラ)のいずれかです。 最新のプロセッサは、コード命令の実行順序を最適化することもできます。
最適化は、高レベルの最適化と低レベルの最適化に分類されます。 高レベルの最適化は、通常、抽象エンティティ(関数、プロシージャ、クラスなど)を処理するプログラマによって実行されます。)と心の中でシステムの設計を最適化するためのタスクの一般的なフレームワークを保持します。 最適化は、ソースコードの基本構造ブロックのレベルで実行されます-ループ、分岐など -通常、高レベルの最適化とも呼ばれますが、一部の著者はそれらを別の(「中間」)レベルに分類します(N.Wirth?). 低レベルの最適化は、ソースコードがマシン命令のセットにコンパイルされる段階で実行され、自動化された最適化が通常採用されるのはこの段階です。 アセンブラプログラマは、しかし、完璧なマシンは、熟練したプログラマよりもこれをうまく行うことができないと信じています(まだ誰もが貧しいプ
何を最適化するか
手動コード最適化では、最適化をどのように正確に行うべきかを知る必要があるだけでなく、プログラムの特定の部分を最適化すべきかを知る必要があるという別の問題に直面しています。 様々な理由(遅い入力操作、人間のオペレータとコンピュータの作業速度の違いなど)のために、プログラムの実行時間の90%はコードの10%だけを実行するのに費やされます(この文はかなり疑わしい根拠としてパレート原理ではなく投機的ですが、A.Tanenbaumはそれを説得力のあるものにしています)。 最適化には、プログラムの開発に費やした時間とは別に追加の時間がかかるため、プログラム全体を最適化するのではなく、このタイムクリティカルな10%のコードを最適化することに集中することをお勧めします。 これらのコード断片はボトルネックとして知られており、プログラムのさまざまな部分が実行するのにかかる時間を測定できる特別なユーティリテ
しかし、実際には、最適化は通常、”混沌とした”プログラミングの段階の後に行われます(”コピーペースト”、”後で見る”、”この方法でOKです”などのメソッドを含む)ので、最適化、リファクタリング、バグ修正が混在しています。strlen(path)のような”奇妙な”コンストラクトの単純化。c_str())、論理条件のような(a.x!=0&&a.x!=0)というようになります。 プロファイラは、この種の最適化にはほとんど役立ちません。 それにもかかわらず、静的解析ツール、つまり意味エラーを検索するように設計されたツールを使用して、ソースコードの深い分析に依存してこれらの問題を検 上記の奇妙な条件の例からわかるように、エラーの結果として非効率的なコードが表示されることがあります(この例では誤植のように、a.x!=0&&a.y!=0は代わりにする必要があります)。 強力な静的アナライザは、このようなコードの断片を検出し、警告メッセージを生成することによって、それらに注意を引きます。
最適化の良い結果と悪い結果
プログラミングでは、ほとんどすべてが合理性の観点から扱われるべきです-最適化も例外ではありません。 経験の浅いアセンブラプログラマによって書かれたコードは、コンパイラ(Zubkov)によって生成されたコードよりも3-5倍遅いという信念があります。 広く知られているのは、初期の低レベルの最適化(演算子や変数を節約しようとする試みなど)に関するKnuthのフレーズです:「時期尚早の最適化はすべての悪
ほとんどのプログラマは、オプティマイザによって実行される最適化について不平を言うことはありません。 たとえば、関数型言語での末尾呼び出しの最適化など(末尾呼び出しは再帰の特別なケースであり、ループとして表すことができます)。
しかし、マシンコードのレベルで複数の複雑な最適化がコンパイルの大幅なスローダウンを引き起こす可能性があることを理解する必要があります。 一般的なシステム設計の最適化(Wirth)と比較すると、彼らがあなたが得ることを可能にする利点は、あまりにも重要ではないかもしれません。 また、現代の言語は、構文的および意味的な”フリル”をすべて備えており、多くのニュアンスと微妙な点を持っているので、それらに精通していないプロ
たとえば、コンパイラが関数によって返された一時オブジェクトのコピーを回避する場合、C++といわゆる戻り値の最適化を取ります。 コンパイラはコピーを省略するため、このメソッドは”コピー消去”とも呼ばれます。 だから、次のコード:
#include <iostream> struct C { C() {} C(const C&) { std::cout << "A copy was made.\n"; }}; C f() { return C();} int main() { std::cout << "Hello World!\n"; C obj = f();}
複数の出力があるかもしれません:
Hello World!A copy was made.A copy was made.Hello World!A copy was made.Hello World!
奇妙に見えるかもしれませんが、言語標準では、コンストラクタが副作用を持っていても、そのような場合にコピーコンストラクタの呼び出しを省略することができるため、三つのバージョンすべてが有効です(§12.8クラスオブジェクトのコピー、パラグラフ15)。
結論
したがって、可能な限り特殊なユーティリティを使用してプログラムコードを最適化することを常に検討する必要がありますが、これは細心の注意を払って行い、コンパイラから予期しないトリックが発生する可能性があることに備えてください。
PVS-Studio
静的アナライザPVS-Studioには一連の診断が実装されており、コードを最適化できる状況を見つけることができます。 ただし、他の静的アナライザとしてのPVS-Studioは、プロファイリングツールの代替として機能することはできません。 動的プログラムアナライザだけがボトルネックを識別できます。 静的アナライザは、どの入力データプログラムが取得し、どのくらいの頻度で特定のコードが実行されるかを知りません。 そのため、アナライザは、パフォーマンスの向上を保証しないコードのいくつかの”マイクロ最適化”を実装することを提案していると言っています。
考慮された欠点にもかかわらず、PVS-Studio analyzerはプロファイリングツールを補完する優れた機能を果たします。 さらに、最適化に関連するPVS-Studioの警告を扱う場合、コードはしばしばより簡単で短くなります。 この効果については、記事”Tizenコードを例として使用したマイクロ最適化の探索”で詳しく説明しています。