2012-07-15 3 views
7

制限付きポインタを使用しようとしましたが、問題が発生しました。 以下のプログラムは、問題を提示するための単純なものです。ポインタとインライン化を制限する

calc_functionは3つのポインタを使用します。これらのポインタは制限されているため、 "SHALL"はお互いに別名ではありません。 Visual Studioでこのコードをコンパイルすると、その関数がインライン化されるため、何の理由もなくVisual Studio 2010は修飾子を無視します。インライン展開を無効にすると、コードは(2200msから360msまで)6倍以上高速に実行されます。しかし、プロジェクト全体でもファイル全体でもインライン展開を無効にしたくはありません(すべてのgetterやsetterなどでオーバーヘッドが発生するため、恐ろしいでしょう)。

(唯一の解決策は、これだけの機能のインライン化を無効にすることであるかもしれません?)

私が教えしようとする上部に、内側のループの両方の機能が一時的に制限する資格のポインタを、作成しようとしましたコンパイラは私にエイリアシングがないと約束していますが、コンパイラは私を信じませんし、動作しません。 私もコンパイラの設定を調整しようとしましたが、私が見つけた唯一のものは、インライン展開を無効にすることです。

私はこの最適化の問題を解決するためにいくつかの助けに感謝します。

引数が0 1000 2000であることを忘れないでください。 ユーザインプット/プログラム引数を使用する理由は、コンパイラが存在しないかどうかを知ることができないのはなぜですか?ポインタa、b、cの間のエイリアシング。

#include <cstdlib> 
#include <cstdio> 
#include <ctime> 

// Data-table where a,b,c will point into, so the compiler cant know if they alias. 
const size_t listSize = 10000; 
int data[listSize]; 

//void calc_function(int * a, int * b, int * c){ 
void calc_function(int *__restrict a, int *__restrict b, int *__restrict c){ 
    for(size_t y=0; y<1000*1000; ++y){ // <- Extra loop to be able to messure the time. 
     for(size_t i=0; i<1000; ++i){ 
      *a += *b; 
      *c += *a; 
     } 
    } 
} 
int main(int argc, char *argv[]){ // argv SHALL be "0 1000 2000" (with no quotes) 
    // init 
    for(size_t i=0; i<listSize; ++i) 
     data[i] = i; 

    // get a, b and c from argv(0,1000,2000) 
    int *a,*b,*c; 
    sscanf(argv[1],"%d",&a); 
    sscanf(argv[2],"%d",&b); 
    sscanf(argv[3],"%d",&c); 
    a = data + int(a); // a, b and c will (after the specified argv) be, 
    b = data + int(b); // a = &data[0], b = &data[1000], c = &data[2000], 
    c = data + int(c); // So they will not alias, and the compiler cant know. 

    // calculate and take time 
    time_t start = clock(); 
     funcResticted(a,b,c); 
    time_t end = clock(); 
    time_t t = (end-start); 
    printf("funcResticted  %u (microSec)\n", t); 

    system("PAUSE"); 
    return EXIT_SUCCESS; 
} 
+1

+1良いプロファイリング実践のため。私は書式指定子について不平を言ってはいけません。 P.S. 'clock'は' time_t'ではなく 'clock_t'を返します。 – Hurkyl

+1

オフセットが十分に大きいことを確認して関数呼び出しを監視してください。おそらく、あなたが使ったハックではなく、実際の 'int'変数を使ってオフセットを保存する必要があります。 – Hurkyl

+0

@Hurkyl私は、clock_tとtime_tはどちらも同じものにtypedefであると思っていましたが、あなたは正しいです。 (Btw、私の質問 - 投稿を編集するにはどうすればいいですか?) – Boll

答えて

3

あなたは__declspec(noinline)で関数を宣言した場合、それはインライン化しないことを強制されますが:

http://msdn.microsoft.com/en-us/library/kxybs02x%28v=vs.80%29.aspx

は、手動で関数単位でインライン展開を無効にするには、これを使用することができます。 restrictについては


、コンパイラは、それが望んでいる場合にのみ、それを使用して自由です。コンパイラがそのような最適化を行うのを "騙してみよう"試みると、同じコードのさまざまなバージョンを使いこなすことはやや避けられません。

+0

このソリューションは、問題のテストコードと実際のアプリケーションの両方で動作します。しかし、__declspec(noinline)が非常に大きな呼び出しオーバーヘッドを強いる非常に小さな関数(何度も呼び出される)が制限付きの修飾されたポインタを必要とする場合、いくつかの問題があります。そのため、これを最高の答えとして受け入れることで、私は待っています。 – Boll

+0

ええ、私はあなたが何を意味しているのか知っています。私の推測では、VS2010で使われているポインタエイリアシング解析は関数レベルの粒度でしかないということです。したがって、関数の途中で "生成された"非エイリアシングポインタを区別することはできません。 'restrict'がローカルで宣言されたポインタで使用できるかどうかはわかりません。もしそうであれば、試してみるべきかもしれません。 – Mysticial

+0

あなたはまったく正しいです、そして私は局所的に宣言されたポインタを使用して、制限なしで運がないことを試みました。あなたの "__declspec(noinline)"は最良の解決策であり、私の現在のケース(私のアプリケーション)で動作するので、Answerとして受け入れます。ありがとう。 – Boll

関連する問題