今日のLKML: テストしてテストしてからbitを立てる

こういうpatchが投稿されている

[10/12] writeback: only allow one inflight and pending full flush - Patchwork

full flushが一度に1つまでしか走らないようにしたいね、というものなのだけど、中身は本題には関係はない

patchの中に以下のようなコードがある

+       if (test_bit(WB_start_all, &wb->state))
+               return;
+
+       set_bit(WB_start_all, &wb->state); 

 "wb->state"のWB_start_allのbitが立っていたらreturnして、立ってなかったら立てる、というもの。このWB_start_allで"full flush"の排他をしていることになる。

厳密には、これは排他になっていない。1つ目のスレッドがtest_bit()してから、set_bit()するまでの間に、2つ目のスレッドがtest_bit()でbitを見にいくことがある。その場合、2つのスレッドが同時に"critical section"に入ってしまう。

ここを厳密な排他にするには、test_and_set_bit()を使う。

linux/atomic.h at master · torvalds/linux · GitHub

もちろんそんなことはkernel developerには、わかっている。patchのコメントは以下のように書いてある

It doesn't matter if we race a little bit on this, so use the faster separate test/set bit variants. 

 もともとfull syncが2つ以上一緒に走ると重いよね、ぐらいのものなのでここで厳密な排他は必要ないのだ。

こういうatomicityが必要でない場合には、test_bit()とset_bit()とを分けた方がいい時もある。

test_and_set_bit()を使うと必ずbitを立てる、すなわち値を更新してしまう。すると、cache lineがdirtyになる。頻繁に呼ばれ、多くの場合にbitが立っているような場所では、この「cache lineを汚すかどうか」が大きな違いになってくる。

 

で、頻繁に呼ばれるところで無駄にcache lineを汚さずにtest_and_set_bitしたいな〜となると以下のようなコードを書くことになる

if (test_bit(bit, addr) || test_and_set_bit(bit, addr))
...

 スレッドはpatchの内容をすっかり離れて、こうした"idiom"のdocumentないし、それもあわせてなんか関数作っとく?という話になる。そこで関数の名前の話になり、"test_and_test_and_set_bit"がいいとか、"test_then_test_and_set_bit"がいいとか、patchの話どうしたみたいな感じになっていってる。

まあ以下のように解説があるぐらい知られている話なのだけど、関数名として見ると"test and test and set bit"ってなんかむずっとする名前だよな・・・と思った次第

Test and test-and-set - Wikipedia

systemd-networkdがオンラインにならないの

sysmtedはなんでもできるつおい子なので、ネットワークの設定もやってくれる. つおい

どうやって設定書くの? ということで、 man systemd.network すると, こんな風に使える感じのサンプルが載っている

Example 2. DHCP on ethernet links

# /etc/systemd/network/80-dhcp.network
[Match]
Name=en*

[Network]
DHCP=yes

This will enable DHCPv4 and DHCPv6 on all interfaces with names starting with "en" (i.e. ethernet interfaces).

だいたいDHCPでよろしくやるとべんりなので、これをこぴぺするわけだが、これで困ったことになったという話。ちゃんと名前を明示しないと、オンラインになるまで待つserviceがタイムアウトまで待ってしまう

NFSと自動生成サービス

systemdは/etc/fstabからそれぞれのmount pointに対応したserviceを自動的に生成する。 mountもserviceの起動という形で行われる。たとえば、以下のようなfstabを書いておく

naota:/linux /remote/linux nfs defaults,hard,intr 0 0

 すると、以下のようにservice fileが自動生成される

$ sudo systemctl cat remote-linux.mount
# /run/systemd/generator/remote-linux.mount
# Automatically generated by systemd-fstab-generator

[Unit]
SourcePath=/etc/fstab
Documentation=man:fstab(5) man:systemd-fstab-generator(8)
Before=remote-fs.target

[Mount]
Where=/remote/linux
What=naota:/linux
Type=nfs
Options=defaults,hard,intr

 この時mount先がNFSなので、ここには明示的には書いていないが、"network-online.target"への依存が自動的に付加される。すなわち, networkがオンラインになってからNFSにつなぎにいく, ということになる。

systemd-networkdでのnetwork-online.target

systemd-networdを使う場合、network-online.targetの前に、systemd-networkd-wait-online.serviceが起動される。

$ sudo systemctl cat systemd-networkd-wait-online.service
# /lib/systemd/system/systemd-networkd-wait-online.service
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.

[Unit]
Description=Wait for Network to be Configured
Documentation=man:systemd-networkd-wait-online.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
Requires=systemd-networkd.service
After=systemd-networkd.service
Before=network-online.target

[Service]
Type=oneshot
ExecStart=/lib/systemd/systemd-networkd-wait-online
RemainAfterExit=yes

[Install]
WantedBy=network-online.target

 このserviceは、"/lib/systemd/systemd-networkd-wait-online"を起動する、というもの。 このプログラム(systemd-networkd-wait-online)は、マシンのnetwork interfaceをなめて全て(loなどはのぞくが)つながるまで待つ。

具体的にどうやって「つながった」と判定されるのか見ていこう。/run/systemd/netif/links/*にinterfaceの数だけのファイルがある。たとえばloだとこんな感じ。

$ cat /run/systemd/netif/links/1
# This is private data. Do not parse.
ADMIN_STATE=unmanaged
OPER_STATE=carrier

特に管理対象じゃありません(ADMIN_STATE=unmaged)となっている。

一方でDHCPにつないでるやつだとこんな感じ。 DHCPIPアドレスをもらっていて、 ADMIN_STATE=configuredとなっている。

$ cat /run/systemd/netif/links/3
# This is private data. Do not parse.
ADMIN_STATE=configured
OPER_STATE=routable
NETWORK_FILE=/etc/systemd/network/80-dhcp.network
DNS=なんたらかんたら
NTP=なんとかかんとか
DOMAINS=
ROUTE_DOMAINS=
LLMNR=yes
MDNS=no
ADDRESSES=.....
ROUTES=.....
DHCP4_ADDRESS=.....
DHCP_LEASE=/run/systemd/netif/leases/3

 DHCP待ちなどのタイミングでは、これが"ADMIN_STATE=configuring"となっている。

結局のところ、systemd-networkd-wait-onlineはこのへんのファイルをなめて、ADMIN_STATE=configuring(やpending)の間ループするといった動きをする。

もしも、configuredにならない場合にはdefaultで120秒のタイムアウトで終了する

LANケーブルをさしてない口があるとつらい

といった状況でLANケーブルをさしていないportがあると、その口は"configuring"のままなのでsystemd-networkd-wait-onlineはタイムアウトするまで待ちつづける. 結果として、あちこち起動が遅れてめんどいなあという気持ちになる

それでどうするの?

Name=en*にしとくとdevice名見なくてもあれこれできるけど、オンライン待ちがうざいのでちゃんと名前を書こうねという話だった

 

変愚蛮怒をXft対応する話 Part1 X11における変愚蛮怒の描画コード

変愚蛮怒というRoguelikeゲームはLinuxでも動作するけれど, TrueTypeフォントが扱えなくてフォント指定がかなりだるいし, レンダリングがびみょう. 変愚蛮怒の描画をXftで行うようにした. フォントがきれいになって, お好きなフォントを使えて超ハッピー. この経験をふまえて, libX11のものをXft対応ってどうやったらいいのかを書く.

リポジトリはここ

github.com

変愚蛮怒ってなに

変愚蛮怒はMoria/Angbandから始まる*band系ローグライクゲームのバリアント(変種)の一種です。直接にはZangbandから派生しています。
鉄獄100Fに潜むラストボス『混沌のサーペント』を撃破して『*勝利*』を遂げるためには、キャラクターのレベルや装備だけでなく、*あなた*自身の習熟が求められます。

変愚蛮怒 公式WEB

まあ日本で派生したこんな感じなローグライクゲームで, 日本で派生しているので斬鉄剣持ったサムライっぽい人とか, 光の剣をはなつ不老不死にして史上最強のエスパーとか, 石仮面を持った吸血鬼とか出てくる. 主人公の方も剣術家になって天翔龍閃したり, 鏡使いになってラフノールの鏡したりできる.

https://pbs.twimg.com/media/DBjx6C6VoAA231H.jpg:large

最近だと東方成分の入ったバリアントもあるみたい. 当方東方ネタはあんまわからんのだけど, わかる人はよさそう.

www65.atwiki.jp

Linuxにおける変愚蛮怒

変愚蛮怒Linuxでも動いてとてもサイコー. ただコードが昔に書かれたものであるため, 現状とあわない点が様々ある

  • 内部コードがEUC (これは簡単に文字幅とか計算するのにはしかたなかったり)
    • 表示もこの前までEUCでしようとしていたがpatchが当たった: チケット #25917: UTF-8サポート - 変愚蛮怒 - OSDN
      • これもまだ, UTF-8読んでEUCにして, またUTF-8に戻して表示しててなんかアレなんだけどまあ既存ルーチンいじらないといけないしな〜
      • あと, UTF-8のCファイルをgcc-wrapというスクリプトで, EUCにconvertしてからcompileしていてまたむずかしい. atomicではないからCtrl-cするとめっちゃdiffが出たりする
  • TrueTypeフォントがうまくあつかえない
    • フォント指定には昔ながらの, XLFD (-*-*-medium-r-normal--24-*-*-*-*-*-iso8859-1ってやつ)を使う
      • めちゃ複雑わからん
    • mkfontdir, mkfontscaleなど使うとTTFも使えるらしい?んだけどうまく動かんわ
      • 昔動いてたんだけど…もうきえた?
    • bitmapフォントは…見た目やっぱアレ

現在のX11用描画コード

ということで, 変愚蛮怒をXftというTrueTypeフォントを扱えるライブラリで描画するように書き変えよう, という話.

今回は現在の描画コードについて整理する.

変愚蛮怒WindowsやらX11やらCursesやら様々な環境に対応できるように, 描画対象をTermと抽象化している. 各環境では以下のhookを実装して, 描画を行う.

いろいろhookはあるけれど, 主に仕事をするのはtext_hookになる. X11での実装は以下の通り:

(x, y)の位置に, 属性番号aで, nバイト長の文字列sを描画します, ということですね. Infoclr_set(clr[a]);で描画色を設定して, Infofnt_text_std(x, y, s, n);でテキスト描画している感じ. ここの(x, y)は文字単位での座標. ピクセル単位での座標へはInfofnt_text_std()内で変換する.

Infofnt_text_std()は以下のあたりから. ifdefとかが多いので抜粋する.

https://github.com/naota/hengband/blob/master/src/main-x11.c#L1605

static errr Infofnt_text_std(int x, int y, cptr str, int len)
{
    /*** Decide where to place the string, vertically ***/

    /* Ignore Vertical Justifications */
    y = (y * Infofnt->hgt) + Infofnt->asc + Infowin->oy;

    /*** Decide where to place the string, horizontally ***/

    /* Line up with x at left edge of column 'x' */
    x = (x * Infofnt->wid) + Infowin->ox;

    /*** Actually draw 'str' onto the infowin ***/
...
    /*** Handle the fake mono we can enforce on fonts ***/

    /* Monotize the font */
    if (Infofnt->mono)
...
    /* Assume monoospaced font */
    else
    {
...
        XmbDrawImageString(Metadpy->dpy, Infowin->win, Infofnt->info, Infoclr->gc, x, y, kanji, kp-kanji);
        free(kanji);
    }

    /* Success */
    return (0);
}

まず, 引数の文字単位の座標である(x, y)ピクセル単位に変換して, 描画位置を決める. フォントの高さ, 幅はどのフォントでも一定(monospaceフォント)と仮定しているので, 基本的にはx, yにそれぞれフォントの幅とフォントの高さを掛ければよい. これに描画の開始座標の(Infowin->ox, Infowin->oy)を足す. また, Y座標にはフォントのアセント(フォントのベースラインから上端までの高さ)Infofnt->ascを足す. これで, (x * フォントの幅 + ox, y * フォントの高さ + oy)ピクセルに文字の左上が当たるように描画されることになる.

あとはkanjiUTF-8が入っているので, そいつをXmbDrawImageString()で描画する. XサーバがMetadpy->dpy(XのDISPLAYのやつ)で, 描画先がInfowin->winになる. フォントがInfofnt->infoで指定され, 色がInfoclr->gcで指定される.

Xft化することを考えると, Infowin, Infofnt, Infoclrの初期化とかを見ておくとべんりそう.

(しかし, #define DPY (Metadpy->dpy)とかしてるのに全然使ってなくてあんまりコードの治安はよくない)

ウィンドウの管理: Infowin

struct infowin Infowinは以下のような変数. ウィンドウの管理をする.

struct infowin
{
    Window win;
#ifdef USE_XIM
    XIC xic;
    long xic_mask;
#endif
...
};

InfowinのデータはInfowin_prepare()で初期化されている.

Xft化する時に, ウィンドウ関係でなにか追加でほしい時は, 上の構造体に変数増やして, Infowin_prepare()で初期化したらいいかな, という感じ.

フォントの管理: Infofnt

struct infofnt Infofntは以下のような変数. フォントの管理をする.

struct infofnt
{
    XFontSet info;

    cptr name;

    s16b wid;
    s16b twid;
    s16b hgt;
    s16b asc;
...
};

ここに, フォント, その幅・高さ・アセントなどが保持されている. 初期化はInfofnt_prepare()で行う.

static errr Infofnt_prepare(XFontSet info)
{
    infofnt *ifnt = Infofnt;

    XCharStruct *cs;
    XFontStruct **fontinfo;
    char **fontname;
    int n_fonts;
    int ascent, descent, width;

    /* Assign the struct */
    ifnt->info = info;

    n_fonts = XFontsOfFontSet(info, &fontinfo, &fontname);

    ascent = descent = width = 0;
    while(n_fonts-- > 0){
        cs = &((*fontinfo)->max_bounds);
        if(ascent < (*fontinfo)->ascent) ascent = (*fontinfo)->ascent;
        if(descent < (*fontinfo)->descent) descent = (*fontinfo)->descent;
        if(((*fontinfo)->max_byte1) > 0){
            /* 多バイト文字の場合は幅半分(端数切り上げ)で評価する */
            if(width < (cs->width+1)/2) width = (cs->width+1)/2;
        }else{
            if(width < cs->width) width = cs->width;
        }
        fontinfo++;
        fontname++;
    }
    ifnt->asc = ascent;
    ifnt->hgt = ascent + descent;
    ifnt->wid = width;
...
    /* Success */
    return (0);
}

XFontsOfFontSet()でフォント一覧をとってきて, そのリストをなめて, 最大のアセント・デセントを求める. 幅は多バイト文字なら, フォント幅の半分と計算していて, 多バイト文字の幅が単一バイト文字の幅の2倍と仮定しているとわかる.

Xftでも, このへんでアセントとかを計算したらいいね, ということになる.

色の管理: Infoclr

Infoclrは以下の通り. GCがXlibのグラフィックコンテキストで, 描画色・背景色などを保持してくれる. ついでに, fg, bgでも描画色・背景色を保持しているけど, べつに使っていない.

struct infoclr
{
    GC gc;

    Pixell fg;
    Pixell bg
...
};

これまでの予想に反して, Infoclrのデータの初期化はinit_x11()の中で行われている.

errr init_x11(int argc, char *argv[])
{
...
    /* Prepare normal colors */
    for (i = 0; i < 256; ++i)
    {
        Pixell pixel;

        MAKE(clr[i], infoclr);

        Infoclr_set(clr[i]);

        /* Acquire Angband colors */
        color_table[i][0] = angband_color_table[i][0];
        color_table[i][1] = angband_color_table[i][1];
        color_table[i][2] = angband_color_table[i][2];
        color_table[i][3] = angband_color_table[i][3];

        /* Default to monochrome */
        pixel = ((i == 0) ? Metadpy->bg : Metadpy->fg);

        /* Handle color */
        if (Metadpy->color)
        {
            /* Create pixel */
            pixel = create_pixel(Metadpy->dpy,
                         color_table[i][1],
                         color_table[i][2],
                         color_table[i][3]);
        }

        /* Initialize the color */
        Infoclr_init_ppn(pixel, Metadpy->bg, "cpy", 0);
    }

angband_color_table[]にARGBが入っている. create_pixelPixell(X11の場合, XColorのtypedef)を作り, その色を描画色としてGCを設定する. Infoclr_set(clr[i])Infoclr = clr[i]となって, Infoclr_init_ppn()で色が設定される. 結局,のところ配列clr[]に各色でGCが格納される.

(ここで256個のGC作っているけど, 実際には8色しかない. alpha == 0xFFあたりでbreakしちゃってもいい気もする)

まとめ

Infowin, Infofnt, Infoclrがそれぞれ現在のウィンドウ・フォント・描画色を管理する.

InfowinInfowin_prepare()で, InfofntInfofnt_prepare()で, Infoclr(clr[])はinit_x11()で初期化される.

Term_text_x11()が指定位置にテキストを描画する. Infoclr_set(clr[a]);で色を変えて, Infofnt_text_std(x, y, s, n);でテキスト描画する. 実際に描画しているのは, XmbDrawImageString().

次回はXmbDrawImageString()をXftのテキスト描画関数に置き換える. それにあたって, 描画先・フォント・色の構造体が変わるので必要な処理を初期化関数に追加するなどについて書く.

Linux kernelをninjaでビルドする

ninjaってなに

Ninja, a small build system with a focus on speed

make代替みたいなビルドシステムで, 小さくてスピードが速いのが特徴となっている. Chromiumとかで使われている様子.

Makefileを読めるわけではなく, ninja用のビルドファイルが必要.

kninja

GitHub - rabinv/kninja: Ninja build file generator for the Linux kernel

kninjaはLinux kernel用にkninjaのビルドファイルを生成してくれるスクリプト.

はやいの?

kninjaによるルール生成にはkninja.pyを使う. ルール生成のためにmakeしてから, “make -p"の情報からビルドファイルを生成する. したがって, 下のようにルール生成まで入れると1分ほどkninjaの方が遅くなる.

フルビルドの場合

$ make clean
$ time make -j$(nproc)
real    4m21.090s
user    41m19.146s
sys     2m48.689s
$ make clean
$ time python3.4 ~naota/src/kninja/kninja.py
[INFO] Ensuring full build: make -j 12
…
[INFO] Generating make database: make -p
[INFO] Caching make database to .makedb
[INFO] Parsing make database (2563191 lines)
[INFO] Wrote build.ninja (3282 rules, 3255 build statements)
[INFO] Wrote .ninja_deps (2597 targets, 1144879 deps)
[INFO] Wrote .ninja_log (3282 commands)
[INFO] Checking ninja status: ninja -d explain -n
[INFO] All OK

real    5m15.829s
user    40m58.248s
sys     2m59.674s

ビルド済

$ time make -j$(nproc)
real    0m5.883s
user    0m24.015s
sys     0m9.905s
$ time python3.4 ~naota/src/kninja/kninja.py
real    1m4.807s
user    1m12.236s
sys     0m23.291s

ただ, これはルール生成をしているから遅いのであって, 一度ルールが作られてしまえばninjaの方が速い. たとえば, なんの変更もない時は以下のようにmakeだと6秒に対して, ninjaは1秒かからない. (ただこれはCHKとかCALLとかでビルドで関係ないチェックスクリプトが走っているのもあるか)

$ time make -j$(nproc)
  CHK     include/config/kernel.release
  CHK     include/generated/uapi/linux/version.h
  CHK     include/generated/utsrelease.h
  CHK     include/generated/timeconst.h
  CHK     include/generated/bounds.h
  CHK     include/generated/asm-offsets.h
  CALL    scripts/checksyscalls.sh
  CHK     include/generated/compile.h
  CHK     kernel/config_data.h
…
real    0m6.005s
user    0m24.038s
sys     0m9.827s
$ time ninja
ninja: no work to do.

real    0m0.204s
user    0m0.152s
sys     0m0.052s

1つのファイルを変更した場合は, makeで7秒, ninjaで3秒といったところ.

$ touch fs/btrfs/ctree.c; time make -j$(nproc)
…
real    0m7.129s
user    0m27.334s
sys     0m10.295s
$ touch fs/btrfs/ctree.c; time ninja
[3/3] ld -r -m elf_x86_64 -T ./scripts/module-common.lds --build-id -o fs/btrfs/btrfs.ko fs/btrfs/btrfs.o fs/btrfs/btrfs.mod.o ; true

real    0m2.922s
user    0m2.755s
sys     0m0.222s

速くはなるので, inotifywaitでいじっているファイルを監視して, ninjaを走らせるループなどしておくとべんり. (while inotifywait fs/btrfs/*.c; do ninja ;done とか)

ただ.configやKconfigやらがupdateされるたびにルールを作り直す必要があるため, 全くLinux kernelを開発しませーん, ビルドしてインストールするだけです〜という人にはいらないツールになる.

compile DBを生成する

Emacsだとirony-mode, Atomだとlinter-clangやautocomplete-clangのように, clangを使ってCのsyntax checkや補完をしてくれるパッケージがある.

これらを動かすにあたって, include pathやらdefineなどなどコンパイルオプションを適切に渡す必要がある. このへんのツールは"compile_commands.json"に書いてある, コンパイルオプションを読んでくれる.

ninjaには, このjsonファイルをdumpする機能がある. ninja -t compdbで以降の引数で指定されたルールのjsonをはきだすので下のようなコマンドを実行すると全ルールとれる.

$ ninja -t compdb $(awk '/^rule /{print $2}' build.ninja) > compile_commands.json

ironyはなんやらうまくやってくれてる感じあるけど, gccだけが対応していてclangが対応していないoptionがあるとAtomの子たちはだいたいうまく動かない. よって, こんな感じで適当にargを削ってあげるといい.

DELETE_ARGS=(
    '-falign-jumps=1'
    '-falign-loops=1'
    '-fconserve-stack'
    '-fno-delete-null-pointer-checks'
    '-fno-var-tracking-assignments'
    '-mfentry'
    '-mno-fp-ret-in-387'
    '-mpreferred-stack-boundary=3'
    '-mskip-rax-setup'
    '--param=allow-store-data-races=0'
    '-DCC_HAVE_ASM_GOTO'
    '-Wno-frame-address'
    '-Wno-unused-but-set-variable'
    '-Werror=designated-init'
)
script=""
for x in ${DELETE_ARGS[@]};do
    script="s/$x//;${script}"
done
sed -i -e "${script}" compile_commands.json

compdbを使えばheader情報とかも追加できる

GitHub - Sarcasm/compdb: The compilation database Swiss army knife

いろいろ入れてこんな感じか

gist.github.com

所感

なんだかんだEmacsのパッケージの方がCみたいな言語にはつよいね

実戦的和服術における荷物運搬法の検討

ドーモ 5月29日 呉服の日ですね. 呉服の日は24時間大バーゲンが行われたり, 和服界隈に盛り上がりがあり, 実戦的和服術者にとっては嬉しいかぎりです.

さて, 実戦的和服において荷物の運搬は大きな問題です. 一般的和服状況においては軽装を旨とし, あまりノートパソコンと本数冊を日常的には運搬しないように思います. しかしながら, 実戦的和服生活においては, 様々な場面で多様な荷物を運搬することが求められています. たとえば, ホームパーティーにワインなど持っていったり, 図書館で本を借りまくったり, 山奥にハッカソンをしにノートパソコンと参考文献のスゴクアツイホンと着替えを持っていったりしたいわけです. ところが, とかく和服で荷物というと小さな袋で財布と携帯ぐらいしか入らないやんという情報が出てきがちです. そんな小さな袋には入らない, より多くの大きな荷物を実戦的に運搬するにはどうしたらいいでしょうか.

本稿では和服で無理なく荷物を運搬する方法について, 和服そのもの, ショルダーバッグ, ミニバッグ, 風呂敷, リュックを検討する.

要求

まず, 自分がどのような荷物を運搬したいのかを整理する. 状況によって持ち運びたいもの・量は異なるが大きく分けて以下のようになる.

  • いつも
  • 日常
    • A4ノートパソコンを運びたい
    • 文庫本を2〜4冊+大きな本を1冊を運びたい
  • 図書館
    • 最大本を5冊ほど運びたい
    • A4ノートパソコンと, 本を6冊と, 着替えを運びたい
    • たまには無段階調整式竹馬(GO GO STICK TAKEUMA SW-12)やペンギンマスクを運びたい

山に行くのはあまりないし, 竹馬を運ぶことはもっとないので基本的に日常に向けて検討していく.

また, 財布やタブレット, 文庫本については低レイテンシでアクセスしたい.

基本装備

  • たもと・ふところ・帯のすきま
  • メリット
    • 追加装備なしでいつでも使える
    • 低レイテンシ
    • 改札でマジックができる
  • デメリット
    • 小物しか入らない
    • 着崩れの原因となる
    • 見た目が悪化する
    • 落下の危険もある
    • どこに入れたかわからなくなりやすい (個人の感想です)

まず基本装備である和服そのものの荷物運搬性能について見ていく.

洋服と違い, 一般的に和服にはポケットが実装されていない. そのため, 和服本体の運搬性能は低いと思われがちである.

しかし, 和服には「たもと」「ふところ」「帯のすきま」と3つの荷物保持空間がある. 「たもと」は袖の下の袋状の空間で, 男性着物の場合はここに穴がないので安心安全な荷物保持空間として使用できる. 「ふところ」はお腹のところの空間で, 落語などでてぬぐいが出てくる部分である. 「帯のすきま」は帯と帯, または帯と着物の間の空間である. たもとにはそれなりの大きさのものを入れることができる. ふところには, 薄手のものを入れることができる. 帯のすきまにはスマホや扇子を挿すことができる.

また, デニム着物など一部環境では, ポケットが実装されておりスマホぐらいは入ったりする.

和服本体に実装されているため, 追加装備コストがかからず, 低レイテンシでアクセスできるというメリットがある.

また, たもとに交通IC系アイテムを入れておくと, 袖でさっと改札を一なでするだけで改札を通れてかっこいいみたいな時もある. (個人の感想です)

その一方で, 多くの物を入れてしまうと着崩れを招く, 見た目が悪化するといったデメリットがある. たとえば, たもとに重いものを入れると袖の感じが変になるし, 場合によってはうっかり袖ラリアットしてしまう. ふところにふくらみのあるものを入れると, 帯まわりの着付けが乱れるし, おなかがぽっこりしてくる. 帯のすきまにはそもそも多くの物は入らない.

また, ふところや帯には落下の危険もある. たとえば, 帯にスマホをはさんでおくと, ふとした拍子にゆるんでスマホが飛んでいく. ふところについても, 帯を直したりなどしたタイミングでスマホがすべりおちやすい.

また, あまり体に影響がかからないものが多いからか, あちこち使っていると場所を見失うこともある. たとえば, 筆者はスマホなくしたーーーーーー!!!!ておくれ〜〜と思って, いざタブレットからスマホ探索するとお腹からアラームがしてきたこともある.

いつものショルダーバッグ

  • メリット
    • いつも通りの使い勝手
    • 全てのものに低レイテンシでアクセスできる
  • デメリット
    • 和服と見た目があわない
    • 相性によっては着物にダメージ
    • 最近肩がつらい

特にこだわらずに, 洋服時と同じバッグを使用するという装備である. 親しんだ使い勝手で, 低レイテンシで(バッグに入るなら)全てのものにアクセスできる.

しかしながら, その見た目が和服と合わなくて変だと数多く指摘される. また, 鞄と着物双方の素材によっては, 着物にダメージが蓄積され, 着物はすりきれほどけとびねじりちぎれ爆発四散サヨナラ!することもある (ニンジャの感想です). 筆者の環境でも, (中古品だけど)羽織がすりきれダメになったことがある.

また, 本を複数冊運ぶにおいて片方の肩に負担のかかるショルダーバッグはそろそろつらい, てか靴底めちゃ片方に傾いてすりきれとるやんけやっべえという問題もある.

帆布バッグ

  • メリット
    • 和服と見た目があう
    • いつも通りの使い勝手
    • 全てのものに低レイテンシでアクセスできる
  • デメリット
    • 大きいやつが少ない
      • ノートパソコン入れてぎりぎり
    • 肩はやっぱりつらいよ

ショルダーバッグの見た目とダメージの問題を解決するため, 帆布バッグを導入した. 帆布バッグは, 見た感じ和風でありつつ, 丈夫で既存ショルダーバッグとほぼ同様の性能で荷物を運搬できる.

しかし, 帆布バッグは入手個所が限られ, したがってサイズなど完全にしっくりくるものは見つけづらいという難点があった. 実際, 使用中の帆布バッグは既存ショルダーバッグより若干小さく, ノートパソコンの出し入れがちょっとめんどい, 本があまり入らないという問題がある.

また, 力学的に同じ特性を持つため, 肩はやっぱりつらい.

エストポーチ類を用いたハイブリッドシステム

重い物を持つには, たとえばリュックのように両肩・背中を活用することが大切である. しかし, リュックには背負う・下ろすといった動作が必要であり, アイテムへのアクセスレイテンシが悪化する.

ここで低レイテンシでアクセスしたいものは, スマホタブレット・財布や文庫本などの小物に限られていることに注目する. ウエストポーチ類によって小物を保持し, 大きなものは別途背負い, 機動的読書やスマホを確保しつつ, 体にやさしいハイブリッドシステムを実現する.

エストポーチ類は実は, 実戦的和服と相性がよい. 和服を着るにあたって, 帯をしめるが, この幅はそれなりに広くウエストポーチ類のベルトを自然に隠すことができる.

筆者環境では, 小さいショルダーバッグのベルトを短くして腰のまわりにフィットさせる実装をとっている. この中には鍵・財布・タブレットスマホ・文庫本3冊を保持できる.

以下では, ハイブリッドシステムにおいて, ウエストポーチ類の双対をなす背負う形式の荷物運搬方法を検討する.

汎用変形古典的荷物運搬用具風呂敷

  • メリット
    • 様々なサイズに対応
    • たためばめっちゃコンパクト
  • デメリット
    • 首がしまる
    • IOレイテンシが高い
    • 背負うと暑い

風呂敷は古来使われている荷物運搬方法である. 様々なサイズがあり, 多様な梱包方法があるので, 手に持つ・身体にまきつける・背負うなど多くの保持方法をサポートしている. また, たためばコンパクトに収納できるため, スケールアップ・スケールダウンが極めて容易である.

風呂敷で多くの荷物を運搬するのに関してはいくつか先行研究がある.

これらを参考として, 現在「お使い包み」の最後の結びをゆるくして首を通したりたすきがけにして, 荷物を運搬する手段をとっている.

この方法により, 肩・背中を活用しながら多くの荷物を運搬できる. しかし, 背負い方には今後も工夫が必要である. 現在の形, 特に首を結び目に通すスタイルは手をはなすと首がしまってトイレなどで大変苦しい. より手を活用しやすい背負い方を見つけていきたい. たとえば, 四つ結びスタイルも, 背負うタイプの運搬に使えそうで, 今後の検討課題となる.

時代劇に知見を求めて

そんで, 昨日これ見たんですよ. 満島ひかり氏がえも言われぬ雰囲気を出していてサイコーだった. 最初一人だけ声の通った稟とした感じの話し方なんだけど, それが変わっていくんだよね. いや〜

それはそうとして, 古典的に大きな荷物をどうしていたのかをざっくり時代劇を参考に見てみると, 行李や風呂敷に入れて背負子を使っているなあということがわかる.

リュック

そうすると, 世の中には背負子と行李・風呂敷が合体したような形態のものリュックがあると気がつく. リュックは背負いやすく, しかも風呂敷よりもアクセスレイテンシが低い. ただし, スケールアップ・スケールダウンはできない.

ところが, 着物にリュックは合わないとか, ショルダーバッグと同様に生地が痛むといった懸念がある. 着物にリュックが合わないに関しては前述のように, 昔から行李が使われていたわけだし, 柄さえうまくやればリュックでも違和感はないと考えている. そうすると問題はうまい生地…ということで, あまり和服がいたまなさそうで和服に合いそうなリュックを発見して, どのような使い心地になるのかを今後実地検証していきたい.

これとか

しかし, 和風でリュックでそれなり大きい(A4ノートPCするっと入れ)ってむずかしい

まとめ

実戦的和服術における荷物運搬法について, 低レイテンシがほしいアイテムをウエストポーチ類に置き, 高レイテンシでもよいアイテムを背負うハイブリッドアプローチをとることを検討している. 背負う側の実装について, 現在は風呂敷を用いているが, 高いレイテンシ・保持が困難といった課題がある. 今後, 背負う側の実装について和風でやわらかい感じのリュックサックを見つけ評価していきたい.

LVMのPhysical Volumeが見つからないとどうなるか

LVMのPhysical Volumeが見つからないとどうなるか

新しくLVMのLogical Volume作ろうとしたらエラーが出て作れなかった

WARNING: Device for PV fkpfAD-HZZG-JmI0-yOTu-TnMZ-J8Ul-B7Hg6D not found or rejected by a filter.
Cannot change VG libvirt_lvm while PVs are missing.

物理デバイスが消えてる? pvsコマンドで見てみよう.

$ sudo pvs
WARNING: Device for PV fkpfAD-HZZG-JmI0-yOTu-TnMZ-J8Ul-B7Hg6D not found or rejected by a filter.
PV VG Fmt Attr PSize PFree
/dev/sdc1 libvirt_lvm lvm2 a-- 1.82t 1.82t
/dev/sdd1 libvirt_lvm lvm2 a-- 1.82t 1.82t
[unknown] libvirt_lvm lvm2 a-m 1.82t 672.11g

たしかに"/dev/sdb1"であるべきところが"[unknown]"になっている.

dmesgでIOエラーなど出てないし, fdiskでも様子が見れていることを確認して, ふと思い出してみると, この前"dd if=/dev/zero of=/dev/sde"するのを間違えて, /dev/sdbにしてあわててCtrl-Cした後に, だいたいこんな感じだっただろとfdiskでパーティションを作り直したようなことを思いだした. その時のがうまくあってなかったんだろうな.

多分, /dev/sdbと/dev/sdcは同じ型だったしfdiskで見ればアタリはつけられそう.

$ sudo fdisk -l /dev/sdb
Disk /dev/sdb: 1.8 TiB, 2000398934016 bytes, 3907029168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: D2D7EE18-BD3C-4E32-926B-D606E7056837

Device Start End Sectors Size Type
/dev/sdb1 4194304 3907028991 3902834688 1.8T Linux filesystem

sudo fdisk -l /dev/sdc
Disk /dev/sdc: 1.8 TiB, 2000398934016 bytes, 3907029168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: 3E260EEF-CEAB-4747-94DB-5E7F2296BD3F

Device Start End Sectors Size Type
/dev/sdc1 3999744 3907026943 3903027200 1.8T Linux filesystem

たしかに/dev/sdb1は"4194304"セクタからで, /dev/sdcは"3999744"セクタからで, 開始位置がずれている.

ただ, これで本当に同じ開始位置でいいのかの自信はなかった.

そこでLVMのヘッダがきっと先頭あたりにあるだろうことを期待して, 確認することを考えた. まず/dev/sdc1をダンプ

$ sudo hexdump -C /dev/sdc1|head
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200  4c 41 42 45 4c 4f 4e 45  01 00 00 00 00 00 00 00  |LABELONE........|
00000210  e9 1e eb 95 20 00 00 00  4c 56 4d 32 20 30 30 31  |.... ...LVM2 001|
00000220  67 57 68 61 65 4e 49 64  65 31 32 77 4c 44 73 79  |gWhaeNIde12wLDsy|
00000230  53 6c 41 48 58 66 6e 54  42 38 44 6f 73 34 68 57  |SlAHXfnTB8Dos4hW|
00000240  00 00 f0 46 d1 01 00 00  00 00 10 00 00 00 00 00  |...F............|
00000250  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000260  00 00 00 00 00 00 00 00  00 10 00 00 00 00 00 00  |................|
00000270  00 f0 0f 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

一方で/dev/sdb1の先頭のダンプ.

$ sudo hexdump -C /dev/sdb1|head
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
0004c490  fe a7 00 00 fe a7 00 00  fe a7 00 00 fe a7 00 00  |................|
*
0004d460  ff a7 00 00 ff a7 00 00  ff a7 00 00 ff a7 00 00  |................|
*
0004e430  40 ad 00 00 40 ad 00 00  40 ad 00 00 40 ad 00 00  |@...@...@...@...|
*
0004f400  61 ad 00 00 61 ad 00 00  61 ad 00 00 61 ad 00 00  |a...a...a...a...|
*

見たまんまext4の先頭のメタデータ(inode bitmapとかGroup Descriptorのあたり)で確かに以前よりもパーティションの開始位置が後ろにずれているっぽい.

とりあえず"LABELONE"を頼りにgrepしてみる.

sudo hexdump -C /dev/sdb|grep -C5 LABELONE
*
7a0e1b10  c6 18 00 00 c6 18 00 00  c6 18 00 00 c6 18 00 00  |................|
*
7a0e2ae0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
7a100200  4c 41 42 45 4c 4f 4e 45  01 00 00 00 00 00 00 00  |LABELONE........|
7a100210  33 c2 fa 36 20 00 00 00  4c 56 4d 32 20 30 30 31  |3..6 ...LVM2 001|
7a100220  66 6b 70 66 41 44 48 5a  5a 47 4a 6d 49 30 79 4f  |fkpfADHZZGJmI0yO|
7a100230  54 75 54 6e 4d 5a 4a 38  55 6c 42 37 48 67 36 44  |TuTnMZJ8UlB7Hg6D|
7a100240  00 00 f0 46 d1 01 00 00  00 00 10 00 00 00 00 00  |...F............|
7a100250  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

見つかった. 最初のエラーにあった"fkpfAD-HZZG-JmI0-yOTu-TnMZ-J8Ul-B7Hg6D"っぽい文字列も見える. 信頼できそう.

(0x7a100200-0x200(/dev/sdb1の"LABELONE"の位置))/512 = 3999744 ということでやっぱり/dev/sdbと同じパーティションテーブルでよかった.

あとはfdiskするだけ

$ sudo fdisk /dev/sdb

Welcome to fdisk (util-linux 2.28).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): p
Disk /dev/sdb: 1.8 TiB, 2000398934016 bytes, 3907029168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: D2D7EE18-BD3C-4E32-926B-D606E7056837

Device Start End Sectors Size Type
/dev/sdb1 4194304 3907028991 3902834688 1.8T Linux filesystem

Command (m for help): d
Selected partition 1
Partition 1 has been deleted.

Command (m for help): n
Partition number (1-128, default 1):
First sector (34-3907029134, default 2048): 3999744
Last sector, +sectors or +size{K,M,G,T,P} (3999744-3907029134, default 3907029134):

Created a new partition 1 of type 'Linux filesystem' and of size 1.8 TiB.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

最後にpvscan

$ sudo pvscan
PV /dev/sdb1 VG libvirt_lvm lvm2 [1.82 TiB / 672.11 GiB free]
PV /dev/sdc1 VG libvirt_lvm lvm2 [1.82 TiB / 1.82 TiB free]
PV /dev/sdd1 VG libvirt_lvm lvm2 [1.82 TiB / 1.82 TiB free]
Total: 3 [5.45 TiB] / in use: 3 [5.45 TiB] / in no VG: 0 [0 ]

認識された. よかった.

i3 likeなwayland compositorのswayを使ってみている

Wayland何度か試してみてまあぼちぼち動くが、いいdesktop環境にはなってないなという感じだった。そんなところへ、いま使っている普通のタイルWMなi3とcompatibleなswayというwayland上desktop環境(wayland composiotr)を見つけたので試している。いまのところ結構いい感じに使えている。

github.com

インストールして、とりあえず起動してみると、i3のconfigを読んでいるらしく、いままで通りに使える。べんりだ。

そのままでも、だいたい動くんだけど、 .i3/configから.sway/configにcopyして調整した方がいい。

ちゃんと動くの?

わりとだいたいのものが動いている。Firefoxで動画とかも見れている。i3と操作が変わらないので、悪くなった感じはあまりない。

時々、GPU hangして落ちてしまって困るけど、これはXの時でも起きてるし、そもそもkernelがRCだからそっちもあやしい。ただ、Xの時はcompositorであるcomptonが死ぬだけで、i3は大丈夫なんだけど、swayだとGPU hangしたらswayごと死んでしまう。しかたないけど。

アプリは動くの?

swayはwlcというwayland compositorを作るlibraryを使っていて、これがXWaylandを立ててXのものもWaylandに乗せて動かしてくれるっぽい。べんり

X固有のものは?

Xに依存したものとして、xrandrとかxbacklightコマンドがある。これらは当然Wayland上で動かないので置きかえる必要がある。

xrandrに対応する機能はswayのconfigで実現できている。

HDMI接続の画面だったら

output HDMI-A-1 res 1920x1080 pos 1920 0

 のように書いておくと、メイン画面の右側になる、という感じ。

configに書いてなくても、

swaymsg -t command output HDMI-A-1 res 1920x1080 pos 1920 0

 というコマンドで動的に認識できる。

画面の名前は

swaymsg -t get_outputs

で、出てくるJSONを見ればわかる。

xbacklightコマンドは使えないので、適当に/sys/class/backlightを使ってがんばる。多分、時間が経ったら画面が消えるとかも現状ない感じがする。

あとタスクトレイが現状動いていない。まあなくてもいいやってことで忘れている。

壁紙は?

これもswayのoutputコマンドで設定できる

swaymsg -t command output eDP-1 bg wallpapers/foo.jpg fit

 こんな感じ。

i3との違いは?

i3でlauncherとしてrofiを使っている。これがswayだとうまく動かない。floatしてるwindowに対して入力できない?っぽい。裏にwindowいると、入力できるのでinputの当たり判定かなんかだろうか。"-normal-window"引数つけておけば動くのでそうしてる。

Rofi

入力deviceの設定も、swayのconfigで出きる。こんな感じ。device nameは"swaymsg -t get_inputs"で

input "2:7:SynPS/2_Synaptics_TouchPad" {
  accel_profile adaptive
  natural_scroll enabled
}

ところでWaylandのよさは出てるの?

よくわからない…。結局ほとんどのものはXWayland経由になってるし、directにwaylandしゃべってるやつは多分いない。入出力まわりよくなってんのかな? 劇的な体感はないけど、まあおもしろいし動くし使ってみている。Waylandでこんな動くんだな、と思うと楽しいのは楽しい。