2014년 9월 20일 토요일

[Linux Kernel] 70주차(2014.09.20)

ARM10C 70주차 후기

일시 : 2014.09.20 (70주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 3명

스터디 진도 :

  • sched_init()

main.c::start_kernel()

  • sched_init()을 분석합니다.
  • start_kernel()부터 sched_init() 전에 어떤 일을 했는지 간추려서 보겠습니다.
asmlinkage void __init start_kernel(void)
{
    char * command_line;
    extern const struct kernel_param __start___param[], __stop___param[];

...
    local_irq_disable();
    // IRQ를 disable한다.
    early_boot_irqs_disabled = true;

    boot_cpu_init()
    // 현재 cpu(core id)를 얻어서 cpu_XXX_bits[] 의 cpu를 셋한다.

    page_address_init();
    // 128개의 page_address_htable 배열을 초기화

    pr_notice("%s", linux_banner);
    // 배너:
    //  Linux version 2.6.37_DM385_IPNC_3.50.00
    //  (a0875405@bangvideoapps01) (gcc version 4.5.3 20110311 
    //  (prerelease) (GCC) ) #1 Fri Dec 21 17:27:08 IST 2012

    setup_arch(&command_line);
    // ARM 아키텍쳐에 맞게 초기화한다.

    setup_nr_cpu_ids();
    setup_per_cpu_areas();
    // pcpu 구조체를 만들어 줌 (mm/percpu.c)

    smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
    // boot cpu 0의 pcpu 영역의 base주소를 core register에 설정해줌

...
    pidhash_init();
    // pidhash의 크기를 16kB만큼 할당 받고 4096개의 hash list를 만듬

    vfs_caches_init_early();
    // Dentry cache, Inode-cache용 hash를 위한 메모리 공간을 각각 512kB, 256kB만큼 할당 받고,
    // 131072, 65536개 만큼 hash table을 각각 만듬

...
    mm_init();
    // buddy와 slab 을 활성화 하고 기존 할당 받은 bootmem 은 buddy,
    // pcpu 메모리, vmlist 는 slab으로 이관

    sched_init();
mm_init()에서 buddy와 slab을 활성화하고 sched_init()을 실행한다.

core.c::sched_init()

  • CONFIG_xxx에 따라서 Sched는 분기한다.
    • CONFIG_FAIR_GROUP_SCHED
    • CONFIG_RT_GROUP_SCHED
    • CONFIG_CPUMASK_OFFSTACK
  • init_defrootdomain();
    • // def_root_domain의 맴버 값을 초기화 수행
    • // (&(&(&def_root_domain)->cpupri)->pri_to_cpu[0 ... 101])->count: 0
    • // (&(&(&def_root_domain)->cpupri)->pri_to_cpu[0 ... 101])->mask.bit[0]: 0
    • // (&(&def_root_domain)->cpupri)->pri_to_cpu[0 ... 3]: -1
    • // &def_root_domain.refcount: 1
  • init_rt_bandwidth(&def_rt_bandwidth, global_rt_period(), global_rt_runtime());
    • // init_rt_bandwidth에서 한일:
    • // (&def_rt_bandwidth)->rt_period: 1000000000
    • // (&def_rt_bandwidth)->rt_runtime: 950000000
    • // &(&def_rt_bandwidth)->rt_runtime_lock을 사용한 spinlock 초기화
    • // (&def_rt_bandwidth)->rt_period_timer의 값을 0으로 초기화
    • // &(&def_rt_bandwidth)->rt_period_timer)->base: &hrtimer_bases->clock_base[0]
    • // (&(&(&def_rt_bandwidth)->rt_period_timer)->node)->node의 RB Tree의 초기화
    • // &(&def_rt_bandwidth)->rt_period_timer.function: sched_rt_period_timer
  • for_each_possible_cpu(i) {
    • raw_spin_lock_init(&rq->lock);
      • // [pcp0] &rq->lock: &(&runqueues)->lock 을 사용한 spinlock 초기화 수행
    • // [pcp0] rq->nr_running: (&runqueues)->nr_running: 0
    • // [pcp0] rq->calc_load_active: (&runqueues)->calc_load_active: 0
    • // [pcp0] rq->calc_load_update: (&runqueues)->calc_load_update: -29499 (0xFFFFFFFFFFFF8CC5)
    • init_cfs_rq(&rq->cfs);
      • // init_cfs_rq 에서 한일:
    • // (&(&runqueues)->cfs)->tasks_timeline: (struct rb_root) { NULL, }
    • // (&(&runqueues)->cfs)->min_vruntime: 0xFFFFFFFFFFF00000
    • // (&(&runqueues)->cfs)->min_vruntime_copy: 0xFFFFFFFFFFF00000
    • // (&(&runqueues)->cfs)->decay_counter: 1
    • // (&(&runqueues)->cfs)->removed_load: 0
    • init_rt_rq(&rq->rt, rq);
      • // init_rt_rq 에서 한일:
    • // (&(&(&runqueues)->rt)->active)->bitmap의 0 ... 99 bit를 클리어
    • // (&(&(&runqueues)->rt)->active)->queue[0 ... 99] 의 리스트 초기화
    • // (&(&(&runqueues)->rt)->active)->bitmap의 100 bit를 1로 세팅
    • // (&(&runqueues)->rt)->rt_runtime_lock 을 사용한 spinlock 초기화
    • // (&(&runqueues)->rt)->rt_runtime: 0
    • // (&(&runqueues)->rt)->rt_throttled: 0
    • // (&(&runqueues)->rt)->rt_time: 0
    • // (&(&(&runqueues)->rt)->pushable_tasks)->node_list 리스트 초기화
    • // (&(&runqueues)->rt)->overloaded: 0
    • // (&(&runqueues)->rt)->rt_nr_migratory: 0
    • // (&(&runqueues)->rt)->highest_prio.next: 100
    • // (&(&runqueues)->rt)->highest_prio.curr: 100
    • // [pcp0] rq->rt.rt_runtime: (&runqueues)->rt.rt_runtime: 950000000
    • // [pcp0] j: 0, rq->cpu_load[0]: (&runqueues)->cpu_load[0]: 0, 1, 2, 3 실행
    • // [pcp0] rq->last_load_update_tick: (&runqueues)->last_load_update_tick: -30000 (0xFFFFFFFFFFFF8AD0)
    • // [pcp0] rq->sd: (&runqueues)->sd: NULL
    • // [pcp0] rq->rd: (&runqueues)->rd: NULL
    • // [pcp0] rq->cpu_power: (&runqueues)->cpu_power: 0x400
    • // [pcp0] rq->post_schedule: (&runqueues)->post_schedule: 0
    • // [pcp0] rq->active_balance: (&runqueues)->active_balance: 0
    • // [pcp0] rq->next_balance: (&runqueues)->next_balance: -30000 (0xFFFFFFFFFFFF8AD0)
    • // [pcp0] rq->push_cpu: (&runqueues)->push_cpu: 0
    • // [pcp0] rq->cpu: (&runqueues)->cpu: 0
    • // [pcp0] rq->online: (&runqueues)->online: 0
    • // [pcp0] rq->idle_stamp: (&runqueues)->idle_stamp: 0
    • // [pcp0] rq->avg_idle: (&runqueues)->avg_idle: 1000000UL
    • // [pcp0] rq->max_idle_balance_cost: (&runqueues)->max_idle_balance_cost: 500000UL
    • INIT_LIST_HEAD(&rq->cfs_tasks);
      • // [pcp0] &rq->cfs_tasks: &(&runqueues)->cfs_tasks 의 list 초기화 수행
    • rq_attach_root(rq, &def_root_domain);
      • // rq_attach_root에서 한일:
    • // (&def_root_domain)->span: 1
    • // (&runqueues)->rd: &def_root_domain
    • // &(&runqueues)->refcount: 1
    • // [pcp0] rq->nohz_flags: (&runqueues)->nohz_flags: 0
    • init_rq_hrtick(rq);
      • // init_rq_hrtick에서 한일:
    • // (&runqueues)->hrtick_csd_pending: 0
    • // (&runqueues)->hrtick_csd.flags: 0
    • // (&runqueues)->hrtick_csd.func: __hrtick_start
    • // (&runqueues)->hrtick_csd.info: &runqueues
    • // (&runqueues)->hrtick_timer의 값을 0으로 초기화
    • // (&(&runqueues)->hrtick_timer)->base: &hrtimer_bases->clock_base[0]
    • // RB Tree의 (&(&(&runqueues)->hrtick_timer)->node)->node 를 초기화
    • // &rq->hrtick_timer.function: &(&runqueues)->hrtick_timerhrtick_timer.function: hrtick
    • // [pcp0] &rq->nr_iowait: &(&runqueues)->nr_iowait: 0
  • set_load_weight(&init_task);
    • // set_load_weight에서 한일:
    • // (&(&init_task)->se.load)->weight: 1024
    • // (&(&init_task)->se.load)->inv_weight: 4194304
  • plist_head_init(&init_task.pi_waiters);
    • // plist_head_init에서 한일:
    • // (&init_task.pi_waiters)->node_list 리스트 초기화
  • atomic_inc(&init_mm.mm_count);
    • // init_mm.mm_count: 2
  • init_idle(current, smp_processor_id());
    • // init_idle에서 한일:
    • // (&init_task)->on_rq: 0
    • // (&init_task)->se.on_rq: 0
    • // (&init_task)->se.exec_start: 0
    • // (&init_task)->se.sum_exec_runtime: 0
    • // (&init_task)->se.prev_sum_exec_runtime: 0
    • // (&init_task)->se.nr_migrations: 0
    • // (&init_task)->se.vruntime: 0
    • // &(&init_task)->se.group_node의 리스트 초기화
    • // &(&init_task)->rt.run_list의 리스트 초기화
    • // (&init_task)->state: TASK_RUNNING: 0
    • // (&init_task)->se.exec_start: 0
    • // (&init_task)->cpus_allowed->bits[0]: 1
    • // (&init_task)->nr_cpus_allowed: 1
    • // ((struct thread_info *)(&init_task)->stack)->cpu: 0
    • // (&init_task)->wake_cpu: 0
    • // pcpu0->curr: &init_task
    • // pcpu0->idle: &init_task
    • // (&init_task)->on_cpu: 1
    • // ((struct thread_info *)(&init_task)->stack)->preempt_count: PREEMPT_ENABLED: 0
    • // (&init_task)->sched_class: &idle_sched_class
    • // (&init_task)->comm: "swapper/0"
  • calc_load_update = jiffies + LOAD_FREQ;
    • // calc_load_update: -29499 (0xFFFFFFFFFFFF8cc5)
  • // current->sched_class: (&init_task)->sched_class: &fair_sched_class
  • zalloc_cpumask_var(&sched_domains_tmpmask, GFP_NOWAIT);
    • // sched_domains_tmpmask.bits[0]: 0
  • zalloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT);
    • // cpu_isolated_map.bits[0]: 0
  • idle_thread_set_boot_cpu();
    • // [pcp0] idle_threads: &init_task
  • init_sched_fair_class();
    • // init_sched_fair_class가 한일:
    • // softirq_vec[7].action: run_rebalance_domains
    • // nohz.next_balance: -30000 (0xFFFFFFFFFFFF8AD0)
    • // nohz.idle_cpus_mask.bits[0]: 0
    • // (&cpu_chain)->head: sched_ilb_notifier_nb 포인터 대입
    • // (&sched_ilb_notifier_nb)->next은 (&slab_notifier)->next로 대입
  • // scheduler_running: 1
// ARM10C 20140830
void __init sched_init(void)
{
    int i, j;
    unsigned long alloc_size = 0, ptr;
    // alloc_size: 0

#ifdef CONFIG_FAIR_GROUP_SCHED // CONFIG_FAIR_GROUP_SCHED=n
    alloc_size += 2 * nr_cpu_ids * sizeof(void **);
#endif
#ifdef CONFIG_RT_GROUP_SCHED // CONFIG_RT_GROUP_SCHED=n
    alloc_size += 2 * nr_cpu_ids * sizeof(void **);
#endif
#ifdef CONFIG_CPUMASK_OFFSTACK // CONFIG_CPUMASK_OFFSTACK=n
    alloc_size += num_possible_cpus() * cpumask_size();
#endif
    // alloc_size: 0
    if (alloc_size) {
        ptr = (unsigned long)kzalloc(alloc_size, GFP_NOWAIT);

#ifdef CONFIG_FAIR_GROUP_SCHED // CONFIG_FAIR_GROUP_SCHED=n
        root_task_group.se = (struct sched_entity **)ptr;
        ptr += nr_cpu_ids * sizeof(void **);

        root_task_group.cfs_rq = (struct cfs_rq **)ptr;
        ptr += nr_cpu_ids * sizeof(void **);

#endif /* CONFIG_FAIR_GROUP_SCHED */
#ifdef CONFIG_RT_GROUP_SCHED // CONFIG_RT_GROUP_SCHED=n
        root_task_group.rt_se = (struct sched_rt_entity **)ptr;
        ptr += nr_cpu_ids * sizeof(void **);

        root_task_group.rt_rq = (struct rt_rq **)ptr;
        ptr += nr_cpu_ids * sizeof(void **);

#endif /* CONFIG_RT_GROUP_SCHED */
#ifdef CONFIG_CPUMASK_OFFSTACK // CONFIG_CPUMASK_OFFSTACK=n
        for_each_possible_cpu(i) {
            per_cpu(load_balance_mask, i) = (void *)ptr;
            ptr += cpumask_size();
        }
#endif /* CONFIG_CPUMASK_OFFSTACK */
    }

#ifdef CONFIG_SMP // CONFIG_SMP=y
    init_defrootdomain();
    // def_root_domain의 맴버 값을 초기화 수행
    // (&(&(&def_root_domain)->cpupri)->pri_to_cpu[0 ... 101])->count: 0
    // (&(&(&def_root_domain)->cpupri)->pri_to_cpu[0 ... 101])->mask.bit[0]: 0
    // (&(&def_root_domain)->cpupri)->pri_to_cpu[0 ... 3]: -1
    // &def_root_domain.refcount: 1
#endif

    // global_rt_period(): 1000000000, global_rt_runtime(): 950000000
    init_rt_bandwidth(&def_rt_bandwidth,
            global_rt_period(), global_rt_runtime());
    // init_rt_bandwidth에서 한일:
    // (&def_rt_bandwidth)->rt_period: 1000000000
    // (&def_rt_bandwidth)->rt_runtime: 950000000
    // &(&def_rt_bandwidth)->rt_runtime_lock을 사용한 spinlock 초기화
    // (&def_rt_bandwidth)->rt_period_timer의 값을 0으로 초기화
    // &(&def_rt_bandwidth)->rt_period_timer)->base: &hrtimer_bases->clock_base[0]
    // (&(&(&def_rt_bandwidth)->rt_period_timer)->node)->node의 RB Tree의 초기화
    // &(&def_rt_bandwidth)->rt_period_timer.function: sched_rt_period_timer

#ifdef CONFIG_RT_GROUP_SCHED // CONFIG_RT_GROUP_SCHED=n
    init_rt_bandwidth(&root_task_group.rt_bandwidth,
            global_rt_period(), global_rt_runtime());
#endif /* CONFIG_RT_GROUP_SCHED */

#ifdef CONFIG_CGROUP_SCHED // CONFIG_CGROUP_SCHED=n
    list_add(&root_task_group.list, &task_groups);
    INIT_LIST_HEAD(&root_task_group.children);
    INIT_LIST_HEAD(&root_task_group.siblings);
    autogroup_init(&init_task);

#endif /* CONFIG_CGROUP_SCHED */

    for_each_possible_cpu(i) {
    // for ((i) = -1; (i) = cpumask_next((i), (cpu_possible_mask)), (i) < nr_cpu_ids; )
        struct rq *rq;

        // i: 0
        // cpu_rq(0):
        // &({
        //      do {
        //      const void __percpu *__vpp_verify = (typeof(&(runqueues)))NULL;
        //      (void)__vpp_verify;
        //      } while (0)
        //      (&(runqueues) + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋);
        // })
        rq = cpu_rq(i);
        // rq: (&(runqueues) + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)

        // NOTE:
        // rq: (&(runqueues) + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
        // 의 주석을 간결하게 하기 위해 [pcp0] 를 변수 앞에 추가하고 rq: (&runqueue) 로 사용함

        // [pcp0] &rq->lock: &(&runqueues)->lock
        raw_spin_lock_init(&rq->lock);
        // [pcp0] &rq->lock: &(&runqueues)->lock 을 사용한 spinlock 초기화 수행

        // [pcp0] rq->nr_running: (&runqueues)->nr_running
        rq->nr_running = 0;
        // [pcp0] rq->nr_running: (&runqueues)->nr_running: 0

        // [pcp0] rq->calc_load_active: (&runqueues)->calc_load_active
        rq->calc_load_active = 0;
        // [pcp0] rq->calc_load_active: (&runqueues)->calc_load_active: 0

        // [pcp0] rq->calc_load_update: (&runqueues)->calc_load_update,
        // jiffies: -30000 (0xFFFFFFFFFFFF8AD0): vmlinux.lds.S 에 있음, LOAD_FREQ: 501
        rq->calc_load_update = jiffies + LOAD_FREQ;
        // [pcp0] rq->calc_load_update: (&runqueues)->calc_load_update: -29499 (0xFFFFFFFFFFFF8CC5)

        // [pcp0] &rq->cfs: &(&runqueues)->cfs
        init_cfs_rq(&rq->cfs);
        // init_cfs_rq 에서 한일:
        // (&(&runqueues)->cfs)->tasks_timeline: (struct rb_root) { NULL, }
        // (&(&runqueues)->cfs)->min_vruntime: 0xFFFFFFFFFFF00000
        // (&(&runqueues)->cfs)->min_vruntime_copy: 0xFFFFFFFFFFF00000
        // (&(&runqueues)->cfs)->decay_counter: 1
        // (&(&runqueues)->cfs)->removed_load: 0

        // [pcp0] &rq->rt: &(&runqueues)->rt, rq: (&runqueues)
        init_rt_rq(&rq->rt, rq);
        // init_rt_rq 에서 한일:
        // (&(&(&runqueues)->rt)->active)->bitmap의 0 ... 99 bit를 클리어
        // (&(&(&runqueues)->rt)->active)->queue[0 ... 99] 의 리스트 초기화
        // (&(&(&runqueues)->rt)->active)->bitmap의 100 bit를 1로 세팅
        // (&(&runqueues)->rt)->rt_runtime_lock 을 사용한 spinlock 초기화
        // (&(&runqueues)->rt)->rt_runtime: 0
        // (&(&runqueues)->rt)->rt_throttled: 0
        // (&(&runqueues)->rt)->rt_time: 0
        // (&(&(&runqueues)->rt)->pushable_tasks)->node_list 리스트 초기화
        // (&(&runqueues)->rt)->overloaded: 0
        // (&(&runqueues)->rt)->rt_nr_migratory: 0
        // (&(&runqueues)->rt)->highest_prio.next: 100
        // (&(&runqueues)->rt)->highest_prio.curr: 100

// 2014/08/30 종료
// 2014/09/13 시작

#ifdef CONFIG_FAIR_GROUP_SCHED // CONFIG_FAIR_GROUP_SCHED=n
        root_task_group.shares = ROOT_TASK_GROUP_LOAD;
        INIT_LIST_HEAD(&rq->leaf_cfs_rq_list);
        /*
         * How much cpu bandwidth does root_task_group get?
         *
         * In case of task-groups formed thr' the cgroup filesystem, it
         * gets 100% of the cpu resources in the system. This overall
         * system cpu resource is divided among the tasks of
         * root_task_group and its child task-groups in a fair manner,
         * based on each entity's (task or task-group's) weight
         * (se->load.weight).
         *
         * In other words, if root_task_group has 10 tasks of weight
         * 1024) and two child groups A0 and A1 (of weight 1024 each),
         * then A0's share of the cpu resource is:
         *
         *  A0's bandwidth = 1024 / (10*1024 + 1024 + 1024) = 8.33%
         *
         * We achieve this by letting root_task_group's tasks sit
         * directly in rq->cfs (i.e root_task_group->se[] = NULL).
         */
        init_cfs_bandwidth(&root_task_group.cfs_bandwidth);
        init_tg_cfs_entry(&root_task_group, &rq->cfs, NULL, i, NULL);
#endif /* CONFIG_FAIR_GROUP_SCHED */

        // [pcp0] rq->rt.rt_runtime: (&runqueues)->rt.rt_runtime,
        // def_rt_bandwidth.rt_runtime: 950000000
        rq->rt.rt_runtime = def_rt_bandwidth.rt_runtime;
        // [pcp0] rq->rt.rt_runtime: (&runqueues)->rt.rt_runtime: 950000000

#ifdef CONFIG_RT_GROUP_SCHED // CONFIG_RT_GROUP_SCHED=n
        INIT_LIST_HEAD(&rq->leaf_rt_rq_list);
        init_tg_rt_entry(&root_task_group, &rq->rt, NULL, i, NULL);
#endif

        // CPU_LOAD_IDX_MAX: 5
        for (j = 0; j < CPU_LOAD_IDX_MAX; j++)
            // [pcp0] j: 0, rq->cpu_load[0]: (&runqueues)->cpu_load[0]
            rq->cpu_load[j] = 0;
            // [pcp0] j: 0, rq->cpu_load[0]: (&runqueues)->cpu_load[0]: 0
            // j: 1 .. 4 까지 수행

        // [pcp0] rq->last_load_update_tick: (&runqueues)->last_load_update_tick
        // jiffies: -30000 (0xFFFFFFFFFFFF8AD0): vmlinux.lds.S 에 있음
        rq->last_load_update_tick = jiffies;
        // [pcp0] rq->last_load_update_tick: (&runqueues)->last_load_update_tick: -30000 (0xFFFFFFFFFFFF8AD0)

#ifdef CONFIG_SMP // CONFIG_SMP=y
        // [pcp0] rq->sd: (&runqueues)->sd
        rq->sd = NULL;
        // [pcp0] rq->sd: (&runqueues)->sd: NULL

        // [pcp0] rq->rd: (&runqueues)->rd
        rq->rd = NULL;
        // [pcp0] rq->rd: (&runqueues)->rd: NULL

        // [pcp0] rq->cpu_power: (&runqueues)->cpu_power, SCHED_POWER_SCALE: 0x400
        rq->cpu_power = SCHED_POWER_SCALE;
        // [pcp0] rq->cpu_power: (&runqueues)->cpu_power: 0x400

        // [pcp0] rq->post_schedule: (&runqueues)->post_schedule
        rq->post_schedule = 0;
        // [pcp0] rq->post_schedule: (&runqueues)->post_schedule: 0

        // [pcp0] rq->active_balance: (&runqueues)->active_balance
        rq->active_balance = 0;
        // [pcp0] rq->active_balance: (&runqueues)->active_balance: 0

        // [pcp0] rq->next_balance: (&runqueues)->next_balance,
        // jiffies: -30000 (0xFFFFFFFFFFFF8AD0): vmlinux.lds.S 에 있음
        rq->next_balance = jiffies;
        // [pcp0] rq->next_balance: (&runqueues)->next_balance: -30000 (0xFFFFFFFFFFFF8AD0)

        // [pcp0] rq->push_cpu: (&runqueues)->push_cpu
        rq->push_cpu = 0;
        // [pcp0] rq->push_cpu: (&runqueues)->push_cpu: 0

        // [pcp0] rq->cpu: (&runqueues)->cpu, i: 0
        rq->cpu = i;
        // [pcp0] rq->cpu: (&runqueues)->cpu: 0

        // [pcp0] rq->online: (&runqueues)->online
        rq->online = 0;
        // [pcp0] rq->online: (&runqueues)->online: 0

        // [pcp0] rq->idle_stamp: (&runqueues)->idle_stamp
        rq->idle_stamp = 0;
        // [pcp0] rq->idle_stamp: (&runqueues)->idle_stamp: 0

        // [pcp0] rq->avg_idle: (&runqueues)->avg_idle,
        // sysctl_sched_migration_cost: 500000UL
        rq->avg_idle = 2*sysctl_sched_migration_cost;
        // [pcp0] rq->avg_idle: (&runqueues)->avg_idle: 1000000UL

        // [pcp0] rq->max_idle_balance_cost: (&runqueues)->max_idle_balance_cost,
        // sysctl_sched_migration_cost: 500000UL
        rq->max_idle_balance_cost = sysctl_sched_migration_cost;
        // [pcp0] rq->max_idle_balance_cost: (&runqueues)->max_idle_balance_cost: 500000UL

        // [pcp0] &rq->cfs_tasks: &(&runqueues)->cfs_tasks
        INIT_LIST_HEAD(&rq->cfs_tasks);
        // [pcp0] &rq->cfs_tasks: &(&runqueues)->cfs_tasks 의 list 초기화 수행

        // [pcp0] rq: &runqueues
        rq_attach_root(rq, &def_root_domain);
        // rq_attach_root에서 한일:
        // (&def_root_domain)->span: 1
        // (&runqueues)->rd: &def_root_domain
        // &(&runqueues)->refcount: 1

#ifdef CONFIG_NO_HZ_COMMON // CONFIG_NO_HZ_COMMON=y
        // [pcp0] rq->nohz_flags: (&runqueues)->nohz_flags
        rq->nohz_flags = 0;
        // [pcp0] rq->nohz_flags: (&runqueues)->nohz_flags: 0
#endif
#ifdef CONFIG_NO_HZ_FULL // CONFIG_NO_HZ_FULL=n
        rq->last_sched_tick = 0;
#endif
#endif
        // [pcp0] rq: &runqueues
        init_rq_hrtick(rq);
        // init_rq_hrtick에서 한일:
        // (&runqueues)->hrtick_csd_pending: 0
        // (&runqueues)->hrtick_csd.flags: 0
        // (&runqueues)->hrtick_csd.func: __hrtick_start
        // (&runqueues)->hrtick_csd.info: &runqueues
        // (&runqueues)->hrtick_timer의 값을 0으로 초기화
        // (&(&runqueues)->hrtick_timer)->base: &hrtimer_bases->clock_base[0]
        // RB Tree의 (&(&(&runqueues)->hrtick_timer)->node)->node 를 초기화
        // &rq->hrtick_timer.function: &(&runqueues)->hrtick_timerhrtick_timer.function: hrtick

        // [pcp0] &rq->nr_iowait: &(&runqueues)->nr_iowait
        atomic_set(&rq->nr_iowait, 0);
        // [pcp0] &rq->nr_iowait: &(&runqueues)->nr_iowait: 0

        // i: 1 .. 3 까지 루프 수행
    }

    set_load_weight(&init_task);
    // set_load_weight에서 한일:
    // (&(&init_task)->se.load)->weight: 1024
    // (&(&init_task)->se.load)->inv_weight: 4194304

#ifdef CONFIG_PREEMPT_NOTIFIERS // CONFIG_PREEMPT_NOTIFIERS=n
    INIT_HLIST_HEAD(&init_task.preempt_notifiers);
#endif

#ifdef CONFIG_RT_MUTEXES // CONFIG_RT_MUTEXES=y
    plist_head_init(&init_task.pi_waiters);
    // plist_head_init에서 한일:
    // (&init_task.pi_waiters)->node_list 리스트 초기화
#endif

    /*
     * The boot idle thread does lazy MMU switching as well:
     */
    // init_mm.mm_count: 1
    atomic_inc(&init_mm.mm_count);
    // init_mm.mm_count: 2

    // current: init_task
    enter_lazy_tlb(&init_mm, current); // null function

    /*
     * Make us the idle thread. Technically, schedule() should not be
     * called from this thread, however somewhere below it might be,
     * but because we are the idle thread, we just pick up running again
     * when this runqueue becomes "idle".
     */
    // current: &init_task, smp_processor_id(): 0
    init_idle(current, smp_processor_id());
    // init_idle에서 한일:
    // (&init_task)->on_rq: 0
    // (&init_task)->se.on_rq: 0
    // (&init_task)->se.exec_start: 0
    // (&init_task)->se.sum_exec_runtime: 0
    // (&init_task)->se.prev_sum_exec_runtime: 0
    // (&init_task)->se.nr_migrations: 0
    // (&init_task)->se.vruntime: 0
    // &(&init_task)->se.group_node의 리스트 초기화
    // &(&init_task)->rt.run_list의 리스트 초기화
    // (&init_task)->state: TASK_RUNNING: 0
    // (&init_task)->se.exec_start: 0
    // (&init_task)->cpus_allowed->bits[0]: 1
    // (&init_task)->nr_cpus_allowed: 1
    // ((struct thread_info *)(&init_task)->stack)->cpu: 0
    // (&init_task)->wake_cpu: 0
    // [pcpu0] (&runqueues)->curr: &init_task
    // [pcpu0] (&runqueues)->idle: &init_task
    // (&init_task)->on_cpu: 1
    // ((struct thread_info *)(&init_task)->stack)->preempt_count: PREEMPT_ENABLED: 0
    // (&init_task)->sched_class: &idle_sched_class
    // (&init_task)->comm: "swapper/0"

    // jiffies: -30000 (0xFFFFFFFFFFFF8AD0): vmlinux.lds.S 에 있음, LOAD_FREQ: 501
    calc_load_update = jiffies + LOAD_FREQ;
    // calc_load_update: -29499 (0xFFFFFFFFFFFF8cc5)

    /*
     * During early bootup we pretend to be a normal task:
     */
    // current->sched_class: (&init_task)->sched_class
    current->sched_class = &fair_sched_class;
    // current->sched_class: (&init_task)->sched_class: &fair_sched_class

#ifdef CONFIG_SMP // CONFIG_SMP=y
    // GFP_NOWAIT: 0
    zalloc_cpumask_var(&sched_domains_tmpmask, GFP_NOWAIT);
    // sched_domains_tmpmask.bits[0]: 0

// 2014/09/13 종료
// 2014/09/20 시작

    /* May be allocated at isolcpus cmdline parse time */
    // cpu_isolated_map: NULL
    if (cpu_isolated_map == NULL)
        // cpu_isolated_map: NULL, GFP_NOWAIT: 0
        zalloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT);
        // cpu_isolated_map.bits[0]: 0

    idle_thread_set_boot_cpu();
    // [pcp0] idle_threads: &init_task
#endif
    init_sched_fair_class();
    // init_sched_fair_class가 한일:
    // softirq_vec[7].action: run_rebalance_domains
    // nohz.next_balance: -30000 (0xFFFFFFFFFFFF8AD0)
    // nohz.idle_cpus_mask.bits[0]: 0
    // (&cpu_chain)->head: sched_ilb_notifier_nb 포인터 대입
    // (&sched_ilb_notifier_nb)->next은 (&slab_notifier)->next로 대입

    scheduler_running = 1;
    // scheduler_running: 1
}

sched_init()에서 호출하는 주요 서브 함수

  • sched_init()->init_defrootdomain()
    • // def_root_domain의 맴버 값을 초기화 수행
    • // (&(&(&def_root_domain)->cpupri)->pri_to_cpu[0 ... 101])->count: 0
    • // (&(&(&def_root_domain)->cpupri)->pri_to_cpu[0 ... 101])->mask.bit[0]: 0
    • // (&(&def_root_domain)->cpupri)->pri_to_cpu[0 ... 3]: -1
    • // &def_root_domain.refcount: 1
  • sched_init()->init_rt_bandwidth(&def_rt_bandwidth, global_rt_period(), global_rt_runtime());
    • // init_rt_bandwidth에서 한일:
    • // (&def_rt_bandwidth)->rt_period: 1000000000
    • // (&def_rt_bandwidth)->rt_runtime: 950000000
    • // &(&def_rt_bandwidth)->rt_runtime_lock을 사용한 spinlock 초기화
    • // (&def_rt_bandwidth)->rt_period_timer의 값을 0으로 초기화
    • // &(&def_rt_bandwidth)->rt_period_timer)->base: &hrtimer_bases->clock_base[0]
    • // (&(&(&def_rt_bandwidth)->rt_period_timer)->node)->node의 RB Tree의 초기화
    • // &(&def_rt_bandwidth)->rt_period_timer.function: sched_rt_period_timer
  • sched_init()::for_each_possible_cpu(i) { ... }
  • sched_init()->set_load_weight()
    • // (&(&init_task)->se.load)->weight: 1024
    • // (&(&init_task)->se.load)->inv_weight: 4194304
  • sched_init()->plist_head_init()
    • // (&init_task.pi_waiters)->node_list 리스트 초기화
  • sched_init()->init_idle()
    • // (&init_task)->on_rq: 0
    • // (&init_task)->se.on_rq: 0
    • // (&init_task)->se.exec_start: 0
    • // (&init_task)->se.sum_exec_runtime: 0
    • // (&init_task)->se.prev_sum_exec_runtime: 0
    • // (&init_task)->se.nr_migrations: 0
    • // (&init_task)->se.vruntime: 0
    • // &(&init_task)->se.group_node의 리스트 초기화
    • // &(&init_task)->rt.run_list의 리스트 초기화
    • // (&init_task)->state: TASK_RUNNING: 0
    • // (&init_task)->se.exec_start: 0
    • // (&init_task)->cpus_allowed->bits[0]: 1
    • // (&init_task)->nr_cpus_allowed: 1
    • // ((struct thread_info *)(&init_task)->stack)->cpu: 0
    • // (&init_task)->wake_cpu: 0
    • // pcpu0->curr: &init_task
    • // pcpu0->idle: &init_task
    • // (&init_task)->on_cpu: 1
    • // ((struct thread_info *)(&init_task)->stack)->preempt_count: PREEMPT_ENABLED: 0
    • // (&init_task)->sched_class: &idle_sched_class
    • // (&init_task)->comm: "swapper/0"
  • sched_init()->zalloc_cpumask_var()
    • // sched_domains_tmpmask.bits[0]: 0
  • sched_init()->idle_thread_set_boot_cpu();
    • // [pcp0] idle_threads: &init_task
  • sched_init()->init_sched_fair_class();
    • // softirq_vec[7].action: run_rebalance_domains
    • // nohz.next_balance: -30000 (0xFFFFFFFFFFFF8AD0)
    • // nohz.idle_cpus_mask.bits[0]: 0
    • // (&cpu_chain)->head: sched_ilb_notifier_nb 포인터 대입
    • // (&sched_ilb_notifier_nb)->next은 (&slab_notifier)->next로 대입

cpumask.h::zalloc_cpumask_var()

// ARM10C 20140913
// &sched_domains_tmpmask, GFP_NOWAIT: 0
static inline bool zalloc_cpumask_var(cpumask_var_t *mask, gfp_t flags)
{
    // *mask: sched_domains_tmpmask
    cpumask_clear(*mask);
    // sched_domains_tmpmask.bits[0]: 0

    return true;
}

smpboot.c::idle_thread_set_boot_cpu()

// ARM10C 20140920
void __init idle_thread_set_boot_cpu(void)
{
    // smp_processor_id(): 0,
    // per_cpu(idle_threads, 0):
    // ({
    //      do {
    //      const void __percpu *__vpp_verify = (typeof(&(idle_threads)))NULL;
    //      (void)__vpp_verify;
    //      } while (0)
    //      (&(idle_threads) + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋);
    // }),
    // current: &init_task
    per_cpu(idle_threads, smp_processor_id()) = current;
    // [pcp0] idle_threads: &init_task

}
// NOTE: // 주석의 편의를 위해 // (&(idle_threads) + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋) 를 // [pcp0] idle_threads 로 표시

main.c::start_kernel()

  • sched_init();
    • scheduler가 사용하는 자료 구조 초기화, idle_threads를 init_task로 세팅
  • preempt_disable();
    • preempt count를 증가시켜 preemption 못하도록 막음
  • irqs_disabled(): 1
  • idr_init_cache();
    • integer ID management로 사용하는 idr_layer_cache에 kmem_cache#21 을 생성 및 초기화 후 할당
  • rcu_init();
    • 분석 진행 중
asmlinkage void __init start_kernel(void)
{
...

    sched_init();
    // scheduler가 사용하는 자료 구조 초기화, idle_threads를 init_task로 세팅

    /*
     * Disable preemption - early bootup scheduling is extremely
     * fragile until we cpu_idle() for the first time.
     */
    preempt_disable();
    // preempt count를 증가시켜 preemption 못하도록 막음

    // irqs_disabled(): 1
    if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n"))
        local_irq_disable();

    idr_init_cache();
    // integer ID management로 사용하는 idr_layer_cache에 kmem_cache#21 을 생성 및 초기화 후 할당

    rcu_init();

preempt.h::preempt_disabled()

#define preempt_disable()/*ARM10C this*/    \
do { \
    preempt_count_inc(); \
    barrier(); \
} while (0)

idr.c::idr_init_cache()

  • idr_layer_cache: kmem_cache#21
// ARM10C 20140920
void __init idr_init_cache(void)
{
    // sizeof(struct idr_layer): 1076 bytes, SLAB_PANIC: 0x00040000UL
    // kmem_cache_create("idr_layer_cache", 1076, 0, SLAB_PANIC: 0x00040000UL, NULL): kmem_cache#21
    idr_layer_cache = kmem_cache_create("idr_layer_cache",
                sizeof(struct idr_layer), 0, SLAB_PANIC, NULL);
    // idr_layer_cache: kmem_cache#21
}

tree.c::rcu_init()

// ARM10C 20140920
void __init rcu_init(void)
{
    int cpu;

    rcu_bootup_announce();
    rcu_init_geometry();
    // rcu_init_geometry에서 한일:
    // jiffies_till_first_fqs: 1
    // jiffies_till_next_fqs: 1

// 2014/09/20 종료

댓글 없음:

댓글 쓰기