Linux Kernel 2.6 のランキューはCPUコアごとにあると思ったが、調べてみた。
[24時間365日] サーバ/インフラを支える技術 ?スケーラビリティ、ハイパフォーマンス、省力運用 (WEB+DB PRESS plusシリーズ)
- 作者: 安井真伸,横川和哉,ひろせまさあき,伊藤直也,田中慎司,勝見祐己
- 出版社/メーカー: 技術評論社
- 発売日: 2008/08/07
- メディア: 単行本(ソフトカバー)
- 購入: 133人 クリック: 2,270回
- この商品を含むブログ (288件) を見る
cpu_rq()はCPUに紐づいているランキューを取得するマクロです。
ということなので、CPUコアごとにあるようだ。*1
ついでに SytemTap でちょっと遊びながカーネルのソースを覗いてみた。
適当に requeue_task.stp という SystemTap のスクリプトを用意して、
probe kernel.statement("requeue_task@kernel/sched.c"){ print_backtrace() exit() }
実行してみると、
[root@localhost ~]# stap requeue_task.stp 0xc041eea6 : requeue_task+0x0/0x27 [kernel] 0xc04205b8 : scheduler_tick+0x307/0x33e [kernel] 0xc042dadf : update_process_times+0x57/0x62 [kernel] 0xc041884a : smp_apic_timer_interrupt+0x5d/0x6f [kernel] 0xc04059d7 : apic_timer_interrupt+0x1f/0x24 [kernel]
こんな感じでバックトレースがとれた。
/* * Local APIC timer interrupt. This is the most natural way for doing * local interrupts, but local timer interrupts can be emulated by * broadcast interrupts too. [in case the hw doesn't support APIC timers] * * [ if a single-CPU system runs an SMP kernel then we call the local * interrupt as well. Thus we cannot inline the local irq ... ] */ fastcall void smp_apic_timer_interrupt(struct pt_regs *regs) { int cpu = smp_processor_id(); /* * the NMI deadlock-detector uses this. */ per_cpu(irq_stat, cpu).apic_timer_irqs++; /* * NOTE! We'd better ACK the irq immediately, * because timer handling can be slow. */ ack_APIC_irq(); /* * update_process_times() expects us to have done irq_enter(). * Besides, if we don't timer interrupts ignore the global * interrupt lock, which is the WrongThing (tm) to do. */ irq_enter(); smp_local_timer_interrupt(regs); irq_exit(); }
- 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. */ if (user_tick) account_user_time(p, jiffies_to_cputime(1)); else account_system_time(p, HARDIRQ_OFFSET, jiffies_to_cputime(1)); run_local_timers(); if (rcu_pending(cpu)) rcu_check_callbacks(cpu, user_tick); scheduler_tick(); run_posix_cpu_timers(p); }
- kernel/sched.c
/* * This function gets called by the timer code, with HZ frequency. * We call it with interrupts disabled. * * It also gets called by the fork code, when changing the parent's * timeslices. */ void scheduler_tick(void) { unsigned long long now = sched_clock(); struct task_struct *p = current; int cpu = smp_processor_id(); struct rq *rq = cpu_rq(cpu); update_cpu_clock(p, rq, now); rq->timestamp_last_tick = now; if (p == rq->idle) { if (wake_priority_sleeper(rq)) goto out; rebalance_tick(cpu, rq, SCHED_IDLE); return; }
*1:厳密にはハイパースレッディングを使っている場合はスレッドごとだと思う