5ちゃんねる ★スマホ版★ ■掲示板に戻る■ 全部 1- 最新50  

■ このスレッドは過去ログ倉庫に格納されています

x86命令の所要クロック計測スレ

1 :デフォルトの名無しさん:04/12/21 15:08:57
PentiumMにて
addpdは4-2(レイテンシ-スループット)
imul 4-1

Pen4、Athlonなどデータを集めてみる

102 :デフォルトの名無しさん:05/02/18 00:51:27
投機実行で上手く先読みされているのかもしれんな
乱数を実数演算で作って書き込んだメモリの特定ビットを参照させたらどうかな

103 :90:05/02/18 04:34:34
測定前に、あらかじめ、乱数値を一通り求めてテーブル化しておいて、

測定中は、テーブルから乱数を読むだけにした方がよくない?

104 :デフォルトの名無しさん:05/02/18 12:22:59
そうするとキャッシュヒットしないメモリアクセスが
入ることになるから、命令実行時間の計測には向かん
のじゃない?

105 :デフォルトの名無しさん:05/02/18 13:40:34
予測アルゴリズムを逆手に取って常に外れ続けるパターンを作ろう

106 :97:05/02/18 14:01:31
とりあえず1氏の実験結果から分岐の処理にかかわるPenMの中の人の動き
を好き勝手想像してみました

妄想1.
分岐予測ミスのチェック、および投機されたパイプラインの破棄
は、分岐より前の、分岐条件の値が確定した時点で行われる。
投機された命令は破棄されるが分岐より前の命令は破棄されない。
このため、分岐予測ミスのペナルティは必ずしもパイプラインの
長さと一致しない。

妄想2.
1.の機構を有効利用のため、分岐先の決定にかかわる命令
(およびそれに依存する命令)は優先的にリオーダされる。

妄想3. 
分岐Aのあとにすぐ分岐Bがあり、分岐Aについてのプロファイル
結果が予測に効果を発揮しない場合、一時的に投機が中断される。
つまりこの状態では分岐のたびに必ずストールする、古典的なCPU
と同じ振る舞いになる。

1.および2.について、もし正しいなら、依存関係のある命令を連発して
分岐条件の決定がクリティカルパスになるようにし、故意に分岐の直前まで
確定させなくしてやると、違った値が出る可能性はあると思う。

3.については、電力馬鹿食いのPen4より更に強力な分岐予測機構を
搭載してまで命令投機の無駄を減らそうとしてるわけだが、
やたら強力な分岐予測機構を積んでもそれが大して役に立たない状態で
無理矢理パイプラインに命令を突っ込み続けてもかえって無駄が多い。
場合に応じて投機自体を止めることは、開発者の語る「投機の無駄を
無くすことで電力の消費を抑える」というアプローチにはなんら矛盾しない。

107 :90:05/02/18 19:17:59
>>104
キャッシュ1ラインが128ビット分でしょ、
で、分岐に使う乱数値が16ビット整数。
キャッシュミスは、最大でも8回のうち一回。

また、テーブルのサイズが過剰でなければ、
作ったテーブルがまだ二次キャッシュ上に残っている間に実行できるから、
キャッシュミスによる影響も小さくなると思う。

少なくとも、レジスタリネームとかでCPUコア内に
データが残ることによる先読みよりは、実行時間の正確さが上がらないかな?

108 :97:05/02/20 01:05:58
1次キャッシュはミスさせるのかよ


つか、MT19937も基本的に4byte×624のテーブル参照(詳しくはソースを見れ)なので
多分PenMのL1データキャッシュ32KBにすっぽり収まると思うのですが。
何ならテーブルを念入りにprefetchやってやるとか?

109 :90:05/02/20 02:38:55
テーブルを大きく取りすぎたら1次キャッシュからはずれてしまうけど、

可能ならば、1次キャッシュから外れない程度の、
小さめのテーブルを使う方が正確にはなると思う。

P4でもPenMでもAthlonXP/64でも、
どれの1次キャッシュにも収まるサイズだと、
比較しやすくていいかな。

110 :1:05/02/22 11:33:56
うかつ、測定ミス。
前置してあるC上で配列に乱数などを入れるコードを変えたときに、
測定対象コードのアライメントが影響受けるということをすっかり忘れていたのだ。

測定はint d[1000]に乱数などを予め入れてから行っているのだが、
実は、同じはずのd[i]=i%2とd[i]=i&1(交互に分岐)のクロック数が違ったので混乱していた。
詳しい原因はわからないが、アライメントの違いで5.5clkと18clkの差が出る。
しかも、コードがアライメントされた16byteに収まっている場合でもこれが起こるのだ。
そういえば、不明な低速化原因が「音楽聴きながらだから」だったこともあったなぁ・・・


なんだか考えたことはここまでのレスでみんな言われてしまったな。
こちらの説明不足も多かった。すんまそん。
乱数は配列に入れて、オールL1ヒットなので問題なし。>>88はギャグだとわかっているよな?
ていうかrand()を予測できる分岐予測があったら神(w
>>101実験サンクス。特定ビットが規則性を持つという一抹の不安は正直あった。

>>99>>102みたいな動的スケジュール説はちょっと考えていた。
>>106を参考に実験しよう(時間ないので後で)。つか普通にOoOするだけでOKな気もする。

PM以外のCPUの話題、ないっすか(むしろそっちが知りたい)。
「測定の環境・スキルはあるが面倒」という人いないかね。汚いけど測定ソース貼る?

結局、無意味なテストコードを速く実行するためのCPUじゃないので、
何かで必要な処理を限界まで最適化して、何がボトルネックかを調べる方がいい気がする。

Prefetchは、分岐とは別に興味があるところ。
L1、L2の帯域・レイテンシやロードバッファ・ストアバッファの数が既知のとき、
連続したメモリに簡単な演算をするのに必要なクロックを計算で出せないだろうか。
ストール中に別の命令を実行するため、リオーダバッファの数も影響しそうだ。

111 :1:05/02/22 11:35:03
さて、新規にコードを書き直してアライメントも揃えてやってみた。
分岐あり5clk、分岐なし10clk。交互が7.5clk、ランダム13.3clk。
素直に計算するとペナルティは11.6clk。ちょっと少ないねえ。
分岐なしではmulを1回余計にやらせるのだが、そのときALUが片方空いてるからか?

そう思って、mulをor*8(4clk)に変えてみたらペナルティ11clk。
で、>>105のP6向けパターンが>>84のリンクにあって、それを食わせると、
ランダムより3clkほど速く、mulのではランダムより1.5clk速いとなっていた。
かなり外してはいるようだがランダムより速い。必ずどころか半分も外してないようだ。
d[i]=i%nでn回に1回分岐方向を変えてみると、過去4回の履歴で予測する傾向はP6と同じ。
しかし、ループ検出器というのがあって(詳細は>>99のリンク先にある)、
これが本来の目的じゃないのに反応して少し精度が上がった感じもする。

次に、発想を変えて、1回だけの分岐で測定。
P6では、前方分岐はしない、後方分岐はすると予測するのがデフォルト。PMもそうだろう。
これはループがないため安定した結果。13〜16clkのペナルティで、ほとんどが14か15clk。
パイプラインの段数はこの辺で間違いないだろう。

ループ検出器の仕様も知りたい。ダウンカウンタの空ループ(lp:dec ecx/jnz lp)は、
P6で2clk/loop。PMではecx=64までは2clk程度で、65から急に速くなる。

μopフュージョンとループ検出器は、PentiumMを知らない頃から欲しかった機能で、
Baniasが出たときには本当に嬉しかった。
>>97、最後の1行。
惚れてる女の悪口言われると気分がよくないものです。
確かにマンデルブロ集合のSSE2ではパワーのなさを痛感したが、あばたもえくぼ。

112 :1:05/02/22 11:37:12
>>106「予測(投機)しない」について。
PentiumMの設計思想は「タスク当たりの必要エネルギー量の最小化」にあり。IPCじゃない。
パイプラインの各段が同じ消費電力(1[電気])で、リーク電流などがないモデルで考えると
予想が半分外れる最悪の状態で、予測をやめると消費電力はどう変わるか。
(全部外れるのは予測器が予測できると勘違いしてる→CPUは最悪と思っていないので除外)
n段のパイプラインでm命令ごとに予測できない分岐が来るとき、2m命令当たりの数字、
予測する:n+2m-1[clk] 2mn+n(n-1)/2[電気]、予測しない:2n+2m-2[clk] 2mn[電気]。
ここで、静的な電力(リーク電流・CPU以外の電気)をa[電気/clk]とすると、
2aがnより小さいなら、予測(投機実行)しない方がタスク当たりの電気を減らせる。
つまり、mには依存せず、システム全体の静的電力が動的電力の半分以下ならいい。
DothanULV-1.1@dynabookSSSXでは、静9W、動4Wだった(静は設定で6.5Wまで減らせる)。
これだと無意味だ。通常電圧版なら、静10W、動20Wとかになるか?これでもギリギリ必要ない。
ひょっとして外れたとき投機実行の破棄のコスト(計算外)がすごいのか?
リオーダバッファの占有率も変わるし、計算モデルが現実とかけ離れていたんだろうな。
ただ、「予測しない」によって電気を節約しても、それで遅くなるのだから、
「クロックと電圧を下げる」という強力な技にはそう簡単には勝てない。
#静:PCアイドル時SpeedStepオフの消費電力。動:「CPU負荷100%、その他は静と同じ(ファンも回さない)」-静

113 :1:05/02/23 10:56:26
>>106の測定結果。
分岐する:15.5clk、分岐しない:30.7clk、ランダム:30.1clk、交互:23.4。
いやピッタリ14.0clkのペナルティです((30.1-(30.7+15.5)/2)*2)。無意識に捏造したな>俺。
これは偶然だが、パイプラインは14〜15段ほぼ決定でいいかな?

俺は106の妄想1が非常に難しく感じられた。パイプラインの長さと一致しないのなら
OoOコアにおけるパイプラインの長さって一体何なんだ、と。
リタイヤはインオーダーだが、命令がリオーダバッファにいる平均clk数を何が規定する?
ひょっとしてリオーダバッファが混んでいるときは実質パイプラインが長くなるのか。
それだと>>81の19clkも納得できる。こじつけ臭いけど。

で、追試。
上の測定はmulを3回、分岐しないと更に3回というコード。mulは実行に時間がかかる命令だ。
そこでこれをadd15回に変えてみた。する:16.3、しない:31.8、ランダム:30.6。
ペナルティ13.1clk(少ないナ)。ここで依存関係をなくすと、ランダム:27.0。30.6-27.0=3.6。
mulの場合は依存関係あり:30.1、なし:27.0だった。差は3.1。
3.6と3.1は、誤差の範囲で一致、だろうか。
mulの方が、長い実行時間中にフェッチ・スケジュールできて差が広がると予想したが外れた。

114 :97:05/02/24 13:15:43
妄想に行き着いた過程を説明いたします。
ちょっと前、Visual C++ + Prosessor Packで、たとえばこんなコード
書いてたとき

/*
MMX系組み込み関数大量
*/
if (i == j) {
//foo
}

最適化ONにしてアセンブラの出力見たら、i == jの評価が
MMX命令の前のほうまで移動してたんです
MMX命令はフラグレジスタを書き換えないから、前のほうに
置くことができるのだ、と。

  じゃあそもそも何でこんなことやるの?

分岐予測・投機実行のないRISCだと分岐毎に必ずストールするのだけど、
いわゆるソフトウェア・パイプライニングというやつで分岐条件を
早めに確定させ、分岐のペナルティを隠蔽するテクニックが使えた。
これと同様の原理が、ひょっとしたらP6コアでも通用するんじゃないかな、と

つまりi == j の評価を先に行うことで分岐のペナルティが無くなるのでは?と。
少なくともゲイツコンパイラはそう判断したのでは?と。

ただし、x86命令は大概命令実行毎にフラグレジスタを書き換える
ような仕様だから、もしそうであっても大抵のケースでは扱いづらい気がする。
Intel謹製のやつだとどういうコードを吐くのかしら

115 :デフォルトの名無しさん:05/02/24 14:07:38
volatile

116 :1:05/03/01 13:26:19
正直、俺は最近アセンブラを“使って”はいない。
プログラミングを始めた頃はカオス・フラクラル系の絵をPenIIとVB5LEで描いていたが、
PenMでFPUを使う(100倍速くなった)今ではマンデルブロ集合も見飽きた。皮肉なものだ。

>>114
なるへそ!妄想1が理解できますた。
ていうか俺がまるっきり106を読めてなかったことに今気づいた。恥ずかすぃ。

110のこれも間違いだな>つか普通にOoOするだけでOKな気もする。
なぜなら、投機実行が「フラグを見ない分岐予測」によってのみ行われるとしたら
フラグが先に確定していても、jccをフェッチした直後には正しいフェッチはできず、
jccを実行して初めて正しいフェッチの場所がわかる。

しかもそのRISCの仕組みは「フラグを見る分岐予測」ですらないのか。
分岐後の命令は、あくまでも確定してからパイプラインに流すのね。

で、実験。
1回の前方分岐・MMXがダミー処理のループ、共にフラグを早く確定させても変化なかった。
(i == j)を先に持ってくるのはi,jの入ってたレジスタを早く解放したいからなど、他にも考えられるが
PMにはなくても、P4やK8ではそういう仕組みが入っているのかもしれない。
まあ、Intelが速くしたいのは、手で書いたアセンブラじゃなくてVC++の吐いたコードだろうけど。

おそらくPMではjccが実行されるまでは投機実行の破棄は行われない。
それでも>>113のように3clkほど速くなることについて考えてみた。
14段のパイプライン、1clkで3命令フェッチ・2命令実行、リオーダバッファ40個と仮定する。
80命令ごとに外れる分岐が来るコードを食わせる。以下、脳内シミュ。

117 :1:05/03/01 13:27:13
time00:今、パイプラインは投機実行を破棄したばかりでからっぽ。
time01:3命令をフェッチ。
time14:パイプラインが埋まる。2命令を実行中。ROB(リオーダバッファ)に3命令。
time15:ROBに3命令入ってくるのに2命令しか出て行かない。ROBに4命令。
time51:ROBに40命令。もう入れないのでパイプラインが一時止まる。
time52:ROBに40命令。2命令ずつ実行中。
time53:分岐を実行、予測ミス発覚。time0に戻る。

80命令を54clkで実行。予測ミスがなければ40clk。ちょうど14clkの損。これじゃダメ。
依存関係を調べて分岐を先に実行する。そのためのROBだ。するとこうなる。

time40:OoO発動。実行できる命令は他にもあるが、フラグに関する命令を先に実行。
time41:そして分岐を実行、予測ミス発覚。ROBに30命令。
time42:投機実行は無駄になったが、ROBには24命令生き残っている。それを2つ実行。
time43:改めて3命令フェッチ。ROBには22命令。内2つ実行中。
time53:ROBの最後の2命令を実行。
time56:パイプラインが埋まる。2命令を実行中。ROB(リオーダバッファ)に3命令。
time84:time42と同じ。

80命令を42clkで実行。2clkしか損してない!
この損はtime54-55でROBが空だったため。ここでネックになったのはROBの数ではない。
命令フェッチの能力だ。フェッチ・デコード能力は過剰でも役に立つんだねえ。
time42-43でROBの命令数が6減っているが、これは2つがtime42に実行され4つが破棄された。

実際は、長いループにランダム分岐を入れてみても、どうしても7〜9clkのペナルティがある。
これが8clk前後で一定なのを説明できる理由が思いつかない。
まさかtime42での4命令のリタイヤごときで8clkはかからないだろうし。
ROBが一杯のときは性能が落ちるのかな。

118 :1:05/03/01 13:31:05
これを考えた後、コンビニに行った。
「またお越し下さいませ」を、おつりを渡す前から言ってる店員を見て、
「そこはインオーダーだろ〜」と思ってしまった。


久しぶりに何か作ろうと思って、ライフゲームをやってみた。
VBのインタプリタで1.8fps。Cで36fps、MMXで57fps、SSEで56fpsだった。
表示部だけだと79fpsなのだが、かなり隠蔽できる気配。グラフィックのclk数はわけわかめ。

SSEは、paddb xmm0,[edx] が16byte alignでなければならないのが痛かった。
レジスタが余っていたのでMMXは1回アンロール、計算部だけならSSEより2割速くなった。
(なのになぜfpsは1しか違わない・・・)

アンロール前のMMXとSSEは互角。MMXをアンロールすると2本束ねてSSEと同じ動作になる。
この状態で、デコーダもメモリアクセスもMMX有利となる(P4だとSSE有利と思う)。

実はSSE2の整数命令主体のコードを書いた経験がほとんどなかったのだが、
やってみると64bitの壁を感じた。MMXが16本あればSSE2整数は要らないと思った。
Load/Storeが128bitいけるCPUじゃないと、本当にただの「2本束ねたMMX」だ。
結局PenMのSSE2整数は、こんな感じ↓
小回り効かない(・A・)イクナイ & レイテンシ隠蔽できる(・∀・)!!イイ


ていうか面白い!昔MMXの256*192くらいで遊んでいたが、今回はXGAをフルに使ってみた。
初期配置を512*1の線にすると、300世代くらいまでフラクタルな感じになる。
菱形に広がるクラスタの縁に沿って列をなし進むグライダーが壮観。
その後もきれいなシンメトリーで、トーラス世界(ねじり)なのでグライダー同士がピタリ激突する。
スレチガイスマソ

119 :デフォルトの名無しさん:05/03/01 22:44:46
うんこ

120 :デフォルトの名無しさん:05/03/01 22:47:22
よくVBで作る気になったね

121 :1:05/03/02 11:34:36
>>120
おいらの基本はVBなので。
アセンブラ直書きが難しいときは、Cで書いてそのコード見ながらアセンブラを書くが、
昔はVBで書いてからCにコンバート、アセンブラ化なんてやってたのう。

nasmでSSEをアセンブルし、VCでDLLを作成、それをVBで呼び出す。
表示するAPIもVBで呼ぶ。てかVCでGUI作れね。


次はアライメントかな。P6では、キャッシュラインをまたぐと9clkほど損した。
ただ、キャッシュラインをまたぎさえしなければズレたアクセスも特に問題はないみたいだった。
P4とかじゃズレたら即死しそうだけど。
(別にP4を貶すわけじゃない。PenMの「性能/電力」の高さは、
絶対性能の低さに甘んじているからだと思うので)

ところで糞P4使いは、いないのかい?
倍速ALUや高スループットのキャッシュ、ぶっちぎりの絶対クロック。
アセンブラレベルでご機嫌とれば、かなり化ける希ガス。
心配なのはライトスルーのL1Dataや等速ALUの遅さ、MMXとFPUは捨ててる感じだし。

122 :デフォルトの名無しさん:05/03/02 14:53:22
>>118
ソースあpしる VBのも

123 :デフォルトの名無しさん:05/03/02 23:25:08
>>116
いや妄想に付き合っていただき感謝
まあゲイツコンパイラの気まぐれの気もしたのだけどね。
GCCもそうなのだけど、PentiumでいうUVパイプライン最適化
ってやつがあんまり利いてないっていうか
ちょっと式が複雑になるとスタックフレーム生成しまくりやがる。
実はcl.exeの最適化エンジンってレジスタ数の多いRISC
由来だったりとか?

最近Prescottマシンに触れる機会があってMMX/SSEバリバリ
のソフトでベンチマークとってみたけど、
同クロックのNorthwoodに比べて、確かに処理能力は落ちてる
のだけど、レイテンシ増大の割にはあんまり低下してないと思った。

NorthwoodでHT enableだとただでさえ小さいL1キャッシュを
分断するので逆効果になるケースがあったけど、
Prescottだとキャッシュの増分、効果は得やすくなったと思う。
ただロード・ストアまわりが・・・

124 :14 ◆TimpoiKAMI :05/03/03 03:48:36
コテ名乗れ。 あぼ〜んできないじゃないか。


>>1
誠にすまんが、このスレはしばらくROMに徹しさせていただく。
進展がないようだったら巡回から外す。

125 :1:05/03/03 10:47:52
>>124
む、それは残念。97よ、おまい何したんだ。
関係ないが、漏れも来週を最後に数週間来られないかもしれん。
何か話し続けといてちょ。

>>122
次来たときうpする。

>>123
コンパイラ作成はかなり大変で、しかたなくメモリアクセスが増えてると思っている。
SIMD対応コンパイラでも大して速くなったという話を聞かないし。
単純なロジックなら人間、複雑な大域最適化はコンパイラじゃないかな。
その辺の知識はないのでハズレかもしれんが。
プレスコは、よりHT向きになった石だね。レイテンシ増はHTで隠蔽できそう。

ところで、だれか上の吉野家コピペに反応してくれ。
けっこう時間かけて作ったんだからさ。

126 :デフォルトの名無しさん:05/03/03 13:15:29
複雑な大域最適化なんて今のコンパイラにはなおのこと荷が重いだろ

127 :デフォルトの名無しさん:05/03/03 13:57:28
10年ぐらい前のmipsコンパイラでも当たり前にやってた
気もするけど。

128 :97:05/03/03 23:28:19
じゃあネタ振りでも
http://www.hackersdelight.org/HDcode.htm
のMMX/SSEを使った高速化について。
とりあえず64×64. 128×128の転置行列を作る。
で、基本的なアイディアとして、

1.サンプルコードと同様、素直にシフトと論理演算の組み合わせ
(原著によれば完全にアンループするとRISCで3886命令程度なるらしい)

2.とりあえず8/16/32bitシフトしてマスクして重ね合わせの部分は
pupk[hl][dwb]でインタリーブすれば同様のことできるじゃん
(去年の4月ごろ考案)

3.そーいやSSEにpmovmskbあるけど、マスク演算無しで
8bitずつビットの間合いを詰められるぜ?(最近おもいつく)

で、気合い入れてコード書いてみた割にはあんまり期待しただけの
パフォーマンスは出なかったのね。
思うに演算ユニットが並列動作してねーんじゃないかと。
まあマイナー命令連発だからな。
8×8bitだとmovqでMMXレジスタに一気にロードしてpmovmskb
+左論理シフトを繰り返す方法がダントツ最速ですた。

てか、このへんの命令ってどんな命令と並列動作できんのかしら?

129 :デフォルトの名無しさん:05/03/04 00:21:27
>>128

MMX演算ユニットって、
用途の限られたユニット二つで構成されてるでしょ?
MMX命令の大半は、どちらか片方でしか動かない。

ちゃんと工夫しないと、並列動作は無理だと思う。

130 :デフォルトの名無しさん:05/03/06 02:55:44
http://homepage1.nifty.com/kaneko/glhair.htm
だれかこいつをスバラシく高速化してみてくれ。得意だろ?

131 :1:05/03/08 13:09:06
>>128
0x80getおめ。
転置行列は2次元FFTで使ったな。Cでそのまま書いて全く最適化してないが。
pmovmskbはビットインバースのインクリメントで見て面白いと思ったが、
「8bit間合いを詰める」とはまた面白い捉え方だ。本当にイイ命令だなあ。

並列実行云々を論ずるのであれば使用CPUを書かないと。
PenMならpmovmskb(MMX)はpaddと同じ負荷しかない(1-1 add/mul)。
K8は3-1 add/mul。これも一応並列実行できるが、デコードが1命令/clkしかできない。
P4は7-2。SSEの128bit pmovmskbも7-2。使えるユニットは1個。P4はMMX自体糞。

思うに128はAthlonを使っていてデコーダがネックになったと見るが、どうか。

>>129
MMXで並列実行できないのは、P6,PM,K7,K8ではmul系同士ぐらいしかないんじゃないかな。
P4のMMX/SSEは、そもそもALU・mov系以外との並列実行ができないのでダメだし。
基本的に、fadd系がaddユニットのみ、fmul・int mul系がmulユニットのみ、ALU・mov系が両方、
という感じだろう。
P4は、2倍速ALUは速いが、SIMDはmov系以外並列実行できない。
というか2つのユニットが合体したものが1つあると言った方が正しいか。
だから、MMXは遅くても、SSE/2では問題にならない。

http://haiiro.info/up2/file/8226.zip
ライフゲーム、うp。自分用フルセット。

>>130
濃緑研究所はなつかしいなあ。初めて行ったのが更新されなくなってからだけど。
SSEをコンパイラまかせにしているんじゃ、遅いだろう。
単純にアセンブラにすれば相当速くなるだろうが、長いアセンブラは頭がこんがらがるのよね。

132 :1:05/03/08 13:10:09
PeniumMのL1Dataはキャッシュラインが64byteになっている。
8KB分のintの総和を求めるコードでロード性能を計測。MMXだと当然8byte/clk。
ここで、アライメントを崩してやる。すると半分の速度(8load/16clk)になった。
MMXレジスタが8byteなので、8(=64/8)回のロードにつき1回キャッシュラインをまたぐ。
つまりキャッシュラインをまたいだ8byteのロードは9clk。P6と同じだ。
またぎさえしなければ一応ペナルティなし。

次に32bitの整数レジスタでやってみる。4byte/clk「弱」。
MMXでは完全に隠蔽できていたループのオーバーヘッドが、なぜか隠せていない。
同様の実験をして、またいだロードはおよそ11clkだったが、addが負荷になっている感じ。
movだけでやるとこれも11じゃなくて9clkっぽい。

そしてSSEのmovdquで実験。結果は9clkより少し大きい感じ。
#8byte alignであればペナルティはない。8byteのloadを2回している状況証拠。
#9clkというのは、(16byteではなく)その8byte loadのこと。

ストアの計測もした。一応ゼロフィルのコード。
movdquだが、おしなべてmovdqa(8byte/clk)の倍遅い。またいだクロックも20clkと倍。
MMXだと普通に8byte/clk。またぐと15clk。clk数が大きくて不安定なのはSSEと同じ。
32bit整数だと10clk。movdも同じだった。


そもそもキャッシュラインをまたいでいるときはどうやって転送しているのだろう。
SSE3にlddquというmovdqu(load)と同等の命令がある。
16byte alignのloadを2回行って合成するため、「またぐ」心配がないのが存在意義。
常に倍のloadをするので、「そもそもが遅い命令である」というのは忘れないように。
さて、わざわざlddquという命令を作ったということは、movdquでまたいだときには
「2回読んで合成」ではないと考えるしかない。
・・・じゃあどうやってんだよ。ダメだと判明してから2回読むから遅いとか?

IntelのP6最適化マニュアルには「6〜12サイクルのストールが生じる」とあった。
対症療法は書いてあるが、原因部分が書いてない。

133 :1:05/03/08 13:11:11
間違い!上で整数レジスタが微妙に遅かったのはeaxにだけ足していたからだ。
MMXではmm0とmm1に分けていた(すみません、ひいきしてました)。
アドレスの計算が依存チェーンを長くしているので普通のOoOじゃ原理的に隠蔽しきれないか?


Prefetchもやってみた。
上述の足し算コードで、paddd xmm0,[esi] の前にprefetcht0 [esi+64]を置く(64byte毎)。
すると、L2は4byte/clkだったのが5.33byte/clkまで上がった。ちょっと感動。
ただ、これが上限である理由がわからない。もっといけるのかな。
キャッシュラインを意識した使い方をする必要がある。

ところが、prefetcht0 [esi+64] をmov eax,[esi+64] で置換したら5.8byte/clkまで上がった!orz
おまいは一体何のためにSSEで実装されたのかと小一時間・・・
それはさておき、L2の真の実力が8byte/clkあるとすれば
prefetcht0 では64byteごとに4clk、mov eax,[ ] では2clkの無駄がある計算だ。
(movは3clkだが、実際にeaxへ転送する1clkを引いてある)

つうかPenMにはHWプリフェッチがあるはずだが、こんなわかりやすい処理でも
HWプリフェッチなしのP6と同じってどないなっとんねん。
・・・と思ったらそれはメモリからL2への話か。確かに、L1へ勝手にフェッチされたら嫌かも。

ライフゲームにprefetcht0使ったが、遅くならないようにするのがやっとだった。
キャッシュラインまたぎまくりだから仕方ないか。
次はL1Dataが8Wayであることの見えるコードでもやろうかね。

134 :デフォルトの名無しさん:05/03/09 01:12:10
キャッシュを考慮したプログラムは興味あったから参考になるなぁ。
ところでプリフェッチは意味ないのかね?

http://www.ueda.info.waseda.ac.jp/~ishizaki/pukiwiki/pukiwiki.php?prefetch%A4%CB%B4%D8%A4%B9%A4%EB%BC%C2%B8%B3
上のページでは効果出てるから使ってみようかと思ってたけど。
Pen4だと効果あるのかな。

135 :1:05/03/09 10:26:41
>>134
プリフェッチは正直わからない。
やらないよりは速いので、効果はちゃんとある。
mov eax,[ ] はeaxを汚染するので、一応prefetcht0の存在意義はあるのだが、
実際の転送を行うmovよりも遅いのは説明がつかない。
転送終わるまで指くわえてるのかな。


>>126
局所的なコードの目的をつかんで必要な命令だけ書くというのは人間の独擅場。
ただ、Cで10行とかになってくるだけで人間アセンブラは思考停止になるので(俺は)、
長いコードでは相対的にコンパイラに負ける。
俺が初めてMMXのライフゲームを作ったときはCコンパイラに負けた。
当時経験が少なかったために冗長なコードしか書けなかったのだ。


16byte境界を表示してくれるアセンブラのエディタが欲しいな。

136 :1:05/03/09 12:29:29
メモリの読み書きは、全てL1キャッシュに対してのみ行われる。
メインメモリからL1への転送は、常にキャッシュライン毎。1ラインをフィルする。
L2は、役割としてはメインメモリと一緒、ひらすらL1へキャッシュラインのバースト転送を行う。

ネタと言えば、
命令キャッシュのアライン・ROBの数・必ず分岐予測を外す方法・L2キャッシュへのプリフェッチ
頭痛くなってくるな。じゃ、さよなら。

137 :デフォルトの名無しさん:05/03/09 19:01:31
今時のCコンパイラは賢いよ。

SIMD命令でも、組み込み命令を使ってコンパイラに最適化させても、かなりの速度が出るよ。

138 :デフォルトの名無しさん:05/03/10 02:19:29
それはVCとかでなんか指定すんの?素人でスマン。

139 :デフォルトの名無しさん:05/03/10 17:45:01
>>138
何も指定しないでいい。

むしろ何か指定すると、最適化が阻害される。

140 :デフォルトの名無しさん:05/03/11 01:50:47
_mm系の命令を普通に使ってるほうがアセンブラでSSE使うより
高速なのかな。

141 :デフォルトの名無しさん:05/03/11 21:19:25
インラインアセンブラで書くと、コンパイラの最適化の対象外になります。

インラインアセンブラで書いた命令だけでなく、その前後までもが最適化されなくなります。
(インラインアセンブラの部分をまたいでの最適化が行われなくなる。)


142 :デフォルトの名無しさん:05/03/12 02:23:20
素人は組み込み関数使っておけって事だね。

143 :デフォルトの名無しさん:05/03/12 03:41:49
そして、
組込み関数をインライン展開する
という一見速くなりそうなオプションは、この場合のみ、逆効果になる。

なぜなら、インライン展開されたコードは最適化されないから。

144 :デフォルトの名無しさん:05/03/12 03:43:49
リリース版だと組込み関数は、そのままSIMD命令になるのに、
デバッグ版だとライブラリ関数の呼び出しになるので、
やってられないくらい動作が遅くなって、デバッグに差し支える。

なので、デバッグ版ではインライン展開してしまったほうが、いいかも・・・。

145 :デフォルトの名無しさん:05/03/12 08:15:03
>>139

おなじVCといっても、LearningEditionとBasicとPrpfessionalで
最適化の規模が段違いでそ

LEでは、確か、まったく最適化してくれないんじゃなかったっけ?

146 :デフォルトの名無しさん:05/03/12 08:28:55
でも今はVC Toolkit 2003(Pro相当)がタダで手に入る。

147 :デフォルトの名無しさん:05/03/12 20:02:25
そうなんだ・・・。

MSDNエンタープライズ版で送られてくるのを使ってたので、エディションの違いは気にしていなかったよ。

148 :デフォルトの名無しさん:05/03/12 21:00:31
>リリース版だと組込み関数は、そのままSIMD命令になるのに、
>デバッグ版だとライブラリ関数の呼び出しになるので、

あぶねー。そんな事しらずにデバッグ版で最適化試すとこだったよ。

149 :97:05/03/13 13:01:58
>>132
> movdqu OR lddqu
その合成処理って例の8ビット単位しかできないシフト演算で実装されてるんじゃねーかなと
思った。なんであんな中途半端な命令の実装にしたのか考えてみたがそれしか思い浮かばない。

MMXのpq[lr]lq×2でもいいから1bit単位のシフトは用意しておくべきだな。
俺多用するから

150 :デフォルトの名無しさん:05/03/13 13:31:42
整数の絶対値命令と丸めモード固定のfist系命令が無いのは許せん

151 :97:05/03/13 15:20:07
すんまそん>>149訂正psrlqとpsllqね。

80 KB
■ このスレッドは過去ログ倉庫に格納されています

★スマホ版★ 掲示板に戻る 全部 前100 次100 最新50

read.cgi ver 05.04.00 2017/10/04 Walang Kapalit ★
FOX ★ DSO(Dynamic Shared Object)