2016-07-12 12 views
2

私は、sqrt()関数の使用量を多く必要とするテスト用ユーティリティを作成しています。可能な最適化を掘り下げた後、C++でインラインアセンブラを試してみることにしました。コードは次のとおりです。インラインアセンブラのsqrtsdはsqrt()より高速ですか?

#include <iostream> 
#include <cstdlib> 
#include <cmath> 
#include <ctime> 

using namespace std; 

volatile double normalSqrt(double a){ 
    double b = 0; 
    for(int i = 0; i < ITERATIONS; i++){ 
     b = sqrt(a); 
    } 
    return b; 
} 

volatile double asmSqrt(double a){ 
    double b = 0; 
    for(int i = 0; i < ITERATIONS; i++){ 
     asm volatile(
      "movq %1, %%xmm0 \n" 
      "sqrtsd %%xmm0, %%xmm1 \n" 
      "movq %%xmm1, %0 \n" 
      : "=r"(b) 
      : "g"(a) 
      : "xmm0", "xmm1", "memory" 
     ); 
    } 
    return b; 
} 


int main(int argc, char *argv[]){ 
    double a = atoi(argv[1]); 
    double c; 
    std::clock_t start; 
    double duration; 

    start = std::clock(); 

    c = asmSqrt(a); 

    duration = std::clock() - start; 

    cout << "asm sqrt: " << c << endl; 
    cout << duration << " clocks" <<endl; 
    cout << "Start: " << start << " end: " << start + duration << endl; 

    start = std::clock(); 

    c = normalSqrt(a); 
    duration = std::clock() - start; 

    cout << endl << "builtin sqrt: " << c << endl; 
    cout << duration << " clocks" << endl; 
    cout << "Start: " << start << " end: " << start + duration << endl; 
    return 0; 
} 

私は繰り返しの数を設定し、このスクリプトを使用してこのコードをコンパイルしています、プロファイリングを開始し、そしてVIMでプロファイル出力を開きます。

#!/bin/bash 

DEFAULT_ITERATIONS=1000000 

if [ $# -eq 1 ]; then 
    echo "Setting ITERATIONS to $1" 
    DEFAULT_ITERATIONS=$1 
else 
    echo "Using default value: $DEFAULT_ITERATIONS" 
fi 

rm -rf asd 

g++ -msse4 -std=c++11 -O0 -ggdb -pg -DITERATIONS=$DEFAULT_ITERATIONS test.cpp -o asd 

./asd 16 
gprof asd gmon.out > output.txt 
vim -O output.txt 
true 

出力は次のとおりです。

Using default value: 1000000 
asm sqrt: 4 
3802 clocks 
Start: 1532 end: 5334 

builtin sqrt: 4 
5501 clocks 
Start: 5402 end: 10903 
sqrtsd命令は16の平方根をカウントするために、唯一の3802クロックを要し、かつ sqrt()は5501個のクロックを要する理由

質問はありますか? 特定の命令のHW実装と関係がありますか?ありがとうございました。

CPU:

Architecture:   x86_64 
CPU op-mode(s):  32-bit, 64-bit 
Byte Order:   Little Endian 
CPU(s):    4 
On-line CPU(s) list: 0-3 
Thread(s) per core: 2 
Core(s) per socket: 2 
Socket(s):    1 
NUMA node(s):   1 
Vendor ID:    AuthenticAMD 
CPU family:   21 
Model:     48 
Model name:   AMD A8-7600 Radeon R7, 10 Compute Cores 4C+6G 
Stepping:    1 
CPU MHz:    3100.000 
CPU max MHz:   3100,0000 
CPU min MHz:   1400,0000 
BogoMIPS:    6188.43 
Virtualization:  AMD-V 
L1d cache:    16K 
L1i cache:    96K 
L2 cache:    2048K 
NUMA node0 CPU(s):  0-3 
+0

はなぜ* *専用のCPUの命令は、ソフトウェアの実装よりも高速ではないでしょうか? –

+2

'normalSqrt'はループ内で' ITERATIONS'回行うのはなぜですか(そして 'asmSqrt'は1回だけです)? – crashmstr

+1

'asmSqrt'は' normalSqrt'compute 'ITERATIONS'ルーツの間に1つのルートを計算します...おそらくここに問題がありますか? – Holt

答えて

3

浮動小数点演算は考慮が丸めに入れなければなりません。ほとんどのC/C++コンパイラはIEEE 754を採用しているため、平方根などの演算を実行するための「理想的な」アルゴリズムを備えています。それらは自由に最適化することができますが、最後の小数点まで同じ結果を、すべての場合はに戻す必要があります。したがって、最適化の自由は完全ではなく、実際には厳しく制限されています。

あなたのアルゴリズムは、おそらく数字や時間の2つの部分ではオフになっています。これは一部のユーザーにとってはまったく無視できるものですが、他のユーザーにとっては厄介なバグを引き起こす可能性もあるため、デフォルトでは許可されていません。

あなたは標準準拠よりもスピードのために多くの世話をした場合、コンパイラのオプションを使用してチャンスをうかがってみてください。例えばGCCの場合、最初に試してみるのは-funsafe-math-optimizationsです。これは、厳格な標準コンプライアンスを無視した最適化を可能にするはずです。一度それを十分に微調整したら、手作りの実装の速度に近づき、おそらくそれを渡すべきです。

+1

実際にC++自体はIEEE754を採用していませんが、コンパイラはこれを選択します。答えの残りの部分は良いですが。 – SirGuy

+0

'sqrtsd'を使うことはこれまで間違っていたアルゴリズムではありません。それは正確に丸められています。 – harold

+0

ありがとう@GuyGreer、私は私の答えを更新します –

0

他の問題を無視して、特定のフラグを指定してコンパイルしない限り、sqrt()sqrtsdより少し遅い場合もあります。

sqrt()は、潜在的にerrnoと設定する必要があります。その場合は、それをチェックする必要があります。合理的なコンパイラのネイティブな平方根命令にまで沸騰しますが、少しオーバーヘッドがあります。あなたの欠陥テストのようなオーバーヘッドの多くは示されていませんでしたが、まだいくつか。

あなたは、アクションhereでそれを見ることができます。

いくつかのコンパイルフラグは、このテストを抑制する。例えば、GCCの場合、fno-math-errnoおよびffinite-math-only

+0

あなたの答えをありがとう、私は改善することができますので、私とそれらの他の問題を共有してくださいありがとう? –

+0

@ JirkaZahradnik最初のループで平方根の結果を使用する方法では、1平方根以上の平方根が生じることは保証されません。それは一度起こらなければならないが、残りは冗長であり、コンパイラはそれらを削除することができる。 GCC(チートを有効にしない)はループを作成しますが、平方根を事前計算して、意図したよりもはるかに速くループを実行します。まあ、それはあなたが観察したことではありませんが、それは明らかに欠点です。 – harold

関連する問題