憂鬱な午後のひととき
ファイル名のUnicode正規化で気を付けること
Unicodeでは同じコードポイントでも異なるバイト列になっていることがある.
そのため人名などの検索では事前にNFCなどによって正規化してから行うことが多い.
ところがファイル名も同じ感覚でやってしまうと困ることがある.
なぜならWindowsでは, ファイルシステム上結合文字列と合成文字列を区別しているから.
たとえば次のC++のコード
#include <stdio.h>
#include <string>
#include <fstream>
int main()
{
const wchar_t tbl[][10] = {
{ 0x01d6 },
{ 0x00fc, 0x0304 },
{ 0x0075, 0x0308, 0x0304 },
{ },
};
for (const wchar_t *file : tbl) {
std::wofstream f(file, std::ios::binary);
}
}
を実行するとカレントディレクトリにǖ(U+01D6)というコードポイントのファイルが3個できる.
3個ともNFCすると同じコードポイントになるのにファイルシステムとしては別のものなのだ.
// python
import unicodedata
for x in [u'\u01d6', u'\u00fc\u0304', u'\u0075\u0308\u0304']:
print hex(ord(unicodedata.normalize('NFC', x)[0]))
>python t.py
0x1d6
0x1d6
0x1d6
それからNFCは一部の文字を別のものに置き換えてしまう.
有名なのでは神(U+795E)と神(U+FA19)がある.
こういう名前のファイルを作ることはできるがNFCすると同じものになる.
import unicodedata
for x in [u'\u795e', u'\ufa19']:
print unicodedata.normalize('NFC', x)
>python t.py
神
神
冒頭で書いたように「神」で検索して「神」がマッチしても問題になることは少ない(少なくとも取りこぼすことはない)けど,
異なるファイルを同じと思ってしまうと問題だ.
Macのファイルシステムではファイル名はNFDされたものが使われる.
だからWindowsとMacで「同じファイル名」というのをどう定義するかとても難しい.
そもそもそれらのファイル名文字列全体が同じ集合ではない.
というわけで対象によってどのように文字を扱うかを変えないといけないのがとても悩ましい.
VMwareでsuspend
しばらく前からVMwareのゲストOSをsuspendしようとすると,
「この仮想マシンへのサスペンド要求は、
対応する VMware Tools スクリプトが正常に実行されなかったため失敗しました。(略)」
というメッセーが出るようになっていた.
もう一度suspendさせると正常にできるのでほっておいたが,
ゲストOSで
sudo vmware-toolbox-cmd script suspend disable
とすればよかったようだ(無視してるのだからいいのかは知らない).
『ダーリンの頭ン中』(小栗左多里&トニー・ラズロ)
英語と違ってひらがなと発音がほぼ一対一に対応している日本語.
ただ連声や鼻母音ぐらいの例外だけと思っていたけど, 結構いろいろ音は違うらしい.
「するめ」の「す」と「です」の「す」とか. へえ, そうなんだ.
>日本語には「手首から先」や「足首から先」を表す言葉がないよね
そんなことは無いと思う.
まさに「手」や「足」がそこを表す言葉だよね.
足の首(上の方)だから足首なんだし.
デバッグ
結構てこずってたけど18日のバグの原因がやっと判明.
ちょっと疲れた.
『盤上の夜』(宮内悠介)
うーん, 残念ながら期待してたのとちょっと方向が違って私にはあまりピンとこなかった.
傍点強調は, それに何か意味があるのか立ち止まって考えてしまうので多用されると読むリズムがくずれて辛い.
vector_execution_policy
Changes to vector_execution_policyを教えてもらった.
20日に書いたように, やっぱParallelアルゴリズムの実行ポリシーにvecのみも必要だよという提案.
スケジュール的に現状のTSは用語の一部だけが反映されている感じ.
- Sequential : 何の並列実行もしない. 要素のアクセス順序は完全に保証される.
- Task Parallel : スレッドを起こして実行する. 一切の順序は保証されない. 同期機構や例外は使える.
- Vector Parallel : SIMD単位を越えての逐次性(定義はもうちょっと別のいいかた)は保証する. 同期機構や例外は使えない.
- Parallel + Vector : その両方
いろいろ議論はされていたようだが,
マルチコアプログラミングよりSIMDの方が有利なケースなんてざらにあるだろうになんでvecが抜け落ちたのか.
C++ parallel TS Working Draft
ざっくりとした説明というか訳を書いた.
以前yohhoyさんが新しい並列for構文のご提案で書かれたときとまたちょっと変わってる.
指定できるポリシーがseq(シーケンシャル)とpar(並列)とpar_vec(並列+ベクトル)だけ.
ベクトル化だけやってくれればいい, スレッドはこちらで制御したいケースってあると思う.
単なるvecは必要だよなあ.
デバッグ
なんか落ちるらしいので調査依頼がきて調べる.
コードが悪いのかコンパイラが悪いのか.
でかいコードなので突き詰めるの大変だなあ.
TSXのバグ
HSW136.
Under a complex set of internal timing conditions and system events, software using
the Intel TSX (Transactional Synchronization Extensions) instructions may result in
unpredictable system behavior.
HSW1. TSX instruction
Due to Erratum HSw136, TSX instructions are disabled and are only supported for
software development. See your Intel representative for details.
今のところTSXオフにするしかないらしい.
鳴り物入りの機能だったのに大変だ.
プロファイル
ある処理がとても重たいのだけど何が原因だかわからない.
しかし入力数を線形で増やすと処理時間がO(n2)っぽい挙動をしていることが分かった.
O(n)なはずなのでどこかがおかしなことしてるのだろう.
こういうのはプロファイラなどのツールで平均化されてしまった値を見るだけではわからない.
複数の手段を用いて推測するのが大事だな.
hotspots
システムで何が時間を食ってるのかみたい場合, やっぱりGUIでやりたい.
VTune Amplifier XEがとても便利だった.
コマンドラインでも使うことができる.
amplxe-cl -collect hotspots -analyze-system <ターゲット>
とかやってできたファイルを別のマシンに持って行ってそちらでGUIでポチポチもできる.
特定のアドレスが食ってると分かったらその場所を探す.
そのプロセスdaemonのmapsを見るとどのモジュールの中かある程度分かる.
cat /rpoc/<pid>/maps
アドレスとマップされてるモジュールの範囲から, 11日のようにoffsetを求めてdisasして追いかければよい.
daemonのcore
daemonはcoreファイルの出力権限が無かったりすると出ない.
/proc/sys/kernel/core_patternで出力先を変えられるので
sudo sh -c 'echo /tmp/core.%e.%p > /proc/sys/kernel/core_pattern'
などとするとよい.
ついでにアドレスがASLRによりランダムになると分かりにくいのでデバッグのときだけ
/proc/sys/kernel/randomize_va_spaceを0にするとよいかも.
dmesgのsegfaultのerrorの意味(その2)
dmesgに出てるerrorの4はエラーの種類を示していてlinux/arch/x86/mm/fault.cに書かれている.
/*
* Page fault error code bits:
*
* bit 0 == 0: no page found 1: protection fault
* bit 1 == 0: read access 1: write access
* bit 2 == 0: kernel-mode access 1: user-mode access
* bit 3 == 1: use of reserved bit detected
* bit 4 == 1: fault was an instruction fetch
*/
これらのbitのorとなっている. 4 = 0b100はbit 0が0なのでpageが割り当てられていない, bit 1が0なのでreadエラー,
bit 2が1なのでuser-modeのアクセスだったことが分かる.
典型的ないくつかの例を出してみよう.
// NULL読み込み
int a = *(int*)0; // error 4 = no page found + read access + user-mode access
// NULL書き込み
*(int*)0 = 3; // error 6 = no page found + write access + user-mode access
// read onlyなメモリへの書き込み
char *s = "abc"; s[0] = 5; // error 7 = protection faulse + write access + user-mode-access
これだけでも知ってると何かと役に立つかもしれない.
dmesgのsegfaultのerrorの意味(その1)
プログラムを走らせたら
a.out[32428]: segfault at 0 ip 00007f9a268917e4 sp 00007fffec8338e0 error 4 in libc-2.19.so[7f9a26823000+1bc000]
となった.
さてこれから分かるのはなんだろう.
まずlibcの中で落ちたことは分かる.
segfault at 0なのでNULLアクセスしたらしい.
libcが7f9a26823000からmappingされているのでipとの差を求めればオフセットがでる.
print hex(0x00007f9a268917e4-0x7f9a26823000)
0x6e7e4
/lib/x86_64-linux-gnu/libc-2.19.soを逆アセンブルして0x6e7e4のあたりを見よう.
dis /lib/x86_64-linux-gnu/libc-2.19.so ; objdump -CSlw -M intelのalias
000000000006e7e0 <_IO_fclose>:
_IO_new_fclose():
/build/buildd/eglibc-2.19/libio/iofclose.c:40
6e7e0: 41 54 push r12
6e7e2: 55 push rbp
6e7e3: 53 push rbx
/build/buildd/eglibc-2.19/libio/iofclose.c:54
6e7e4: 8b 17 mov edx,DWORD PTR [rdi] ; ここ
/build/buildd/eglibc-2.19/libio/iofclose.c:40
6e7e6: 48 89 fb mov rbx,rdi
fclose()の中でrdiが0で読もうとしたことが分かる.
実は元のコードは
#include <stdio.h>
int main()
{
fclose(NULL);
}
というものだった.
二度寝
最近夜中に目が覚めることが多くて慢性的な寝不足なんだけど, 寝たいときに寝られなかった.
今日はあまりに疲れてぐたっと寝た. というか体が動かなかった.
久しぶりにぐっすり寝たという感じ.
本社創業記念祭
キッズルームというのがあった.
本社の方のお子さんが何人か預かってもらってるというので行ってみた.
みんな走り回って元気だなあ.
vEB tree
以前, @iwiwiさんのCache-Obliviousデータ構造入門を聞いて面白かったのでvEB treeがどんなものか写経しながら勉強する.
TokuDBが採用しているFractal Tree indexがそれベースと聞いていたし.
だけど, Wikipediaによると初めはcache-obliviousだったけど,
今はBε木の拡張だと書かれていてなんだってー, という感じ.
今度はそちらを勉強してみるか.
『長い冬』(ローラ・インガルス・ワイルダー 鈴木哲子訳)
なんか実家帰ってる度についつい読み返してしまう.
ついでではないけど『玻璃の天』(北村薫)も. どちらもたまたま冬の話だ.
読んでるときは暑さを忘れる.
夏の「鰍沢」だな.
昔
御意見は光成滋生<herumi@nifty.com>までお願いします