憂鬱な午後のひととき
Xbyakのcall(getCurr() + 5)が正しく動作しない(8bit相対jmpと勘違い)というバグを修正. 恥ずかしい.
言語雑談会って毎年参加してみたいと思っているのだが, 気づいたら終わってるぽい.
抜糸は痛くないと聞いていたが, 糸が塞ぎ掛けている傷口に入り込んでしまってたらしく, まだ痛いところをぐりぐりとされて拷問状態だった.
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));とやればうまくいった. でもスマートじゃないなあ. もっといいのないかな
ベンチマークとってみた. ソースは
次の通り.
// 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
| デフォルト | tie | tie + sync_with_stdio |
loop | 154.22 | 21.35 | 16.72 |
rdbuf | 17.24 | 17.96 | 0.05 |
C-loop1 | 6.41 | - | - |
C-loop2 | 0.07 | - | - |
time ./a.out < data > sss
| デフォルト | tie | tie + sync_with_stdio |
loop | 225 | 21.00 | 17.34 |
rdbuf | 18.96 | 18.10 | 2.56 |
C-loop1 | 7.01 | - | - |
C-loop2 | 2.47 | - | - |
結論. cin, cout使うならtie(0) + sync_with_stdio(false)は呼んでおくこと.
バッファリング
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
抜歯後の痛みがずっと続く. 今のところ我慢できないわけではない程度なのが救い.
η
T on F
3193の
ソース公開. 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だとどうだろう(環境が無いので試せない).
__builtin_clz(x)ってbsr(x)かと思い込んでいたがbsr(x) ^ 0x1fだった. 64bitだったらbsr(x) ^ 0x3fか?
x86にとって
__builtin_ctz以上に使いにくい気がする.
下の親不知を抜いた.
上のときとは違って今回は安全のため口腔外科で. 埋もれていたので切って削って砕いてほじくり返す. おぞましい.
後半麻酔が切れかけていたのかめっちゃ痛かった. 顎の骨も少し削ったから腫れるでしょうとのこと. 明日が怖い.
初めてスペイン語の論文を見た. というかスペイン語を意識したのは初めて. 数式を眺めて本文をなんとなく推測する. 形容詞は後ろから掛かるっぽい.
熟練パートさんでがっちり
「手に職」な人に脚光を当てるこのシリーズは好きだけど, フルタイム勤続25年で時給800円そこそこは明らかに搾取だろう. 他の人も同様(ラストの人が唯一正社員). 厚生年金とかどうなってるんだ.
森永卓郎には美談にまとめるのではなく, 辛口のコメントをして欲しかった.
吐きっぱなしの酷い一日だった.
#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の酷いバグ…だよね?
・体調が本調子でないのに胃のレントゲン用のバリウム飲んでぐるぐる回されるのは辛かった.
・
JANTの発表の質疑応答の時に「m = 193は多分600usecは切れますよ」と答えてたので, 実証しとく.
現在566usec@Core 2 Duo 2.6GHz. 近日公開予定.
昨日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文字列では[]がメタキャラクタになってるので正規表現と相性悪いんじゃないかとか思った.
C++WGアドホック会議終了
疲れたけどとても刺激的だった. 規格を変えるのは大変だと実感.
念願の
Cryoliteさんにもお会いする.
swapとADLにまつわる問題だけでいくらでも話せますよと, 夜ご飯食べながら説明して頂いた. 難しいなあ.
VC9(SP1でも直ってない)のstd::swapの
タコさには同意して頂いてうれしい.
『神は沈黙せず』(山本弘)
幽霊, UFO, 超能力, 宗教, AI, 進化論, となんでもありの膨大な資料に基づいた近未来(1995年初版で2010年の事が触れられている)SF.
ネットによる革命など, いかにもありそうな感じで恐ろしい.
中盤, 優歌と兄による「神は人間の心を理解できるか」という議論は持っていきたいところは分かるけどちょっと強引すぎるかな.
でもなんといってもこのボリューム, 満喫した.
ペアリングのやつコード整理. 基本はベダで書いてて一部をtemplate特殊化で高速化していきゃいいやと思っていたが,
こう関数が増えるとどれが特殊化されているのかわけわかめな状態になってしまった. 関数の使用順序によって特殊化されなくなっちゃったりするのでやりすぎは禁物だと実感した.
昔
御意見は光成滋生<herumi@nifty.com>までお願いします