poor man's profilerの全容は、次のページで知ることが出来る。
Poor Man's Profiler
http://poormansprofiler.org/
poor man's profilerは、現Facebook(元MySQL ABのサポートエンジニア)のDomas Mituzasによって開発されたプロファイリングテクノロジーである。以下が、その全ソースコードである。
#!/bin/bash nsamples=1 sleeptime=0 pid=$(pidof mysqld) for x in $(seq 1 $nsamples) do gdb -ex "set pagination 0" -ex "thread apply all bt" -batch -p $pid sleep $sleeptime done | \ awk ' BEGIN { s = ""; } /Thread/ { print s; s = ""; } /^\#/ { if (s != "" ) { s = s "," $4} else { s = $4 } } END { print s }' | \ sort | uniq -c | sort -r -n -k 1,1何を言っているのか分からないようなのでもう一度言う。これが、poor man's profilerのソースコードの全てである。
「馬鹿にするな!こんなたった10数行程度のプログラムで、プロファイリングなんて出来るわけがないだろっ!」
などと思ったアナタ。まずはこのプロファイラの出力サンプルを見て欲しい。
これは何をしているかというと、gdbでスレッドの一覧を抜き出し、awkで整形し、sortで集計しているのである。これにより、スレッドがどの関数を実行しているか、即ちどのロックを待っているかということが統計的に分かるのだ!!この例では、50のスレッドがos_event_wait_low()内でpthread_cond_wait()していることが分かる。このような情報は、まさにシングルプロセス/マルチスレッドプログラムにおいて、ボトルネックになり得るロックを探し出すのに打ってつけだ。shell> sudo poormans-profiler -p 1593 50 pthread_cond_wait@@GLIBC_2.3.2,os_event_wait_low,srv_conc_enter_innodb,ha_innobase::general_fetch(unsigned,rr_sequential(st_read_record*),sub_select(JOIN*,,??,JOIN::exec(),mysql_select(THD*,,handle_select(THD*,,??,mysql_execute_command(THD*),mysql_parse(THD*,,dispatch_command(enum_server_command,,do_command(THD*),handle_one_connection,start_thread,clone,?? 11 select,os_thread_sleep,srv_conc_enter_innodb,ha_innobase::general_fetch(unsigned,rr_sequential(st_read_record*),sub_select(JOIN*,,??,JOIN::exec(),mysql_select(THD*,,handle_select(THD*,,??,mysql_execute_command(THD*),mysql_parse(THD*,,dispatch_command(enum_server_command,,do_command(THD*),handle_one_connection,start_thread,clone,?? 5 __lll_lock_wait,_L_lock_1173,__pthread_mutex_lock,??,??,ha_autocommit_or_rollback(THD*,,dispatch_command(enum_server_command,,do_command(THD*),handle_one_connection,start_thread,clone,?? 4 pthread_cond_wait@@GLIBC_2.3.2,os_event_wait_low,os_aio_simulated_handle,fil_aio_wait,??,start_thread,clone,?? 3 select,os_thread_sleep,srv_conc_enter_innodb,ha_innobase::write_row(unsigned,handler::ha_write_row(unsigned,write_record(THD*,,mysql_insert(THD*,,mysql_execute_command(THD*),mysql_parse(THD*,,dispatch_command(enum_server_command,,do_command(THD*),handle_one_connection,start_thread,clone,?? : (snip)
もちろん、「スレッドの実行がどこで停止しているか」ということが分かったからと言って、それが即解決に繋がるわけではない。ボトルネックを解消するには、なぜ多くのスレッドがそのロックを待っているかということを分析し、仮説を立て、解決法を実装し、効果を測定するという地道な作業を積み重ねる必要があるだろう。ボトルネックを解消するのは一筋縄では行かない。Twitterの中の人も言っているが、チューニングに定石はなく、「すべてのエンジニアリング上の解決策というのは、一時的なもの」なのだ。だが、少なくともこれだけは言える。poor man's profilerはボトルネックを発見する人にとって力強い味方なのだ!!
poor man's profilerは、UNIXで広く使われている汎用ツール3つを駆使している。使われているコマンドは、
- gdb
- awk
- sort
- uniq
poor man's profilerを使うのに金はかからない。その上仕組みは至極簡単だ。しかし効果は絶大である。たとえ貧乏でもプロファイリングが出来るのである!!マルチスレッドプログラムで思うように性能が出ないと感じたら、まずはpoor man's profilerのテクニックを試して頂きたい。
poor man's profilerのスクリプトは至極単純だが、いちいち書き換えるのは面倒だ。そもそもマルチスレッドプログラムであれば汎用的に利用出来るテクニック(もちろんMySQL以外のプログラムにも!)であるため、スクリプト化してオプションを受け付けた方が便利である。そこで、そのように仕立てたスクリプトを書いたので、ここからダウンロードして利用して頂きたい。このスクリプトの書式とオプションの意味は次の通り。
shell> poormans-profiler -p {pid} [options] or shell> poormans-profiler [options] {progname}
- -p: プロファイリング対象プロセスのPID
- -n: 情報をサンプリングする回数
- -s: サンプリングする間隔(秒)
- -w: 最大文字幅(デフォルトは999)
0 コメント:
コメントを投稿