読者です 読者をやめる 読者になる 読者になる

テストステ論

高テス協会会長が, テストステロンに関する情報をお届けします.

(writeboost report) v2.2.4をリリースしました

およそ一ヶ月ぶりのリリースとなります.

v2.2.4の主な変更は

github.com

update_sb_record_intervalを使った場合に, resume処理のあとバグるという致命的なバグを修正しました.

github.com

リスペクトのない人を追放したIssueは, キャッシュデバイス上に空きセグメントがなくなった状況で, ユーザランドからのREQ_FLUSHの応答時間が悪化したことが原因だと考えています. 緩和にしかなりませんが, そのようなケースではライトバックを小刻みにすることによって応答時間を改善することが出来ます. この修正によって, nr_max_batched_writebackのデフォルト値を微妙な中間値ではなく最大値に振り切って設定する口実を得ました. 新しいデフォルト値では, 16MB分のデータをキャッシュデバイスからreadして, アドレス順にソートしてから一気にライトバックします. おそらく, ライトバック待ちになる状況に到達するのも緩和させることが出来ます.

今はすでにそうですが, ライトブーストに関して能動的に何かしようという気はなく, Issueが上がってきたら考えるということにしています. また, 新しいユーザを時々獲得出来ていて, 同じような質問をされることに飽きたので, https://github.com/akiradeveloper/dm-writeboost/wikiを少しずつ書いています.

非モテなので結婚はしていませんし彼女もいませんが, こうやって週末にがっつりと作業が出来るのはそのおかげであるとポジティブに考えています.

それではライトブーストv2.2.4をお楽しみください.

スクワットを考える

スクワットをしゃがんだ時,

  • バーベルから腰までの距離: Lb (back)
  • 上腿の長さ: Lf (femur)
  • 下腿の長さ: Ls (shin)

として, バーベルを背負ったまま上腿を地面と並行まで下ろした時, 上体と上腿の角度P, 膝の角度Qとして, バーベルが足の真上にあると仮定すると,

Lf = Lb cos P + Ls cos Q

が言える. 3つの長さが固定値であるとすると, PかQの一方が決まるともう片方も決定するということになる.

腰にかかるモーメントは第一項Lb cos Pに比例し, 膝にかかるモーメントは第二項Ls cos Qに比例する. 仮に, 右辺第一項と第二項が等しいことが最適だとすると, PとQは決定する. 簡単のためこれを仮定しよう. この最適な割合は, 筋力バランスなどに依ると思われるが, Lfを二分割することは, 最適からそう遠くないと考えられる. (ある長さの紐で長方形を作る時, 面積が一番大きいのは正方形であるのと同じ理由)

この場合, スクワットに適した体型というのは,

  1. Lbが長い (上腿を倒さなくて済むため)
  2. Lfが短い
  3. Lsが長い (下腿を倒さなくて済むため)

という特徴を持っていることになる.

これがスクワットの面白いところで, 白人や黒人のように, 2,3を満たす場合でも1によって悩むように出来ている. 一方で2,3はないアジア人も1は持っている.

しかし実は上の説明は若干嘘であり, 2は克服出来る. 上の説明におけるLfは, 正確には横からみた時の実効距離であり, 実際の骨の長さではない. そしてこれは, 股関節の角度を広げることによって, 短縮することが出来る.

股関節の角度(片側)をRとすると, 実効距離Lfeは, Lf sin Rとなる. 改めて整理すると, 正しい式は,

Lf cos R = Lb cos P + Ls cos Q

となる.

Rの補正がどれほど強力なものか考察しよう. Rを広げすぎることは前後のバランスを崩すことになるのと, 股関節を痛めるからあまり広げられないとして, cos RはRが30度の場合は0.86くらい. 45度の場合は0.71程度なので, 民族差を超えることが出来る程度の補正が出来る(考えてほしい. もしあなたのスネが0.86/0.71倍になったらむっちゃ長いだろ). だから現実的なRの範疇で最適なものを選択することによって, Lfのハンデは克服出来る.

だからアジア人のみなさんに言いたい. スクワットをする時は足先の角度を45度に開けと. 足先を30度にするスクワットは, 欧米人にしか出来ない. 悲しい現実を受け入れるしかない.

(writeboost report) ライトバックが切迫している時にもっと小刻みにライトバックする

adaptively change the nr_cur_batched_writeback · Issue #147 · akiradeveloper/dm-writeboost · GitHub

これ2.2.4に入れます. なので, 2.2.4の目玉は,

  1. update_sb_record_intervalに関する修正
  2. これ

の2点. 一日で終わるかなぁ・・・.

146でトランザクションが遅くなったのは, 全セグメントがライトバック待ちになってライトバックが切迫した時にREQ_FLUSHフラグのついたbioが長時間ブロックされるからだと推測している.

ライトブーストは, 空きセグメントがなくなった時, 新しくフラッシュすることが出来なくなり, ライトバックの結果空きセグメントが出来るのを待つことになる. この最悪な状況では, bioはブロックされまくる. その中にREQ_FLUSHをもったものがいた場合, 悲惨なことになる.

このような状況を回避することは出来ないし, ライトブーストはライトバックを高速化することによってなるべくこの状況に陥らない努力はしている. しかしそれでも起こりうる. 例えば, 断続的にライトするような, 明らかにキャッシュを挟むのが無駄なワークロードの場合は100%起こる.

実際に起こって気づいたのだが, このような状況下においてもライトブーストは悠長に「32個セグメントを一括でライトバックするぞーい」と寝ぼけている. それは, 空きセグメントが一杯ある場合ならば最善の戦略だと思うが, 少なくなった場合には最悪だ. そういう状況では, ライトバックのスループット低下には多少目を瞑って, 小刻みに例えば1個ずつライトバックする方が理に適っている.

そういう修正をする.

(writeboost report) リスペクトがない人はOSSから排除するしかない

Question regarding writeboost and MYSQL · Issue #146 · akiradeveloper/dm-writeboost · GitHub

最近ライトブーストを試し始めたユーザだが, 他人に対するリスペクトがないため「お前の質問には一切答えない」と言って打ち切った. 出来るだけそういうことはしたくなかったため, 過去に同様のことをした時は忠告する程度に止めていたが, 再発したため追放することとした. (Issue 141でも同様に, foolなど罵る言葉を使っていたため忠告した)

OSSでは, 会ったこともなく, それこそ本名も知らない人がコミュニケーションをとることになる. 言語は英語だが, お互いにネイティブである方が稀である. そこで大事なのは, 他人をリスペクトする気持ちだ. まじでリスペクトする必要はない. 本当にリスペクト出来ないなら去ればいいだけだし, リスペクトはしないけど関わりたいというのであればリスペクトを装う必要がある. 母国語でないことによって意思疎通がうまくいかないこともあり得るし, 国や文化が違えばどういうことを不快に思うかも分からないから, 思い切り安全側に倒したコミュニケーションをしなければいけない.

この人のように, "fool", "arrogant", "flaw"などという言葉を使ってはならない. ましてや, "admit there is a FUNDAMENTAL flaw in writeboost."などと考えを押し付けてくるから, もう追放するよりない. この人は, sysstatの読み方も知らないほどに経験不足であり, はっきりいって性能がどうとか論じるレベルにないのだが, もちろん私はそれを理由にして追放したのではなく, 議論しようともせずに一方的に考えを押し付ける脅迫的な態度自体が危険と感じて追放した. 何か事実を観測していて, それが問題だと論じられる根拠があるならば論じればいいのだ. それが出来ないからといって感情的にバカと言い出すのは幼稚だ. むしろ, ライトブーストを通じて誰かが学ぶことがあればと思っているくらいだから, 議論をすることは歓迎だ. ライトブーストをシンプルに作ってあるのは, コードを読んでLinuxカーネルのことを学ぶきっかけになれば良いと考えているからでもある.

ライトブーストには他にもユーザがいる. 彼らはライトブーストが他のソフトウェアより良いと信じているからこんなout-of-treeでしかも日本人が一人でやってるような弱小プロジェクトをサポートしてくれている. 私やソフトウェアをけなすことは, 彼らの意思もけなすことになる. 私は彼らに感謝している. 私はプロジェクトオーナーとして, 彼らを守る必要がある. だからこれ以上, リスペクトに欠ける人間を輪の中に入れておくことは出来なかった.

私自身がこのようなことを学んだのはつい最近のことだ. 私はfinchに関わっていた. Gitterで仕様についてinacceptableという言葉を使ったことでオーナーに注意され, 学んだのだ. このような強い言葉は使うべきではないし, リスペクトがあるならば使うことはない. もし本当にinacceptableならば, acceptableにするようにPRを出せばいいだけだし, rejectされるならば黙って去ればいいだけだ. PRを作る能力がないならばROMってりゃいい. 同様に, 会社についても私は過去に去る際には騒ぎすぎたと反省しているから, 今後辞める時は黙って去ろうと思っている. 失敗は実に人を成長させる.

私は過去の記事(コードのない開発者は評価出来ない - テストステ論)で, コードがない人間は技術力が評価出来ないと言ったけど, 同様にOSSを運営していたり, 海外のエンジニアと円滑にコミュニケーションを取れている人間は, 英語が出来るという以前に, 全くの赤の他人と卒なくやっていける可能性が高いと考えている. OSSをやっているエンジニアというのは, こういう点でも評価出来る.

リスペクトを装う方法として良い方法は, ネガティブな表現を使わず, 常にポジティブな表現を使うことだ. 例えば, 「こうするとダメだ」ではなく「こうした方がよくなる」と言い換える. これは実は私が新卒で入った日立製作所で学んだことでもある. 日立製作所には, 当時で言うと, 本体だけで3万, グループ全体では40万人の人がいる. 百人から成る部もあるし, 出張にいけばそこにも人がたくさんいる. そして彼らはバックグラウンドも違うし, 当然考え方もそれぞれ. 「色んな人がいる」わけだ. だから, それを前提にしてコミュニケーション方法を叩き込まれる. 会社内で他の人と一緒に働けない人に育ってもらっては困るからだ. それは, ネガティブな表現を使わずにコミュニケーションを円滑にする方法でもあるし, 誰にでも一意に読める文章の書き方でもある. 私の書く文章はとてもわかりやすいと言われることがあるが, その基礎は日立製作所で培われたと言っても過言ではない. 多くの人は, 研論をバカにするけど, 私はとても学びがあったと思っている.

本当に, OSSプロジェクトを運営すると勉強になる. オススメだ.

(writeboost report) update_sb_record_intervalを使うとバグる

github.com

ジョウピンというのは中国名だろうか. dm-writeboostを1週間ほど動作させたら, 再起動時にエラーが出たとGitterで報告してきた.

CPUが大変不安定ということなので私の第一感はそれによって何か起こったというものだったが, 実際にはただのコードのバグだったことが分かった. 彼に, wb_metaツールを使ってキャッシュデバイスを解析するように依頼し, 週末には返事が来なかったがようやく返事が返ってきた. それを以って色々と考えると, やはりコードのバグだった.

writeboostは, SSDの先頭1MB領域をsuperblockと名付け, そのうち先頭512Bをsuperblock header, 尻尾の512Bをsuperblock recordと読んでいる. headerは初期化時から永遠に固定されるものだが, recordは動的に変化し得るものとして役割が異なる.

sb recordには現在, 「一体どのIDまでライトバックしましたか」という情報が入っている. これによって, 再起動後に「すでにライトバックしたものを再度ライトバックすること」を防げる. もっとも, この情報は単なるヒントであり, もし省略された場合は, flushされたIDの先頭から「最低ここまではライトバックされたはずだ」という位置を推定する. infer_last_writeback_idにこの処理が書かれている.

static int infer_last_writeback_id(struct wb_device *wb)
{
    int r = 0;

    u64 record_id;
    struct superblock_record_device uninitialized_var(record);
    r = read_superblock_record(&record, wb);
    if (r)
        return r;

    atomic64_set(&wb->last_writeback_segment_id,
        atomic64_read(&wb->last_flushed_segment_id) > wb->nr_segments ?
        atomic64_read(&wb->last_flushed_segment_id) - wb->nr_segments : 0);

    /*
    * If last_writeback_id is recorded on the super block
    * we can eliminate unnecessary writeback for the segments that were
    * written back before.
    */
    record_id = le64_to_cpu(record.last_writeback_segment_id);
    if (record_id > atomic64_read(&wb->last_writeback_segment_id))
        atomic64_set(&wb->last_writeback_segment_id, record_id);

    return r;
}

問題は, returnの前の「もしsb recordに書かれたlast_writeback_segment_idが推定したものより新しければそれを採用する」という部分で起こる. この採用自体は良いのだが, セグメントのメモリ上の状態がライトバックされたあとの状態になってないということが問題を引き起こす. 具体的には, そのセグメントをflush用に獲得しようとした時, 「セグメントはクリーンである」という不変条件を満たせない. writeboost-test-suite上にリプロデューサは作った.

    Memory(Sector.M(128)) { backing =>
      Memory(Sector.M(32)) { caching =>
        Writeboost.sweepCaches(caching)
        Writeboost.Table(backing, caching).create { s =>
          s.bdev.write(Sector(0), DataBuffer.random(Sector.M(64).toB.toInt))
          s.dropTransient()
          s.dropCaches()
          assert(s.status.lastFlushedId === s.status.lastWritebackId)
          s.dm.message("update_sb_record_interval 1")
          Thread.sleep(5000) // wait for updating the sb record
        }
        // this should not cause kernel panic
        Writeboost.Table(backing, caching).create { s =>
        }
      }
    }

実直には, このifに入った時に, セグメントの状態をライトバックされた風に帰着させるというのが考えられるが, ミスを誘発しやすい気がするのと, ロジックの重複が気になるため, より良い方法がないか考える.

なぜ起こったかというと, update_sb_record_intervalを使っている人がいなかったからだろう. 私自身, 「当然動くだろう」と鷹をくくってたため, テストが抜けていたくらいだ. 叩いてくれるユーザには感謝したい.

バーベルプレートの知識

あなたがバーベルスクワットをしたいとする. バーベルはパワーリフティング用のものでたった20kg, これでは軽い. 話にならない. ではどうするか. プレートをつけるしかない.

プレートにはラバーコーティングされているものと, 金属製のものがある.

ラバーコーティングされているものは, ウェイトリフティングで使うことを念頭に作られたものだ. ウェイトリフティングでは, 挙上したあとにバーベルをそのまま落下させる. もちろん床は専用のプラットフォームとなっているのだが, さらに衝撃を和らげるためにラバーコーティングされている. 色は赤25kg, 青20kg, 黄15kg, 緑10kgと決まっている. この知識が共有されているから, 見るだけでそれが何キロなのか一目でわかる. これがわからないと, 主催者側がセッティングをミスった時に指摘出来ない.

金属製のものは, 持ちやすいように穴が開いているものと, そうでないものがある. 穴が開いている方が加工が難しいから当然値段は高い. しかし持ちやすいから, うっかり落として足にぶつけてしまうなどのトラブルが起きにくく, 高級なジムにはこれが導入されていることが多い. このタイプのプレートは, 色はついているものを見たことがない.

穴が開いていないタイプの金属プレートについて語る. これは, 公式用と練習用がある. 公式用はウェイトリフティングと同じ色づけがされていて, 試技重量が一目でわかるようになっている. しかし, ラバーコーティングがされていないから, その分薄い. ウェイトリフティングでは世界トップレベルでもクリーン&ジャークで扱うのは260kg程度だが, パワーリフティングでは450kg近いスクワットをする. プレートをたくさんつけるから, プレートは薄くなければいけない. もっとも, 0.01mmという薄さではないが.

公式用も練習用も, 大抵は片面がフラットで, もう片面が凹型をしている. 凹面には, 重量やメーカー名が書いてある.

さてここで問題. これらの金属プレートは, 凹面をバーベルからみて内側にするか外側にするか?

正解は内側だ. これは驚いたと思う. しかし理由がある. 凹面のふちに人差し指から小指までをかけて持ちながらバーベルに差し込むことを想定されているからだ. 実は, プレートを手元から落としてしまう一番の原因は, バーベルにつけている時に手が滑ることだ. しかし, 安心してほしい. プレートの持ち方を学んだ今, あなたがプレートを落として足の指を骨折する可能性はもうない.

ジムに行って, 他の人がプレートをどう持ち, どうつけているかを観察してみよう. 間違った持ち方をしている人は素人だ. あなたが教えてもどうせロクな説明は出来ないから, テストステ論を紹介してあげよう.

(writeboost report) 無償カスタマーサービス

github.com

やっとお客様がご納得の上IssueをCloseされた...

言ってることは完全に言いがかりで, 結局は, sysstatの見方も知らないからライトバックが継続していることすら調べられなかったとか, 単にオペミスしてたとか, 本当にくだらないことだった. 何でもハングハングと叫び, あげくライトブーストは欠陥品だ!と言い出すので, 無視してやろうかとも思ったが, 逆にここでプロジェクトオーナーとしての余裕のある冷静沈着な姿勢を見せることによって他の信頼を得ることが出来ると考えて, 耐えた.

ライトブーストのログリプレイが遅いのは, どうしようもないことだが, リブート自体めったにすることではないし, ストレージのメンテナンスは通常, 他の作業も一杯入るので, そこそこ長くかかったとしても希釈されるため, 価値を一気に損なうほどではない. もちろんデスクトップでは使いものにならないということは重々承知している. それに, ドミトリが推奨するように, シャットダウンする時には必ず全部ダーティをドロップしてしまい, 再起動時にはキャッシュを全部捨てるという運用も十分にあり得る. (メンテナンス間隔が長ければ長いほど, キャッシュヒットによる恩恵は十分に受けられるから, キャッシュは捨ててもさほど損しないという考え. デスクトップではリブート時にあらゆるものがキャッシュヒットしてほしいから受け入れられない考え方というのはもちろん分かっている) それならば, ライトブーストのログリプレイの時間はほぼゼロに出来る. (reformattingをする場合に限ってログリプレイを省略するfast pathを用意してある)

最近, clone数やvisitor数が少しずつ上がっており, 注目度が上がっていることは分かっている. それ自体は嬉しいことだが, 自力解決が不能な人がメールやIssueで質問をしてきたりする. これに労力を費やすことになる. 無視することはあまり好ましいことではない.

たぶん, wikiを作るなりして, 質問を誘導出来る素材を作ると良いと思うのだが, まとまった時間がないとちゃんとしたものは作れない. docやスライドがある現場, そこまで力を入れる気にもなれない. Frequent Q&Aは作るかもしれない

全部無償なので, 本当に辛い. でもこうやって続けていくうちに, ライトブーストをほぼ完全理解する人が増えてきて(英語ネイティブで), おれの代わりに答えてくれるようになる日がくると信じている.