CELLプロセッサ--linux


linux

make sched_yield more agressive

linux kernel v2.6.23 から Completely Fair Scheduler (CFS) という新しいスケジューラが導入 されましたが、これに伴い sched_yield() の挙動が大幅に変更されています。簡単に言うと、スレッド が sched_yield() を発行すると、次回のスレッド実行が以前のバージョンの kernel と較べると遅くなります。で、以前 と同じ挙動にするためには以下のように kernel を設定すれば良いようです。

echo 1 > /proc/sys/kernel/sched_compat_yield

また、関連する commit は以下になります。

x264 for cell でも sched_yield() は多用しており、v2.6.21 から v2.6.23 にバージョンを上げた 時に速度が低下したため、しばらくは v2.6.21 を使用していました。 が、v2.6.21 は正常にリブート出来ない上に nfs の使用に難があるため、やっぱり v2.6.23 を使用 しようということで kernel source を調べて判明しています。で、原因が sched_yield() にあると 分かって念のため google してみるとすでに以下の記事があってガックリなわけですが、、

x264 for cell ではどう sched_yield() を使用している?

x264 for cell では PPE <-> SPE 間通信が 多対一 となっているため、PPE->SPE は SPU シグナルが使用出来ますが、SPE->PPE は、複数の PPE スレッドが一つの SPE スレッドに対して待ち状態 になっているため、SPU アウトバウンド(割り込み)メールボックスを使用しようとすると、pthread の cond や mutex を組み合わせて複雑な通信方式を実現しなければならないからです。 この代わりとして、 SPE が処理終了時にメモリを変更するので、このメモリを PPE で監視して、 未終了なら sched_yield() するようにしています。 (つまり PPE<->SPE 間で mutex, cond 等を実現する場合と同じことをしています) 速度や実現性を考えると kernel のドライバを作成するというのも考えていますが、、

他の Cell 用ソフトでは?

fixstars 社で公開されている CTK: Cell ToolKit Library でも PPE-SPE 間で使用可能な mutex, cond, queue 等を実現するために使用しています。(source としては以下の辺り)

./ctk/sync/ppu/ctk_mutex-impl.h
./ctk/sync/ppu/ctk_sem-impl.h
./ctk/sync/ppu/ctk_cond-impl.h
./ctk/sync/ppu/ctk_genericq-impl.h
./ctk/sync/ppu/ctk_barrier-impl.h
./ctk/sync/ppu/ctk_queue-impl.h

また、SPE 側では sched_yield() に該当する箇所で random delay させており、スラッシング しないように工夫されています。

逆に、Cell SDK 内で提供されている libsync の mutex, cond では sched_yield() は使用せず、 スピンロックする(実行権を放棄しない)ようです。

sched_yield() は使うべき?使わないべき?

状況による、というありきたりな答えになってしまいますが、 mutex, cond によるロック期間が短ければ sched_yield() を使用しないほうが有利、ロック期間 が長かったり、PPE 上で複数のスレッドが動作する場合は sched_yield() を使用したほうが有利 という感じになるのかな、、

Patches for Toshiba Cell reference set are merged

先週から 2.6.21 の新機能マージ期間が始まっていますが、とうとう TOSHIBA のリファレンスセット (Celleb) 向けの patch が linus tree にマージされまし た。

他にも PS3 用 の usb, fb/av driver のマージも行われています。ただ、 net や logo 関連でまだマージされていないものが幾つかあるようので PS3 で はまだ使用できないと思います (Linuxppc-dev ML を追いきれてません、、)。

ともあれ、詳細は以下をご覧下さい。

We hope 2.6.21 will be the "big cell release"

このエントリ で話題にした TOSHIBA のリファレンスセット向けの linux kernel patch ですが、2.6.20 には 間に合わず、2.6.21 でのマージを目指すということになったようです。詳しくは 以下のメールのスレッドを見てください。

PS3 用のドライバも マージされていないもの (ps3-linux-patches-*) が幾つかありますし、、

PS3 用のドライバ等も全てマージされて、TOSHIBA の方がメールで仰っているように、 2.6.21 が "big cell release" となるといいですね。

Patches for Toshiba Cell reference set are posted again

今週は 2.6.20 の新機能マージ期間なのですが、これに間に合わせる?べく TOSHIBA のリファレンスセット向けの patch が再び Linuxppc-dev ML に流れて います。この patch が新機能に分類される場合、今回マージされないと次 (2.6.21 の新機能マージ) まで待たないといけなくなるので、間に合うといいで すね。

TOSHIBA のリファレンスセットに関する説明は 東芝レビュー2006年6月号 を見てください。

PS3Linux is merged with linus

今週から v2.6.20 に向けて新機能マージ週間が始まっていますが、PS3 用 kernel patch が linus tree (upstream) にマージされました。詳細は以下をご覧下さ い。

その他のマージされていないものは以下にあるようです。

PS3Linux and libspe2

PS3Linux キタ

他にも spe-samples-1.0.tar.bz2 とか CELL-Linux-CL_20061110-ADDON.iso とか。

libspe2 のプロトタイプも来てます。

libc 解析 take.1 (spu_run syscall)

これから数回に渡って、"PPE Serviced SPE C Library Functions" について 解説しようと思います。この処理は SPE thread, Linux kernel, libspe が密接 にからんでいますが、1 回目は Linux kernel が行う処理についてです。

この処理の詳細は libraries_SDK.pdf p.66 "4.2 PPE Serviced SPE C Library Functions" にあります。

4.2 PPE Serviced SPE C Library Functions

  1. The SPE constructs a local store image of the input and outout parameters.
  2. The SPE creates a 32-bit message consisting of an opcode and pointer to the local store parameter image array.
  3. The SPE executes a Stop and Signal instruction.
  4. The PPE detects the Stop and Signal.
  5. The PPE invoke a specialist to service the request according to the message opcode.
  6. The PPE services the requested function.
  7. The PPE returns results in the local store image array.
  8. The PPE resumes SPE execution.
  9. The SPE returns that results back to the caller.

この内、Linux kernel が行うのは 4. だけで、実際には SPE thread の実行 を開始する spu_run システムコールの内部で処理されています。spu_run に関し てはドキュメントがlinux/Documentation/filesystems/spufs.txt にあるので訳 してみますと、、

------------------------------------------------------------------------------
SPU_RUN(2)                 Linux Programmer's Manual                SPU_RUN(2)



名前
       spu_run - spu context を実行する


SYNOPSIS
       #include 

       int spu_run(int fd, unsigned int *npc, unsigned int *event);

DESCRIPTION
       The  spu_run system call is used on PowerPC machines that implement the
       Cell Broadband Engine Architecture in order to access Synergistic  Pro-
       cessor  Units  (SPUs).  It  uses the fd that was returned from spu_cre-
       ate(2) to address a specific SPU context. When the context gets  sched-
       uled  to a physical SPU, it starts execution at the instruction pointer
       passed in npc.

       spu_run システムコールは Cell Broadband Engine Architecture を実装した 
       PowerPC 上で Synergistic Processor Units (SPUs) にアクセスするために使
       用される。SPU context を特定するために spu_create(2) の返り値である fd
       を使用する。context が物理 SPU を獲得後、npc で指定された命令ポインタの
       さす命令の実行を開始する。

       Execution of SPU code happens synchronously, meaning that spu_run  does
       not  return  while the SPU is still running. If there is a need to exe-
       cute SPU code in parallel with other code on either  the  main  CPU  or
       other  SPUs,  you  need to create a new thread of execution first, e.g.
       using the pthread_create(3) call.

       SPU 命令は同期的に実行されるため、SPU 実行中は spu_run は復帰しません。
       メイン CPU や他の SPU 上のコードと並列に実行する必要のある時は、例えば 
       pthread_create(3) を使用して、最初に新しいスレッドを生成する必要があり
       ます。

       When spu_run returns, the current value of the SPU instruction  pointer
       is  written back to npc, so you can call spu_run again without updating
       the pointers.

       spu_run から復帰する時に SPU 命令ポインタの現在値が npc に書き込まれるた
       め、命令ポインタを更新することなく再度 spu_run を呼び出すことができます。

       event can be a NULL pointer or point to an extended  status  code  that
       gets  filled  when spu_run returns. It can be one of the following con-
       stants:

       event は NULL ポインタか spu_run から返る時の拡張ステータスコードが格納
       されるポインタを指定でき、その値は以下の定数にいづれかになる。

       SPE_EVENT_DMA_ALIGNMENT
              A DMA alignment error

       SPE_EVENT_SPE_DATA_SEGMENT
              A DMA segmentation error

       SPE_EVENT_SPE_DATA_STORAGE
              A DMA storage error

       If NULL is passed as the event argument, these errors will result in  a
       signal delivered to the calling process.

       event 引数に NULL が指定された場合、これらのエラーはシグナルとして呼び出
       したプロセスに配送される。


返り値
       spu_run  returns the value of the spu_status register or -1 to indicate
       an error and set errno to one of the error  codes  listed  below.   The
       spu_status  register  value  contains  a  bit  mask of status codes and
       optionally a 14 bit code returned from the stop-and-signal  instruction
       on the SPU. The bit masks for the status codes are:

       spu_run は spu_status レジスタの値か、エラーを指す -1 を返し、以下に示す
       エラーコードのいづれかを errno に格納する。spu_status レジスタの値はステ
       ータスコードのビットマップと、SPU 上で実行された stop-and-signal 命令で
       指定された 14 ビットの値を含む。ステータスコードのビットマスクは、

       0x02   SPU was stopped by stop-and-signal.

       0x04   SPU was stopped by halt.

       0x08   SPU is waiting for a channel.

       0x10   SPU is in single-step mode.

       0x20   SPU has tried to execute an invalid instruction.

       0x40   SPU has tried to access an invalid channel.

       0x3fff0000
              The  bits  masked with this value contain the code returned from
              stop-and-signal.

       There are always one or more of the lower eight bits set  or  an  error
       code is returned from spu_run.

       下位 8 ビットの内、常に 1 つ以上のビットが立ったものか、エラーコードが
       spu_run から返される。

エラー
       EAGAIN or EWOULDBLOCK
              fd is in non-blocking mode and spu_run would block.

       EBADF  fd is not a valid file descriptor.

       EFAULT npc is not a valid pointer or status is neither NULL nor a valid
              pointer.

       EINTR  A signal occured while spu_run was in progress.  The  npc  value
              has  been updated to the new program counter value if necessary.

       EINVAL fd is not a file descriptor returned from spu_create(2).

       ENOMEM Insufficient memory was available to handle a page fault result-
              ing from an MFC direct memory access.

       ENOSYS the functionality is not provided by the current system, because
              either the hardware does not provide SPUs or the spufs module is
              not loaded.


ノート
       spu_run  is  meant  to  be  used  from  libraries that implement a more
       abstract interface to SPUs, not to be used from  regular  applications.
       See  http://www.bsc.es/projects/deepcomputing/linuxoncell/ for the rec-
       ommended libraries.

       spu_run は SPU へのより抽象的なインタフェースを実装するライブラリから使
       用することが意図されており、通常のアプリケーションから使用されることは意
       図されていない。推奨するライブラリとしては
       http://www.bsc.es/projects/deepcomputing/linuxoncell/ を参照。

準拠
       This call is Linux specific and only implemented by the ppc64 architec-
       ture. Programs using this system call are not portable.

       この関数は Linux 特有であり、ppc64 アーキテクチャでのみ実装されている。
       このシステムコールを使用したプログラムはポータブルではない。

バグ
       The code does not yet fully implement all features lined out here.

       コードはここに記述した機能を全て実装していない。

筆者
       Arnd Bergmann 

関連項目
       capabilities(7), close(2), spu_create(2), spufs(7)



Linux                             2005-09-28                        SPU_RUN(2)

------------------------------------------------------------------------------

と長々と訳してみましたが、関連部分を超要約すると、"SPE thread は PPE に何かしてほしい場合は、お願いをオペランドに指定して stop 命令を発行 してね。で、PPE thread は spu_run の返り値としてお願いを受け取ることがで きるから、お願いに応じて実際の処理をしてちょ〜だい" ということです。

返り値についてもエラーでなければ CBE_Public_Registers_v10.pdf p.75 "3.4.3.4 SPU Status Register (SPU_Status)" の値がそのまま返り値となりま す。

あと、注意する点としては spu_run から復帰した時は SPE thread は必ず止 まっているということです。この後、PPE thread が spufs 経由で SPE のメモリ イメージ (/spu/*/mem) を読み書きをしますが、止まっていない場合は spufs 経 由のメモリイメージへ書き込みをしても正しく反映されません。(この処理で扱う システムコールは同期的なので当然止まっているわけですが、、)

内部的には、SPE スケジューラやコンテキストの処理がからんできて結構難 しいのですが、今回説明する処理を理解する上では spu_run システムコールの 仕様がわかっていれば十分なのでこの辺でお茶を濁しておきます。

spufs in linux-2.6.19-rc1

先週、linux kernel v2.6.19 用の新機能マージ期間が終わって、 linux-2.6.19-rc1 がリリースされましたが、cell 用の拡張にも新機能が滑り込 みでマージされました。ログを拾い読みしてみると以下の機能が追加されている ようです。

  1. [POWERPC] spufs: scheduler support for NUMA.
  2. [POWERPC] spufs: make mailbox functions handle multiple elements
  3. [POWERPC] spufs: Add infrastructure needed for gang scheduling

2. の commit log を見てみると libspe2 なんてキーワードも出てきています。

その他の詳細は 2006-06-28 以降の commit log を参照してください。

spufs で linux tree を検索

kernel 解析 take.2 (syscall だけ見るって無理があるわな)

2 つしかない SPE 用の syscall (sys_spu_create, sys_spu_run) くらい見ておくか、と思って 見始めたらどんどん深みにはまって気づいたら最深部までいってます。そのおかげでなかなか興 味深いことがわかったのでまずはメモということで。

  • SPE プログラム用のスケジューラがあり、物理数以上の SPE プログラムを扱うことが可能。
  • ディスパッチ時に退避、復帰される SPE のコンテキストには、128 個ある GPR (General-Purpose Register)、256KB の LS (Local Store)、MFC 制御レジスタ等 のほぼ全ての資源が含まれる (巨大コンテキスト)。
    (参考 include/asm-powerpc/{spu.h,spu_csa.h})
  • コンテキストが巨大ということは復帰、退避処理も長いです。退避 54 STEP、復帰 75 STEP って 、、、
    (参考 arch/powerpc/platforms/cell/spufs/switch.c)
  • PPE から制御できる資源は PPE が退避、復帰する。が、SPE の GPR は PPE からは制御できないので、、
  • GPR を退避、復帰するために、まず PPE から LS を 16KB だけ MFC を使って退避し、空いた領域に プログラムを別途転送、このプログラムから GPR の退避、復帰と LS の残り 240KB (256KB - 16KB) の 退避、復帰を行っている。
    (参考 arch/powerpc/platforms/cell/spufs/spu_{save,restore}.c)
  • SPE のプログラムは、PPE 上の対応する SPE thread の優先度をそのまま使用している。 ということは libspe-1.1.0 が SPE thread の優先度変更に対応していないので、現状では やっぱり SPE プログラムの優先度変更はできない。
    (参考 arch/powerpc/platforms/cell/spufs/context.c: spu_acquire_runnable())

なんか、スゴい、、

kernel 解析 take.1 (2.6.18-rc6 との差分調査)

Cell 用 Linux kernel を解析をするまえに upstream (v2.6.18-rc6) との差分を調査しておこうと思います。後から大きく違うことがわかると ショックだし、、といっても Cell 用のディレクトリに関する差分を大まかに ながめただけで、powerpc 自体や include に関する調査はしていません。


$diff -Nru cbe-linux-2.6.16/arch/powerpc/platforms/cell/ \
            linux-2.6.18-rc6/arch/powerpc/platforms/cell/ \
            | grep "^diff -Nru" | gawk '{print $3}'
cbe-linux-2.6.16/arch/powerpc/platforms/cell/Kconfig
cbe-linux-2.6.16/arch/powerpc/platforms/cell/Makefile
cbe-linux-2.6.16/arch/powerpc/platforms/cell/cbe_regs.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/cbe_regs.h
cbe-linux-2.6.16/arch/powerpc/platforms/cell/interrupt.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/interrupt.h
cbe-linux-2.6.16/arch/powerpc/platforms/cell/iommu.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/pci.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/perfmon.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/perfmon.h
cbe-linux-2.6.16/arch/powerpc/platforms/cell/pervasive.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/setup.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/smp.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/spider-pic.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/spu_base.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/spu_callbacks.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/spu_priv1_mmio.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/spufs/Makefile
cbe-linux-2.6.16/arch/powerpc/platforms/cell/spufs/backing_ops.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/spufs/file.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/spufs/hw_ops.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/spufs/inode.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/spufs/run.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/spufs/sched.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/spufs/switch.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/spufs/syscalls.c

upstream にないファイル


cbe-linux-2.6.16/arch/powerpc/platforms/cell/pci.c

ハードに関連する暫定対策のようで upstream にはコミットされないようです。(pci-fixup-hack.diff 参照)


cbe-linux-2.6.16/arch/powerpc/platforms/cell/perfmon.c
cbe-linux-2.6.16/arch/powerpc/platforms/cell/perfmon.h

performance monitor のサポート。(cell-perfmon.diff 参照)

irq 関連

upstream での irq 関連の変更への追従。

semaphore から mutex に変更

upstream では semaphore を使うのをやめて mutex を使う方向になっているのでこれに追従。

mutex から semaphore に変更


cbe-linux-2.6.16/arch/powerpc/platforms/cell/spufs/sched.c

upstream 2.6.16 では、まだ semaphore を使っているのでまだコミットされていないだけでしょう。

NUMA (node) 関連

まだコミットされてないだけのようだが、差分見るだけではよくわからない。(spufs-sched-numa-2.diff 参照)

TAG データ作成

早速、構築した環境を使ってソースコードの TAG データを作成してみます。解析のターゲットにしている Linux kernel と libspe は BSC (Barcelona Supercomputer Center) にありますので、以下をダウンロードします。

http://www.bsc.es/projects/deepcomputing/linuxoncell/cellsimulator/sdk1.1/kernel-2.6.16-bsc4.2.src.rpm
http://www.bsc.es/projects/deepcomputing/linuxoncell/stable/libspe/libspe-1.1.0.tar.gz

まずは Linux kernel からですが、rpm には linux-2.6.16 と、quilt で管理するファイルの入ったディレクトリ (patches/) が kernel-2.6.16.tar.gz として入っていますので、Linux kernel を展開した後に quilt を使って Cell 用 kernel のソースコードを作成します。

$ rpm -ivh kernel-2.6.16-bsc4.2.src.rpm
$ tar xvzf ~/rpm/SOURCES/linux-2.6.16.tar.bz2
$ mv linux-2.6.16 cbe-linux-2.6.16
$ cd cbe-linux-2.6.16/
$ tar xvzf ~/rpm/SOURCES/kernel-2.6.16.tar.gz

では、quilt を使ってこれから適用する patch の状態を見てみます。

$ quilt series -v

  patches/hvc-console-rework-4.diff
  patches/hvc-console-rtas-4.diff
  patches/cell-detect.diff
            :
  patches/spufs-dma-events-2.diff
  patches/spufs-correct-dma-exceptions.diff
  patches/SDK

patch を全部適用します。

$ quilt push -a

で、patch の状態を確認すると

$ quilt series -v

+ patches/hvc-console-rework-4.diff
+ patches/hvc-console-rtas-4.diff
+ patches/cell-detect.diff
            :
+ patches/spufs-dma-events-2.diff
+ patches/spufs-correct-dma-exceptions.diff
= patches/SDK

という具合に適用されている patch の先頭には + が付き、この内、最上位の patch には = が付きます。全ての patch をはずす場合は

$ quilt pop -a

です。push, pop に -a を指定すると管理している全ての patch が対象となり、指定しないと一つだけが対象となります。あとは、最上位の patch の表示の仕方くらい覚えておけばソースコードを解析はできます。

$ quilt diff

で、gtags 実行

$ gtags

ちなみに TAG データのサイズはこのくらいです。ほぼ 1GB ですが、最近の HDD のサイズを考えれば問題にならないでしょう。

GPATH: 3137536 byte
GTAGS: 115400704 byte
GRTAGS: 758595584 byte
GSYMS: 93298688 byte

libspe も同様に解凍して gtags します。

$ tar xvzf libspe-1.1.0.tar.gz
$ cd libspe-1.1.0/

$ gtags

こちらの TAG データのサイズはこのくらいです。

GPATH: 16384 byte
GTAGS: 81920 byte
GRTAGS: 352256 byte
GSYMS: 188416 byte

あ〜、やっと解析準備完了。

HOME |  企業情報 |  事業内容 |  採用情報 |  社内活動 |  お問合せ |  サイトマップ
.
Copyright(c)2006 Sijam.Inc all rights Reserved
システム開発 株式会社シジャム