一昨日くらいに思いついた無駄コード第一弾に向けて、erlangのlinkedin driverについて調べています。で、メモ。
↓のように、C言語FFI(リンクインドライバ)がボトルネックになりやすい仕組みになっているらしい(tutorialの冒頭の画像なんかがまさにそのイメージ)というのが、ずっと引っかかっていたので、その辺りを詳細に調べてみようと思う。
Erlangで,C言語のライブラリ(この場合はopenssl)を使う場合,リンクインドライバを使うのだが,リンクインドライバがそもそも同時に1つのプロセスからしか利用できないことが多い.
(file,inetのモジュールだけが例外で,smp対応のドライバになっている模様.)
その上,このようなドライバの実装を見ると,いったん1つのプロセスにメッセージを集めて,そのプロセスがドライバと通信するような仕組みになっているので,絶対に速度が向上しない構造になってしまっている.
みかログ: マルチコアでスケールしないErlang その2
少なくとも、"There may be multiple instances of a driver, each instance is connected to an Erlang port. Every port has a port owner process. Communication with the port is normally done through the port owner process."とあるので、最悪、ドライバを叩くプロセスを複数作ればいいかなぁと思っていた。それ作るだけでも割と使えるかも、と思ったけど、読み進めてみると
Previously, in the runtime system without SMP support, specific driver call-backs were always called from the same thread. This is not the case in the runtime system with SMP support. Regardless of locking scheme used, calls to driver call-backs may be made from different threads, e.g., two consecutive calls to exactly the same call-back for exactly the same port may be made from two different threads. This will for most drivers not be a problem, but it might. Drivers that depend on all call-backs being called in the same thread, have to be rewritten before being used in the runtime system with SMP support.
erl_driver
とあるので、SMP supportをきちんとつけておけば冒頭のボトルネック問題はR13Bでは解決されているっぽいかも(要確認)。で、それでもモジュールとしてスレッド等を構えておきたいのであれば、Threads, Mutexes, Condition variables, Read/Write locks, Thread specific dataなどが使えるみたい。というか、Cで書かれているところまで並行性の面倒は見切れません、という風に読める。
MacOSだと、フツーは-dynamiclibなどとして動的ライブラリを作るんだけど、それだとダメだと注意されているので要注意(via Young Risk Taker)。
If you develop linked-in drivers (shared library) you need to link using "gcc" and the flags "-bundle -flat_namespace -undefined suppress". You also include "-fno-common" in CFLAGS when compiling. Use ".so" as the library suffix.
まだ何したらいいかよくわかってないときにErlang VM本体のソースも落としてきてみたんだけど、やっぱりワケワカランかった。こんなスゴいもの再発明してる場合じゃないね。
みかログに載っているコードをコピってテストしてみたところ、10倍からは随分改善されたけど、マルチコアの優位性を使い切れていない。チューニングの問題なのかどうなのか。
> $ erl -noshell -smp disable -eval 'mesbench:test(),halt().' {11242894,ok} > $ erl -noshell -smp enable -eval 'mesbench:test(),halt().' {13285326,ok}
SPARC x Solarisで使われてきたシステムだから、そっちだと性能が出るとか?うーむ。わからん。