トップ 最新 追記

U-memo

2006|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|08|
2009|08|10|
2010|02|03|
2011|11|12|
2012|04|
2016|02|
All= / Today= / Yesterday=

2008-04-09 [長年日記]

_ [プロセッサ] Intel x86 CPU の最近の命令フェッチ機構

(Ando's Processor Information の「最近の話題 2008年4月5日」経由)

ここでは LSD (Loop Stream Decoder) の話題を拾う。 そもそも実装されたのは Core2 (Conroe/Merom世代)。

たとえば IBM の POWER シリーズプロセッサのような、ある命令フェッチ機動と同時に分岐予測まで行って次のサイクルには分岐先アドレスを予測できる構造を取っている場合には(省電力をのぞいて)LSDなんて考え方は不要。 分岐予測のロスが無いんだから。

# とはいえキャッシュラインを跨ぐケースはあるので全くロスがないわけでは無い。やれば効果はある(はず)。

分岐予測のため野記憶バッファが大きくて、分岐先アドレスの予測が即座にできない場合に効果が出てくる。特に

loop:
 mov eax,[ecx]
 add ecx,1
 cmp eax,0
 jnz loop
 ...
(命令はとてもてきとう)

のような短いループ構造の場合、 実行系は1ループが1サイクルのスループットで並列処理が出来てしまう のに対し、分岐予測は (命令フェッチアドレス生成 -> 分岐予測アドレス生成) に2サイクル掛かるとすると、分岐予測先のアドレスを待つために(毎回同じアドレスなのにね!)、実行系の半分のスループットしか出ないことになる。 つまり命令フェッチ側がボトルネックになる。

# パイプラインを書かないとイメージしにくいかも。

ゆえに、「(短い)ループと分かっているなら」分岐予測を省いてしまってその後ろのバッファからばがばかと繰り返し供給してやればよい、となる。 x86 のような CISC マシンはデコードも重いので Nehalem ではデコーダの後ろにまで持っていっただけ。

というのが基礎的な話題。

しかし触れられていない厄介な話題として、CISC アーキテクチャ特有の話として、命令書き換え(が可能)がある。

# RISC CPUは大抵は明示的に専用のフラッシュ命令を実行しない限りは命令書き換えしたことを反映しなくていいことになっているので、問題は限定的。

loop:
 mov [ecx],0x90909090  ; 0x90 は nop の機械語コード
 add ecx,100
 jmp loop
 ...

たまたま 0x90 をメモリに書いたその先がこのループ命令列の jmp 命令 だった場合、 (条件はあるものの) jmp ではなく書き換えた後の nop を実行する(つまりループが終わる) 必要がある。

毎回命令フェッチを実行することでキャッシュにとりに行っていれば、 書き換えも反映されるはず(というようにキャッシュは設計されている)わけだが、 LSD の仕掛けではデコーダーの前後にある命令バッファを書き換えてやるとか、パイプラインをフラッシュして命令フェッチからやりなおすとか、してやらないといけない (命令セットアーキ違反になる)。 制御の方法はいくつか考えられるけれど、これは結構困難なことだったりする。

単純にアドレスを覚えて一致検出をするにしても、仮想アドレス(Virtual Address) で命令フェッチするのに、仮想アドレスが違うのにたまたま物理アドレス(Physical Address) が一致しているようなところに書き込まれた ケースまで含めて書き換えを認識する必要があるのだ。

MMU は大抵キャッシュ側にくくりつけられていて命令バッファの近くにはないので、面倒臭いことこの上ない。かといって大雑把にやりすぎると逆に足を引っ張るはずなのだが...。

# 単純にストア命令がいるときはあきらめるというのが手っ取り早い解決方法ではある。それでも周辺に影響は有るが。


2008-04-22 [長年日記]

_ [プロセッサ] Nehalem の LSD はバッファかトレースキャッシュか

当サイト的な分析であるが、大原先生の言うとおりこのバッファが質的には事実上のトレースキャッシュである点は間違いないだろう。 理由は簡単で、同記事にもあるとおり単なるバッファならFIFOバッファであるべきところをファーストループに沿って再実行できる点と、x86ではなくμOPsを保存することでデコードを省略している点から読み取る事ができる。トレースキャッシュの本質は「デコードと実行をデカップルすること」にあるわけだから、LSDはその条件を満たしている。 (Core MAの構造ではデコードと実行をデカップルできないから、一見似ているが動作の本質は全く異なる。)

このバッファは決してトレースキャッシュではない。分岐予測に失敗した場合には何処から再起動が掛かるかを考えると、トレースキャッシュとの違いが鮮明になる。 分岐予測に失敗した場合にもトレースキャッシュにHitする限りデコードをすっとばせるが、LSD および命令バッファは分岐予測ミスしたら flush されてしまって、デコードをすっ飛ばすことは不可能(のはず)。

つまりトレースキャッシュは実行パイプラインの(レイテンシの)短縮化が主な目的になっているのだが、命令バッファはあくまでも命令キャッシュ(メモリ)と実行部とのデカップルが目的(=メモリレイテンシの隠蔽と実効スループットの確保)である。

トレースキャッシュはその存在により、Hit すれば命令実行パイプラインが短いが、現実には Miss する割合がそれなりに避けられない以上、Hit/Miss の混在によって L1I$ 〜実行部への直接パスのスループットを阻害しうる (トレースキャッシュへの書き込み処理などが邪魔する) 。つまりスループット変動を起こしやすく、実効スループットは低下しやすい。

逆に、命令バッファは L1I$ 〜実行部の「実効」スループットを確保することが本質的な目的であり、パイプラインの全長は短くならない(しない)。

そう考えると、CoreMA方式とNehalem方式ではこのLSDを含むバッファの「目的」の点では差が無い。デコードの前段か後段かの違いがあるだけであり、「命令キャッシュ(メモリ)との」デカップルという目的はどちらも達成している。

ただし、x86アーキテクチャはデコードスループットが致命的なボトルネックになりやすい (あんな変態的な命令体系でスーパースカラは大変)ので、デコーダの後ろでデカップルするというのは、実効スループットを稼ぐという命令バッファの目的に最も適っている。つまり命令バッファをx86アーキテクチャ向けに最適化したというスループット向上の正当進化であって、レイテンシ主眼スループット無視(...は言い過ぎか)のトレースキャッシュのような先祖返りでは無いのである。

LSD もこの「実効スループット確保」の目的を考えると自然である。 前回の日記でも書いたことだが、ショートループになる場合には命令キャッシュ〜分岐予測機構の実効供給能力がピークの半分以下に下がる。 ループになる分岐命令は高い精度で分岐予測が出来るのに勿体ない話であって、ILP を確保できる優良顧客からしっかり確保しようというのが LSD である。

トレースキャッシュもショートループはキャッシュヒットするから高い性能が出るわけで、ショートループだけに目を付ければ同じように高スループットの挙動を観測できるので、同一視したくなるのは仕方がない話ですが。


2008-04-24 [長年日記]

_ [雑記] Google map はデータが古い

先月末に開業した横浜市営地下鉄グリーンラインがまだ google map では観測できない。2月開業の新名神(亀山〜草津田上)もないな。2005年の地図なのかー。

Yahoo! Map にはある。すばらしい。