dtrace機能を有効にしたNetBSDインストールCDを作成してみた

dtrace機能を有効にしたNetBSDインストールCDを作成してみた

NetBSDのdtrace機能を試してみようと思い立ち、@akachochinさんのNetBSD dtrace格闘記その2を元にdtrace機能を有効にしたインストールCDの作成手順をまとめてみました。

インストールCD作成準備

@akachochinさんのblogでは、インストール済みのNetBSD環境に直接dtraceまわりのカーネルモジュールをインストールしています。私の環境ではdtraceを有効にしたNetBSDのインストールCDを作成したいため、まずはインストールCD作成用のNetBSD環境を準備します。

ソースコードを展開する

NetBSD-6.1.3-i386仮想マシンにインストールした後、ソースコードを展開します。

# mount /dev/cd0a /cdrom
# cd /cdrom/source/sets/
# ls -l *.tgz
-r--r--r--  1 root  wheel   43069713 Jan 19 20:15 gnusrc.tgz
-r--r--r--  1 root  wheel    7661899 Jan 19 20:16 sharesrc.tgz
-r--r--r--  1 root  wheel  203542266 Jan 19 20:14 src.tgz
-r--r--r--  1 root  wheel   40189162 Jan 19 20:15 syssrc.tgz
-r--r--r--  1 root  wheel  158393066 Jan 19 20:18 xsrc.tgz

ソースコードは/usr/src以下に展開します。

# for i in *.tgz; do tar zxvf $i -C /; done

カーネルコンフィグを修正してdtrace機能を有効化する

dtrace機能を有効にするためのカーネルコンフィグを追加します。INSECURE,KDTRACE_HOOKS,MODULARを有効にする必要がありますが、GENERICコンフィグではINSECURE,MODULARは既に有効になっていたため、KDTRACE_HOOKSのみ追加します。

# cd /usr/src/sys/
# diff -u arch/i386/conf/GENERIC.orig arch/i386/conf/GENERIC
--- arch/i386/conf/GENERIC.orig 2012-08-16 00:33:00.000000000 +0900
+++ arch/i386/conf/GENERIC      2014-04-13 02:23:38.000000000 +0900
@@ -74,6 +74,7 @@
 # Standard system options

 options        INSECURE        # disable kernel security levels - X needs this
+options                KDTRACE_HOOKS

 options        RTC_OFFSET=0    # hardware clock is this many mins. west of GMT
 options        NTP             # NTP phase/frequency locked loop

build.shを実行する

build.shを使用して一通りのビルドを行います。ビルドは時間がかかるので、以下のスクリプトを作成し、バッチ処理的にビルドを行うようにしました。

上記のスクリプトMac mini(2.4GHz Intel Core 2 Duo,メモリ 8GB)のVirtualBox上のNetBSDで走らせたところ、全てのビルドが完了するまで15時間程度かかりました。

ビルドが完了すると、以下の場所にdtrace機能が有効になったインストールCDが生成されます。

/usr/obj/distrib/i386/cdroms/installcd/NetBSD-6.1.3-i386.iso 

OSインストール後のdtrace機能を利用するための設定投入

インストールCDが作成できたので、このCDを使用してNetBSDを再度インストールします。インストール後、dtrace用にデバイスファイルを作成します(OSインストール後に一度行うだけで良い)。

# mkdir /dev/dtrace
# mknod /dev/dtrace/dtrace c dtrace 0

そして、OS起動時にdtraceに必要なカーネルモジュールをロードするよう設定します。もっとスマートな方法があると思うのですが、今回は/etc/rc.localに以下の処理を追加しました。

_MODULE="
solaris
dtrace
sdt
fbt
"
for i in ${_MODULE}
do
    echo "modload ${i}"
    modload ${i}
done

OSを再起動するとdtrace機能が利用可能になっています。

# dtrace -l | wc -l
  45326

dtrace機能を試してみる

NetBSDでdtraceが利用できるようになったので、例としてgetpid()システムコールをフックさせてみます。

"getpid"というキーワードにマッチする関数は、sys_getpid(),sys_getpid_with_ppid()の2つがあるようです。

# dtrace -l | grep getpid
21001        fbt            netbsd                        sys_getpid entry
21002        fbt            netbsd                        sys_getpid return
21003        fbt            netbsd              sys_getpid_with_ppid entry
21004        fbt            netbsd              sys_getpid_with_ppid return

どちらがgetpid()システムコールの実体か分からないので、"getpid"でマッチするようにしてみます。dtrace -nを実行すると、その端末内で出力待ちの状態になります。

# dtrace -n fbt:netbsd:*getpid*:entry
dtrace: description 'fbt:netbsd:*getpid*:entry' matched 2 probes

別の端末にて、getpid()を実行するサンプルプログラムを用意します。

# cat _getpid.c
#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
        printf("%d\n", getpid());
        return 0;
}
# gcc -Wall -Werror -g -o _getpid _getpid.c

サンプルプログラムを実行すると、dtraceを実行している端末に以下が出力されます。

# dtrace -n fbt:netbsd:*getpid*:entry
dtrace: description 'fbt:netbsd:*getpid*:entry' matched 2 probes
CPU     ID                    FUNCTION:NAME
  0  21003       sys_getpid_with_ppid:entry
  0  21003       sys_getpid_with_ppid:entry

getpid()の実体はsys_getpid_with_ppid()のようです。プロセスの生成時にもsys_getpid_with_ppid()は呼ばれるようで、出力が2回になっています。

# cat -n /usr/src/sys/kern/kern_prot.c
    81  /* ARGSUSED */
    82  int
    83  sys_getpid_with_ppid(struct lwp *l, const void *v, register_t *retval)
    84  {
    85          struct proc *p = l->l_proc;
    86
    87          retval[0] = p->p_pid;
    88          retval[1] = p->p_ppid;
    89          return (0);
    90  }

まとめ

NetBSDでdtrace機能を試してみました。デフォルトインストールではdtrace機能が有効で無いため、カーネルカーネルモジュールの構築が必要です。インストールCDが欲しかったので、備忘録を兼ねた一通りのビルド手順についてもまとめてみました。

ポケットミクでテキスト読み上げ

ポケットミクでテキスト読み上げ

学研から発売された「歌うキーボード ポケットミク」を動かしてみました。

カーボンキーボードで演奏すると、初音ミクが「どーれーみー」という感じで歌ってくれます。また、MIDIデバイスとして利用でき、例えばNetBSDでは以下のdmesgが得られます(NetBSD-6.1-i386の場合です)。

Apr 29 07:12:32 hayase /netbsd: uaudio0 at uhub3 port 3 configuration 1 interface 0
Apr 29 07:12:32 hayase /netbsd: uaudio0: NSX-39 NSX-39, rev 2.00/1.00, addr 2
Apr 29 07:12:32 hayase /netbsd: uaudio0: audio descriptors make no sense, error=4
Apr 29 07:12:32 hayase /netbsd: umidi0 at uhub3 port 3 configuration 1 interface 1
Apr 29 07:12:32 hayase /netbsd: umidi0: NSX-39 NSX-39, rev 2.00/1.00, addr 2
Apr 29 07:12:32 hayase /netbsd: umidi0: (genuine USB-MIDI)
Apr 29 07:12:32 hayase /netbsd: umidi0: out=1, in=1
Apr 29 07:12:32 hayase /netbsd: midi1 at umidi0: <0 >0 on umidi0

すばらしいことに、GitHub上にはRuby,Python等のスクリプトからポケットミクを操作するためのライブラリが有志によって公開されており、Rubyからポケットミクを操作できるpoket_mikuがあります。

pocket_mikuのインストール

私の環境では、以下の手順でpocket_mikuをインストールしました。

  1. Gemfileを作成する

以下の内容でGemfileを作成します。

source :rubygems
gem 'pocket_miku', :git => "git://github.com/toshia/pocket_miku.git"
  1. gemでインストールする
$ sudo gem193 install pocket_miku
  1. 簡単なサンプルを試す

以下のサンプルを実行すると、初音ミクが「ふぁー ぼー」としゃべります。

#!/usr/bin/env ruby193
# -*- coding: utf-8 -*-

require 'pocket_miku'

PocketMiku.sing '/dev/rmidi1' do
  tempo 240
  ふぁ 75; ぼ 82;
end

ポケットミクでテキストを読み上げてみる

さて、無事にスクリプトから初音ミクにおしゃべりさせることができたワケですが、もう一歩進めて、今度はテキストを読み上げさせてみます。

以下のように、初音ミクにしゃべらせたい音をスクリプトから指定するだけでOKなのですが、「日本語」→「にほんご」のように、平仮名に直して指定する必要があります。

  ふぁ 75; ぼ 82;

ここはサクっとChasenを使ってテキストを平仮名に直すという方法を試してみました。

Chasenによる形態素解析では、以下のような出力が得られます。読みの第一候補(第二カラム)を使うとうまく行きそうです。 (実はこのカラムの名称を知らず、Chasenマニュアルを読む羽目に...)

$ chasen
今日は良い天気です
今日  キョウ    今日    名詞-副詞可能
は    ハ        は      助詞-係助詞
良い  ヨイ      良い    形容詞-自立     形容詞・アウオ段        基本形
天気  テンキ    天気    名詞-一般
です  デス      です    助動詞  特殊・デス      基本形
EOS

スクリプトは以下においてあります。

以下の手順でスクリプトを実行します(現状「!」とかの記号が入ったテキストだとエラーがでます...)。

$ echo 今日は良い天気です | chasen > data.txt
$ ./miksay.rb data.txt

テキストを読み上げたものの...

ポケットミクによるテキスト読み上げまで行えたのですが、いざ発声を聞いてみると、あまりよく聞き取れません。 しばらく聞いていて気がついたのですが、発声の「間」を調節しないと聞き取りにくいようです。

「キョウハ ヨイ テンキデス」という発声だと良いのですが、「キョウハヨイテンキデス」と一気に読み上げると、思っている以上に単語の区切りが分かりにくいです。日々会話する時にはほとんど意識しないのですが、この「間」は重要なのですね。

まとめ

スクリプトからポケットミクをしゃべらせてみました。形態素解析ツールを活用することでうまいこと仮名の切り出しが行えました。テキスト読み上げについては、発声の「間」などの考慮が必要そうで、まだまだ改良の余地ありです。

追記

肝心なことを忘れていました。5月6日に「ポケットミクちゃんに何かいろいろさせる会(その1)」という会を開催する予定です。ご興味のある方はぜひご参加ください。

「悪循環画像ジェネレータ」を作ってみた

悪循環画像とは

昨日くらいから、Twitter上で「悪循環コラ画像」というものが流行っているようです。元々はみやぎ県政だより(2010年12月号)http://www.pref.miyagi.jp/kohou/kenseidayori/backnumber/201012/special/special01.htmの薬物乱用防止の啓蒙記事にある、薬物依存の悪循環を示すイメージ図がオリジナルなのですが、妙に汎用性(?)があるのか、様々なジャンルでの悪循環コラが作られる状態になっています。

そこで悪循環コラ作成の一助になればと思い、「悪循環画像ジェネレータ」を作成してみました。ブラウザ上で文言を入力することで悪循環コラが作れるというものです。

悪循環画像ジェネレータ

URLは以下になります(2017/02/12追記:Bitbucketだと404 Requestが返されてしまうのでGitHub Pagesに引っ越しました)。

入力欄に文言を入力すると、オリジナル画像をテンプレ化(吹き出しの文字を消したもの)した画像に文言が反映されるという動作になっています。
(それしか機能がない……)

単に入力された文言をHTML5 CanvasのfillText()で描画するだけのはずだったのですが、<br>で改行できるようにしたところ、予想よりもちょっと複雑な処理になってしまいました。
というわけで、文言の中に<br>を入れると、改行文字として扱われ、かつ、配置も(ある程度)よきにはからってくれる動作になっています。

悪循環コラを作ってみる

簡単なサンプルとして、のんのんびよりの悪循環コラを作ってみました。
以下のような感じになります。

f:id:furandon_pig:20140104082917p:plain

このツールでさらに悪循環コラが増えてくれればと思います。

その他

このアプリケーションはTwitter Bootstrapを利用したのですが、あまり活用できていません。また、バージョンが上がったのか、デザインやレイアウトルールが以前(1年くらい前)と変わっているようでした。

アセンブラ短歌を詠みつつブログを始めてみた

あけましておめでとうございます。

2014年の幕開けにあわせて、人もすなる日記といふものを始めようと思いたちました。

最初の日記は新年らしく(?)アセンブラ短歌を詠んでみることにしました。

アセンブリ短歌とは、http://kozos.jp/asm-tanka/で紹介されているように、機械語命令がちょうど五・七・五・七・七の並びにおさまるようにしたプログラムのことであります。

さっそく九九の表を出力するアセンブラ短歌を読んでみます。環境はNetBSD-6.1-i386です。
(数値を出力したかったのですが、ASCII文字にマッピングした文字を出力しています...)

コメントの5,7,5...の部分が五・七・五の切れ目になっており、このmain関数はアセンブラ短歌が2首入っています。

.globl  main
main:
        mov     $0x01, %eax     # 5
xloop:  mov     $0x01, %ebx
yloop:  push    %eax
        nop                     # 7
        imul    %ebx
        add     $0x1f, %eax     # 5
        call    my_putchar
        mov     $0x20, %al      # 7
        call    my_putchar
        pop     %eax
        inc     %ebx            # 7
        cmp     $0x0a, %ebx
        jnz     yloop           # 5
ybreak: inc     %eax
        cmp     $0x0a, %al
        jz      xbreak
        push    %eax
        nop                     # 7
        mov     $0xa, %eax      # 5
        call    my_putchar
        pop     %eax
        nop                     # 7
        jmp     xloop
xbreak: nop
        nop
        nop
        nop
        ret                     # 7

.globl  my_putchar
my_putchar:
        sub     $0x10, %esp
        mov     %eax,(%esp)
        mov     %esp,%eax
        movl    $0x1, 0xc(%esp)
        movl    %eax, 0x8(%esp)
        movl    $0x1, 0x4(%esp)
        mov     $0x4, %ax
        int     $0x80
        add     $0x10, %esp
        ret

コンパイルと実行結果は以下のようになります。

$ gcc -Wall -Werror -g kuku.s
$ ./a.out
  ! " # $ % & ' (
! # % ' ) + - / 1
" % ( + . 1 4 7 :
# ' + / 3 7 ; ? C
$ ) . 3 8 = B G L
% + 1 7 = C I O U
& - 4 ; B I P W ^
' / 7 ? G O W _ g
( 1 : C L U ^ g p

1首目の短歌を逆アセンブルして見てみます。五・七・五・七・七のリズムで機械語命令を区切ることができます。

$ objdump -d a.out | grep -A20 '<main>:'
080486a0 <main>:
 80486a0:       b8 01 00 00 00          mov    $0x1,%eax

080486a5 <xloop>:
 80486a5:       bb 01 00 00 00          mov    $0x1,%ebx

080486aa <yloop>:
 80486aa:       50                      push   %eax
 80486ab:       90                      nop
 80486ac:       f7 eb                   imul   %ebx
 80486ae:       83 c0 1f                add    $0x1f,%eax
 80486b1:       e8 28 00 00 00          call   80486de <my_putchar>
 80486b6:       b0 20                   mov    $0x20,%al
 80486b8:       e8 21 00 00 00          call   80486de <my_putchar>
 80486bd:       58                      pop    %eax
 80486be:       43                      inc    %ebx
 80486bf:       83 fb 0a                cmp    $0xa,%ebx
 80486c2:       75 e6                   jne    80486aa <yloop>

080486c4 <ybreak>:
 80486c4:       40                      inc    %eax

アセンブラ短歌の詠み方としては、以下のような流れになります。

  1. アセンブリ言語でプログラムを書く
  2. アセンブルして動かしてみる(この段階では五・七・五は考えない)
  3. objdump -dで逆アセンブルし、五・七・五...になるよう調整する

x86アーキテクチャでは、意外と最初から五・七・五...になっていることも多いです。
機械語命令がうまいこと五・七・五...にならない場合、以下の方法で命令数を調整します。

  • nop(1byte命令)で埋める
  • movで代入するレジスタをeax→al等にして命令数を増減させる
  • 機械語命令の順番を入れ替える(入れ替えても問題がない場合のみ)

これ他にも機械語命令数の調整方法はあるかと思います。筆者は上記の3パターンで何とかアセンブラ短歌を詠めています。

皆様も新年はアセンブラ短歌で(プログラムの)書き初めをしてみてはいかがでしょうか。

【1/4追記】環境の記述が抜けていたので追記しました。