川の流れのように‥(Eiji Ota's Weblog)
SPARC Memory Model - 涙のハング物語 (またかいっ)
今週悩ませたのは、(またまた?)ハングの問題でした。 でも、今回のハングは、よりシステムプログラムっぽく、いてての問題でした。(++;) そんな僕の涙物語。。。。 眠ったきり、誰にも起こされないThreadがシステムに居たんですけれど、よりによってその子がロックを抱えたまま眠ってしまったんですね。 そのため、そのロックを待っている人たちがずらりと列を作るかのように並んでしまって、システムがにっちもさっちも行かなくなってしまいました。 ちょうと、おトイレの中で眠ってしまって、おトイレを待っている人たちがずらりと並んで、仕事どころではないっという状態でしょうか(って、例えがいいのか微妙ですが。。。。) そもそも、「ロックを抱えたまま眠って」っていうのがあり得ないって感じなんですが、デバイスノードを管理しているルーチンで、こういうことがあり得るものがあるんですね。 今回とは違う例ですけれど、例えば、mutexロックを掴んだthreadがsemaphoreでI/O完了を待っているのに、ちっとも完了しない‥そうこうしているうちに、そのロックを待っている人たちがずらりと並んで‥恐ろしい状況になってしまっている、、というのも似たような(?)感じですね。 # 振り向けばそこに‥たくさんの人たちがぁ‥って怖いですよね、どうでもいいですけれど。(-.-;) 今回のは、どうやらSPARCのメモリモデルと関係しているようでした。 これはちょっと難しい話なので、例をあげましょう。 支払いに小切手を送ったのに、届いていないと電話を貰う。「そんな馬鹿な、今日には届いているはず。ちゃんと郵便ボックスを見てよ?」と言っても、「配達の時間は過ぎている。さっき見たばかり。何も入っていなかった」って言われちゃう。 そんなぁぁぁと思っていると、また電話があって「アパートの人が間違えて入っていたよと君の封筒を持ってきたよ。ごめんね」。 ちっ、人騒がせなやつだ。。 こういうことと似たようなことが起こり得るのが、SPARCのload/store命令です。 上の例を次のように読み替えてみましょう。
小切手を貰う人 = メモリのデータをloadする 小切手を送る人 = メモリにデータをstoreする 郵便を送り、配達時間に届く = プログラムオーダー 隣の人が間違えて持っていった後、実際に郵便が届く = メモリーオーダーそうなると、上の例は次のような現象が起きたことになりますね。(って、ちょっと無理矢理かしら?) メモリにフラグ(データ)をstoreし、その番地からデータをloadしているのに、フラグが見えない。プログラムでは、storeが先でloadが後になっているので、フラグが見えるはず??? ちょっと後で、もう一度念のため見てみると、あれぇフラグが見えている。どうなっているのぉ??? こんな不可思議なことが起きてしまったりするんですねぇ。(*_*;) これは、実はプログラムで書かれているとおりに、loadやstore命令が実行されないことから起きます。えっ? コンパイラやアッセンブラの問題じゃないのぉって? そういう問題もあるかも知れないけど、ここでのプログラムっていうのは、機械語を想定してて、どちらかというとアッセンブラで書かれたプログラムっていう感じに近いですね。 例えば、次のプログラムをCPU1とCPU2で実行し、観測ポイントでそれぞれの結果を確認した時に、CPU1ではレジスタ%r1に1が入っているにもかかわらず、CPU2ではレジスタ%r2には、1が入っていない‥「えぇぇぇぇ、なんだってぇぇぇっ」ということが起きます。(へぇぇぇぇって感じでもあるけど ^-^)
CPU1 CPU2
store #1, [A] store #1, [B]
load [B], %r1 load [A], %r2 {{{{{ 観測ポイントでデータを確認
各CPUではstore→load命令の順に実行するようにプログラムでは指示しているわけなので、それぞれの値は1であるはずですよね?
CPU1ではそのとおりに実行したように見えますが、CPU2はload命令を先に実行してstore命令を実行したみたい。感じ、load命令を先に実行してしまったものですから、CPU1のstore命令がまだ完了していなかったって状況。
ここで、プログラムが指示しているstore→load命令の順をプログラムオーダーといいます。そして、実際にCPUが実行した順番、CPU1ではstore→load命令の順、CPU2では逆のload→store命令の順をメモリオーダーといいます。
つまり、SPARCプロセッサーは、プログラムで指示した順(プログラムオーダー)にメモリにアクセス(メモリーオーダー)するとは限らない‥ということなんですね。(な、なんだとぉぉぉぉ!)
ちょっと頭が痛いです。。。。(かなり頭が痛い???)
実際には、SPARC V9では次の3つのメモリモデルを決めています。
TSO: Total Store Order {{{{{ Load/Store同士の命令の順は守ってくれるモード
PSO: Partial Store Order {{{{{ Loadの命令の順は守ってくれるモード
RMO: Relaxed Memory Order {{{{{ Load/Storeもどっちの順も守らないモード
メモリモデルがRMOに指定されると、もうプロセッサーのお行儀はひどいものですね。LoadもStoreもしったことかぁっていう感じです。
当然性能は、期待とおり荒くれの順で、RMO > PSO > TSOの順に速くなります。
アウトローの方が行儀は悪いが、やたら速いっていう感じでしょうか? なんとなくイメージと合いますね。^-^
Solaris Operationg Systemは、UltraSPARCをTSOで使用しています。
RMOで走らせたいけど、制御できなくなってしまう‥という状況でしようか。
まだまだUltraSPARCを乗りこなせているとはいえませんねぇ。。。^-^; (やばぁぁぁぁ)
TSOでもloadとstore間で実行の順序を保証しないときがあるので、上の例のような状況が起き得るのです。こういう状況でハングが起きると、もぉ頭が痛いどころではありませんね。(しくしく状況 (;-;))
ちなみに、loadとstore間の実行順序を指定してやりたいときは、membar命令を使ってやります。
上の例ですと、次のようにmembar #StoreLoadを指定してやれば、実行順序はプログラムオーダーのとおりとなります。
CPU1 CPU2
store #1, [A] store #1, [B]
membar #StoreLoad membar #StoreLoad {{{{{ 実際には、この命令が要る
load [B], %r1 load [A], %r2
このmembarを忘れたりすると、いててててぇ状況になってしまったりするんですね。
このmembarについては、/usr/include/sys/atomic.hにコメントが書いてありますので、
近くにSunのシステムがあれば(で、Solarisがインストールしてあれば)見てみて下さいね。
(membar_enter(), membar_exit(), membar_producer(), membar_consumer()のところです)
# OpenSolarisがリリースされれば、堂々とソースを載せられるんですけど。もうしばらくの辛抱ですね。
今日はちょっとイテテの話題でした。仕事柄、こういう痛いトラブルにぶつかることもある‥そんな涙のお話(というより、愚痴かい?)でした。
さて、週末はゆっくり休むことにしましょ。
それでは皆さん、良い週末を
Posted at 06:46午後 5 27, 2005 by eota in opensolaris | Comments[0]