ペパボでは技術スタッフ正社員を募集しています

Posted by Gosuke Miyashita Fri, 25 May 2007 11:51:00 GMT

プログラマサーバーエンジニア の枠で正社員募集中です。

プログラマは、現在僕が出張で来ている福岡で、サーバエンジニアは東京での募集です。

社長から「頭がおかしい」と言われるような こんな僕が技術のトップなんぞやってる会社ですが、ドクターペッパーが好きなサーバエンジニアの方、ぜひ僕と一緒にリフレッシュエリアでドクターペッパー飲み飲み、社長の生態を観察しましょう。(リフレッシュエリアのソファに座ると、真正面にガラス越しの社長が観察できます。動物園気分が味わえますよ。)またはカレー(ハヤシ含む)を飲みながらでも OK です。

プログラマは福岡での募集ですが、たびたび出張で来ますので、ぜひ福岡オフィスの自販機にドクターペッパーを入れるよう、署名運動とかしてもらいたいと思います。そしてドクターペッパー飲みつつ、焼きカレーを食べましょう。

write はユーザプロセスを待たせない?の答え 2

Posted by Gosuke Miyashita Fri, 25 May 2007 11:03:00 GMT

前回のエントリ について、naoya さんから僕の期待以上の素晴らしい回答を頂きました。感謝感謝です。

詳細は上記エントリをじっくり読んで頂きたいのですが、僕の疑問への直接の答えとなるのが、まとめにある

  • write はプロセスを待たせない
  • ただし明示的に sync する場合は待たせる

ですね。「write はプロセスを待たせない」が正しい、というのは naoya さんの解説を読んで納得しました。プロセスが write するということと、それが実際にディスクに書き出されることを、区別しないで考えていたのが僕の敗因ですね。

また、こちらの環境で kjournald や qmail-queue プロセスが待たされていたのは、sync してるから、ということでした。kjournald は確かめていないのですが、qmail-queue のソースの中では確かに fsync() が実行されていました。考えてみれば当然ですよね。ジャーナルのメタデータやメールキューなど、大事なデータを write して sync しないなんてことはあり得ないでしょうし。

なので、id:hirose31さんからのコメント「fsync(2)のせい?」がずばり回答になっていました。ありがとうございます。今度カレーおごらせてください。

というわけで、「write はユーザプロセスを待たせない?」は「待たせない」が答え、ということで完結です。

あと、

ということですが free の結果では、プロセスに割り当てるためのメモリが足りてるかどうかはわかりますが、ページキャッシュ用にメモリが足りてるかどうかはわかりません。

実際そのサーバーが主な仕事で使っているデータは、合計でどのぐらいのサイズでしょう。おそらく、キューに溜まったメールその他 OS 上で必要なデータのサイズをあわせると 800MB を超えるんではないかなあと思います。外してたらごめん。

もおっしゃるとおりですね。プロセスに必要なメモリ容量と、キャッシュに必要なメモリ容量をちゃんと区別していませんでした。

となると、メモリを増やせば書き込み性能が向上する可能性があるのでは、と思ったのですが、今回のケースではおそらく向上することはなさそうです。というのも、iostat の値を見てると、avgqu-sz が 1 日平均でおよそ 5、短時間で見ると 10 とか 20 あるいはそれ以上ということがざらにあります。avgqu-sz はキューに入っていて待ちとなっている I/O リクエストの数なので、常に処理待ちとなっている I/O リクエストが存在する、ということなります。なので、ページキャッシュの容量の問題ではなく、ディスクの性能がボトルネックになっている、と言えそうです。(これも自分の勘違いなら恥ずかしいなー…メモリを簡単に増やせるなら、試してみたいんですけどね。)

naoya さん、詳細な解説ありがとうございました。大変勉強になりました。僕のために時間を割いて長文エントリ書いてくれた、と思うとちょっと萌えました。(べっ、別にあんたのために…、とか言われそうですが。)

write はユーザプロセスを待たせない? 6

Posted by Gosuke Miyashita Tue, 22 May 2007 15:24:00 GMT

naoyaグループ - naoyaの日記 - I/O, iowait にちょっと反応してみます。

write はページに dirty フラグを立てるだけなので決してユーザープロセスを待たせない

って、本当にそうなんでしょうか?(否定しているわけではなく、純粋な疑問です。)

最近、書き込みの多いメールサーバのディスク I/O 周りを調査していて、実際にどのプロセスの書き込みが多いのかを調べる方法がわからなかったため、I/O 待ちになっているプロセスをカウントして、そこから類推してみようと、まずは

while [ 1 ]
  do
    ps -eo comm,state|grep D|grep -v COMMAND >> ps.txt
    sleep 1
  done

な感じで STAT が D のプロセスを記録するスクリプトをしばらく走らせておいて、

sort ps.txt | uniq -c | sort -gr| more

でカウントしてみると、

9129 kjournald       D
6576 qmail-queue     D
2017 multilog        D
1897 pdflush         D
1373 qmail-send      D
1094 procmail        D
1032 syslogd         D

な感じで、kjournald と qmail-queue が圧倒的に多い。これってどっちも書き込みがメインの仕事のはず。

man ps で見ても、

D    Uninterruptible sleep (usually IO)

なので、書き込みでプロセスが待たされてるのだと思うのですが、何か間違ってますでしょうか?

ちなみに、書き込みが多いというのはどれぐらいかというと、iostat での r/s と w/s の比率が 1:7 ぐらいです。

また、free の結果はこんな感じなので、メモリに余裕はあるみたいです。

# free
             total       used       free     shared    buffers     cached
Mem:       2043756    2011160      32596          0     351016     847776
-/+ buffers/cache:     812368    1231388
Swap:      1052248

ここ数日 I/O まわりを追いかけていたので、naoya さんのエントリはタイムリーでとてもためになります。ついでに色々教えてもらおうという甘い考えで、疑問に感じたことを書いてみました。

追記

もしかして「write はユーザプロセスを待たせない」というのは、非同期 I/O の話?であれば納得はいく。

FizzBuzz アセンブラ版 for x86/Linux

Posted by Gosuke Miyashita Sun, 13 May 2007 12:01:00 GMT

竹迫さんYappo さん に触発されて、FizzBuzz アセンブラ版 for x86/Linux をつくってみた。

20年ほど前に Z80 でアセンブラをちょっとかじった程度の知識しかないので、ベストには程遠いコードだと思います。だれかもっといいコードを教えてください。

最初竹迫さんのコードと同じように書けるかな、と思ったのですが、Windows とちがって、画面に表示するだけで EAX, EBX, ECX, EDX レジスタ使うので、竹迫さんのように BX レジスタを見張り役に、CX レジスタをカウンタに、ってことができませんでした。

また、とりあえず書いただけで疲れたので、コードゴルフにチャレンジする気力はありません。

global  _start

_start:
        mov     si, 0

mawasu: 
        call    space
        inc     si
        mov     ax, si

        mov     di, 3
        xor     edx, edx
        div     di
        cmp     dx, 0
        je      pfizz

        mov     ax, si
        mov     di, 5
        xor     edx, edx
        div     di
        cmp     dx, 0
        je      pbuzz

        call    num
        cmp     si, 100
        jb      mawasu

pfizz:
        call    fizz

        mov     ax, si
        mov     di, 5
        xor     edx, edx
        div     di
        cmp     dx, 0
        je      pbuzz

        jmp     mawasu

pbuzz:
        call    buzz
        jmp     mawasu

num:
        mov     ax, si

        mov     di, 100
        cmp     ax, di
        jnge    num2

        jmp     end

num2:
        mov     di, 10
        cmp     ax, di
        jnge    num3

        xor     edx, edx
        div     di
        add     ax, 48
        call    print

num3:   
        mov     ax, si
        mov     di, 10
        xor     edx, edx
        div     di
        mov     al, dl
        add     al, 48
        call    print
        ret

fizz:
        mov     al, 0x46
        call    print
        mov     al, 0x69
        call    print
        mov     al, 0x7a
        call    print
        call    print
        ret

buzz:
        mov     al, 0x42
        call    print
        mov     al, 0x75
        call    print
        mov     al, 0x7a
        call    print
        call    print
        ret

space:
        mov     al, 0x20
        call    print
        ret

print:
        push    eax
        mov     eax, 4
        mov     ebx, 1
        mov     ecx, esp
        mov     edx, 1
        int     0x80
        pop     eax
        ret

end:    
        mov     al, 0x0a
        call    print

        mov     al, 1
        mov     bl, 0
        int     0x80

nasm を使ってこんな感じで動かすことができます。

$ nasm -f elf fizzbuzz.asm
$ ld -s -o fizzbuzz fizzbuzz.o
$ ./fizzbuzz

fizzbuzz.asm

書いていてアセンブラの TMTOWTDI っぷりは Perl の比じゃないと思った。

Re: DBICとDBIx::Class::Schema::Loader 僕のいろいろな勘違い 2

Posted by Gosuke Miyashita Sun, 06 May 2007 10:11:00 GMT

ブログが続かないわけ | DBICとDBIx::Class::Schema::Loader 僕のいろいろな勘違い にて、

とはいえ、僕の稼働中のアプリはすでに手動型のSchema で動いている。スキーマを作り直したら、リレーションの設定を全てしなおさなければならないので、それは現実的じゃない。inflate, deflate の指定は、やっぱりすべてのSchema にかかなきゃだめそうだ。

とあったので、これに関して少し楽ができる方法をコメントしようと思ったけれど、コメント欄ではうまく伝えられる自信がないので、こちらで書いてみることにしました。

load_components で 読み込む方法

DBIx::Class::Schema::Loader ではなく DBIx::Class::Schema を継承したスキーマの場合には、各スキーマファイルに以下の様に書いてあげれば OK です。(既にご存知かもしれませんが。)

package My::Schema::Table;

__PACKAGE__->load_components(
  "InflateColumn::DateTime",
  "PK::Auto",
  "Core",
);

すべてのスキーマファイルに書かなきゃいけないことには変わりありませんが、各カラムに inflate/deflate を設定するよりははるかに楽だと思います。

make_schema_at を使う方法

make_schema_at でスキーマファイルを生成しているのであれば、こんな感じでリレーションだけ定義した ./tmp/lib/My/Schema/Table.pm をまず用意します。

package My::Schema::Table;

__PACKAGE__->belongs_to(
    realation => 'My::Schema::OtherTable
    { 'foreign.id' => 'self.other_table_id' },
);

1;

でもって、こんなスクリプトを実行します。

#!/usr/bin/perl

use strict;
use warnings;

use lib qw( ./tmp/lib );
use Carp;
use DBIx::Class::Schema::Loader qw( make_schema_at dump_to_dir:lib dump_overwrite );

make_schema_at(
    'My::Schema::Table',
    {
        components     => [qw/ ResultSetManager UTF8Columns InflateColumn::DateTime /],
        dump_overwrite => 1,
    },
    ['dbi:mysql:dbname' ,'user', 'password'],
);

そうすると、lib/My/Schema/Table.pm に以下の内容を吐き出してくれます。

package My::Schema::Table;

# Created by DBIx::Class::Schema::Loader v0.03009 @ 2007-04-26 18:21:23

use strict;
use warnings;

use base 'DBIx::Class';

__PACKAGE__->load_components(
  "ResultSetManager",
  "UTF8Columns",
  "InflateColumn::DateTime",
  "PK::Auto",
  "Core",
);
__PACKAGE__->table("table");
__PACKAGE__->add_columns(
  "id",
  { data_type => "INT", default_value => undef, is_nullable => 0, size => 11 },
  "other_table_id",
  { data_type => "INT", default_value => 0, is_nullable => 0, size => 11 },
  "date",
  { data_type => "DATE", default_value => undef, is_nullable => 1, size => 10 },

__PACKAGE__->set_primary_key("id");
# These lines loaded from user-supplied external file:
package My::Schema::Table;

__PACKAGE__->belongs_to(
    employees => 'My::Schema::Table',
    { 'foreign.id' => 'self.other_table_id' },
);

1;
# End of lines loaded from user-supplied external file

この方法を使うと、スキーマを作り直しても、リレーションの再設定をしなくて済みます。

手動でやるのが楽なのか、上の方法のいずれかを使うのが楽なのかは、状況にもよると思いますが、こんな方法もありますよ、ということで、ご参考になれば幸いです。

blosxom から typo へ

Posted by Gosuke Miyashita Sat, 05 May 2007 21:10:00 GMT

色々あって、typo へ移行してみた。

SVN::TracWiki #2

Posted by Gosuke Miyashita Mon, 30 Apr 2007 15:30:12 GMT

SVN::TracWiki (svn repos) をアップデート。以下の機能を実現するパッチを、Assurer の開発にも参加してくれている franck が送ってくれました。

  • Plugin::Extract::Pod で Perl プログラムのコミット時に、pod を自動で抽出して Wiki にアップ。
  • xmlrpc プラグインがなくても Wiki ポストができる。

Trac はソースコード自体の検索ができないので、当然 pod の内容も検索することができないのですが、このプラグインにより、pod の検索ができるようになります。

また、検索だけではなく、こんな感じ で pod を Trac の Wiki フォーマットに変換してキレイに表示してくれます。

試しに手元にあった XML::Atom をつっこんでみると、こんな感じ になります。

あと、File::Extract 内部で利用している File::MMagic::XS が謎の Segmentation Fault で落ちるので、File::MMagic を使うように強引に書き換えたり。

SVN::TracWiki #1

Posted by Gosuke Miyashita Sun, 22 Apr 2007 06:07:01 GMT

SVN::TracWiki (svn repos) について、ブクマコメントで miyagawa さんから「File::Extract?」というアドバイス?を頂きましたので、テキスト抽出部分を File::Extract ベースに書き換えてみました。

おかげでプラグインまわりの処理が少しすっきりした上に、File::Extract で対応しているファイルフォーマットであれば、SVN::TracWiki 用のプラグインを書かなくてもテキスト抽出ができるようになりました。(Excel で試しましたが、ばっちり動作しました。)

SVN::TracWiki #0

Posted by Gosuke Miyashita Sat, 21 Apr 2007 19:55:57 GMT

SVN::TracWiki というツールをつくってみました。svn repos はこちら

何をするものかというと、Subversion の post-commit スクリプトとして動作して、コミットされたファイルからテキストを抽出、そのファイルの実体へのリンクを付加して、Trac の Wiki へ自動ポストするというもの。

具体的な例としては、PowerPoint ファイルをコミットしたら、そのファイルからテキストのみを抽出して Wiki へ自動ポスト。こんな感じで

これで何がうれしいかというと、Subversion で管理している PowerPoint ファイルを、Trac 上で検索ができるようになります。こんな感じですね。元ファイルへのリンクもあるので、検索して元ファイルを開いて読む、ってことが簡単にできます。

例によって YAMLで設定 and プラガブル。ファイルからテキストを抽出する部分がプラグインになっていて、簡単に拡張できるようにしています。

現在は PowerPoint 用フィルタプラグインしかないのですが、以下の様なコードになっていて、フィルタ対象ファイルの MIME タイプを register() で指定、テキスト抽出ルーチンを filter() に記述、という感じで書きます。

package SVN::TracWiki::Plugin::Filter::PowerPoint;

use strict;
use warnings;
use base qw( SVN::TracWiki::Plugin::Filter );
use Encode;

sub register {
    my $self = shift;
    $self->register_mime_types( qw! application/vnd.ms-powerpoint !);
}

sub filter {
    my ( $self, $file ) = @_;
    my $html = `/usr/local/bin/ppthtml $file`;
    my $text = $self->strip_html($html);

    $text = Encode::decode('utf8', $text);
    $text = Encode::encode('utf8', $text);

    return $text;
}

1;

とりあえず動くようになっただけで、いけてない部分盛りだくさんですが、こんなのつくってみました、ってことで。

html-tt-mode を sgml-mode のマイナーモードで動くようにしてみた

Posted by Gosuke Miyashita Mon, 09 Apr 2007 08:36:45 GMT

Clouder::Blogger: html-tt - emacsのTemplate Toolkit用のmode を html-helper-mode ではなく、sgml-mode のマイナーモードで動くようにしたパッチ。(置換しただけ。)

別に sgml-mode に思い入れはなく、Meadow でデフォルトで動いてるからそのまま使ってるだけなので、html-helper-mode にしてもいいんだけど、どうも Meadow でうまく色づけされないので、その原因追求するよりも、sgml-mode で動くようにした方がはやかったので。

本当はどっちでも動くようにするのがいいんだろうけど、それはまた今度。

=== html-tt.el
==================================================================
--- html-tt.el	(revision 193)
+++ html-tt.el	(local)
@@ -66,7 +66,7 @@
 ;; Code:
 
 (provide 'html-tt)
-(require 'html-helper-mode)
+(require 'sgml-mode)
 (require 'tempo)
 (require 'font-lock)
 
@@ -217,38 +217,38 @@
 (defun html-tt-load-hook ()
   (interactive)
   ;; define key bind
-  ;(define-key html-helper-mode-map "\C-cs"
+  ;(define-key sgml-mode-map "\C-cs"
   ;  'html-tt-insert-sequence)
-  (define-key html-helper-mode-map "\C-cs"
+  (define-key sgml-mode-map "\C-cs"
     'tempo-template-html-tt-insert-sequence)
-  (define-key html-helper-mode-map "\C-cd"
+  (define-key sgml-mode-map "\C-cd"
     'html-tt-insert-directive)
-  (define-key html-helper-mode-map "\C-cn"
+  (define-key sgml-mode-map "\C-cn"
     'tempo-template-html-tt-insert-directive)
-  (define-key html-helper-mode-map "\C-ci"
+  (define-key sgml-mode-map "\C-ci"
     'tempo-template-html-tt-insert-if)
-  (define-key html-helper-mode-map "\C-cl"
+  (define-key sgml-mode-map "\C-cl"
     'tempo-template-html-tt-insert-elsif)
-  (define-key html-helper-mode-map "\C-ce"
+  (define-key sgml-mode-map "\C-ce"
     'tempo-template-html-tt-insert-else)
-  (define-key html-helper-mode-map "\C-cf"
+  (define-key sgml-mode-map "\C-cf"
     'tempo-template-html-tt-insert-foreach)
-  (define-key html-helper-mode-map "\C-cw"
+  (define-key sgml-mode-map "\C-cw"
     'tempo-template-html-tt-insert-while)
-  (define-key html-helper-mode-map "\C-cm"
+  (define-key sgml-mode-map "\C-cm"
     'tempo-template-html-tt-insert-switch)
-  (define-key html-helper-mode-map "\C-cn"
+  (define-key sgml-mode-map "\C-cn"
     'tempo-template-html-tt-insert-include)

   ;; add hilit-set-mode-pattern, if use hilit19.
   (if (featurep 'hilit19)
-      (hilit-add-pattern "\\[%" "%\\]" 'midnightblue 'html-helper-mode)
+      (hilit-add-pattern "\\[%" "%\\]" 'midnightblue 'sgml-mode)
     )
 
   ;; set font-lock
   (make-local-variable 'font-lock-defaults)
   (setq html-tt-font-lock-keywords
-	(append html-helper-font-lock-keywords html-tt-font-lock-keywords))
+	(append sgml-font-lock-keywords html-tt-font-lock-keywords))
   (setq font-lock-defaults '(html-tt-font-lock-keywords t t))
   ) 

.emacs での設定はこんな感じで。

(require 'html-tt)
(add-hook 'sgml-mode-hook 'html-tt-load-hook)

Older posts: 1 2 3 4 ... 27