tag:blogger.com,1999:blog-3212697734036899542024-03-13T22:03:07.305+09:00技術者見習いの独り言Twitter @orumin の日々の雑記やメモですoruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comBlogger253125tag:blogger.com,1999:blog-321269773403689954.post-7386698979357454222023-08-24T01:44:00.002+09:002023-08-24T01:44:44.976+09:00Gitで複数のブランチで並列して扱うべんりな方法<p>タイトルどおりのトピックです</p>
<p>Gitには便利なことに<a href="https://git-scm.com/docs/git-worktree">git-worktree(1)</a>が存在する。しかし、普通にgit-cloneしてきたレポジトリの中でgit-worktreeで他のブランチをチェックアウトしてくると、当然だがgitとしてはそのチェックアウトしてきた別のブランチのあるディレクトリがまるっとuntracking filesに出てきて、大変ジャマなことこの上ない、という欠点があるのである……</p>
<h2>解決方法</h2>
<p><a href="https://git-scm.com/docs/git-clone">git-clone(1)</a>にはいくつかcloneの方法がある。<code>--mirror</code>や<code>--bare</code>などである。今回は<code>--bare</code>を取り上げる。</p>
<pre><code class="language-bash">mkdir my_project
cd my_project
git clone --bare git@github.com/orumin/my_project .bare
</code></pre>
<p>このようにcloneすると、my_project/.bare配下にgitのレポジトリ本体だけがcloneされる。レポジトリで管理されているファイル群やコミットも全てgitレポジトリでgit objectとして管理されている状態にのみなっており、ファイルの実体はどこにもcheckoutされていない状態となる</p>
<pre><code class="language-bash">cd my_project
echo "gitdir: .bare" > .git
git worktree add main</code></pre>
<p>こうすると、実際はgitレポジトリではないmy_projectディレクトリ直下に居るときでもgitレポジトリとしてgitコマンドが認識してくれるので、<code>git-worktree(1)</code>も利用できる状態となっている。この場合、ここで<code>git worktree add main</code>をすることで、<code>my_project/main</code>というディレクトリに<code>origin/main</code>のブランチがcheckoutされて、gitで管理しているファイル群にアクセスできるようになる。同様に、他のブランチに関しても<code>my_project</code>直下で<code>git worktree add</code>すればディレクトリの形でぽこぽこブランチがcheckoutできる、というわけである。</p>
<p>また、</p>
<pre><code class="language-bash">git worktree -b add_new_feature feature_branch origin/main
</code></pre><p>などとすれば、<code>origin/main</code>をベースとして新規ブランチ<code>add_new_feature</code>を切り、これを<code>feature_branch</code>というディレクトリ名でworktreeを作成してくれる。べんり!</p>
<h2>remote branchをfetchできない!</h2>
<p>以上でよいように思うが、<code>git-pull</code>などをするとき途端に困った事実に直面する。remote branchをfetchできないのである。これは、<code>--bare</code>ではなく普通に<code>git-clone</code>するときに設定される値が、<code>git clone --bare</code>では設定されないためである。</p>
<pre><code class="language-bash">git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"</code></pre>
<p>簡単に言えば、この設定を追加すればoriginとして設定しているremote repositoryに対して<code>git-fetch</code>したときちゃんとlocal repositoryに紐付けてダウンロードしてくれるようになる。これで、オールオッケー!</p>
<h2>ブランチごとにディレクトリを作成する……?</h2>
<p><b>でもこれってSVNみたいじゃないですか?</b></p>
<p>はい……でも便利だし……</p>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-82926681979418029782022-05-20T01:03:00.004+09:002022-05-20T01:03:35.581+09:00C言語でRAII<h2>前置き:RAII って?</h2>
<p> C++ 言語には RAII; Resource Acquisition is Initialization という考え方があります。これはどういうことでしょうか。</p>
<pre><code class="language-c">#define ARRY_SZ (5)
int32_t p_arry = (int32_t *)malloc(sizeof(int32_t) * ARRY_SZ);
p_arry[0] = 1;
p_arry[1] = 2;
p_arry[2] = 3;
p_arry[3] = 4;
p_arry[4] = 5;
for (size_t idx=0; idx<ARRY_SZ; ++idx) {
printf("p_arry[%zu]=%" PRId32 "\n", idx, p_arry[idx]);
}</code></pre>
<p>よくある、Cでヒープ確保するコードですが、このコード片は <code>free(p_arry)</code> を呼び出し忘れているため、もしかしたらメモリーがリークするかもしれません。また、for 文で値を表示する前に <code>p_arry[n] = n+1;</code> の形式で確保した領域を初期化していますが、ここで初期化を忘れていたらどうでしょう。未初期化の領域を読み出そうとするのは Undefined Behavior なので、鼻から悪魔が出るかもしれません。</p>
<pre><code class="language-cpp">#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cinttypes>
#include <new>
#include <initializer_list>
class HeapArray {
private:
std::int32_t *values = nullptr;
std::size_t size = 0;
public:
HeapArray() = delete;
HeapArray(std::initializer_list<std::int32_t> init) {
this->values = new(std::nothrow) std::int32_t[init.size()];
if (this->values == nullptr) {
return;
}
this->size = init.size();
std::size_t idx=0;
for (auto&& v : init) {
this->values[idx] = v;
++idx;
}
}
~HeapArray() { delete[] this->values; };
void debug() {
for (std::size_t idx=0; idx<this->size; ++idx) {
std::printf("values[%zu]=%" PRId32 "\n", idx, this->values[idx]);
}
}
};
int main() {
HeapArray test {1, 2, 3, 4, 5};
test.debug();
return 0;
}</code></pre>
<p>ではこちらの C++ のコードはどうでしょう。クラスにしておくことで、先程の C のコードとやってることは同じですが、変数宣言するだけでコンストラクタでヒープ確保をしますし、スコープから外れたら自動でデストラクタが呼ばれてヒープが開放され、また、初期化子リストなしで変数宣言するとデフォルトコンストラクタが delete してあるのでコンパイルが通らないので、プログラマに初期化を強要できます。</p>
<pre>prog.cc: In function 'int main()':
prog.cc:36:15: error: use of deleted function 'HeapArray::HeapArray()'
36 | HeapArray test_2;
| ^~~~~~
prog.cc:13:5: note: declared here
13 | HeapArray() = delete;
| ^~~~~~~~~</pre>このようなコンパイルエラーになるわけですね。
<p>今回はやってませんが、ここで更に unique_ptr などスマートポインタ使うともっと良いかもしれませんね。</p>
<p>そもそも<code> std::int32_t *values = new std::int32_t[5] {1, 2, 3, 4, 5}; </code> とかやれば new だけで領域確保と初期化を同時にできるだろ、とかは目を瞑ってください……。</p>
<p>RAII によるリソース管理、他の言語にもあったりします。たとえば Pyton の with 構文。</p>
<pre><code class="language-python">with open("file.txt") as f:
print(f.read())</code></pre>
この場合、open(2) で確保したリソースが変数 f に紐付いて管理されて、with 構文のインデントブロックのスコープから外れると、自動で close(2) が裏で呼ばれてリソースが開放されます。close 呼び忘れがなくてめっちゃ便利ですね。
<h2>C で RAII</h2>
C プログラマーはこのようなイディオムの恩恵に与れないのでしょうか。いえ、実はコンパイラ拡張によっては、このような書き方も可能になるのです。
<pre><code class="language-c">#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
static inline void dtor(void *p) {
free(*(void **)p);
puts("freed!");
}
#define ARRY_SZ (5)
int main() {
__attribute__((cleanup(dtor))) int32_t *p_arry = (int32_t *)malloc(sizeof(int32_t)*ARRY_SZ);
}</code></pre>
<p>それがこの <code>__attribute__((cleanup(func)))</code> です。一見このコードは p_arry に格納したヒープがリークしてそうですが、実はちゃんと dtor 関数が呼ばれています。その証拠に、このコードをコンパイル・実行するとコンソールに <code>freed!</code> と表示されるはずです。</p>
<p>ところで、このコードだと確保した領域は未初期化のままです。そこで、次のようにしてみます。</p>
<pre><code class="language-c">#include <stddef.h>
#include <stdint.h>
#include <inttypes.h>
#include <starg.h>
#include <stdlib.h>
#include <stdio.h>
static inline void ctor(int32_t *p, size_t sz, ...) {
va_list ap;
va_start(ap, sz);
for (size_t idx=0; idx<sz; ++idx) {
p[idx] = va_arg(ap, int32_t);
}
va_end(ap);
}
static inline void dtor(void *p) {
free(*(void **)p);
puts("freed!");
}
#define CTOR_HEAP_ARRY(var, sz, ...) \
__attribute__((cleanup(dtor))) int32_t *var = (int32_t *)malloc(sizeof(int32_t)*sz); \
ctor(var, sz, __VA_ARGS__)
#define ARRY_SZ (5)
int main() {
CTOR_HEAP_ARRY(p_arry, ARRY_SZ, 1, 2, 3, 4, 5);
for (size_t idx=0; idx<ARRY_SZ; ++idx) {
printf("p_arry[%zu]=%" PRId32 "\n", idx, p_arry[idx]);
}
}</code></pre>
<p>どうでしょうか!ヒープ確保と共に初期化もできましたよ!やりましたね!</p>
<p>ここで用意したマクロを使ってもらえなかったらどうするの、とか、そもそもこのマクロ結構危険じゃない?とか、いろいろ言いたいこともあると思います。initializer list でやるようなことを可変長引数で実現しようとしてエラーチェックもサボってるので、バッファオーバーランの危険性もあります。だめですね。</p>
<p>はい。みんな Rust とか使おうね。</p>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-74418985528903773222022-04-26T19:35:00.000+09:002022-04-26T19:35:02.295+09:00としぁ Adventしたね Calendar 2022 #toshi_a解凍 22日目<p> 今度こそ遅刻しないとか思ってたけど普通に遅刻したし特にネタも思い浮かばなかったので、としぁさん初対面の時の思い出でも書きます。</p><p><br /></p><p>mikutter というものを知ったのは 2010 年かそこらに、Ruby で書かれた Linux でも使えるクライアントがあるらしいことを聞いていたのですが、そのときはたぶん Windows メインの利用者で Ruby はむしろ導入ダルそうだったので、たぶん Tween とか使ってました。</p><p>懐しいですね Tween。</p><p>そのあと、FreeBSD や Arch Linux とか使い出して mikutter も普段使いしはじめて、TL 大破させられたのは前 https://orumin.blogspot.com/2022/04/toshia-tl-advent-calendar-2022-toshia-6.html に書いたとおり。</p><p>そのあと、2014 年、なんやかんやで Google Summer of Code とか参加して、そのネタで syuu1228 先生と一緒に OSC Kansai@Kyoto のブース出したんですよね。</p><p>そこでコード書いてたら、いきなりにやにやしながら mikutter シールを束で目の前に叩き付けた人がやってきてですね、そうです、としぁさんと生で会ったはじめてのタイミングでした。</p><p>SNS 上の振舞い・発言と裏腹にリアルではすごい真面目な感じで、という人は結構居そうですが、としぁさんリアルでもヤベーよと思って笑ったの覚えています。</p><p>なんやかんやでそこから 8 年も経ってるし、OSC Kansai も今は OSC 大阪や OSC 京都になってるんでしたっけ。時間経つの早いですねぇ。</p>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-21324005650289416562022-04-07T02:52:00.006+09:002022-04-07T02:59:05.664+09:00toshi_a に TL 大破されてから8年と4ヶ月経ちました― としぁ Adventしたね Calendar 2022 #toshi_a解凍 6日目(遅刻)<ul><li><a href="https://orumin.blogspot.com/2014/12/toshiatl1.html">前回</a></li>
<li><a href="https://orumin.blogspot.com/2013/12/toshia.html">前々回</a></li></ul>
2021年の年始に引越してからこのブログ更新しわすれていたことに気付きました。<div>え、マジ?</div><div>私事ですがそれから今までなんと就労しはじめるなど個人的に大きな変化があったのでそのうちなんか書きます。</div><div><br /></div><h3 style="text-align: left;">本題</h3><div>Twitter から UserStream が消え mikutter で TL 大破させられ煮え湯を飲まされた <a href="https://twitter.com/toshi_a">@toshi_a</a> も凍結し、ここ何年も toshi_a を青い鳥のタイムラインで見ることはなくなっていました。</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7sm1KPSyVrCgoneUgUjr03OYSdHTVmAfuQyJi6bdG1zufM_aZ9xTuXA04dNx8jmCeJUzIhtlto52VZCHdKXY5XVi4a3wzpv925H5FTzfKRMb2UrmjzElwGNy7hpsuZbdR1s66k8278Cbv0JeyheM8ktT0Blyf1MTezAlco07bq2SKDxldehPfxEHWfg/s640/https___imgix-proxy.n8s.jp_DSXZZO5212915013112019000000-PN1-2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="426" data-original-width="640" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7sm1KPSyVrCgoneUgUjr03OYSdHTVmAfuQyJi6bdG1zufM_aZ9xTuXA04dNx8jmCeJUzIhtlto52VZCHdKXY5XVi4a3wzpv925H5FTzfKRMb2UrmjzElwGNy7hpsuZbdR1s66k8278Cbv0JeyheM8ktT0Blyf1MTezAlco07bq2SKDxldehPfxEHWfg/s320/https___imgix-proxy.n8s.jp_DSXZZO5212915013112019000000-PN1-2.jpg" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">凍結したtoshi_a <span style="font-size: xx-small;">(出典:「1991年、エッツィ(アイスマン)のミイラ化した遺体を調べる登山家のラインホルト・メスナー氏(右)と仲間」、PHOTOGRAPH BY PAUL HANNY, GAMMA-RAPHO/GETTY、NATIONAL GEOGRAPHIC より)</span></div><br /><div><br /></div><div><br /></div><div>しかしなんと4年と数ヶ月ぶりに解凍されたということでこれを記念した toshi_a Advent カレンダーとしての記事がこちらになります。</div><div>4/6 担当ですがいつもどおり無事一日遅れました。</div><div><br /></div><div>タイトル通りですが、toshi_a の凍結は4年前かもしれないですが、toshi_a に TL を大破されたのはなんと8年前なんですね。許さない。</div><div>いつまでこのネタひっぱるんだよ、と言われる気がしますが、気にしないことにします。</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgflr_kngbWlDVx7aFWQzIugcQnvP6_6ilNufyRWaLYV2TcnZhrQhR43Xzq-gcWtbY6KJNCwtIU4C3cjPIVOXOc159BQ-8shAyjhdJBTlviqsWWFk6ifdw2zgb0JOPzYdVW46PT8f9V71T81ScOtO3QNArdquIbFdADGLtn65YUiwXu9vrt1SAa72EF0w/s545/825741356.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="266" data-original-width="545" height="156" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgflr_kngbWlDVx7aFWQzIugcQnvP6_6ilNufyRWaLYV2TcnZhrQhR43Xzq-gcWtbY6KJNCwtIU4C3cjPIVOXOc159BQ-8shAyjhdJBTlviqsWWFk6ifdw2zgb0JOPzYdVW46PT8f9V71T81ScOtO3QNArdquIbFdADGLtn65YUiwXu9vrt1SAa72EF0w/s320/825741356.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">toshi_aに壊された当時のタイムライン</div><br /><div><br /></div><div><br /></div><div>ちょうどあのぐらいから Twitter の人に一部認知されたり、その後ておくれと言われたりするようになったのですが、</div><div><br /></div><div><ul style="text-align: left;"><li>わたしはておくれではない</li><li><b>真の元祖ておくれ toshi_a の帰還を歓びましょう!</b></li></ul>これが言いたかったことです、無事 Twitter に真のておくれが帰ってきたことを思い出しましょう!</div>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-21415900136182958082020-11-25T16:52:00.001+09:002020-11-25T16:52:04.248+09:00Type 3 フォントが埋め込まれた古い PostScript データになっている論文をそこそこ綺麗な PDF にする<p>これを使う。<a href="https://www.ctan.org/pkg/pkfix">CTAN: Package pkfix</a></p>
<p>以下利用例(論文ではないけれど)</p>
<pre><code class="language-bash">$ pkfix-helper Lions\ -\ 1977\ -\ Lions\'\ Commentary\ on\ UNIX®\ 6th\ Edition.ps lions-helper.ps
Reading Lions - 1977 - Lions' Commentary on UNIX® 6th Edition.ps ... done.
Total number of Type 3 fonts encountered: 16
Bitmapped fonts are typeset at 300 DPI.
Finding character widths ... done.
Reading TFM files ... done (103 TFMs in 193 scaling variations).
Matching fonts:
Processing Fn ... done (cmsl10 @ 1X, mismatch=0.53898).
Processing Ff ... done (cmtt10 @ 1X, mismatch=0.19819).
Processing Fg ... done (cmbx12 @ 1X, mismatch=0.36583).
Processing Fi ... done (cmbx10 @ 1X, mismatch=0.42627).
Processing Fk ... done (cmti10 @ 1X, mismatch=0.20169).
Processing Fj ... done (cmbx12 @ 1.2X, mismatch=3.41283).
pkfix-helper: Best match for Fj is rather poor
Processing Fe ... done (cmssi10 @ 1X, mismatch=0.37342).
Processing Fo ... done (cmr17 @ 1X, mismatch=0.12955).
Processing Fb ... done (cmsl10 @ 1.2X, mismatch=0.10469).
Processing Fm ... done (cmr10 @ 1X, mismatch=0.20941).
Processing Fp ... done (cmbx12 @ 2.0733X, mismatch=4.04419).
pkfix-helper: Best match for Fp is rather poor
Processing Fc ... done (cmr12 @ 1.2X, mismatch=0.25500).
Processing Fl ... done (cmsy10 @ 1X, mismatch=0.06818).
Processing Fh ... done (cmmi10 @ 1X, mismatch=0.06707).
Processing Fa ... done (cmtt12 @ 1.7283X, mismatch=1.23894).
pkfix-helper: Best match for Fa is rather poor
Processing Fd ... done (cmmi7 @ 1X, mismatch=0.00003).</code></pre>
<pre><code class="language-bash">$ pkfix lions-helper.ps ../lions-fixed.ps
PKFIX 1.7, 2012/04/18 - Copyright (c) 2001, 2005, 2007, 2009, 2011, 2012 by Heiko Oberdiek.
*** Font conversion: `cmtt12' -> `CMTT12'.
*** Font conversion: `cmsl10' -> `CMSL10'.
*** Font conversion: `cmr12' -> `CMR12'.
*** Font conversion: `cmmi7' -> `CMMI7'.
*** Font conversion: `cmssi10' -> `CMSSI10'.
*** Font conversion: `cmtt10' -> `CMTT10'.
*** Font conversion: `cmbx12' -> `CMBX12'.
*** Font conversion: `cmmi10' -> `CMMI10'.
*** Font conversion: `cmbx10' -> `CMBX10'.
*** Font conversion: `cmbx12' -> `CMBX12'.
*** Font conversion: `cmti10' -> `CMTI10'.
*** Font conversion: `cmsy10' -> `CMSY10'.
*** Font conversion: `cmr10' -> `CMR10'.
*** Font conversion: `cmsl10' -> `CMSL10'.
*** Font conversion: `cmr17' -> `CMR17'.
*** Font conversion: `cmbx12' -> `CMBX12'.
*** Merging font `CMSL10' (2).
*** Merging font `CMBX12' (3).
==> 16 converted fonts.
==> 2 merged fonts.</code></pre>
<pre><code class="language-bash">$ ps2pdf lions-fixed.ps lions.pdf</code></pre>
<p>利用したデータはこちらより > <a href="http://www.lemis.com/grog/Documentation/Lions/">Commentary on the Sixth Edition UNIX Operating System</a></p>
<p>ここで配布している PDF はビットマップフォントが埋め込まれているのでちょっと悲しい。まあ LaTeX ソースも配布しているのでここから PDF 作るので十分なのですが、ほかにも Mach や L4 あたりの 90 年代の論文とかけっこう PostScript しかデータがないやつがいるので、それをビットマップで読むのはなにか悲しかったのでこういう方法を探していたとさ。</p>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-6970247666802185572020-11-25T14:12:00.011+09:002021-10-11T13:44:17.524+09:00時刻取得・時間計測本稿では,Linux カーネルで扱える時計のうち,PTP(Precision Time Protocol)という IEEE 1588 で策定されている高精度な時計をクロックソース[1]にする場合について追っていこうと思います。<br />
<h2>
Linux における時刻同期:NTP と PTP</h2>
Linux や Windows,macOS といった現在の OS のシステムクロックは,一般的にはインターネットを通じて NTP(Network Time Protocol)が同期するようになっています。<br />
NTP を使っていればインターネットに接続されている際には大きく時刻がズレることはなく,たまにネットワーク接続が失われていてもクォーツ時計は安物の振り子式ほど時間はズレません。<br />
<br />
では,NTP は設計としてどのくらいの誤差が考えられているのでしょうか。NTP の設計者 David L. Mills 博士は自身が実装した PDP-11 向けの OS「Fuzzball」上の実験でそれを示しており,答えは数十ミリ秒です[2]。現代のマシンと OS ならば数ミリ秒までは迫れるかもしれません。ちなみにこの論文が発表された翌年には NTP version 2 が RFC から発行されています[3]。(現在は version 4。)<br />
<br />
NTP は日常的な利用には十分な精度があります。しかし,マイクロ秒やナノ秒といった単位での高精度さが目的ではありません。日本の NTP のサーバーとして有名な NICT(情報通信研究機構)は日本標準時の決定をしており原子時計も所有していますが,インターネットを介して NICT などのサーバーにアクセスしている時点でミリ秒やひどいときは数秒の遅れが発生するでしょう。LAN に NTP サーバーがあったとしても,アルゴリズムとして数ミリ秒の遅延を許容しています。そこで高精度な時刻同期のために存在するのが PTP です。<br />
<h2>
PTP とは</h2>
PTP とは,ネットワークデバイス内の時計を高精度に同期する仕組みです。グランドマスタークロックと呼ばれる時計をマスターとして設置し,LAN の NIC たちがそれを元に同期するといったような仕組みになります。これによって,パケットのタイムスタンプをハードウェアで高精度に打つことが可能になったり,この PTP をクロックソースとしてシステムクロックを同期したりできます。<br />
<h2>
ixgbe と PTP</h2>
Intel の 10GbE のネットワークインターフェイスとして,ドライバ名から ixgbe と呼ばれるものがあります。Intel 82599 や Intel X540 などが該当します。今回は Intel X550[4 sec. 7.7]について追っていこうと思います。<br />
<h3>
前準備・Intel アーキテクチャと割り込みについて</h3>
ソースコードを追う前にまず,PCIe 機器はどのように CPU に接続されどのように扱われるかを知らなければなりません。
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://4.bp.blogspot.com/-PjAkJkozMZU/Ww5WK-kKuSI/AAAAAAAANCc/6ONhtpmgTiEUnjrsVsZtdilQQjpeX6wYwCLcBGAs/s1600/intel_interrupt.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="778" data-original-width="1115" height="278" src="https://4.bp.blogspot.com/-PjAkJkozMZU/Ww5WK-kKuSI/AAAAAAAANCc/6ONhtpmgTiEUnjrsVsZtdilQQjpeX6wYwCLcBGAs/s400/intel_interrupt.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">図1.Intel アーキテクチャと割り込みの関係についてのブロックダイアグラム図</td></tr>
</tbody></table>
Intel CPU はおおむね上図のような形になっています[5 sec. 10.1]。大昔は Intel 8259 という割り込みコントローラーが直接 CPU に接続されて,周辺機器の割り込み信号は全部このコントローラーに接続されていましたが,現在では CPU の各コアに Local APIC という割り込みコントローラーがあり,チップセットのほうに割り込み I/O APIC という割り込みコントローラーがあります。このように分離されているおかげで,周辺機器からの割り込み信号は I/O APIC が受け取ってからどのコアに割り込みを配送するか自由に設定できますし,コア同士の通信は Local APIC を通じて IPI を送ることで可能となっています。
<br />
<br />
PCI デバイスは I/O APIC へ割り込み信号を送ることも可能ですが,もうひとつ,MSI という割り込みも可能です[6 sec. 6.8]。これは,割り込みコントローラーのピンに割り込み線を接続して INTx で割り込む(pin-based 割り込み)のではなく,デバイスにメモリに直接割り込みメッセージを書くことによって CPU コアの Local APIC へ割り込みが送られます。<br />
<br />
MSI での割り込みは pin-based の割り込みと違い,ピンが少なくてすんだりパフォーマンス上有利だったりとメリットが多く,また,PCIe デバイスでは MSI やその拡張である MSI-X が必須になっています。<br />
<h3>
ソースコードを読もう</h3>
今回は v4.17-rc7 のソースコードを読みます。ixgbe のソースコードは,<code>drivers/net/ethernet/intel/ixgbe/</code>にあります。以下断わりなくソースコードのファイル名を出した場合はこのディレクトリを起点に考えてください。
<br />
<br />
Linux のクロックソースとして ixgbe の PTP を設定するとなると,ixgbe のエントリポイントで割り込みベクタを設定する部分を読む必要がありそうです。そこで,irq や msix といった割り込みに関連しそうな処理をエントリポイントから探してみます。<br />
<br />
まずはエントリポイントそのものを探さなければなりません。<code>ixgbe_main.c</code>といういかにもなソースコードから entry point という語で探すと,6584 行目,<code>ixgbe_open()</code>が見つかります。
<br />
<pre class="line-numbers" data-start="6584"><code class="language-c">int ixgbe_open(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
int err, queues;
/* disallow open during test */
if (test_bit(__IXGBE_TESTING, &adapter->state))
return -EBUSY;
netif_carrier_off(netdev);
/* allocate transmit descriptors */
err = ixgbe_setup_all_tx_resources(adapter);
if (err)
goto err_setup_tx;
/* allocate receive descriptors */
err = ixgbe_setup_all_rx_resources(adapter);
if (err)
goto err_setup_rx;
ixgbe_configure(adapter);
err = ixgbe_request_irq(adapter);
</code></pre>
<br />
このコードの 6088 行目で<code>ixgbe_request_irq(adapter);</code>という呼び出しがあります。この関数は,同じソースコードに短い定義があります。3418 行目です。
<br />
<pre class="line-numbers" data-start="3418"><code class="language-c">static int ixgbe_request_irq(struct ixgbe_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
int err;
if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
err = <span style="color: red;">ixgbe_request_msix_irqs(adapter)</span>;
else if (adapter->flags & IXGBE_FLAG_MSI_ENABLED)
err = request_irq(adapter->pdev->irq, ixgbe_intr, 0,
netdev->name, adapter);
else
err = request_irq(adapter->pdev->irq, ixgbe_intr, IRQF_SHARED,
netdev->name, adapter);
if (err)
e_err(probe, "request_irq failed, Error %d\n", err);
return err;
}
</code></pre>
3424 行目に <code>ixgbe_request_msix_irqs(adapter)</code> がありますね。ここで MSI-X の割り込みを登録しているのではないか,と推測されますね。では,実際に確かめます。同一ファイル 3274 行目。
<br />
<pre class="line-numbers" data-start="3274"><code class="language-c">static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
unsigned int ri = 0, ti = 0;
int vector, err;
for (vector = 0; vector < adapter->num_q_vectors; vector++) {
struct ixgbe_q_vector *q_vector = adapter->q_vector[vector];
struct msix_entry *entry = &adapter->msix_entries[vector];
if (q_vector->tx.ring && q_vector->rx.ring) {
snprintf(q_vector->name, sizeof(q_vector->name),
"%s-TxRx-%u", netdev->name, ri++);
ti++;
} else if (q_vector->rx.ring) {
snprintf(q_vector->name, sizeof(q_vector->name),
"%s-rx-%u", netdev->name, ri++);
} else if (q_vector->tx.ring) {
snprintf(q_vector->name, sizeof(q_vector->name),
"%s-tx-%u", netdev->name, ti++);
} else {
/* skip this unused q_vector */
continue;
}
err = request_irq(entry->vector, &ixgbe_msix_clean_rings, 0,
q_vector->name, q_vector);
if (err) {
e_err(probe, "request_irq failed for MSIX interrupt "
"Error: %d\n", err);
goto free_queue_irqs;
}
/* If Flow Director is enabled, set interrupt affinity */
if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) {
/* assign the mask for this irq */
irq_set_affinity_hint(entry->vector,
&q_vector->affinity_mask);
}
}
err = request_irq(adapter->msix_entries[vector].vector,
ixgbe_msix_other, 0, netdev->name, adapter);
</code></pre>
割り込みベクタを登録していると思しき関数呼び出し,<code>request_irq()</code> が二箇所ありますね?これはそれぞれどういうことでしょう。ひとつめの <code>request_irq()</code> (3298 行目)は 3280 行目からのイテレーターの中にあります。このイテレーターではデバイスの構造体である <code>adapter</code> にある <code>q_vector</code> というものをイテレートしているようです。
<br />
<pre class="line-numbers" data-start="465"><code class="language-c">/* MAX_Q_VECTORS of these are allocated,
* but we only use one per queue-specific vector.
*/
struct ixgbe_q_vector {
struct ixgbe_adapter *adapter;
#ifdef CONFIG_IXGBE_DCA
int cpu; /* CPU for DCA */
#endif
u16 v_idx; /* index of q_vector within array, also used for
* finding the bit in EICR and friends that
* represents the vector for this ring */
u16 itr; /* Interrupt throttle rate written to EITR */
struct ixgbe_ring_container rx, tx;
struct napi_struct napi;
cpumask_t affinity_mask;
int numa_node;
struct rcu_head rcu; /* to avoid race with update stats on free */
char name[IFNAMSIZ + 9];
/* for dynamic allocation of rings associated with this q_vector */
struct ixgbe_ring ring[0] ____cacheline_internodealigned_in_smp;
};
</code></pre>
<code>adapter->q_vector</code> のデータ構造の定義を <code>ixgbe.h</code> から探してみるとこのようになっていることから,送受信のためのキューとその設定の構造体でしょう。ひとつの <code>adapter</code> に複数 <code>q_vector</code> が登録できるのはマルチキューのためですかね。さて,<code>ixgbe_request_msix_irqs()</code>に戻ってみてみると,3284 行目から 3294 行目までの条件分岐で vector が <code>rx.ring</code> か <code>tx.ring</code> かを見ているため,これが,送受信のためのリングバッファが作られているのならそれに関連した割り込みベクタを登録しているのだということが推測できます。時計の処理には関係なさそうなので,もうひとつの <code>request_irq()</code> をみてみましょう。
<br />
<br />
3313 行目のもうひとつの <code>request_irq()</code> では <code>ixgbe_msix_other</code> という関数の名前を持ってきています。この関数はやはり同じソースコード,<code>ixgbe_main.c</code> の 3109 行目に存在しています。
<br />
<pre class="line-numbers" data-start="3109"><code class="language-c">static irqreturn_t ixgbe_msix_other(int irq, void *data)
{
struct ixgbe_adapter *adapter = data;
struct ixgbe_hw *hw = &adapter->hw;
u32 eicr;
/*
* Workaround for Silicon errata. Use clear-by-write instead
* of clear-by-read. Reading with EICS will return the
* interrupt causes without clearing, which later be done
* with the write to EICR.
*/
eicr = IXGBE_READ_REG(hw, IXGBE_EICS);
/* The lower 16bits of the EICR register are for the queue interrupts
* which should be masked here in order to not accidentally clear them if
* the bits are high when ixgbe_msix_other is called. There is a race
* condition otherwise which results in possible performance loss
* especially if the ixgbe_msix_other interrupt is triggering
* consistently (as it would when PPS is turned on for the X540 device)
*/
eicr &= 0xFFFF0000;
IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr);
</code></pre>
<pre class="line-numbers"><code> ...</code></pre>
<pre class="line-numbers"><code> (略)</code></pre>
<pre class="line-numbers"><code> ...</code></pre>
<pre class="line-numbers" data-start="3184"><code class="language-c">
if (unlikely(eicr & IXGBE_EICR_TIMESYNC))
ixgbe_ptp_check_pps_event(adapter);
/* re-enable the original interrupt state, no lsc, no queues */
if (!test_bit(__IXGBE_DOWN, &adapter->state))
ixgbe_irq_enable(adapter, false, false);
return IRQ_HANDLED;
}
</code></pre>
やりました,ついに見つけました。3185,3186 行目,EICR というレジスタを確認して,<code>ixgbe_ptp_check_pps_event(adapter)</code> を呼び出しています。<code>IXGBE_EICR_TIMESYNC</code> というのは,レジスタ EIRC と論理積でテストをしているためレジスタの何らかのフラグではないかと考えられます。
X550 のデータシートの EICR レジスタのところ[4 sec. 8.2.2.6.1]を確認すると,割り込み原因が書き込まれるレジスタであることがわかります。どうやら 24-bit 目が TIMESYNC レジスタのようで,NIC に時刻同期を要求する割り込みが来るとこのフラグが立つようです。
<br />
<br />
さて,この <code>ixgbe_ptp_check_pps_event()</code> を探してみると,<code>ixgbe_main.c</code> にはありません。ついにこのファイルから離れ他のファイルを探してみると,<code>ixgbe_ptp.c</code>の 559 行目に見つかります。
<br />
<pre class="line-numbers" data-start="552"><code class="language-c">/**
* ixgbe_ptp_check_pps_event
* @adapter: the private adapter structure
*
* This function is called by the interrupt routine when checking for
* interrupts. It will check and handle a pps event.
*/
void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
struct ptp_clock_event event;
event.type = PTP_CLOCK_PPS;
/* this check is necessary in case the interrupt was enabled via some
* alternative means (ex. debug_fs). Better to check here than
* everywhere that calls this function.
*/
if (!adapter->ptp_clock)
return;
switch (hw->mac.type) {
case ixgbe_mac_X540:
ptp_clock_event(adapter->ptp_clock, &event);
break;
default:
break;
}
}
</code></pre>
NIC のドライバなのでちょっと混乱しそうになるのですが,ここで言う pps とは packet per second ではなく,pulse per second signal です。1 秒あたりのパルス数を表示する単位,pulses per second とも違います。キッカリ 1 秒ごとにパルスを発するような信号のことを言い,この pulse per second signal のための Unix-like OS の API が RFC に策定されていたりします[7]。
<br />
<br />
この関数,<code>ptp_clock_event()</code> を呼び出していますが,X540 の場合のみ対応しているようです。X550 は対応していないのかしら。ここで終わってしまうのもなんなので,この先の処理も追ってみます。<br />
<br />
<br />
ここからは ixgbe のコードを一気に離れ,ptp のコードに入ります。<code>drivers/ptp/ptp_clock.c</code> の 325 行目を見てみましょう。
<br />
<pre class="line-numbers" data-start="325"><code class="language-c">void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)
{
struct pps_event_time evt;
switch (event->type) {
case PTP_CLOCK_ALARM:
break;
case PTP_CLOCK_EXTTS:
enqueue_external_timestamp(&ptp->tsevq, event);
wake_up_interruptible(&ptp->tsev_wq);
break;
case PTP_CLOCK_PPS:
pps_get_ts(&evt);
pps_event(ptp->pps_source, &evt, PTP_PPS_EVENT, NULL);
break;
case PTP_CLOCK_PPSUSR:
pps_event(ptp->pps_source, &event->pps_times,
PTP_PPS_EVENT, NULL);
break;
}
}
EXPORT_SYMBOL(ptp_clock_event);
</code></pre>
<code>ptp_clock_event()</code> は PTP_CLOCK_PPS というイベントで呼び出されていました。そこでみてみると,<code>pps_event()</code> という API が呼び出されています。この関数の説明は <code>Documentations/pps/pps.txt</code> にも載ってまして,割り込みハンドラのような pps 信号へのイベントはこれを使い登録するそうです。この関数の定義は <code>drivers/pps/kapi.c</code> の 172 行目にあり,
<br />
<pre class="line-numbers" data-start="159"><code class="language-c">/* pps_event - register a PPS event into the system
* @pps: the PPS device
* @ts: the event timestamp
* @event: the event type
* @data: userdef pointer
*
* This function is used by each PPS client in order to register a new
* PPS event into the system (it's usually called inside an IRQ handler).
*
* If an echo function is associated with the PPS device it will be called
* as:
* pps->info.echo(pps, event, data);
*/
void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
void *data)
{
unsigned long flags;
int captured = 0;
struct pps_ktime ts_real = { .sec = 0, .nsec = 0, .flags = 0 };
</code></pre><pre class="line-numbers"><code> ...</code></pre>
<pre class="line-numbers"><code> (略)</code></pre>
<pre class="line-numbers"><code> ...</code></pre>
<pre class="line-numbers" data-start="223"><code class="language-c">
pps_kc_event(pps, ts, event);
/* Wake up if captured something */
if (captured) {
pps->last_ev++;
wake_up_interruptible_all(&pps->queue);
kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
}
spin_unlock_irqrestore(&pps->lock, flags);
}
EXPORT_SYMBOL(pps_event);
</code></pre>
さらに <code>pps_kc_event()</code> が呼ばれています。この関数の定義は <code>drivers/pps/kc.c</code> の 112 行目であり,pps 信号のイベントに対してただ <code>hardpps()</code> を呼び出すだけのようです。
<br />
<pre class="line-numbers" data-start="105"><code class="language-c">/* pps_kc_event - call hardpps() on PPS event
* @pps: the PPS source
* @ts: PPS event timestamp
* @event: PPS event edge
*
* This function calls hardpps() when an event from bound PPS source occurs.
*/
void pps_kc_event(struct pps_device *pps, struct pps_event_time *ts,
int event)
{
unsigned long flags;
/* Pass some events to kernel consumer if activated */
spin_lock_irqsave(&pps_kc_hardpps_lock, flags);
if (pps == pps_kc_hardpps_dev && event & pps_kc_hardpps_mode)
hardpps(&ts->ts_real, &ts->ts_raw);
spin_unlock_irqrestore(&pps_kc_hardpps_lock, flags);
}
</code></pre>
そろそろ脳内の呼び出しスタックも深くなりすぎていい加減うんざりしてきたところだと思います。<code>hardpps()</code> のコードともなるともはやドライバーのソースですらありません。<code>kernel/time/timekeeping.c</code> 2347 行目,
<br />
<pre class="line-numbers" data-start="2343"><code class="language-c">#ifdef CONFIG_NTP_PPS
/**
* hardpps() - Accessor function to NTP __hardpps function
*/
void hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_ts)
{
unsigned long flags;
raw_spin_lock_irqsave(&timekeeper_lock, flags);
write_seqcount_begin(&tk_core.seq);
__hardpps(phase_ts, raw_ts);
write_seqcount_end(&tk_core.seq);
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
}
EXPORT_SYMBOL(hardpps);
#endif /* CONFIG_NTP_PPS */
</code></pre>
これもまたロックなどをしていますが関数を呼び出しているのが主な処理であり,<code>__hardpps()</code>という NTP の処理のための内部関数を呼んでいます。
<code>kernel/time/ntp.c</code> の 973 行目,
<br />
<pre class="line-numbers" data-start="961"><code class="language-c">/*
* __hardpps() - discipline CPU clock oscillator to external PPS signal
*
* This routine is called at each PPS signal arrival in order to
* discipline the CPU clock oscillator to the PPS signal. It takes two
* parameters: REALTIME and MONOTONIC_RAW clock timestamps. The former
* is used to correct clock phase error and the latter is used to
* correct the frequency.
*
* This code is based on David Mills's reference nanokernel
* implementation. It was mostly rewritten but keeps the same idea.
*/
void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_ts)
{
struct pps_normtime pts_norm, freq_norm;
pts_norm = pps_normalize_ts(*phase_ts);
...
</code></pre>
コメントによるとどうやら,<code>hardpps()</code> というのはまたもや出てきた NTP の著者の David L. Mills 博士の成果である nanokernel の実装が初出のものだそうです。
nanokernel というのを調べてみると,アメリカの航海学会で開催されている Precise Time and Time Interval (PTTI) Meeting(正確な時間と時間間隔の会合)のうち第 32 回目のときに報告された論文が元のようですね[8]。なんか意外な学会ですが,PTTI 2000 の URL は U.S. Navy のドメインでホストされていたのでなんか納得。海軍の作戦行動とかシステムはやっぱり時刻同期も重要なのでしょう。<br />
<br />
この論文を読んでも良いのですが,どうやら<code>hardpps()</code>のアルゴリズムについては NTP.org にある解説のほうが要約されていてわかりやすそうです[9]。システムの時計での pps と外部信号(今回は PTP による pps ですね)を使って,システムの時計のオフセットのズレや周期のズレといったものを最小化しつつ pps に同期するようです。<br />
<h2>
次回予告</h2>
お気づきかもしれませんが,途中で割り込みハンドラ登録関数であるところの <code>request_irq()</code> の処理についてすっ飛ばしました。なので,たとえば NIC に PTP から時刻同期の信号が入り OS に割り込みが MSI-X を通じて飛んだとして,先程まで読んできた <code>hardpps()</code> を呼びだすような割り込みベクタ <code>ixgbe_msix_other</code> がどのように呼び出されるかはまだわかっていません。この割り込みの呼び出しにはどのような処理がありどのくらいオーバーヘッドが見込まれるでしょうか。次回をお楽しみください。
<br />
<h2>
宣伝</h2>
100 Gbps のネットワーク,数 GB/s の速度の I/O を持つストレージ,ピコ秒単位で刻まれる CPU クロック,さらに不揮発性メモリの登場によりさらに速度やレイテンシといったものを積み,ナノ秒やピコ秒の世界が当たり前になりつつある計算機の世界ですが,これらのハードウェアとそれを司るソフトウェアを新たに実装したとしても,その性能の計測は正確でないと意味がありません。そこで,ナノ秒レベルでの時刻同期や時刻計測の手法も重要になってきます。<br />
<br />
そこで,このような高精度な時刻について関心があるまたは,それを使って研究をしたり卒論や修論を書きたいという学生はぜひ,<a href="http://www.iij-ii.co.jp/index.html">IIJ Innovation Institute(IIJ 技術研究所)</a>でアルバイトをしてみませんか。アルバイトとして研究を進めることができ,そこそこのお給料を貰えたりネットワークや低レイヤ,データセンターのプロと議論できたりします。勤務地は飯田橋です。<br />
<br />
また,時刻同期だけではなく IIJ-II では 100 GbE のネットワークを実機を用いて実験できたり,libraryOS やクラウドといった部分での研究・実験もやってたりします。学生のアルバイトは常に募集しているので,分散システムやクラウド,OS,ネットワークなどに興味のある関東近辺の学生は是非声をかけてください。<br />
<br />
気になった方は <a href="https://twitter.com/kotatsu_mi">@kotatsu_mi</a> か私の上司である <a href="https://twitter.com/yojiro">@yojiro</a> まで DM などで気軽にご相談ください。<br />
<h2>
参考文献</h2>
[1] IEEE,“IEEE 1588<sup>TM</sup> Standard for A Precision Clock Synchronization Protocol for Networked Measurement and Control Systems,” URL: <a href="https://www.nist.gov/el/intelligent-systems-division-73500/ieee-1588">https://www.nist.gov/el/intelligent-systems-division-73500/ieee-1588</a>.<br />
[2] D. L. Mills, “The Fuzzball,” in Proc. of <i>Symposium Proceedings on Communications Architectures and Protocols</i>, Aug. 1988, pp. 115-122. URL: <a href="https://www.eecis.udel.edu/~mills/database/papers/fuzz.pdf">https://www.eecis.udel.edu/~mills/database/papers/fuzz.pdf</a>.<br />
[3] D. L. Mills, “Internet Time Synchronization: the Network Time Protocol,” <i>IETF</i>, Oct. 1989, URL: <a href="https://tools.ietf.org/pdf/rfc1129.pdf">https://tools.ietf.org/pdf/rfc1129.pdf</a>.<br />
[4] Intel, “Intel®︎ Ethernet Controller X550 Datasheet,” URL: <a href="https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/ethernet-x550-datasheet.pdf">https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/ethernet-x550-datasheet.pdf</a>.<br />
[5] Intel, “Intel® 64 and IA-32 architectures software developer's manual volume 3A: System programming guide, part 1,” URL: <a href="https://software.intel.com/en-us/articles/intel-sdm">https://software.intel.com/en-us/articles/intel-sdm</a>.<br />
[6] PCI-SIG, “PCI Local Bus Specification Revision 3.0,” URL: <a href="https://www.xilinx.com/Attachment/PCI_SPEV_V3_0.pdf">https://www.xilinx.com/Attachment/PCI_SPEV_V3_0.pdf</a>.<br />
[7] J. Mogul, D. Mills, J. Brittenson, J. Stone and U. Windl “Pulse-Per-Second API for UNIX-like Operating Systems, Version 1.0,” <i>IETF</i>, Mar. 2000, URL: <a href="https://tools.ietf.org/html/rfc2783">https://tools.ietf.org/html/rfc2783</a>.<br />
[8] D. L. Mills and P.-H. Kamp, “THE NANOKERNEL,” in Proc. of <i>32<sup>nd</sup> Annual Precise Time and Time Interval Meeting</i>, Nov. 2000, pp. 423-430. URL: <a href="https://www.eecis.udel.edu/~mills/database/papers/nanokernel.pdf">https://www.eecis.udel.edu/~mills/database/papers/nanokernel.pdf</a>.<br />
[9] NTP.org, “5.2 The Kernel Dicipline,” URL: <a href="http://www.ntp.org/ntpfaq/NTP-s-algo-kernel.htm#Q-ALGO-KERNEL-HARDPPS">http://www.ntp.org/ntpfaq/NTP-s-algo-kernel.htm#Q-ALGO-KERNEL-HARDPPS</a>.oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-61749368094075714522020-11-11T09:46:00.004+09:002020-11-11T10:04:43.150+09:00コードカヴァレッジ計測<h2>コードカヴァレッジとは</h2>
あるプログラムコードについて実行した際に、実際にコード中の命令を何割実行したかを数値に表したものを言う。
<h2>計測手法</h2>
<p>方法は様々である。たとえば、Linux kernel の fuzzer である Google の <a href="https://github.com/google/syzkaller">syzkaller</a> を用いれば、ユーザーアプリケーションへの入力を自動で変化させつつコードカヴァレッジを確認させてくれる。また、Linux kernel のコンフィグ自体にもカヴァレッジについてのコンフィグが存在する。これは <a href="https://kernhack.hatenablog.com/entry/2017/06/18/192850">masami256 さんのブログなどが詳しい</a>。</p>
<p>今回は gcc に組込みの手法でカヴァレッジテストを実行する手法についてメモをする</p>
<h2><code>gcov</code></h2>
<p><code>gcov</code> がカヴァレッジ情報を <code>.gcov</code> という拡張子でダンプすることでカヴァレッジを確認できる。このコマンドは gcc に附属している。</p>
<p>使い方を見ていく</p>
<script src="https://gist.github.com/orumin/4d270d628903b37b47a57cc11cff9d45.js"></script>
<p>このようなソースコードを用意し、次のようにコンパイルする。</p>
<pre><code class="language-bash">$ gcc -fprofile-arcs -ftest-coverage -o cov_test cov_test.c</code></pre>
<p>すると次のようなファイルが用意されるはずだ。</p>
<pre><code class="language-bash">$ ls
cov_test cov_test.c cov_test.gcno</code></pre>
<p>これでカヴァレッジテストの準備は完了した。では、実際にカヴァレッジテストを行なってみよう。まずは、何も引数を与えずコンパイルしたコードを実行する。</p>
<pre><code class="language-bash">$ ./cov_test
./cov_test: you need to pass arguments at least 1
$ ls
cov_test cov_test.c cov_test.gcda cov_test.gcno</code></pre>
<p><code>.gcno</code> に加えて <code>.gcda</code> が追加されている。このファイルがカヴァレッジテストの結果を格納している。ここで、<code>gcov</code> コマンドを用いてみよう。</p>
<pre><code class="language-bash">$ gcov cov_test.gcda
File 'cov_test.c'
Lines executed:38.89% of 18
Creating 'cov_test.c.gcov'
</code></pre>
<p><code>cov_test.c</code> というコード全体が 18 行で、そのうち 38.89% が実行されたということを物語っている。また、ここで新たに出力されたファイルの中身を見てみよう。</p>
<pre><code class="language-bash">$ cat cov_test.c.gcov
-: 0:Source:cov_test.c
-: 0:Graph:cov_test.gcno
-: 0:Data:cov_test.gcda
-: 0:Runs:1
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:#include <stdlib.h>
-: 3:
1: 4:void usage(char *cmd)
-: 5:{
1: 6: fprintf(stderr, "%s: you need to pass arguments at least 1\n", cmd);
1: 7: return;
-: 8:}
-: 9:
1: 10:int main(int argc, char **argv)
-: 11:{
1: 12: if (argc < 2) {
1: 13: usage(argv[0]);
1: 14: exit(EXIT_FAILURE);
-: 15: }
-: 16:
#####: 17: switch (argc) {
#####: 18: case 2:
#####: 19: printf("you passed 1 argument\n");
#####: 20: break;
#####: 21: case 3:
#####: 22: printf("you passed 2 arguments\n");
#####: 23: break;
#####: 24: default:
#####: 25: printf("you passed more than 3 arguments\n");
#####: 26: break;
-: 27: }
#####: 28: return EXIT_SUCCESS;
-: 29:}
</code></pre>
<p>見てのとおり、コード全体のうち空行やプリプロセッサの行、ブラケットのみの行などを除いた行のうち、実行された <code>1</code> でマークされており、実行されなかった行は <code>#####</code> でマークされている。この両者の合計は 18 行であり、そのうち <code>1</code> でマークした行は 7 行、<code>7/18 = 0.38..</code> というわけである。続けて、引数をいくつか与えてみる。</p>
<pre><code class="language-bash">$ ./cov_test 1
you passed 1 argument
$ gcov cov_test.c.gcov
File 'cov_test.c'
Lines executed:66.67% of 18
Creating 'cov_test.c.gcov'
$ ./cov_test 1 2
you passed 2 arguments
$ gcov cov_test.c.gcov
File 'cov_test.c'
Lines executed:83.33% of 18
Creating 'cov_test.c.gcov'
</code></pre>
<p>どうだろうか。実行する度に引数を変えているため、当然コードパスも異なる。そして、そのぶんカヴァレッジ率が積算されている。</p>
<pre><code class="language-bash">$ cat cov_test.c.gcov
-: 0:Source:cov_test.c
-: 0:Graph:cov_test.gcno
-: 0:Data:cov_test.gcda
-: 0:Runs:3
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:#include <stdlib.h>
-: 3:
1: 4:void usage(char *cmd)
-: 5:{
1: 6: fprintf(stderr, "%s: you need to pass arguments at least 1\n", cmd);
1: 7: return;
-: 8:}
-: 9:
3: 10:int main(int argc, char **argv)
-: 11:{
3: 12: if (argc < 2) {
1: 13: usage(argv[0]);
1: 14: exit(EXIT_FAILURE);
-: 15: }
-: 16:
2: 17: switch (argc) {
1: 18: case 2:
1: 19: printf("you passed 1 argument\n");
1: 20: break;
1: 21: case 3:
1: 22: printf("you passed 2 arguments\n");
1: 23: break;
#####: 24: default:
#####: 25: printf("you passed more than 3 arguments\n");
#####: 26: break;
-: 27: }
2: 28: return EXIT_SUCCESS;
-: 29:}</code></pre>
<p><code>.gcov</code> を確認してみると、実行しなかった行を示す <code>#####</code> のマークは減っている。その変わり、新たに実行された行は <code>1</code> がマークされており、また、何度も実行された行はその回数に合わせ <code>2</code> や <code>3</code> がマークされている。</p>
<pre><code class="language-bash">$ ./cov_test 1 2 3
you passed more than 3 arguments
$ gcov cov_test.gcda
File 'cov_test.c'
Lines executed:100.00% of 18
Creating 'cov_test.c.gcov'
</code></pre>
<pre><code class="language-bash">cat cov_test.c.gcov
-: 0:Source:cov_test.c
-: 0:Graph:cov_test.gcno
-: 0:Data:cov_test.gcda
-: 0:Runs:4
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:#include <stdlib.h>
-: 3:
1: 4:void usage(char *cmd)
-: 5:{
1: 6: fprintf(stderr, "%s: you need to pass arguments at least 1\n", cmd);
1: 7: return;
-: 8:}
-: 9:
4: 10:int main(int argc, char **argv)
-: 11:{
4: 12: if (argc < 2) {
1: 13: usage(argv[0]);
1: 14: exit(EXIT_FAILURE);
-: 15: }
-: 16:
3: 17: switch (argc) {
1: 18: case 2:
1: 19: printf("you passed 1 argument\n");
1: 20: break;
1: 21: case 3:
1: 22: printf("you passed 2 arguments\n");
1: 23: break;
1: 24: default:
1: 25: printf("you passed more than 3 arguments\n");
1: 26: break;
-: 27: }
3: 28: return EXIT_SUCCESS;
-: 29:}</code></pre>
<p>そしてついには、全てのコードパスを実行することに成功し、100% が表示され、<code>.gcov</code> ファイルにおいても全ての行に数字がマークされている。また、4 回の実行のうち、どの行が必ず実行され、どの行が場合によって実行されないかもマークされた数字によってある程度把握可能になる。</p>
<h2><code>lcov, genhtml</code></h2>
<p>これは別個インストールが必要である。インストール後、<code>.gcda</code> があるディレクトリで次のように用いる。</p>
<pre><code class="language-bash">$ lcov -c -d. -o cov.info
Capturing coverage data from .
Found gcov version: 7.3.1
Scanning . for .gcda files ...
Found 1 data files in .
Processing cov_test.gcda
TN:
SF:/home/orumin/cov/cov_test.c
FN:4,usage
FN:10,main
FNDA:1,usage
FNDA:4,main
FNF:2
FNH:2
DA:4,1
DA:6,1
DA:7,1
DA:10,4
DA:12,4
DA:13,1
DA:14,1
DA:17,3
DA:18,1
DA:19,1
DA:20,1
DA:21,1
DA:22,1
DA:23,1
DA:24,1
DA:25,1
DA:26,1
DA:28,3
LF:18
LH:18
end_of_record
Finished .info-file creation
$ genhtml cov.info
Reading data file cov.info
Found 1 entries.
Found common filename prefix "/home/orumin"
Writing .css and .png files.
Generating output.
Processing file cov/cov_test.c
Writing directory view page.
Overall coverage rate:
lines......: 100.0% (18 of 18 lines)
functions..: 100.0% (2 of 2 functions)</code></pre>
<p>すると、次のようにファイルが出力される</p>
<pre><code class="language-bash">$ ls
amber.png cov cov.info cov_test cov_test.c cov_test.gcda cov_test.gcno emerald.png gcov.css glass.png index.html index-sort-f.html index-sort-l.html ruby.png snow.png updown.png</code></pre>
<p>すなわち、<code>gcov</code> コマンドで plain text を出力する代わりに HTML でグラフィカルにカヴァレッジテストの結果を出力できるというわけである。</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-rsvUS14fyYg/X6s4o1XskVI/AAAAAAAAQ7w/6TmP7r7feu82vvqpJ_ohuQi5rJmfaqsCwCLcBGAsYHQ/s808/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588%2B2020-11-11%2B100359.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="600" data-original-height="633" data-original-width="808" src="https://1.bp.blogspot.com/-rsvUS14fyYg/X6s4o1XskVI/AAAAAAAAQ7w/6TmP7r7feu82vvqpJ_ohuQi5rJmfaqsCwCLcBGAsYHQ/s600/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588%2B2020-11-11%2B100359.png"/></a></div>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-21308540600530009022020-10-12T20:28:00.016+09:002023-11-19T17:19:59.006+09:00静電容量Helix (EC Helix) NiZ スイッチ ver. ビルドログ (β2)<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-oWpiAg0AEqg/X4QasAx-EAI/AAAAAAAAQ5E/91bLVjG4y5IyBBbMpzZlel_du6LXiLJ4QCPcBGAYYCw/s2048/IMG_0818.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="600" data-original-height="1536" data-original-width="2048" src="https://1.bp.blogspot.com/-oWpiAg0AEqg/X4QasAx-EAI/AAAAAAAAQ5E/91bLVjG4y5IyBBbMpzZlel_du6LXiLJ4QCPcBGAYYCw/s600/IMG_0818.JPEG"/></a></div>
<h2>前書き</h2>
<p>兼ねてより自作キーボードに興味はあったのですが静電容量無接点式スイッチ(東プレスイッチ)の分割が実現できそうになるまでやらないと公言しておりました。以前より <a href="https://github.com/tomsmalley/custom-topre-guide">Custom Topre Guide</a> など指針になるものがちらほら出てたようなのですが,今年の春先ごろ 銀鮭(<a href="https://twitter.com/sirojake">@sorojake</a>)さんが Booth で『<a href="https://ginjake.booth.pm/items/2232932">真の静電容量キーボードを作る本</a>』というものを出しているのを見掛け,どうやら PCB 設計勉強したり発注しなきゃいけないかなあと思っていたのですが,ありがたいことに Helix ベースのキットを出して貰えるということで,今回β2 版のテスターとして購入・製作しました。</p>
<p>長くなりましたが,次から実際に製作した過程とそのメモです。</p>
<p>実は初自作キーボード。</p>
<h2>disclaimer</h2>
β2 版のビルドログなので正式版とは異なる可能性があります。ご了承ください。
<h2>ビルドログ</h2>
<h3>道具・機材</h3>
<ul>
<li><a href="https://ginjake.booth.pm/items/2191959">静電容量Helix ラバードームタイプ(β2)キット</a></li>
<li><a href="https://www.nizkeyboard.com/collections/ornaments/products/2019-new-niz-ec-switch">NiZ のハウジングと軸×100</a><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-8CFS7dd90pU/X4Qab7W9JcI/AAAAAAAAQ44/QKETTpcqppkRnwKwZIGSxvjU7zBJ4tJXgCPcBGAYYCw/s2048/IMG_0697.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="320" data-original-height="2048" data-original-width="1536" src="https://1.bp.blogspot.com/-8CFS7dd90pU/X4Qab7W9JcI/AAAAAAAAQ44/QKETTpcqppkRnwKwZIGSxvjU7zBJ4tJXgCPcBGAYYCw/s320/IMG_0697.JPEG"/></a></div></li>
<li>東プレ OEM キーボードのジャンクから剥いだラバードームと円錐型スプリング</li>
<ul>
<li>Hitachi 2050 という 80 年代ぐらいのワークステーション付属のものらしい。<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-O_onrV2lIS4/X4QakIpFkJI/AAAAAAAAQ44/WlCEcRpIz10mG4fxSTNKLtlK4D8p5RvmwCPcBGAYYCw/s2048/IMG_0768.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="1536" data-original-width="2048" src="https://1.bp.blogspot.com/-O_onrV2lIS4/X4QakIpFkJI/AAAAAAAAQ44/WlCEcRpIz10mG4fxSTNKLtlK4D8p5RvmwCPcBGAYYCw/s320/IMG_0768.JPEG"/></a></div></li>
<li>いまならビットトレードワンさんが製作しているものを買うほうが簡単だし安いはず。<a href="https://yushakobo.jp/shop/a0500es-01-1/">遊舎工房にも置いてあった。</a>これを買う場合はハウジングや軸もセットだから NiZ から何か買う必要はなし。</li>
</ul>
<li><a href="https://kbdfans.com/products/enjoypbt-abs-doubleshot-mechanical-keyboard-keycaps-set-1">キーキャップ ENJOYPBT ABS Doubleshot Dolch</a></li>
<ul><li><a href="https://yushakobo.jp/shop/enjoypbt-abs-doubleshot-keycaps-set/">遊舎工房実店舗で購入</a>したけど,KBDFans で自分で買うほうが安いかも(ただしその場合届くまでのタイムラグがある)</li></ul>
<li>Pro Micro×2,OLED×2,LED (SK6812mini)×54,M2 スペーサー 8mm(OLED 保護アクリル用)</li>
<ul><li>いずれも遊舎工房の実店舗にて購入</li></ul>
<li>アクリルプレート Helix 向け 2mm 厚(押し出し・クリア)</li>
<ul><li><a href="https://yushakobo.jp/lasercut/">遊舎工房オンライン発注サービス利用</a></li></ul>
<li>ジャンパ用銅線,絶縁テープ</li>
<ul><li>うっかり買うの忘れてたので製作直前で適当にホームセンターで購入</li></ul>
<li>はんだこて先 (HAKKO T18-S9),フラックス (HAKKO FS-200),フラックスクリーナー(Sunhayato FL-L15),高密度集積基板用糸はんだ (goot SF-B1004, 0.4φ)</li>
<ul>
<li>いずれも秋葉原の千石電商にて購入</li>
<li>こて先は遊舎工房で聞いたおすすめなのだけれども,SOP のチップ実装には D 型ではなく K 型のほうがよかったのでは?と後で友人に指摘された。</li>
</ul>
<li>ソルダーアシスト (goot SA-10)</li>
<ul><li><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-cLfGFP-4v6Y/X4QarREWhCI/AAAAAAAAQ4c/0JvN6hUsHu8j18f-RSXCYz3RjHSVwjcYwCPcBGAYYCw/s2048/IMG_0814.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="320" data-original-height="2048" data-original-width="1536" src="https://1.bp.blogspot.com/-cLfGFP-4v6Y/X4QarREWhCI/AAAAAAAAQ4c/0JvN6hUsHu8j18f-RSXCYz3RjHSVwjcYwCPcBGAYYCw/s320/IMG_0814.JPEG"/></a></div>これも千石で購入。チップ押さえとかめっちゃ役立った。後述。でも今考えるとヒートクリップとかでも良かったね。</li></ul>
<li>はんだこて (HAKKO FX-600),はんだこて台 (HAKKO 633),はんだ吸い取り線 (HOZAN No.3793),デジタルマルチメーター (SANWA CD771)</li>
<ul><li>どれも以前から所有して利用していたもの。新しく買うならたぶん吸い取り線はもっと細いやつとか買うほうがいいです。</li></ul>
</ul>
<h2>ドキュメント類</h2>
<ul>
<li><a href="https://github.com/MakotoKurauchi/helix/blob/master/Doc/buildguide_jp.md">オリジナル Helix の公式ビルドログ</a></li>
<li><a href="https://hanocha.hateblo.jp/entry/2018/03/24/200514">オリジナル Helix のビルドログで参考にしたログ</a>(<a href="https://profile.hatena.ne.jp/hano_tea/">id:hano_tea</a> 氏によるもの)</li>
<li>銀鮭さんの EC Helix 設計者による<a href="https://github.com/ginjake/ec_helix_build">ビルドログ</a></li>
</ul>
<h2>製作</h2>
<h3>注意点</h3>
<p>チップ部品や LED の実装は取り立てて難しくないし,もし不安ならオリジナル Helix のビルドログを再確認すれば良いけれども,ふたつほど SOP パッケージのチップ(ピンのピッチが 1.27mm)があって,とくにマルチプレクサが一片あたり 8-pin あるので失敗しやすい。一度だめにしていい基板と SOP のチップを用意して,素振りしておくと良いと思った。たぶん一度練習すればじゅうぶん。</p>
<h3>はじめ</h3>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-TzBXv3UrB9M/X4QakORApXI/AAAAAAAAQ40/KL23LrcytdU3OfwwHVuZpi9O2fTGt5oMwCPcBGAYYCw/s2048/IMG_0777.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="1536" data-original-width="2048" src="https://1.bp.blogspot.com/-TzBXv3UrB9M/X4QakORApXI/AAAAAAAAQ40/KL23LrcytdU3OfwwHVuZpi9O2fTGt5oMwCPcBGAYYCw/s320/IMG_0777.JPEG"/></a></div>
<p>まず部品の種類や点数を確認しましょう。でないと私みたいに動作確認のために Pro Micro を開封してから「あれ,コンスルーが入ってない?」とか言って秋葉原に駆け込むハメになります。確認だいじ。</p>
<h3>Pro Micro 実装予定場所のジャンパ・絶縁(左手側のみ)</h3>
<p>基本的に銀鮭さんのビルドログ通り。ジャンパさせるのは左手側かつ<b>表側</b>です。</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-c-JWSrGqwHM/X4QadAdiltI/AAAAAAAAQ48/OtZ9dqL4ebwOeiPeVZwhPVa0UeA9tDl9gCPcBGAYYCw/s2048/IMG_0786.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="320" data-original-height="2048" data-original-width="1536" src="https://1.bp.blogspot.com/-c-JWSrGqwHM/X4QadAdiltI/AAAAAAAAQ48/OtZ9dqL4ebwOeiPeVZwhPVa0UeA9tDl9gCPcBGAYYCw/s320/IMG_0786.JPEG"/></a></div>
<p>スルーホールに銅線を 13 本すべて通してから,裏側からはんだ付けして,余った足はニッパーで切断しました。</p>
<p>あとビルドログにはないですが,OLED 使う予定の人は絶縁テープ貼る前に Pro Micro 実装予定場所の下側のランドもジャンパさせてしまったほうがいいです。私はうっかり完成してからジャンパしてないことに気付きました。</p>
<p>本家 Helix と違って OLED 実装のためにジャンパさせる場所に文字のシルクはありませんが,本家と同じ場所を同じやり方でオッケー。</p>
<h3>表面実装</h3>
<p>PCB をひっくりかえして,実装していきます。本家と違ってキーひとつごとにパーツを実装する必要はなく,Pro Micro 実装予定場所の裏側にチップ部品が密集しています。</p>
<p>さきに SOP パッケージチップ 2 つ(マルチプレクサ,OP アンプ)を実装したほうがこて先を動かす空間が確保しやくて失敗したときのリカバリーもしやすいと思います。</p>
<h4>SOP</h4>
<p>SOP を実装するときは,フラックスを PCB にたっぷり塗っておいて,ランドひとつだけ予備はんだをしておき,ピンセットでチップを持ったらまず足一本だけ予備はんだをくっつけておいて,次に対角線の足もはんだで固定します。このときソルダーアシストセットに含まれていたチップ押さえがおおいに役立ちました。</p>
<p>次に,一辺にフラックスを塗ってから,こて先の直線になっている部分をランドと端子の境界にあて,はんだを流しながらこて先もこの直線部分をチップの辺と平行に滑らせていきます。複数の足にまとめてはんだ流すかんじです。</p>
<p>このときわりと大きな確率でチップのピンとピンの間がはんだブリッジしてしまいますが,多少はんだが多めに盛ってあるほうがかえってはんだ吸い取り線で吸い取りやすいので,それで綺麗にしてしまいます。はんだを吸い取るときもフラックスを付けておけば,たぶんいい感じに必要量だけ残るはず。</p>
<p>一度失敗してから,こういう動画とかサイトとか眺めてイメージトレーニングしてからはんだ付けに臨みました。<iframe width="560" height="315" src="https://www.youtube.com/embed/-8SRkSjkZ8A" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
これは SOP より一際ピンのピッチが狭く (0.5 mm) さらにピンが四辺から出ている QFP ですが。</p>
<p>吸い取るときは私はこて先温度を 320~370 のダイヤルにしていました。利用した吸い取り線が 3.8mm だったのもあって多少温度を大きめにしないとそもそも吸い取れませんでした。このぐらいの温度でもチップはたぶん大丈夫です。</p>
<p>このとき,極めて少量だけがうっかりピンの根本とかでブリッジしてしまったなどの場合,へたに掻き出したり吸い取ろうとしたりせずいちどはんだを盛ってしまったほうが私はラクに感じました。</p>
<p>私の場合は最初それに気付かず,また,吸い取り線に対する温度が低すぎるのにも気付かなかったため,ニッパーでピンを切ってから余計なはんだを吸い取ってリカバリーしよとして,かえって取り外したチップとともにランドとパターンが剥離してしまったため PCB のお代わりを銀鮭さんから送ってもらうという失態をしました……。</p><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-dDno_dQSAdw/X4QarlHSTkI/AAAAAAAAQ48/1imNA7ElHeMLC5ybssweVK1bRQAH5I51QCPcBGAYYCw/s2048/IMG_0815.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="320" data-original-height="2048" data-original-width="1536" src="https://1.bp.blogspot.com/-dDno_dQSAdw/X4QarlHSTkI/AAAAAAAAQ48/1imNA7ElHeMLC5ybssweVK1bRQAH5I51QCPcBGAYYCw/s320/IMG_0815.JPEG"/></a></div><p>(ひとつダメにしたのはマルチプレクサでしたが,こっちは予備がキットにひとつ入っており,なんとかなりました。しかし既に実装していた OP アンプのほうは余りパーツもなく,また,SOP を取り外せる自信もなく,これまた銀鮭さんに OP アンプをひとつ都合してもらいました。大変感謝です!)</p>
<p>ルーペは持っていませんでしたが,幸いなことにチップ抵抗表面の印刷や SOP のピンとピンの間ブリッジしてないかとかはギリギリ肉眼で視認できたためなんとかなりました。</p><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-B0d8LGBzyGE/X4QaljlAFAI/AAAAAAAAQ5A/PWPQGy3lAFg8ULo4IBqeNFmb-u0qbZVlQCPcBGAYYCw/s2048/IMG_0787.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="320" data-original-height="2048" data-original-width="1536" src="https://1.bp.blogspot.com/-B0d8LGBzyGE/X4QaljlAFAI/AAAAAAAAQ5A/PWPQGy3lAFg8ULo4IBqeNFmb-u0qbZVlQCPcBGAYYCw/s320/IMG_0787.JPEG"/></a></div>
<h4>その他チップ部品</h4>
<p>私の場合の実装順ですが,まず 200 Ω 抵抗を全て実装し,次にマルチプレクサのすぐ下側のチップコンデンサ,10k Ω 抵抗,そしてトランジスタ,トランジスタ脇の 10k Ω 抵抗,その下側の 1k Ω 抵抗,51k Ω 抵抗,OP アンプ脇の 10k Ω 抵抗,そして最後に 100k Ω 抵抗を全て実装,という手順で実装しました。このへんの順番はどうでもいいのですが,チップとチップの間隔が狭いのでこて先を動かしやすい順番を気をつけると良さそうです。</p>
<h4>LED</h4>
LED を実装したい人はここで実装するとよいでしょう。すでに LED 実装の注意点は本家 Helix のビルドログで語られ尽くしているのであまり多くは書きません。私はこての温度ダイヤルを 270 度にし,こて先に溶かしたはんだをたっぷり盛ったうえで,PCB と LED にフラックスをたっぷり塗り,左手はソルダーアシストセットのチップ押さえで LED 動かないよう上からしっかり抑え,右手は PCB と LED のそれぞれのランドを始点・終点にした直線を引くつもりですっとコテを動かしてピンをひとつ固定してから,あとは糸はんだ片手に残りのピンを付けていきました。
<h4>注意点</h4>
<p>ここまでの実装を終えたらたぶん焦げたフラックスで PCB 裏面はやや茶色くなっている場所がちらほらあったり,べとべとしたりしていると思いますが,ここでフラックスクリーナーで綺麗にすると茶色いのが消えてべとべとが取れていいカンジです。また,フラックスを落とさずそのままにすると基板が腐食する可能性もあるそうで……。</p>
<h3>表側部品</h3>
<p>PCB をまたひっくりかえして,リセットスイッチ,TRRS ジャック,OLED のためのピンソケットを実装します。部品の足をスルーホールに通したらはんだは裏側から。</p>
<h3>ProMicro/OLED</h3>
<p>どちらもコンスルーやピンヘッダを PCB ではなくそれぞれ ProMicro 側と OLED 側にはんだ付けする必要があります。ProMicro にはコンスルー以外に普通のピンヘッダも同梱されており,また,コンスルーには向きがあるため,本家 Helix の公式ビルドログを見ながら注意深く実装しましょう。</p>
<h3>ファームウェアビルド</h3>
<p>ビルドの前に AVR アーキテクチャ向けの <code>gcc, binutils, libc</code> をインストールしておかなければなりません。</p>
<p>ただしこれを Alpine Linux でやったらビルドの最後の最後でリンカーがリンカスクリプト (<code>avr5.xn</code>) を発見できずにコケました。実際はファイル自体はパッケージからインストールされていたので,パッケージのバグだと思われますが,誰も Alpine なんかで AVR 向けのコンパイルをしたりしないんですかね。普通の Hello, World! を <code>gcc -mmcu=avr5</code> でコンパイルしてもコケました。まあメンテナンスされていないだけだとは思いますが,素直に Ubuntu とか使っておきましょう。</p>
<p>ちなみにこれは Gentoo では解決されているらしい <a href="https://bugs.gentoo.org/530786">https://bugs.gentoo.org/530786</a></p>
<p>気を取り直して以下が具体的なビルド手順</p>
<pre><code class="lang-bash">git clone https://github.com/orumin/qmk_firmware
cd qmk_firmware
git submodule update --init --recursive
qmk compile -kb ec_helix -km default</code></pre>
<s><p>上記ではなぜか脱落してる submodule を手動で追加していますが,将来的には <code>git submodule add ...</code> の三行ぶんはやらなくて良くなるんじゃないかな。<strike>修正作って pull-request を送ろうと思っているので。</strike> force push とか必要そうかつかなり巨大な差分になる修正だったので pull-request を出すのは諦めましたが,銀鮭さんに問題解決の対応をして頂きました。現在は <code>git submodule add ..</code> とある 3 行ぶんのコマンドは不要です。</p></s>
<p>もともと ginjake さんの repository を参照したビルド例を記載していましたが、現在 QMK 0.22 に対応した版を私の repository で作成したので以後 firmware 関連の記載修正しました (2023-11-19)</p>
<p>現在 <code>qmk_firmware/keyboards/ec_helix/rule.mk</code> の <code>OLED_DRIVER_ENABlE</code> がもし <code>yes</code> になっているのならば,完成して動作確認終えるまでは <code>no</code> にしておいたほうがキー入力の確認とりやすいと思います。ただし OLED の動作確認をさきにしておきたい場合はそれを行なってから書き換えると吉。</p>
<p>あとキーレイアウト変えたければ</p>
<pre><code class="lang-bash">qmk new-keymap -kb ec_helix
cd keyboards/ec_helix/keymaps/<your git user name>
</code></pre><p>を実行したのち、<code>keymap.c</code> を書き換えます。ビルドの最後の手順も <code>qmk comile -kb ec_helix -km default</code> から <code>qmk -kb ec_helix -km orumin</code> のように作ったキーレイアウトの名前に書き換えて実施しましょう。</p>
<s><p>作ったファームウェアファイルは以下のように書込みます。このとき <code>avrdude</code> とやらが必要なのでこれもパッケージから入れておいてください。</p>
<pre><code class="lang-bash">avrdude -c avr109 -p m32u4 -P /dev/ttyUSB001 -U flash:w:ec_helix_default.hex</code></pre>
<p>このなかの <code>/dev/ttyUSB001</code> のところは環境依存です。数字の部分が環境によって違うだけでなく,たとえば Windows だと COM1 とか COM7 とかの COM Port になります。</p></s>
<p>作成したファームウェアを書き込むときは、</p>
<pre><code class="lang-bash">qmk flash -kb ec_helix -km default</code></pre>
<p>のようにコマンドを実行した後、基板上の ProMicro の近くにあるタクトスイッチを押して DFU mode に切り替えます。ここで、両手ぶんそれぞれに書き込むことを忘れずに。</p>
<p>ただし WSL 上の場合、実際 Windows の COMn としてシリアルポートが接続されるのに反して WSL 内の Linux が <code>/dev/ttyUSB0</code> などに新しいシリアルデバイスが接続されることを期待して待ち受けてしまうため、うまいくいきません。この場合は次のようにすると良いでしょう。</p>
<pre><code class="lang-bash"># qmk_firmware ディレクトリに居ると仮定します
cd ../
git clone https://github.com/qmk/qmk_toolbox
cp qmk_firmware/ec_helix_default.hex .
qmk_toolbox/windows/QMK\ Toolbox/avrdude.exe -C qmk_toolbox/common/avrdude.conf -c avr109 -p m32u4 -P COM10 -U flash:w:ec_helix_default.hex</code></pre>
<p>こちら、コマンドを忘れがちなのと、コマンド実行した後に新しく接続されてくるシリアルデバイスを検知してから実際に書込みモードに移行するような挙動であってほしいので、こういうヘルパースクリプトを用意してみました。 <a href="https://gist.github.com/orumin/26e4840fd8aa23cbaac9fdf11e3df01f">https://gist.github.com/orumin/26e4840fd8aa23cbaac9fdf11e3df01f</a></p>
<h3>動作確認</h3>
<p>これは完成後動かないキーを修正してるとき気付いたのですが,この時点で LED だけじゃなくキーの動作確認もしてしまったほうがいいです。やりかたは,ボトムプレートの上に M5 スペーサー(黒いわっかです)をのせてその上にファームウェア焼き込み済み ProMicro を搭載した PCB を載せます。そして,キーひとつぶんだけに切られたラバードームとスプリングひとつ,そしてハウジングと軸もひとつずつ用意しましょう。最後に,PCB 上のテストしたいキーの位置の円のシルクがあるところに,スプリング,ラバードーム,軸,ハウジングの順番でのっけて,これでテストします。別のキーを試したければ,このスイッチ一式をそのまま別のキーの位置に滑らすだけです。</p>
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">クソ雑動作確認 <a href="https://t.co/ezGeY0Q2OO">pic.twitter.com/ezGeY0Q2OO</a></p>— まちカドおるみん (@kotatsu_mi) <a href="https://twitter.com/kotatsu_mi/status/1315315283943321601?ref_src=twsrc%5Etfw">October 11, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>注意点としては,この方法だとノイズが防げないため,確実と言っていいほど入力が暴走します(チャタリング)。メモ帳を開いてカーソルを合わせておくなど,不意のキー入力でも困らないようにしておいてください。</p>
<p>またこの方法ではあくまでキーがまったく読みとれない不具合がないかどうかだけ確認するなど割り切った確認として,実際にチャタリングが起きないかなどは完成後にあらためて確認しましょう。</p>
<p>ところで静電容量無接点方式でバネの具合やノイズなどで静電容量が微妙に閾値を超えて入力状態と誤判定される,のはチャタリングと表現して良いのでしょうか。正しい用語ではないかもしれない……。</p>
<h3>スイッチとケース(アクリルプレート)の実装</h3>
<p>もうここまで来るとはんだごても要らなくなりあとはやるだけです。手順も銀鮭さんのビルドログ通り。</p>
<p>ポイントとしては,ハウジングはトッププレートに嵌めるんですが,このとき工作精度の都合上たまにゆるゆるなハウジングが居たりします。どうせ NiZ から買うと 100 個も届いて余るので,微妙そうなハウジングは除けて別のハウジング使うといいと思います。</p>
<p>また,ハウジングと軸をトッププレートの裏側に嵌めたところで,スムーズに軸が動くかテストすると良いかと思います。たまにハウジングのプレートに嵌めるためのツメが内側に曲がってて軸の動きを邪魔しているやつが居ました。</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/SSenx6WD7_8" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<p>あと,これは一目で見ればわかるのであんま書かなくてもいいとは思いますが,NiZ のハウジングと軸は向きがあります。軸を嵌める向きがおかしいとユルユルになります。</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-PFRjPK2Nmyo/X4Qaqed_haI/AAAAAAAAQ40/yIMU-92_N88FyVTe8p8JVcULlrjcOh7PgCPcBGAYYCw/s2048/IMG_0806.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="320" data-original-height="2048" data-original-width="1536" src="https://1.bp.blogspot.com/-PFRjPK2Nmyo/X4Qaqed_haI/AAAAAAAAQ40/yIMU-92_N88FyVTe8p8JVcULlrjcOh7PgCPcBGAYYCw/s320/IMG_0806.JPEG"/></a></div><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-tkwKSVhf0YI/X4QaqSH55UI/AAAAAAAAQ44/_Qfuxwx8Czk1dlen1h864rUgKscXx9h_QCPcBGAYYCw/s2048/IMG_0807.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="320" data-original-height="2048" data-original-width="1536" src="https://1.bp.blogspot.com/-tkwKSVhf0YI/X4QaqSH55UI/AAAAAAAAQ44/_Qfuxwx8Czk1dlen1h864rUgKscXx9h_QCPcBGAYYCw/s320/IMG_0807.JPEG"/></a></div><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-9shZIxQ9dvM/X4QaqmIJ6BI/AAAAAAAAQ5A/aLTdxkOlr64bwdOyxhWJAbPlKgEknulzACPcBGAYYCw/s2048/IMG_0808.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="320" data-original-height="2048" data-original-width="1536" src="https://1.bp.blogspot.com/-9shZIxQ9dvM/X4QaqmIJ6BI/AAAAAAAAQ5A/aLTdxkOlr64bwdOyxhWJAbPlKgEknulzACPcBGAYYCw/s320/IMG_0808.JPEG"/></a></div><p>この場合は後者は間違った向き。</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-3Qxuo0BAt5E/X4Qana9yyHI/AAAAAAAAQ5E/TYv05rPRnmkLJDHeEdCGPJ-vkrp7qJKmgCPcBGAYYCw/s2048/IMG_0791.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="1536" data-original-width="2048" src="https://1.bp.blogspot.com/-3Qxuo0BAt5E/X4Qana9yyHI/AAAAAAAAQ5E/TYv05rPRnmkLJDHeEdCGPJ-vkrp7qJKmgCPcBGAYYCw/s320/IMG_0791.JPEG"/></a></div><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-eIO-z7f8Q6E/X4Qao6i5-HI/AAAAAAAAQ4s/C5SCcSKaQ8kLbaGTotOK0pcx2xkFzxhIACPcBGAYYCw/s2048/IMG_0803.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="1536" data-original-width="2048" src="https://1.bp.blogspot.com/-eIO-z7f8Q6E/X4Qao6i5-HI/AAAAAAAAQ4s/C5SCcSKaQ8kLbaGTotOK0pcx2xkFzxhIACPcBGAYYCw/s320/IMG_0803.JPEG"/></a></div><div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-nfU_8UccN9Q/X4QanzcNY7I/AAAAAAAAQ44/jsJIsCbKK_Aj7GYOTaOxymPq2SwtKTJ8QCPcBGAYYCw/s2048/IMG_0793.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="1536" data-original-width="2048" src="https://1.bp.blogspot.com/-nfU_8UccN9Q/X4QanzcNY7I/AAAAAAAAQ44/jsJIsCbKK_Aj7GYOTaOxymPq2SwtKTJ8QCPcBGAYYCw/s320/IMG_0793.JPEG"/></a></div>
<p>一度完成してから PCB だけ取り出してはんだを直そうとかすると写真二枚目のようにハウジングや軸もバラバラに取れちゃいがちなので,気をつけましょう。万一 PCB の修正が要るなら腹括ってください。</p>
<p>あと,私が使ったラバードームのせいなのかキットの低頭ネジだとボトムプレート留めるのにやや長さが足りなかったので,元の Hitachi 2050 キーボードで内部の基板を留めるのに使われていたネジを流用しました。</p>
<h3>完成</h3>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-MyY-X8-85BM/X4QarD0Ya0I/AAAAAAAAQ48/z3JUI3LGCEQDBaTJRnWckftcX8X8fdFrQCPcBGAYYCw/s2048/IMG_0812.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="1536" data-original-width="2048" src="https://1.bp.blogspot.com/-MyY-X8-85BM/X4QarD0Ya0I/AAAAAAAAQ48/z3JUI3LGCEQDBaTJRnWckftcX8X8fdFrQCPcBGAYYCw/s320/IMG_0812.JPEG"/></a></div>
<p>ということでおめでとうございます。ここまで来ればおおむね大丈夫でしょう。わたしはこの時点で右手側の特定列が入力できない(チップ抵抗がはんだ不足),OLED のジャンパ忘れなどで多少のやりなおしが発生しました。</p>
<p>一般にはんだは多すぎても少なすぎても,そして温めすぎてもダメですが,仕事ではなくホビーなので,動くこと優先で多少はんだが常に多めでも問題ないかと思います。動かないほうが怖いです。</p>
<div class="separator" style="clear: both;"><a href="https://1.bp.blogspot.com/-HL6ASqkhGPo/X4Qar8dMnyI/AAAAAAAAQ5A/d3kfwJs60sINCnMO6lREFSezNmCn7ABRACPcBGAYYCw/s2048/IMG_0817.JPEG" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" height="320" data-original-height="2048" data-original-width="1536" src="https://1.bp.blogspot.com/-HL6ASqkhGPo/X4Qar8dMnyI/AAAAAAAAQ5A/d3kfwJs60sINCnMO6lREFSezNmCn7ABRACPcBGAYYCw/s320/IMG_0817.JPEG"/></a></div>
<p>余談ですがフルカラー RGB LED なものを持つのが初めてなもので,完成した最初の夜(昨夜ですね)寝ようと布団に入ったら天井がパーリナイな感じに綺麗に照らされてて笑ってしまいました。</p>
<h2>おわりに</h2>
<h3>使ってみて</h3>
<p>この記事は EC Helix (NiZ) で作成しています。おおむね問題はないんじゃないでしょうか。ただ,作った直後たまにスペースが効かなくなることがあったのですが,キーキャップを全て付けた時点で再発しなくなりました。ですが,OLED のジャンパ忘れを直し,この記事を書いていて,終盤になってからまたたまにスペースが効かなくなり,USB 抜き差しでリセットされるのか直るんですが,再発の間隔がどんどん狭くなっています。もしかしたら OLED はやめておいたほうがいいのかもしれません。仮に OLED は関係なかったとしたら,おそらく私の実装の問題でしょう。</p>
<p><b>追記:しばらく使ってたら OLED 付けていても安定するようになっていて、上記のような不具合は起きなくなっていました。</b></p>
<p>基本的にはかなりちゃんと動作するし,タイプ感も静電容量無接点式そのもので,とても良いです……。テンションガン上げ。</p>
<p>私が現在利用しているキーレイアウトは次のようなカンジです。 <a href="https://github.com/orumin/qmk_firmware/blob/ec_helix_orumin/keyboards/ec_helix/keymaps/orumin/keymap.c">https://github.com/orumin/qmk_firmware/blob/ec_helix_orumin/keyboards/ec_helix/keymaps/orumin/keymap.c</a></p>
<h3>最後の注意事項</h3>
<p>キーレイアウトを変更したとき,左手側だけ書き換えても動くには動くんですが,ちゃんと両手どちらもファームウェア書き換えをしないと,右手側で取り零したり遅延が起きたりしました。両手どちらも書き換えたらちゃんと動作して,しかも入力はスムーズで最高です。</p>
<h3>謝辞</h3>
<p>こんな素敵なキットを作ってくれた上に壊れた PCB の都合や私の実装ミスによる不具合の解決のサポートまで色々してくださった銀鮭さん,大変ありがとうございました。</p>
<br />
<br />
<br />
<iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=orumin-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B001PR1L5U&linkId=2520ddc82facd0076ff71dcf68364ef6"></iframe>
<iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=orumin-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B006MQD7M4&linkId=c550ec8862c3c26620c70e400a1df921"></iframe>
<iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=FFFFFF&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=orumin-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=B0836889GC&linkId=c555092630d425c969e227c292a3931e"></iframe>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-15355670359335796992020-10-10T20:14:00.002+09:002020-10-10T20:14:13.126+09:00SuperH開発ストーリー<p>かつてルネサスのサイトに掲載されていたが消滅してしまい,Internet Archive にもアーカイヴされていないがウェブ魚拓には残っていた。しかし話数とそのリンクを一覧するのが面倒なため以下にメモしておこうと思う。</p>
<ul>
<li><a href="https://megalodon.jp/2014-0708-2332-39/japan.renesas.com/products/mpumcu/superh/related_sh/theme/story/01.jsp">第一話</a></li>
<li><a href="https://megalodon.jp/2014-0708-2346-36/japan.renesas.com/products/mpumcu/superh/related_sh/theme/story/02.jsp">第二話</a></li>
<li><a href="https://megalodon.jp/2014-0709-0008-01/japan.renesas.com/products/mpumcu/superh/related_sh/theme/story/03.jsp">第三話</a></li>
<li><a href="https://megalodon.jp/2014-0709-0017-11/japan.renesas.com/products/mpumcu/superh/related_sh/theme/story/04.jsp">第四話</a></li>
<li><a href="https://megalodon.jp/2014-0709-0104-38/japan.renesas.com/products/mpumcu/superh/related_sh/theme/story/05.jsp">第五話</a></li>
<li><a href="https://megalodon.jp/2014-0708-2324-58/japan.renesas.com/products/mpumcu/superh/related_sh/theme/story/06.jsp">第六話</a></li>
</ul>
<p>こういうドキュメントは大切なので消さないで欲しいなあ……。</p>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-15467255340487560412020-08-13T20:08:00.001+09:002020-08-13T20:42:35.581+09:00Line of Code (LoC) の計測<p>LoCの計測で一番簡単だと思われるのは次のような方法である。</p>
<pre><code class="language-bash">find ./src -type f -name '*.c' -o -name '*.h' | xargs wc -l</code></pre>
<p>この例では <code>./src</code> ディレクトリに含まれる C 言語のソースファイルとヘッダファイルについて全て <code>wc(1)</code> に食わせて行数を出力する,といったことを行なっている。</p>
<p>しかしこれでは,プロジェクトで利用する言語が増える度に <code>find(1)</code> のオプションを調整しなければならないし,コード内の空行やコメント行を全く考慮しない。</p>
<h2>cloc</h2>
<p>そこで,実は <code>cloc</code> という便利な LoC 計測ツールがあるらしい。<a href="https://github.com/AlDanial/cloc">https://github.com/AlDanial/cloc</a></p>
<p>このコマンドでは,単純にプロジェクトのディレクトリを引数として渡すと,どういう言語がどのくらい使われており,それぞれに含まれる空行とコメントはどのぐらいか,といったことを一覧表示してくれる。</p>
<p>しかし,私はLinux kernelにおける各サブシステムがコード全体のうちどのぐらいを占めているかを知りたかったため,次のように <code>cloc</code> を実行した。</p>
<pre><code class="language-bash">cd /usr/src/linux/
for dir in $(find . -maxdepth 1 -type d ! \( -name '.*' -o -name 'Documentation' -o -name 'LICENSES' -o -name 'samples' -o -name 'scripts' -o -name 'tools' \)); do
echo $dir
cloc $dir
done > ~/linux_loc.txt</code></pre>
すると <code>linux_loc.txt</code> には次のような出力が得られる。
<pre><code class="language-bash">./arch
16005 text files.
15902 unique files.
4299 files ignored.
github.com/AlDanial/cloc v 1.72 T=28.79 s (406.7 files/s, 90104.3 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
C 4725 226114 234741 1106210
C/C++ Header 5078 82383 114960 432840
Assembly 1245 44995 98313 220827
make 591 3298 3271 12514
Perl 7 1187 959 7692
Bourne Shell 55 398 621 2090
awk 5 51 58 486
Python 1 7 12 46
sed 1 2 5 5
-------------------------------------------------------------------------------
SUM: 11708 358435 452940 1782710
-------------------------------------------------------------------------------
./block
94 text files.
94 unique files.
3 files ignored.
...
</code></pre>
<p>さて,欲しいのは各サブシステムのコードが全体に占める割合であるため,次のようにして各サブシステムのコード行数を表にしてしまう。</p>
<pre><code class="language-bash">dirs=$(find . -maxdepth 1 -type d ! \( -name '.*' -o -name 'Documentation' -o -name 'LICENSES' -o -name 'samples' -o -name 'scripts' -o -name 'tools' \))
for i in $(grep SUM ~/linux_loc.txt | awk '{print $5}'); do
echo -e "${dirs[$count]}\t$i"
set count (expr $count + 1)
done | sort -r -n -k 2,2 > loc.txt</code></pre>
<p>これで <code>loc.txt</code> には次のような出力が得られるはずである。</p>
<pre><code class="language-bash">./drivers 13048806
./arch 1782710
./fs 967163
./sound 935637
./net 828886
./include 644501
./kernel 237713
./lib 131807
./mm 91805
./crypto 83988
./security 67041
./block 37711
./ipc 6689
./virt 5234
./init 3309
./usr 867
./certs 442</code></pre>
<p>最後にこの TSV から集計と割合の計算を行う。そう,こういう時役立つのは <code>awk</code> 言語だ。</p>
<pre><code class="language-bash">LOC_percentage=$(awk 'NR==FNR{sum=sum+$2;next}{percentage=$2/sum*100; print $0, "\t", percentage"%"}' loc.txt loc.txt)
LOC_total=$(awk '{sum+=$2} END {print "total\t",sum}' loc.txt)
echo "$LOC_percentage" > loc.txt
echo "$LOC_total" >> loc.txt</code></pre>
<p> <code>NR</code> は行数だが,<code>FNR</code> はファイル単位の行数である。ここでは <code>loc.txt</code> を二回食わせているため,一度目では <code>NR</code> と <code>FNR</code> が一致するが,二度目では <code>FNR</code> はまた 1 からカウントアップされるが <code>NR</code> は一度目の数を引き継ぐため,一致しなくなる。
そこで,一度目のループでのみ各ディレクトリのコード行数を足し合わせており,また,<code>next</code>によってその次の <code>{}</code> で囲まれているコードは実行しない。</p>
<p>二度目のループでは二つ目の <code>{}</code> の中身のみを実行するため,一度目のループで取得した総和に対して各ディレクトリのコード行数の割合を計算する,といった具合になる。</p>
<p>最後に,Linux 5.8 に対してこれを行なって,得られた結果は次の通りとなる。</p>
<pre><code class="language-bash">./drivers 13048806 69.1353%
./arch 1782710 9.44517%
./fs 967163 5.12423%
./sound 935637 4.9572%
./net 828886 4.39161%
./include 644501 3.4147%
./kernel 237713 1.25945%
./lib 131807 0.698341%
./mm 91805 0.486402%
./crypto 83988 0.444986%
./security 67041 0.355197%
./block 37711 0.199801%
./ipc 6689 0.0354397%
./virt 5234 0.0277308%
./init 3309 0.0175318%
./usr 867 0.00459355%
./certs 442 0.00234181%
total l18874309</code></pre>
<p>コードの実に 8 割が <code>drivers/</code> と <code>arch/</code> で占められ,次点に <code>fs/</code>,<code>sound/</code>,<code>net/</code> ... と続く。</p>
<p>ちなみに同様のことを <code>OSv</code> に対して実行するとこのようになる。</p>
<pre><code class="language-bash">./modules 421847 51.0683%
./bsd 251317 30.4241%
./musl 68332 8.27219%
./include 22400 2.71172%
./drivers 15663 1.89614%
./core 12595 1.52474%
./libc 11885 1.43878%
./fs 9164 1.10938%
./arch 9136 1.10599%
./ 3166 0.383272%
./fastlz 526 0.0636769%
./compiler 14 0.00169482%
total 826045</code></pre>
<p>最大の行数を誇るのは <code>modules/</code> であるが,この部分は CLI や RESTful API server,Java VM のバルーニング実装に libz や ncurses,openssl といったものが並ぶ。通常の OS であればユーザーランドに置かれるものであり,<code>OSv</code> のビルドや実行にも必ずしも含まれると限らない。</p>
<p><code>bsd/</code> には主に FreeBSD 由来であるネットワークスタックと ZFS のコードを含み,カーネルとしては実質この部分が最大になる。次に musl-libc の移植コードである <code>musl/</code> が続き,それから以降は OSv の独自実装が主となっていく。</p>
<p>また,<code>./</code> となっているのは <code>OSv</code> の場合トップディレクトリにもいくつか重要なコードがあるためで,これは <code>bootfs.S, dummy-shlib.cc, empty_bootfs.S, gen-ctype-data.cc, linux.cc, loader.cc, Makefile, runtime.cc</code> の 8 つのファイルを集計したものとなる。</p>
<p><code>OSv</code> は unikernel としては実装が大きいほうだが,それでも全体で 8 万行強であり,コア部分だけみるとたかだか 1 万行になっており,Linux に比べればカーネルの実装全体に目が通しやすい。</p>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-88523223844630588242020-07-09T16:20:00.001+09:002020-07-09T16:23:51.467+09:00GitHub で一番古いコミットを辿る<p><code>git clone</code> したレポジトリを開いて <code>git log</code> でも眺めれば済む話なんですが,ちょっとコードが気になったとき Web ブラウザから閲覧してて最初のコミットはいつか,なんて気になったときにいちいち clone はしたくない。
そういうときは次の手順で古いコミットが確認できます</p>
<ul>
<li>GitHub の該当プロジェクトのページから「Insights → Network」を開く</li>
<li>「Shift + ←」あるいは「Shift + h」で一番古いコミットまでカーソルを移動</li>
<li>グラフ上の該当ノードをクリック</li>
</ul>
ただし,cVim のような Vim 互換のキーバインドをブラウザに導入する extension を入れてるとキーバインドがこっちに取られるので微妙に上手くいかないこともある。
<h2>追記</h2>
モバイル端末のひとはがんばってスクロールしてください(コミット歴のページで Older をタップしつづけるよりかはマシかもしれない)oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-19965106756889968642020-07-03T07:51:00.001+09:002020-07-03T07:57:26.920+09:00IPv6 prefix と物理的な地理のカンケイ?<p>NTT が構築してきたインフラ網として,公衆電話網,地域 IP 網,そして NGN がある。</p>
<p>たとえば公衆電話では電話番号がそのままルーティングに活用されており,電話交換機の仕組みと市外局番・市内局番の関係を調べると実に面白い。</p>
<p>また,地域 IP 網によってブロードバンドが提供されるようになっても,効率性や合理性の観点から,ISP によっては PTR で逆引きすることによってある程度はグローバルアドレスから県ぐらいまでの特定は可能なようだ。これは,昔のフレッツ網は県間通信が制限されていたため,特定の県内網にしか出口を持たない ISP が居たり,あるいは全国でサーヴィスを提供する ISP であっても県内網ごとにネットワークの出口を設けていたためである。</p>
<p>さて,では NGN ではどうだろう。</p>
<p>NGN では IPv6 が割り振られ,近年は IPoE の利用によって NGN から払い出されるアドレスで直接インターネットに接続できるようになった。</p>
<p>このインターネットに接続できる IPv6 アドレスは,IANA から RIR(地域インターネットレジストリ)の APINC,NIR(国別インターネットレジストリ)の JPNIC,そして LIR(ローカルインターネットレジストリ)である指定事業者に払い出され,そこから ISP に払い出されることになっている。IPoE の VNE は指定事業者である。 <a href="https://www.nic.ad.jp/ja/ip/member/cidr-block-list.txt">https://www.nic.ad.jp/ja/ip/member/cidr-block-list.txt</a></p>
<p>この VNE が管理する IPv6 プレフィックスは /30 である。このプレフィックスは NGN 内のサーバーに預けられており,払い出しや実際の割り振りの管理は NGN 内で実施されることになる。なので,ルーティングなどの合理性からいっても,地理的に近いユーザーは似たようなアドレスが払い出されるだろうということが想像できる。</p>
<p>実際に私の手元に降ってきている IPv6 プレフィックスはひかり電話契約有りなので /56 なので,そのような物理的な地理に基いたアドレス分けに利用できる長さは 56-30 = 26-bit ということになる。</p>
<p>さて,実際に IPv6 プレフィックスはどういう管理がなされているのか,実は判明しているらしい。</p>
<blockquote cite="https://mao.5ch.net/test/read.cgi/network/1525232260/481">
都道府県の識別は 2bit(東京)~8bit(島根、鳥取)の可変長。
都道府県~収容局~エッジルーターまでで合計 13 bit。都道府県が短いところほど、その分収容局~エッジルーターにたくさん割り当てられる。
エッジルーター内の回線はその後の 13 bit で識別できる。
<footer><cite><a href="https://mao.5ch.net/test/read.cgi/network/1525232260/481">【時代が追いついた】IPv6スレ ver11【にわか爆増】</a></cite></footer>
</blockquote>
<p>実際に自分に払い出されている IPv6 プレフィックスを確認する,なるほどどうやらこれは合っているようにも思えるが,どうだろうか?</p>
<p>しかし自分の故郷である山陰が 8-bit の識別 ID になっているというのも,つまり人口の少なさ(=加入者の少なさ)を反映しているのであろう,納得ではあるがとても悲しい気持ちになった。</p>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-7980904830316093262020-07-03T07:25:00.004+09:002020-07-04T00:12:45.199+09:00BBIX の IPv4 over IPv6 技術は 4rd/SAM ではありません<h2>IPoE と IPv4 over IPv6</h2>
<p>現在,インターネット接続性のある VNE が持っている IPv6 を,トンネリングせず NGN から直接払い出してもらう IPoE(ネイティブ方式)がにわかに普及している。
当初 NGN に接続している VNE も BBIX,JPNE,MF の三社だけに制限されていたが,現在は NNTCom や Biglobe,ASAHInet など増加している</p>
<p>ところで,これら VNE がそれぞれ独自に提供している,IPv4 パケットを IPv6 上にカプセル化することによって IPv4 接続性を確保する方式として,4rd/SAM (RFC7600), MAP-E (RFC7597), DS-Lite (RFC6333) があると言われている。</p>
<p>MAP-E と DS-Lite については,JPNE と MF(ならびに MF 主要株主の IIJ)からそれぞれ技術詳細も出ており,確実にその方式を利用していることは明らかである。これらの方式については次を参照されたい。
<ul>
<li>あきみちさんが書いた『徹底解説v6プラス』<a href="https://www.jpne.co.jp/ebooks/v6plus-ebook.pdf">https://www.jpne.co.jp/ebooks/v6plus-ebook.pdf</a></li>
<li>IIJ の技術ブログ「てくろぐ」<a href="https://techlog.iij.ad.jp/archives/1879">https://techlog.iij.ad.jp/archives/1879</a></ li>
</ul>
とくに,MAP-E は JPNE 以外の VNE も多く利用しており,おそらくフレッツ網で使える IPv4 over IPv6 で一番多い手法なのではないだろうか。
</p>
<p>ということで今回の本題は,「BBIX は本当に 4rd/SAM を利用しているのか」です。</p>
<h2>4rd/SAM</h2>
<div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-xEu2CoONeXE/Xv5XKUuSiqI/AAAAAAAAQrQ/Xvlh6OF5lgEfA_sobGj21SjIPJKIxIG5wCK4BGAsYHg/s958/%25E3%2582%25B3%25E3%2583%25A1%25E3%2583%25B3%25E3%2583%2588%2B2020-07-03%2B065215.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="717" data-original-width="958" src="https://1.bp.blogspot.com/-xEu2CoONeXE/Xv5XKUuSiqI/AAAAAAAAQrQ/Xvlh6OF5lgEfA_sobGj21SjIPJKIxIG5wCK4BGAsYHg/s320/%25E3%2582%25B3%25E3%2583%25A1%25E3%2583%25B3%25E3%2583%2588%2B2020-07-03%2B065215.png" width="320" /></a></div>
出典:<a href="https://www.ietf.org/proceedings/83/slides/slides-83-softwire-10.pdf">https://www.ietf.org/proceedings/83/slides/slides-83-softwire-10.pdf</a>
<p>上記の図のように,4rd/SAM は 6rd がやることの逆のヴァージョンとして生まれ,MAP-E の前身となっている。そしてどうやら RFC7600 は草稿のまま放棄されているようだ。なので,4rd も MAP-E 同様に A+P (Address + Port) の 48-bit を IPv6 アドレスに埋め込んで stateless に IPv6 へ変換する,ISP 側ではなく CPE 側での変換技術らしい。</p>
<p>ではなぜ BBIX はこの放棄された 4rd/SAM を利用している,と言われているのであろう。</p>
<p>それはどうやら,BBIX の資料として 2010~2011 年に書かれた公開資料に,「BBIX、JPIX、IMF、IIJイノベーションインスティチュートの4社で共同仕様を作成し、技術検証を行なっています!」と書かれているあたりのようだ。 <a href="https://www.soumu.go.jp/main_content/000119430.pdf">https://www.soumu.go.jp/main_content/000119430.pdf</a></p>
<p>ここで言う IMF は前述の MF のことであり,また,IIJイノベーションインスティチュート (IIJ-II) はつまり IIJ 技術研究所のことなので,MF の技術検証に研究所として協力しているのだと考えられる。そしてここには JPIX が名を連ねているが,JPIX のネイティブ接続業者としての権利は JPNE に譲渡されている</p>
<p>つまりこの資料は IPoE の初期の VNE 事業者 3 社が当初は共同して IPv4 over IPv6 の方式を仕様化しようと努力していた,という過去の事実が読み取れるだけで,実は BBIX が現在も 4rd/SAM を利用しているという根拠はない。</p>
<p>この記述のあるページには SAM についての BBIX からのプレスリリース <a href="http://www.bbix.net/press/file/press_20100831.pdf">http://www.bbix.net/press/file/press_20100831.pdf</a> の URL も記述されているが,この URL は既に失なわれており,Internet Archive からもこの PDF 資料は取り出せなかったため,もはやどういったリリースだったかは完全に失なわれている。</p>
<p>いずれにせよ,BBIX が 4rd/SAM を利用している,というのはかなり根拠のない話だと考えられる。これは,先程見た 4rd の資料を見ても,4rd の仕様では MAP-E 同様にエンドユーザーに割り当てられたポートの範囲でしか「ポート開放」が出来ないというのに対して,ソフトバンク光の利用者は「IPv6 ハイブリッド」を利用していてもグローバルアドレスをまるまる一つ占有し,自由に IPv4 の NAPT が出来ている事実と符号する。よって,「BBIX では 4rd/SAM が IPv4 over IPv6 のため用いられている」はマチガイだと断言してもいい。</p>
<p>さて,重要なのは 10 年前に検討されていた事項ではなく,現在提供されているサーヴィスである</p>
<p>私は IIJ と契約し MF を通じてインターネットを利用しているため,実地で BBIX の検証をすることは望むべくもないが,インターネット上に出典不明の情報が転がっていた。</p>
<blockquote cite="https://mao.5ch.net/test/read.cgi/network/1356679044/736">禿は独自プロトコル。トンネルはただのIPIPで、ユーザ側の専用ルータがIPv4のグローバルアドレスを占有し(他のVNEは共有)、トンネル終端と普通のNATをするだけ。
だから所謂ポート開放ができる。
v4のアドレスは半固定で、RADIUS認証で取得している模様。
<footer><cite><a href="https://mao.5ch.net/test/read.cgi/network/1356679044/736">【風前の灯火】IPv6スレ ver10【IPv4NATに完敗】</a></cite></footer>
</blockquote>
<p>もしかしたら『徹底解説v6プラス』の 6.3 で述べられている「v6プラスでの固定IPv4アドレスのサービス」に近いのかもしれない(これも IPv4 over IPv6 のトンネリングに MAP-E を使用しない</p>
<h2>追記</h2>
<p>本稿を公開したことによって BBIX COO の福智氏から「アドレス共有は行なっていない」という旨の言及を頂きました。その上で念のため,不躾ながら,「BBIX の IPv6 高速ハイブリッドサービスは RFC7600 に沿ったものか否か」について質問したところ,大変ありがたいことに BBIX は 4rd を利用していないという確認を頂けました。大変ありがとうございます。よって,「BBIX の IPv4 over IPv6 は 4rd/SAM である」は明確に間違いです。</p>
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">弊社は4rdは利用しておりません。アドレス共有をしていませんので。</p>— Charlie Fukuchi (@bbix_mfukuchi) <a href="https://twitter.com/bbix_mfukuchi/status/1278921440180367360?ref_src=twsrc%5Etfw">July 3, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<h2>追記 2</h2>
BBIX ユーザーが 5ch 情報について追試して裏を取ってくれました。「ただの IPIP トンネル」「貰えるアドレスは RADIUS 認証によって配られる」「BR と CPE で NAT している」あたり間違いはないようです。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ミラーリング出来るハブを掴まえたのでキャプチャしました。RADIUS で認証したあとはただの IPIP トンネルっぽいです。ここにあるとおりでした <a href="https://t.co/aKWjI4GRmX">https://t.co/aKWjI4GRmX</a></p>— Rokoucha (@rokoucha) <a href="https://twitter.com/rokoucha/status/1279069564077146114?ref_src=twsrc%5Etfw">July 3, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-819251143955347682020-06-30T10:27:00.006+09:002020-07-03T08:00:56.007+09:00MTU,MSS の計算と最適化の便利な手段をまとめる<h2>MTU/MSS の計算</h2>
<p>IP ヘッダや Ethernet フレームの計算は結構大変だけれどもこのサイトを使えばわりとラクに導出できます。 <a href="https://baturin.org/tools/encapcalc/">https://baturin.org/tools/encapcalc/</a></p>
<p>たとえば MTU 1454 の環境(フレッツ網で ISP と PPPoE で接続した場合)の MSS は次の画像のとおり 1414 と計算可能です。</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-V2oFSgDG3bM/XvqLvBn572I/AAAAAAAAQqQ/Esw11yuCA0c4P8OtfXRQsPkMj_vuH1k6ACK4BGAsYHg/s953/%25E3%2582%25B3%25E3%2583%25A1%25E3%2583%25B3%25E3%2583%2588%2B2020-06-30%2B094734.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="507" data-original-width="953" src="https://1.bp.blogspot.com/-V2oFSgDG3bM/XvqLvBn572I/AAAAAAAAQqQ/Esw11yuCA0c4P8OtfXRQsPkMj_vuH1k6ACK4BGAsYHg/s320/%25E3%2582%25B3%25E3%2583%25A1%25E3%2583%25B3%25E3%2583%2588%2B2020-06-30%2B094734.png" width="320" /></a></div>
<p>この MTU 1454 の根拠は,フレッツ網では PPPoE で接続する際,NTT の収容ビルから事業者装置までの間は L2TP で接続しており,そこで PPPoE ヘッダを認証用の PPP ヘッダだけ残して取り払い,PPP over L2TP の状態にすると,IP (20 byte) + UDP (8 byte) + PPP (2 byte) + L2TP (16 byte) = 46 byte なので,1500 - 46 = 1454 byte になります。<a href="https://i.open.ad.jp/news-160614/">参考サイト</a></p>
<p>さきほどのサイトでは L2TPv3 の計算はできるけど L2TP の計算が出来ないのが惜しいところ。</p>
<h2>MTU の最適化</h2>
<p>前述の手段で計算した値をルーターやクライアントに設定しても良いですが,既に通信が可能な環境ならばヒューリスティックに最適な MTU を導出することもできます。</p>
<h3>ping コマンド</h3>
<pre><code class="language-powershell">PS C:\Users\orumin> ping -f -l 1424 -n 1 8.8.8.8
8.8.8.8 に ping を送信しています 1424 バイトのデータ:
8.8.8.8 からの応答: バイト数 =68 (1424 を送信) 時間 =3ms TTL=119
8.8.8.8 の ping 統計:
パケット数: 送信 = 1、受信 = 1、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
最小 = 3ms、最大 = 3ms、平均 = 3ms
</code></pre>
たとえば Windows なら,このようにして ping のパケットサイズを指定し DF ビットを立てます(=分割を禁止する)。こうすると,MTU を超過するようなパケットを送出すると以下のようになります。
<pre><code class="language-powershell">PS C:\Users\orumin> ping -f -l 1425 -n 1 8.8.8.8
8.8.8.8 に ping を送信しています 1425 バイトのデータ:
パケットの断片化が必要ですが、DF が設定されています。
8.8.8.8 の ping 統計:
パケット数: 送信 = 1、受信 = 0、損失 = 1 (100% の損失)、
</code></pre>
<p>これで最適なサイズは 1424 だとわかりますが,この数字はデータサイズなので,ここに IP ヘッダ (20 byte) と ICMP ヘッダ (8 byte) を足した 1424 + 20 + 8 = 1452 byte が私の環境で最適な MTU となります。</p>
<p>これは IPoE で IPv6 を貰った上で IPv4 over IPv6 (DS-Lite) を利用している環境なので,MTU 1500 - IPv6 (40 byte) - encap_limit (8 byte) = 1452 です。<a href="https://www.spinics.net/lists/netdev/msg143874.html">https://www.spinics.net/lists/netdev/msg143874.html</a></p>
<p>ping のオプションについて,Linux と macOS(FreeBSD ユーザーランド)でのオプションはそれぞれ以下のとおり。</p>
<pre><code class="language-bash">$ ping -c 1 -s 1424 -M do 8.8.8.8 # Linux
$ ping -c 1 -s 1424 -D 8.8.8.8 # macOS</code></pre>
<h3>traceroute コマンド</h3>
<p>また,世の中には <s>Path MTU</s> Path MTU Discovery (ご指摘感謝 <a href="https://twitter.com/ichinose_iroha/status/1278822907053932544">https://twitter.com/ichinose_iroha/status/1278822907053932544</a>) というものがあり,途中経路で ICMP が破棄されない環境なら,ルーターが ICMP 経由で適切な MTU を返してくれることにより,MTU が自動で最適な値に設定できます。<a href="https://xtech.nikkei.com/it/article/COLUMN/20090121/323165/?P=2">参考サイト</a></p>
<p>ここで,traceroute のコマンドオプションによって <s>PMTU</s> PMTU 探索を使って適切な MTU を取得することが可能です</p>
<pre><code class="language-bash">$ traceroute -F -N 1 --mtu 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 65000 byte packets
1 192.168.11.1 (192.168.11.1) 0.485 ms F=1500 0.456 ms 0.465 ms
2 ike-gw10.transix.jp (14.0.9.78) 3.856 ms F=1452 3.530 ms 3.245 ms
..
</code></pre>
<p><code>F=xxxx</code>の値を確認すると,最初に CPE で F=1500 として渡してますが,次に DS-Lite の AFTR で NAPT されたあとに返ってくる F= の値が 1452 になっており,この環境の適切な MTU が 1452 であることが把握可能です。</p>
<p>ちなみにこれを DS-Lite ではなく PPPoE 経由にしてみると,</p>
<pre><code class="language-bash">$ sudo traceroute -F -N 1 --mtu -i enp2s0 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 65000 byte packets
1 192.168.1.1 0.395 ms F=1500 0.408 ms 0.357 ms
2 xxxxxxxxxxxxxxxx (xxx.xxx.xxx.xxx) 3.415 ms F=1454 3.373 ms 3.356 ms
</code></pre>
<p>たしかに F=1454 になっており,本記事冒頭で計算した MTU に合致していますね。</p>
<p><s>PMTU</s> PMTU 探索 は便利ですが,PMTU を信頼してこちら側で MTU を指定していない時,途中経路に ICMP を返さないヤツとかが居ると Path MTU Black Hole になってしまい,こちら側で適切な MTU が設定できなくて TCP のセッションがタイムアウトするといった可能性があります (RFC2923) <a href="https://www.seil.jp/blog/11.html">参考サイト</a></p>
<p>最後に余談ですが,たとえば SINET などはジャンボフレームに対応しており MTU が 9140 bytes とされています(念のためちょっと少なめの 9000 byte あたりに設定することを推奨されています)。そのため,インターネットへの接続が SINET を経由している学術機関などではもう少し大きいパケットを送れる可能性があります。ただし大学→SINET のアクセス回線がフレッツの可能性もあるので,そこらへんは自分の所属機関に問合せたほうが早いでしょう。</p>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-25769746918048260382020-06-06T11:46:00.001+09:002020-06-06T12:22:28.309+09:00grep で OR 検索,AND 検索<h2>OR 検索</h2>
<pre><code class="language-bash">grep -e 'pattern1' -e 'pattern2'
grep -e 'pattern1\|pattern2'
grep -E -e 'pattern1|pattern2'</code></pre>
<h2>AND 検索</h2>
<p>基本的にムリ。</p>
<pre><code class="language-bash">grep -e 'pattern1' | grep -e 'pattern2'</code></pre>
<p>スマートではないが grep の結果を grep するのを何度も繰り返せば出来なくもない。</p>
<p>また,GNU grep は PCRE が利用できるのでそれを使えば</p>
<pre><code class="language-bash">grep -P '^(?=.*pattern1)(?=.*pattern2)'</code></pre>
<p>と書ける。</p>
<h2>grep 以外で AND 検索</h2>
<p>AND 検索のときはこっちを使うほうが良さそう。</p>
<pre><code class="language-bash">awk '/pattern1/ && /pattern2/'</code></pre>
<pre><code class="language-bash">sed -e '/pattern1/!d' -e '/pattern2/!d'</code></pre>
<h2>出典</h2>
<p><a href="https://unix.stackexchange.com/questions/55359/how-to-run-grep-with-multiple-and-patterns">https://unix.stackexchange.com/questions/55359/how-to-run-grep-with-multiple-and-patterns</a></p>
<p>以上</p>
<h2>メモ</h2>
<p>PCRE は 1234,1324,1432,1423,2341,... のような {1,2,3,4} の順列にマッチする条件,とかも綺麗に書こうと思えば書けるらしい。マジかよ。
<a href="https://stackoverflow.com/questions/3101366/regex-to-match-all-permutations-of-1-2-3-4-without-repetition/3101385#3101385">https://stackoverflow.com/questions/3101366/regex-to-match-all-permutations-of-1-2-3-4-without-repetition/3101385#3101385</a></p>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-20464309616340423142020-05-28T12:41:00.009+09:002020-05-30T18:05:40.096+09:00ssh-rsa,非推奨のお知らせ<h2>2020-05-28T14:11+9:00 追記</h2>
<p>これは SHA-1 を用いた RSA 鍵についての話で,OpenSSH 7.2 以降で生成・利用される RSA 鍵はまだ利用可能です</p>
<h2>2020-05-28T19:27+9:00 追記</h2>
<p>既に生成されている RSA 鍵でも<strike>ホスト・クライアントの両方が OpenSSH 7.2 以降</strike>ホスト・クライアントの両方が OpenSSH 7.2 以降,ただしサーバー側は OpenSSH 7.4 以外であれば SHA-2 で署名するので大丈夫なようです。(OpenSSH 7.4 はバグがあるようです)</p>
<blockquote class="twitter-tweet"><p dir="ltr" lang="ja">ssh-rsaという名前は"公開鍵の形式"と"公開鍵を使った署名方式"の二つで使われていて、廃止対象となっているのは署名方式の方だけです。なのでOpenSSH 7.2以降を入れれば、鍵自体は古いOpenSSHで生成した物がそのまま使えます。</p>— いわもと こういち (@ttdoda) <a href="https://twitter.com/ttdoda/status/1265966190909747200?ref_src=twsrc%5Etfw">May 28, 2020</a></blockquote> <script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script>
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">openssh-unix-devで指摘が出ていますが、OpenSSH 7.4のバグで、サーバ側が7.4だとrsa-sha2-256/512が使えると通知してこないのでssh-rsaでユーザ認証が行われてしまいます。これはユーザ認証時のみの問題で、ホスト鍵の確認には影響しません。 <a href="https://t.co/oyNVS08jGI">https://t.co/oyNVS08jGI</a></p>— いわもと こういち (@ttdoda) <a href="https://twitter.com/ttdoda/status/1266592381572222976?ref_src=twsrc%5Etfw">May 30, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<h2>本文</h2>
<p>OpenSSH 8.3 がリリースされたとのこと <a href="https://lwn.net/Articles/821544/">OpenSSH 8.3 released (and ssh-rsa deprecation notice) [LWN.net]</a></p>
<p>これに伴ない,ssh-rsa は将来的に deprecate になり,デフォルトでこの鍵形式を利用する機能自体が無効化されることが改めて告知されました。</p>
<p>サーバー側がこの形式を利用しているかどうを確認するには,`HostKeyAlgorithms` ディレクティヴから ssh-rsa を取り除いた上で以下のコマンドを使うこと</p>
<pre><code class="language-bash">ssh -oHostKeyAlgorithms=-ssh-rsa user@host</code></pre>
<p>`HostKeyAlgorithms` は <code>~/.ssh/config</code> で利用する鍵形式を指定できます。</p>
<p>現在は SHA-1 ハッシュを用いているアルゴリズムが $50K 以下で chosen-prefix attack という手法で攻撃できてしまうことから,ssh-rsa も非推奨になるそうです。</p>
<p></p><ul><li><a href="https://eprint.iacr.org/2020/014.pdf">"SHA-1 is a Shambles: First Chosen-Prefix Collision on SHA-1 and Application to the PGP Web of Trust" Leurent, G and Peyrin, T (2020)</a></li>
<li><a href="https://en.wikipedia.org/wiki/Collision_attack#Chosen-prefix_collision_attack">Collision attack - Wikipedia</a></li>
</ul><p></p>
<p>なお,ssh-rsa と同じ形式の鍵ですが SHA-2 ハッシュを用いている rsa-sha2-256/512 は OpenSSH 7.2 からサポートされており,ほかにも ECDSA 形式の ecdsa-sha2-nistp256/384/521 が OpenSSH 5.7 から,ssh-ed25519 が OpenSSH 7.2 から利用できます。</p>
<pre><code class="language-bash">ssh-keygen -t ecdsa
ssh-keygen -t ed25519
</code></pre>
<p>また,鍵生成のときは,以上に加えて, <code>ssh-keygen -t rsa -b 4096</code>,<code>ssh-keygen -t ecdsa -b 521</code> というようになるべく大きな鍵長を指定するようにすると,より安全です。</p>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-87914137787024597182020-05-22T17:39:00.001+09:002020-05-22T17:39:26.172+09:00Linux kernel のコードをパッチレベルを指定して入手<p>URL を覚えていて手癖で簡単に入力できるという理由で Linux kernel を手元に持ってくるときにはよく
<pre><code class="language-bash">git clone https://github.com/torvalds/linux.git</code></pre>
をしてしまうのだが,ここで <code>git checkout</code> をマイナーバージョンまでではなくパッチバージョンまでのレベルで指定しようとすると,そのようなタグはないと言われる。
<blockquote>error: pathspec 'v4.1.8' did not match any file(s) known to git</blockquote></p>
<p>これは GitHub にあるミラーレポジトリはリリース候補のタグしか置いてないためで,<a href="https://www.kernel.org">kernel.org</a> にある linux-stable の Git レポジトリを利用しないとパッチバージョンのタグが打たれていない。
<pre><code class="language-bash">git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linu.git</code></pre>
このレポジトリを利用すれば,パッチバージョンでの変化や歴史を Git で追いたいときに便利だ。
<pre><code class="language-bash">$ git checkout v4.1.8
HEAD is now at 36311a9ec490 Linux 4.1.8</code></pre></p>
<p>もっとも,Git の機能を利用せずコードを読むだけなら tarball をダウンロードするほうが手っ取り早い。
<pre><code class="language-bash">curl -LO https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.1.8.tar.xz</code></pre></p>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-50109372299442053512020-05-15T15:33:00.000+09:002020-05-15T15:33:33.522+09:00 素の Windows からリモートホストの macOS や Linux にクリップボードのテキストを流す<p>PowerShell で次を実行</p>
<pre><code class="language-powershell">$OutputEncoding = [Console]::OutputEncoding
Get-Clipboard -Format Text | ssh macOS_host "iconv -f sjis -t utf8 | pbcopy"
Get-Clipboard -Format Text | ssh Linux_host "iconv -f sjis -t utf8 | xsel --clipboard --input"</code></pre>
<p>上記のコマンドで,リモートの macOS ホストと Linux ホストそれぞれのクリップボードにローカルのクリップボードのテキストが転送されます。</p>
<p>最初のほうで OutputEncoding を上書きしているのは,これをしないと <code>Get-Clipboard</code> コマンドレットの出力が <code>us-ascii</code> でエンコードされるので,クリップボードの中身が日本語だと化けます。ちなみに ASCII のテキストなら
<pre><code class="language-powershell">Get-Clipboard -Format Text | ssh macOS_host "pbcopy"</code></pre>
だけで済む。</p>
<p>逆に,macOS や Linux のホストのクリップボードを手元に持ってきたいときは,macOS なら <code>pbpaste</code>,Linux なら <code>xsel --clipboard --output</code> を使ってください。</p>
<p>あと言わないでもわかることだとは思うけど,PowerShell の <code>Get-Clipboard/Set-Clipboard</code> コマンドレットや macOS の <code>pbcopy/pbpaste</code> コマンドはデフォルトで使えますが Linux の <code>xsel</code> コマンドは自分でインストールしなくても必ず存在するとは限りません。</p>
<p>ちなみに,とくに Windows ホストに外部コマンドをインストールしてはいけない縛りとかないのなら,<a href="https://github.com/equalsraf/win32yank">win32yank</a> を導入するのはオススメ。oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-2714886303162243722020-05-12T19:09:00.000+09:002020-05-12T19:09:36.193+09:00Oculus Quest と Virtual Desktop でモニタが一枚しかない部屋でマルチモニタを実現したい<div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-uDDE1L30FP4/Xrp1UIIQ_iI/AAAAAAAAQeA/H7GATr504PsZkCHvuAd73103uMwwkCL9wCK4BGAsYHg/OculusScreenshot1589187848.jpeg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1536" data-original-width="1536" height="320" src="https://1.bp.blogspot.com/-uDDE1L30FP4/Xrp1UIIQ_iI/AAAAAAAAQeA/H7GATr504PsZkCHvuAd73103uMwwkCL9wCK4BGAsYHg/s320/OculusScreenshot1589187848.jpeg" /></a></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-nSrqnCi0Ti8/Xrp1d0dKiBI/AAAAAAAAQeM/rcvVM9cq2D4t5_Gniqfzw-QTZES47A5pACK4BGAsYHg/2019-12-07_11-53-18_642%2B%25282%2529.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="3024" data-original-width="4032" src="https://1.bp.blogspot.com/-nSrqnCi0Ti8/Xrp1d0dKiBI/AAAAAAAAQeM/rcvVM9cq2D4t5_Gniqfzw-QTZES47A5pACK4BGAsYHg/s320/2019-12-07_11-53-18_642%2B%25282%2529.jpg" width="320" /></a></div><h2>前提</h2>
<ul>
<li>VR HMDで VR 空間に埋没してかっこいい空間を広々使ってお仕事したい</li>
<li>現実世界の PC がモニタ 1 枚しかない</li>
<li>画面出力端子を適当なドングルで埋めて fake monitor を召喚する手もあるがソフトウェアで解決したいところ</li>
</ul>
<h2>どういうことなのか</h2>
<p>実は去年末に Oculus Quest を購入していました。そのうち記事にするかも。それはそれとして,Oculus Quest を買ったのは『狼と香辛料 VR』が気になってた,というのと,サイバーパンクでありがちな,半透明のウィンドウが自分を取りかこむようにぶわーっと浮いて広がってるやつ,あれをやりたいという理由でした。</p>
<p>みなさんお気付きかと思いますが,後者の目的なら HoloLens とか買うほうが実現しやすいとは思います。でも高い。しかし Oculus Quest はスタンドアローンで 6DoF なワリには安い。それに Oculus Go を買うぞ買うぞと言い続けて結局 Oculus Quest 開発中の発表を見てしまったので,発売したら絶対買うぞ!と思ってました。それでいい加減に腹決めて買ったのが去年末。</p>
<p>で,VR 世界でデスクトップ環境を実現する方法はいくつかあります。たとえば私の理想に近いのは Linux のデスクトップ環境である <a href="https://github.com/SimulaVR/Simula">SimuraVR</a> でしょう。しかしこれは HTC Vive か Vavle Index あたりでしか利用できないようです。Oculus Rift S なら <a href="https://www.khronos.org/openxr/">OpenXR</a> に対応しているので,かろうじて使えるようですが,Oculus Quest は PCVR に対応しているとは言えども Oculus Link が必要で,この Oculus Link は Windows の Oculus ランタイムアプリに依存しています。血も涙もない。</p>
<p>故に Oclus Link+Virtual Desktop で,なんとかマルチモニターを仮想的に実現して気分を良くしたかったのでした。</p>
<h2>やりかた</h2>
<h3>ハードウェア</h3>
<p>素直にやるなら,ハードウェアでごまかすことが手っ取り早いです。</p>
<p>有名な手段としては,GPU の DP 端子に DP→VGA 変換器を取り付けて,Dsub 15-pin の VGA 端子,これの 2-pin と 7-pin を 102Ω 抵抗で結線します。こうするとモニタが接続されていると誤認識されるのです。PowerPC Mac に Linux を入れてヘッドレスで運用しようとしたときもコレ必要でした。しかしこのために VGA 変換ケーブル用意したり工作するのはやや面倒で,しかも解像度が限定されるでしょう。</p>
<p>次に考えられるのは,<a href="https://www.headlessghost.com">Headless Ghost</a> あたりの,fake monitor(あるいは ghost monitor)を Windows に認識させる専用のドングルを利用することです。これは 4K ディスプレイが接続されていると誤認させてくれる回路が積んである HDMI 端子のドングルですが,同様のドングルは様々な端子であちこちで発売されているようです。Amazon とか Aliexpress で色々ありました。</p>
<h3>ソフトウェア</h3>
<p>とはいえ私はそれをすぐに実現したい,できなかったらすぐ諦めるぐらいの気持ちだったので,ソフトウェアでの解決を試みました。よくあちこちで書かれている手段としては,Windows のコントロールパネル,画面解像度の設定にて,「画面の検出」を押したのちにアレコレすると VGA driver な fake monitor を用意することができる,というもの。しかしこれは Windows 10 の近年[いつ?] の ver. では使えません。そもそも画面設定がついにコントロールパネルからオミットされました。</p>
<p>なのでここで最終的に利用した手段を書きます。<a href="https://spacedesk.net">SpaceDesk</a> という driver とアプリを用いる方法でした。ドイツ・バイエルン州のアウクスブルクに本社がある <a href="https://www.datronic.de/en/">datronic</a> という会社のソフトウェアだそうです。まずこれの driver をインストールし,その後 Google Chrome で <a href="http://viewer.spacedesk.net">http://viewer.spacedesk.net</a> このページを開きます。すると IP アドレスの入力画面が登場するので,自身の PC のローカル IP アドレスを入力してください。</p>
<p>ここでブラウザが全画面になり,二つめの画面の中身が登場すると思うので,いったん ESC を押したりして抜け出してください。そのあと,このページの左上のハンバーガーボタンを選択すると設定が選べます。設定の中で「Use Client Resolution (for Extension)」などにチェックを入れればよろしかろうと思います。</p>
<p>もし画面が拡張ではなく一つ目の画面の複製になっていたら,「Super(Winキー,あるいは Cmd キーとも言います)+P」を押して「拡張」を選ぶと解決</p>
<h2>追伸</h2>
ひさびさに Blogger 開いたら記事編集画面がめっちゃ fancy になってて驚いた。正直微妙。
それと最近雑誌に記事書きました。技術評論社の『Software Design』,2020 年 5 月号です。初商業出版の記事,そちらもよろしければご一読ください[<a href="https://gihyo.jp/magazine/SD/archive/2020/202005">link</a>]。それと,そのうち SimuraVR っぽいことが Oculus Quest で出来るようになったら誰か教えてください……。oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-73134625626934510332020-02-07T00:15:00.000+09:002020-02-07T00:52:58.396+09:00Rockbox のダーティーハック(複数の値を持つ音楽メタデータへの対応)<p>本日誕生日のおるみんです。</p>
<p>みなさんは Rockbox というファームウェア/カーネルをご存知でしょうか。
単一メモリ空間,シングルプロセスで動作するファームウェアで,簡単なスレッドスケジューラを備えることによってマルチスレッドで動作可能な,
主にディジタルオーディオプレイヤー(DAP)上で動作するオープンソースファームウェアです。</p>
<p>初期には仏 Archos 製の MP3 プレイヤーに不満を持ったユーザーが homebrew プログラムの動作方法を見つけ,独自実装したのが始まりで韓国 iriver 製 DAP や米 SanDisk の Sansa,東芝の Gigabeat シリーズなど様々な DAP へ porting されています。</p>
<p>わけても初期のSony ネットワークウォークマンや大半の米 Apple iPod シリーズにも対応していることで,2000~2010 年ごろの DAP ユーザー(のごく一部)に広く知られています(広く?)。</p>
<p>Rockbox の場合,iPod の純正 Apple OS と違い Album Artist タグに対応してますし FLAC は再生できますし crossfeed やパラメトリックイコライザ(low-shelf,high-shelf,peaking * 8 の合わせて 10 バンドで Q 値も設定できる)など再生時のパラメータも細かく設定できるため,ギーク向きの良いファームウェアなのですが,不満もあります</p>
<h2>何をしたいか</h2>
<p>ここまで前置き,本題は Rockbox は意図的に複数の値を持つタグを読み捨ててしまうというところです。</p>
<p>音楽のメタデータは MP3 や AAC に対応する ID3 タグが知られていますが他にも Ogg Vorbis や FLAC に対応する Vorbis Comment,Monkey's Audio に対応する APE tag などが存在します。</p>
<p>ID3 タグの場合は ID3v2.3 だとスラッシュ,ID3v2.4 だとヌル文字を区切り文字にし複数の値を書いていけば良いという仕様がありますが,今回の記事では考えないことにします。今回は FLAC で使われる Vorbis Comment について複数の値に対応する方法を考えてみたいと思います。</p>
<h2>Vorbis Comment</h2>
<p>Vorbis Comment の細かい仕様は仕様書を見てもらうとして,簡単には次のようになっています。
<pre><code class="language-bash">TITLE=Canned Heat
ALBUM=Synkronized
ARTIST=Jamiroquai
...
</code></pre>
<key, value> という構成になっているだけの至極単純なもので,key のほうは大文字小文字を区別しません。
さて,これがどのように複数アーティストに対応するかというと,次のようになります。
<pre><code class="language-bash">TITLE=Yes! Party Time!! (M@STER VERSION)
ALBUM=THE IDOLM@STER CINDERELLA GIRLS VIEWING REVOLUTION Yes! Party Time!!
ARITST=島村卯月(大橋彩香)
ARITST=渋谷凛(福原綾香)
ARITST=本田未央(原紗友里)
ARITST=赤城みりあ(黒沢ともよ)
ARITST=安部菜々(三宅麻理恵)
...
</code></pre>
このように同じ key 名の値を複数並べていくだけです。<b>ね,簡単でしょ?</b>
<h2>処理をかんがえる</h2>
<p><b>簡単なわけがない。</b>ある key 名が 1 つだけ来るかもしれないし,100000000 コくるかもしれない,それをパーサーは予期できない。
しかも key の名前は推奨されるものはいくつかあるけれども,規格で決まってるわけではない。ID3 タグと違ってかなり自由度の高いメタデータが記述できるのはメリットではありますが,いくら事細かにメタデータを記入したところで読み出し側がちゃんと処理してくれなければ絵に描いた餅です。
</p>
<p>さて,Rockbox が動作するプラットフォームは大抵メモリや CPU が貧弱極まりないため(iPod classic はかなり良いほうですね),メモリを潤沢に扱えません。そのため,Vorbis Comment については,同じ key 名が来たら読み捨てる,という手段を取ります。また,読み込んだメタデータについても,ID3 タグを念頭に置いている <code>struct mp3entry</code> という構造体のメンバのひとつである単一の文字配列をバッファとして全てここに読み込んでしまい,この構造体の artist や title といった名前のメンバはそのバッファへのポインタになっています。各タグの間はヌル文字で仕切る,というわけです。(<code>rockbox/lib/rbcodec/metadata/metadata.h#L233</code> を参照のこと)</p>
<p>しかしならば話はある意味簡単です。いままで読み飛ばしてた処理のところで,読み飛ばさずに追記してしまえば良いのです。</p>
<h2>実装</h2>
<p>行なった実装は次のとおり。コードはわりと読み易く,改変も簡単なものなので,ものの数分でやりたいことは完了した気がします。この記事を書くほうが時間がかかったぐらいです。
<script src="https://gist.github.com/orumin/c2088d7b64e7fcb651787955f5a4aea9.js"></script>
ごらんの通り,以前読んだ key がやってきたら,スラッシュを区切り文字代わりにして新しい値をもうひとつ追記しています。こうすると,例えば複数のアーティストについて,
<pre>島村卯月(大橋彩香) / 渋谷凛(福原綾香) / 本田未央(原紗友里) / 赤城みりあ(黒沢ともよ) / 安部菜々(三宅麻理恵)
</pre>
のように複数の値が 1 つの連結された文字列として格納されるため,結果として複数アーティストがきちんと iPod に表示されるわけです。やったね!</p>
<p>ところで勘の良いかたはお気付きかもしれませんが,この方法だと Vorbis Comment として
<pre><code class="language-bash">ARTIST=CHAGE
TILTE=YAH YAH YAH
ARTIST=ASKA</code></pre>
みたいなメタデータがやってきた場合,おそらく文字列を格納する順番から考えて TITLE の文字列の一部が上書きされてしまい,かなり微妙な読み出し結果になってしまうでしょう。つまりこのパッチはかなり雑なやりかたです。ダーティーハックですね。(ところで CHAGE and ASKA はたぶん ARTIST を分割して複数値にしたりはしないと思うのでこの例はかなり微妙ですね)</p>
<p>ですが良いのです。まともな頭がついてればメタデータを書き込むほうだって同じ key は連続して書くでしょう。少なくとも自分がデータ管理している foobar2000 では ; セミコロンを区切り文字にすれば ID3 タグではスラッシュやヌル文字,Vorbis Comment なら複数 key と欲しいデータをいい感じに書いてくれるみたいなので,たぶん気にしなくても良いはずです。少なくとも自分の環境ではうまくいきました。</p>
<h2>何がうれしいの</h2>
<p>ぶっちゃけ iPod の表示が欠けてたって何も困らないのですが,Rockbox が last.fm 向けに生成する scrobbler ログに複数アーティストが歌う曲が単独アーティストかのように間抜けに書かれて last.fm にヘンなログが残るのが無くなりました。</p>
<h2>そのうち気分転換のコード書きたくなったらやりたいこと</h2>
<p>とりあえず複数の値は / 区切りということで読み出してしまったので,Rockbox のデータベース生成のルーチンを書き換えて / 区切りでデータベースの値を生成したら,複数のアーティストが 1 つの文字列に連結されていてもデータベース上は複数の値として扱われるので曲の検索に便利そうです。そしてそれほど難しくないかもしれない。</p>
<p><code>app/tagcache.c</code>を書き換えればいいのかなあ。まあいつかやりたいですね,いつか……。oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-34636682355043766622019-12-03T14:05:00.000+09:002019-12-03T14:05:29.118+09:00Makefileの基本的な書き方について最近研究室Wikiに後輩向けの文章書いてたのですが,いくつかはclosedにするのも勿体無いので編集してブログで公開しようかと思います。
<h1 id="概要">概要</h1>
<ul>
<li>Makefile は自分の書いたコードのビルドの自動化に便利なため基本的な記法は知っておくとよい
<ul>
<li>いちいちシェルの履歴を確認したりコマンドをミスする悲しいことがなくなる</li>
</ul></li>
<li>Makefile はビルドだけでなく実験やらなんやらの task runner としても便利
<ul>
<li>ビルド・実験を回す・結果をグラフにする,などをまとめてやったりすることも可能</li>
</ul></li>
<li>上記は shell script でも可能だがメリットとして
<ul>
<li>あるタスクに対して依存関係が記述できる
<ul>
<li>実験タスクの依存にビルドタスクを記述すれば,実験タスクを実行したら自動でビルドしてくれる</li>
</ul></li>
<li>あるタスクについて,依存先が更新されていなければ実行しないという機能が標準で存在
<ul>
<li>二行上のような依存を記述していたときに,ソースコードの更新の有無でビルドの実行をする/しないを勝手に判断してくれる</li>
</ul></li>
</ul></li>
<li><em>以下の説明は GNU Make に準拠して説明を行う。BSD Make の場合上手く動作しない記法も含まれる</em></li>
</ul>
<h1 id="makefile-の基本的な利用法">Makefile の基本的な利用法</h1>
<pre><code class="language-makefile">TARGET := prog
CC := /usr/bin/gcc
CFLAGS := -g -O2 -Wall
RM := /bin/rm
$(TARGET): main.c
$(CC) $(CFLAGS) $< -o $@
clean:
$(RM) -rf $(TARGET)
all: $(TARGET)
.PHONY: all clean</code></pre>
<p>上記は最も基本的な Makefile の記述のひとつ。 ひとつひとつ見ていく</p>
<h2 id="makefile-の変数">Makefile の変数</h2>
<p>Makefile はシェル変数とは別に独自の変数を持つ。<code>:=</code> で変数を定義し,<code>$(VAR)</code> のように記述して展開する。 また,変数は <code>=</code> でも定義が可能だが,<code>:=</code> と <code>=</code> は定義式の評価のタイミングが異なるなど差異が存在する。 具体的には <code>=</code> を用いると値が決まるのが実際に参照されるときになる。 Makefile のタスクの中でシェルの環境変数($PATH など)を展開したい場合は <code>$$PATH</code> のように <code>$</code> をエスケープする必要がある。</p>
<p>Makefile の変数は <code>:=</code> の代わりに <code>+=</code> を使うことで,既に存在する変数に追記することができる。</p>
<p>また,Makefile(とくに GNU Make)には多種多様な関数や機能が用意されている。一例として,</p>
<pre><code class="language-makefile">SRC := main.c test.c test2.c
OBJS := $(SRC:.c=.o)</code></pre>
<p>と記述すると,<code>$(OBJS)</code> の中身は <code>main.o test.o test2.o</code> になる。</p>
<h2 id="makefile-のタスク">Makefile のタスク</h2>
<p>タスクは <code>ターゲット: 依存先</code> という風に記述する。最初の節にある Makefile の例をみてみると,</p>
<pre><code class="language-makefile">$(TARGET): main.c
$(CC) $(CFLAGS) $< -o $@</code></pre>
<p>と書いてある。この中に書いてある変数を全部展開すると,</p>
<pre><code class="language-makefile">prog: main.c
gcc -g -O2 -Wall main.c -o prog</code></pre>
<p>となる。つまり,<code>prog</code> という実行ファイルは,<code>main.c</code> というファイルに依存しているという記述である。このタスクの中身は,タスクの依存関係の次の行からインデントしてシェルスクリプトを記述することになる。この例では</p>
<pre><code class="language-bash">$(CC) $(CFLAGS) $< -o $@
</code></pre>
<p>となっている部分である。タスクが複数行ある場合は,</p>
<pre><code class="language-makefile">target: deps
mkdir -p test
cd test && touch testfile.txt
</code></pre>
<p>のように全てインデントを行なう。注意しなければならないのは,このインデントはソフトインデント(半角スペース)ではなくハードインデント(タブ文字)でなくてはならない。また,このタスクは実際には</p>
<pre><code class="language-makefile">target: deps
sh -c "mkdir -p test"
sh -c "cd test && touch testfile.txt"</code></pre>
<p>のように一行ごとにシェルが別々に起動して実行されるため,</p>
<pre><code class="language-makefile">target: deps
mkdir -p test
cd test
touch testfile.txt</code></pre>
<p>と記述すると意図通り動作せず失敗してしまう。</p>
<h2 id="makefile-の疑似ターゲット">Makefile の疑似ターゲット</h2>
<p>例示した Makefile では <code>.PHONY: all clean</code> と記述してあり,また,依存が存在しないタスク <code>clean</code> や <code>$(TARGET)</code> を依存に指定するタスク <code>all</code> が記述してある。<code>.PHONY:</code> で指定したタスクは擬似的なターゲットである。</p>
<p>これは <code>all</code> や <code>clean</code> といった名前のファイルを作るタスクではないことを明示している。というのも,Makefile のタスクは一般的にターゲットと同じファイル名のファイルを生成するタスクを記述するツールであるためだ。</p>
<p>Makefile の挙動として,タスクのターゲットに指定しているファイル名が存在しないとき,または依存先が更新されていた場合,このどちらかが真であればタスクが実行されるということになっている。しかし,プロジェクトのビルドではなく,この <code>clean</code> ターゲットのようにただのタスクを記述したいときにそれでは不便なため,このように <code>.PHONY:</code> を用いて擬似的なターゲットを作ることで解決している。</p>
<p>ちなみに,<code>make</code> コマンドは引数にターゲットを指定するが,引数を渡さずにただ <code>make</code> とだけ打った場合は暗黙的に <code>make all</code> を実行したことと同じと見なされる。</p>
<h2 id="makefile-の特殊な変数">Makefile の特殊な変数</h2>
<p>Makefile のタスクの例にて,<code>$<</code> や <code>$@</code> という変数を利用した。これは Makefile が自動的に定義する特殊な変数である。</p>
<pre><code class="language-makefile">TARGET: DEP1 DEP2
なんかのタスク</code></pre>
<p>というタスクを用意したときに,<code>$@</code> は <code>TARGET</code> として展開される。また,<code>$^</code> は <code>DEP1</code> として展開され,<code>$<</code> は <code>DEP1 DEP2</code> という風に展開される。他にも自動変数は複数あるが,基本的にこのみっつを覚えておけば良い。</p>
<h2 id="makefile-の発展的な記述方法サフィックスルール">Makefile の発展的な記述方法:サフィックスルール</h2>
<pre><code class="language-makefile">TARGET := prog
CC := gcc
CXX := g++
CFLAGS := -g -O2 -Wall
CXXFLAGS := $(CFLAGS)
LD := ld
LDFLAGS := -lc -lm -lpthread
SRCS := main.c library1.c library2.c
OBJS := $(SRCS:.c=.o)
.SUFFIXES:
.SUFFIXES: .c .o
.PHONY: all
all: $(TARGET)
.c.o:
$(CC) $(CFLAGS) -c $^ -o $@
$(TARGET): $(OBJS)
$(LD) $(LDFLAGS) $< -o $@</code></pre>
<p>Makefile の発展的な記法として <em>サフィックスルール</em> が存在する。 上記の Makefile を見てほしい。</p>
<p><code>make</code> コマンドを実行したとき,自動で <code>all</code> ターゲットを実行するため,この場合は <code>all: $(TARGET)</code> という疑似ターゲットによる依存関係をみて,<code>$(TARGET): $(OBJS)</code> という依存関係が記述されたターゲットのタスクを実行することになる。</p>
<p>しかし,この時依存関係には <code>$(OBJS)</code> しか書いていない。この <code>$(OBJS)</code> 変数はこの定義だと <code>main.o library1.o library2.o</code> と展開されるが,この <code>.o</code> 拡張子を持つオブジェクトファイルをどのソースコードからどう生成するかという依存関係は一切記述されていないのである。</p>
<p>これは実は,<code>.c.o:</code> と書かれているターゲットで解決される。これをサフィックスルールと呼び,この場合,<code>.o</code> という拡張子であれば自動的に同名で拡張子が <code>.c</code> となっているファイルから生成するよ,ということを言っている。</p>
<p>このサフィックスルールの場合は gcc に <code>-c</code> オプションを追加しているため,結果としてソースコードが 1 ファイル単位でオブジェクトファイルにコンパイルされ,<code>$(TARGET): $(OBJS)</code> のタスクでは生成された全てのオブジェクトファイルを <code>ld</code> コマンドによってリンカーがリンクしているのである。</p>
<p>この方法だと,複数のソースコードのうち一つのファイルだけが変更された時,そのファイルのコンパイルと全体のリンクだけが走り,全てのファイルを全てコンパイルしなおさなくて済む(=差分コンパイルが可能)という点でメリットがある。</p>
<h1 id="makefile-の-task-runner-としての利用方法">Makefile の task runner としての利用方法</h1>
<p>基本的には前章で説明した方法を応用し,疑似ターゲットを作りつつそのターゲットに依存関係を追加すれば,プロジェクトのビルド以外の仕事も依存関係を考慮して実行できるということになる。</p>
<p>次に示すのは Markdown で記述されたファイルを LaTeX へ変換した上で PDF へ typeset(コンパイル)するタスクと,<code>make preview</code> によって生成した PDF を PDF ビューワーで閲覧するタスクが定義してある筆者作の Makefile である。</p>
<p>実際には LaTeX には <code>latexmk</code> という Perl 製の便利な typeset スクリプトが標準に存在するため,実際に LaTeX を記述する際には PDF の閲覧にも typeset にもそちらを用いてほしい。あくまで Makefile の応用の一例である。</p>
<pre><code class="language-makefile">TEX=platex
PANDOC=pandoc
BIBTEX=pbibtex
DVI2PDF=dvipdfmx
TEX_FLAGS= --shell-escape -kanji=utf8 -kanji-internal=utf8 -interaction=batchmode
UNAME=$(shell uname)
ifeq $($(UNAME), Darwin)
VIEWER=open
else ifeq $($(UNAME), Linux)
VIEWER=xdg-open
else ifeq $($(OS), Windows_NT)
VIEWER=start
endif
TARGET=paper
COUNT=3
SOURCE = manuscript.tex
MDSCRIPTS = src/abstract.md src/contents.md
TEXFILES=$(MDSCRIPTS:.md=.tex)
DVIFILE=$(SOURCE:.tex=.dvi)
BIBFILES=cite/paper.bib
REFSTYLES=sty/crossref_config.yaml
PANDOC_FLAGS= --smart -f markdown+pipe_tables -t latex --filter pandoc-crossref --natbib
PANDOC_FILTER_FLAGS= -M "crossrefYaml=$(REFSTYLES)"
.SUFFIXES: .tex .md .pdf
.PHONY: all semi-clean clean preview
all: $(TARGET).pdf semi-clean
.md.tex:
@cat $< \
| $(PANDOC) --verbose $(PANDOC_FLAGS) $(PANDOC_FILTER_FLAGS) \
| sed 's/.png/.pdf/g' \
| sed 's/includegraphics/includegraphics[width=1.0\\columnwidth]/g' \
| sed 's/\[htbp\]/[t]/g' \
> $@
$(TARGET).pdf: $(TEXFILES)
@cd tex && for i in `seq 1 $(COUNT)`; \
do \
$(TEX) $(TEX_FLAGS) $(SOURCE); \
if [ ! -e "$(SOURCE:.tex=.blg)" ]; then \
$(BIBTEX) $(basename $(SOURCE)); \
fi \
done
cd tex && $(DVI2PDF) -o ../$(TARGET).pdf $(DVIFILE) 2> /dev/null
semi-clean:
@cd tex && rm -f *.aux *.log *.out *.lof *.toc *.bbl *.blg *.xml *.bcf *blx.bib *.spl
clean: semi-clean
@rm -f $(TARGET).pdf $(DVIFILE) $(TEXFILES)
preview:
@$(VIEWER) $(TARGET).pdf 2> /dev/null
</code></pre>
<p>ちなみに,タスクの先頭に <code>@</code> がついてる行があるが,これを行うと実行したコマンドが表示されなくなる。</p>
oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-56258963279223418862019-05-29T19:01:00.004+09:002019-07-22T15:42:46.459+09:00計算機科学(一部分野)の論文の探しかた・投稿先の探しかたGoogle scholar や CiNii で検索しろなどという論文一般の探しかたはもう言われ尽くしてるので,CS(の一部の分野)に限った話をします。
<h2>論文</h2>
<p>まず論文の探しかたとして,<a href="https://jeffhuang.com/best_paper_awards.html">https://jeffhuang.com/best_paper_awards.html</a> が 1996 年以降のベストペーパーを分野を横断して掲載しています。
分野ごとにトップカンファレンス 1 つしか掲載していないので網羅的ではないですが,面白い論文を探してるのなら手軽に探せると思います。
</p>
<p>
なんならここから見つけた会議名や論文についてる reference から芋蔓で他の論文探せますしね。
</p>
<p>
あとは <a href="https://ieeexplore.ieee.org">IEEE Xplore</a> や <a href="https://dl.acm.org">ACM Digital Library</a> で検索するととてもよいですね。
IEEE や ACM が主な戦場ではない CS の分野はたくさんあると思いますが,私はそれらについて詳しくないので詳しい人に任せます。
</p>
<p>
また,検索した論文のカンファレンスが分野でどのぐらいの位置付けなのか,あるいは,この分野についてどういうカンファレンスをみればよいのか,というので,
<ul>
<li><a href="http://www.conferenceranks.com">Conference Ranks</a></li>
<li><a href="http://www.guide2research.com/topconf/">Guide2Reserch</a></li>
</ul>
これらのようなカンファレンスのランクが検索できるようなサイトでカンフェレンスの格付けが確認できます。
ジャーナルについてもランクが出てきますが。
</p>
<p>
最後に,普段から読んでる論文を <a href="https://www.mendeley.com">Mendeley</a> に登録しましょう。Mendeley が論文を suggest してくれるようになります。
なんならたまにメールとかで suggest をまとめて送ってくれます。
</p>
<h2>投稿先</h2>
<p>先程も出したカンファレンス格付けサイト,これはひとつの参考になります。また,これは完全に OS や DB といった CS のうちシステム系に限定した話なのですが,
</p><p>
<a href="http://www.cs.technion.ac.il/~dan/index_sysvenues_deadline.html">http://www.cs.technion.ac.il/~dan/index_sysvenues_deadline.html</a>
</p><p>
テクニオン(イスラエル工科大学)の Dan Tsafrir 准教授がまとめていらっしゃるこのサイトが非常に有用です。
システム系の主要な会議が網羅的に書いてある上に,それぞれの締切日と開催日が載っています。</p>
<h2>追記</h2>
<p>
OS 系会議リスト <a hrerf="https://www.os.ecc.u-tokyo.ac.jp/conf.html">https://www.os.ecc.u-tokyo.ac.jp/conf.html</a> <br />
東大の品川准教授によるリスト。Tsafrir 准教授のものよりさらに OS に絞ってあるので,システム系でも特に OS 分野だけに絞るのならこっちのほうが見易そうですね。
紹介ありがとうございました。
</p>
<p>
セキュリティ系の会議リスト<br />
阪大宮地研究室が公開しているリスト <a href="https://cy2sec.comm.eng.osaka-u.ac.jp/miyaji-lab/announce/ranking-jp.html">https://cy2sec.comm.eng.osaka-u.ac.jp/miyaji-lab/announce/ranking-jp.html</a> や
テキサス A&M 大学の Guofei Gu 教授が公開しているリスト <a href="http://faculty.cs.tamu.edu/guofei/sec_conf_stat.htm">http://faculty.cs.tamu.edu/guofei/sec_conf_stat.htm</a>
があるそうです。須崎先生,紹介ありがとうございました。
</p>
<p>
<blockquote class="twitter-tweet" data-conversation="none" data-lang="ja"><p lang="ja" dir="ltr">よかったら、こちらもご参照ください。OS 系の国際会議をリストアップしています。<a href="https://t.co/Ti6M0WEK9x">https://t.co/Ti6M0WEK9x</a></p>— 品川 高廣 (@utshina2) <a href="https://twitter.com/utshina2/status/1133874762210598913?ref_src=twsrc%5Etfw">2019年5月29日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote class="twitter-tweet" data-conversation="none" data-cards="hidden" data-lang="ja"><p lang="ja" dir="ltr">OS 系の国際会議をリストは参考人させていただいてます。<a href="https://t.co/PszRQST3DK">https://t.co/PszRQST3DK</a> <br><br>その他、つい最近参考にした国際会議リスト(セキュリティ系)<br>大阪大学宮地研学会ランキング <a href="https://t.co/8uBoYqLiRL">https://t.co/8uBoYqLiRL</a><br>"Computer Security Conference Ranking and Statistic" by Guofei Gu<a href="https://t.co/NKo02vqZ2w">https://t.co/NKo02vqZ2w</a></p>— suzaki (@KuniSuzaki) <a href="https://twitter.com/KuniSuzaki/status/1133892001802272769?ref_src=twsrc%5Etfw">2019年5月30日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</p>
<p>
<iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=orumin-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=4121006240&linkId=c836086b7913a8bc8ecc13215d322d00"></iframe>
<iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=orumin-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=4061531530&linkId=5017ec889d0368d1a9d27c4bf1e902d2"></iframe>
<iframe style="width:120px;height:240px;" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" src="//rcm-fe.amazon-adsystem.com/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=orumin-22&language=ja_JP&o=9&p=8&l=as4&m=amazon&f=ifr&ref=as_ss_li_til&asins=4815809232&linkId=bed32ee543170c976e37f3879d6cc547"></iframe>
</p>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-63862940159558448642019-05-29T00:00:00.002+09:002019-05-29T19:03:13.092+09:00コマンドラインでメール/GPG で暗号化と復号<p>
<code>msmtp</code> と <code>msmtp-mta</code> をインストールすると <code>sendmail</code> 互換のコマンドが生えるため CLI からメールがサクっと送れる。
これは Git で ML に patch に送る際に便利である。
</p>
<p>
<pre><code class="language-bash">defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-bundle.crt
logfile ~/.msmtp.log
account gmail
host smtp.gmail.com
port 587
from example@gmail.com
user example
passwordeval "gpg --quiet --for-your-eyes-only --decrypt ~/.msmtp-gmail.gpg"
account outlook
host smtp.office365.com
port 587
from example@outlook.com
user example@outlook.com
passwordeval "gpg --quiet --for-your-eyes-only --decrypt ~/.msmtp-outlook.gpg"
account default : gmail
</code></pre>
こういう風に設定を書いておけばよい。
また,この際に password に平文でパスワードを書くこともできるが,passwordeval として暗号化されたファイルを復号するコマンドを記述すると,
パスワードを暗号化し別に扱えるので便利である。
</p>
<p>
さて,ここで GPG の暗号化なのだが,暗号化のコマンドは以下の通り
<pre><code class="language-bash">➤ gpg --encrypt -o ~/.msmtp-gmail.gpg -r example@gmail.com -
password
^D
</code></pre>
<code>-r</code> に指定するメールアドレスは自分の GPG 秘密鍵に登録してあるメールアドレスである。
コマンドの末尾に <code>-</code> を指定しているので標準入力から暗号化するテキストを入力することになり, <code>Ctrl-D</code> で入力を打ち切る。
この例では「password」という文字列を暗号化して <code>~/.msmtp-gmail.gpg</code> に保存することになる。
</p>
<p>
しかしここでハマりポイントがある。
<pre><code class="language-text">gpg: XXXXXXXX: There is no assurance this key belongs to the named user</code></pre>
などと言われる場合だ。他所のマシンから秘密鍵を持ってきて import したときなどに起きる。
これは自分の鍵を信用する設定にし忘れているため,
<pre><code class="language-bash">➤ gpg --edit-key XXXXXX</code></pre>
と鍵のシグネチャを指定し edit-key をすれば良いのだが,
<pre><code class="language-text">gpg: can't do this in batch mode</code></pre>
と言われるのだ。これは昔には起きなかった気がする(どうして……)
</p>
<p>
<pre><code class="language-text">➤ gpg --command-fd 0 --status-fd 1 --expert --edit-key XXXXXXXXX
[GNUPG:] KEY_CONSIDERED XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 0
Secret key is available.
...(略)...
[GNUPG:] GET_LINE keyedit.prompt
trust
[GNUPG:] GOT_IT
...(略)...
Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)
1 = I don't know or won't say
2 = I do NOT trust
3 = I trust marginally
4 = I trust fully
5 = I trust ultimately
m = back to the main menu
[GNUPG:] GET_LINE edit_ownertrust.value
5
[GNUPG:] GOT_IT
[GNUPG:] GET_BOOL edit_ownertrust.set_ultimate.okay
y
[GNUPG:] GOT_IT
...(略)...
[GNUPG:] GET_LINE keyedit.prompt
quit
[GNUPG:] GOT_IT
</code></pre>
このように, <code>--command-fd</code> と <code>--status-fd</code> などをそれぞれ標準入力,標準出力にし,あとは,「trust 5 y quit」と順番にコマンドを入れていけばよい。
</p>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-87709507413250051752019-02-22T17:57:00.003+09:002020-08-24T13:17:41.377+09:00デュアルブート環境で Bluetooth を使いたい!<h2>問題</h2>
<p>
Windows と Linux のどちらか片方でしかペアリングができない。
これは,Windows と Linux でデュアルブートする際, Bluetooth のインターフェースを共有することに起因する。
Bluetooth のペアリングは,ある MAC アドレスの Bluetooth インターフェースに対して Bluetooth 周辺機器がペアリングすることになるため,片方の OS でペアリングしてしまうと,もう片方の OS ではまだペアリングしていないのに周辺機器は「ペアリング済」と判断してしまう,ということである。
周辺機器側でペアリング登録の解除が可能ならば(たとえば iPhone はペアリング済みのホストを一覧・解除できる)両方の OS でペアリング動作は行えるものの,両方の OS でペアリングに使うキーが異なってしまう。しかし,周辺機器が特定の MAC アドレスの Bluetooth インターフェースに対して記憶するペアリングキーは当然ひとつだけである。</p>
<h2>解決方法</h2>
<p>Linux ならテキストファイル,Windows ならレジストリにペアリングキーが書き込まれる。片方の OS でこれを閲覧して,もう片方の OS のペアリングキーを上書きしてしまえば良い。</p>
<h2>手順</h2>
<p>まず,Linux でペアリングする。次に,Windows でペアリングしなおす。この時点で Linux で接続が失敗するようになる。</p>
<p>ここからがミソである。Linux を起動し,<code>chntpw</code> をインストールする。これは,Windows のレジストリファイルを編集することが可能なコマンドである。</p>
<p>たとえば,Windows の C ドライブにあたるパーティションを /media にマウントしていた場合,
<pre><code>$ chntpw -e /media/Windows/System32/config/SYSTEM
chntpw version 1.00 140201, (c) Petter N Hagen
Hive </media/Windows/System32/config/SYSTEM> name (from header): <SYSTEM>
ROOT KEY at offset: 0x001020 * Subkey indexing type is: 686c <lh>
File size 23855104 [16c0000] bytes, containing 5166 pages (+ 1 headerpage)
Used for data: 368592/23358472 blocks/bytes, unused: 17/28216 blocks/bytes.
Simple registry editor. ? for help.
> cd ControlSet001\Services\BTHPORT\Parameters\Keys
(...)\Services\BTHPORT\Parameters\Keys> ls
Node has 1 subkeys and 0 values
key name
<deadbeef0000>
(...)\Services\BTHPORT\Parameters\Keys> cd deadbeef0000
(...)\BTHPORT\Parameters\Keys\deadbeef0000> ls
Node has 0 subkeys and 3 values
size type value name [value if type DWORD]
16 3 REG_BINARY <0123456789ab>
(...)\BTHPORT\Parameters\Keys\deadbeef0000> hex 0123456789ab
Value <0123456789ab> of type REG_BINARY (3), data length 16 [0x10]
:00000 XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX ..R..D.Yb.q.M<j.
</code></pre>
ここで deadbeef0000 は Bluetooth インターフェースの MAC アドレス,0123456789ab はペアリングした Bluetooth 周辺機器の MAC アドレスである。
これは各自の環境の値に置き換えてほしい。
ここで,最後に出てきた <code>XX XX XX XX .. XX </code> となっている部分,これが実際には 16 進数 32 ケタで記述されたペアリングキーである。
これら,<b>インターフェースの MAC</b>,<b>周辺機器の MAC</b>,<b>ペアリングキー</b> の組をメモしたら,次のステップである。
</p>
<p>最後に, <code>/var/lib/bluetooth/<インターフェースの MAC>/<周辺機器の MAC>/info</code> を編集する。
このファイルの [LinkKey] セクションにある Key= の部分を,メモしたペアリングキーに置き換える。
その後に,<pre><code>systemctl restart bluetooth</code></pre> とすればおっけー。これで Linux でも Windows でも接続できるはずである。</p>
<h2>追記</h2>
<p>BLE の場合,LinkKey でなくいくつか複数の値が必要な模様 <a href="https://unix.stackexchange.com/questions/402488/dual-boot-bluetooth-device-pairing">https://unix.stackexchange.com/questions/402488/dual-boot-bluetooth-device-pairing</a>。 </p>
<p>具体的には
<ul>
<li>IRK を [IdentityResolvingKey] の Key= へ</li>
<li>CSRK を [LocalSignatureKey] の Key= へ</li>
<li>LTK を [LongTermKey] の Key= へ</li>
<li>ERand を Rand へ。ただし,たとえば 16 進数で ab cd ef とあればこれを逆順にした (ef cd ab) 上で 10 進数に変換する必要アリ</li>
<li>EDIV を EDiv へ。ただし 16 進数から 10 進数へ変換する必要アリ</li>
</ul>
</p>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.comtag:blogger.com,1999:blog-321269773403689954.post-8833532182394630142018-12-28T18:40:00.002+09:002018-12-28T18:40:59.653+09:00gdb で子プロセスを追い掛ける<pre><code class="language-bash">(gdb) set follow-fork-mode child</code></pre>oruminhttp://www.blogger.com/profile/14336376848351277656noreply@blogger.com