rubyのベンチマークのログ3
ログだけなので、隠しておきます。
#1日に書けるデータ量に制限が有るのかな?日付変わらないとかけなかった……
rubyのベンチマークのログ2
ログだけなので、隠しておきます。
続きを読むrubyのベンチマークのログ1
ログだけなので、隠しておきます。
続きを読むrubyバイナリの速さをベンチマークで比べてみる
折角いろんなバイナリを作られるようになったので、速さを比較してみる。
アーキテクチャはi386 = 32ビット、x86_64 = 64ビット、ppc = 32ビットの3種類。ppc64のバイナリは動作させられないようで、rubyはコンパイルもできなかった。
こんな最低限のソースから作ったものですら実行できないので、configureにコケルのです。
MyMac:~ chcoopu$ cat ppc64test.c int main(void){ return 0; } MyMac:~ chcoopu$ gcc -arch ppc64 -O0 ppc64test.c -o ppc64test MyMac:~ chcoopu$ file ppc64test ppc64test: Mach-O 64-bit executable ppc64 MyMac:~ chcoopu$ ./ppc64test -bash: ./ppc64test: Bad CPU type in executable MyMac:~ chcoopu$
また、使用したコンパイラはXcode 3.1に付属していたgcc-4.0とgcc-4.2の2種類。
コンパイルには
CFLAGS="-O2 -pipe -arch それぞれのアーキテクチャ"
状態で
./configure --prefix=インストール場所 --enable-shared
してコンパイルしたもの。一部configureファイルやMakefileでLDSHAREDの値を
cc -dynamiclib ...
から
$(CC) -arch それぞれのアーキテクチャ -dynamiclib ...
に変更してコンパイルしている。
そうしてできたバイナリを使って、ベンチマークを動かしている。ベンチマーク自体はRuby作者のMatzさんも取り上げているフラクタルベンチマーク。実際のコード
これを以下のようにして連続3回実行している。
date; time /usr/local/ruby/ruby-1.8.6-i386-gcc-4.0/bin/ruby fractal.rb; date; time /usr/local/ruby/ruby-1.8.6-i386-gcc-4.0/bin/ruby fractal.rb; date; time /usr/local/ruby/ruby-1.8.6-i386-gcc-4.0/bin/ruby fractal.rb; date
それぞれのバイナリのインストールしたフォルダ名を別々にしてあるので、そこは変更する。フォルダ名にはアーキテクチャ名やコンパイラ名を入れてあるので、間違うことはないだろう。
以下3回の実行時間の平均。
*アーキテクチャ | *コンパイラ | 実行時間(s) |
i386 | gcc-4.0 | 6.248884 |
i386 | gcc-4.2 | 6.295775 |
x86_64 | gcc-4.0 | 5.873572 |
x86_64 | gcc-4.2 | 6.141422 |
ppc | gcc-4.0 | 15.694515 |
ppc | gcc-4.2 | 18.666161 |
実行すると端末に「*」を使ってフラクタル画像が出力されるのだが、ppcバイナリの場合ははっきりと遅いことが感じられた。ロゼッタによる実行時変換に時間がかかっているんだろう。
また、折角Javaも入っているのでJRubyでも実行してみた。
JRubyは環境変数JAVA_HOME以下にあるJava VMを使うので、JAVA_HOMEを切り替えており、確認のための出力もしている。使用したのはJava1.5.0の32ビットClient VM、同64ビットServer VM、Java1.6.0の64ビットServer VMの3種類。JRuby自体は全てで1.1.5を使用。
JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home; export JAVA_HOME; $JAVA_HOME/bin/java -client -version; date; time /usr/local/ruby/jruby-1.1.5/bin/jruby --client fractal.rb; date; time /usr/local/ruby/jruby-1.1.5/bin/jruby --client fractal.rb; date; time /usr/local/ruby/jruby-1.1.5/bin/jruby --client fractal.rb; date
こちらも同様に平均。
*JavaVMバージョン | *起動VM | 実行時間(s) |
Java 1.5.0 | 32ビット Client VM | 4.538105 |
Java 1.5.0 | 32ビット Server VM | 3.580182 |
Java 1.5.0 | 64ビット Server VM | 3.960026 |
Java 1.6.0 | 64ビット Server VM | 3.147230 |
実行するとCのrubyとは違い、最初にフラクタル画像が出力される前に、突っかかるように一旦止まる。これはJava VMの起動にかかっている時間だろう。なので、ruby内で計測している上記実行時間よりも、実際の実行時間は長い。
総括
- gcc-4.0で作ったバイナリはgcc-4.2で作ったバイナリよりも速い……気がする。
- i386で32ビットなバイナリよりx86_64で64ビットなバイナリの方が速い……と思う。
- JavaはClient VMよりもServer VMの方が速い……と言っていいと思う。
- Java 1.6.0はJava 1.5.0よりも速い……のだろう。
といった辺りはほぼ言える。
rubyとjrubyの比較は一概には言えない。今回のフラクタルベンチマークではjrubyの方が速かったが、単にこれだけかもしれない。
傾向として見えてくるほどに色んなベンチマークを色んな環境で試した訳ではないし、そもそも実アプリではないので参考程度にとどめるべきだし、最終的には自分の使いたいアプリで、どれが速いかを実測するべき。
なぜ今回比較したかというと、おもしろそうだったから。それだけ。
以下、実行時の生の出力のみ。
と思ったのだが、長過ぎるせいか途中できれるのでエントリ分割。
まとめていたら、Java 1.5.0のServer VMは、64ビットではなく32ビットで動作していたので、修正&64ビットの結果も取得。
サーバ/インフラを支える技術 読了
はてなの中の人が書いた本。
[24時間365日] サーバ/インフラを支える技術 ?スケーラビリティ、ハイパフォーマンス、省力運用 (WEB+DB PRESS plusシリーズ)
- 作者: 安井真伸,横川和哉,ひろせまさあき,伊藤直也,田中慎司,勝見祐己
- 出版社/メーカー: 技術評論社
- 発売日: 2008/08/07
- メディア: 単行本(ソフトカバー)
- 購入: 133人 クリック: 2,270回
- この商品を含むブログ (288件) を見る
電車の中でしか読んでいなかったので、読み始めてから1ヶ月くらいかかったかな?読むの遅すぎ、反省。
内容は非常にわかりやすく、どのように安心、安全なシステムを構築・運用していくか、という話。
本当にわかりやすいので、ちょっとでもこの辺りに興味あったら読むべき。というか多くのIT技術者に読んで欲しい内容。
自分が構築・運用しなくても、知っている/認識しているかいないかで、できるシステム・アプリのできが変わると思う。
個人的に大絶賛。
残念な部分
- サービスのチューニング・最適化の話が出てくるが、サーバ/インフラ側での解決の話だけになり、アプリ側がアルゴリズム・実装・設定レベルで最適であるべきということが、あまりにも本文でさらっと出てくるだけだったこと。富豪的プログラミングは有りとはいえ、アプリ側を最適にするだけで10倍速くなったとかは普通にあるのだから、前提としてもっとはっきり書くべきだったんじゃないかな。#もちろんサーバ/インフラ側の変更でアプリの変更が必要になることもあるけど、ここでは置いておく。
- この本では全部Linux上にソフトで組んだけどLinuxでなく他のOSでも専用HWとかでもできるよ、ってのがあまり見えてこないこととか。
- 仮想化の話がほとんどなかったこと。VMware InfrastructureでActive/Stand-byやDR対応できるとかのレベル。
- ディザスタリカバリ( DR )周りの話……は、まぁしょうがないか。
- そうそう、バックアップの話とか。個人的には同一種類メディアはバックアップにならないよ派。つまりRAIDミラーやディスクコピーそのものはバックアップにならないと考える人なんで、この辺りの話も欲しいかなと。D2D2Tあたりが最近のトレンドかな?
- さいごは個人的・宗教的問題なんだけど、いきなりGPL (と思われる)コードが出てくるのはやめて欲しい。疑似コードになっていれば問題ないんだけど、そのままは……
と、なんだか残念な部分の方が多く書いてしまったけれど、こんな些末な内容でしかケチがつけられないほど、いい本なんだYO!!ってことなんですよ。
だって、残念として挙げたものって、注意してあれば嬉しいけど、なくても全然致命的な問題にならないじゃない?
ちなみに、はてなでブログ始めたのはこの本を途中まで読んで、いいと思ったからってもの有ったりする。
ユニバーサルバイナリを作ってみる ruby編補足
昨日の検索では引っかかってこなかったファイルもユニバーサルバイナリ化しないといけない雰囲気。これ
MyMac:~ chcoopu$ file /usr/local/ruby/lib/libruby-static.a /usr/local/ruby/lib/libruby-static.a: current ar archive random library MyMac:~ chcoopu$
Mach-O形式として出てこなかったから見落としていた。libruby-static.aを展開してみると
MyMac:libruby chcoopu$ ls -a ./ ../ MyMac:libruby chcoopu$ MyMac:libruby chcoopu$ cp /usr/local/ruby/lib/libruby-static.a ./ MyMac:libruby chcoopu$ ar x libruby-static.a MyMac:libruby chcoopu$ ls __.SYMDEF SORTED hash.o re.o array.o inits.o regex.o bignum.o io.o ruby.o class.o libruby-static.a signal.o compar.o marshal.o sprintf.o dir.o math.o st.o dln.o numeric.o string.o dmyext.o object.o struct.o enum.o pack.o time.o enumerator.o parse.o util.o error.o prec.o variable.o eval.o process.o version.o file.o random.o gc.o range.o MyMac:libruby chcoopu$
ほら、i386なバイナリが出てきた。本当はこのlibruby-static.aもユニバーサルバイナリにしないといけない。
MyMac:libruby chcoopu$ file *.o array.o: Mach-O object i386 bignum.o: Mach-O object i386 class.o: Mach-O object i386 compar.o: Mach-O object i386 dir.o: Mach-O object i386 dln.o: Mach-O object i386 dmyext.o: Mach-O object i386 enum.o: Mach-O object i386 error.o: Mach-O object i386 eval.o: Mach-O object i386 file.o: Mach-O object i386 gc.o: Mach-O object i386 hash.o: Mach-O object i386 inits.o: Mach-O object i386 io.o: Mach-O object i386 marshal.o: Mach-O object i386 math.o: Mach-O object i386 numeric.o: Mach-O object i386 object.o: Mach-O object i386 pack.o: Mach-O object i386 parse.o: Mach-O object i386 prec.o: Mach-O object i386 process.o: Mach-O object i386 random.o: Mach-O object i386 range.o: Mach-O object i386 re.o: Mach-O object i386 regex.o: Mach-O object i386 ruby.o: Mach-O object i386 signal.o: Mach-O object i386 sprintf.o: Mach-O object i386 st.o: Mach-O object i386 string.o: Mach-O object i386 struct.o: Mach-O object i386 time.o: Mach-O object i386 util.o: Mach-O object i386 variable.o: Mach-O object i386 version.o: Mach-O object i386 MyMac:libruby chcoopu$
まぁここまでできていたら、単にこれもi386バイナリなファイルとx86_64バイナリなファイルを用意してくっつければいいだけ。
MyMac:libruby chcoopu$ lipo -create libruby-static.a.i386 libruby-static.a.x86_64 -output libruby-static.a MyMac:libruby chcoopu$
ほいできた。
……しかし、よく考えたら名前の通り静的ライブラリだな、これ。arでファイル取り出せるし。
それじゃ、動的共有ライブラリで作り直すか。
いつものようにi386なバイナリ作る準備して、configure時に--enable-sharedオプションを付けるだけ。
すると、こんな感じで動的共有ライブラリが作られる。
MyMac:ruby-1.8.6-p287 chcoopu$ ls -l libruby* -rw-r--r-- 1 chcoopu staff 1276776 12 2 00:03 libruby-static.a -rwxr-xr-x 1 chcoopu staff 844844 12 2 00:03 libruby.1.8.6.dylib* lrwxr-xr-x 1 chcoopu staff 19 12 2 00:03 libruby.1.8.dylib@ -> libruby.1.8.6.dylib lrwxr-xr-x 1 chcoopu staff 19 12 2 00:03 libruby.dylib@ -> libruby.1.8.6.dylib MyMac:ruby-1.8.6-p287 chcoopu$ file libruby.1.8.6.dylib libruby.1.8.6.dylib: Mach-O dynamically linked shared library i386 MyMac:ruby-1.8.6-p287 chcoopu$
そしてまたお決まりのようにx86_64バイナリを--enable-sharedで作ってユニバーサルバイナリを作り出すと。
MyMac:ruby-1.8.6-p287 chcoopu$ file libruby.1.8.6.dylib libruby.1.8.6.dylib: Mach-O universal binary with 2 architectures libruby.1.8.6.dylib (for architecture i386): Mach-O dynamically linked shared library i386 libruby.1.8.6.dylib (for architecture x86_64): Mach-O 64-bit dynamically linked shared library x86_64 MyMac:ruby-1.8.6-p287 chcoopu$
これをインストールすれば、おわり。
64ビットなrubyを野良ビルドする
何も考えずに本家からソースをダウンロードしてコンパイル&インストールすると
MyMac:~ chcoopu$ file /usr/local/ruby/bin/ruby /usr/local/ruby/bin/ruby: Mach-O executable i386 MyMac:~ chcoopu$
といった感じでi386アーキテクチャ用バイナリ、つまり32ビット環境でも動作するバイナリが作成される。PowerPC、SPARC、EM64T/AMD64なら64ビットモードで動作している時は32/64ビットのバイナリ両方を同時に実行できるので特に問題ないし不思議でもない。
Max OS X付属のrubyなら
MyMac:~ chcoopu$ file /usr/bin/ruby /usr/bin/ruby: Mach-O universal binary with 2 architectures /usr/bin/ruby (for architecture ppc7400): Mach-O executable ppc /usr/bin/ruby (for architecture i386): Mach-O executable i386 MyMac:~ chcoopu$
とPowerPC、Intel両方で動作するユニバーサルバイナリだとわかる。
ppc7400ということは、おそらくPowerPC 7400シリーズのこと。ということはG3かG4以降のバイナリということか。まぁ自分で使わないからどっちでもいいけど。
でも、実行バイナリではなくライブラリを調べてみると
MyMac:~ chcoopu$ file /System/Library/Frameworks/Ruby.framework/Versions/Current/usr/lib/libruby.1.dylib /System/Library/Frameworks/Ruby.framework/Versions/Current/usr/lib/libruby.1.dylib: Mach-O universal binary with 4 architectures /System/Library/Frameworks/Ruby.framework/Versions/Current/usr/lib/libruby.1.dylib (for architecture ppc7400): Mach-O dynamically linked shared library ppc /System/Library/Frameworks/Ruby.framework/Versions/Current/usr/lib/libruby.1.dylib (for architecture ppc64): Mach-O 64-bit dynamically linked shared library ppc64 /System/Library/Frameworks/Ruby.framework/Versions/Current/usr/lib/libruby.1.dylib (for architecture i386): Mach-O dynamically linked shared library i386 /System/Library/Frameworks/Ruby.framework/Versions/Current/usr/lib/libruby.1.dylib (for architecture x86_64): Mach-O 64-bit dynamically linked shared library x86_64 MyMac:~ chcoopu$
PowerPCも32ビット(ppc7400)、64ビット(ppc64)バイナリの2種類入っており、Intelの方も32ビット(i386)、64ビット(x86_64)バイナリの両方入った、合計4種類のバイナリの入ったユニバーサルバイナリだとわかる。実行バイナリに両アーキテクチャの64ビット版が入っていないのは何か理由があるのかな?
とゆーわけで、普通に使える64ビットなrubyバイナリはない訳だ。
なので、自分で作ってみようという話。
x86_64向けにバイナリを作れば64ビットバイナリになるので、そのようにする。特に-m64とかは必要ではないみたい。
gccへのオプションとして-arch x86_64を付けるだけ。x86_64の代わりにi386を指定すれば今までと同じバイナリになる……が、指定する意味はないな。ppcやppc64も選択できるが、まぁ必要な人だけ、ドゾー。
で、大抵のソフトはMakefileの中でCC、CXXでCコンパイラやC++コンパイラの指定をすることが多い。同時にCFLAGS、CXXFLAGSでCコンパイラ、C++コンパイラに対するオプションを指定することになる。
rubyのコンパイルする時にもCFLAGSに-arch x86_64を指定すればOKかなと。
指定してconfigure、makeすると見事64ビット対応のrubyができる。
MyMac:~ chcoopu$ file /usr/local/ruby/bin/ruby /usr/local/ruby/bin/ruby: Mach-O 64-bit executable x86_64 MyMac:~ chcoopu$ MyMac:~ chcoopu$ /usr/local/ruby/bin/ruby -v ruby 1.8.6 (2008-08-11 patchlevel 287) [i686-darwin9.5.0] MyMac:~ chcoopu$
できるのだが、作っている途中で部分的に文句を言われる。
ld warning: in bytecode.o, file is not of required architecture
その結果何も拡張していないruby本体は動作するものの、添付ライブラリ辺りでこけてしまう。
MyMac:rubygems-1.3.1 chcoopu$ /usr/local/ruby/bin/ruby setup.rb /usr/local/ruby/lib/ruby/1.8/i686-darwin9.5.0/thread.bundle: Failed to load /usr/local/ruby/ruby/lib/ruby/1.8/i686-darwin9.5.0/thread.bundle (LoadError) from /usr/local/ruby/lib/ruby/1.8/thread.rb:5 from ./lib/rubygems.rb:10:in `require' from ./lib/rubygems.rb:10 from setup.rb:22:in `require' from setup.rb:22 MyMac:rubygems-1.3.1 chcoopu$
というわけで、どこが問題なのかを確認してみる。
ソースの中の$RUBY_SOURCE/extディレクトリ以下にある拡張ライブラリのソースをコンパイルしてできたオブジェクトファイル( .o )は64ビットバイナリ。
MyMac:thread chcoopu$ file thread.o
thread.o: Mach-O 64-bit object x86_64
MyMac:thread chcoopu$
それに対して$RUBY_SOURCE/.ext/i686-darwin9.5.0ディレクトリ以下にあるのは何故かi386な32ビットバイナリ。
MyMac:i686-darwin9.5.0 chcoopu$ file thread.bundle thread.bundle: Mach-O bundle i386 MyMac:i686-darwin9.5.0 chcoopu$
つまりオブジェクトファイルをリンクする時に64ビットバイナリではなくなっているみたい。
ここでどうやってリンクしているかMakefileを確認してみると
LDSHARED = cc -dynamic -bundle -undefined suppress -flat_namespace
となっている。この呼び出されているccというのは/usr/bin/ccであり実体はgccである。
MyMac:~ chcoopu$ which cc /usr/bin/cc MyMac:~ chcoopu$ ls -l /usr/bin/cc lrwxr-xr-x 1 root wheel 7 10 22 00:14 /usr/bin/cc@ -> gcc-4.0 MyMac:~ chcoopu$
gccなら、コンパイル時と同じにオプションを渡してやればいいわけ。
今回はMakefileを変更するのではなく、Makefileを生成するためのconfigureを変更。しかも手抜き変更。
ccをgcc-4.0に固定しないように変更+x86_64用の設定。
※そのままMakefileに展開されるので、変数の書き方はMakefile形式で。
MyMac:ruby-1.8.6-p287 chcoopu$ diff configure configure.ORG 16520c16520 < darwin*) : ${LDSHARED='$(CC) -arch x86_64 -dynamic -bundle -undefined suppress -flat_namespace'} --- > darwin*) : ${LDSHARED='cc -dynamic -bundle -undefined suppress -flat_namespace'} MyMac:ruby-1.8.6-p287 chcoopu$
この状態でconfigure、makeをし直し。一度makeした後ならmake distcleanしてからconfigure、makeをすると。
そうすると、今度はちゃんと64ビットバイナリになった。
MyMac:i686-darwin9.5.0 chcoopu$ file thread.bundle
thread.bundle: Mach-O 64-bit bundle x86_64
MyMac:i686-darwin9.5.0 chcoopu$
そして、拡張ライブラリでもこけなくなった。めでたしめでたし。