memologueスマートフォン用の表示で見るmemologueこの広告は、90日以上更新していないブログに表示しています。ARMgoogle-perftoolsというx86,x86_64,ppcなUNIX向けのプロファイラの(cpu-profiler部分)を、armなLinuxに対応させてみました。何かの役に立つかもしれないので、patchおよびpatch作成作業のメモを載せます。arm-v5tアーキテクチャ(ARM9系)向けの移植です。Linux/ARM向けのソフトウェアのパフォーマンスを解析したいなぁと思うことがあったのですが、OProfileはカーネル入れ替えがめんどくさい、gprofはプロファイル専用のバイナリを作成するのがめんどくさい、プロプラな奴は興味ないということで移植しました。移植の方がめんどくさいだろという話もありますが。perftools自体の説明はこちらが便利です。あーそういえばAndroidもARMでしたっけ?パッチhttp://binary.nahi.to/google-perftools-0.93_armv5t_1.patchパッチの適用方法とmake方法は次のとおりです。install以上でインストールが完了します。ARMマシン(以下target)上で、.soをPRELOADして解析対象を実行すると、prof.outという解析結果ファイルが生成されます。コンパイルされていることが必要です。stripされていてもOKです。解析結果のprof.outファイルの内容を可視化するにはpprofコマンドを使います。graphvizくらいはインストールされていないとダメですが、これらを頑張ってARMマシンに入れなくても、次を満たしていればx86上でプロファイル結果を見られます。次のファイルがx86からアクセス可能prof.out解析対象のprogramprogramが依存しているDSO群crossのbinutilsがx86マシンにインストールされているこれは便利。main(pprof)pprofにかける際のprogramは、strip前のものにしてください。うまく動かなかったりしたら教えてください。私は主にqemuとFedora6-armで動作確認してます。同ソフトウェアはアーキテクチャ依存部分が分離されているので、移植作業は楽で、ARMv5t用のアトミック演算関数を2種類書くスタックトレース関数を書くシグナルを受信したときのPCの値を得る関数を書くの3stepで大体終わりです。(src/base/atomicops-internals-armv5t.h)最低限、compare-and-swap(CAS)と、storeだけ書けばOKです。これは、ユーザ空間で完結したスレッドの排他制御に使われます。ようなので、自分で書くことになります。ARMv5tでは、CAS実装に直接的に使える命令がありません。cmpxchg8b命令はv7アーキテクチャ(Cortex)から、ldrex/strex命令(=ll/sc)もv6アーキテクチャ(ARM11とか)からしか使えないそうで。v5の場合は...どうしよ。割り込みを禁止できないユーザモードのプロセスでCASするのは面倒ですね。swp/swpb命令というのは使えるので、それを使ってatomicに最大限近そうなCASを書くのが、速度と安全性のバランスが良いのかな。実装例がありますねぇ。この実装は、2つあるswpの間のcmp命令実行の前後でコンテキストスイッチが起きるとまずいことになりますが*1、まープロファイラだし(?)、これでよしとします。result;}次、release-storeですが、storeはCで書き、store直前にGCCの最適化を阻むバリアだけ置いとけばOKかと。例によってメモリ同期命令はv6tアーキ以降にしかない(筈)です。ほうを参考にする手もあるのかな。v5/v6両用のコードにできる模様。ARMの命令は、「RealViewコード生成ツールv2.0」の「アセンブラガイド」をダウンロードすれば全て載ってます。Web版もあったかも。すると表示されるあれのことです。この関数も1.同様、シグナルハンドラから呼ばれるので、シグナルセーフにつくるのがベターです。等にも、デッドロックの危険があるからGetStackTrace()でmallocは呼ばない方が良いのだと注記されていました。するだけですぐ使えたりするんですが、この関数は内部でmallocを呼ぶことがあるのでできれば避けろと書かれてます。portでもそれに従い自作することにしました。ま、そんなに難しいわけではありません。フレームポインタが省略されていないと仮定すると、arm-gccでコンパイルしたコードの、関数の入口部分は次のようになってます。表示される場合もありますが、単に表記が違うだけでマシン語のバイト列は同じです。2行目のpushが実行された後のスタックのレイアウトは、こんな感じです。n;}でよろしいのではないかと。x86版を多少書き換えただけです。インラインアセンブラ部分など。counterの値)を戻す関数GetPCを書きます。シグナルハンドラをsigaction()で登録する際、SA_SIGINFOというフラグを指定しておくと、シグナルハンドラの第三引数としてucontext_t*という型の構造体を得ることができますので、この構造体の中に保存されているPC値を戻してやればOKです。(void*)signal_ucontext.uc_mcontext.arm_pc;}これだけ。参照すればわかります。カーネルが古いと(?)、SA_SIGINFOのucontext_t経由ではPCの値が取れないようです。手元の2.6.10カーネルではダメでした。SIGCONTEXTマクロやGET_PC()マクロを使う方法なら、きちんとPCを取ることができました。詳しい事情をだれか教えて的。configureオプションで、こちらの実装も選択できるようにしておきました。詳細はパッチ見てください。