Practice of Programming

プログラム とか Linuxとかの話題

spork で作ったスライドをPDFにする

YAPC::Asiaお疲れ様でした!
牧さん、櫛井さん、スピーカーの皆様、来場者の方々、ありがとうございました。


今回は、スタッフとしてRoom 1(中教室)にずっといましたが、仕事してたり、perldoc.jp がバグってるのを見つけたり(deltaが表示できてなかった orz)で、実はちゃんと聞けてなかったりします。ボランティアの仕事もあんまりできてなかったかも。すみません!
気になるトークはまた動画で見ようと思います。


で、1日目のLT、perldoc.jp の10周年のお話を2分でやらせて頂きましたが、2012年というのにspork使ってます。sporkはオワコンという話を聞きましたが(kwiki.org落ちてるし)、kwiki記法は楽なので。


ただ、HTMLだ公開するのが面倒だなぁということで、PhantomJS で HTML のスライドを PDF にし SlideShare にあげる方法を参考に、scriptを作りました。
https://github.com/ktat/tools/blob/master/mkslide


使い方は、

% mkslide perldocjp

みたいな感じにすると、spork -make して、PhantomJS でpng画像にして、sam2p で PDFにして、pdftk で結合して、foxitreader で開く。
という感じで、完全自分用でしかないし、てきとーに作りました。phantomjsに渡す js も、メンテがめんどくさいから、コマンド内に書いちゃって、毎度書き出してるって言う...。S5 plugin を使っているのも前提だし、ディレクトリも固定で、以下のようになります。

~/docs/slides/perldocjp/slides/start.html -> ~/docs/slides/perldocjp/perldocjp.slide.pdf

てわけで、誰も使わないと思いますが、このscriptとは関係なく、PhantomJS は便利そうだなーと思った。

ループ回数が多いときにDateTime使うのはやめよう

ボトルネックを探していたら、5000回くらいのループでDateTimeを使っている場面だったという話。
簡単な例として、1分追加する処理でベンチマークとってみた。

Benchmark: running datetime, timepiece for at least 3 CPU seconds...
  datetime:  3 wallclock secs ( 3.14 usr +  0.00 sys =  3.14 CPU) @ 2720.70/s (n=8543)
 timepiece:  4 wallclock secs ( 2.70 usr +  0.55 sys =  3.25 CPU) @ 60119.38/s (n=195388)

5000回のループだったら、DateTimeが1.8秒かかるのに対して、Time::Pieceなら、0.01秒弱。
ベンチマークのコードは下記。

#!/usr/bin/perl

use strict;
use warnings;
use DateTime;
use Time::Piece ();

use Benchmark qw/cmpthese timethese/;
my $time = time;

my $dt = DateTime->now(epoch => $time);
my $tp = Time::Piece::localtime($time);

timethese(0,
          {datetime  => sub {
              $dt->add(minutes => 1);
          },
          timepiece => sub {
              $tp += 60;
          }},
         );

実際のコードでは、ループが大きいのはなくせないんだけど、日付の演算を毎回使う必要はなかったので、使う数はだいぶ数は減ったんですけども。

そもそも、epoch time で記録すべきだったとか、今更感漂う今日この頃に orz

YAML::XS 0.35未満のメモリリーク

DBに大きめのYAMLが保存してあって、それを読み取る処理があったのですが、メモリがどんどん増えていくなーと思ったら、以下のものでした。
http://blogs.perl.org/users/brian_d_foy/2011/03/fixing-yamlxss-memory-leak.html

Changesでは、

    • -

version: 0.35
date: Mon Apr 4 00:33:09 CST 2011
changes:

  • Apply bdfoy patch from rt-46172
  • Update ppport.h to fix rt-64749 & rt-62054
  • Add ANDK's regexp.t patch from rt-62266
http://cpansearch.perl.org/src/INGY/YAML-LibYAML-0.38/Changes

"Apply bdfoy patch from rt-46172"がそれ。1年くらい前には直っている話でした。
というわけで、0.35未満の人は上げたほうが良いですよ。

AEとQudoを組み合わせる

別に書くほどのことは無いのですが。

QudoをAEとの組み合わせで使ったので、work メソッドの中身をAE::timer に渡すことにしました。

my $qudo = Qudo->new(...);
$w = AE::timer 0, $qudo->{work_delay}, sub {
    my $manager = $qudo->manager;
    unless ($manager->has_abilities) {
        Carp::croak 'manager dose not have abilities.';
    }
    $manager->work_once;
  }

これだけ。

AE::signal とかでも良いような気もする。

Text::Parts 0.13 リリース

Text::Parts 0.13

会社の隣の人に、write_filesが完全にバグってると指摘されたので、直しましたorz
テストでサイズだけチェックしてたんですが、まぁ、サイズ分書き出してるんだから、意味ないよね…
md5_hexでファイル内容をチェックするように変更しました。

後、typoがやたら目に付くので、ispellでチェックして直しました。たくさんあったorz

また、Windows環境でのテストがこけてたのを放置してましたが、修正しました。

Text::Parts 0.09 リリース

Text::Parts

2000くらいファイル分割しようと思ったら、"Too many open files"と言われてしまったので。
no_open オプションを使って、write_files を使うのであれば、特に問題は無かったかと思いますが、split メソッドを使って、自分で write_file を使うと、お亡くなりになってたみたいなので、その対応をしました。


no_open オプションを付けても、write_file や all の際には、勝手に open_and_seek /close するようにしました。

    use Text::Parts;
    
    my $splitter = Text::Parts->new(file => $file, no_open => 1);
    my (@parts) = $splitter->split(num => 2000);
    my $i;
    foreach my $part (@parts) {
       $part->write_file("file_name" . $i++);
    }

getline の場合は、open_and_seek と close を最初と最後に自分でよんで下さい。

    use Text::Parts;
    
    my $splitter = Text::Parts->new(file => $file, no_open => 1);
    my (@parts) = $splitter->split(num => 2000);
    foreach my $part (@parts) {
       $part->open_and_seek;
       while(my $l = $part->getline) {
          # ...
       }
       $part->close;
    }


ちなみに、Linuxであれば、1020を超えるような分割をする場合に、no_open オプションをつけてください。
ulimit -n 2000 のように開けるファイルディスクリプタの数を変更すれば、特に何もオプションつけなくてもOKですが。

Teng::Plusing::SearchBySQLAbstractMore 0.07リリース

Teng::Plusing::SearchBySQLAbstractMore

Teng内で用意されている_executeメソッドを使うようにしましたので、エラーメッセージが改善されています。
というか、普通のTengが出すエラーメッセージになりました。

# なんで、素のexecuteを使うようにしちゃってたのかが謎