Shibuya.pm #9 My First XS
-
Upload
masaaki-hirose -
Category
Technology
-
view
2.917 -
download
2
description
Transcript of Shibuya.pm #9 My First XS
Shibuya.pm Tech Talk #9XS Nite
はじめてのXSハマりどころはココだ
ひろせ まさあき
id:hirose31
1Shibuya.pm Tech Talk#9 - はじめてのXS
自己紹介
ひろせ まさあき
id:hirose31
KLab株式会社@六本木
座右の銘
NO CURRYNO LIFE
2Shibuya.pm Tech Talk#9 - はじめてのXS
質 問
3Shibuya.pm Tech Talk#9 - はじめてのXS
アジェンダ
XS概説
XSとは何か?
なぜXSを書くのか?
はじめてのXS ♥ 実体験レポート
XSを書くに至った経緯
書きはじめ
XS厨期
最初のリリース
その後のXSとわたし
4Shibuya.pm Tech Talk#9 - はじめてのXS
XS 概 説
5Shibuya.pm Tech Talk#9 - はじめてのXS
XSとは何か?
PerlとCをつなぐための言語
インターフェース
XSソース(Foo.xs)
XSソース(Foo.xs)
xsubpp
Cソース(Foo.c)
Cソース(Foo.c)
Cコンパイラ
リンカ
共有ライブラリ(Foo.so)
共有ライブラリ(Foo.so)
XSLoaderDynaLoader
Perlモジュール(Foo.pm)
Perlモジュール(Foo.pm)
use Foo;
Perlスクリプト(bar.pl)
Perlスクリプト(bar.pl)
perl Makefile.PL&& make
&& make test
6Shibuya.pm Tech Talk#9 - はじめてのXS
なぜXSを書くのか?
Cのライブラリを使いたいため
Perlで実装しなおすのがめんどくさい、など
パフォーマンスアップのためCache::Memcached::Fast
Perlの内部をいじくりたおすため
autobox 例:10‐>to(1); # [10,9,...,1]
ヘンタイ上級者、魔法使い向け
7Shibuya.pm Tech Talk#9 - はじめてのXS
なぜXSを書くのか?
Cのライブラリを使いたいため
Perlで実装しなおすのがめんどくさい、など
パフォーマンスアップのためCache::Memcached::Fast
Perlの内部をいじくりたおすため
autoboxヘンタイ上級者、魔法使い向け本日続いてのトークで!
キミも魔法使いに!!!本日続いてのトークで!
キミも魔法使いに!!!
8Shibuya.pm Tech Talk#9 - はじめてのXS
なぜXSを書くのか?
Cのライブラリを使いたいため
Perlで実装しなおすのがめんどくさい、など
パフォーマンスアップのためCache::Memcached::Fast
Perlの内部をいじくりたおすため
autoboxヘンタイ上級者、魔法使い向け
このトークのテーマ
もうすこし詳しくこのトークのテーマ
もうすこし詳しく
本日続いてのトークで!
キミも魔法使いに!!!本日続いてのトークで!
キミも魔法使いに!!!
9Shibuya.pm Tech Talk#9 - はじめてのXS
アジェンダ
XS概説
XSとは何か?
なぜXSを書くのか?
はじめてのXS ♥ 実体験レポート
XSを書くに至った経緯
書きはじめ
XS厨期
最初のリリース
その後のXSとわたし
10Shibuya.pm Tech Talk#9 - はじめてのXS
はじめてのXS
11Shibuya.pm Tech Talk#9 - はじめてのXS
XSを書くに至った動機
ganglia:サーバリソースのモニタリングツー
ル
観測値を送る方法system(“gmetric”, “-n”, “cpu_system”,...)を観測値の種類の分だけ実行
fork(2)はコストが高い
12Shibuya.pm Tech Talk#9 - はじめてのXS
XSを書くに至った動機
13Shibuya.pm Tech Talk#9 - はじめてのXS
アジェンダ
XS概説
XSとは何か?
なぜXSを書くのか?
はじめてのXS ♥ 実体験レポート
XSを書くに至った経緯
書きはじめ
XS厨期
最初のリリース
その後のXSとわたし
14Shibuya.pm Tech Talk#9 - はじめてのXS
XSのチュートリアルをざっと読んだ
perlxstutXSのチュートリアル
perlxsXSのリファレンスマニュアル
perlgutsPerlの内部構造についての解説
変数([SAH]V,[IUNP]V,)、関数コールなどなど
perlapiPerlのAPIリファレンス
関数、マクロ、フラグ、変数
15Shibuya.pm Tech Talk#9 - はじめてのXS
はじめのいっぽ - XSのテンプレート生成
h2xs –A –n Mytest
module-starter––module=MyTest––class=Module::Starter::XSimple
16Shibuya.pm Tech Talk#9 - はじめてのXS
XSで“Hello, World”を書いてみた
#include "EXTERN.h"#include "perl.h"#include "XSUB.h"
#include "ppport.h"
MODULE = SayHello PACKAGE = SayHello
voidsay_hello_xs()
CODE:say_hello();
#include "EXTERN.h"#include "perl.h"#include "XSUB.h"
#include "ppport.h"
MODULE = SayHello PACKAGE = SayHello
voidsay_hello_xs()
CODE:say_hello();
書くのはここだけ
17Shibuya.pm Tech Talk#9 - はじめてのXS
XSで“Hello, World”を書いてみた
#include "EXTERN.h"#include "perl.h"#include "XSUB.h"
#include "ppport.h"
MODULE = SayHello PACKAGE = SayHello
voidsay_hello_xs()
CODE:say_hello();
#include "EXTERN.h"#include "perl.h"#include "XSUB.h"
#include "ppport.h"
MODULE = SayHello PACKAGE = SayHello
voidsay_hello_xs()
CODE:say_hello();
書くのはここだけ
libhello.so:LIBS => ['-L/path/to/libdir -lhello']
libhello.a:MYEXTLIB => 'libhello/libhello.a',
libhello.so:LIBS => ['-L/path/to/libdir -lhello']
libhello.a:MYEXTLIB => 'libhello/libhello.a',
Makefile.PL
18Shibuya.pm Tech Talk#9 - はじめてのXS
APIがわからない。。。
CPANにあるXSモジュールを参考にした
JSON::XS, YAML::XSMemcached::libmemcachedCache::Memcached::Fast
API名がわかるが使い方がわからんとき
Google Code Searchで『API名 file:¥.xs』http://www.google.com/codesearch?q=hv_fetch_ent+file:¥.xs
19Shibuya.pm Tech Talk#9 - はじめてのXS
アジェンダ
XS概説
XSとは何か?
なぜXSを書くのか?
はじめてのXS ♥ 実体験レポート
XSを書くに至った経緯
書きはじめ
XS厨期
最初のリリース
その後のXSとわたし
20Shibuya.pm Tech Talk#9 - はじめてのXS
そしてXS厨へ
APIを覚えはじめると、あれもこれもXSでやり
たくなるヨ!
例:XSのコードで...可変長の引数を得る
ハッシュからとあるキーにひも付く値を得る
21Shibuya.pm Tech Talk#9 - はじめてのXS
そしてXS厨へ – 引数のハッシュからとある値を返す
sub getval_pp {my($h) = @_;my $k = “drink”;return exists $h‐>{$k}? $h‐>{$k} : ();
}
sub getval_pp {my($h) = @_;my $k = “drink”;return exists $h‐>{$k}? $h‐>{$k} : ();
}
Perl
22Shibuya.pm Tech Talk#9 - はじめてのXS
そしてXS厨へ – 引数のハッシュからとある値を返す
sub getval_pp {my($h) = @_;my $k = “drink”;return exists $h‐>{$k}? $h‐>{$k} : ();
}
sub getval_pp {my($h) = @_;my $k = “drink”;return exists $h‐>{$k}? $h‐>{$k} : ();
}
PerlSV *getval_xs(SV *args)CODE:HV *hv;HE *he;SV *key;
hv = (HV*)SvRV(args);key = newSVpv("drink",0);
if (he = hv_fetch_ent(hv, key, 0,0)) {
RETVAL = newSVsv(HeVAL(he));} else {RETVAL = &PL_sv_no;
}OUTPUT:RETVAL
SV *getval_xs(SV *args)CODE:HV *hv;HE *he;SV *key;
hv = (HV*)SvRV(args);key = newSVpv("drink",0);
if (he = hv_fetch_ent(hv, key, 0,0)) {
RETVAL = newSVsv(HeVAL(he));} else {RETVAL = &PL_sv_no;
}OUTPUT:RETVAL
XS
23Shibuya.pm Tech Talk#9 - はじめてのXS
そしてXS厨へ – 引数のハッシュからとある値を返す
sub getval_pp {my($h) = @_;my $k = “drink”;return exists $h‐>{$k}? $h‐>{$k} : ();
}
sub getval_pp {my($h) = @_;my $k = “drink”;return exists $h‐>{$k}? $h‐>{$k} : ();
}
PerlSV *getval_xs(SV *args)CODE:HV *hv;HE *he;SV *key;
hv = (HV*)SvRV(args);key = newSVpv("drink",0);
if (he = hv_fetch_ent(hv, key, 0,0)) {
RETVAL = newSVsv(HeVAL(he));} else {RETVAL = &PL_sv_no;
}OUTPUT:RETVAL
SV *getval_xs(SV *args)CODE:HV *hv;HE *he;SV *key;
hv = (HV*)SvRV(args);key = newSVpv("drink",0);
if (he = hv_fetch_ent(hv, key, 0,0)) {
RETVAL = newSVsv(HeVAL(he));} else {RETVAL = &PL_sv_no;
}OUTPUT:RETVAL
XS
ぶっちゃけ~XSなんて~
超ヨユーなんすよ~
ぶっちゃけ~XSなんて~
超ヨユーなんすよ~
24Shibuya.pm Tech Talk#9 - はじめてのXS
25Shibuya.pm Tech Talk#9 - はじめてのXS
『汝、Perlの「代わりに」XSを書くなかれ』
DO NOT WRITE XS INSTEAD OF PERLPerlの「代わりに」XSを書くなかれ
SV操作ばかりが必要な事をCでやらないPerlでやってることをCで書き直した
ところで全く効率に影響はない
『Getting Your Feet Even Wetter With XS』, 牧 大輔YAPC::Asia 2008 より
26Shibuya.pm Tech Talk#9 - はじめてのXS
あれ...それ
おれのことじゃん><
27Shibuya.pm Tech Talk#9 - はじめてのXS
悔い改める。。。
intsend(self, SV *args)
SV *self;PREINIT:ganglia *gang;char *name = "";char *value = "";char *type = "";char *units = "";
CODE:HV *hv;HE *he;SV *tmp;char *key;I32 keylen = 0;int r;gang = XS_STATE(ganglia *, self);gang‐>gmetric = Ganglia_gmetric_create(gang‐>context);
if (!SvROK(args))croak("ref(hashref) expected");
hv = (HV*)SvRV(args);if (SvTYPE(hv) != SVt_PVHV)croak("hashref expected");
hv_iterinit(hv);while ( (tmp = hv_iternextsv(hv, &key, &keylen)) != NULL ) {if (strEQ(key, "name")) {name = SvPV_nolen(tmp);
} else if (strEQ(key, "value")) {value = SvPV_nolen(tmp);
} else if (strEQ(key, "type")) {type = SvPV_nolen(tmp);
} else if (strEQ(key, "units")) {units = SvPV_nolen(tmp);
}}
r = Ganglia_gmetric_set(gang‐>gmetric, name, value, type, units, 3, 60,0);
RETVAL = ! Ganglia_gmetric_send(gang‐>gmetric, gang‐>channel);Ganglia_gmetric_destroy(gang‐>gmetric);
intsend(self, SV *args)
SV *self;PREINIT:ganglia *gang;char *name = "";char *value = "";char *type = "";char *units = "";
CODE:HV *hv;HE *he;SV *tmp;char *key;I32 keylen = 0;int r;gang = XS_STATE(ganglia *, self);gang‐>gmetric = Ganglia_gmetric_create(gang‐>context);
if (!SvROK(args))croak("ref(hashref) expected");
hv = (HV*)SvRV(args);if (SvTYPE(hv) != SVt_PVHV)croak("hashref expected");
hv_iterinit(hv);while ( (tmp = hv_iternextsv(hv, &key, &keylen)) != NULL ) {if (strEQ(key, "name")) {name = SvPV_nolen(tmp);
} else if (strEQ(key, "value")) {value = SvPV_nolen(tmp);
} else if (strEQ(key, "type")) {type = SvPV_nolen(tmp);
} else if (strEQ(key, "units")) {units = SvPV_nolen(tmp);
}}
r = Ganglia_gmetric_set(gang‐>gmetric, name, value, type, units, 3, 60,0);
RETVAL = ! Ganglia_gmetric_send(gang‐>gmetric, gang‐>channel);Ganglia_gmetric_destroy(gang‐>gmetric);
beforeint_ganglia_send(self, name, value, type, units, slope, tmax, dmax)
SV *self;char *name, *value, *type, *units;unsigned int slope, tmax, dmax;
PREINIT:ganglia *gang;
CODE:int r;
gang = XS_STATE(ganglia *, self);gang‐>gmetric = Ganglia_gmetric_create(gang‐>context);
r = Ganglia_gmetric_set(gang‐>gmetric, name, value, type, units, slope,tmax, dmax);
RETVAL = ! Ganglia_gmetric_send(gang‐>gmetric, gang‐>channel);Ganglia_gmetric_destroy(gang‐>gmetric);
int_ganglia_send(self, name, value, type, units, slope, tmax, dmax)
SV *self;char *name, *value, *type, *units;unsigned int slope, tmax, dmax;
PREINIT:ganglia *gang;
CODE:int r;
gang = XS_STATE(ganglia *, self);gang‐>gmetric = Ganglia_gmetric_create(gang‐>context);
r = Ganglia_gmetric_set(gang‐>gmetric, name, value, type, units, slope,tmax, dmax);
RETVAL = ! Ganglia_gmetric_send(gang‐>gmetric, gang‐>channel);Ganglia_gmetric_destroy(gang‐>gmetric);
after
28Shibuya.pm Tech Talk#9 - はじめてのXS
アジェンダ
XS概説
XSとは何か?
なぜXSを書くのか?
はじめてのXS ♥ 実体験レポート
XSを書くに至った経緯
書きはじめ
XS厨期
最初のリリース
その後のXSとわたし
29Shibuya.pm Tech Talk#9 - はじめてのXS
メモリリークとの戦い
インスタンス作るとスコープ外れても使用メモリが減らないお
もりもりnewするともりもり増えるお
New* したのはSafefree()すべし、newSV* したのはsv_freeすべし。
デストラクタDESTROY()とかでやると
いいぜ!
New* = Newx,Newxc,NewxznewSV* = newSV,newSViv,newSVpv,...
【事後補足】
基本的にはsv_free(=SvREFCNT_dec)はする必要がないので字消しを入れました。
30Shibuya.pm Tech Talk#9 - はじめてのXS
ノロマなやつを探せ! - プロファイリング
なんか遅いんでプロファイリングしたいけど、gprofじゃできないお
valgrind --tool=callgrind+ kcachegrindがいいぜ!
valgrind --tool=callgrind --dump-instr=yes --trace-jump=yes XXX.pl
31Shibuya.pm Tech Talk#9 - はじめてのXS
ノロマなやつを探せ! - プロファイリング
32Shibuya.pm Tech Talk#9 - はじめてのXS
あっちのPerlで動かない – 互換性
NewxzってのがPerl 5.8.8の環境では使えるけど、5.8.4ではつかえ
ないお
ppport.hで吸収できるぜ!Devel::PPPortを最新版にして、
perl -MDevel::PPPort -e 'Devel::PPPort::WriteFile()'
33Shibuya.pm Tech Talk#9 - はじめてのXS
まとめ
XSって意外と簡単です
Cライブラリをコールするだけならとても簡単
Cのコードがある場合はさらに簡単
ただ、典型的な落とし穴があるのでそこは気をつけて
Perl内部の構造、処理に詳しくなる
Perlの気持ちがわかってくる
魔法使いへの入り口...
34Shibuya.pm Tech Talk#9 - はじめてのXS
thx
ご清聴ありがとうございました