dtraceに関する情報のリンクと、NetBSD dtraceでグローバルに使える組み込み変数&関数について
まず、いきなりだが、dtraceの概要は以下のページなどで紹介されているので参考にされたし。
http://nippondanji.blogspot.jp/2010/02/ddtrace.html
https://blogs.oracle.com/yappri/entry/dtrace
http://docs.oracle.com/cd/E24845_01/html/E22189/gcfpv.html
なので、dtraceの文法などについてはここでは記載しない。
(まだakachochinが完全に文法などを把握していないこともある...)
またさらにググってみると、OracleのWebPageにはDtraceの文法が載っているようだ。
これを参考にしつつ頑張ってみたい。
で、終わりではあんまりなのでこのページのサンプルプログラムを入力、実行してみる。
ところが、エラーが起こり、実行できない。どうやら、SolarisとNetBSDではプロバイダなどが違うようだ。
また、利用可能な述語も違うようで、サンプルプログラムの/uid==0/も使えないようだ。
ところで、プローブ記述はPROVIDER:MODULE:FUNCTION:NAMEの4つから構成される。
システムにあるプローブのリストはdtrace -lで表示できる。
# dtrace -l | head -n 10 ID PROVIDER MODULE FUNCTION NAME 1 dtrace BEGIN 2 dtrace END 3 dtrace ERROR 4 fbt netbsd AES_GMAC_Final entry 5 fbt netbsd AES_GMAC_Final return 6 fbt netbsd AES_GMAC_Init entry 7 fbt netbsd AES_GMAC_Init return 8 fbt netbsd AES_GMAC_Reinit entry 9 fbt netbsd AES_GMAC_Setkey entry
例えば上記ID8のプローブに対して何かしたい場合、プローブ記述は
fbt:netbsd:AES_GMAC_Reinit:entry
となる。
述語に指定できるものはどんなものがあるのだろうか?また、組み込み変数のようなものはあるのか?(例えば先のWebPageに出てきた「execname」など)
また、このWebPageの下の方には「集計関数」というものもあるらしいことがわかる。
こういった情報はソースのどこかにないものか。少なくともNetBSDで動作が確認できている「execname」で全ソースをgrepしてみた。
すると気になる検索結果があった。それを抜粋する。
external/cddl/osnet/dist/lib/libdtrace/common/dt_open.c:{ "execname", DT_IDENT_SCALAR, 0, DIF_VAR_EXECNAME, external/cddl/osnet/dist/uts/common/dtrace/dtrace.c: * builtin values such as 'execname' and 'probefunc.' external/cddl/osnet/dist/uts/common/dtrace/dtrace.c: * curthread, pid, ppid, tid, execname, zonename, uid and gid variables. external/cddl/osnet/dist/uts/common/sys/dtrace.h: * execname <= Current executable name
external/cddl/osnet/dist/lib/libdtrace/common/dt_open.cには
static const dt_ident_t _dtrace_globals[] = { { "alloca", DT_IDENT_FUNC, 0, DIF_SUBR_ALLOCA, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_func, "void *(size_t)" }, { "arg0", DT_IDENT_SCALAR, 0, DIF_VAR_ARG0, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, { "arg1", DT_IDENT_SCALAR, 0, DIF_VAR_ARG1, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, (略) { "vtimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_VTIMESTAMP, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "uint64_t" }, { "walltimestamp", DT_IDENT_SCALAR, 0, DIF_VAR_WALLTIMESTAMP, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "int64_t" }, #if defined(sun) { "zonename", DT_IDENT_SCALAR, 0, DIF_VAR_ZONENAME, DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" }, #endif { NULL, 0, 0, 0, { 0, 0, 0 }, 0, NULL, NULL } };
というテーブルが。このテーブルの各エントリの最初のメンバがグローバルな組み込み変数だったり、組み込み関数だったりするわけか。
(300行程度あるので、さすがに全て載せられない・・・。NetBSD6.0リリース版ではこのソースが該当するソースなので、このソースの_dtrace_globalsテーブルを参考にしてほしい。
これをもとに、dtrace言語の勉強をしてみますか・・・。
今回は私の体調不良や忘年会などの飲みがあり、NetBSDのdtraceに関する調査にあまり進展がなかったが、お許し願いたい。
NetBSD dtrace格闘記その2
(NetBSD6.0でdtrace環境を手っ取り早く整えたい方は、末尾のほうにある「まとめ」を読んでくださいな。)
前回の日記では
*NetBSD6.0ではdtraceが導入された。公式のWiki(http://wiki.netbsd.org/how_to_enable_and_run_dtrace/)に導入方法が書いてあった。
* しかし、modloadしようとするとsolarisモジュール以外のモジュールがいないといわれる。
* build.shでdistributionしてできたオブジェクト群の中にはモジュールが存在している。ということはインストールができていないだけ。
*build.shにはinstallmodulesというOperationが存在するが、そのときに指定するディレクトリがよくわからない。
*modloadのソースをシステムコール含め読んでみると、どうやらmodloadは/stand/i386/6.0/modulesディレクトリの下を見に行っていることがわかった。
*よって、installmodulesに指定するディレクトリは/stand/i386/6.0/modulesを指定すればいいんじゃね?という仮説が立った。
ということを書いた。
そこで、今日はbuild.shでinstallmodulesを試す。
./build.sh -a i386 -O ../obj -T ../tools installmodules=/stand/i386/6.0/modules
途中までうまくいくが、sys/modules/xldscriptsのところでエラーが発生する。
install ===> sys/modules/xldscripts # install /stand/i386/6.0/modules/usr/libdata/ldscripts/kmodule /usr/src/../tools/bin/i486--netbsdelf-install -N /usr/src/etc -c -r -o root -g wheel -m 444 kmodule /stand/i386/6.0/modules/usr/libdata/ldscripts/kmodule i486--netbsdelf-install: /stand/i386/6.0/modules/usr/libdata/ldscripts: mkstemp: No such file or directory *** Failed target: /stand/i386/6.0/modules/usr/libdata/ldscripts/kmodule *** Failed command: /usr/src/../tools/bin/i486--netbsdelf-install -N /usr/src/etc -c -r -o root -g wheel -m 444 kmodule /stand/i386/6.0/modules/usr/libdata/ldscripts/kmodule *** Error code 1
ログによると、/stand/i386/6.0/modules/usr/libdata/ldscripts/kmoduleが存在しないと言われているようだ。
けど、/stand/i386/6.0/modules/の下のさらに/usr/libdata/ldscripts/kmoduleを探しにいくのはおかしい。
他のモジュールのインストールログを見ると「/stand/i386/6.0/modules/stand/i386/6.0/modules」なんてディレクトリ構成になっている・・・。
どうやら指定したディレクトリに/stand/i386/6.0/modulesディレクトリを作成し、そこにモジュールをインストールしていると推定。
今回モジュールをインストールしたいのは/stand/i386/6.0/modulesなので、installmodulesで「/」を指定することにした。
./build.sh -a i386 -O ../obj -T ../tools installmodules=/
installmodulesは成功した。しかし、再度modloadを試みてもやはりsolaris以外のモジュールがロードできないし、/stand/i386/6.0/modulesの下に該当モジュールがいない。
よって、「インストールすべきモジュール群はどのようにして決まっているのか」を追うことにする。
まず、ソースファイルが置かれたルートディレクトリ(build.shがあるディレクトリ)にあるMakefileを見る。build.shがinstallmodules時に叩いているMakefileだ。
installmodulesターゲットでは、諸々のチェックをしたあと、以下の3行を実行する。
${MAKEDIRTARGET} sys/modules install DESTDIR=${INSTALLMODULESDIR:U/} @echo "make ${.TARGET} started at: ${START_TIME}" @printf "make ${.TARGET} finished at: " && date
${MAKEDIRTARGET}とは何でこれは何処にいるのか?
grepをかけて調べると、share/mk/bsd.own.mkにいることがわかる。
bsd.own.mkの説明書きによると
# # MAKEDIRTARGET dir target [extra make(1) params] # run "cd $${dir} && ${MAKEDIRTARGETENV} ${MAKE} [params] $${target}", with a pretty message #
とのことである。このことからcd sys/modulesしてmakeをしていることが伺える。
そこで、sys/modulesの下のMakefileを見る。すると以下の記述が存在する。
.if (${MKDTRACE} != "no") SUBDIR+= dtrace .endif # we need solaris for the dtrace and zfs modules .if (${MKDTRACE} != "no" || ${MKZFS} != "no") SUBDIR+= solaris .endif
これによるとdtraceはMKDTRACEというビルド変数が"no"以外でないとmakeの対象にしてもらえないらしい。
ここで、solarisモジュールはインストールできている。
その理由はshare/mk/bsd.own.mkの中で以下のように定義されているためである。
# # We want to build zfs only for i386 and amd64 by default for now. # .if ${MACHINE} == "amd64" || ${MACHINE} == "i386" MKZFS?= yes .endif
しかし、MKDTRACEはどこの時点でnoにされているのか。grepをかけてみた。
ヒットしたファイルの一つであるshare/mk/bsd.own.mkを確認すると、以下の記述があった。
# # MK* options which default to "no". Note that MKZFS has a different # default for some platforms, see above. # _MKVARS.no= \ MKBSDGREP MKBSDTAR \ MKCATPAGES MKCRYPTO_RC5 MKDEBUG \ MKDEBUGLIB MKDTRACE MKEXTSRC \ MKMANZ MKOBJDIRS \ MKLLVM MKPCC \ MKPIGZGZIP \ MKREPRO \ MKSOFTFLOAT MKSTRIPIDENT \ MKUNPRIVED MKUPDATE MKX11 MKZFS .for var in ${_MKVARS.no} ${var}?=no .endfor
ああ、列挙されているビルド変数を"no"にしているのね。ここまでのところで、installmodulesしてもモジュールがインストールできないのはビルド変数MKDTRACEが"no"だったからということがわかる。
ということで再度build.shをかけてみる。
./build.sh -a i386 -O ../obj -T ../tools -V MKDTRACE=yes installmodules=/
これまで失敗していた「modload dtrace」を実行してみると、今度は成功した。
「modload sdt」も「modload fbt」も同様に成功した。
公式ブログで述べられているデバイスファイル作成も成功。
mkdir /dev/dtrace mknod /dev/dtrace/dtrace c dtrace 0
プルーブの一覧を表示するために「dtrace -l」を実行したが、これが失敗する。(dtrace: Command not found.)
build.shでdistributionしてからinstallをしていなかった事に気づく。よって、以下のコマンドを実行する。
./build.sh -a i386 -O ../obj -T ../tools -V MKDTRACE=yes install=/
実行後、rehashし、再度dtraceコマンドを実行する。今度は無事にprobeの情報を出力することができた。
まとめ
NetBSD6.0でdtraceの環境を作るためには以下の手順が必要。
(ソースが/usr/src以下に、objディレクトリは/usr/objに、ツールチェインが/usr/toolsにあるという前提で記載する。)
(1)ツールチェインを作成する。
./build.sh -a i386 -O ../obj -T ../tools tools
(2)カーネルをビルドする。ビルドする際、カーネルコンフィグファイルに以下の3記述があることを確認する。(コメントアウトされていないか要確認。なければ追加)
options INSECURE options KDTRACE_HOOKS options MODULAR
(3)distributionをビルドする。
./build.sh -a i386 -O ../obj -T ../tools -V MKMODULAR=yes -V MKDTRACE=yes distribution
(4)(3)でビルドしたブツをインストールする。
./build.sh -a i386 -O ../obj -T ../tools -V MKDTRACE=yes install=/
(5)(3)でビルドされたモジュールをインストールする。
./build.sh -a i386 -O ../obj -T ../tools -V MKDTRACE=yes installmodules=/
(6)モジュールをロードする。
modload solaris modload dtrace modload sdt modload fbt
(7)デバイスファイルの作成を行う。
mkdir /dev/dtrace mknod /dev/dtrace/dtrace c dtrace 0
これでdtrace -lしてプルーブの一覧が表示されれば成功です。
公式ブログでは端折っている箇所があり、苦労しましたが、いろいろと勉強になりました。
NetBSD dtrace格闘記(道半ば)
NetBSD6.0はdtrace対応している。
手順は http://wiki.netbsd.org/how_to_enable_and_run_dtrace/ に書いてあったから簡単に行くと思いきや・・・。なかなか上手くいかないもので。
未だ格闘中で使えるようにはなっていないけれど、途中色々調べたことがあったので、長いけれどまとめてみることにします。
(1)build.shでdistributionを作るときの注意
http://wiki.netbsd.org/how_to_enable_and_run_dtrace/ によれば、「You also need to build distribution with the options MKMODULAR=yes and MKDTRACE=yes.」とある。この"option"の指定の仕方は-Vオプションで指定する。
つまり、
./build.sh -O ../obj -T ../tools -u -V MKMODULAR=yes -V MKDTRACE=yes distribution
のように。
(正確には"option"というよりも"make variables"らしい。これは/etc/mk.confでも指定が可能である。)
(2)新しいユーザランドをインストールするときの注意
build.shに-Uオプションをつけると
don't know how to make /usr/src../obj/destdir.i386/METALOG. Stop
と言われてしまうようなので、-Uオプションをつけない。
ただし、この場合、rootで作業する必要がある。
(3)モジュールがロードできない!
Running hello worldの項で
modload solaris
modload dtrace
modload sdt
modload fbt
とあるが、modload solaris以外は失敗してしまう。このときのエラーメッセージは「No such file or directory」である。
dtraceモジュールなどが生成されていないと思われるので、ルートディレクトリの下でfindコマンドを実行して探してみる。
すると、solarisモジュールは/stand/i386/6.0/modules/solarisに存在する(他にも存在するがいずれも/usr/srcもしくは/usr/objの下かもしくは明らかにmoduleでなさそうなファイルなので除外)に対し、dtraceはいずれも/usr/srcの下かもしくは/usr/objの下にしか存在しない。(sdt,fbtも同様)
しかも/stand/i386/6.0/modules/solarisの日付をlsコマンドで確かめると、./build.shで配布物を構築しているときに相当している。これはどういうことだろう。
ということはシステムにdtrace,sdt,fbtがインストールされていないようだ。
ここで二つの疑問が生じる。
疑問1.なぜ、これら3つのモジュールがシステムに反映されていないのか
疑問2.modloadが見に行くディレクトリはどうなっているのか
まずは疑問1について。まずは./build.shとタイプしてヘルプを見る。すると、Other operationsのところに install=idirとは別にinstallmodules=idirというオペレーションがある。
このことより、モジュールのインストールは別途行う必要があると思われる。
しかし、installmodulesに指定するディレクトリにつき、何が正解なのかわからない。
そこで、疑問2.を解決してみることにする。
modloadが見に行くディレクトリが分かれば、そのディレクトリをinstallmodulesオペレーションで指定することによって正しくモジュールがインストールできる見込みが立つからである。
疑問2を解消すべく、sbin/modloadのソースを読む。
まず、modloadのmain.cを追う。modload実行時は、オプションはつけていないので、output_propsはfalse。よって、else節が実行される。
else節にあるprog_modctl()でモジュールのロードをやっているのだろう。
prog_ops.hでprog_modctlの定義がある。
おそらくはCRUNCHOPSの定義はないので、op_modctlポインタ経由での呼び出しになる。
op_modctlを初期化している箇所は2箇所あるが、rumpはとりあえず関係なさそうなので、modctlが関数ポインタの実体となっていることが判断できる。
modctlについてgrepなどで調べた結果、どうやらシステムコールらしい事が分かる。
カーネルソースを引き続き読んでみる。sys_modctlではcmdを見てMODCTL_LOADだった場合はhandle_modctl_loadを呼び出す。
う〜ん、sbin/modloadのソースの時点から気になっていた「prop」がまだついて回っている。(sys_modctlとhandle_modctl_loadはkern/sys_module.c)
とりあえず先に進んで、module_loadを読んでみる。(module_loadはkern/kern_module.c)
module_loadでの処理本体はmodule_do_loadが担っている模様。
module_do_loadではmodule_builtinsリストを調べる。そしてロードしたいモジュールが見つかった場合はreturnしているように見える。
module_buildinsリストで見つからない場合、module_bootlistリストを調べる。
そして見つかったら、module_bootlistリストからpendingリストにモジュールを移し替える。
見つからない場合「if(isdep)」の節には入らずに(isdepはfalse)、module_newmodule関数がコールされる。(エラーだったときのメッセージから判断するに、これはモジュールをロードするための領域確保の関数ではないか?)
次にmodule_load_vfs_vecがコールされる。そして正常終了した段階でモジュールをpendingリストに加える。(pendingリストに加えられたモジュールはロードに成功した段階でリストから外される。)
以後の処理はロードしようとしているモジュールの妥当性の確認とロードそのものに関する処理のように見えるので、これらの処理を読んでも疑問は解消されないと思われる。よって、
(1)module_builtinsリストとは何者?
(2)module_bootlistリストとは何者?
(3)module_load_vfs_vec関数の処理内容
を追ってみることで、modloadがどこのディレクトリを探しにいくのかがわかるかな、と思う。
(1)module_builtinsリストについて
module_builtin_add()によってこのリストにエントリが追加される。
module_builtin_add()は(rumpを別にすれば)module_init()から呼ばれている。
module_init()では
__link_set_decl(modules, modinfo_t)
と
__link_set_foreach(mip,modules)
があり、このforeachの中でmodule_builtin_add()が呼ばれている。
__link_set_decl()の実体はsys/cdefs_elf.h内で以下のように定義されている。
#define __link_set_decl(set, ptype) \ extern ptype * const __start_link_set_##set[]; \ extern ptype * const __stop_link_set_##set[] \
つまり、__link_set_decl(modules, modinfo_t)は
extern modinfo_t * const __start_link_set_modules[]; extern modinfo_t * const __stop_link_set_modules[]
と展開される。
__start_link_set_modulesおよび__stop_link_set_modulesについてカーネルソースを検索してみるが、rumpのldscript以外には存在しない。
試しにビルドを行ったNetBSD側のsysの下をgrepすると、netbsd.mapファイルに記述があるようだ。
netbsd.mapによると
link_set_modules
0xc0bbd8ac 0x1e4 load address 0x00bbd8ac
0xc0bbd8ac . = ALIGN (0x4)
0xc0bbd8ac PROVIDE (__start_link_set_modules, ABSOLUTE (.))
となっており、以後は
link_set_modules
0xc0bbd8ac 0x4 accf_data.o
link_set_modules
0xc0bbd8b0 0x4 accf_http.o
(略)
link_set_modules
0xc0bbda8c 0x4 xc5k.o
0xc0bbda90 PROVIDE (__stop_link_set_modules, .)
となっている。
試しにnetbsdに対してreadelf -Sを実行すると
[ 4] link_set_modules PROGBITS c0bbd8ac ...
という行が表示される。
これらの事から、module_builtinsリストには、link_set_modulesセクションの中身が順次突っ込まれると考えられる。
そこで、link_set_modulesセクションの中身について調べる。
link_set_modules
0xc0bbd8ac 0x4 accf_data.o
という記述があるので、試しにaccf_data.cを探してみて、その中に何が書かれているのかを見ることにする。
accf_data.cはnetinet/accf_data.cにある。中身はいくつかの関数と構造体定義があるのみである。
しかし、ソースの上の方に
MODULE(MODULE_CLASS_MISC, accf_dataready, NULL);
という行がある。
MODULEマクロはsys/module.hの中で以下のように定義されている。
#define MODULE(class, name, required) \ static int name##_modcmd(modcmd_t, void *); \ static const modinfo_t name##_modinfo = { \ .mi_version = __NetBSD_Version__, \ .mi_class = (class), \ .mi_modcmd = name##_modcmd, \ .mi_name = #name, \ .mi_required = (required) \ }; \ __link_set_add_rodata(modules, name##_modinfo);
これは構造体の実体を定義するためのマクロであるが、末尾の__link_set_add_rodataが気になる。
これはsys/cdefs_elf.hで
#define __link_set_add_rodata(set, sym) __link_set_make_entry(set, sym)
と定義されている。__link_set_make_entryは同じくsys/cdefs_elf.hで
#define __link_set_make_entry(set, sym) \ static void const * const __link_set_##set##_sym_##sym \ __section("link_set_" #set) __used = &sym
と定義されている。
例えば「MODULE(MODULE_CLASS_MISC, accf_dataready, NULL);」
の場合、
__link_set_add_rodata(modules, accf_dataready_modinfo);
|
__link_set_make_entry(modules, accf_dataready_modinfo)
|
static void const * const __link_set_modules_sym_accf_dataready_modinfo \
__section("link_set_modules") __used = &accf_dataready_modinfo
のようにマクロ展開される。このことから、link_set_modulesセクションにはMODULEマクロで定義されたmodinfo_t型構造体のアドレスが格納される事が分かる。
おそらくシステムに静的に組み込まれているモジュールであろう。あとから動的に追加されるものではない。
よって、module_builtinsリストについてこれ以上追っても今回疑問に上がっている「modloadがどこのディレクトリを見にいくのか」についてはわからないということになる。
なので、次に「(2)module_bootlistリストとは何者?」について追ってみることにする。
(2)module_bootlistリストとは何者?
このリストにエントリを追加している関数はkern/kern_module.cのmodule_prime()である。
説明書きを見ると「ブートローダによってロードされたモジュールを内部リストに押し込む」とある。
arch/x86/x86/x86_machdep.cからのみ呼ばれている。中をみたがよくわからん。
ブートローダによってロードされた、と言っている時点で「modloadが何処のディレクトリを見にいくのか」についての疑問が解消する可能性が低そうである。
なので、(2)は置いておき、「(3)module_load_vfs_vec関数の処理内容」を追ってみることにする。
(3)module_load_vfs_vec関数の処理内容
module_load_vfs_vecは関数ポインタであり、module_load_vfs_init()でmodule_load_vfs()を指すように初期化される。(kern/kern_module_vfs.c)
module_load_vfs()はkern/kern_module_vfs.cにある関数である。
今回のような呼び出し経路の場合、autoloadはfalseで呼び出される。で、普通に「modload dtrace」とした場合「/」は含まないのでENOENTとなる。ENOENTの場合で指定したモジュール名に「/」を含まない場合、「module_baseで指定されるディレクトリ/モジュール名/モジュール名.kmod」というパスで示されるファイルをロードしようと試みる。
それでもダメならエラーで戻る。
となると、module_baseの内容が何か調べれば、今回の疑問が解消するかもしれない。
module_baseはどうやらkern/kern_module.cで宣言されているようだ。
この変数はmodule_init()で以下のように初期化されているようだ。
#if __NetBSD_Version__ / 1000000 % 100 == 99 /* -current */ snprintf(module_base, sizeof(module_base), "/stand/%s/%s/modules", module_machine, osrelease); #else /* release */ snprintf(module_base, sizeof(module_base), "/stand/%s/%d.%d/modules", module_machine, __NetBSD_Version__ / 100000000, __NetBSD_Version__ / 1000000 % 100); #endif
module_machineは何か?module_init()では
if (!module_machine) module_machine = machine;
となっている。
今回のi386では特に初期化がされていないので、machineの内容がmodule_machineになる。
grepなどで追うのはかなり面倒(machineというキーワードに大量に引っかかるため)なので、実際のNetBSD環境の/standの下を見る。
すると、「i386」というディレクトリのみがあった。よって、machineの内容は「i386」だと思われる。
今回NetBSDのバージョンは6.0なので、最終的なmodule_baseは「/stand/i386/6.0/modules」となる。
実際のNetBSD環境と比較しても一致しているため、これで間違いが無いと思われる。
よって、modloadがモジュールの有無を見に行くディレクトリは「/stand/i386/6.0/modules」であると言えそうだ。
今日はここまで。次回は得られたパスを元にbuild.shのinstallmodulesを実施する事にする。
満州焼
先週の木曜日に横浜野毛で飲んで来たので、備忘録を。
今回飲みに行ったのは、「満州焼」なる酒の肴を出す「庄兵衛」。
早速つくねと満州焼を注文。
満州焼は↑で、甘味噌を搦めて焼いたカシラでした。
これは甘味噌の味とカシラの肉汁が合わさってなかなか美味い。
ただ、惜しまれるのは、飲み物のサイズが値段の割に小さいということ。思い切ってガバッと飲めなかったのは残念です。
串メニューは、他にも大エビの串などバラエティに富んでいますので串が好きな人はおすすめかな。
で、二軒目は串揚げを出してくれるお店「北村」へ。
揚げ物はシュウマイとれんこんとキス(だったっけな?)、あさりを頼みました。揚げ具合はなかなかです。
ただ、残念なのはメニューが10品くらいしかないこと。せっかく美味い串を食わせてくれるのだからもっとメニュー数があってもよいのでは、と思いました。
横浜市民のくせに、横浜野毛は初めてでしたが、まずまずでした。
小料理屋が多めな飲み屋街という印象を受けました。小料理屋だと、1件あたりの値段がそれなりにしてしまうので、1件ずつになりますが、コツコツと飲み歩きたいと思います。リーズナブルでおすすめな店があったら、紹介求む!
今日はツィラタール ラドラーをいただく
サッポロビールよりいただいた「世界のビール12本」。
今日はオーストリアのビール、ツィラタール ラドラーをいただくことにする。
ツィラタールビールは、500年以上の歴史を持つオーストリアでもっとも古くから存在するビール会社です。ラドラーは、元々自転車配送人が好む飲み物と言われ、ピルスナービール50%:レモネード50%の低アルコールの爽やかな飲み物です。苦いビールが苦手な女性にも人気の銘柄です。
ということだそう。
早速呑んでみると、ピルスナーのあっさりさそのままにレモンの爽やかな味が喉を駆け巡る。アルコール度数は1.5%。爽やかなレモン水を飲んでいるような、それでいてビールであることを忘れていない、そんな味がしました。
これは、飲んだ後の迎え酒にいいかも。
世界のビール12本
少し前にサッポロビール主催の「百人ビール・ラボ」の話を書いたと思う。
このイベントの参加者に抽選で「世界のビール12本」が当たるということらしかったが、どうやらakachochinが当たったみたいで、自宅に12本のビールが届いた。
ビールは12本。ベルギー、ドイツが多い。
ビールは以下のとおり。(今度写真を載せようと思います。何分12本と多いものでして・・・)
ベルギー:デリリュウムノクトルム瓶
ベルギー:ロシュフォール8
ベルギー:ブルゴーニュ・デ・フランドル
ドイツ:ホフブロイ ドゥンケル
ドイツ:ヴァイエンステファン・ヘフヴァイス
チェコ:ピルスナーウルケル
イギリス:フラーズ・ロンドンプライド
ドイツ:ケストリッツァー・シュバルツビア
オーストリア:エーデルワイススノーフレッシュ
オーストリア:ツィラタール ラドラー
シンガポール:タイガー・ラガー
日本:ヱビスビール
そして、今日はベルギーのロシュフォール8を呑んでみました。
このビールは解説によると
深い赤褐色のダークブラウンエールのビール。豊かなレーズンやイチジクのような香りがします。コーヒーキャラメル、トーストされたパン、バナナハーブなど複雑な味わいで、後口に香草や穀物の風味が広がります。
ということである。
うん。確かに赤褐色。呑んでみると香草というより薬草臭いビール。沈殿物も見受けられます。
こんなビールにはついついチーズが欲しくなります。ということで冷蔵庫を家探ししてチーズをパクリ。
うん、美味い。コレステロールを摂りすぎようがakachochinは構いません。美味い酒が飲めることが生きる証なのですから。
今度は何を飲もうか、今から楽しみです!
「やきとん道場三鶴」に行ってきました
先週の水曜日に西小山にある「焼きとん道場三鶴」に行ってきたので備忘録を。
店に入るとコの字カウンターの店。いきなりのっけから良い予兆です。
店の人に案内されてカウンターに座ります。
まずはホッピー。ここはホッピービバレッジが推奨する「三冷」を頑なに守る店なのです。
三冷とは「ジョッキ、ホッピー、焼酎を冷やし、氷を入れずに作られるホッピー」なのです。
普通ホッピーを売っている店は「外」と「中」があり、別々に頼めるところが多いのですが、ここは焼酎と混ぜてキンキンに冷えたジョッキにホッピーが注がれて供されます。
美味い!家で作ると焼酎臭さが残ったり、やや水っぽくなるホッピーがどうしてこんなに美味いのか!これこそプロの技なのか!それとも三冷のおかげ?いや、どちらも要因に含まれるのだと思います。
さて、焼きとん屋といえば欠かせないのが煮込み。早速いただきましょう。
ややあっさり目の煮込みですが、しっかりと煮込まれていて美味いこと美味いこと。ホッピーがまたまた進みます。
落ち着いたところで焼きものを頼むことに。そうだな、レバ、はつ、コブクロ行ってみるか。
しばらくすると、タレが付いた焼きものが出てきました。
(下の写真の串は中途半端につまんだ後の写真です。写真に撮るのを忘れ、思わずつまんでしまった結果です・・・)
自分の特に大好きなのはコブクロなのですが、コリコリ感がしっかり残っていて美味いこと。またまたホッピーが進んでしまいます。
最後に気づきましたが、マカロニサラダや奴などのサイドメニューもある模様。今度行くときには是非とも頼んでみたいところです。
(akachochinはマカロニサラダがとても好きなのです!同じく焼きとん系の店である祐天寺のばんでもいつもマカロニサラダを頼んでいます。)
そうそう、店の女将さんと常連さんと少しお話をしてホッピーの話題になったときのこと。ホッピービバレッジからもらった団扇を女将さんに見せてもらいました。なにやら地ビールのようなものが団扇にプリントされているではありませんか。
あとで調べてみると、ホッピーは地ビールも作っていることを初めて知りました。ここの商品一覧を見ると確かに書かれています。
そんなこんなでとても良い店でした。ああ、こんな店が地元にあったら、通いつめるのになあ。