[powerpc]oprofileの実装を追う
2012/07/25
ftraceとは何が異なるのかを確認するため、実装を追いかけた。
アーキテクチャ依存する部位も含むため、大枠はこれで理解するといいかもしれない。
QorIQをターゲットとして捜査したので、ほかのpower architectureは各自で追いかけていただきたい。
参考:
http://ssvb.github.com/2011/08/23/yet-another-oprofile-tutorial.html
参照したファイル類
linux-2.6/drivers/oprofile/oprof.clinux-2.6/drivers/oprofile/oprofile_stats.c
linux-2.6/drivers/oprofile/oprofile_files.c
linux-2.6/drivers/oprofile/oprofile_stats.c
linux-2.6/drivers/oprofile/event_buffer.c
linux-2.6/drivers/oprofile/buffer_sync.c
linux-2.6/drivers/oprofile/cpu_buffer.c
linux-2.6/include/linux/ring_buffer.h
linux-2.6/kernel/trace/ring_buffer_benchmark.c
linux-2.6/kernel/trace/ring_buffer.c
linux-2.6/arch/powerpc/oprofile/common.c
linux-2.6/arch/powerpc/kernel/head_booke.h
linux-2.6/arch/powerpc/kernel/head_fsl_booke.S
linux-2.6/arch/powerpc/kernel/cpu_setup_fsl_booke.S
linux-2.6/arch/powerpc/kernel/traps.c
linux-2.6/arch/powerpc/kernel/pmc.c
platform initialization
linux-2.6/arch/powerpc/kernel/cpu_setup_fsl_booke.S
_GLOBAL(__setup_cpu_e500v1) _GLOBAL(__setup_cpu_e500v2) mflr r4 bl __e500_icache_setup bl __e500_dcache_setup bl __setup_e500_ivors mtlr r4 blr
FILE: linux-2.6/arch/powerpc/kernel/cpu_setup_fsl_booke.S
"PerformanceMonitor"へ飛ぶようにセットしてる。/* Adjust or setup IVORs for e500v1/v2 */ _GLOBAL(__setup_e500_ivors) li r3,DebugCrit@l mtspr SPRN_IVOR15,r3 li r3,SPEUnavailable@l mtspr SPRN_IVOR32,r3 li r3,SPEFloatingPointData@l mtspr SPRN_IVOR33,r3 li r3,SPEFloatingPointRound@l mtspr SPRN_IVOR34,r3 li r3,PerformanceMonitor@l mtspr SPRN_IVOR35,r3 sync blr
/* Performance Monitor */ EXCEPTION(0x2060, PerformanceMonitor, performance_monitor_exception, EXC_XFER_STD)
linux-2.6/arch/powerpc/kernel/traps.c
PerformanceMonitor()を用意、
void performance_monitor_exception(struct pt_regs *regs)
{
perf_irq(regs);
}
linux-2.6/arch/powerpc/kernel/pmc.c
perf_irq() が定義されている。以下の関数で、ユーザ定義?の関数に差し替えることができる。oprofile driverで差し替えとる。
int reserve_pmc_hardware(perf_irq_t new_perf_irq)
linux-2.6/arch/powerpc/oprofile/common.c
static void op_handle_interrupt(struct pt_regs *regs)
{
model->handle_interrupt(regs, ctr);
}
初期化処理で、ハンドルを奪う。
static int op_powerpc_setup(void)
{
/* Grab the hardware */
err = reserve_pmc_hardware(op_handle_interrupt);
driver登録時点で、以下の初期化が行われている。int __init oprofile_arch_init(struct oprofile_operations *ops) case PPC_OPROFILE_FSL_EMB: model = &op_model_fsl_emb;
linux-2.6/arch/powerpc/oprofile/op_model_fsl_emb.c
static void fsl_emb_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)oprofile_add_ext_sample()でイベント登録。
イベントがなければぬける。
うっひょ-
linux-2.6/drivers/oprofile/cpu_buffer.c
カウントはこちらで行う。
static inline void
__oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
unsigned long event, int is_kernel)
{
struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(op_cpu_buffer);
unsigned long backtrace = oprofile_backtrace_depth;
/*
* if log_sample() fail we can't backtrace since we lost the
* source of this event
*/
if (!log_sample(cpu_buf, pc, backtrace, is_kernel, event))
/* failed */
return;
if (!backtrace)
return;
oprofile_begin_trace(cpu_buf);
oprofile_ops.backtrace(regs, backtrace);
oprofile_end_trace(cpu_buf);
}
void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
unsigned long event, int is_kernel)
{
__oprofile_add_ext_sample(pc, regs, event, is_kernel);
}
集計は?
ユーザ空間でoprofiledとかctrlが間接的に呼び出す。上記kernel空間で取得したPC/backtraceデータを用いて、どの区間を何ステップ走行したか、で
実行時間を推定している。
集計結果だけを見ているようでは、厳密な測定結果とはいえないだろう。
ざっくりとみる分には、それでもいいかもしれないですね。
profile取得のオーバヘッドと、サンプリング周期と測定対象の解像度とを十分に考慮してくださいね。