2008/06/27

はてな
TheSchwartzも良いのですが、MySQLが必要だったりポーリングのタイムラグがあったりと、要件に合わない場合というのも出て来たりします。こんな時はどうするか、解決策の一つにメッセージバスがあります。
メッセージバスとして一般的に有名なのが、DBusです。Linux等では数多くのアプリケーションが採用しており、GNOMEもBonoboからの移行を表明、KDE4でも採用される様です。ちなみに私が愛用している軽量デスクトップROXは当初に採用しており、ちょっとしたpythonのコードでリッチなアプリケーション間通信が実現出来ています。他にも既に色々なプロジェクトでDBusが使われています。
さて今日はNet::DBusを使い、TheSchwartzと似たような事が出来ないかをWindows上でやってみようかと思います。
まず、DBusのWindows実装であるwinDBusをインストールします。winDBusはこちらで配布されておりバイナリもダウンロード出来ます。
ここでまず、DBusの動作を確認します。winDBusを展開したディレクトリの中のbinフォルダに移動し以下の様にしてデーモンを起動します。
C:¥winDBus¥> dbus-daemon.exe --config-file=C:/winDBus/dbus/bin/session.conf
winDBusを"C:¥Programme"に展開された場合には
C:¥Programme¥> dbus-daemon.exe --session
とするだけでも動作します。winDBusの場合、unixドメインソケットをサポートしていませんので、上記session.confに書かれている
<listen>tcp:host=localhost,port=12434</listen>
の値を環境変数「DBUS_SESSION_BUS_ADDRESS」に設定します。
set DBUS_SESSION_BUS_ADDRESS=tcp:host=localhost,port=12434
その上でdbus-daemon.exeと同じ位置にあるtest_names.exeを実行し
Successfully acquired name 'org.freedesktop.DBus.Test'
Successfully acquired name 'org.freedesktop.DBus.Test-2'
Successfully acquired name 'org.freedesktop.DBus.Test_2'
と表示されれば動作確認は終了です。
次にNet::DBusをインストールします。まずNet::DBusはビルドにpkg-configを使うので`pkg-config --cflags dbus-1`が扱えないVCではビルドに難があります。私の場合はMinGWを使用しました。
まず、winDBusに同梱されていなかったdbus-1.pcを作成します。winDBusをインストールしたディレクトリを指定して
prefix=C:/winDBus/dbus
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: D-Bus
Description: D-Bus Protocol Library
Version0.90
Libs: -LC:/winDBus/dbus/lib -ldbus-1
Cflags: -IC:/winDBus/dbus/include
という内容でdbus-1.pcを保存します。次に環境変数PKG_CONFIG_PATHにこのdbus-1.pcを保存したディレクトリを設定し、cpanからインストールします。おそらくこれでインストール出来るかと思いますが、出来なかった方はVCのコンパイラのパスを外し、MinGWのパスを設定して確認して見て下さい。
これでようやくperlからDBusを使える準備が揃いました。
さて、サーバのソース。DBusのセッションからバスを取得し、サービスをエクスポート、ワーカーの役目をするオブジェクトを作成します。ワーカーオブジェクトにはJobStartというメソッドを定義します。
#!/usr/bin/perl

use strict;
use warnings;
use threads;
use YAML;
use Net::DBus;
use Net::DBus::Service;
use Net::DBus::Reactor;

package MyWorker;
use base qw(Net::DBus::Object);
use Net::DBus::Exporter qw(net.kaoriya.mattn.DBusWorker);

sub new {
    my $class = shift;
    my $service = shift;
    my $self = $class->SUPER::new($service, "/MyWorker");
    bless $self, $class;
    
    return $self;
}

dbus_method("JobStart", [["dict", "string", "string"]], [["dict", "string", "int32"]]);
sub JobStart {
    my $self = shift;
    my $job = shift;
    my $thread = threads->new(sub {
        my $job = shift;
        printf "processing job%03d : %s\n", threads->tid, $job->{request};
        sleep 10;
        printf "done job%03d\n", threads->tid;
    }, $job);
    return { "id" => $thread->tid };
}

package main;

my $bus = Net::DBus->session();
my $service = $bus->export_service("net.kaoriya.mattn.DBusWorker");
my $object = MyWorker->new($service);
Net::DBus::Reactor->main->run();
DBusは非同期通信も提供していますが、リクエストを連続で送った際サーバがビジー状態だとクライアントが側が応答を待ってロックします。
そこで上記ソースではスレッドを起こし、重たい処理をさせる様になっています。スレッド内では"threads->tid"で言わばジョブ番号の役割をするスレッドIDを使ってユニークな処理が出来るかと思います。
さらにクライアントのコード。
#/usr/bin/perl

use strict;
use warnings;

use Net::DBus;
use Net::DBus::Reactor;
use Net::DBus::Callback;
use Net::DBus::Annotation qw(:call);

my $request = shift @ARGV || 'request at '.time();
my $bus = Net::DBus->session();
my $service = $bus->get_service("net.kaoriya.mattn.DBusWorker");
my $object = $service->get_object("/MyWorker");
my $res = $object->JobStart({ request => $request });
printf "job was accepted as job%03d\n", $res->{id};
DBusセッションからもらったMyWorkerオブジェクトのJobStartメソッドにリクエスト文字列を指定して送信します。
まずクライアントの実行結果は
C:¥winDBus¥test¥> perl client.pl
job was accepted as job001
C:¥winDBus¥test¥> perl client.pl
job was accepted as job002
C:¥winDBus¥test¥> perl client.pl
job was accepted as job003
クライアントではjob001を実行した後、10秒待ってjob002、job003を投入しました。そしてサーバの実行結果
processing job001 : request at 1214560175
done job001
processing job002 : request at 1214560192
processing job003 : request at 1214560195
done job002
done job003
おぉ!非同期ですね!
DBusでは、引数の構成および戻り値の構成をdbus_methodにて指定でき、文字列(string)や数値(int32等)、配列(array)、タプル(tuple)、構造体(struct)を引き渡したり、戻り値として返したり出来ます。
さらに、Net::DBusに同梱されている"example-client-async.pl"の様に非同期送信結果を受け取り、完了イベントで結果を受け取るという事も出来ます。
#/usr/bin/perl

use warnings;
use strict;

use Net::DBus;
use Net::DBus::Reactor;
use Net::DBus::Callback;
use Net::DBus::Annotation qw(:call);

my $bus = Net::DBus->session();

my $service = $bus->get_service("org.designfu.SampleService");
my $object = $service->get_object("/SomeObject");

print "Doing async call\n";
my $reply = $object->HelloWorld(dbus_call_async, "Hello from example-client.pl!");

my $r = Net::DBus::Reactor->main;

sub all_done {
    my $reply = shift;
    my $list = $reply->get_result;
    print "[", join(", ", map { "'$_'" } @{$list}), "]\n";

    $r->shutdown;
}

print "Setting notify\n";
$reply->set_notify(\&all_done);

sub tick {
    print "Tick-tock\n";
}


print "Adding timer\n";
$r->add_timeout(500, Net::DBus::Callback->new(method => \&tick));

print "Entering main loop\n";
$r->run;
今回はWebで扱いやすい様に、非同期で結果を待機する処理ではなくサーバ側でスレッドを実行していますが、デスクトップクライアントを作る際にはdbus_call_asyncを使う事になるかと思います。

TheSchwartzも面白いですが、DBusも面白いですね。
perlの他にも、C(GLib)はもちろんpythonやJava等でも実装されています(参照)。
皆さんも試してみては如何でしょうか。

2008/06/26

はてな
vimで自前でYAML読み込むとか面倒くさすぎる。
こう言う時はif_pythonとかif_perlとかを使わせてもらう。運良くvimスクリプトはjsonと相性が良いのでYAMLを読み込み、JSONに変換してvimに戻してあげる。
function! LoadYAML(file)
  perl << EOF
use YAML::Syck;
use JSON::Syck qw(Dump);
eval {
  VIM::DoCommand("let ret = " . Dump(LoadFile("".VIM::Eval('a:file'))));
};
VIM::DoCommand("let v:errmsg = substitute('$@', \"\\n\", '', 'g')") if $@;
EOF
  if !exists('ret')
    throw v:errmsg
  endif
  return ret
endfunction

echo LoadYAML("config.yaml")
戻り値はDictionary形式になります。
読み込めなかった場合はthrowしているのでvim7限定になりますがcatchしてやって下さい。

さて、if_perlですがperl510で動かなくなってました。今日パッチを作成してvim-devに送ったのですが、如何せん自信がありません(Shibuya.xsでvimmerな皆様、どうか私にお力をお貸し下さい)。
パッチは
vim72-perl510-fix.diff
にあります。不具合報告等あればご連絡下さい。

はてな
最近TheSchwartが賑わってる様ですね。
TheSchwartzで仕事をあとにまわす - bits and bytes

なければ勝手に作ってくれるのかなと思ってSYNOPSISのコードを実行してみたけどやっぱり自動でできたりはしなそうだったので調べたらCatalyst and TheSchwartz: Reliable JobQueue in a great framework - Voxschema.sqlを使うといいと書いてありました。このスキーマをmysqlで実行すればTheSchwartzのキューを管理するためのテーブルが出来上がります。

http://labs.gmo.jp/blog/ku/2008/06/theschwartz.html

Twitter / ku: TheSchwartzおもしろかった sqliteで動...

TheSchwartzおもしろかった sqliteで動くようにしたいけどsqliteようのschemeかきかたわかんない

http://twitter.com/ku/statuses/843135311

って事でSQLiteでも動く様に出来ないか調べてみました。
schema.sqlは、MySQL用のスキーマで
CREATE TABLE funcmap (
        funcid         INT UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT,
        funcname       VARCHAR(255) NOT NULL,
        UNIQUE(funcname)
);

CREATE TABLE job (
        jobid           BIGINT UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT,
        funcid          INT UNSIGNED NOT NULL,
        arg             MEDIUMBLOB,
        uniqkey         VARCHAR(255) NULL,
        insert_time     INTEGER UNSIGNED,
        run_after       INTEGER UNSIGNED NOT NULL,
        grabbed_until   INTEGER UNSIGNED NOT NULL,
        priority        SMALLINT UNSIGNED,
        coalesce        VARCHAR(255),
        INDEX (funcid, run_after),
        UNIQUE(funcid, uniqkey),
        INDEX (funcid, coalesce)
);

CREATE TABLE note (
        jobid           BIGINT UNSIGNED NOT NULL,
        notekey         VARCHAR(255),
        PRIMARY KEY (jobid, notekey),
        value           MEDIUMBLOB
);

CREATE TABLE error (
        error_time      INTEGER UNSIGNED NOT NULL,
        jobid           BIGINT UNSIGNED NOT NULL,
        message         VARCHAR(255) NOT NULL,
        funcid          INT UNSIGNED NOT NULL DEFAULT 0,
        INDEX (funcid, error_time),
        INDEX (error_time),
        INDEX (jobid)
);

CREATE TABLE exitstatus (
        jobid           BIGINT UNSIGNED PRIMARY KEY NOT NULL,
        funcid          INT UNSIGNED NOT NULL DEFAULT 0,
        status          SMALLINT UNSIGNED,
        completion_time INTEGER UNSIGNED,
        delete_after    INTEGER UNSIGNED,
        INDEX (funcid),
        INDEX (delete_after)
);
というSQLなので、これをSQLite用に書き換えます。
cl.pocari.org - SQLite で auto-increment なフィールドを作成する方法

つまり,SQLite で auto-increment なフィールドを作りたければ,INTEGER PRIMARY KEY を指定してあげればいいらしい.

http://cl.pocari.org/2006-02-12-1.html
こちらの記事でも書かれている通り、SQLiteではINTEGER PRIMARY KEYを指定すればok。
※ちなみにUNSIGNEDとかNOT NULLとか付けると動かないです。

で書き換えたSQLは以下の通り
CREATE TABLE funcmap (
        funcid         INTEGER PRIMARY KEY,
        funcname       VARCHAR(255) NOT NULL,
        UNIQUE(funcname)
);

CREATE TABLE job (
        jobid           INTEGER PRIMARY KEY,
        funcid          INTEGER NOT NULL,
        arg             MEDIUMBLOB,
        uniqkey         VARCHAR(255) NULL,
        insert_time     INTEGER UNSIGNED,
        run_after       INTEGER UNSIGNED NOT NULL,
        grabbed_until   INTEGER UNSIGNED NOT NULL,
        priority        SMALLINT UNSIGNED,
        coalesce        VARCHAR(255),
        UNIQUE(funcid, uniqkey)
);
CREATE INDEX job_idx_1 ON job (funcid, run_after);
CREATE INDEX job_idx_2 ON job (funcid, coalesce);

CREATE TABLE note (
        jobid           INTEGER NOT NULL,
        notekey         VARCHAR(255),
        value           BLOB
);

CREATE TABLE error (
        error_time      INTEGER UNSIGNED NOT NULL,
        jobid           INTEGER NOT NULL,
        message         VARCHAR(255) NOT NULL,
        funcid          INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX error_idx_1 ON error (funcid, error_time);
CREATE INDEX error_idx_2 ON error (error_time);
CREATE INDEX error_idx_3 ON error (jobid);

CREATE TABLE exitstatus (
        jobid           INTEGER PRIMARY KEY,
        funcid          INTEGER NOT NULL DEFAULT 0,
        status          SMALLINT UNSIGNED,
        completion_time INTEGER UNSIGNED,
        delete_after    INTEGER UNSIGNED
);
CREATE INDEX exitstatus_idx_1 ON exitstatus (funcid);
CREATE INDEX exitstatus_idx_2 ON exitstatus (delete_after);
あとはコレを
# sqlite3 the_schwartz < theschwartz_schema.sql
としてDBファイルを作る。
さてサーバのコードはDSNを"dbi:SQLite:the_schwartz"にするだけ。
#!/usr/bin/env perl
package MyWorker;
use strict;
use utf8;
use warnings;
use base qw( TheSchwartz::Worker );
use Data::Dumper;

binmode STDERR, ":encoding(cp932)" if $^O eq "MSWin32";

sub work {
    my ($class, $job) = @_;
    warn "お仕事ですよ! @{[ Dumper($job->arg) ]}\n";
    $job->completed();
}

package main;
use strict;
use warnings;
use TheSchwartz;

my $client = TheSchwartz->new(
    databases => [ +{ dsn => 'dbi:SQLite:the_schwartz' } ]
);
$client->can_do('MyWorker');
$client->work();
さらにクライアントのコード
#!/usr/bin/env perl
use strict;
use warnings;
use TheSchwartz;

my $client = TheSchwartz->new(
    databases => [ +{ dsn => 'dbi:SQLite:the_schwartz' } ]
);
$client->insert('MyWorker' => +{ hoge => "fuga" });
実行すると
お仕事ですよ! $VAR1 = {
          'hoge' => 'fuga'
        };
という風にサーバ側で表示されます。 ちなみに、DBD::SQLiteのバグで
closing dbh with active statement handles at .../Data/ObjectDriver/Driver/DBI.pm line 566.
という表示が出る様ならばココにある"issue-17603.tar.gz"のパッチを当てるといいです。どうやらこのバグ、デグレっぽいですね。

ま、結局SQLiteでやっちゃったら同一マシンだし負荷分散にはならない(UIロックを避けるという意味では有用)んですけどね。

2008/06/24

はてな
ようやくblosxomで動く用になりました。
tomblooハックス - share on WordPressにポストするためのMetaWeblog API « ku

アップデート 2008.6.24

mattnさんにいただいたBig Sky :: tomblooハックス90_MetaWeblog.jsのパスワードをパスワードマネージャに保存するパッチを文字化けしないようにしてtombloo - Google Codeにコミットしました。ページのView raw fileのところからダウンロードしてください。

http://ido.nu/kuma/2008/06/07/werwer/
google codeのtomblooから90_MetaWeblog.jsを取得し、"extensions/tombloo@brasil.to/chrome/content/library/"に入れると動きます。詳しい説明はkuさんのページを確認して下さい。
kuさんのスクリプトから、若干手を入れさせて頂いていてXMLRPCのエントリポイントである"extensions.tombloo.posters.MetaWeblog.endpoint"の他に"extensions.tombloo.posters.MetaWeblog.mediapath"という設定が出来る様になっています。
ブログツールの中には画像をアップロードするパスが設定出来る物もあり、環境に合わせて
mediapathの設定
の様に設定します。これで90_MetaWeblog.jsが使えるブログツールが増えたかと思います。恐らくMTでもendpointを
http://www.example.com/cgi-bin/mt/mt-xmlrpc.cgi
の様に設定すれば動きます。確認してませんが。
今回blosxomでは"SourceForge.net: BXR: Blosxom XML-RPC Interface"を使い、特定のカテゴリ(90_MetaWeblog.jsは「reblog」というカテゴリ)のみ
  • インデックスやRSSから隠す
  • dynamic_cacheしない
  • アクセスランキングに載せない
処理を入れ、reblogサイトっぽく動く様になりました。名づけてreblosxomとします!
blosxom-xmlrpc.cgiを色々なブログツールに対応させる為のパッチを当てれば、日本語周りや動的なカテゴリ変更などにも対応出来るblosxom-xmlrpc.cgiが出来上がります。オリジナルのBXRで上手く行かない人は試してみて下さい。
実際に以下の様にして
reblosxomでポスト
ポストした結果が「reblogカテゴリ」となります。
自分の写真しかreblogしてないので、全くreblogじゃないんですが家族や友人の写真からreblogなんて事ならokですかね...
わずか3クリック程でreblog出来てしまうtombloo & 90_MetaWeblog.js すばらしいです。

今回blosxomプラグイン等に行った修正は後日公開したいと思います。

ku++ brazil++ tombloo++ blosxom++

2008/06/20

はてな
これすごいわ。
wildoptions=autoとcomplete=lが凄い件 - Dis Communication - 符号無し

vimperator1.2pre 2008-06-19以降で実装されてるwildoptions=autoとcomplete=lがlifechangingだったので紹介しておきますね。

何が凄いって
:set complete=l
が凄い。「たかがtab押さなくても良くなっただけだよね」と思うでしょうが、使ってみたら無茶苦茶便利。
vimperator使いだと、おそらくURLを開くのに
:open http://...
とか「<c-l>」してアドレスバーにフォーカス合わしたりしてるかと思いますが、firefox3で登場したアドレスバーの便利機能(おせっかい機能とも言われてるらしい)、「AweSomeBar」
firefox-awesomebar
:open
で使えるのです。例えば
:open twitter teramako
とすると
vimperator-awesomebar
と出るんです。URLなんか殆ど打たなくても良くなります。あとは通常と同じくtabで選べばok。すばらしい。
これでおそらくvimperatorがブラウジング最速になったかと思います。

ところで、vimperator使ってると稀にパススルーモードが外れてしまい、「Google Readerでキーバインドが効かなくなった」とか「LivedoorReaderで上手く動かなくなった」って事になったりします。
私の場合、以下の様にキーマップして回避しています。
noremap <c-i> :js modes.passAllKeys = true<cr>
ただ、これを使ってて気づいたのですがどうやらvimperatorの補完はmapで実行する「:ex」コマンドにも反応してる臭い。これはいずれ直るかと思うけど気になる様だったらパッチを送ってみよう。 とりあえずは、mapで実行するんじゃなくてaddUserMap使ってやる事にした。
javascript <<EOM
liberator.mappings.addUserMap([liberator.modes.NORMAL], ['<C-i>'],
    'Pass through mode',
    function () { liberator.modes.passAllKeys = true }
);
EOM

2008/06/19

はてな
グダグダの文章ですみません。
perl-monger.orgってはてなグループじゃダメなの? - DTP+印刷営業メモ

なんとなくだが近所の人がperl-monger.orgな話をしていてさっきページを見ていたんだけど、これってはてなグループ(なんとか部みたいな)のじゃダメなのかなぁ、と思った。

...snip...

っていうかWikiに色々なコンテンツを追加していくてのはダメなんだろうかと普通に思ったんだけど。

Wikiでもログイン制にしてしまえば同じような事は出来るし、弄れば同じ風貌に出来なくもないと思う。ただWikiだと筆者に掛かる責任ぽい物だとか、評価だとか、「perl-mongers」っていう組織感だとかが表現し辛いんじゃないかなぁ。
例えば「Journal of miyagawa」がWikiだったら少し感じが変ってくる様な気がする。(私だけかもしれない)

記事を原稿用紙に書くのかフリースケッチに描くのか...そんな程度の違いなのかもしれないけど、私は今の形がCoolだと思う。

答えになってないなぁ。

追記
組織感ってのは、例えばsubtechみたいなもんかな。

はてな
面白いもの見つけた。(via ku's twitter post)
Tumblr, RMagick and a Photo Frame! - igvita.com

Over the course of the past year or so, I got myself into a habit of using Tumblr for storing insightful snippets and quotes from my daily endeavours on the internet. Usually, this entails saving a paragraph (too long for tweet, and not enough for del.icio.us) so I can revisit it later.

However, having Tumblr to save the quotes is nice, but I rarely (if ever) went back to read them. Pondering this dilemma, I spotted my Phillips digital photo frame, and a quick weekend project was born: Tumblr API, RMagick to render the images, and an SD card full of wisdom and quotes for easy consumption!

どっちかって言うと、書いてる理由が面白い。要は「Tumblrの引用は面白いけど一々見に行くのめんどいよね!ならって事でデジタルフォトスタンドを使っちゃおうと思った」て感じかな。

動かすにはrubyのImageMagick拡張rmagickが必要。
私はPhillips digital photo frameは持ってないけど、chumbyとか使うと良く似た事出来るのかな?
ソースはそのまま使えました。日本語はImageMagickがghostscriptを使ってるのでTrueTypeフォント直接指定すれば動きます。
--- render-tumblr.rb.orig   Sat Jun 07 19:32:46 2008
+++ render-tumblr.rb    Thu Jun 19 12:02:57 2008
@@ -62,7 +62,7 @@
        img.background_color = "transparent"
        img.pointsize = 23
        img.antialias = true
-       img.font = "Helvetica"
+       img.font = "c:\\windows\\fonts\\meiryo.ttc"
    end
    quote.write "text.png"
    
@@ -72,12 +72,12 @@
        img.background_color = "transparent"
        img.pointsize = 18
        img.antialias = true
-       img.font = "Helvetica"
+       img.font = "c:\\windows\\fonts\\meiryo.ttc"
    end
    source.write "source.png"  
 end
 
-doc = Hpricot.XML(open("http://igrigorik.tumblr.com/api/read?type=quote&num=5"))
+doc = Hpricot.XML(open("http://mattn.tumblr.com/api/read?type=quote&num=5"))
 (doc/'post').each do |post|
    text = CGI::unescapeHTML((post/'quote-text').inner_html).gsub(/&[^;]*;?/,'')
    source = CGI::unescapeHTML((post/'quote-source').inner_html).gsub(/\<.*?\>/, '').gsub(/&[^;]*;?/,'').strip

実行するとquotesディレクトリに以下の様なファイルが出来上がりました。
render-tumblr-34978042

render-tumblr-36274314

render-tumblr-37077963

render-tumblr-37111519

render-tumblr-38695135

面白いですね。あとは何とかしてこれをchumbyとかで動かせればいいのですが、いかんせんchumby持ってない!chumbyでrubyが動くかどうかも知らない。
って事で誰か後はよろしく。

2008/06/18

はてな
blog chart.jp

「ブログチャート」なら、今注目のブログのヒットチャートや木になるブログの影響力レベルがすぐに分かります。

もちろんあなたのブログも登録可能。自分のブログの特徴を他のブログと比較してみて下さい。

http://blogchart.jp/
404 Blog Not Found:"ブログ"とは"\xa5\xd6\xa5\xed\xa5\xb0"ですかとblogchart.jp

文字文字化け化けなmailが来たので調べてみたら...

  • Content-Type:ヘッダーもMime-Version:ヘッダーも不在
  • Subject:ヘッダーもMIME header encodingされていない
  • 全部EUC-JPのまま

もうしわけないけど、最近のSPAMだってこのあたりはきちんとしてるよ!

http://blog.livedoor.jp/dankogai/archives/51067631.html
メールの文字化けもなんだけど、届いたブログチャート貼り付け用スクリプトが
<script type="text/javascript" src="http://blogchart.jp/js/blogparts.js"></script>
<script type="text/javascript"><!--
id="1784";blogurl="http://mattn.kaoriya.net";partstype="b";viewBlogparts();
// --></script>
思いっきりグローバル汚染。...orz

2008/06/17

はてな
試してみた
memcpy 最適化 - id:kazuhookuのメモ置き場

バイト単位でコピーするアホなコードの方が、勝手にベクトル化される分、gcc 内蔵のヤツより最大3倍高速なんだってwww

x64じゃないけど、最近のgccはどれくらい最適化が出来てるのかを見たかったので確認してみた。
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <time.h>
#include <sys/time.h>

void *(memcpy2)(void *__restrict__ b, const void *__restrict__ a, size_t n){
    char *s1 = b;
    const char *s2 = a;
    for(; 0<n; --n)*s1++ = *s2++;
    return b;
}

static double