35
Shibuya.pm Tech Talk #9 XS Nite はじめてのXS ハマりどころはココだ ひろせ まさあき id:hirose31

Shibuya.pm #9 My First XS

Embed Size (px)

DESCRIPTION

Shibuya Perl Mongers technical talk #9 a.k.a. XS Nite http://shibuya.pm.org/blosxom/techtalks/200806.html

Citation preview

Page 1: Shibuya.pm #9 My First XS

Shibuya.pm Tech Talk #9XS Nite

はじめてのXSハマりどころはココだ

ひろせ まさあき

id:hirose31

Page 2: Shibuya.pm #9 My First XS

1Shibuya.pm Tech Talk#9 - はじめてのXS

自己紹介

ひろせ まさあき

id:hirose31

KLab株式会社@六本木

座右の銘

NO CURRYNO LIFE

Page 3: Shibuya.pm #9 My First XS

2Shibuya.pm Tech Talk#9 - はじめてのXS

質 問

Page 4: Shibuya.pm #9 My First XS

3Shibuya.pm Tech Talk#9 - はじめてのXS

アジェンダ

XS概説

XSとは何か?

なぜXSを書くのか?

はじめてのXS ♥ 実体験レポート

XSを書くに至った経緯

書きはじめ

XS厨期

最初のリリース

その後のXSとわたし

Page 5: Shibuya.pm #9 My First XS

4Shibuya.pm Tech Talk#9 - はじめてのXS

XS 概 説

Page 6: Shibuya.pm #9 My First 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

Page 7: Shibuya.pm #9 My First XS

6Shibuya.pm Tech Talk#9 - はじめてのXS

なぜXSを書くのか?

Cのライブラリを使いたいため

Perlで実装しなおすのがめんどくさい、など

パフォーマンスアップのためCache::Memcached::Fast

Perlの内部をいじくりたおすため

autobox 例:10‐>to(1); # [10,9,...,1]

ヘンタイ上級者、魔法使い向け

Page 8: Shibuya.pm #9 My First XS

7Shibuya.pm Tech Talk#9 - はじめてのXS

なぜXSを書くのか?

Cのライブラリを使いたいため

Perlで実装しなおすのがめんどくさい、など

パフォーマンスアップのためCache::Memcached::Fast

Perlの内部をいじくりたおすため

autoboxヘンタイ上級者、魔法使い向け本日続いてのトークで!

キミも魔法使いに!!!本日続いてのトークで!

キミも魔法使いに!!!

Page 9: Shibuya.pm #9 My First XS

8Shibuya.pm Tech Talk#9 - はじめてのXS

なぜXSを書くのか?

Cのライブラリを使いたいため

Perlで実装しなおすのがめんどくさい、など

パフォーマンスアップのためCache::Memcached::Fast

Perlの内部をいじくりたおすため

autoboxヘンタイ上級者、魔法使い向け

このトークのテーマ

もうすこし詳しくこのトークのテーマ

もうすこし詳しく

本日続いてのトークで!

キミも魔法使いに!!!本日続いてのトークで!

キミも魔法使いに!!!

Page 10: Shibuya.pm #9 My First XS

9Shibuya.pm Tech Talk#9 - はじめてのXS

アジェンダ

XS概説

XSとは何か?

なぜXSを書くのか?

はじめてのXS ♥ 実体験レポート

XSを書くに至った経緯

書きはじめ

XS厨期

最初のリリース

その後のXSとわたし

Page 11: Shibuya.pm #9 My First XS

10Shibuya.pm Tech Talk#9 - はじめてのXS

はじめてのXS

Page 12: Shibuya.pm #9 My First XS

11Shibuya.pm Tech Talk#9 - はじめてのXS

XSを書くに至った動機

ganglia:サーバリソースのモニタリングツー

観測値を送る方法system(“gmetric”, “-n”, “cpu_system”,...)を観測値の種類の分だけ実行

fork(2)はコストが高い

Page 13: Shibuya.pm #9 My First XS

12Shibuya.pm Tech Talk#9 - はじめてのXS

XSを書くに至った動機

Page 14: Shibuya.pm #9 My First XS

13Shibuya.pm Tech Talk#9 - はじめてのXS

アジェンダ

XS概説

XSとは何か?

なぜXSを書くのか?

はじめてのXS ♥ 実体験レポート

XSを書くに至った経緯

書きはじめ

XS厨期

最初のリリース

その後のXSとわたし

Page 15: Shibuya.pm #9 My First XS

14Shibuya.pm Tech Talk#9 - はじめてのXS

XSのチュートリアルをざっと読んだ

perlxstutXSのチュートリアル

perlxsXSのリファレンスマニュアル

perlgutsPerlの内部構造についての解説

変数([SAH]V,[IUNP]V,)、関数コールなどなど

perlapiPerlのAPIリファレンス

関数、マクロ、フラグ、変数

Page 16: Shibuya.pm #9 My First XS

15Shibuya.pm Tech Talk#9 - はじめてのXS

はじめのいっぽ - XSのテンプレート生成

h2xs –A –n Mytest

module-starter––module=MyTest––class=Module::Starter::XSimple

Page 17: Shibuya.pm #9 My First XS

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();

書くのはここだけ

Page 18: Shibuya.pm #9 My First XS

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

Page 19: Shibuya.pm #9 My First XS

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

Page 20: Shibuya.pm #9 My First XS

19Shibuya.pm Tech Talk#9 - はじめてのXS

アジェンダ

XS概説

XSとは何か?

なぜXSを書くのか?

はじめてのXS ♥ 実体験レポート

XSを書くに至った経緯

書きはじめ

XS厨期

最初のリリース

その後のXSとわたし

Page 21: Shibuya.pm #9 My First XS

20Shibuya.pm Tech Talk#9 - はじめてのXS

そしてXS厨へ

APIを覚えはじめると、あれもこれもXSでやり

たくなるヨ!

例:XSのコードで...可変長の引数を得る

ハッシュからとあるキーにひも付く値を得る

Page 22: Shibuya.pm #9 My First 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

Page 23: Shibuya.pm #9 My First XS

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

Page 24: Shibuya.pm #9 My First 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なんて~

超ヨユーなんすよ~

Page 25: Shibuya.pm #9 My First XS

24Shibuya.pm Tech Talk#9 - はじめてのXS

Page 26: Shibuya.pm #9 My First 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 より

Page 27: Shibuya.pm #9 My First XS

26Shibuya.pm Tech Talk#9 - はじめてのXS

あれ...それ

おれのことじゃん><

Page 28: Shibuya.pm #9 My First 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

Page 29: Shibuya.pm #9 My First XS

28Shibuya.pm Tech Talk#9 - はじめてのXS

アジェンダ

XS概説

XSとは何か?

なぜXSを書くのか?

はじめてのXS ♥ 実体験レポート

XSを書くに至った経緯

書きはじめ

XS厨期

最初のリリース

その後のXSとわたし

Page 30: Shibuya.pm #9 My First 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)はする必要がないので字消しを入れました。

Page 31: Shibuya.pm #9 My First XS

30Shibuya.pm Tech Talk#9 - はじめてのXS

ノロマなやつを探せ! - プロファイリング

なんか遅いんでプロファイリングしたいけど、gprofじゃできないお

valgrind --tool=callgrind+ kcachegrindがいいぜ!

valgrind --tool=callgrind --dump-instr=yes --trace-jump=yes XXX.pl

Page 32: Shibuya.pm #9 My First XS

31Shibuya.pm Tech Talk#9 - はじめてのXS

ノロマなやつを探せ! - プロファイリング

Page 33: Shibuya.pm #9 My First 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()'

Page 34: Shibuya.pm #9 My First XS

33Shibuya.pm Tech Talk#9 - はじめてのXS

まとめ

XSって意外と簡単です

Cライブラリをコールするだけならとても簡単

Cのコードがある場合はさらに簡単

ただ、典型的な落とし穴があるのでそこは気をつけて

Perl内部の構造、処理に詳しくなる

Perlの気持ちがわかってくる

魔法使いへの入り口...

Page 35: Shibuya.pm #9 My First XS

34Shibuya.pm Tech Talk#9 - はじめてのXS

thx

ご清聴ありがとうございました