Skip to content

Latest commit

 

History

History
548 lines (464 loc) · 15.3 KB

a10c_103.md

File metadata and controls

548 lines (464 loc) · 15.3 KB
ARM10C : 103 주차
일시 : 2015.05.30 (103 주차 스터디 진행)
모임명 : NAVER개발자커뮤니티지원_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(-)