2015년 5월 30일 토요일

[Linux Kernel] 103주차(2015.05.30)

ARM10C : 103 주차
일시 : 2015.05.30 (103 주차 스터디 진행)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 2명

103 주차 진도

1  1 start_kernel        1  ~/kernel/iamroot/linux-stable/init/main.c
2  1 time_init         743  ~/kernel/iamroot/linux-stable/init/main.c
3  1 clocksource_of_init   557  ~/kernel/iamroot/linux-stable/arch/arm/kernel/time.c
4  1 mct_init_spi       56  ~/kernel/iamroot/linux-stable/drivers/clocksource/clksrc-of.c
5  1 mct_init_dt      1420  return mct_init_dt(np, MCT_INT_SPI);
6  1 exynos4_clocksource_init  1410  exynos4_clocksource_init();
7  1 exynos4_mct_frc_start   425  exynos4_mct_frc_start(0, 0)

main.c::main.c()

  • called: start_kernel()->time_init()
asmlinkage void __init start_kernel(void)
{
...
        sched_clock_postinit();

sched_clock.c::sched_clockinit()

  • call: start_kernel()->sched_clock_postinit()
void __init sched_clock_postinit(void)
{
    /*
     * If no sched_clock function has been provided at that point,
     * make it the final one one.
     */
    if (read_sched_clock == jiffy_sched_clock_read)
        sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ);
  • call: start_kernel()->sched_clock_postinit()->sched_clock_register()

sched_clock.c::sched_clock_register()

  • called: start_kernel()->sched_clock_postinit()->sched_clock_register()
void __init sched_clock_register(u64 (*read)(void), int bits,
                 unsigned long rate)
{
    unsigned long r;
    u64 res, wrap;
    char r_unit;

    // cd.rate: 0, rate: 100
    if (cd.rate > rate)
        return;

    // irqs_disabled(): 1
    WARN_ON(!irqs_disabled());
    // read_sched_clock: read: jiffy_sched_clock_read
    read_sched_clock = read;
    // sched_clock_mask: CLOCKSOURCE_MASK(bits: 32):
    // #define CLOCKSOURCE_MASK(bits) (cycle_t)((bits) < 64 ? ((1ULL<<(bits))-1) : -1)
    // sched_clock_mask: 0xffffffff
    sched_clock_mask = CLOCKSOURCE_MASK(bits);
    // cd.rate: rate: 100
    cd.rate = rate;

    /* calculate the mult/shift to convert counter ticks to ns. */
    clocks_calc_mult_shift(&cd.mult, &cd.shift, rate, NSEC_PER_SEC, 3600);
    // clock_calc_mult_shift():
    // (&cd)->mult: 0x98968000
    // (&cd)->shift: 8

    r = rate;
    if (r >= 4000000) {
        r /= 1000000;
        r_unit = 'M';
    } else if (r >= 1000) {
        r /= 1000;
        r_unit = 'k';
    } else
        r_unit = ' ';

    /* calculate how many ns until we wrap */
    wrap = clocks_calc_max_nsecs(cd.mult, cd.shift, 0, sched_clock_mask);
    //

clocksource.cc::clocks_calc_max_nsecs()

u64 clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask)
{
    u64 max_nsecs, max_cycles;

    /*
     * Calculate the maximum number of cycles that we can pass to the
     * cyc2ns function without overflowing a 64-bit signed result. The
     * maximum number of cycles is equal to ULLONG_MAX/(mult+maxadj)
     * which is equivalent to the below.
     * max_cycles < (2^63)/(mult + maxadj)
     * max_cycles < 2^(log2((2^63)/(mult + maxadj)))
     * max_cycles < 2^(log2(2^63) - log2(mult + maxadj))
     * max_cycles < 2^(63 - log2(mult + maxadj))
     * max_cycles < 1 << (63 - log2(mult + maxadj))
     * Please note that we add 1 to the result of the log2 to account for
     * any rounding errors, ensure the above inequality is satisfied and
     * no overflow will occur.
     */
    // mult: 0x98968000, maxadj: 0, ilog2(0x98968000): 31   
    max_cycles = 1ULL << (63 - (ilog2(mult + maxadj) + 1));
    // max_cycles: 0x80000000   

    /*
     * The actual maximum number of cycles we can defer the clocksource is
     * determined by the minimum of max_cycles and mask.
     * Note: Here we subtract the maxadj to make sure we don't sleep for
     * too long if there's a large negative adjustment.
     */
    // max_cycles: 0x80000000, 0xFFFFFFFF   
    max_cycles = min(max_cycles, mask);
    // max_cycles: 0x80000000   

    // max_cycles: 0x80000000, mult: 0x98968000, maxadj: 0x0, shift: 8,
    // clocksource_cyc2ns(0x80000000, 0x98968000, 8): 0x4c4b4000 000000
    max_nsecs = clocksource_cyc2ns(max_cycles, mult - maxadj, shift);
    // max_nsecs: 0x4c4b400000000 

    // max_nsecs: 0x4c4b400000000 
    return max_nsecs;
    // return 0x4c4b400000000 
}

sched_clock.c::

// ARM10C 20150530
// jiffy_sched_clock_read, BITS_PER_LONG: 32, HZ: 100
void __init sched_clock_register(u64 (*read)(void), int bits,
                 unsigned long rate)
{
...
    /* calculate how many ns until we wrap */
    wrap = clocks_calc_max_nsecs(cd.mult, cd.shift, 0, sched_clock_mask);
    // wrap: 0x4c4b400000000

    // wrap: 0x4c4b400000000, 0x9896800000000
    // ns_to_ktime(0x42c1d800000000)
    cd.wrap_kt = ns_to_ktime(wrap - (wrap >> 3));

ktime.h::ns_to_ktime()

static inline ktime_t ns_to_ktime(u64 ns)
{
    static const ktime_t ktime_zero = { .tv64 = 0 };
    // ktime_zero.tv64: 0

    // ktime_zero: 0x1000000000000000
    // ns: 0x42c1d800000000 
    // ktime_add_ns(ktime_zero, 0x42c1d800000000):
    // ({ (ktime_t){ .tv64 = (ktime_zero).tv64 + (0x42c1d800000000) }; })

    return ktime_add_ns(ktime_zero, ns);
    // return 0x42c1d8389aca00
}

sched_clock.c::sched_clock_register()

// ARM10C 20150530
// jiffy_sched_clock_read, BITS_PER_LONG: 32, HZ: 100
void __init sched_clock_register(u64 (*read)(void), int bits,
                 unsigned long rate)
{
...
    /* calculate how many ns until we wrap */
    wrap = clocks_calc_max_nsecs(cd.mult, cd.shift, 0, sched_clock_mask);
    // wrap: 0x4c4b400000000

    // wrap: 0x4c4b400000000, 0x9896800000000
    // ns_to_ktime(0x42c1d800000000)
    cd.wrap_kt = ns_to_ktime(wrap - (wrap >> 3));
    // cd.wrap_kt: 0x42c1d8389aca00

    /* calculate the ns resolution of this counter */
    res = cyc_to_ns(1ULL, cd.mult, cd.shift);

sched_clock.c::cyc_to_ns()

static inline u64 notrace cyc_to_ns(u64 cyc, u32 mult, u32 shift)
{
    // cyc: 1, mult: 0x98968000, shift: 8
    return (cyc * mult) >> shift;
    // return 0x989860
}

sched_clock.c::sched_clock_register()

  • return 0x989860
// ARM10C 20150530
// jiffy_sched_clock_read, BITS_PER_LONG: 32, HZ: 100
void __init sched_clock_register(u64 (*read)(void), int bits,
                 unsigned long rate)
{
...
    /* calculate the ns resolution of this counter */
    res = cyc_to_ns(1ULL, cd.mult, cd.shift);
    // res: 0x989860
    pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lluns\n",
        bits, r, r_unit, res, wrap);
    // bits:32, r: 100, r_unit: ' ' res: 989680, wrap: 0x4c48400000000
    // sched_clock: 0x20 bits at 100 hz resolution 10000000ns wraps every 214748364800000ns"

    update_sched_clock();

sched_clock.c::update_sched_clock()

static void notrace update_sched_clock(void)
{
    unsigned long flags;
    u64 cyc;
    u64 ns;

    // read_sched_clock(): 0
    cyc = read_sched_clock();
    // cyc: 0

    // cd.epoch_ns: 0
    // cyc_to_ns((cyc: 0 - cd.epoch_cyc: 0) & sched_clock_mask: 0xffffffff , cd.mult: 0x98968000, cd.shift:0
    ns = cd.epoch_ns +
        cyc_to_ns((cyc - cd.epoch_cyc) & sched_clock_mask,
              cd.mult, cd.shift);
    // ns: 0

    raw_local_irq_save(flags);
    raw_write_seqcount_begin(&cd.seq);
    // static inline void raw_write_seqcount_begin(seqcount_t *s)
    //   s->sequence++;
    //   smp_wmb();
    // cd.seq: 1
    cd.epoch_ns = ns;
    // cd.epoch_ns: 0
    cd.epoch_cyc = cyc;
    // cd.epoch_cyc: 0
    raw_write_seqcount_end(&cd.seq);
    // static inline void raw_write_seqcount_begin(seqcount_t *s)
    //   smp_wmb();
    //   s->sequence++;
    // cd.seq: 2
    raw_local_irq_restore(flags);
}

sched_clock.c::sched_clock_register()

  • return 0x989860
// ARM10C 20150530
// jiffy_sched_clock_read, BITS_PER_LONG: 32, HZ: 100
void __init sched_clock_register(u64 (*read)(void), int bits,
                 unsigned long rate)
{
...
    update_sched_clock();
    // cd.epoch_ns: 0
    // cd.epoch_cyc: 0
    // (&cd.seq): 2


    /*
     * Ensure that sched_clock() starts off at 0ns
     */
    cd.epoch_ns = 0;
    // cd.epoch_ns: 0

    /* Enable IRQ time accounting if we have a fast enough sched_clock */
    // irqtime: -1
    // rate: 100 >= 100000
    if (irqtime > 0 || (irqtime == -1 && rate >= 1000000))
        enable_sched_clock_irqtime();

    pr_debug("Registered %pF as sched_clock source\n", read);
    // Registered xxx as sched_clock source
}
// ARM10C 20150530
void __init sched_clock_postinit(void)
{
    /*
     * If no sched_clock function has been provided at that point,
     * make it the final one one.
     */
    // read_sched_clock: jiffy_sched_clock_read
    if (read_sched_clock == jiffy_sched_clock_read)
        // BITS_PER_LONG: 32, HZ: 100
        sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ);

    update_sched_clock();

sched_clock.c::update_sched_clock()

static void notrace update_sched_clock(void)
{
    unsigned long flags;
    u64 cyc;
    u64 ns;

    // read_sched_clock(): 0
    cyc = read_sched_clock();
    // cyc: 0

    // cd.epoch_ns: 0
    // cyc_to_ns((cyc: 0 - cd.epoch_cyc: 0) & sched_clock_mask: 0xffffffff , cd.mult: 0x98968000, cd.shift:0
    ns = cd.epoch_ns +
        cyc_to_ns((cyc - cd.epoch_cyc) & sched_clock_mask,
              cd.mult, cd.shift);
    // ns: 0

    raw_local_irq_save(flags);
    raw_write_seqcount_begin(&cd.seq);
    // static inline void raw_write_seqcount_begin(seqcount_t *s)
    //   s->sequence++;
    //   smp_wmb();
    // cd.seq: 1
    cd.epoch_ns = ns;
    // cd.epoch_ns: 0
    cd.epoch_cyc = cyc;
    // cd.epoch_cyc: 0
    raw_write_seqcount_end(&cd.seq);
    // static inline void raw_write_seqcount_begin(seqcount_t *s)
    //   smp_wmb();
    //   s->sequence++;
    // cd.seq: 2
    raw_local_irq_restore(flags);
}

sched_clock.c::sched_clock_postinit()

// ARM10C 20150530
void __init sched_clock_postinit(void)
{
    /*
     * If no sched_clock function has been provided at that point,
     * make it the final one one.
     */
    // read_sched_clock: jiffy_sched_clock_read
    if (read_sched_clock == jiffy_sched_clock_read)
        // BITS_PER_LONG: 32, HZ: 100
        sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ);

    update_sched_clock();

    hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);

hrtimer.c::hrtimer_init()

void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
          enum hrtimer_mode mode)
{
    // timer: &(&def_rt_bandwidth)->rt_period_timer, clock_id: 1, mode: 1
    // timer: &(&runqueues)->hrtick_timer, clock_id: 1, mode: 1
    debug_init(timer, clock_id, mode);

    // timer: &(&def_rt_bandwidth)->rt_period_timer, clock_id: 1, mode: 1
    // timer: &(&runqueues)->hrtick_timer, clock_id: 1, mode: 1
    __hrtimer_init(timer, clock_id, mode);
    // __hrtimer_init(rt_period_timer) 한일:
    // (&def_rt_bandwidth)->rt_period_timer의 값을 0으로 초기화
    // (&(&def_rt_bandwidth)->rt_period_timer)->base: &hrtimer_bases->clock_base[0]
    // RB Tree의 (&(&(&def_rt_bandwidth)->rt_period_timer)->node)->node 를 초기화
    //
    // __hrtimer_init(hrtick_timer) 한일:
    // (&runqueues)->hrtick_timer의 값을 0으로 초기화
    // (&(&runqueues)->hrtick_timer)->base: &hrtimer_bases->clock_base[0]
    // RB Tree의 (&(&(&runqueues)->hrtick_timer)->node)->node 를 초기화
}
EXPORT_SYMBOL_GPL(hrtimer_init);

hrtimer.c::debug_init()

static inline void
debug_init(struct hrtimer *timer, clockid_t clockid,
       enum hrtimer_mode mode)
{
    // timer: &(&def_rt_bandwidth)->rt_period_timer
    // timer: &(&runqueues)->hrtick_timer
    debug_hrtimer_init(timer);
    // debug_hrtimer_init(): null function

    // timer: &(&def_rt_bandwidth)->rt_period_timer, clock_id: 1, mode: 1
    // timer: &(&runqueues)->hrtick_timer, clock_id: 1, mode: 1
    trace_hrtimer_init(timer, clockid, mode);
}

sched_clock.c::sched_clock_postinit()

// ARM10C 20150530
void __init sched_clock_postinit(void)
{
    /*
     * If no sched_clock function has been provided at that point,
     * make it the final one one.
     */
    // read_sched_clock: jiffy_sched_clock_read
    if (read_sched_clock == jiffy_sched_clock_read)
        // BITS_PER_LONG: 32, HZ: 100
        sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ);

    update_sched_clock();

    hrtimer_init(&sched_clock_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);

hrtimer.c::__hrtimer_init()

static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
               enum hrtimer_mode mode)
{
    struct hrtimer_cpu_base *cpu_base;
    int base;

    // timer: &(&def_rt_bandwidth)->rt_period_timer, sizeof(struct hrtimer): 40 bytes
    // timer: &(&runqueues)->hrtick_timer, sizeof(struct hrtimer): 40 bytes
    memset(timer, 0, sizeof(struct hrtimer));
    // (&def_rt_bandwidth)->rt_period_timer의 값을 0으로 초기화
    // (&runqueues)->hrtick_timer의 값을 0으로 초기화

    // __raw_get_cpu_var(hrtimer_bases):
    // *({
    //      do {
    //      const void __percpu *__vpp_verify = (typeof((&(hrtimer_bases))))NULL;
    //      (void)__vpp_verify;
    //      } while (0)
    //      &(hrtimer_bases) + __my_cpu_offset;
    // })
    cpu_base = &__raw_get_cpu_var(hrtimer_bases);
    // cpu_base:
    // ({
    //      do {
    //      const void __percpu *__vpp_verify = (typeof((&(hrtimer_bases))))NULL;
    //      (void)__vpp_verify;
    //      } while (0)
    //      &(hrtimer_bases) + __my_cpu_offset;
    // })

    // clock_id: 1, CLOCK_REALTIME: 0, mode: 1, HRTIMER_MODE_ABS: 0
    // clock_id: 1, CLOCK_REALTIME: 0, mode: 1, HRTIMER_MODE_ABS: 0
    if (clock_id == CLOCK_REALTIME && mode != HRTIMER_MODE_ABS)
        clock_id = CLOCK_MONOTONIC;

    // clock_id: 1, hrtimer_clockid_to_base(1): 0
    // clock_id: 1, hrtimer_clockid_to_base(1): 0
    base = hrtimer_clockid_to_base(clock_id);
    // base: 0
    // base: 0

    // timer->base: (&(&def_rt_bandwidth)->rt_period_timer)->base,
    // base: 0, &cpu_base->clock_base: &hrtimer_bases->clock_base
    // timer->base: (&(&runqueues)->hrtick_timer)->base,
    // base: 0, &cpu_base->clock_base: &hrtimer_bases->clock_base
    timer->base = &cpu_base->clock_base[base];
    // timer->base: (&(&def_rt_bandwidth)->rt_period_timer)->base: &hrtimer_bases->clock_base[0]
    // timer->base: (&(&runqueues)->hrtick_timer)->base: &hrtimer_bases->clock_base[0]

    // &timer->node: &(&(&def_rt_bandwidth)->rt_period_timer)->node
    // &timer->node: &(&(&runqueues)->hrtick_timer)->node
    timerqueue_init(&timer->node);
    // RB Tree의 (&(&(&def_rt_bandwidth)->rt_period_timer)->node)->node 를 초기화
    // RB Tree의 &(&(&runqueues)->hrtick_timer)->node 를 초기화

#ifdef CONFIG_TIMER_STATS // CONFIG_TIMER_STATS=n
    timer->start_site = NULL;
    timer->start_pid = -1;
    memset(timer->start_comm, 0, TASK_COMM_LEN);
#endif
}

log

  • 1st log
   cf3996e..db7acca  master     -> origin/master
Updating cf3996e..db7acca
Fast-forward
include/asm-generic/bitsperlong.h |   1 +
include/asm-generic/param.h       |   1 +
include/linux/clocksource.h       |   2 +
include/linux/irqflags.h          |   3 +
include/linux/sched_clock.h       |   2 +-
include/linux/time.h              |   1 +
init/main.c                       |   3 +
kernel/time/clocksource.c         | 341 +++++++++++++++++++++++++++++---------
kernel/time/sched_clock.c         |  26 +++
9 files changed, 302 insertions(+), 78 deletions(-)
  • 2nd log
   db7acca..e6b188d  master     -> origin/master
Merge made by the 'recursive' strategy.
include/linux/clocksource.h  |   4 ++++
include/linux/hrtimer.h      |   2 ++
include/linux/irqflags.h     |   1 +
include/linux/ktime.h        |  16 +++++++++++++---
include/linux/log2.h         |   2 ++
include/linux/rbtree.h       |   2 ++
include/linux/seqlock.h      |  20 ++++++++++++++++++++
include/linux/timerqueue.h   |   6 ++++++
include/trace/events/timer.h |   2 ++
include/uapi/linux/time.h    |   1 +
kernel/hrtimer.c             |  46 ++++++++++++++++++++++++++++++++++++++++++++--
kernel/time/clocksource.c    |  13 ++++++++++++-
kernel/time/sched_clock.c    | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13 files changed, 223 insertions(+), 6 deletions(-)

댓글 없음:

댓글 쓰기