サイズが重要な場合









アプリケーションのサイズを小さくするタスク、またはサイズとパフォーマンスの適切なバランスを優先するタスクが実行速度よりも優先される場合があります。 このような問題は、特に組み込みシステム向けに開発するときに存在します。 彼らにとって、アプリケーションはメモリサイズが非常に限られた特定のタイプのプロセッサ向けに「シャープ化」されています。つまり、アプリケーションのサイズは最終製品のコストに直接影響します。 さらに、機能を追加して、コード自体の品質を向上させることができます。



インテル®コンパイラーは通常、パフォーマンスを優先し、結果の出力アプリケーションのサイズをほとんど気にしません。 デフォルトでは、最高速度に焦点を合わせます。 開発者のタスクは、アプリケーションの速度と使用するコンパイラー最適化、およびそのサイズの間の適切なバランスを見つけることです。 Intel C / C ++コンパイラには、このバランスを制御し、パフォーマンスよりもアプリケーションのサイズを重要にする多くの機能があります。 これらの可能性を見てみましょう。



少ないほど良い!

コンパイラには特別なオプション-Osがあり、これにより、デフォルトでO2と比較してコードサイズを小さくする最適化を有効にできます。 さらに、最適化レベルをO1に下げると、ベクトル化やその他の最適化を無効にする必要がありますが、サイズが大幅に小さくなります。 それでも、一度にすべてではなく、段階的に最適化をオフにすることをお勧めします。



オプション: -Os (Linux / OS X)および/ Os (Windows)

Visual Studio:最適化>優先サイズまたは速度

+:O2オプションと比較したコードサイズの削減

-:パフォーマンスのわずかな低下



使用しないでください-「炉へ」

デフォルトでは、リンカーはCOMDATセクションのレベルで動作します。 コンパイル中、すべてのコードはオブジェクトファイルの単一セクションに格納されます。これは、リンカーがカットする権利を持たないソリッドブロックです。 結果として、未使用の関数とグローバル変数を削除することはできません。本当に欲しいのです。

ただし、たとえばWindowsの/ Gyオプションを使用して、関数と変数を別々のセクションにパックすることにより、関数レベルのリンクを有効にできます。 この場合、リンカはそれらを個別に操作でき、リンカキー(/ OPT:REF)を使用して、誰も参照していないすべてのエンティティを破棄します(つまり、依存関係グラフが構築され、このグラフに該当しないものはすべて破棄されます) 。 したがって、アプリケーションのサイズを大幅に削減できます。



オプション:-fdata-sections、-ffunction-sections、-WI、-gc-sections(Linux / OS X)および/ Gy / Qoption、link、/ OPT:REF(Windows)

+:実行時に使用したコードのみを残す

-:リンカーのサポートが必要で、リンク時間が長くなる可能性があります



組み込み関数のインライン化を無効にします

通常、関数呼び出しのオーバーヘッドがないため、組み込み関数を使用するコードは高速です。 したがって、コンパイラーは、一部の関数の呼び出しを組み込み関数に置き換えて、パフォーマンスのためにより多くのコードを生成することを好みます。 たとえば、関数abs、strcpy、sinには類似物があります。 これらの組み込み関数の1つ以上のインライン化を無効にできます。



オプション: -fno-builtin [-name] (Linux / OS X)および/ Oi-(/ Qno-builtin-name) (Windows)

Visual Studio:最適化>組み込み関数を有効にする(/ Oi)

+:オブジェクトファイルのコード削減

-:他の最適化が無効になっている可能性があります。 より遅いライブラリ関数が可能です



Intelライブラリを動的にリンクする

Linuxでは、Intelライブラリの静的リンク( -static-intel )をキャンセルして、サイズを増やすことができます。 OS Xでこれを行う場合、変数DYLD_LIBRARY_PATHを設定する必要があります。 -shared-intelオプションは、コンパイラのメモリ動作を制御する-mcmodel = mediumまたは-mcmodel = largeでも有効になります



オプション: -shared-intel (Linux / OS X)

Xcode:ランタイム> Intelランタイムライブラリ

+:パフォーマンスへの影響なし。 すべてのライブラリが使用可能です

-:アプリケーションとともにライブラリを出荷する必要があります



プロシージャー間の最適化を使用します

アプリケーションのサイズを減らすために最適化を有効にする必要があるまれなケース。 IPOを最適化すると、常にインライン化される関数や呼び出されない関数に対してコードが生成されないため、デッドコードが削除されるため、コードサイズを削減できます。

オプション: -ipo (Linux / OS X)および/ Qipo (Windows)

Visual Studio:最適化>プロシージャ間最適化

Eclipse:最適化>プログラム全体の最適化を有効にする



+:パフォーマンスを向上させ、実行可能ファイルのサイズを縮小します

-:バイナリファイルのサイズが大きくなる可能性があります。 最終製品がオブジェクトファイルである場合は推奨されません



レジスタを通過する引数を無効にする

コンパイラには、スタックではなくレジスタを介して引数を渡すことができる最適化があります。 サイズを増やす追加のエントリポイントの作成を回避することにより、無効にすることができます。 このオプションは、32ビットアーキテクチャでのみ使用できます。



オプション: -opt-args-in-regs = none (Linux / OS X)および/ Qopt-args-in-regs:none (Windows)

+:コードサイズの縮小が可能

-:パフォーマンスの低下に関して、コードの削減は大幅に少なくなります。



インライン化をオフにする

インライン化は、関数を呼び出さずにサイズを増やすことでパフォーマンスを改善します。 インライン化を完全に無効にする代わりに、その使用をより細かく制御できる特別な係数を使用します。



オプション: -fno-inline (Linux / OS X)および/ Ob0 (Windows)

/ Qinline-factor = n (0 <= n <100)

Visual Studio:最適化>インライン関数展開

Eclipse:最適化>インライン関数展開

Xcode:最適化>インライン関数展開



+:コードサイズの削減

-:パフォーマンスの低下



例外処理

コンパイラが例外を処理するための特別なコードを作成することを忘れないでください。もちろん、EH(例外処理)セクションのサイズが大きいため、アプリケーションのサイズが大きくなります。 -fno-exceptionsオプションを使用すると、例外処理テーブルの生成を無効にすることができ、例外を生成するアプリケーションには使用できません。 このオプションを使用してコードをコンパイルした場合、たとえばtryブロックなどの例外処理を使用すると、エラーがスローされます。

オプション-fno-asynchronous-unwind-tablesもあり、次の機能のプロモーションテーブルの作成を無効にできます。

-デストラクタでオブジェクトを作成せず、例外をスローできる他の関数を呼び出さないC ++関数

--fexceptionsなしでコンパイルされたC / C ++関数、およびインテル®64アーキテクチャーの場合、-tracebackオプションなしでコンパイルされた

-例外をスローできる他の関数への呼び出しを含まない-fexceptionsでコンパイルされたC / C ++関数



オプション: -fno-exceptions-fno-asynchronous-unwind-tables (Linux / OS X)

+:バイナリのサイズを最大15%削減します

-:アプリケーションの動作が変わる場合があります



ライブラリを使用しません

標準ライブラリを使用しないスタンドアロン環境(独立型環境)で動作するための規則に従うようコンパイラーに指示できるため、コンパイラーはコード内の関数呼び出しのみを生成します。 そのようなアプリケーションの例は、OSのカーネルです。



オプション: -ffreestanding-gnudefaultlibs (Linux / OS X)および/ Qfreestanding (Windows)

+:バイナリファイルのサイズを最大15%削減します

-:ライブラリのコードがアクティブに使用された場合、パフォーマンスが低下する可能性があります



バイナリファイルから文字を削除する

アプリケーションのサイズを気にする場合、バイナリからデバッグ情報とシンボリック情報を捨てることは非常に論理的です。



オプション: --WI、-strip-all (Linux / OS X)

+:大幅なサイズ削減

-:文字の情報がなければ、アプリケーションのデバッグはほとんど不可能です



ベクトル化をオフにする

ベクトル化を完全に無効にすることも、部分的に(ディレクティブを使用して)無効にすることもできます。



オプション: -no-vec (Linux / OS X)および/ Qvec- (Windows)

+:コンパイル時間の大幅な短縮、サイズの縮小

-:パフォーマンスが大幅に低下します。 #pragma novectorディレクティブを使用して、パフォーマンスが重要ではない一部のループのベクトル化を無効にすることができます。



不要な16バイトのアライメント

32ビットアーキテクチャでは、コンパイラは16バイトのアライメントを実行します。これにより、関数が呼び出されたときにスタックをアライメントするための追加の命令を作成できます。 コードに小さな関数が多数ある場合、サイズを大幅に増やすことができます。 オプションを使用

-コードでは、このオプションなしでビルドされた他のライブラリ関数の呼び出しはありません

-SSE命令をサポートせず、正しい結果を得るためのアライメントを必要としないアーキテクチャ向けに、コードが強化されています。

オプション: -falign-stack = guess-4-byte (Linux / OS X 32ビット)

+:追加の命令が不足しているため、コードサイズが削減されます。 命令の数を減らすことでパフォーマンスを向上させることもできます

-:他のライブラリとのリンクと互換性がありません



ループの展開を無効にする

スイープサイクルは、展開係数に比例してサイズを増やすことができます。 この最適化を無効または制限すると、パフォーマンスが低下するため、サイズが小さくなります。 #pragma unrollディレクティブを使用して展開を制御することが可能です。 このオプションは、デフォルトで-Os / -O1で有効になっています。



オプション: -unroll = 0 (Linux / OS X)および/ Qunroll:0 (Windows)

+:コードサイズの削減。 個々のサイクルのスイープを制御する機能

-:他のサイクル最適化も制限される可能性があるため、パフォーマンスが著しく低下する可能性があります



結論として、これらのオプションを段階的に使用することで、アプリケーションのサイズを徐々に小さくすることができ、何らかの方法でパフォーマンスが低下することに注意してください。 主なことは、適切なバランスを見つけることです!



All Articles