一眼レフカメラはでかいんだから,iPhone くっつけて Eye-Fi みたいなことをするようなものってないのかな.
ぱっとググったらこういうのがあるようだ.
最初のが(形は別にして)想像していたものだった.しかし,iPhone 無いと使えないってのは凄い.
そういえば,JavaScript ライブラリによって,最近気軽に syntax highlight ができるようになっている気がする.
機械語で,飛び先に矢印を付けてくれるようなものは気軽に出来たりしないものか.むしろ,gdb や objdump の吐く disassemble 結果が HTML で,みたいな.
GCC には,関数やグローバル変数に section attribute を付けることができる.リンカに,これはどこセクションですよ,と教えてあげる機能.
で,これを使うと局所性のあるデータを集められないかと思って,考えてみた.
==> sec.c <== #include <stdio.h> extern int highly_access1, highly_access2, highly_access3; int main() { printf("%p\n%p\n%p\n", &highly_access1, &highly_access2, &highly_access3); return 0; } ==> sec_1.c <== #include "sec.h" int dummy_1_1[0x100]; int dummy_1_2[0x100]; int highly_access1 HIGHLY_ACCESS; int dummy_1_3[0x100]; int dummy_1_4[0x100]; ==> sec_2.c <== #include "sec.h" int dummy_2_1[0x100]; int dummy_2_2[0x100]; int highly_access2 HIGHLY_ACCESS; int dummy_2_3[0x100]; int dummy_2_4[0x100]; ==> sec_3.c <== #include "sec.h" int dummy_3_1[0x100]; int dummy_3_2[0x100]; int highly_access3 HIGHLY_ACCESS; int dummy_3_3[0x100]; int dummy_3_4[0x100]; ==> sec.h <== #if 1 #define HIGHLY_ACCESS __attribute__ ((section ("data.highly_access"))) #else #define HIGHLY_ACCESS /* empty */ #endif
sec.h で,section attribute を使うかどうか選択できるようにしている.sec_[123].c では,グローバル変数の束中に,それぞれ1つだけ HIGHLY_ACCESS な値があるとする.
コンパイルしてみた結果.
$ gcc -O3 sec*.c -o sec $ objdump -t sec| sort (略) 080495e4 g O .data 00000000 .hidden __dso_handle 080495e8 g O data.highly_access 00000004 highly_access1 080495e8 l d data.highly_access 00000000 data.highly_access 080495ec g O data.highly_access 00000004 highly_access2 080495f0 g O data.highly_access 00000004 highly_access3 080495f4 g *ABS* 00000000 __bss_start 080495f4 g *ABS* 00000000 _edata 08049600 l O .bss 00000001 completed.5982 08049600 l d .bss 00000000 .bss 08049604 l O .bss 00000004 dtor_idx.5984 08049620 g O .bss 00000400 dummy_1_1 08049a20 g O .bss 00000400 dummy_1_2 08049e20 g O .bss 00000400 dummy_1_3 0804a220 g O .bss 00000400 dummy_1_4 0804a620 g O .bss 00000400 dummy_2_1 0804aa20 g O .bss 00000400 dummy_2_4 0804ae20 g O .bss 00000400 dummy_2_3 0804b220 g O .bss 00000400 dummy_2_2 0804b620 g O .bss 00000400 dummy_3_4 0804ba20 g O .bss 00000400 dummy_3_1 0804be20 g O .bss 00000400 dummy_3_2 0804c220 g O .bss 00000400 dummy_3_3 0804c620 g *ABS* 00000000 _end
ちゃんと,集まっていることがわかる.
これを,無効にしてみる.
08049600 l d .bss 00000000 .bss 08049604 l O .bss 00000004 dtor_idx.5984 08049620 g O .bss 00000004 highly_access1 08049640 g O .bss 00000400 dummy_1_1 08049a40 g O .bss 00000400 dummy_1_2 08049e40 g O .bss 00000400 dummy_1_3 0804a240 g O .bss 00000400 dummy_1_4 0804a640 g O .bss 00000400 dummy_2_1 0804aa40 g O .bss 00000004 highly_access2 0804aa60 g O .bss 00000400 dummy_2_4 0804ae60 g O .bss 00000400 dummy_2_3 0804b260 g O .bss 00000400 dummy_2_2 0804b660 g O .bss 00000400 dummy_3_4 0804ba60 g O .bss 00000400 dummy_3_1 0804be60 g O .bss 00000400 dummy_3_2 0804c260 g O .bss 00000004 highly_access3 0804c280 g O .bss 00000400 dummy_3_3 0804c680 g *ABS* 00000000 _end
ぐちゃっとしていることがわかる.そもそも BSS だった.これはフェアじゃないかなぁ.
小崎さんによると,Linux でも read mostly,つまり殆ど変わらないで read が頻発するところは,このテクニックを使っているらしい.逆に,read mostly なデータと update が頻発するデータを混ぜると,大変なことになるらしい.ご利用は計画的に.
MacOSX の dtrace について調査したのでメモ.ユーザ定義プロバイダの話.
$ cat foo.c #include "foo_probe.h" #include <stdio.h> int main(int argc, char *argv[]) { if (FOO_FOO_START_ENABLED()) FOO_FOO_START(); if (FOO_FOO_MIDDLE_ENABLED()) FOO_FOO_MIDDLE("foo!"); if (FOO_FOO_END_ENABLED()) FOO_FOO_END(); return 0; }
こんなコードに対して,
$ cat foo_probe.d provider Foo { probe foo_start(); probe foo_middle(char *); probe foo_end(); };
こんな,プロバイダ定義を書く.こいつから,.h を生成する.
$ dtrace -h -s foo_probe.d
foo_probe.d を指定したので,foo_probe.h が出来る.-o オプションで指定可能.
foo_probe.h に,ごにょごにょ書いてあるわけです.
#define FOO_FOO_START() \ do { \ __asm__ volatile(".reference " FOO_TYPEDEFS); \ __dtrace_probe$foo$foo_start$v1(); \ __asm__ volatile(".reference " FOO_STABILITY); \ } while (0) #define FOO_FOO_START_ENABLED() \ ({ int _r = __dtrace_isenabled$foo$foo_start$v1(); \ __asm__ volatile(""); \ _r; })
正直何が書いてあるかよくわからない..reference って何.
これで,そのまま gcc でビルド可能.
$ gcc -O3 foo.c
Sun のマニュアルとか,SystemTap (Linux) のマニュアルを見ると,dtrace -G foo.o とやらないといけない(dtrace 用に前処理が必要),とあるんだけど,多分 Apple は gcc を弄って,この手間を省く(むしろ,出来なくしている)ように見える.これが正しいかどうかはよくわからないけど,まぁ便利ならば入れちゃおうぜ,って精神が見える気がする.見当外れだったらごめん.
で,実際に動かしてみる.
$ ./a.out
何事も無く動く.
dtrace で実行してみる.
$ sudo dtrace -c ./a.out -P 'foo$target' dtrace: description 'foo$target' matched 3 probes dtrace: pid 22611 has exited CPU ID FUNCTION:NAME 1 144192 main:foo_start 1 144191 main:foo_middle 1 144190 main:foo_end
最初,-P foo で動かなくて大変だった.なんで $target なんて付ける必要があるんだ.-c 付きだったら,デフォルトでこう考えても良さそうなものなのに.
objdump で見てみる.
$ gobjdump a.out -t a.out: file format mach-o-x86-64 SYMBOL TABLE: 0000000100001000 l 0e SECT 08 0000 __DATA.__program_vars _pvars 0000000100001040 g 0f SECT 0b 0000 __DATA.__common _NXArgc 0000000100001048 g 0f SECT 0b 0000 __DATA.__common _NXArgv 0000000100001058 g 0f SECT 0b 0000 __DATA.__common ___progname 0000000100000000 g 03 ABS 01 0010 __mh_execute_header 0000000100001050 g 0f SECT 0b 0000 __DATA.__common _environ 0000000100000c50 g 0f SECT 01 0000 .text _main 0000000100000c10 g 0f SECT 01 0000 .text start 0000000000000000 g 01 UND 00 0100 _exit 0000000000000000 g 01 UND 00 0100 dyld_stub_binder
dtrace ほげほげ,というシンボルがないのが気になる.不思議.多分,objdump では読めない(対応していない)ところに,なんか情報があるんじゃないかと思うのだけど.
$ gobjdump a.out -d (略) 0000000100000c50 <_main>: 100000c50: 55 push %rbp 100000c51: 48 89 e5 mov %rsp,%rbp 100000c54: 33 c0 xor %eax,%eax 100000c56: 90 nop 100000c57: 90 nop 100000c58: 90 nop 100000c59: 85 c0 test %eax,%eax 100000c5b: 74 05 je 100000c62 <_main+0x12> 100000c5d: 90 nop 100000c5e: 0f 1f 40 00 nopl 0x0(%rax) 100000c62: 33 c0 xor %eax,%eax 100000c64: 90 nop 100000c65: 90 nop 100000c66: 90 nop 100000c67: 85 c0 test %eax,%eax 100000c69: 74 0c je 100000c77 <_main+0x27> 100000c6b: 48 8d 3d 38 00 00 00 lea 0x38(%rip),%rdi # 100000caa <_exit$stub+0x20> 100000c72: 90 nop 100000c73: 0f 1f 40 00 nopl 0x0(%rax) 100000c77: 33 c0 xor %eax,%eax 100000c79: 90 nop 100000c7a: 90 nop 100000c7b: 90 nop 100000c7c: 85 c0 test %eax,%eax 100000c7e: 74 05 je 100000c85 <_main+0x35> 100000c80: 90 nop 100000c81: 0f 1f 40 00 nopl 0x0(%rax) 100000c85: 31 c0 xor %eax,%eax 100000c87: 5d pop %rbp 100000c88: c3 retq (略)
dtrace に関係ありそうなところは nop になっている.SystemTap だと,ENABLED のところはグローバル変数を読むコードが埋め込まれていたんだけど.
では,実際にどうなるのか見てみる.
$ gdb ./a.out GNU gdb 6.3.50-20050815 (Apple version gdb-1752) (Sat Jan 28 03:02:46 UTC 2012) Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared li braries .. done warning: UUID mismatch detected between: /Users/ko1/src/c/a.out /Users/ko1/src/c/a.out.dSYM/Contents/Resources/DWARF/a.out...
gdb を起動する../a.out をターゲットにすることを示しただけで,まだ起動はしない.
(gdb) b main Breakpoint 1 at 0x100000c54 (gdb) run Starting program: /Users/ko1/src/c/a.out Reading symbols for shared libraries +........................ done Breakpoint 1, 0x0000000100000c54 in main ()
main 関数に breakpoint を設定し,実行(run)する.プログラムは開始され,main で止まる.
では,disassemble してみる.
(gdb) disassemble Dump of assembler code for function main: 0x0000000100000c50 <main+0>: push %rbp 0x0000000100000c51 <main+1>: mov %rsp,%rbp 0x0000000100000c54 <main+4>: xor %eax,%eax 0x0000000100000c56 <main+6>: nop 0x0000000100000c57 <main+7>: nop 0x0000000100000c58 <main+8>: nop 0x0000000100000c59 <main+9>: test %eax,%eax 0x0000000100000c5b <main+11>: je 0x100000c62 <main+18> 0x0000000100000c5d <main+13>: nop 0x0000000100000c5e <main+14>: nopl 0x0(%rax) 0x0000000100000c62 <main+18>: xor %eax,%eax 0x0000000100000c64 <main+20>: nop 0x0000000100000c65 <main+21>: nop 0x0000000100000c66 <main+22>: nop 0x0000000100000c67 <main+23>: test %eax,%eax 0x0000000100000c69 <main+25>: je 0x100000c77 <main+39> 0x0000000100000c6b <main+27>: lea 0x38(%rip),%rdi # 0x100000caa 0x0000000100000c72 <main+34>: nop 0x0000000100000c73 <main+35>: nopl 0x0(%rax) 0x0000000100000c77 <main+39>: xor %eax,%eax 0x0000000100000c79 <main+41>: nop 0x0000000100000c7a <main+42>: nop 0x0000000100000c7b <main+43>: nop 0x0000000100000c7c <main+44>: test %eax,%eax 0x0000000100000c7e <main+46>: je 0x100000c85 <main+53> 0x0000000100000c80 <main+48>: nop 0x0000000100000c81 <main+49>: nopl 0x0(%rax) 0x0000000100000c85 <main+53>: xor %eax,%eax 0x0000000100000c87 <main+55>: pop %rbp 0x0000000100000c88 <main+56>: retq End of assembler dump.
objdump で確認した結果と同じ.そこで,別の端末から,この a.out プロセスに対して dtrace を有効にしてみる.
$ ps ax|grep a.out 22650 s001 U+ 0:00.63 /usr/libexec/gdb/gdb-i386-apple-darwin ./a.out 22662 s001 SX 0:00.21 /Users/ko1/src/c/a.out 22666 s002 R+ 0:00.00 grep a.out $ sudo dtrace -P foo22662
この foo22662 って指定がださ過ぎる.
で,もう一度 disassemble 結果を見直してみる.
(gdb) disassemble Dump of assembler code for function main: 0x0000000100000c50 <main+0>: push %rbp 0x0000000100000c51 <main+1>: mov %rsp,%rbp 0x0000000100000c54 <main+4>: xor %eax,%eax 0x0000000100000c56 <main+6>: nop 0x0000000100000c57 <main+7>: int3 0x0000000100000c58 <main+8>: nop 0x0000000100000c59 <main+9>: test %eax,%eax 0x0000000100000c5b <main+11>: je 0x100000c62 <main+18> 0x0000000100000c5d <main+13>: int3 0x0000000100000c5e <main+14>: nopl 0x0(%rax) 0x0000000100000c62 <main+18>: xor %eax,%eax 0x0000000100000c64 <main+20>: nop 0x0000000100000c65 <main+21>: int3 0x0000000100000c66 <main+22>: nop 0x0000000100000c67 <main+23>: test %eax,%eax 0x0000000100000c69 <main+25>: je 0x100000c77 <main+39> 0x0000000100000c6b <main+27>: lea 0x38(%rip),%rdi # 0x100000caa 0x0000000100000c72 <main+34>: int3 0x0000000100000c73 <main+35>: nopl 0x0(%rax) 0x0000000100000c77 <main+39>: xor %eax,%eax 0x0000000100000c79 <main+41>: nop 0x0000000100000c7a <main+42>: int3 0x0000000100000c7b <main+43>: nop 0x0000000100000c7c <main+44>: test %eax,%eax 0x0000000100000c7e <main+46>: je 0x100000c85 <main+53> 0x0000000100000c80 <main+48>: int3 0x0000000100000c81 <main+49>: nopl 0x0(%rax) 0x0000000100000c85 <main+53>: xor %eax,%eax 0x0000000100000c87 <main+55>: pop %rbp 0x0000000100000c88 <main+56>: retq
int3 が挿入されていることがわかる.あれあれ,dtrace の実際の実行が int3 でフックかけるのはわかるんだけど,ENABLED まで int3 で処理するの?
推測としては,int3 でカーネルに入った瞬間に当該箇所の書き換えを発生させるのかと思った(そして,以降は int3 を実行しない)のだけど,ni(gdb で,命令ごとにステップ実行)で実行しても,書き換わらなかった.もしかしたら観測していないだけかもしれないけど.
まぁ,だいたいわかった.
おまけ:
別の端末の dtrace コマンドを終了したら,ちゃんと後始末していた.正直驚いた.
(gdb) disassemble Dump of assembler code for function main: 0x0000000100000c50 <main+0>: push %rbp 0x0000000100000c51 <main+1>: mov %rsp,%rbp 0x0000000100000c54 <main+4>: xor %eax,%eax 0x0000000100000c56 <main+6>: nop 0x0000000100000c57 <main+7>: nop 0x0000000100000c58 <main+8>: nop 0x0000000100000c59 <main+9>: test %eax,%eax 0x0000000100000c5b <main+11>: je 0x100000c62 <main+18> 0x0000000100000c5d <main+13>: nop 0x0000000100000c5e <main+14>: nopl 0x0(%rax) 0x0000000100000c62 <main+18>: xor %eax,%eax 0x0000000100000c64 <main+20>: nop 0x0000000100000c65 <main+21>: nop 0x0000000100000c66 <main+22>: nop 0x0000000100000c67 <main+23>: test %eax,%eax 0x0000000100000c69 <main+25>: je 0x100000c77 <main+39> 0x0000000100000c6b <main+27>: lea 0x38(%rip),%rdi # 0x100000caa 0x0000000100000c72 <main+34>: nop 0x0000000100000c73 <main+35>: nopl 0x0(%rax) 0x0000000100000c77 <main+39>: xor %eax,%eax 0x0000000100000c79 <main+41>: nop 0x0000000100000c7a <main+42>: nop 0x0000000100000c7b <main+43>: nop 0x0000000100000c7c <main+44>: test %eax,%eax 0x0000000100000c7e <main+46>: je 0x100000c85 <main+53> 0x0000000100000c80 <main+48>: nop 0x0000000100000c81 <main+49>: nopl 0x0(%rax) 0x0000000100000c85 <main+53>: xor %eax,%eax 0x0000000100000c87 <main+55>: pop %rbp 0x0000000100000c88 <main+56>: retq End of assembler dump.
参考文献
では,気になる性能を.個人的に気になるのは,トレースしない,nop 入れたバージョンですね.
ということで,今回は FOO_FOO_START_ENABLED() などだけ残したプログラムで計測します.
#include <stdio.h> #include <stdlib.h> #include "foo_probe.h" int main(int argc, char *argv[]) { int n = 0; int i; if (argc < 2) return 0; n = atoi(argv[1]); printf("loop count: %d\n", n); for (i=0; i<n; i++) { if (FOO_FOO_START_ENABLED()) ; if (FOO_FOO_MIDDLE_ENABLED()) ; if (FOO_FOO_END_ENABLED()) ; } return 0; }
としようとしたら,なんか怒られたので,一応最後に申し訳程度にトレースをつけておくことにする.
ちなみに,こんなふうに怒られた.なんか理不尽だ.
$ gcc -O3 foo_perf.c -o foo_perf error: Must have a valid dtrace stability entry ld: error creating dtrace DOF section for architecture x86_64 collect2: ld returned 1 exit status
#include <stdio.h> #include <stdlib.h> #include "foo_probe.h" int main(int argc, char *argv[]) { int n = 0; int i; if (argc < 2) return 0; n = atoi(argv[1]); printf("loop count: %d\n", n); for (i=0; i<n; i++) { if (FOO_FOO_START_ENABLED()) ; if (FOO_FOO_MIDDLE_ENABLED()) ; if (FOO_FOO_END_ENABLED()) ; } FOO_FOO_START(); FOO_FOO_MIDDLE("foo!"); FOO_FOO_END(); return 0; }
まずは,普通にビルドして,実行.
結果:
$ time ./foo_perf 1000000000 loop count: 1000000000 real 0m1.760s user 0m1.756s sys 0m0.003s
次に,dtrace を有効にして実行.
$ time sudo dtrace -c './foo_perf 1000000000' -P 'foo$target' dtrace: description 'foo$target' matched 3 probes loop count: 1000000000
お,終わらない....10倍程度は覚悟していたんだが.やっぱり,int3 でやってるから悪いのかなぁ.
ちょっと,数を減らす.
$ time ./foo_perf 10000000 loop count: 10000000 real 0m0.026s user 0m0.022s sys 0m0.003s
$ time sudo dtrace -c './foo_perf 10000000' -P 'foo$target' dtrace: description 'foo$target' matched 3 probes loop count: 10000000 dtrace: pid 22947 has exited CPU ID FUNCTION:NAME 2 145289 main:foo_start 2 145288 main:foo_middle 2 145287 main:foo_end real 0m15.565s user 0m10.090s sys 0m5.452s
なんというか,有効にしなかったときの速度がさっぱり信用ならない(多分,プロセス生成の時間が大幅にくってんだろう)ので確かなことは言えないのだが,dtrace を有効にするというのは,まぁそれなりにコストがかかるということはわかった.まぁ,int3 だしなあ.
さて,個人的に一番知りたい ENABLED() のコストについて.つまり,グローバル変数をチェックするのと,nop で埋めるの,どっちが速いか,という話.
では,無効にしてみよう.
$ gcc -O3 foo_perf.c -o foo_perf_disabled -D DTRACE_PROBES_DISABLED=1
DTRACE_PROBES_DISABLED を 1 にしておけば,dtrace 回りは 0 になる.ついでに,ループが消えないように asm volatile(""); を突っ込んでおいた.
0000000100000ed0 <_main>: 100000ed0: 55 push %rbp 100000ed1: 48 89 e5 mov %rsp,%rbp 100000ed4: 53 push %rbx 100000ed5: 48 83 ec 08 sub $0x8,%rsp 100000ed9: 83 ff 02 cmp $0x2,%edi 100000edc: 7c 26 jl 100000f04 <_main+0x34> 100000ede: 48 8b 7e 08 mov 0x8(%rsi),%rdi 100000ee2: e8 27 00 00 00 callq 100000f0e <_atoi$stub> 100000ee7: 89 c3 mov %eax,%ebx 100000ee9: 48 8d 3d 5e 00 00 00 lea 0x5e(%rip),%rdi # 100000f4e <_printf$stub+0x34> 100000ef0: 30 c0 xor %al,%al 100000ef2: 89 de mov %ebx,%esi 100000ef4: e8 21 00 00 00 callq 100000f1a <_printf$stub> 100000ef9: 85 db test %ebx,%ebx 100000efb: 7e 07 jle 100000f04 <_main+0x34> 100000efd: 0f 1f 00 nopl (%rax) 100000f00: ff cb dec %ebx 100000f02: 75 fc jne 100000f00 <_main+0x30> 100000f04: 31 c0 xor %eax,%eax 100000f06: 48 83 c4 08 add $0x8,%rsp 100000f0a: 5b pop %rbx 100000f0b: 5d pop %rbp 100000f0c: c3 retq
よくわかんないけど,多分ループ残ってるんじゃないだろうか.では,いざ実行.
$ time ./foo_perf 1000000000 loop count: 1000000000 real 0m1.760s user 0m1.756s sys 0m0.003s $ time ./foo_perf_disabled 1000000000 loop count: 1000000000 real 0m0.448s user 0m0.444s sys 0m0.003s
だいたい3倍? 3個 probe が入ってるから,まぁそんなもんか.nop が入ってるだけでも馬鹿に出来ないところは馬鹿に出来ないのだねえ.
では,dtrace 環境がないところで dtrace みたいなことをやるときの常道,グローバル変数でチェックするのはどうか.
#include <stdio.h> #include <stdlib.h> #include "foo_probe.h" #define nop() asm volatile("") int probe_p[3]; int main(int argc, char *argv[]) { int n = 0; int i; if (argc < 2) return 0; n = atoi(argv[1]); printf("loop count: %d\n", n); for (i=0; i<n; i++) { nop(); #if !DTRACE_PROBES_DISABLED if (FOO_FOO_START_ENABLED()) nop(); if (FOO_FOO_MIDDLE_ENABLED()) nop(); if (FOO_FOO_END_ENABLED()) nop(); #else if (probe_p[0]) nop(); if (probe_p[1]) nop(); if (probe_p[2]) nop(); #endif } FOO_FOO_START(); FOO_FOO_MIDDLE("foo!"); FOO_FOO_END(); return 0; }
こんなコードにしてみた.
$ gcc -O3 foo_perf.c -o foo_perf $ gcc -O3 foo_perf.c -o foo_perf_disabled -D DTRACE_PROBES_DISABLED=1 $ time ./foo_perf_disabled 1000000000 loop count: 1000000000 real 0m1.765s user 0m1.760s sys 0m0.003s $ time ./foo_perf 1000000000 loop count: 1000000000 real 0m3.515s user 0m3.511s sys 0m0.003s
上がグローバル変数版,下が dtrace 版.あれあれー.そもそも dtrace 版の値が変わっている....nop() って付けたからかな.そんな気がする.
そして,驚くべきは,グローバル変数版のほうが速いってこと.これは意外.いや,そうでもないのか? 分岐予測が十分に当たるときは,nop で埋められるよりも速いってことなのだろう.
評価環境:
一応確認.グローバル変数版のコンパイル結果:
0000000100000eb0 <_main>: 100000eb0: 55 push %rbp 100000eb1: 48 89 e5 mov %rsp,%rbp 100000eb4: 53 push %rbx 100000eb5: 48 83 ec 08 sub $0x8,%rsp 100000eb9: 83 ff 02 cmp $0x2,%edi 100000ebc: 7c 47 jl 100000f05 <_main+0x55> 100000ebe: 48 8b 7e 08 mov 0x8(%rsi),%rdi 100000ec2: e8 47 00 00 00 callq 100000f0e <_atoi$stub> 100000ec7: 89 c3 mov %eax,%ebx 100000ec9: 48 8d 3d 7e 00 00 00 lea 0x7e(%rip),%rdi # 100000f4e <_printf$stub+0x34> 100000ed0: 30 c0 xor %al,%al 100000ed2: 89 de mov %ebx,%esi 100000ed4: e8 41 00 00 00 callq 100000f1a <_printf$stub> 100000ed9: 85 db test %ebx,%ebx 100000edb: 7e 28 jle 100000f05 <_main+0x55> 100000edd: 48 8d 05 8c 01 00 00 lea 0x18c(%rip),%rax # 100001070 <_probe_p> 100000ee4: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 100000eea: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 100000ef0: 83 38 00 cmpl $0x0,(%rax) 100000ef3: 74 00 je 100000ef5 <_main+0x45> 100000ef5: 83 78 04 00 cmpl $0x0,0x4(%rax) 100000ef9: 74 00 je 100000efb <_main+0x4b> 100000efb: 83 78 08 00 cmpl $0x0,0x8(%rax) 100000eff: 74 00 je 100000f01 <_main+0x51> 100000f01: ff cb dec %ebx 100000f03: 75 eb jne 100000ef0 <_main+0x40> 100000f05: 31 c0 xor %eax,%eax 100000f07: 48 83 c4 08 add $0x8,%rsp 100000f0b: 5b pop %rbx 100000f0c: 5d pop %rbp 100000f0d: c3 retq
ちゃんとチェックしてる気がする.
dtrace 版.
0000000100000bf0 <_main>: 100000bf0: 55 push %rbp 100000bf1: 48 89 e5 mov %rsp,%rbp 100000bf4: 53 push %rbx 100000bf5: 48 83 ec 08 sub $0x8,%rsp 100000bf9: 83 ff 02 cmp $0x2,%edi 100000bfc: 7c 57 jl 100000c55 <_main+0x65> 100000bfe: 48 8b 7e 08 mov 0x8(%rsi),%rdi 100000c02: e8 57 00 00 00 callq 100000c5e <_atoi$stub> 100000c07: 89 c3 mov %eax,%ebx 100000c09: 48 8d 3d 8e 00 00 00 lea 0x8e(%rip),%rdi # 100000c9e <_printf$stub+0x34> 100000c10: 30 c0 xor %al,%al 100000c12: 89 de mov %ebx,%esi 100000c14: e8 51 00 00 00 callq 100000c6a <_printf$stub> 100000c19: 85 db test %ebx,%ebx 100000c1b: 7e 22 jle 100000c3f <_main+0x4f> 100000c1d: 0f 1f 00 nopl (%rax) 100000c20: 33 c0 xor %eax,%eax 100000c22: 90 nop 100000c23: 90 nop 100000c24: 90 nop 100000c25: 85 c0 test %eax,%eax 100000c27: 74 00 je 100000c29 <_main+0x39> 100000c29: 33 c0 xor %eax,%eax 100000c2b: 90 nop 100000c2c: 90 nop 100000c2d: 90 nop 100000c2e: 85 c0 test %eax,%eax 100000c30: 74 00 je 100000c32 <_main+0x42> 100000c32: 33 c0 xor %eax,%eax 100000c34: 90 nop 100000c35: 90 nop 100000c36: 90 nop 100000c37: 85 c0 test %eax,%eax 100000c39: 74 00 je 100000c3b <_main+0x4b> 100000c3b: ff cb dec %ebx 100000c3d: 75 e1 jne 100000c20 <_main+0x30> 100000c3f: 90 nop 100000c40: 0f 1f 40 00 nopl 0x0(%rax) 100000c44: 48 8d 3d 63 00 00 00 lea 0x63(%rip),%rdi # 100000cae <_printf$stub+0x44> 100000c4b: 90 nop 100000c4c: 0f 1f 40 00 nopl 0x0(%rax) 100000c50: 90 nop 100000c51: 0f 1f 40 00 nopl 0x0(%rax) 100000c55: 31 c0 xor %eax,%eax 100000c57: 48 83 c4 08 add $0x8,%rsp 100000c5b: 5b pop %rbx 100000c5c: 5d pop %rbp 100000c5d: c3 retq
ふーむ.やっぱり違いはメモリアクセスか nop か,ってことになるようだ.面白いな.
まぁ,この例だとキャッシュにあたるしねぇ.
solaris だともっと賢いことしてそうだなあ.
なんという,生産性のない.というか,寝過ぎ.しかも風邪引いた.
Ubuntu 環境がよくわからない.samba インストールしたら [homes] がデフォルトでオンになっておらずはまる./init.d/foo を直接触るんじゃなくて,service foo restart みたいにするんだな.