まず、Accelerateフレームワークを使用して周波数分析機能を調整する場合、システムの絶対時間は一貫して反復あたり225msでした。それから昨夜、2つのアレイが宣言される順序を変更しましたが、突然202msになりました。宣言の順序を変更するだけで10%増加するのは、非常識なようです。コンパイラ(最適化するように設定されている)がまだこの解決策を見つけていない理由を誰かが私に説明できますか?
追加情報:ループの前に、ループで使用される配列のセットアップがあります。これは、配列を整数から浮動小数点配列(Accelerateの場合)に変換し、時間配列(16行の長さ)のsinとcosを取得することで構成されます。すべてのfloat配列(8配列x 1000要素)は、関数で最初に宣言されます(パラメーターの健全性チェックの後)。フットプリントの縮小がほとんどないためにパフォーマンスが低下するため、これらは常に同じサイズ(定数によって)と宣言されます。それらをグローバルにすることをテストしましたが、パフォーマンスに変化がないため、コンパイラーはすでにそれを理解していると思います。ループの長さは25行です。
---追加---
はい、「-Os」がフラグです。(とにかくXcodeのデフォルト:最速、最小)
(以下はメモリからのものです。コンパイルしようとしないでください。ストライド(1)などを入れなかったためです。ただし、Accelerate呼び出しはすべてそこにあります)
渡されたパラメーター:inttimearray、intamparray、length、scale1、scale2、amp
float trigarray1[maxsize];
float trigarray2[maxsize];
float trigarray3[maxsize];
float trigarray4[maxsize];
float trigarray5[maxsize];
float temparray[maxsize];
float amparray[maxsize]; //these two make the most change
float timearray[maxsize]; //these two make the most change
vDSP_vfltu32(inttimearray,timearray,length); //convert to float array
vDSP_vflt16(intamparray,amparray,length); //convert to float array
vDSP_vsmul(timearray,scale1,temparray,length); //scale time and store in temp
vvcosf(temparray,trigarray3,length); //cos of temparray
vvsinf(temparray,trigarray4,length); //sin of temparray
vDSP_vneg(trigarray4,trigarray5,length); //negative of trigarray4
vDSP_vsmul(timearray,scale2,temparray,length); //scale time and store in temp
vvcosf(temparray,trigarray1,length); //cos of temparray
vvsinf(temprray,trigarray2,length); //sin of temparray
float ysum;
vDSP_sve(amparray,ysum,length); //sum of amparray
float csum, ssum, ccsum, sssum, cssum, ycsum, yssum;
for (i = 0; i<max; i++) {
vDSP_sve(trigarray1,csum,length); //sum of trigarray1
vDSP_sve(trigarray2,ssum,length); //sum of trigarray2
vDSP_svesq(trigarray1,ccsum,length); //sum of trigarray1^2
vDSP_svesq(trigarray2,sssum,length); //sum of trigarray2^2
vDSP_vmul(trigarray1,trigarray2,temparray,length); //temp = trig1*trig2
vDSP_sve(temparray,cssum,length); //sum of temp array
// 2 more sets of the above 2 lines, for the 2 remaining sums
amp[i] = (arithmetic of sums);
//trig identity to increase the sin/cos by a delta frequency
//vmma is a*b+c*d=result
vDSP_vmma (trigarray1,trigarray3,trigarray2,trigarray4,temparray,length);
vDSP_vmma (trigarray2,trigarray3,trigarray1,trigarray5,trigarray2,length);
memcpy(trigarray1,temparray,length*sizeof(float));
}
---現在の解決策---
私は次のようにいくつかの変更を加えました:
配列はすべて整列されていると宣言され、ゼロにされ(次に説明します)、maxsizeは16の倍数になります
__attribute__ ((align (16))) float timearray[maxsize] = {0};
長さがmaxsize未満の場合、長さを16の最も近い倍数に切り上げて、ループされたすべての関数が16で割り切れる幅で動作するように、すべての配列をゼロにしました。合計。
利点は次のとおりです。
- わずかなパフォーマンスの向上
- 配列宣言の順序に関係なく、速度はほぼ一定です(これは、すべてが大きなブロックではなく、必要になる直前に実行されます)。
- 速度は、16幅の長さ(つまり、241から256、または225から240 ...)でもほぼ一定ですが、以前は、長さが256から255になると、関数のパフォーマンスが3%以上低下していました。
将来的には(おそらくこのコードでは、分析要件はまだ流動的であるため)、スタックの使用量とベクトルの整列/チャンクをさらに考慮する必要があることに気付きました。残念ながら、このコードでは、この関数を一度に複数のオブジェクトから呼び出すことができるため、これらの配列を静的またはグローバルにすることはできません。