犬との生活 その1
この記事はまたまた!ぴょこりんクラスタ Advent Calendar 2017のために書いたものです。
はじめに
突然犬(トイプードル)を飼うことになったので、犬との生活についてもろもろやったことなど書いておく。
まずは家探しから
何はともあれ犬を飼うには、犬を飼える部屋が必要である。
それなりの期間独居生活を送っていて、何回か引っ越しているので、家賃の相場などはおおよそわかるのだけれど、それでもペット可の物件はほとんど見たことがない。仲介業者も「ペット可物件は神出鬼没なので気長に待ってください」「猫は不可ってところが多いので犬はまだましですよ*1」というくらいなので時間がかかるかと不安だったが、突然Suumoにちょうどいい物件が湧いて出て来るという幸運に出くわし、部屋探しはあっけなく終わった。
ペット可というくらいなのでにおいが気になるかと思ったが、きれいに清掃されているのか、全く気にならなかった。他の犬の吠えも聞こえないので、防音もちゃんとしているようだ。
犬を迎える前準備
犬用のトイレスペースと食事用深皿を用意した。トイレスペースと食事用深皿の下にアクリルマットを引いておき、事件が起こってもリカバリー可なようにした。また、絨毯は撤去した。フローリングは拭き取れるが、絨毯は洗濯になってしまって面倒だ。
家具に加えて、犬を連れてくるために犬が入れるリュックを買った。背面以外は一部網になっており、中を覗くことができる。犬も暗がりでは怖かろうということなのか、はたまた犬を覗けないと人間が不安になるのかはわからなかった。おそらく両方だろう。 果たしてこんなリュックにおとなしく入ってくれるだろうか?吠えて暴れたらどうすればいい?何かの拍子に逃げ出さないか?不安に思うことはいくつかあるが、一旦置いておくことにした。
犬を連れて帰ってくる
リュックに入れる際も入った後も期待通りの大暴れだった。しかし化学繊維の前には野生は無力であった。
大暴れよりも、さらには悲しげな声で鳴きだすのには困った。ワンワン、ではなく、キューンキューンと鳴いていた。これが本当に悲しさを訴えてくるので、電車の中で思わず何度も出してやろうかと思ったが、そんなことをすると事態は悪化することが明確だったので、つらい気持ちで耐えた。お互いつらい。20分くらいすると諦めたのかおとなしくなった。犬にも無力感というものがあるのだろう。もしくは単に疲れただけなのかもしれない。
トイプードルということもあってか、中身に気づくとみんな視線が釘付けになっていた。概して表情が緩かったので、かわいさでうるささを中和しきった感があった。
なお、トイプードルに限らず動物を電車にのせるときは特別に切符を買う必要がある。犬は物として扱われるのだ。
駅からうちまでの帰り道、おとなしくなった犬をリュックに入れて歩くと、いつもとずいぶん違って見えた。歩くときの振動がともかく大きく感じるのだ。犬は相変わらずおとなしいので、それだけが救いである。
うちについてから
ベッドルームを封印してからリュックから出した。体を振るわせたあと、においを嗅ぎまわっていた。いかにも犬である。かわいいトイプードルでも犬であることには変わりない。緊張しているのか、用意したごはんは食べなかった。ひとしきり嗅ぎ回ったあと、普段使っているはずの座布団を後目に僕の座布団の上で寝転がった。新飼い主からのプレゼントということにしておこう。幸いにも座布団は3枚ある。
もともと躾ができているだけあって、トイレは特に問題なかった。命中率は改善の余地があるが、どうすればいいのかはよくわからなかった。ともかく、トイレがきちんとできてしまえば、僕としては満足である。この分だと絨毯は出せないにしても、日常生活に支障はなさそうだ。
その2に続く
*1:壁とかひっかくし資産価値が下がりやすいかららしい
2048p
サマリ
- 2048をgolangで書いてみた
- せっかくなので新ルールも追加してみた
はじめに
2048とは一昔前に流行ったパズルゲームで、さっと検索かけてみればいくらでもクローンがひっかかるような人気のゲームである。Wikipedia)を見るとなかなか業が深い感じがあるが、それはさておきこれは楽しいゲームで、やっていると時間を忘れてしまう。パズルゲームのご多分にもれず、ルールが大変にシンプルであり、手を動かす練習に適しているというわけ。そこで、golangの勉強も兼ねて作ってみた。特に立派なGUIなどはなく、もくもくとCUIで動くような殺風景な感じのものになった。
2048pと2048の違い
2048pは基本は2048と同じものだが、Pタイルがあるという点で違っている。 Pタイルは数値のタイルとは違い、マージすると隣接マス上のタイルの数値を倍にしてくれて消滅するという便利なタイルである。ただし、そんなに頻繁に生成されないので、結構邪魔。
成果物
https://github.com/bisco/2048p-go
バイナリはここからどうぞ。Windows版バイナリも簡単に作れるあたりgolangは偉大ですね。
おわりに
※この記事はまたまた!ぴょこりんクラスタ Advent Calendar 2017のために書かれたものです
SystemTapのprobeにおける"!"とは何か?
SystemTapのtapsetのソースコードを読んでいると、以下のような記述が出てくる。
# systemtap/tapset/linux/x86_64/sysc_mmap.stp probe syscall.mmap = dw_syscall.mmap !, nd_syscall.mmap ? {}
このびっくりマークというかexclamation markは、"probe pointが見つかったらそこで評価しろ"の意味。 IBMのRedbook(http://www.redbooks.ibm.com/redpapers/pdfs/redp4469.pdf)にわかりやすい例が載っていたので、引用しておく。
# SystemTap: Instrumenting the Linux Kernel for Analyzing Performance and Functional Problems # P16より kernel.function(“this_might_exist”) !, kernel.function(“if_not_then_this_should”) !, kernel.function(“if_all_else_fails”) { ... }
この例では、kernel.function(“this_might_exits”)があれば、そこで{…}を評価する。 なければ、kernel.function(“if_not_then_this_should”)を探し、存在すれば{…}を評価する。 どちらもなければ、kernel.function(“if_all_else_fails”)を探す。
この例、SystemTap開発元のLanguage Referenceに載っていないのでつらい。
Systemtapを使ってKernelのWarningメッセージを止めた(かったがダメだった)
サマリ
- オンボードのUSB3.0コントローラとUSB ICカードリーダの相性が悪いのか、使っているとWarningが出続けてつらい
- Systemtapを使って抑止しようとしたが、一部止めきれず。何が悪いのかは不明。
- 試したスクリプトは以下。
はじめに
うちのICカードリーダ*1とルネサス製と思しきUSB3.0コントローラ *2 の相性が悪く、使っていると以下のようなメッセージが2秒おきに出続ける。
xhci_hcd 0000:03:00.0: WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk? xhci_hcd 0000:03:00.0: WARN Event TRB for slot 1 ep 8 with no TDs queued?
前者は、ソースコードをみた感じだと、前者はデータ転送に成功しているけど、 期待したよりも転送長が長くないときに出るもののようだ。
// drivers/usb/host/xhci-ring.c 2300 static int handle_tx_event(struct xhci_hcd *xhci, 2301 struct xhci_transfer_event *event) <snipped...> 2373 switch (trb_comp_code) { 2374 /* Skip codes that require special handling depending on 2375 * transfer type 2376 */ 2377 case COMP_SUCCESS: 2378 if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) 2379 break; 2380 if (xhci->quirks & XHCI_TRUST_TX_LENGTH) 2381 trb_comp_code = COMP_SHORT_TX; 2382 else 2383 xhci_warn_ratelimited(xhci, 2384 "WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk?\n"); ★これ
後者はというと、2483行目と2484行目にひっかかっているらしい。 リストが空っぽなのにSTOPじゃないのがダメとか、そういう感じなんだろうか。
// drivers/usb/host/xhci-ring.c 2477 if (list_empty(&ep_ring->td_list)) { 2478 /* 2479 * A stopped endpoint may generate an extra completion 2480 * event if the device was suspended. Don't print 2481 * warnings. 2482 */ 2483 if (!(trb_comp_code == COMP_STOP || 2484 trb_comp_code == COMP_STOP_INVAL)) { 2485 xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", 2486 TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), 2487 ep_index); 2488 xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", 2489 (le32_to_cpu(event->flags) & 2490 TRB_TYPE_BITMASK)>>10); 2491 xhci_print_trb_offsets(xhci, (union xhci_trb *) event); 2492 }
出続けたから何だというわけでもないが、dmesgが埋め尽くされるのはなんとなく嫌なので*3、 これをKernelを改変せずに抑止したい。どうすればよいか?今回は、Systemtapを使ってみる。
実行環境
MOCHI /home/bisco% uname -r 4.4.0-78-generic MOCHI /home/bisco% cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=16.04 DISTRIB_CODENAME=xenial DISTRIB_DESCRIPTION="Ubuntu 16.04.2 LTS"
Systemtapとは何か
具体的にはここ。 ざっくり言うと、動作中のKernelやユーザプロセスに対し、動的に情報を取ったりメモリを書き換えたりできるツール*4。
Systemtapのインストール
今回はKernelをいじるので、Systemtapバイナリに加えてKernelのデバッグ情報をインストールする。 全部まとめてここに書いてあることに従えばよい。
ソースコードの取得
Systemtapで変数を書き換える行を特定するためにソースコードを取得する必要がある。 ソースコードもaptで取得できる。
$ sudo vim /etc/apt/sources.list # deb-srcから始まる行のコメントを外す $ sudo apt update $ sudo apt source linux-image-$(uname -r) # カレントディレクトリにソースコードをダウンロードする
書き換え箇所の特定
needs XHCI_TRUST_TX_LENGTH quirk?
に関しては、以下の2ステップ。
- 2380行目で
xhci->quirks
にXHCI_TRUST_TX_LENGTH
bitを立てる - 2477行目でtrb_comp_codeをCOMP_SUCCESSに戻す
Systemtapは、tapした行が実行される前に効果を発揮するようなので、 2381行目で変数を書き換えても期待した結果が得られない。
// drivers/usb/host/xhci-ring.c(再掲) 2300 static int handle_tx_event(struct xhci_hcd *xhci, 2301 struct xhci_transfer_event *event) <snipped...> 2373 switch (trb_comp_code) { 2374 /* Skip codes that require special handling depending on 2375 * transfer type 2376 */ 2377 case COMP_SUCCESS: 2378 if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) 2379 break; 2380 if (xhci->quirks & XHCI_TRUST_TX_LENGTH) ★ここ 2381 trb_comp_code = COMP_SHORT_TX; 2382 else 2383 xhci_warn_ratelimited(xhci, 2384 "WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk?\n"); <snipped...> 2463 default: 2464 if (xhci_is_vendor_info_code(xhci, trb_comp_code)) { 2465 status = 0; 2466 break; 2467 } 2468 xhci_warn(xhci, "ERROR Unknown event condition %u, HC probably busted\n", 2469 trb_comp_code); 2470 goto cleanup; 2471 } 2472 2473 do { 2474 /* This TRB should be in the TD at the head of this ring's 2475 * TD list. 2476 */ 2477 if (list_empty(&ep_ring->td_list)) { ★ここ
with no TDs queued?
に関しては、以下の2ステップ。
- 2477行目の条件がTRUEなら、trb_comp_codeをCOMP_STOPに書き換える
- 2493行目でtrb_comp_codeを戻す
ここでは2483行目でtrb_comp_codeを書き換えたいんだけど、 2483行目からはtrb_comp_codeにアクセスできないので、しょうがなくこうする。
2473 do { 2474 /* This TRB should be in the TD at the head of this ring's 2475 * TD list. 2476 */ 2477 if (list_empty(&ep_ring->td_list)) { 2478 /* 2479 * A stopped endpoint may generate an extra completion 2480 * event if the device was suspended. Don't print 2481 * warnings. 2482 */ 2483 if (!(trb_comp_code == COMP_STOP || 2484 trb_comp_code == COMP_STOP_INVAL)) { 2485 xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", 2486 TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), 2487 ep_index); 2488 xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", 2489 (le32_to_cpu(event->flags) & 2490 TRB_TYPE_BITMASK)>>10); 2491 xhci_print_trb_offsets(xhci, (union xhci_trb *) event); 2492 } 2493 if (ep->skip) { 2494 ep->skip = false; 2495 xhci_dbg(xhci, "td_list is empty while skip " 2496 "flag set. Clear skip flag.\n"); 2497 }
ちなみに、アクセスできる/できない変数は、-L
オプションで調べることができる。
アクセスできる変数は$xxxx
と表示されるんだけど、2483行目にはtrb_comp_codeがない。
$ stap -L 'kernel.statement("handle_tx_event@drivers/usb/host/xhci-ring.c:*")' | grep 248 kernel.statement("handle_tx_event@/build/linux-0XAgc4/linux-4.4.0/drivers/usb/host/xhci-ring.c:2483") $xhci:struct xhci_hcd* $event:struct xhci_transfer_event* $xdev:struct xhci_virt_device* $ep_ring:struct xhci_ring* $event_trb:union xhci_trb* $status:int $td_num:int $__func__:char const[] const kernel.statement("handle_tx_event@/build/linux-0XAgc4/linux-4.4.0/drivers/usb/host/xhci-ring.c:2485") $xhci:struct xhci_hcd* $event:struct xhci_transfer_event* $xdev:struct xhci_virt_device* $ep_ring:struct xhci_ring* $event_trb:union xhci_trb* $status:int $trb_comp_code:u32 $td_num:int $__func__:char const[] const kernel.statement("handle_tx_event@/build/linux-0XAgc4/linux-4.4.0/drivers/usb/host/xhci-ring.c:2488") $descriptor:struct _ddebug $xhci:struct xhci_hcd* $event:struct xhci_transfer_event* $xdev:struct xhci_virt_device* $ep_ring:struct xhci_ring* $status:int $__func__:char const[] const
Systemtapスクリプト
上記の変更をSystemtapスクリプトにすると、こうなる。
kernel.statement(<PATH>)
で、ソースコードの位置を指定する。<PATH>
のフォーマットは関数名@ファイルへのパス(ビルドしたときのルートディレクトリからの相対パスでよい)
。- $xxxxでKernel内の変数アクセス。構造体メンバへのアクセスは
->
を使う。 - グローバル変数は
global
をつけて宣言すると使える
このスクリプトを-g
オプションを付けて実行する。
-g
オプションを渡すと、guruモードと呼ばれている変数を書き換えられるモードにしてくれる。
$ sudo stap -gv usb.stp
結果
quirks?
のほうは抑止できたけど、with no TDs queued?
はなぜか抑止できなかった。うーん、原因がわからん。
その他
Systemtapスクリプトの実行をCtrl-C止めても、quirks?
のメッセージが出なくなった。何か残ってるのか・・・?
[2017/05/22 23:11追記]
このコードに対して
2473 do { 2474 /* This TRB should be in the TD at the head of this ring's 2475 * TD list. 2476 */ 2477 if (list_empty(&ep_ring->td_list)) { 2478 /* 2479 * A stopped endpoint may generate an extra completion 2480 * event if the device was suspended. Don't print 2481 * warnings. 2482 */ 2483 if (!(trb_comp_code == COMP_STOP || 2484 trb_comp_code == COMP_STOP_INVAL)) { 2485 xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", 2486 TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), 2487 ep_index); 2488 xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", 2489 (le32_to_cpu(event->flags) & 2490 TRB_TYPE_BITMASK)>>10); 2491 xhci_print_trb_offsets(xhci, (union xhci_trb *) event); 2492 }
このtap
probe begin { printf("force stop warning short TX\n") } probe end { printf("stop probe\n") } probe kernel.statement("handle_tx_event@drivers/usb/host/xhci-ring.c:2477") { next_addr = @cast(&$ep_ring->td_list, "list_head", "kernel")->next list_addr = &$ep_ring->td_list if(next_addr == list_addr) { $trb_comp_code = 26 printf(">> trb_comp_code = %d\n", $trb_comp_code) } } probe kernel.statement("handle_tx_event@drivers/usb/host/xhci-ring.c:2485") { printf("trb_comp_code = %d\n", $trb_comp_code) }
結果がこれ
Pass 1: parsed user script and 110 library script(s) using 109624virt/43860res/6236shr/37692data kb, in 320usr/40sys/359real ms. Pass 2: analyzed script: 4 probe(s), 4 function(s), 0 embed(s), 0 global(s) using 302812virt/236012res/7292shr/230880data kb, in 3640usr/130sys/3774real ms. Pass 3: translated to C into "/tmp/stapdRn9iB/stap_072980ba0aa3ed0cb26e4f8ce5aa1922_3963_src.c" using 302812virt/236140res/7420shr/230880data kb, in 10usr/10sys/12real ms. Pass 4: compiled C into "stap_072980ba0aa3ed0cb26e4f8ce5aa1922_3963.ko" in 3850usr/440sys/4690real ms. Pass 5: starting run. force stop warning short TX >> trb_comp_code = 26 trb_comp_code = 26 >> trb_comp_code = 26 trb_comp_code = 26 >> trb_comp_code = 26 trb_comp_code = 26 >> trb_comp_code = 26 trb_comp_code = 26
COMP_STOP = 26
という事実からすると、systemtapがおかしいようにも思うし、
自分の理解が間違っているのではという感もあり、よくわからなくなった。
C用Makefileのテンプレートと覚書
サマリ
たまに使うときに毎回調べなくてもよいようにC用Makefileのテンプレートを作った。
はじめに
Cでプログラムを書くときに、Makefileを書こうとして毎回書き方を探し回っている間抜けの極みなんですが、 だいたい書く内容は変わらないので、テンプレを作って使いまわせるようにしておきたくなった。
このテンプレがカバーしない範囲
テンプレ
覚書
GNU Makeにおける関数コール
$(<関数名> <引数>)
みたいに書くと関数をコールできる。
使っているGNU Makeの関数
Makeにはいくつかビルトインの便利関数がある。カンマ前後はスペースを入れないように。
realpath
:指定されたディレクトリの単一絶対パス(canonical absolute path)を取得する。 canonicalというのは、.
、..
、symlinkを含まないpathのこと。abspath
と違ってsymlinkを解決するという違いがあるけども、 この違いがMakefileに及ぼす影響はよくわからない・・・wildcard
:wildcardで指定したパターンに該当するものをスペース区切りで出力してくれる関数。 ファイルパスを渡すと、指定したパターンに該当するファイルを出力してくれる。subst
:$(subst <from>,<to>,<置き換え対象文字列(空白区切り)>)
というように、<置き換え対象文字列>内の全てのを へ置き換えてくれるもの。 patsubst
:$(<変数名>:<置き換え前suffix>=<置き換え後suffix>)
という形式で使っている。指定したパターンを残して置き換えをしてくれる。filter-out
:あるパターンに一致するものを除外する。$(filter-out <除外したいパターン>,<空白区切り文字列>)
とすると、 除外パターンに完全一致する文字列を除外して文字列を返してくれる。
Phonyターゲット
make clean
みたいに、何もファイルを作らないがコマンドを実行したいときに指定しておくターゲット。
テンプレでは、default
、conf
、clean
の3つのPhonyターゲットを指定している。
default
:Makeを引数無しで実行すると実行されるもの。Makefileの変数を出力して、バイナリを作ってくれるようにしている。conf
:Makefileの変数を出力するターゲット。clean
:おなじみのやつ。オブジェクトファイルと実行ファイルを消すターゲット。
パターンマッチルール
Makefileにおける以下の部分のこと。%
はワイルドカードで、$(OBJDIR)
以下の*.o
ファイルは、
$(SRCDIR)/*.c
から作られますよということをMakeに教えてあげるのがパターンマッチルール。
$(OBJDIR)/%.o : $(SRCDIR)/%.c
変数のメモ
SRCDIR
:ソースファイルを格納するディレクトリ。テンプレではMakefileと同じディレクトリ。 Makefileの置いてあるディレクトリは毎回変わるけども、realpath関数でカレントディレクトリを取得するようにしている。INCDIR
:ヘッダファイルを格納するディレクトリ。テンプレではSRCDIR
と同じ。OBJDIR
:オブジェクトファイルを格納するディレクトリ。テンプレではOBJDIR
と同じ。IGNORE
:コンパイル時に無視してほしいファイルを指定する。SRCDIR
がフルパスなので、IGNORE
もテンプレみたいにフルパスで指定する必要がある。SRCS
:SRCDIR
内のCファイル全部。いちいち指定するのが大変なので、wildcard関数を使って、ワイルドカードで指定できるようにしている。OBJS
:オブジェクトファイル全部。patsubst関数($(SRCS:.c=.o)
の:
のこと)を使って、Cファイルの".c"部分を".o"に変えている。 オブジェクトファイル置き場が変わったときのことを考えて、subst関数によりファイルパスのSRCDIR
部分をOBJDIR
に置き換えるようにしている。
おわりに
だいたい事足りそうなMakefileが書けたと思う。 これでちょこっとCでプログラムを書くときに、長いオプションをつけてgccコマンドを打たなくてよくなると思うと少し気が楽になる。
参考
fishを使っているときにtmuxのwindow nameをコマンド履歴にしたい
サマリ
fishのfish_preexecイベントをフックして、tmuxのwindow nameをコマンド履歴に変えることができる。
はじめに
tmuxを使っていると、このwindowでは一体何をしていたんだっけという状況に陥ることがままある。 そういうとき、window nameが最後に実行したコマンドだと、何をしていたか思い出すのに役立つ*1。
そんなことができるのか
以下の2つの材料から結構簡単にできちゃう。 ちなみに、"フックをかける"というのは、イベント発生時に何かコマンドが実行できるよ、って意味。
tmux rename-window <window name>
でwindowの名前が変えられる- fishには、fish_preexecという、コマンド実行前にフックをかけられるイベントがある
どうするのか
fish_preexecイベントフックは、~/.config/fish/config.fish
に書くのが作法らしい*2。
実際にはこんな感じになる。
tmuxを使っているときは、環境変数$TERMがscreenかtmuxになるので、そのときだけwindow nameを変えるコマンドを打つ。
あんまり長いコマンドを表示してもあれなので、16文字くらいで打ち止めするようにしている。
# rename tmux window function window_rename --on-event fish_preexec if test -n (echo $TERM | grep -e screen -e tmux) tmux rename-window (printf "%.16s" $argv[1]) end end
おわりに
fish_preexecイベントのおかげで、簡単にtmuxのwindow nameを動的に変えることができる。
雑感
- fishの設定ファイルは人間に読みやすいのがよい。bashとの互換性はないけど、別にどうでもいいやという感。
- fishは手入れが楽なのでありがたい