6

gcc v4.8.1 の使用

私が行った場合:

//func.hpp

#ifndef FUNC_HPP
#define FUNC_HPP

int func(int);

#endif

//func.cpp

#include "func.hpp"

int func(int x){
    return 5*x+7;
}

//main.cpp

#include <iostream>

#include "func.hpp"

using std::cout;
using std::endl;

int main(){
    cout<<func(5)<<endl;
    return 0;
}

単純な関数でさえfuncインライン化されません。inlineexternstatic、およびプロトタイプおよび/または定義の組み合わせはこれを変更しません__attribute__((always_inline))(明らかに、これらの指定子のいくつかの組み合わせにより、コンパイルおよび/または警告が生成されず、それらについては話されません)。アセンブリ出力にg++ *.cpp -O3 -o runandを使用しています。g++ *.cpp -O3 -Sアセンブリの出力を見ると、まだcall func. 関数を適切にインライン化する唯一の方法は、ヘッダー ファイルにプロトタイプ (おそらく必要ない) と関数の定義を含めることです。ヘッダーがプログラム全体の 1 つのファイルにのみ含まれている場合 (main.cpp例としてのみ含まれている場合)、それはコンパイルされ、関数は必要なくても適切にインライン展開されます。inline指定子。ヘッダーが複数のファイルに含まれる場合、inline指定子は複数の定義エラーを解決するために必要なようであり、それが唯一の目的のようです。関数はもちろん適切にインライン化されています。

だから私の質問は:私は何か間違ったことをしていますか?何か不足していますか?何が起こったとしても:

「コンパイラはあなたよりも賢いです。関数をインライン化する必要がある場合をあなたよりもよく知っています。そして、C 配列を決して使用しないでください。常に std::vector を使用してください!」

- 他のすべての StackOverflow ユーザー

本当に?func(5) を呼び出して結果を表示するほうが、単に 32 を出力するよりも速いのでしょうか? 私は盲目的に崖の端からあなたをフォローします。

記録のために、上記のコードは単なる例です。私はレイ トレーサーを作成しています。数学およびその他のユーティリティ クラスのすべてのコードをヘッダー ファイルに移動し、inline指定子を使用すると、パフォーマンスが大幅に向上しました。一部のシーンでは、文字通り 10 倍高速です。

4

3 に答える 3

10

最近の GCC は、リンク時最適化(LTO)により、コンパイル ユニット全体でインライン化できます。でコンパイルおよびリンクする必要があります-fltoリンク時の最適化とインラインおよびGCC 最適化オプションを参照してください。

(実際には、LTO はリンク時にコンパイラの特別なバリアントによって実行されます。LTOlto1は、オブジェクト ファイル内で、GCC の一部の内部表現をシリアライズすることによって機能します。これは、 によっても使用されますlto1。生成された には、オブジェクト バイナリに加えて GIMPLE 表現が含まれています。また、「フロントエンド」とリンクすると、内部からその GIMPLE 表現が抽出され、ほとんどすべてが再コンパイルされます...)-fltosrc1.csrc1.ogcc -flto src*.olto1src*.o

-fltoコンパイル時とリンク時の両方で明示的に渡す必要があります(これを参照してください)。を使用しているMakefile場合は、試すことができmake CC='gcc -flto'ます。それ以外の場合は、各翻訳単位を eg gcc -Wall -flto -O2 -c src1.c(および同様にsrc2.cetc...) でコンパイルし、すべてのプログラム (またはライブラリ) を次のようにリンクします。gcc -Wall -flto -O2 src1.o src2.o -o prog -lsomelib

-fltoビルドが大幅に遅くなることに注意してください(渡され-O3ないため、明示的に使用する必要があり、リンクする必要もあります)。多くの場合、ビルド時間はほぼ 2 倍になりますが、ビルドされたプログラムのパフォーマンスが 5% または 10% 向上します。場合によっては、より多くの改善を得ることができます。

于 2013-10-22T12:14:48.353 に答える
3

コンパイラは、持っていないものをインライン化することはできません。コードをインライン化するには、関数の本体全体が必要です。

コンパイラは一度に 1 つのソース ファイル (より正確には、一度に 1 つの翻訳単位) に対してのみ動作し、他のソース ファイルとその内容については何も知らないことを覚えておく必要があります。

ただし、リンカーはすべてのコードを認識し、一部のリンカーにはリンク時の最適化を可能にするフラグがあるため、それを実行できる場合があります。

于 2013-10-22T12:14:34.220 に答える