kubo39's blog

ただの雑記です。

D言語の数値まわりの字句解析のはなし

仕様はここにある https://dlang.org/spec/lex.html#Integer

これをみると、 0b_ はBinaryIntegerとして表現可能なリテラルとなる。

import std.stdio;

void main()
{
    writeln("0b_: ", 0b_);
    writeln("0b________: ", 0b________); // _ がいくつあってもよい
}

結果は _ が何個あっても0になる。

(dmd-2.076.1)$ rdmd bin.d
0b_: 0
0b________: 0

しかし、 BinaryIntegerは 0b だけでも評価できてしまう。そのためこんなコードもコンパイルが通ってしまう。

import std.stdio;

void main()
{
    writeln("0b: ", 0b);
    writeln("0buL: ", 0buL);
}

結果はやはり0となる。

(dmd-2.076.1)$ rdmd bin.d
0b: 0
0buL: 0

また、 0x_HexadecimalInteger として表現できないリテラルであるが、実際にはコンパイルできてしまう。

import std.stdio;

void main()
{
    writeln("0x_: ", 0x_);
}

0b_ 同様、結果は値0となる。

(dmd-2.076.1)$ rdmd hex.d
0x_: 0

こちらも 0x0xuL のようなコードが実行できる。

import std.stdio;

void main()
{
    writeln("0x: ", 0x);
    writeln("0xuL: ", 0xuL);
}

結果:

(dmd-2.076.1)$ rdmd hex.d
0x: 0
0xuL: 0

社内勉強会でD言語とマイコンのはなしを発表した

スライド

Q&A

  • 組込みでDを使うメリットがあまりなかった、Rustのほうが筋がいいのでは?
    • たしかにそうなんですよね
  • Cのライブラリを使わなかったのはなぜ?
    • プリプロセッサマクロがふんだんに使われているので、どうせなら全部自前で実装したほうがはやかった

雑談

ちょっと話をどうふるべきか迷った感がある。メモリ安全も例外もラインタイムも標準ライブラリもない状態なのでエレガントにコードが書けるよ、みたいなのに全般的にふるべきだった気が。やはり文字列ミックスインは強力。

GC

そもそもGCは組み込み向きではないので、どうしたものかな。組込み向けのGCを作ればいいんじゃないか、という話があるがなんにせよ優先度は下がりそう。

例外

クラスベースの例外システムはほんとうに欲しいものなんだろうか。 それと例外の実装そのまま流用するのはdruntimeのオレオレ実装にしろucontext(3)にしろsetjmp(2)/longjmp(2)にしろaltstackを用意して、という話なので組込みと相性悪いんじゃないかと思っている。 assertくらいはほしくて、ユーザ定義な例外ハンドラに飛ばせるように、というイメージ。

ランタイム

GCも例外もランタイムなのだが。。まあdruntimeをそのままもってくるのはできないという話。少なくとも__tls_getaddr相当のものを実装する必要がある。libcに依存してしまえばいいのでは、というのもあるがその場合でもdruntime側にそうとう手を入れる必要があるので、なんともなあ。。

標準ライブラリ

標準ライブラリはアーキテクチャサポートの問題、libc依存の問題、バイナリサイズの問題、だいたいの実装でヒープが必要(これは実装すればいいだけ)な問題がある。全部サポートする気はないけどstd.mathはほしい。

emacsのD言語設定をひさしぶりにいじった

emacs 25.1.1でd-modeを使おうとするとなんかエラーが出てたので今までjava-modeを使っていたが、d-mode.elをM-x byte-recompile-fileすると動くようになったので、ついでにD言語設定をえいやっとやってしまった。 大した設定はしていなくて、

  • auto-completeベースのac-dcからcompany-modeベースのcompany-dcdへ移行した
  • DCDにパスを通して補完は以前と同じようにやってる

といった具合。

(require 'd-mode)

(setq auto-mode-alist (cons '("\\.d$" . d-mode) auto-mode-alist))
(setq load-path (cons "~/DCD/bin" load-path)) ;;;   DCDに load-path を通す

(require 'company-dcd)
(add-hook 'd-mode-hook
          (lambda ()
            (c-set-style "bsd")
            (setq c-basic-offset 4)
            (setq indent-tabs-mode nil)
            (setq tab-width 4)))

(provide 'init-d)

LDCのsanitizeオプション

LDCはバックエンドがLLVMであるので、sanitizerの機能が一部使える。 一応 address, fuzzer, memory, thread とあるけれど、手元のLDC 1.4.0でまともに使うことができたのはThreadSanitizerのみであった。

AddressSanitizer

asan/outofbounds.d

void main()
{
    auto arr = [0, 1, 2, 3];
    auto y = arr.ptr + 4;
}

これLeakSanitizerでひっかかってるけど、どうなんだ。

(ldc-1.4.0)$ ( cd asan && ldc2 -fsanitize=address -boundscheck=off outofbounds.d && ./outofbounds )

=================================================================
==7758==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 72 byte(s) in 1 object(s) allocated from:
    #0 0x55ecd0e3f5b0  (/home/kubo39/dev/dlang/ldc-san/asan/outofbounds+0xb75b0)
    #1 0x55ecd0e87ddc  (/home/kubo39/dev/dlang/ldc-san/asan/outofbounds+0xffddc)

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x55ecd0e3f3b8  (/home/kubo39/dev/dlang/ldc-san/asan/outofbounds+0xb73b8)
    #1 0x55ecd0e8876a  (/home/kubo39/dev/dlang/ldc-san/asan/outofbounds+0x10076a)
    #2 0x55ecd0d9b5e4  (/home/kubo39/dev/dlang/ldc-san/asan/outofbounds+0x135e4)

SUMMARY: AddressSanitizer: 88 byte(s) leaked in 2 allocation(s).

どうやらGCが入るとそもそもLeakSanitizerでひっかかるのでだめらしい。

void main()
{
}
(ldc-1.4.0)$ ( cd asan && ldc2 -fsanitize=address emptymain.d && ./emptymain )

=================================================================
==19717==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 72 byte(s) in 1 object(s) allocated from:
    #0 0x55934f6ffd90  (/home/kubo39/dev/dlang/ldc-san/asan/emptymain+0xb2d90)
    #1 0x55934f74cafc  (/home/kubo39/dev/dlang/ldc-san/asan/emptymain+0xffafc)

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x55934f6ffb98  (/home/kubo39/dev/dlang/ldc-san/asan/emptymain+0xb2b98)
    #1 0x55934f74d48a  (/home/kubo39/dev/dlang/ldc-san/asan/emptymain+0x10048a)
    #2 0x55934f660304  (/home/kubo39/dev/dlang/ldc-san/asan/emptymain+0x13304)

SUMMARY: AddressSanitizer: 88 byte(s) leaked in 2 allocation(s).

それでは、とGCを外してみるとAddressSantizerはちゃんと動いていないように見受けられる。

extern(C) void main()
{
    int[4] arr = [0, 1, 2, 3];
    auto y = arr.ptr + 10;
}
(ldc-1.4.0)$ ( cd asan && ldc2 -fsanitize=address outofbounds2.d && ./outofbounds2 )
(ldc-1.4.0)$

結論からいうと、-fsanitize=address はLeakSanitizerを有効にし、GCを起動するようなプログラムの場合は必ずリーク検出が発生してしまうようだ。

ちなみに -sanitize=memory の結果は以下のようになった。

(ldc-1.4.0)$ ( cd asan && ldc2 -fsanitize=memory emptymain.d && ./emptymain )
gcc: error: unrecognized argument to -fsanitize= option: ‘memory’
Error: /usr/bin/gcc failed with status: 1

ThreadSanitizer

tsan/datarace.d

import core.thread;

__gshared static int ANSWER = 32;

void f()
{
    ANSWER = 42;
}

void main()
{
    auto t = new Thread(&f).start();
    ANSWER = 24;
    t.join();
}

表示は質素だけど、競合条件を判定できている。

(ldc-1.4.0)$ ( cd tsan && ldc2 -fsanitize=thread datarace.d && ./datarace )
FATAL: ThreadSanitizer: unexpected memory mapping 0x56288abe3000-0x56288ac1b000

追記

いろいろ追試したところ、ThreadSanitizerも信頼できない。

(ldc-1.4.0)$ ldc2 -fsanitize=thread emptymain.d
(ldc-1.4.0)$ ./emptymain
FATAL: ThreadSanitizer: unexpected memory mapping 0x562d389a0000-0x562d389d7000

AddressSanitizerに至っては、いつのまにかリンカエラーでこけるようになっている。

(ldc-1.4.0)$ ( cd asan && ldc2 -fsanitize=address emptymain.d && ./emptymain )
/usr/bin/ld: /home/kubo39/dlang/ldc-1.4.0/lib/libldc_rt.asan-x86_64.a(asan_allocator.cc.o): 誤った再配置シンボル索引 (0x1fd8ca57 >= 0x11f) (オフセット 0x1fd8000000027079、セクション `.debug_loc' 内用) です
/usr/bin/ld: /home/kubo39/dlang/ldc-1.4.0/lib/libldc_rt.asan-x86_64.a(asan_allocator.cc.o): 誤った再配置シンボル索引 (0x1fd8ca57 >= 0x11f) (オフセット 0x1fd8000000027079、セクション `.debug_loc' 内用) です
/usr/bin/ld: 最終リンクに失敗しました: 不正な値です
collect2: error: ld returned 1 exit status
Error: /usr/bin/gcc failed with status: 1

GNU ld側の問題な気がするが、追求するのがおっくうになっている。どうせ現時点では使い物にならないだろう。

(ldc-1.4.0)$ ( LANG=C; cd asan && LD_DEBUG=reloc ldc2 -fsanitize=address emptymain.d && ./emptymain )
...
     22218:     relocation processing: /usr/lib/gcc/x86_64-linux-gnu/6/liblto_plugin.so
     22218:
     22218:     calling init: /usr/lib/gcc/x86_64-linux-gnu/6/liblto_plugin.so     
     22218:                                                                  
/usr/bin/ld: /home/kubo39/dlang/ldc-1.4.0/lib/libldc_rt.asan-x86_64.a(asan_allocator.cc.o): bad reloc symbol index (0x1fd8ca57 >= 0x11f)
 for offset 0x1fd8000000027079 in section `.debug_loc'                       
/usr/bin/ld: /home/kubo39/dlang/ldc-1.4.0/lib/libldc_rt.asan-x86_64.a(asan_allocator.cc.o): bad reloc symbol index (0x1fd8ca57 >= 0x11f)
 for offset 0x1fd8000000027079 in section `.debug_loc'                        
/usr/bin/ld: final link failed: Bad value                 
     22218:                                                                                  
     22218:     calling fini: /usr/lib/gcc/x86_64-linux-gnu/6/liblto_plugin.so [0]
     22218:                                       
...

SSDのはなし

ざっくり。基本的にSSDの特性はNANDの特性で、そこをファームのコントローラーがどのくらいサポートするかで製品の質が決まる。

寿命

  • NANDの寿命 - よく言われるのが書き換え回数

    • SLCだと約10万回
    • 書き換え回数 = イレース回数
      • ブロック単位で行われる(Linuxなんかでいうディスクブロックとは別もの)
    • これが多くなるとビットエラーが多くなったり
  • SSD readonlyの場合

    • readにも寿命がある(何百万回という単位だけど)
    • 何度もreadするとまわりのブロックに電荷の影響 -> ビット化けがおきる
    • 産業用だと定期的にリフレッシュかける機能を入れているものもある
  • データリテンション

    • NANDはデータを書き込んでも電源が入っていない状態のまま放置すると時間の経過とともにデータが化ける
    • 書いた後電源入れずにどのくらいもつかはだいたいの製品は出してる -> 約10年(SLC)
  • NANDは大容量化で品質落ちている

    • 大容量だと工夫しなくても平準化する
    • 負荷が特定のブロックに集中しないように
  • NANDは小さいデータに弱い

    • 穴あきになると効率よく使えない -> スペアブロックも穴あきになるから
    • ファイルの追記は大丈夫(ファイルシステムやバッファキャッシュが緩衝してる?)

故障原因

  • データは電源断で壊れる(SSDとして壊れるというのとは違う)
  • リード中壊れることはまずない(基本的にSSDというものはそれでは壊れない)

  • NANDが壊れるとは -> 論理と物理のアドレスマッピングができなくなる

    • 民製品ではSSDとして認識できなくなってしまう
    • 産業用だと壊れる前に戻ってはじめられるものもある
  • ECC訂正

    • エラー訂正
    • これで訂正できないものをアンクエラーとよぶ
    • アンクエラーまででるとそのブロックはもう使えない
    • スペアブロックがなくなれば書けなくなる
  • SSDマザーボードとの相性はある

    • 電源とか
    • クロック系は露骨に相性がわかる(明らかに遅いとか、そもそも認識しないとか)
  • NANDの物理ブロックは観測できない

    • 産業用だとbad blockを検出するツールを提供しているところはある
  • 一番こわいのはファームウェアの故障

    • OS更新時とか一気に書いてるときのの電源オフは避ける

FAQ?

  • どういうSSDがアプリケーションによいか?

    • 想定負荷をかけるしかない
  • 小さい単位でのランダムアクセスをどうやって観測するか?

    • バスアナライザを使うのが確実

静岡旅行

サッカー観戦ついでに一泊二日で静岡に行った。

1日目

勝ったので最高でした。パトリックのゴールシーンではゴール裏みな狂喜乱舞して最高だったし最高だった。

大庄水産です。

2日目

写真とかないけど、駿府城跡と日本平動物園に行った。 日本平動物園レッサーパンダとかジャガーとかゴマフアザラシが間近でみれて最高だった。

まとめ

静岡とにかく飯美味いし街並みもきれいだし最高なのでまた行きたい。

Rustでバイナリなライブラリ

最近いじるときにどっかに情報まとめとくといいかな、と思い。他にもあれば是非教えてください。