Tag Archive for '技術紹介'

Grand Central Dispatch をためす (2)

その1では、man ページしかドキュメントのない状態で手探りで GCD をさわってみる、ということをしていました。

で、その1を書いた数時間後に全世界で Snow Leopard の発売開始が完了したためか、 ADC で Snow Leopard の開発資料すべてに、ヒラ会員でもアクセスできるようになっていました。すばらしい。

でもそのあたりはロクに読まないまま、今回も man ページを頼りに遊んでみます。

dispatch_apply

man ページによれば、データ並列を実現するもののようですね。与えられた Block を、指定された回数だけ並列実行して回す、という並列プログラミングパターン。

たとえばこんな感じになる。

実行結果:

% ./apply_dispatch
1
0
3
4
5
6
2
8
9
7

ちゃんと非決定的に、突っ込まれた順序でなく Block が実行されている様子が見てとれます。

とはいえ、 dispatch_apply はそのままだと、ループが終わるまで処理をブロックしてしまうので、それがイヤなら dispatch_apply そのものを dispatch_async でくるむといいよ、とか書いてます。

(さいしょ、iteration の各 Block が並列に実行されないのかと勘違いしていて、なんだよそれじゃ意味ないじゃんと思って実験してみたら、ちゃんと個々の Block が並列に実行されてるのを見て感心してました)

こんな感じになる。

実行結果は前のと同じ傾向になります。 違いは、 dispatch_apply の終了を待たずに main が終わりそうになるというところ。 (なので sleep で適当に待っている)

ローカル変数はどうなるの

Block の中から、外のスコープにある変数を参照するとどうなるでしょうか。

タイミング的には、

  • x=3 in 外のスコープ
  • Block を評価
  • x=7 in 外のスコープ
  • Block が実行される

となるように仕組んでいるわけです。

実行してみましょう。

% ./dispatch_local_var
x in outside block : 7
x in async block : 3

おおっと、 Block から参照する、外のスコープにある変数は、 Block が評価された時点の値になるようですね。

クロージャ

それってなんてクロージャ、という。

Apple が GC と Block をC1X に提案している中で (APPLE’S EXTENSIONS TO C March 10, 2009)、Block はクロージャを C に導入する、といった文脈で提案されています。コールバック関数を実装する際に、いちいち関数にコンテキストを引数で渡すのはめんどうだし、コンテキストはレキシカルスコープにある情報そのものでしょうよ、という。

並列プログラミングするときに問題になるのがレースコンディションといった共有変数への競合アクセスですが、クロージャを使うことで評価時に値を束縛してしまうので、 Block が実行されるときの変数の値が決定的になる、ということでしょうか。

並列プログラミングとクロージャの関係についてはもうちょっと考えてみないと。

まとめ

dispatch_apply は、parallel_for のようなデータ並列モデルを提供するものです。また、 Block は C でクロージャを記述できるようにする構文拡張でした。

次は、上でさらっと流した変数を Block 間で共有するあたりの話を掘り下げてみたいと思います。あとイベントとかもセマフォとかも。 Queue でタスク間の依存関係の制御をするあたりも。おわらない…

参考


いま MacBook Pro を買うと Snow Leopard が入ってて Grand Central Dispatch で遊べるし NVIDIA GPU が載ってるので OpenCL でバリバリと次世代並列プログラミングができてよいんじゃないでしょうか。

Grand Central Dispatch をためす (1)

Snow Leopard がでましたね!

OpenCL と Grand Central Dispatch がおもしろそうなので、そのへんのことを書いていくシリーズです。まずは Grand Central Dispatch について、手がかりのない状態からかるく使ってみるまで。

0. Grand Central Dispatch について

前に少し書いたように、Snow Leopard から入る並列実行基盤ですね。

1. Xcode でドキュメント探し

Xcode のドキュメントビューア (えらくインターフェイスがかわった) から、 Grand Central とか Dispatch とかをキーワードにして検索すると、それらしいタイトルがひっかかります。しかし、内容をみることはまだできないみたい。 ADC の上級メンバーならよいのでしょうが、ヒラ会員の我々は無理なの?

2. カンをつかう

mdfind dispatch とかしてみるわけです。すると

/usr/share/man/man3/dispatch.3

とかひっかかる。これはあやしい。 というわけで man 3 dispatchman 3 dispatch_async としていくと、概念を紹介するためのサンプルコードが書かれている man ページにあたります。ビンゴですね。

3. 書いてみる

6-9 行がミソですね。 global queue に、ブロックないの処理を非同期で実行するようつっこんでるわけです。

4. 実行してみる

% ./a.out
hoge
... (寝てる)
%

ちゃんと非同期で実行されてます。

5. 確かめてみる

gdb であそんでみましょう。

% gdb a.out
(gdb) b 7           # ブロック内で break
(gdb run
Starting program: /Users/mootoh/gcd_sandbox
[Switching to process 10433]

Breakpoint 1, __main_block_invoke_1 (.block_descriptor=0x100001080) at gcd_sandbox.c:7
7               printf("hoge\n");

とまりました。 switching to process とかでてますね。スレッド切り替えがおこったのでしょう。

(gdb) bt
#0  __main_block_invoke_1 (.block_descriptor=0x100001080) at gcd_sandbox.c:7
#1  0x00007fff85bc2dc7 in _dispatch_call_block_and_release ()
#2  0x00007fff85ba1341 in _dispatch_worker_thread2 ()
#3  0x00007fff85ba0c80 in _pthread_wqthread ()
#4  0x00007fff85ba0b1d in start_wqthread ()

wqthread とな。 Worker Queue thread とかかな? スレッド全体をみてみましょう。

(gdb) info threads
* 2 port# 0x417 __main_block_invoke_1 (.block_descriptor=0x100001080) at gcd_sandbox.c:7
  1 port# 0x903 0x00007fff85bc1ace in __semwait_signal ()
(gdb) thread 1
(gdb) bt
#0  0x00007fff85bc1ace in __semwait_signal ()
#1  0x00007fff85bc195d in nanosleep ()
#2  0x00007fff85c0f320 in sleep ()
#3  0x0000000100000e94 in main (argc=1, argv=0x7fff5fbfe9b0) at gcd_sandbox.c:10

ちゃんと元スレッドがいますね。

6. その他

そういえば、 gcc に何のオプションも指定することなく、ふつうに Grand Central Dispatch のブロック構文が使えていました。また、特になにかライブラリをリンクすることもなく、ただ gcc -g gcd_sandbox.c これだけでビルドできて並列実行できるバイナリが生成されますね。うむむ。

7. まとめ

ADC ヒラ会員なので、まとまったドキュメントとして man 3 dispatch 周りだけをたよりに Grand Central Dispatch を覗いてみました。ブロック構文がちゃんと使えることをまず確認し、 gdb からもちゃんとマルチスレッドの動作が見える、というところまでを追いました。

あと気になるのは、ハイレベル API がどういうものなのか、というところです。 Cocoa 的なのがあるとすれば、 .framework にまとまってるだろうと思うのですけれど、それらしきものはまだ見つけられていません。

次回はもう少し掘り下げてみたいとおもいます。それまでにドキュメント手に入るようにならないかなぁ…

20009-09-02 21:13 JST 追記

その2 を書きました。

Native Client

今朝目覚めたら、Google が Native Client という面白そうなものを出していたので、論文 (PDF) をざっと読んでみました。で思ったのは、これは Google の 分散 OS ミドルウェア なのだな、ということ。

以下、自分が受け取ったことを書きます。ちゃんと知りたい方は、論文をあたってください。(参考: id:amachang による実践エントリ)

かんたんなおさらい

Native Client とは?

ブラウザの中で、x86のネイティブコードを実行できるようにする仕組みです。

何がうれしいの?

  • 実行速度。スピード! とにかくもっとスピードを!!
  • マシンの機能をフルに使える。ファイルアクセスも、マルチスレッドも、SIMDでさえも書けるよ!
  • それでいてセキュア: 多段サンドボックス方式で、危険なことができないようになってます。

例として挙げられているのは、写真をあつかうWebアプリ。JS+HTMLでユーザインターフェイスを書いておいて、スピードが必要な画像処理はローカルのネイティブコードでやるという処理分担です。 ユーザは JS/HTML/ネイティブコード の3つを書くことになりますね。

それに加えて、Native Client 間の通信もサポートされています。先ほどの写真アプリだと、画像処理に加えてローカルストレージへのアクセスを提供するライブラリと組み合わせる、なんてことも難なくできるという。

みどころ

ランタイムシステムのところでは、とにかく OSっぽさ が随所にでてきますね。マイクロカーネルみたいなもんだよ、とか IPC とか UDP ライクな通信とかマルチスレッドとか。sbrk(), mmap(), malloc(), free() みたいな API を提供するとか。それでいて、 Windows/Mac/Linux といったマルチプラットフォームで動きますと。なので、ぼくはこれこそが Google OS なのだと思いました。下位に存在する OS レイヤをラップするような、それでいて低レベルなタスクをこなすミドルウェア

NativeClient-1

Intel TBB (Threading Building Blocks) でさえ移植できたよ! というのもおもしろかったです。

どうやってセキュアにするのか

2段階のサンドボックスでアプリを閉じ込めます (3) 。Inner (HW, x86 アーキテクチャの機能を利用) と Outer (SW, ptrace とか使う) の2つ。ここの実装がバイナリハックス的に面白いですね。実行できる命令の種類に制限をつけるとか、GCCに手を入れて出力する機械語をサンドボックス用にするとかそういうあたり。論文読む方はこのへんを重点的にどうぞ。

3.1 の Inner Sandbox の性能について述べてるとこが楽しいですね。ユーザのコードがSandbox規約に違反してないかをチェックする Validator が、たった 500 statements の C コードであり、コンパイルすると 6000 バイトでしかないよ、と胸を張っているあたりにぐっときます。

Java とか Flash とかとどう違うの?

より低レイヤなことができる、ということなのかと思いました。 Java は思想的に近いだろうけど、さらに泥臭いことができるという。あと、 Java とか Flash だと、中間に VM というレイヤがあるのですが、 Native Client ではそこをすっとばしていきなりネイティブをさわりにいくというあたりが Google っぽいなと (参考: Google Chrome)。

そもそも、記述言語として使えるのが GCC toolchain が提供するものなので (3.6) 、まあ C/C++ になりますよね。そんなレベルでゴリゴリ書いたコードが Web アプリで動かせるという。データベースと回線の太さに律速されるようなふつうの Web アプリ屋さんにはオーバースペックになるかもしれませんが、 Goolge みたいな用途ではバリバリ使うのかしら。

疑問が残るところ

2.1 では、 UI を書く JS+HTML コードと .nacl なネイティブコードはプラットフォーム間でポータブルとあるのですが、その後の章でそれについて触れられていないのが気になりました。gcc toolchain を使うんだし、 Windows とかどうするんだろうな、と。そのままのバイナリでいけるのかな。

2008-12-10 01:33 追記: takuma104さんのブコメ によると、同じバイナリ (ELF フォーマット) が Mac でも Windows でもそのまま動いたとのこと。3.2 で書かれている、セキュア ELF ローダ (sel_ldr) とその先にあるランタイムで、プラットフォーム間の差異を吸収しているのでしょう。

あと、評価のところ (4.3) で、 H.264 decoder を Native Client のコードと元々のコードとで比較しているのですが、実測値がでてこず

Performance of the original and NaCl versions were comparable and limited by video frame-rate

としか書かれていなかったのが寂しかったです。

思うところ

  • ブラウザの中で動く言語処理系とかを簡単につくれるのではないでしょうか。これまで JavaScript で実装した処理系とかいくつかありましたけれど、そういうのがもっと簡単につくれる (というか、移植できる) ようになる気が。
  • GPGPUと組み合わせてみてもおもしろそうですね。ちょうど OpenCL 1.0 も出たところだし。
  • 練習問題: Gears との関係は?

Native Client が流行るかといわれるとそうでもないかなーと思うんですが、やはり Google のインフラ技術はおもしろいですね。