D-7 <altijd in beweging>

Day to day life of a Perl/Go/C/C++/whatever hacker. May include anything from tech, food, and family.

2008年04月

奥田民生ツアー最終節@JCBホール。

正直そんなに民生ファンってわけでもないのだが、結構楽しめた。3月にできたばかりというJCBホールがよかったのも確実に理由の一つ。縦に3階分バルコニー席があって、奥に広がるのではなく、円筒状になっている。もはやメタリカやレイジでアリーナは懲りて、これからはジジィらしく席で座って見ることにした俺にとってはこのセットアップがちょうどよかった。

「息子」はツアー中もそんなに演奏しなかったらしいのだが、ちょうど聞けた。いい歌だね。本当のツアーフィナーレは今夜。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

EC2使ってると新しいイメージを作った時に毎回前のイメージをS3から消し損ねそうになる。お金がもったいないしいやんいやんなので、スクリプト書いた。

以下のように呼び出すとEC2に登録したイメージをderegister+バケットを空にする。
perl ec2-remove-image.pl -a ACCESS_KEY -s SECRET_KEY -b BUCKET_NAME -i IMAGE_NAME
ソースはこんな感じ。あんまりテストしてないから気をつけて!
use strict; use Net::Amazon::S3; use Getopt::Long; use constant EC2_DEREGISTER => "/usr/local/ec2/bin/ec2-deregister"; main(); sub main { my %options; if (! GetOptions(\%options, "access_key|a=s", "secret_key|s=s", "bucket|b=s", "image|i=s", )) { exit 1; } my $aws_access_key_id = $options{access_key} or die "No access_key"; my $aws_secret_access_key = $options{secret_key} or die "No secret_key"; my $bucket = $options{bucket} or die "No bucket"; my $image = $options{image} or die "No image"; system("/usr/local/ec2/bin/ec2-deregister", $image) == 0 or die "Failed to execute ec2-deregister"; my $s3 = Net::Amazon::S3->new( { aws_access_key_id => $aws_access_key_id, aws_secret_access_key => $aws_secret_access_key, retry => 1, } ); my $bucket = $s3->bucket($options{bucket}); my $response = $bucket->list; foreach my $key ( @{ $response->{keys} } ) { next unless ( $key->{key} =~ /image\.part\.\d+$/ || $key->{key} eq 'image.manife st.xml'); print "deleting '$key->{key}'\n"; $bucket->delete_key( $key->{key} ) or die $s3->errstr; } }
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

えーと、結論から言うと、柴咲コウに萌えるための映画です。以上。カンフーハッスルと一緒で話は支離滅裂、細かい伏線は何も説明されず、とりあえずなんか話が進んでいく。

柴咲コウはとてもとても凛々しく、美しかったです。

でも以上。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

Perlで*GLOBとか*{"$pkg\::foo"} = sub { .. }とかそういう書き方ができるわけです。で、これって言語上全く問題のない書き方だし、実際にstatic typedな言語では絶対できないものすごく便利な使い方があったりするんですが、これ実際には色々と制限がつきます。というか、副作用があったりなかったりする。

IRCでも言ってたんだけど、たとえばid:tokuhiromとかid:miyagawaとかid:Yappoとか、もう確実にそれがどんな副作用があるか分かった上で使っている人たちはまだいいんだけど、問題はそのコードをコピペしてしまう人たちがいるということ。コピペしてしまうのはもう人間の性なのでしょうがない。だから分かってる人こそ自重すべき。

と、#codereposとsvn経由でid:tokuhiromに因縁をつけてみたら、きれいにしてくれた、という話。

daisuke@beefcake HTTPx-Dispatcher$ svk log --limit 6 ---------------------------------------------------------------------- r52078 (orig r10420): tokuhirom | 2008-04-25 12:50:24 +0900 おこらないで!srezic! ---------------------------------------------------------------------- r52077 (orig r10419): tokuhirom | 2008-04-25 12:46:28 +0900 これならいいんじゃないのかな! ---------------------------------------------------------------------- r52076 (orig r10418): tokuhirom | 2008-04-25 12:43:07 +0900 黒魔術レス ---------------------------------------------------------------------- r52075 (orig r10417): daisuke | 2008-04-25 12:40:00 +0900 Exporter使わない版 ---------------------------------------------------------------------- r52074 (orig r10416): daisuke | 2008-04-25 12:27:27 +0900 あたらしめのExporter必須 ---------------------------------------------------------------------- r52073 (orig r10415): daisuke | 2008-04-25 12:26:58 +0900 Globでガボガボするのをやめてみる ----------------------------------------------------------------------
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

Debianでなんか問題がでていたCrypt::DH::GMPですが、昨日作った0.00004で問題を解決しました。普通に文字列が1文字分足りてなかった。くそ。なんでFreeBSDで起こらないのか不明

で、今日はpub_keyとcompute_keyのそれぞれをバイナリ+バイト単位での0パッドという形でMath::BigIntではなく直接文字列を作成するpub_key_twocとcompute_key_twocを追加した0.00005を作った。あとはGMPHack.pmというモジュールを作っているので、これを使ってNet::OpenID::Consumerを外部から変えてしまおう、というもくろみ
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

Perl5は実にさまざまな環境で動く。すると当然だが、C/XSでコードを書くときはその辺りも考慮にいれつつコードを書くのが良い。

File::MMagic::XSはApacheもmod_mime_magicをXSから直接使えるようにポートした物だ。これをPerl用にポートするとなると当然APRが使えないので環境の差を吸収してくれるレイヤーがなくなってしまう。んじゃあそのままCの関数使えばいいのかというと・・・Perl5がすでに吸収してくれるところが結構おおいのだな。

perldoc perlclibとすると、その辺りのC関数→Perlの内部関数の対応表を出してくれる。

が。書いてないものもある。そういうのはperlのソースコードを展開したところで.hファイルを色々grepしてるとでてくるので積極的に使っていくといいと思う。ちなみに今回そもそもこのエントリを書こうと思ったのはstat()に対応する関数はないのかと思って探してみたからだ。そしたらStat()というものを発見。S_ISDIR()とか、そのまわりの処理も結構マクロがかかれていて便利

あと、Perl API自体もバージョンによってちょっぴり違う事があるので、そういう時はDevel::PPPortを使ってppport.hを作成するといい。このppport.hはマクロでバージョン毎の違いを吸収してくれるとともに、その差異に該当する構文がディストリビューション内に存在するのかどうかをチェックしてくれるPerl スクリプトでもある:
perl -MDevel::PPPort -e 'Devel::PPPort::WriteFile()' # ppport.h作成 perl ppport.h # 実行!

あとは表示される診断結果に従って、#defineをファイルに入れていくだけ。便利よ!
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

書くの忘れてた。NetApp Focus 2008に行ってきました。NetAppは自分の古巣でもありますし、特にS3とか、仮想ストレージが台頭しつつある昨今、どんな戦略をとっていくのか興味もあったのです。

まずとほほに感じた点。いろんな人がプレゼンしてたけど、正直あれじゃあ寝る。普段YAPCやShibuya.pmで見てるプレゼンターたちの能力の高さが伺えた。本当に期待していたのはベンダーやクライアント会社の方たちのプレゼンで実際のユースケースでどういう工夫をしたか、なんだけど、なんか全然要旨を得ないし・・・。む〜ん。

NetApp経営陣は相変わらずの明瞭の歯切れだった。まぁこの辺は好き嫌いが分かれるところだろうな。あとはyazさんの話がおもしろかった。半分くらいは内部の人だった自分はわかることなんだけどね。yazさんはなんか偉くなってました(見かけが)。あ、なんとかマネジャーっていう肩書きになっていたので本当に偉くなってたみたいです。

しかし最初のまともな仕事がこの会社でよかったよ。ちゃんとしたエンジニアリングを教えてくれて。

で、NetAppも今後は仮想化していく方向のようだ。WAFLだけ超低価格で売ってくれないかなw


    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

自己啓発本って世にあふれてるけど、ほんとにそんなにみんな好きなの?ためになってるわけ?自己啓発本をまぁ参考に、ってのはなんとなくわかるんだけど、でも所詮他人のノウハウじゃない。その人のノウハウって本当にあなたに有効?

まぁそれはためになる新発見もあるとは思うけど、自己啓発本は読む=成功をイメージさせるマーケティングを行っているので、基本的なところで「つけるだけで幸せが訪れるパワーストーン」的な商法と同じだって事はどこかでわかってたほうがいいと思うんだよな。

まぁいいんだけどね。自己啓発本を参考にした、っていう成功者を見たことがないもんで、メディアとかでの取り上げ方を見てたりするとどうも、ね。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

結婚九ヶ月で離婚宣言」についての発狂小町を流し読みしたわけだが、この一言がすげぇ

「夫は、基本的には女が家事をするべきだけど、専業主婦ではない以上、最低限週一回でも夕飯を作れば、良くできた妻だと認めてくれる」そうです

・・・ってどんだけ上から目線!

いやあ、基本女性がご飯を作る作らないはこの際置いておいて、旦那のほうはたぶん一人暮らしとかしたことねぇんだろうなぁ。仕事しながら飯を作るには冷凍とかそれなりの工夫が必要だし、ともかく大変なんだよ!

自分だけが食べるならかなりの手抜きもできるんだけど、この旦那の場合はなんやかんやいいそうだしなぁ。作ってくれるだけいいじゃん。っていうか自分で作れよ。

ちなむと、「おいしい」と言うのを強要する人も嫌だ。まずいものはまずいんだ。「まずい」とは言うのはあれだけど、やんわりと言われたら、もっとうまくなろうよ。まぁその前に感謝の気持ちがないと難しいだろうが(というわけでいたちごっこ)
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

Memcached::libmemcachedでリークを発見しました。子クラスであるCache::Memcached::libmemcachedもその影響を受けます。以下のようなコードを書くとすぐわかるのですが、DESTROY()が毎ループではなく、global destruction時まで起きません。
for( 1..100) { my $cache = Cache::Memcached::libmemcached->new( { ... } ); }
これは単純にSV -> SV間のコピーをする時にSvREFCNT_incを呼んでしまうコードがMemcached::libmemcachedのコンストラクタにあったからです。sv_2mortal()することで解決しました。

報告してコミットした時にTimはちょうど寝る寸前だったのでリリースはまだもう少し先になりそうですが、待てない方はsvnから最新版を入手してください:
http://perl-libmemcached.googlecode.com/svn/trunk
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

Benchmark::ProgressBarというものを書きました。

追記:id:tokuhiromがほぼ同じ物を書いていたんだが、俺がsvk importしたらそのまま上書きしたらしいよ

長い時間かかるベンチマークを待つのが苦痛で苦痛でしょうがなかったので、なんとかしてプログレスバーを出したかったのです。

で、元々はこういうコードだったのを
use strict; use Benchmark qw(cmpthese); use Crypt::DH; use Crypt::DH::GMP; .... { print "Benchmarking instatiation cost...\n"; cmpthese(500, { pp => sub { Crypt::DH->new(%args) }, gmp => sub { Crypt::DH::GMP->new(%args) }, } ); }
こういうふうにすると:
use Benchmark::ProgressBar qw(cmpthese); # あとは一緒
こんな感じでプログレスバーが出るようになります。
Benchmarking instatiation cost... gmp: 35% [======================== ]
あら素敵☆なんとなくいつ終わるかわかるわ!

コードはめちゃくちゃ汚いです。まねしてはいけません。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

Crypt::DHは基本3つのフェーズからなっていて、
my $dh = Crypt::DH->new( p => ..., g => ... ); $dh->generate_keys(); $dh->compute_key( $some_public_key );
という3つのことをすると作業完了となる。で、tools/benchmark.plを書き直してこのフェーズ毎にベンチマークを取ってみた。結果はこんな感じ
perl tools/benchmark.pl Benchmarking instatiation cost... (warning: too few iterations for a reliable count) Rate gmp pp gmp 223/s -- -98% pp 10000/s 4380% -- Benchmarking key generation cost... Rate pp gmp pp 3.42/s -- -99% gmp 435/s 12621% -- Benchmarking compute_key cost... Rate pp gmp pp 3.39/s -- -99% gmp 370/s 10825% --
最初の初期化・インスタンス作成に関しては圧倒的にCrypt::DHのほうが速い。これは単純にCrypt::DH::GMPではnew() -> xs_new()というメソッドディスパッチをしてるからだと思う。

その後のgenerate_keys()およびcompute_key()に関しては圧倒的にGMPが速い。

ただし、上記はそれぞれの値を「文字列として」処理した場合の話だ。Crypt::DHはこれらの値をMath::BigInt形式で受け渡しするため、それぞれの値をMath::BigIntへ変換しないといけない。で、ここでまた遅くなる。

Crypt::DH::GMP::Compatはその部分の差異を吸収するためのモジュールだが、これだと実質パフォーマンス改善は数パーセントで、あまり意味がない(やってみたら5%から10%くらいだった)。だからNet::SSH::Perl とかを速くするには多少ソースコードに手を加える必要があるね。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

id:tokuhiromにそそのかされれてCrypt::DH::GMP (リンクはそのうち出現します)書きました。Crypt::DHってモジュールがあって、これに依存するモジュールが少々あるわけですが、このモジュールがすこぶる遅いわけですな。なんで遅いかというとこのモジュールは裏でMath::BigIntを使っているから。Math::BigInt自体はいわゆる任意精度数演算ライブラリで、これをポータブルな方法でPerl上で動作させるにはとてもよくできたモジュールです。

が。遅い。

裏でlibgmpやPari等を使っても、それでも遅い。その理由は単純で、Math::BigIntを使うと裏で何回も何回もSV -> mpz_t -> SV等の変換を含めた、「Perlらしい手法が実現できるための処理」が行われるからです。

Crypt::DHのソースコードを読む限り、Crypt::DHが行っている計算はたいしたことではない。だったら、普通にC structの中にmpz_t構造体を何個かもって、それらを使って直接GMPで計算したら速いんでないの?というのが今回のモジュールの趣旨です。まぁ、このモジュールだとlibgmpが必須になるから敷居が高くなるんだけど、どうせ実用的なレベルで計算を行うにはlibgmp必須だし、いいじゃん?ということで作ってみた。ちなみにソースコードのほとんどは半蔵門線車内の渋谷→大手町間で書いたよ!

さて、とりあえずうごくようになったのベンチマークを・・・と思ってベンチマークを動かしてみたら、これが遅い遅い。なんじゃこのスピード。全く話にならないので、ベンチを5000回から100回まで落としてみたらとりあえず走った。
daisuke@beefcake Crypt-DH-GMP$ perl -Mblib tools/benchmark.pl Rate pp gmp pp 1.70/s -- -98% gmp 112/s 6526% --
まぁ、速いことは実証できたかな。長いベンチマークは寝てる間にでも走らせておく。

あと、Crypt::DHはMath::BigIntオブジェクトを返すようになっているので、そのあたりの互換性を保つために-compatオプションを指定できるようにしておいた。以下のようにしておくと、今までのCrypt::DHを使っているモジュールでもCrypt::DH::GMPを使える・・・はず。
use Crypt::DH; use Crypt::DH::GMP qw(-compat);
まだちゃんと使ってないので人柱歓迎です。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

2年ぶりに京都旅行してきた。が。やっぱりとこかしこで作業してしまった。

で、Catalystでいうところの$class->config()が欲しかったので新幹線に乗ってる間に別パッケージにしてアップした。あと同じく新幹線の中でCache::Memcached::libmemcachedもバージョンアップしておいたよ
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

Memcached::libmemcachedにはstats()相当のものがないのだけれども、Cache::Memcached::libmemcachedではそれを実装しようと思ってMemcached::libmemcachedのほうにwalk_stats()というメソッドを足しました。それが実装されているバージョンの0.1901が昨日の夜にアップされた模様。

これはサブルーチンを渡すと、STATSコマンドを発行して、そのそれぞれの値に対してそのサブルーチンを実行します。ハッシュとかにつっこみたかったらその関数内でやるといいよ!

実際には俺がコミットした後にTimがだいぶ手を入れてくれた。tim++
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

追記:これ書いて、バグレポートしたとたんに4.50をかましてくれたよ。mlehman++。(まだコンパイル通るかどうかみてない)

このパッチで通ると思うよ。たぶん作者がperl 5.8でテストするの忘れてるだけだと思われ。ちなみに最初のPL_parser云々はたぶんそのまま消しちゃっても大丈夫。
--- Coro-4.49/Coro/State.xs 2008-04-07 02:47:38.000000000 +0900 +++ Coro-4.49.hacked/Coro/State.xs 2008-04-10 17:29:34.000000000 +0900 @@ -738,7 +738,7 @@ PL_localizing = 0; PL_dirty = 0; PL_restartop = 0; -#if !PERL_VERSION_ATLEAST (5,10,0) +#if PERL_VERSION_ATLEAST (5,10,0) PL_parser = 0; #endif @@ -1132,7 +1132,7 @@ croak ("Coro::State::transfer called with destroyed next Coro::State, but can only transfer to inactive states"); #if !PERL_VERSION_ATLEAST (5,10,0) - if (expect_false (PL_lex_state != LEX_NOTPARSING) + if (expect_false (PL_lex_state != LEX_NOTPARSING)) croak ("Coro::State::transfer called while parsing, but this is not supported"); #endif }
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

もうずいぶん前からCoroを使いたくて使いたくてしょうがなかったのだが、やっときたよ。Flickr APIを叩いて、非同期I/OしながらCoroで写真の情報をダウンロードするよ!

まず某sukebeさん作のWebService::Simpleを使ってみるよ(本当に使ったコードは違うフレームワーク用にいろいろついてたので、あまり利便性とか考えずに説明用のコードだけ書きだします)
package MyFlickrModel; use strict; use WebService::Simple; my $webservice = WebService::Simple->new( \%必要な引数 ); # 写真のIDを渡すとinfo, context, sizes, permsを全部ひっぱってくる sub find_photo { my $class = shift; my $photo_id = shift; my %photo; foreach my $type qw(info context sizes perms) { my $method = "find_photo_$type"; $photo{$type} = $class->$method($photo_id); } return \%photo; } # infoをひっぱってくる sub find_photo_info { my ($class, $id) = @_; my $response = $webservice->get( { method => "flickr.photos.getInfo", photo_id => $id } ); # エラーチェックとかはしょってます return $response->parse_xml; } # あと同じようにcontext, sizes, perms用の関数を書く # で、よびだす MyFlickrModel->find_photo( $photo_id );
でもこれだと写真1個につき都合4回、順番にFlickr APIを叩かなくちゃいけないね。そんなに待ちたくないんだな。非同期にしたいじゃん?で、ここでCoroですよ
Coroはcoroutineの実装をPerl5上でするわけですな。で、ちょっとハックだけれども、LWP::UserAgent系のモジュールの中身も適当にいじってくれるモジュールも用意してくれている。なのでそこらへんをまず追加:
use Coro; use Coro::Event; use Coro::LWP; use WebService::Simple; # 必ずCoro::LWPのあとに
で、先ほどのfind_photoをちょっと書き換える。ほんとにちょっとですよ?
sub find_photo { my $class = shift; my $photo_id = shift; my %photo; my @coros; # Coroを取っておく foreach my $type qw(info context sizes perms) { push @coros, async { # ここを別Coroに切り分ける my $method = "find_photo_$type"; $photo{$type} = $class->$method($photo_id); }; } $_->join for @coros; # Coroが終了するのを待つ return \%photo; }
以上! これだけで、10個の写真を検索→その後find_photo()で詳細を取得、というのが単純に17秒弱から5秒強に減った。Coroすげぇ

ちなみに同じことをしつつ、Cache::Memcached::libmemcachedでキャッシュすると0.2秒で終わるよ!
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

Power Nap - 要は昼寝だけどな。

5分から20分、一瞬だけ深く深く寝る。だらだらと寝ない。これだけのことだが、これが効く。このあとその数分で3時間はばりばり動ける。

まぁこればっかりは人それぞれだろうから「パワーナップするといいよ!」って言ったところでできない人はできないだろうけど、短時間の睡眠を得られる人は下手に徹夜みたいなことをするよりさっさと寝たほうがいいと思うんだ。

ってことで、6時半から起きてて、8時過ぎに5分寝てすっきりした俺様でした。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

P5Pにスパムがきていた。日本語だ。melmaだ。リンク先はちょっと文字化けしているが、内容は「キツイ口臭で、嫌われていませんか?」だってさ。

日本人の恥さらしだからやめてくれよ。
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

ちょっと前から急にMacBookのファンがうるさくなってて、どうしたんだと思ってたんだけど、とりあえず放っておいた。が、先ほどとうとう我慢の限界をすぎたのでどうにかすることに。

ちょっと前にdaemontoolsが悪影響あるのは学習済みだったので、まずtopで何が問題なのか見てみたら"mds"と"mdworker"というプロセスがCPU稼働率のほとんどを奪っていた模様。ぐぐってみるとどうやら微調整が可能なようなので 環境設定>Spotlightの「プライバシー」にいろいろ足してみたが、それだけでは何も変わらず。

もう少々ぐぐってみるとmdutilというコマンド発見どうやらSpotlightのインデックシングをコントロールできるらしい。これで書いてあったmdutil -i off /してみたらファンが止まった。おお!でもこれだとSpotlightが使えないってことなので、ほかのところに書いてあったmdutil -E /としてみて、今までのインデックスを破棄して、もう一回mdutil -i on /してみたところ、今度はmdsが動いているにも関わらず動いた。

・・・と思ったらこれを書いている先からまたmdsがキックしてCPUの6割〜すべてを占拠している。ええーい、offにするしかないのか?
    このエントリーをはてなブックマークに追加 mixiチェック Share on Tumblr

このページのトップヘ