憂鬱な午後のひととき


12月30日_
Xbyakのcall(getCurr() + 5)が正しく動作しない(8bit相対jmpと勘違い)というバグを修正. 恥ずかしい.
12月28日_
言語雑談会って毎年参加してみたいと思っているのだが, 気づいたら終わってるぽい.
12月27日_
抜糸は痛くないと聞いていたが, 糸が塞ぎ掛けている傷口に入り込んでしまってたらしく, まだ痛いところをぐりぐりとされて拷問状態だった.
12月26日_
pairingのプログラム, Intelコンパイラで試してみたら若干遅くなってしまった. SIMD系なら絶対VCより速いと思ってたのに意外だ. ところでSSEではシフト命令のシフトの量に定数しか許されないものがある. たとえば
int a = 3;
_mm_srli_si128(x, a); // compile error
const int b = 5;
_mm_srli_si128(x, b); // ok
ちょっと奇妙だけど対応するニーモニックが存在しないので仕方ない(shlも即値とそうでないのとでニーモニックが違うし). こういうのはtemplateにして使う.
template<int n>
static __m128i psrldq(const __m128i& x)
{
    return _mm_srli_si128(x, n);
}
ただそうすると
template<int n>
void func()
{
    for (int i = 0; i < n; i++)
    {
        x = psrldq<i>(x);
    }
}
みたいなことができなくて困る. で, こういう場合は再帰templateを使う.
#include <stdio.h>

template<class P, int n, int i = n>
struct Loop {
    Loop(P& p)
    {
        p.template calc<n - i>();
        Loop<P, n, i - 1> run(p); // QQQ
//        Loop<P, n, i - 1>(p);
    }
};

template<class P, int n>
struct Loop<P, n, 0> {
    Loop(P&) { }
};

struct P {
    // ループ呼び出ししたい関数例(上記psrldqの代わり)
    template<int i>
    void calc()
    {
        printf("%d\n", i);
    }
};

int main()
{
    P p;
    Loop<P, 5> run(p);
}
実行結果が
0
1
2
3
4
なのはもちろん, asmソースは
  mov     esi, DWORD PTR __imp__printf
  push     0
  push     OFFSET msg
  call     esi
  push     1
  push     OFFSET msg
  call     esi
  push     2
  push     OFFSET msg
  call     esi
  push     3
  push     OFFSET msg
  call     esi
  push     4
  push     OFFSET msg
  call     esi
となってハッピー. これで全然問題ないんだけど, QQQの部分でコメントアウトしたように書くとLoopコンストラクタと思ってくれなくてうまくいかない(pが再定義されたと看做されてしまう). 一時変数runを宣言せずにうまく書くにはどうすればいいんだっけ.
Loop<P, n, i - 1>(Loop<P, n, i - 1>(p));とやればうまくいった. でもスマートじゃないなあ. もっといいのないかな
12月25日_
ベンチマークとってみた. ソースは次の通り.
// 1. loop
for (char c; std::cin.get(c); ) std::cout << c;
// 2. rdbuf
std::cin >> std::cout.rdbuf();
// 3. C-loop1
int c;
while ((c = getchar()) != EOF) putchar(c);
// 4. C-loop2
for (;;) {
    char buf[BUFSIZ];
    int n = fread(buf, 1, sizeof(buf), stdin);
    if (n <= 0) break;
    fwrite(buf, 1, n, stdout);
}
C++のコード(1~3)には最初に
std::cin.tie(0); // tie
std::ios::sync_with_stdio(false); // sync
の二つを追加して比較. 128MBのファイルに対して
time ./a.out < data > /dev/null
time ./a.out < data > sss
の2パターン(CoreDuo 1.8GHz, gcc 4.3.2).
time ./a.out < data > /dev/null
デフォルトtietie + sync_with_stdio
loop154.2221.3516.72
rdbuf17.2417.960.05
C-loop16.41--
C-loop20.07--
time ./a.out < data > sss
デフォルトtietie + sync_with_stdio
loop22521.0017.34
rdbuf18.9618.102.56
C-loop17.01--
C-loop22.47--
結論. cin, cout使うならtie(0) + sync_with_stdio(false)は呼んでおくこと.
12月24日_
バッファリング
C++のstreamの転送速度を調べる
まあ, 大きなファイル操作にstd::cin使うなというような気もします. isspace遅いみたいなこともあったし. flushは標準で入出力は連動すべきというのが決まってるみたいなんで仕方ないかな. std::cin.tie(0);とやれば1文字出力ごとにflushは呼ばれなくなるのでまあまそこそこな速度になるかも.
#C++のiostream複雑怪奇でわかんねーには激しく同意ですが.
>cat t.cpp
#include <iostream>

int main()
{
    char c;
//  std::cin.tie(0);
    while (std::cin.get(c)) {
        std::cout << c;
    }
}
tieデフォルトだと
g++ -O3 t.cpp && strace ./a.out < t.cpp |& less
fstat64(1, {st_mode=S_IFCHR|0620,
    st_rdev=makedev(136, 1), ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE,
    MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb80ac000
write(1, "#", 1#)                        = 1
write(1, "i", 1i)                        = 1
write(1, "n", 1n)                        = 1
write(1, "c", 1c)                        = 1
tie(0);を加えると
>g++ -O3 t.cpp && strace ./a.out < t.cpp |& less
write(1, "#include <iostream>
    \n\nint main()\n"..., 112#include <iostream>

int main()
{
    char c;
    std::cin.tie(0);
    while (std::cin.get(c)) {
        std::cout << c;
    }
}

) = 112
12月23日_
抜歯後の痛みがずっと続く. 今のところ我慢できないわけではない程度なのが救い.
12月21日_
ηT on F3193ソース公開. 553usec@Core2Duo 2.6GHz. main loopが今となっては古いアルゴリズムで実装してるので最新の方式に追従したらもっと速くなるだろう.
1.8GHzマシンでm = 97の時はXp : Linux@VMware = 202 : 209だったのが, m = 193の時は1328 : 1567になった. m = 97のときはXbyak全開でコンパイラ性能にはほとんど依存しない(つまりVMwareの影響も数%以下だと分かる). m = 193のときはCのintrinsicしか使ってない. ということはintrinsicまわりの最適化能力はgcc 4.3よりもVC2008の方がよいということか. 結構差が出るな. 64bitだとどうだろう(環境が無いので試せない).
12月20日_
__builtin_clz(x)ってbsr(x)かと思い込んでいたがbsr(x) ^ 0x1fだった. 64bitだったらbsr(x) ^ 0x3fか? x86にとって__builtin_ctz以上に使いにくい気がする.
12月19日_
下の親不知を抜いた. 上のときとは違って今回は安全のため口腔外科で. 埋もれていたので切って削って砕いてほじくり返す. おぞましい. 後半麻酔が切れかけていたのかめっちゃ痛かった. 顎の骨も少し削ったから腫れるでしょうとのこと. 明日が怖い.
12月16日_
初めてスペイン語の論文を見た. というかスペイン語を意識したのは初めて. 数式を眺めて本文をなんとなく推測する. 形容詞は後ろから掛かるっぽい.
12月15日_
3バグ報告してみた.
12月14日_
熟練パートさんでがっちり
「手に職」な人に脚光を当てるこのシリーズは好きだけど, フルタイム勤続25年で時給800円そこそこは明らかに搾取だろう. 他の人も同様(ラストの人が唯一正社員). 厚生年金とかどうなってるんだ. 森永卓郎には美談にまとめるのではなく, 辛口のコメントをして欲しかった.
12月13日_
吐きっぱなしの酷い一日だった.
12月11日_
#include <stdio.h>
#include <typeinfo>

int main()
{
    printf("%s\n", typeid("str").name());
    printf("%s\n", typeid("str" - 1).name());
}
gccだと
A4_c ; char[4]
PKc  ; const char *
なのにVCでは
char const [4]
char const [4] ; 何故?
だからVCでは
template<typename T, int N>
int getCount(const T (&x)[N])
{
    return N;
}
int main()
{
    return getCount("abc" - 1);
}
が通ってしまう. これはVCの酷いバグ…だよね?
12月10日_
・体調が本調子でないのに胃のレントゲン用のバリウム飲んでぐるぐる回されるのは辛かった.
JANTの発表の質疑応答の時に「m = 193は多分600usecは切れますよ」と答えてたので, 実証しとく. 現在566usec@Core 2 Duo 2.6GHz. 近日公開予定.
12月6日_
昨日raw文字列の仕様を初めて見たのだがその奇怪さに驚いた. 全然rawに見えない. ところで次の正規表現はVC9SP1では失敗する. 何故でしょう.
#include <boost/regex.hpp>
#include <string>

int main()
{
    boost::regex r("\\??!");
    std::string str = "xxx!xx";
    boost::smatch m;

    if (boost::regex_search(str, m, r)) {
        printf("match=[%s]\n", m[0].str().c_str());
    } else {
        puts("ng");
    }
}
答え: VCではトライグラフをoffにできないから. r("\\?""?!");なら大丈夫. これはraw文字列だと大丈夫になるのだろうか. でもC++0xのraw文字列では[]がメタキャラクタになってるので正規表現と相性悪いんじゃないかとか思った.
12月5日_
C++WGアドホック会議終了
疲れたけどとても刺激的だった. 規格を変えるのは大変だと実感. 念願のCryoliteさんにもお会いする. swapとADLにまつわる問題だけでいくらでも話せますよと, 夜ご飯食べながら説明して頂いた. 難しいなあ.
VC9(SP1でも直ってない)のstd::swapのタコさには同意して頂いてうれしい.
12月4日_
『神は沈黙せず』(山本弘)
幽霊, UFO, 超能力, 宗教, AI, 進化論, となんでもありの膨大な資料に基づいた近未来(1995年初版で2010年の事が触れられている)SF. ネットによる革命など, いかにもありそうな感じで恐ろしい. 中盤, 優歌と兄による「神は人間の心を理解できるか」という議論は持っていきたいところは分かるけどちょっと強引すぎるかな. でもなんといってもこのボリューム, 満喫した.
12月2日_
ペアリングのやつコード整理. 基本はベダで書いてて一部をtemplate特殊化で高速化していきゃいいやと思っていたが, こう関数が増えるとどれが特殊化されているのかわけわかめな状態になってしまった. 関数の使用順序によって特殊化されなくなっちゃったりするのでやりすぎは禁物だと実感した.

御意見は光成滋生<herumi@nifty.com>までお願いします