【C++】高速化手法【SSE】2 [転載禁止]©2ch.net
■ このスレッドは過去ログ倉庫に格納されています
C++やインラインアセンブラ、SSEなどによる高速化の手法
について語りましょう。
前スレ
【C++】高速化手法【SSE】
http://peace.2ch.net/test/read.cgi/tech/1130349336/ >>223
理論的にはレジスタを使うほうが乱さないだろうけど、
コンパイラやプロセッサがどうするかは動かしてみないと分からないだろうね。 レジスタに収まるならレジスタの方が良いに決まってる 1次キャッシュに収まるなら他のキャッシュなんて気にする必要は無いと思うんだが
普通のOSで普通のコードを動かすなら、スレッド切り替えによるオーバーヘッドなんて無視できるレベルだし
そんなことを心配するよりも、肝心なコードを気にしようよ
いろんなテクニックを知ってるからコードをアップしてくれれば、小さいループならお役にたてるかも知れない 最近ニコニコ動画に上がってる経済シミュ、生態シミュ動画の人の高速化手法がすごい std::copyってsimd化などの最適化って既にされてるのかな?
sse_copy()とか自作したとして
効果は期待出来る? sse_copyとやらはmemcpy、memmoveと何が違うの? 名前的に、SSEの128bitレジスタを使ってのコピーだろう
memcpyとmemmoveの違いはぐぐればすぐわかる じゃなくて、自作しようとしているSSEでコピーするであろう「sse_copy」と
標準で用意されている「memcpy、memmove」←両方合わせて、とで
何が違うの?という話
当たり前だがmemcpyはCPUがSIMDに対応していれば使うし
カリカリにチューニングしてあるわけだが
sse_copyなど要るの? memcpyはC言語の関数だったか
存在を忘れてた
こいつは最適化入ってるのね
これ使えば良さそうだ
そうする、どうもです 条件にもよるがmemcpyあたりはコンパイラ自身がインライン展開したりする std::copy使っておけばPODならmemcpyかmemmove使うんじゃないの
VS2017のやつはmemmove使ってるな 謎の速度低下で悩んでいたが、キャッシュレイアウトって重要だな。
AVX512で一部分だけ値更新したい時、16バイト読み込んでその位置に64バイト書き戻すようなケース。
そのまま16バイト読み込みで実装すると、読み込み時に16バイト分しかキャッシュがないので、書き込む時に64バイトに拡張というか再配置されて遅くなる。
最初から64バイトで読み出すと、サイズが変化しないので遅くならない。
ついつい、読み出し量が少ない方が速いに違いないと思い込んでしまう罠。 パーシャルライトって奴だな
キャッシュにも有効なのか
昔のPenProの頃の8/16bitレジスタへの書き込み後の32bit読み出しとか
HDDが2T超える頃の4Kセクタのパーティションでの位置ずれとか
信じられないほど遅くなる要因になるもんな え、memcpy()とかstd::copy()ってSIMD使うん??
vectorのコピー遅いから困ってて、カリカリとSIMDで書こうかと思ってたんやけど、手間省けるわ。 コピーが遅いから困っててと言うけれど
どうやって遅いと結論づけたのですか?
本来なら16ms完了するはずなのに29msもかかってしまっている!
とかわかるんですか? ああ、いえいえ、言い方が悪かったですが、
処理時間に占めるコピーの割合が増えてきたので、高速化したいなぁ、と思っただけです。 rep movsbが糞速い
https://srad.jp/~miyuri/journal/569822/
>>REP MOVSはマイクロコードで実装されていて、最初にコピーサイズを見て適するコピーアルゴリズムを決めるセットアップ処理を行なってから
>>実際のコピー処理を始めるようになっている。そのため小さいサイズのコピーではセットアップ時間のオーバーヘッドが無視できないが
>>コピーサイズ(適度に大きいサイズ)とアラインメントの要件とプロセッサの世代の条件を満たすとそこそこの性能が出る。
>
>>プロセッサの世代によって展開されるマイクロプログラムが変わり最適化の度合いも変わってくると。
>>第1世代Core i以降のプロセッサのREP MOVSのマイクロコードは比較的速い。
デコード済みの命令をキャッシュ出来るようになったから、マイクロコード展開命令でも最適化が行われるようになってるみたいだよ。 メモリのレイテンシ、スループットやキャッシュサイズに依存するんだから
ブロック転送命令の最適化は無駄な努力だとインテルは思ってんだろう。 Visual Studio 2017 で
memcpyを調べてみた
x86は rep movs
x64は vmovups 128bit 2パラ16アンロール
オプションでAVX2命令を使うようにしてもかわらず
vmovaps 256bit/512bitの方が速いから
頻繁に使うなら自作した方が良い >>238
キャッシュ可な領域はキャッシュライン単位でDRAMの読み書きが行われるはずだから
キャッシュは関係ないでしょ。 >>246
アライメントのほうだったかも。
境界跨いで更新する時、あらかじめ更新サイズで読み出しておけば、全領域使用可能状態になるが、読み出し半分だと残り分キャッシュ要求発生して遅くなると。 >>247
一定のストライドで読み込んでいれば自動プリフェッチで早めにキャッシュに取り込まれる可能性もあるけど、
DRAMの帯域を圧迫しないようにページ境界をまたいでは機能しないようになってるはずだったので、
AVX512のベクタ長だと、何サイクルか先のループで使うデータをプリフェッチで要求した方がいいかも。 >>248
ありがとう。すでに別件でPrefetchもやってみてるけど、AVX512だとかなり効果があった。 >>249
一時は自動プリフェッチの性能が向上してあまりprefetchの意味がない状態が続いていたけど、
AVX512ともなると1ページ分のデータをループ64回で消費しちゃうんだよな…
DRAMのCASレイテンシをCPUクロックで換算すると結構長いからね。 え?AVX512は手書きprefetchのほうが性能出る?
これまではハードウェアプリフェッチが超優秀で、手書きprefetchはむしろオーバーヘッドになって遅くなる感じだったんだけど。 prefetchはハードウェアにまかせて手書きでclflush入れるのが一番いい感じなんだけど。こんなケースは少数派なのかな。 xeonでavx命令使うと過熱防止のため1ms間、動作クロック下げるなんて聞いてないよ〜(>∀<) ☆ 日本の、改憲を行いましょう。現在、衆議員と参議院の
両院で、改憲議員が3分の2を超えております。
『憲法改正国民投票法』、でググってみてください。国会の発議は
すでに可能です。平和は勝ち取るものです。お願い致します。☆☆ 僕の知り合いの知り合いができたパソコン一台でお金持ちになれるやり方
役に立つかもしれません
グーグルで検索するといいかも『ネットで稼ぐ方法 モニアレフヌノ』
YF4RO 過熱してなくても1ms間、強制的にクロック下げるん? >>257、そうみたいなんですよ
https://pc.watch.impress.co.jp/img/pcw/docs/665/641/html/14.png.html
> AVX命令が実行されるときに、CPUはAVXベースで定義されている
> クロック周波数に一時的に下がって実行し、実行終了後元のベースクロックに戻る
> AVX命令の実行完了後1ms程度で通常(非AVX)動作モードに復帰 AVXが有効な処理なら微妙にクロックが落ちようがどうでもいい クロックが高いのが目的じゃなくて
処理が速いのが目的
その辺がよくわかってないアホがいるみたい Programmable Calculation Unit (嘘) XEON、AVX-512だとさらにクロック下がるぞ
コア数多いとさらにクロック低下するでw
Platinum 8180M 28C 2.5GHz -> 2.1GHz(AVX2) -> 1.7GHz(AVX-512)
Platinum 8153 16C 2.0GHz -> 1.6GHz(AVX2) -> 1.2GHz(AVX-512) そもそも4倍の量が同時に計算できるわけだから
クロックが半分になっても元は取れる クロックが実際は半分にならないから
メリットは高速化 これsum1()とsum2()でだいぶスピード違うんだが、みんな知ってた?
#include<vector>
#include<iostream>
using namespace std;
class Tree{
public:
long long i;
vector<Tree> v;
Tree(){i=0;}
long long sum1(){
long long x=i;
for(vector<Tree>::iterator p=v.begin();p!=v.end();++p)x+=p->sum1();
return x;}
long long sum2(){
long long x=i;
for(auto p:v)x+=p.sum2();
return x;}
};
void big_tree(Tree *t,int d){
t->i=d;
if(d<=0)return;
t->v.push_back(Tree());
t->v.push_back(Tree());
big_tree(&(t->v[0]),d-1);
big_tree(&(t->v[1]),d-1);}
int main(){
Tree t;
big_tree(&t,20);
cout<<t.sum1()<<endl;
cout<<t.sum2()<<endl;
} そりゃ、やってることが違うんだから
同じにしたけりゃ sum2 で for (auto& p: v) にしてみ うお、autoってこんな書き方も出来るのかよw
勉強になりました。 結果は同じだろ? 鬼のように発生するコピーのためにメモリ不足で死なない限りは。 C++は、書いた通りに実行されるだけ。
高速な処理が必要なら、そう実行されるように実装しないと。 まるでC++コンパイラは最適化しないとかデタラメな言い分けだな。 何のためにコピーしてるん? 使い方間違ってんじゃね? reserveせずのpush_backしまくるバカのことじゃね? push_backしまくってもそれほどパフォーマンスは悪化しないように出来てるはずだが
コピーしまくりっていうんだから関数で値渡ししてるとかじゃないか?
いずれにしろC++自体の問題ではない データの並び順やアルゴリズム、...
この辺がパフォーマンスに大きな影響を与える
コンパイラの最適化なんぞ知れてる
その辺を最適化したければガシガシアセンブラだが
その前にいくらでもやることがあるのが普通 メインメモリが相対的に遅くなってきてるので
データの並びは非常に重要
大きなデータはディスクアクセスのような感覚で扱わないとダメ 突っ込みどころもあるが1年前のレスに真面目に返答してるおまえを評価する。 x おまえ
o おまえら
って書こうとしたが
同じ人だった orz 組み込み関数でSIMD命令駆使すれば、しっかり高速化されてキモティー! >>292
アセンブラを使わなくても速度チューニングネタはたくさんあるが
当然最後の手段としてはアセンブラは有効
小さいループに処理が集中してるような処理は
特に効果的
下手くそがアセンブラに手を出すと逆に遅くなったりもするけど >>292
急にどうしたw
レジスタ割り当て面倒くさいから、Intrinsics使うの普通だぞ >>295
>>286が
>コンパイラの最適化なんぞ知れてる
>その辺を最適化したければガシガシアセンブラだが
とか書いてたから
この人10年くらい時間が止まってるよね
64bitと32bitじゃレジスタの数も違うし、SIMDの新命令に対応させるたびに
レジスタ割り付けが全く変わってしまうこともあるのにアセンブラって…
AVXなら3オペランドも使えるから、コンパイラに任せてもコードの質は低下しにくくなってるはず 費用対効果を考えればIntrinsicsでも良いけど
究極の最適化はアセンブラしか無い
IACAを使ったり実測したりしながらパズルする
処理が非常に単純で速度の求められる小規模DSPなんかでも
いまだにそういう開発をする >>297
IACA=Intel Architecture Code Analyzer
ですよね。 SIMDを覚えたての初心者はこんなコードを書きやすい
典型的な糞コード
ループ {
sum = _mm_add_ps(sum, data[i]);
}
>>299
そうです >>298
CPU, GPU, FPGA
それぞれ得意分野が違うから GPUユニットはCPUに乗っけたのだから後はFPGAも乗っけるだけ。
アルテラは既に買収済みだしな。 スパコン分野じゃ固定の計算式はFPGAが一番効率的。そういう意味で地球シミュレータや京はゴミ。
スパコンが必要な分野でCPUのような汎用性などいらない。 今度はスパコンが出て来たか
関わったこともないだろうに
スーパーコンピューターこそ汎用性が必要
ベクトルコンピューターが消えたのも
より汎用性を重視するから
スーパーコンピューターの世界でFPGAが求められてるなら
当然スーパーFPGAが流行ってないと辻褄が合わないわけだけど
流行ってないね 何を言ってるからよく分からないなぁ。
特定の式を大量に速く計算したいという要望に対してなんで汎用性が出てくるの?
汎用性スパコンが1億なら同じ性能で1000万で達成できるんだよ。
しかも汎用性のために可用性が落ちるとか話にならないよ。京見れば分かるでしょ。 FPGAとかスーパーコンピューターとか自分専用とか
具体的な処理を何も語ってないのによくもまあ勝手に前提を作るよなあ
ここはソフトの最適化のスレなんだけど FPGAなんかで妥協しないでASICでも作れば良いよ FPGAだってプログラムでコーディングするんだが・・・。勝手な前提作ってるのはおまえじゃん。
というかSSEでの高速化がOKなら、GPGPU、FPGAもOKだろう。 1年もレスが無かった過疎スレになんでこんな必死な自治厨がいるのだろうw
前スレも10年かけて1スレ消費したんだぞw
おまえは何者だw ID:EqcpRCSG = >>311 = >>313 か?
こんな過疎スレで布教ってw マジおまえここの住人じゃないんだな。 >>312
前に64bitで絶対アドレス使えって書いて突っ込み受けたらファビョってたのいたでしょ
あれと同一人物っぽいんだよなあ
>究極の最適化はアセンブラしか無い
とか書くところとか
午後のこ〜だの開発者たちが動画コーデックの開発しなかったのだって、
MMXは除外しても、SSE2、SSE3、SSSE3、SSE4、SSE4.1、AVX、AVX2、AVX512に加えて、
64bitでは一気に種類が2倍と、次々と登場する新命令ごとに最速のルーチン用意していく手間と、
コードが異なるために特定のCPUでしか発現しないバグがでるリスクが増すこと考えたら、
最速に拘るのが現実的ではなくなったんだよ
彼らとしては妥協したコード書く気はなかっただろうし、興味が失せるのも仕方ないのかもね
AVISynthもインラインアセンブラ使ったプラグインだらけで64bit化に対応できずに放置されてたのが
相当あったけど、自分も64bit化やった経験からも、今更初心者にアセンブラ使えなんて教えんなと言いたい 初心者ならIntrinsicsなんか使わないで素直に汎用性のあるC++で書くかライブラリを使えばいいよ
ここは高速化手法スレだから高速なコードであることは重要
Intrinsicsよりアセンブラの方が高速に書けるのは自明なのでアセンブラの話題は当然出てくる Intrinsicsで32bit/64bitの共通化は出来ても
新命令がでたらどうせ作り直しだよ
新命令に最適化しないならそのままでいいよ
「新命令対応」て謳うのが目的じゃなければ
SSEからAVXの移植もレーン縛りで苦労しただろ?
単純に置き換えなんて出来ない
128bitのまま単に3オペとレジスタ数だけなら簡単だけど
AVX512も同じ
マスクレジスタや新命令を使うなら書き直し アセンブラ狂信者じゃない
Intrinsicsも使う
極限な最適化にはアセンブラが必要ってだけ
まあ当然だ どうせ今後は32bit向けの最適化なんかやらんだろ
だとすると手間の差はレジスタ管理くらい >>320
>だとすると手間の差はレジスタ管理くらい
こんなこと書くようだと大したコードは書けないな
レジスタ割り付けの妙味と面倒さを知らないのなら、別に組み込み関数で書いても構わないだろ >>321
レジスタ割り付けの妙味www
さほど時間をかけなくてもコンパイラよりマシなのは作れるよ
そもそもIntrinsicsの時点でもレジスタ数削減は考えるべきであって
何も考えなきゃIntrinsicsだろうがアセンブラだろうが遅い 詳しい自信があるなら
とりあえず問題ありまくりな>>300の問題点でも語ってみようか ■ このスレッドは過去ログ倉庫に格納されています