ablog

不器用で落着きのない技術者のメモ

「テキトーーク!!(TechyTalk) Vol.2 低レイヤー芸人」で話したこと

2014/4/24に社内で低レイヤー芸人*1として、ターミナルを開いてコマンドを打ちながら話したときのメモ。口頭でしゃべったことやホワイトボードに書いたことは書いていません、本当にただのメモです。

ねらい

  • 知らない世界に案内し、興味を持ってもらう(時間も短いので網羅性より面白さ重視)

何がわかるようになるか

  • iowait は idle である
  • CPU使用率が高いのは必ずしも悪ではない
  • CPU使用率が高くなくてもランキューの値が大きくなることがあるのはなぜか
  • CPU使用率が高い場合のドリルダウン方法
    • コア別、プロセス別、スレッド別、カーネル(sys,irq,soft...) or ユーザー(usr,nice...)、システムコール別、ライブラリ関数別、ユーザー関数別、
  • いろいろコマンドはあるが、実体はカーネルの構造体から取得している。
    • Oracle Database で言うと、V$→X$→共有メモリの構造体を見ているのと同じ

サマリ

  • iowait の割合が高い場合、CPU は忙しいのか暇なのか?
  • dstat、htop、perf、crash などのコマンドの紹介
  • vmstat も上記のようなコマンドも /proc を参照していて、/proc の実体はメモリ上のカーネル空間のデータ構造(たぶんだいたい)
  • /proc で参照できるようなデータは定期的に割込みが入って累積値が積み上げられていき、vmstat などは差分を算出して表示している(たぶんだいたい)
  • Brendan D. Gregg の USE Method の話

内容

コマンド
  • 一般ユーザで実行したコマンド
dstat -ta 2
fio -rw=randread -bs=4k -size=300m -directory=/tmp -numjobs=5 -name=file1
python -c 'while 1: pass' &
strace -e open dstat 1 1
strace -e open vmstat 1 1
strace -e open iostat 1 1
htop
strace htop
pkill python
perl -e 'while(1){}' &
pkill perl
  • rootで実行したコマンド
 perf top
crash
crash> runq
crash> kmem -i
crash> kmem -f
crash> dis メモリアドレス
Linuxカーネルのソースでプロセスアカウンティングの仕組みを解説
  • /usr/src/debug/kernel-2.6.39/linux-2.6.39.x86_64/kernel/timer.c
/*
 * Called from the timer interrupt handler to charge one tick to the current
 * process.  user_tick is 1 if the tick is user time, 0 for system.
 */
void update_process_times(int user_tick)
{
        struct task_struct *p = current;
        int cpu = smp_processor_id();

        /* Note: this timer irq context must be accounted for as well. */
        account_process_tick(p, user_tick);
        run_local_timers();
        rcu_check_callbacks(cpu, user_tick);
        printk_tick();
#ifdef CONFIG_IRQ_WORK
        if (in_irq())
                irq_work_run();
#endif
        scheduler_tick();
        run_posix_cpu_timers(p);
}
    • /usr/src/debug/kernel-2.6.39/linux-2.6.39.x86_64/kernel/sched.c
/*
 * Account a single tick of cpu time.
 * @p: the process that the cpu time gets accounted to
 * @user_tick: indicates if the tick is a user or a system tick
 */
void account_process_tick(struct task_struct *p, int user_tick)
{
        cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
        struct rq *rq = this_rq();

        if (sched_clock_irqtime) {
                irqtime_account_process_tick(p, user_tick, rq);
                return;
        }

        if (user_tick)
                account_user_time(p, cputime_one_jiffy, one_jiffy_scaled);
        else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET))
                account_system_time(p, HARDIRQ_OFFSET, cputime_one_jiffy,
                                    one_jiffy_scaled);
        else
                account_idle_time(cputime_one_jiffy);
}

...

/*
 * Account for idle time.
 * @cputime: the cpu time spent in idle wait
 */
void account_idle_time(cputime_t cputime)
{
        struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat;
        cputime64_t cputime64 = cputime_to_cputime64(cputime);
        struct rq *rq = this_rq();

        if (atomic_read(&rq->nr_iowait) > 0)
                cpustat->iowait = cputime64_add(cpustat->iowait, cputime64);
        else
                cpustat->idle = cputime64_add(cpustat->idle, cputime64);
}

今後紹介したいもの

  • perf、/proc/meminfo、fio、blktrace。crash、DTrace、oratop、MOTAS など。

*1:低レイヤー芸人と言えるほどではないですが、とりあえずそういうくくりでやりました