BlackCurtain::DBI::Cache::Memcachedって早いの? 
Tuesday, January 11, 2011, 04:43 AM - Programing, Programing / Perl
Posted by Administrator
BlackCurtain::DBI::Cache::Memcachedは自分用途(も当然あるが)ではなく業務用途なので速度を気にする必要がある
1.0bはMemcachedこそ使うが、恩恵による速度向上と拡張による速度低下のバランスが麗しくないので、その検証

実験用のコードはこれ
#!/usr/bin/perl
use Benchmark;
use DBI;
use BlackCurtain::DBI::Cache::Memcached;

sub perlDBI
{
$dbh = DBI->connect(qw(dbi:mysql:database=a;host=172.16.2.205;port=3306 a));
$sth = $dbh->prepare("SELECT * FROM `a` WHERE 1 LIMIT 0,?");
$sth->bind_param(1,$ARGV[1],DBI::SQL_INTEGER);
$sth->execute();
while($sth->fetch()){
}
$sth->finish();
$dbh->disconnect();

return();
}

sub BlackCurtainDBI
{
$dbh = BlackCurtain::DBI::Cache::Memcached->connect(qw(dbi:mysql:database=a;host=172.16.2.205;port=3306 a),undef,{Memcached =>{servers =>[qw(127.0.0.1:11211)]}});
$sth = $dbh->prepare("SELECT * FROM `a` WHERE 1 LIMIT 0,?");
$sth->bind_param(1,$ARGV[1],DBI::SQL_INTEGER);
$sth->execute();
while($sth->fetch()){
}
$sth->finish();
$dbh->disconnect();

return();
}

sub BlackCurtainDBI_noncache
{
$dbh = BlackCurtain::DBI::Cache::Memcached->connect(qw(dbi:mysql:database=a;host=172.16.2.205;port=3306 a));
$sth = $dbh->prepare("SELECT * FROM `a` WHERE 1 LIMIT 0,?");
$sth->bind_param(1,$ARGV[1],DBI::SQL_INTEGER);
$sth->execute();
while($sth->fetch()){
}
$sth->finish();
$dbh->disconnect();

return();
}

printf("=== %d records, %d repeats ===\n",reverse(@ARGV));

timethese(
$ARGV[0],
{
"pDBI" =>\&perlDBI,
"BCDBI(a)" =>\&BlackCurtainDBI,
"BCDBI(b)" =>\&BlackCurtainDBI_noncache,
}
);

__END__

で、測定
(a)はMemcachedを使用、(b)は使用していない
> === 10 records, 100 repeats ===
> Benchmark: timing 100 iterations of BCDBI(a), BCDBI(b), pDBI...
> BCDBI(a): 0 wallclock secs ( 0.17 usr + 0.04 sys = 0.21 CPU) @ 476.19/s (n=100)
> BCDBI(b): 1 wallclock secs ( 0.15 usr + 0.03 sys = 0.18 CPU) @ 555.56/s (n=100)
> pDBI: 0 wallclock secs ( 0.10 usr + 0.02 sys = 0.12 CPU) @ 833.33/s (n=100)
> === 100 records, 100 repeats ===
> Benchmark: timing 100 iterations of BCDBI(a), BCDBI(b), pDBI...
> BCDBI(a): 1 wallclock secs ( 0.18 usr + 0.03 sys = 0.21 CPU) @ 476.19/s (n=100)
> BCDBI(b): 1 wallclock secs ( 0.65 usr + 0.04 sys = 0.69 CPU) @ 144.93/s (n=100)
> pDBI: 1 wallclock secs ( 0.18 usr + 0.03 sys = 0.21 CPU) @ 476.19/s (n=100)
> === 1000 records, 100 repeats ===
> Benchmark: timing 100 iterations of BCDBI(a), BCDBI(b), pDBI...
> BCDBI(a): 1 wallclock secs ( 0.69 usr + 0.02 sys = 0.71 CPU) @ 140.85/s (n=100)
> BCDBI(b): 3 wallclock secs ( 2.02 usr + 0.06 sys = 2.08 CPU) @ 48.08/s (n=100)
> pDBI: 3 wallclock secs ( 0.97 usr + 0.13 sys = 1.10 CPU) @ 90.91/s (n=100)
> === 10000 records, 100 repeats ===
> Benchmark: timing 100 iterations of BCDBI(a), BCDBI(b), pDBI...
> BCDBI(a): 6 wallclock secs ( 5.93 usr + 0.04 sys = 5.97 CPU) @ 16.75/s (n=100)
> BCDBI(b): 27 wallclock secs (17.03 usr + 0.87 sys = 17.90 CPU) @ 5.59/s (n=100)
> pDBI: 15 wallclock secs ( 4.98 usr + 0.83 sys = 5.81 CPU) @ 17.21/s (n=100)
> === 100000 records, 100 repeats ===
> Benchmark: timing 100 iterations of BCDBI(a), BCDBI(b), pDBI...
> BCDBI(a): 58 wallclock secs (56.26 usr + 0.22 sys = 56.48 CPU) @ 1.77/s (n=100)
> BCDBI(b): 240 wallclock secs (144.47 usr + 13.74 sys = 158.21 CPU) @ 0.63/s (n=100)
> pDBI: 131 wallclock secs (34.73 usr + 13.61 sys = 48.34 CPU) @ 2.07/s (n=100)
Memcachedを組み込む事で評判通り爆発的な速度が見込める事がわかる
拡張による速度低下も凄まじい(2~3倍)が、それを相殺しきれているのだから驚く
しかし(非現実的だが)10000レコードまで膨らむと1.0aではどうしようもなくなる、こんなの当たり前の有り得ない話(sub fetch{ ... }を見たまえ、こんなコードで10000レコードを扱えるわけがない)だが

ともかくMemcachedはぶっ飛ぶ程早い
では現状だとキャッシュ利用による速度向上幅はどの程度なのか
> === 10 records, 1000 repeats ===
> Benchmark: timing 1000 iterations of BCDBI(a), BCDBI(b), pDBI...
> BCDBI(a): 5 wallclock secs ( 1.82 usr + 0.53 sys = 2.35 CPU) @ 425.53/s (n=1000)
> BCDBI(b): 6 wallclock secs ( 2.03 usr + 0.30 sys = 2.33 CPU) @ 429.18/s (n=1000)
> pDBI: 5 wallclock secs ( 1.12 usr + 0.28 sys = 1.40 CPU) @ 714.29/s (n=1000)
> === 100 records, 1000 repeats ===
> Benchmark: timing 1000 iterations of BCDBI(a), BCDBI(b), pDBI...
> BCDBI(a): 5 wallclock secs ( 2.08 usr + 0.21 sys = 2.29 CPU) @ 436.68/s (n=1000)
> BCDBI(b): 9 wallclock secs ( 4.37 usr + 0.23 sys = 4.60 CPU) @ 217.39/s (n=1000)
> pDBI: 7 wallclock secs ( 1.97 usr + 0.35 sys = 2.32 CPU) @ 431.03/s (n=1000)
> === 1000 records, 1000 repeats ===
> Benchmark: timing 1000 iterations of BCDBI(a), BCDBI(b), pDBI...
> BCDBI(a): 10 wallclock secs ( 6.52 usr + 0.16 sys = 6.68 CPU) @ 149.70/s (n=1000)
> BCDBI(b): 36 wallclock secs (21.83 usr + 0.57 sys = 22.40 CPU) @ 44.64/s (n=1000)
> pDBI: 25 wallclock secs ( 9.88 usr + 1.32 sys = 11.20 CPU) @ 89.29/s (n=1000)
> === 10 records, 10000 repeats ===
> Benchmark: timing 10000 iterations of BCDBI(a), BCDBI(b), pDBI...
> BCDBI(a): 50 wallclock secs (19.32 usr + 3.02 sys = 22.34 CPU) @ 447.63/s (n=10000)
> BCDBI(b): 58 wallclock secs (19.18 usr + 2.28 sys = 21.46 CPU) @ 465.98/s (n=10000)
> pDBI: 46 wallclock secs ( 9.55 usr + 2.36 sys = 11.91 CPU) @ 839.63/s (n=10000)
> === 100 records, 10000 repeats ===
> Benchmark: timing 10000 iterations of BCDBI(a), BCDBI(b), pDBI...
> BCDBI(a): 47 wallclock secs (19.68 usr + 1.75 sys = 21.43 CPU) @ 466.64/s (n=10000)
> BCDBI(b): 110 wallclock secs (59.99 usr + 2.84 sys = 62.83 CPU) @ 159.16/s (n=10000)
> pDBI: 68 wallclock secs (18.11 usr + 3.25 sys = 21.36 CPU) @ 468.16/s (n=10000)
と、いうような結果になった
これは"恩恵による速度向上=拡張による速度低下"ということ
1.0bはまるで意味がない

付録(運用予定のセッション維持なコードを使ったベンチマーク)はREADMORE

Read More...
add comment ( 814 views )   |  permalink
BlackCurtain-DBI-Cache-Memcached-1.0b.tar.gz 
Monday, January 10, 2011, 09:41 AM - Release
Posted by Administrator
Archive : BlackCurtain-DBI-Cache-Memcached-1.0b.tar.gz (755B)

DBIそのままでMemcachedの恩恵を受けられるモジュール……の試作版

従来のDBIなコード
my $dbh = DBI->connect(qw(dbi:mysql:database=database;host=127.0.0.1;port=3306 user pass));

my $dbh = BlackCurtain::DBI::Cache::Memcached->connect(qw(dbi:mysql:database=database;host=127.0.0.1;port=3306 user pass),{Memcached =>{servers =>[qw(127.0.0.1:11211)]}});
と、変更するだけ

※注意
試作版なので恩恵によるパフォーマンス向上がプラスであるとは限らない件について
add comment ( 1774 views )   |  permalink
DBIのSubclassを書く 
Saturday, January 8, 2011, 07:48 AM - Programing, Programing / Perl
Posted by Administrator
いつだかTwitterでMySQL+Memcachedがどうたらこうたら言っていたが、最終的な結論としてDBIのSubclassとして実装するのが最強なんじゃないのかなあ、とか思う、これが大晦日だか元旦
そんな事を思い付いてしまったら年越し蕎麦をゆっくり食って餅の無差別殺人事件をゲラゲラ笑いながら見ている場合ではない
ともかく最適化を捨てても、既存のDBIなコードを変更せずともMemcachedの恩恵を受けるメリットは非常に大きいと思う
こうなれば「あけましておめでとう」などと心にもない挨拶回りをしている場合ではない、大体お年玉貰えないし

と、いう事でDBIを解読しながら色々模索するが、悩む部分がいくつかある

#!/usr/bin/perl
use DBI;

printf("dbh=%s\n",my $dbh = DBI->connect("dbi:mysql:database=a;host=172.16.2.130;port=3306","a",undef));
$dbh->{myparam} = "^o^";
printf("dbh->myparam = %s\n",$dbh->{myparam});
$dbh->disconnect();

__END__

の、出力
> dbh=DBI::db=HASH(0x13b13c60)
> dbh->myparam =
これは一体どういうことだろうか
HASHと見えているが、値が反映されない

少なくともこの状態はSubclassを書く上での例えば
package MyDBI;
use base qw(DBI);
use DBI;
use Cache::Memcached::libmemcached;

sub connect
{
my($h,@p) = @_;
$h->SUPER::connect(@_);
$h->{memcached} = new Cache::Memcached::libmemcached(...);
return($h);
}

こういうコードでCache::Memcached::libmemcachedのオブジェクトを維持できないことになる

全くわからなくてtieしてblessしてなんてやっていたが、実に単純
種が割れてしまえばなんて事はないのだが、丸一日要してしまった
DBIのdbh->{}やsth->{}な変数アクセスはtieされているので
package MyDBI::db;
use base qw(DBI::db);

sub FETCH
{
my($h,$k) = @_;
if($k =~ /^mydbi_/){
$h->{$k};
}else{
$h->SUPER::FETCH($k);
}
}

sub STORE
{
my($h,$k,$v) = @_;
if($k =~ /^mydbi_/){
$h->{$k} = $v;
}else{
$h->SUPER::STORE($k,$v);
}
}

このように割り込んで変数処理をしなければならない
よく考えれば当たり前の話なのだが

また$dbhとか$sthをhashとして扱うと値が見えないが、当然FETCH/STORE内で出力させれば
> FetchHashKeyName = NAME
> TraceLevel = 0
> ImplementorClass = DBD::mysql::db
> dbi_imp_data =
> State = SCALAR(0x1b287450)
> Username = miko
> Errstr = SCALAR(0x1b287410)
> Driver = DBI::dr=HASH(0x1b7bcab0)
> Statement =
> Name = database=a;host=172.16.2.130;port=3306
> dbi_connect_closure = CODE(0x1b7bcbc0)
> RootClass = CachedDBI
> Err = SCALAR(0x1b2873d0)
ちゃんとhashとして見える
これが見えなくて->{Statement}とか->{ParamValues}とか->{Database}とかで困っていた

こういう変数絡みでいくらか問題を抱えていたが、結局FETCH/STOREのこれだけで解決
脳味噌の柔軟性が失われつつあるなあ、とか思う事件

残るはアプローチの問題

Memcachedへ値を置く時のkeyをどうするか
当然DBIと異なる方法(executeでkeyを与えなければならない、とか)は方向性と反してしまう(useの一行を書き換えるのみで済ませたい)
普通に考えればSQL Queryがkeyだが、この場合insert/updateの後、一度selectしなければMemcachedを使えない

どのタイミングでMemcachedへ聞きにいくか
->execute(...)でSQL Queryを発行している以上、ここしかない
しかし実際の値を引っ張るのは->fetch(...)なので関数を跨ぐことになる、余り好ましくない
->execute(...)にしても内部へ割り込みたい(StatementやNUM_OF_FIELDSの関係)が、xsなので厳しい

->execute(...)でチェックのみ、->fetch(...)するとしても->fetch(...)は複数回呼ばれる
対してMemcachedのgetは一度
と、なると->execute(...)か最初の->fetch(...)で値を全て読み込む事になる、好ましくない
しかし->fetch(...)ごとにkeyを与えると、分散している場合に整合性が保てなくなる可能性がある、それを回避するために->fetch(...)し続けて値が無ければ->execute(...)というのもおかしな話だ

なんて頭の中で巡り巡る
この割り込み部分はまだいい案が出ない

とりあえず試し書きしたコードを貼っておく

Read More...
add comment ( 1848 views )   |  permalink
Apache+mod_perl Perl*Var 
Tuesday, January 4, 2011, 10:32 PM - Programing, Programing / Perl
Posted by Administrator
忘れたら困る個人的なApache+mod_perlの挙動
とは言っても複雑怪奇な仕様ではなく、十分推測の範疇だが

Apacheはこう
<Location /level1>
PerlSetVar set level1
PerlAddVar add level1
</Location>
<Location /level1/level2>
PerlSetVar set level2
PerlAddVar add level2
</Location>
<Location /level1/level2/level3>
PerlSetVar set level3
PerlAddVar add level3
</Location>


各階層で実行するコードはこう
#!/usr/bin/perl
use Apache2::RequestRec;
use Apache2::RequestUtil;
use APR::Table;

printf("Content-Type: text/html\r\n\r\n");
printf("%s<br>\n",Apache2::RequestUtil->request()->location());
printf(" PerlSetVar: %s<br>\n",Apache2::RequestUtil->request()->dir_config("set"));
printf(" PerlAddVar: %s<br>\n",Apache2::RequestUtil->request()->dir_config("add"));

__END__


結果は捻りもなくこちら
> /level1
> PerlSetVar: level1
> PerlAddVar: level1

> /level1/level2
> PerlSetVar: level2
> PerlAddVar: level1

> /level1/level2/level3
> PerlSetVar: level3
> PerlAddVar: level1

PerlAddVarの値は->dir_config(...)で取ると常に先頭の値がscalarで返る
arrayで取る必要があるならば->dir_config()->get(...)とする

これらのPerl*Varはhttpd.confの影響を受ける
挙動そのものは推測できる範囲だが、つまり
<Location /level1/level2/level3>
PerlSetVar set level3
PerlAddVar add level3
</Location>
<Location /level1>
PerlSetVar set level1
PerlAddVar add level1
</Location>
<Location /level1/level2>
PerlSetVar set level2
PerlAddVar add level2
</Location>

ならば、/level1/level2/level3の出力はこのように変化する
> /level1/level2
> PerlSetVar: level2
> PerlAddVar: level3 level1 level2
注意すべきは->location()が/level1/level2/level3を返す事がなくなる、ということだ

これらの前提で変数継承
<Location /level1/level2/level3>
PerlSetVar set level3
PerlAddVar add level3
PerlSetVar level3 3
</Location>
<Location /level1>
PerlSetVar set level1
PerlAddVar add level1
PerlSetVar level1 1
</Location>
<Location /level1/level2>
PerlSetVar set level2
PerlAddVar add level2
PerlSetVar level2 2
</Location>

表示用の無駄に長いコード
printf(" levels: %s %s %s<br>\n",Apache2::RequestUtil->request()->dir_config("level1"),Apache2::RequestUtil->request()->dir_config("level2"),Apache2::RequestUtil->request()->dir_config("level3"));

結果
> /level1
> PerlSetVar: level1
> PerlAddVar: level1
> levels: 1

> /level1/level2
> PerlSetVar: level2
> PerlAddVar: level1 level2
> levels: 1 2

> /level1/level2
> PerlSetVar: level2
> PerlAddVar: level3 level1 level2
> levels: 1 2 3

ここまでで基本的な動作が観測できたので、次に->location_merge(...)で意図的に値を弄る

実際にはファイルシステム上に存在していないlevel4階層の設定を変なところに追記
<Location /level1/level2/level3>
PerlSetVar set level3
PerlAddVar add level3
PerlSetVar level3 3
</Location>
<Location /level1>
PerlSetVar set level1
PerlAddVar add level1
PerlSetVar level1 1
</Location>
<Location /level1/level2/level3/level4>
PerlSetVar set level4
PerlAddVar add level4
PerlSetVar level4 4
</Location>
<Location /level1/level2>
PerlSetVar set level2
PerlAddVar add level2
PerlSetVar level2 2
</Location>

この設定でlevel4階層が存在したと仮定して今までの話ならこの出力が想定される
> /level1/level2
> PerlSetVar: level2
> PerlAddVar: level3 level1 level4 level2
> levels: 1 2 3 4

->location_merge(...)を含めた検証用コード
#!/usr/bin/perl
use Apache2::RequestRec;
use Apache2::RequestUtil;
use APR::Table;

Apache2::RequestUtil->request()->location_merge("/level1/level2/level3/level4");

printf("Content-Type: text/html\r\n\r\n");
printf("%s<br>\n",Apache2::RequestUtil->request()->location());
printf(" PerlSetVar: %s<br>\n",Apache2::RequestUtil->request()->dir_config()->get("set"));
printf(" PerlAddVar: %s %s %s %s<br>\n",Apache2::RequestUtil->request()->dir_config->get("add"));
printf(" levels: %s %s %s %s<br>\n",Apache2::RequestUtil->request()->dir_config("level1"),Apache2::RequestUtil->request()->dir_config("level2"),Apache2::RequestUtil->request()->dir_config("level3"),Apache2::RequestUtil->request()->dir_config("level4"));

__END__


結果
> /level1/level2/level3/level4
> PerlSetVar: level4
> PerlAddVar: level4
> levels: 4

> /level1/level2/level3/level4
> PerlSetVar: level4
> PerlAddVar: level4
> levels: 4

> /level1/level2/level3/level4
> PerlSetVar: level4
> PerlAddVar: level4
> levels: 4
どの階層でも同一の、->location_merge(...)で与えた階層しか得られなくなる

もし凝ったシステムを作るつもりがなければ全く知らなくていいこと

ああ、余談だが仮に各Locationに独自のPerl*Handlerを仕掛けたとして、その挙動はPerlSetVarと同一
最後のPerl*Handlerで仕掛けたhandler:methodのみが走る
add comment ( 2195 views )   |  permalink
LG E2360V-PNを3枚購入……したが 
Tuesday, January 4, 2011, 02:30 AM - Hardware
Posted by Administrator
遂に作業領域の拡張のため、LG E2360V-PNを3枚購入
これで3870X2が1出力、2600XTX2が4出力となり、2600XTX2である意味をやっと持つ事になる
2枚のままでは一体何の4GPUなのかまるでわからん

びふぉー

あふたー

横9060pxはまゆらをどこに置くか悩む
/var/log/messagesを喋るまゆらは案外重要度が高い

しかしLG E2360V-PNは評判(レビュー)を裏切らない程度に問題を抱えている
安かろう悪かろうなのだ

・貧弱貧弱ゥ

製品写真、もしくは製品を見る限り不安定感を拭えない構造、つまり倒れそうだとか折れそうだとか曲がりそうだとか、デザインを重視する余り実用は愚か重力にすら耐えられない設計思想が見え隠れするが、全くそんな事はなかった
単純にパネルそのものが超軽量、LED液晶は従来より軽量であるというような謳い文句を具体化している

しかし残念ながらこの設計思想は大きなミスを犯している
ディスプレイの接地面が完全である、空間に固定されている状態を想定して設計している
もし接地面が何らかの水平方向に対する運動エネルギーを持った場合、ディスプレイ本体にディスプレイ本体が持つ質量以上の運動エネルギーを受けた場合を想定していない

つまり凄まじく揺れるって事だ

例えばこの長文を真面目に読んでいるあなたが椅子に座り直したとしよう
足を伸ばした時にちょっとだけデスクにぶつかって運動エネルギーが生じたとしよう
マウスを横に引っ張りすぎて置き直したとしよう
喉が渇いて飲み物のたっぷり入ったグラスをデスクに置いたとしよう

もしそれでディスプレイが凄まじく揺れるようなら、あなたの今使っているディスプレイの設計思想はLG E2360V-PNと同様だし、揺れないならば通常の生活空間での使用を前提とした設計思想で造られた製品である事がわかる

・色弱色弱ゥ

評判では青すぎるという話だった
確かにその通りだが、白色LEDバックライトの欠点を模倣していると言える

ある一定の照度輝度を前提に色調整をしたとする
これ以下ならば黄色が相対的に強くなり、これ以上ならば青が強くなる
基準となる照度輝度が低ければ低い程この現象はより明確に観測できる
逆に基準となる照度輝度が高くなれば観測しにくくなる

簡単に言えばfpsゲームで野外の風景が綺麗に見えるよう色を調整したとしよう
そして薄暗い室内戦闘になった、この時あなたは突然色盲になって画面が黄色に見えるだろう
あなたは敵を見付けたので、ありったけのスモークグレネードを投げ、火炎放射器で敵を焼き払い、RPG-7で木っ端微塵に吹き飛ばした、この時あなたは突然色盲になって画面が青く見えるだろう
火炎放射器で炎上した家屋の中、至近距離で発射したRPG-7の爆風であなたは死んで画面が真っ赤に染まるが、あなたはもう死んでいるので綺麗な赤はもう見えない

ちなみに推測だが、グレアパネル用ではないか
目に突き刺さる光度まで発光させた状態で色調整を行えば一応色のレンジは正常に見える
しかし同時に色盲どころか盲目になってしまう、勘弁してくれ

この現象は白色LEDバックライトである限り個体差はあれど発生する問題だ、注意すべき点と言える
4万円の専用眼鏡を買うくらいなら最初からまともなディスプレイを選ぶべきだ
add comment ( 2357 views )   |  permalink

<<First <Back | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Next> Last>>