[커널 18차] 85주차

2023.01.07 22:26

kkr 조회 수:53

PELT core 기능 끝. schedule tick, cfs 계속 진행중.

 

git : https://github.com/iamroot18/5.10/commit/4f520464f3a4ae9273f8d9a9da459e5876b78d23

 

diff --git a/arch/arm64/include/asm/preempt.h b/arch/arm64/include/asm/preempt.h
index 69b779947436..4529230e5f3a 100644
--- a/arch/arm64/include/asm/preempt.h
+++ b/arch/arm64/include/asm/preempt.h
@@ -38,6 +38,10 @@ static inline void preempt_count_set(u64 pc)
     task_thread_info(p)->preempt_count = PREEMPT_DISABLED; \
 } while (0)
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - reschedule 요청.
+ */
 static inline void set_preempt_need_resched(void)
 {
     current_thread_info()->preempt.need_resched = 0;
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index d979405d9f98..85533ca9b624 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -1022,6 +1022,10 @@ static irqreturn_t ipi_handler(int irq, void *data)
     return IRQ_HANDLED;
 }
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - @ipinr을 @target에 요청한다.
+ */
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
 {
     trace_ipi_raise(target, ipi_types[ipinr]);
@@ -1107,6 +1111,11 @@ void __init set_smp_ipi_range(int ipi_base, int n)
     ipi_setup(smp_processor_id());
 }
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - @cpu에 ipi reschedule 요청을 한다. ipi를 받은 cpu에선
+ *   do_handle_IPI()를 통해서 scheduler_ipi()가 호출된다.
+ */
 void smp_send_reschedule(int cpu)
 {
     smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE);
diff --git a/include/linux/preempt.h b/include/linux/preempt.h
index e6424e96b55d..71e970f0555f 100644
--- a/include/linux/preempt.h
+++ b/include/linux/preempt.h
@@ -306,6 +306,11 @@ do { \
 do { \
     set_preempt_need_resched(); \
 } while (0)
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - current task info reschedule 요청이 있으면 reschedule set한다.
+ */
 #define preempt_fold_need_resched() \
 do { \
     if (tif_need_resched()) \
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 80f60bbf021b..f6fc6140f117 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -651,6 +651,12 @@ struct sched_statistics {
  */
 struct sched_entity {
     /* For load-balancing: */
+/*
+ * IAMROOT, 2023.01.07:
+ * - tg shares * load 기여율의 비율에따른 shares값이 load에 set된다.
+ *   (update_cfs_group(), calc_group_shares(), reweight_entity()참고)
+ *   단, cfs_rq에 들어가는 load weight은 해당 entity들의 weight 총합이 된다.
+ */
     struct load_weight        load;
     struct rb_node            run_node;
     struct list_head        group_node;
@@ -2221,6 +2227,12 @@ extern char *__get_task_comm(char *to, size_t len, struct task_struct *tsk);
 })
 
 #ifdef CONFIG_SMP
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - 별거안한다. reschedule은 interrupt를 빠져나가면서 수행하기 때문에
+ *   reschedule ipi를 받았다는 명목상의 이유로 호출할뿐이다.
+ */
 static __always_inline void scheduler_ipi(void)
 {
     /*
@@ -2269,11 +2281,19 @@ static inline int test_and_clear_tsk_thread_flag(struct task_struct *tsk, int fl
     return test_and_clear_ti_thread_flag(task_thread_info(tsk), flag);
 }
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - @flag가 있으면 return 1. 없으면 return 0
+ */
 static inline int test_tsk_thread_flag(struct task_struct *tsk, int flag)
 {
     return test_ti_thread_flag(task_thread_info(tsk), flag);
 }
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - @tsk에 set TIF_NEED_RESCHED. reschedule 요청.
+ */
 static inline void set_tsk_need_resched(struct task_struct *tsk)
 {
     set_tsk_thread_flag(tsk,TIF_NEED_RESCHED);
@@ -2284,6 +2304,11 @@ static inline void clear_tsk_need_resched(struct task_struct *tsk)
     clear_tsk_thread_flag(tsk,TIF_NEED_RESCHED);
 }
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - TIF_NEED_RESCHED이 있으면 return 1. 없으면 return 0.
+ * - resched 요청이 있는지 확인한다.
+ */
 static inline int test_tsk_need_resched(struct task_struct *tsk)
 {
     return unlikely(test_tsk_thread_flag(tsk,TIF_NEED_RESCHED));
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index 0999f6317978..36c54624e7dc 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -113,6 +113,10 @@ static inline int test_and_clear_ti_thread_flag(struct thread_info *ti, int flag
     return test_and_clear_bit(flag, (unsigned long *)&ti->flags);
 }
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - @flag있으면 return 1. 없으면 return 0.
+ */
 static inline int test_ti_thread_flag(struct thread_info *ti, int flag)
 {
     return test_bit(flag, (unsigned long *)&ti->flags);
@@ -163,6 +167,10 @@ static inline int test_ti_thread_flag(struct thread_info *ti, int flag)
     clear_ti_thread_flag(task_thread_info(t), TIF_##fl)
 #endif /* !CONFIG_GENERIC_ENTRY */
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - current_thread_info에 TIF_NEED_RESCHED이 있는지 확인한다.
+ */
 #define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED)
 
 #ifndef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES
diff --git a/kernel/irq/ipi.c b/kernel/irq/ipi.c
index 08ce7da3b57c..371ad55bba93 100644
--- a/kernel/irq/ipi.c
+++ b/kernel/irq/ipi.c
@@ -260,6 +260,11 @@ int __ipi_send_single(struct irq_desc *desc, unsigned int cpu)
  *
  * Return: %0 on success or negative error number on failure.
  */
+/*
+ * IAMROOT, 2023.01.07:
+ * - cpumask로 ipi를 전송하는 기능이 있으면 그걸 사용하고 아니면 single로 interate 
+ *   하면서 호출한다.
+ */
 int __ipi_send_mask(struct irq_desc *desc, const struct cpumask *dest)
 {
     struct irq_data *data = irq_desc_get_irq_data(desc);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 16ea63efd0e8..b2f11935b2c9 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -876,6 +876,15 @@ static inline void hrtick_rq_init(struct rq *rq)
  * this avoids any races wrt polling state changes and thereby avoids
  * spurious IPIs.
  */
+/*
+ * IAMROOT, 2023.01.07:
+ * - papago
+ *   원자 단위로 TIF_NEED_RESCHED를 설정하고 TIF_POLLING_NRFLAG를 
+ *   테스트하면 폴링 상태 변경에 대한 경합을 방지하여 가짜 IPI를 방지할 
+ *   수 있습니다.
+ *
+ * - cpu 경합 방지를 위한 코드. arm 계열은 아래 쪽 code를 사용한다.
+ */
 static bool set_nr_and_not_polling(struct task_struct *p)
 {
     struct thread_info *ti = task_thread_info(p);
@@ -907,6 +916,11 @@ static bool set_nr_if_polling(struct task_struct *p)
 }
 
 #else
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - arm64 @p에 reschedule 요청.
+ */
 static bool set_nr_and_not_polling(struct task_struct *p)
 {
     set_tsk_need_resched(p);
@@ -1016,7 +1030,8 @@ void wake_up_q(struct wake_q_head *head)
  */
 /*
  * IAMROOT, 2022.12.22:
- * - TODO
+ * - @rq가 자기자신이면 reschedule 수행. 아닌 경우 @rq의 cpu로
+ *   ipi를 통해서 reschedule 요청을 한다.
  */
 void resched_curr(struct rq *rq)
 {
@@ -1025,17 +1040,31 @@ void resched_curr(struct rq *rq)
 
     lockdep_assert_rq_held(rq);
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - reschedule 요청이 있으면 빠져나간다.
+ */
     if (test_tsk_need_resched(curr))
         return;
 
     cpu = cpu_of(rq);
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - @rq가 현재 cpu라면 reschedule요청을 한다.
+ */
     if (cpu == smp_processor_id()) {
         set_tsk_need_resched(curr);
         set_preempt_need_resched();
         return;
     }
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - @rq가 현재 cpu가 아닌 상태. rq의 cpu의 대상으로 reschedule ipi를 보낸다.
+ *   해당 cpu는 interrupt가 끝나면 reschedule을 할 것이다.
+ */
+
     if (set_nr_and_not_polling(curr))
         smp_send_reschedule(cpu);
     else
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 1669eaf96604..608a9932625c 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -35,6 +35,11 @@
  *
  * (default: 6ms * (1 + ilog(ncpus)), units: nanoseconds)
  */
+/*
+ * IAMROOT, 2023.01.07:
+ * - TODO
+ * - 6ms
+ */
 unsigned int sysctl_sched_latency            = 6000000ULL;
 static unsigned int normalized_sysctl_sched_latency    = 6000000ULL;
 
@@ -152,6 +157,11 @@ static inline void update_load_sub(struct load_weight *lw, unsigned long dec)
     lw->inv_weight = 0;
 }
 
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - @w를 weight로 사용.
+ */
 static inline void update_load_set(struct load_weight *lw, unsigned long w)
 {
     lw->weight = w;
@@ -822,8 +832,16 @@ static inline u64 calc_delta_fair(u64 delta, struct sched_entity *se)
  *
  * p = (nr <= nl) ? l : l*nr/nl
  */
+/*
+ * IAMROOT, 2023.01.07:
+ * - ING
+ */
 static u64 __sched_period(unsigned long nr_running)
 {
+/*
+ * IAMROOT, 2023.01.07:
+ * - sched_nr_latency(8개) 이상일 때에는 
+ */
     if (unlikely(nr_running > sched_nr_latency))
         return nr_running * sysctl_sched_min_granularity;
     else
@@ -836,11 +854,23 @@ static u64 __sched_period(unsigned long nr_running)
  *
  * s = p*P[w/rw]
  */
+/*
+ * IAMROOT, 2023.01.07:
+ * - ING
+ */
 static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
+/*
+ * IAMROOT, 2023.01.07:
+ * - entity 수를 nr_running으로 사용한다.
+ */
     unsigned int nr_running = cfs_rq->nr_running;
     u64 slice;
     
+/*
+ * IAMROOT, 2023.01.07:
+ * - 계층구조의 task 수로 갱신한다.
+ */
     if (sched_feat(ALT_PERIOD))
         nr_running = rq_of(cfs_rq)->cfs.h_nr_running;
 
@@ -3257,6 +3287,12 @@ account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
 } while (0)
 
 #ifdef CONFIG_SMP
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - @se는 @cfs_rq에 속해있다. @cfs_rq에 @se의 값들을 적산한다.
+ *   cfs_rq의 load_sum엔, 속해있는 entity의 weight가 적용되서 들어간다.
+ */
 static inline void
 enqueue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
@@ -3264,6 +3300,11 @@ enqueue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
     cfs_rq->avg.load_sum += se_weight(se) * se->avg.load_sum;
 }
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - @cfs_rq에서 @se에 대한 값을 뺀다.
+ * - @cfs_rq에서 @se에 대한 load_avg를 빼고, cfs_rq의 sum을 다시 계산한다.
+ */
 static inline void
 dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
@@ -3279,13 +3320,64 @@ dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
 #endif
 
 /*
- * IAMROOT, 2022.12.29:
- * - TODO
+ * IAMROOT, 2023.01.07:
+ * - @se의 load weight에 tg에 기여한 load비율에 따른 shares값을 set한다.
+ * - ex) cpu가 2개있는 상황. cpu0 = 50% 이였다가 cpu1 = 30%로 떨어지는 상황.
+ *       weight는 330으로 가정.
+ *
+ *   reweight_entity 진입전 값들정리(cpu0 = 50%)
+ *   cfs_rq load weight = 1024
+ *   cfs_rq load avg    = 1024 
+ *   cfs_rq load sum    = 47742
+ *
+ *   se load weight = 512
+ *   se load avg    = 512
+ *   se load sum    = 47742 / 2
+ *
+ *   cpu0 se weight = 512
+ *
+ *   reweight_entity 수행
+ *   1) update_load_sub()
+ *      cfs_rq load weight = 1024 - 512 = 512
+ *
+ *   2) dequeue_load_avg()
+ *      cfs_rq load avg    = 1024 - 512 = 512
+ *      cfs_rq load sum    = 47742 / 2
+ *
+ *   3) update_load_set
+ *      se weight = 330
+ *
+ *   4) se load_avg 재계산
+ *      se load avg = (330 * (47742 / 2)) / 47742
+ *                  = 165
+ *
+ *   5) enqueue_load_avg
+ *      cfs_rq load avg = 512 + 165 = 677
+ *      cfs_rq load sum = (47742 * 677) / 1024
+ *
+ *   6) update_load_add
+ *      cfs_rq load weight = 512 + 330 = 842
+ *
+ *   7) 결과
+ *   cfs_rq load weight 1024 -> 842
+ *   cfs_rq load avg    1024 -> 677
+ *   cfs_rq load sum    100% -> 약 70%
+ *   se load weight     512  -> 330
+ *   se load avg        512  -> 165
+ *   se load sum        50%  -> 50%(계산안함)
+ *
+ * - 1) @cfs_rq의 기존 @se값을 뺀다.
+ *   2) @se의 weight를 @weight(tg shares비율)로 갱신한다.
+ *   3) 변경된 @se를 @cfs_rq에 적용한다.
  */
 static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
                 unsigned long weight)
 {
     if (se->on_rq) {
+/*
+ * prifri, 2023.01.07:
+ * - @cfs_rq에서 @se에 대한 weight와 load값들을 뺀다.
+ */
         /* commit outstanding execution time */
         if (cfs_rq->curr == se)
             update_curr(cfs_rq);
@@ -3293,6 +3385,10 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
     }
     dequeue_load_avg(cfs_rq, se);
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - @weight(shares)을 @se->load에 set한다.
+ */
     update_load_set(&se->load, weight);
 
 #ifdef CONFIG_SMP
@@ -3303,6 +3399,11 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
     } while (0);
 #endif
 
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - @cfs_rq에 다시계산된 @se를 적산한다.
+ */
     enqueue_load_avg(cfs_rq, se);
     if (se->on_rq)
         update_load_add(&cfs_rq->load, se->load.weight);
@@ -3399,13 +3500,189 @@ void reweight_task(struct task_struct *p, int prio)
  *
  * hence icky!
  */
+/*
+ * IAMROOT, 2023.01.07:
+ * - papago
+ *   이 모든 것은 우리 모두가 싫어하는 전체 합계를 포함하는 계층적 비율에 가깝습니다.
+ *
+ *   즉, 그룹 엔터티의 가중치는 그룹 실행 대기열 가중치를 기반으로 한 그룹 가중치의 비례적 
+ *   공유입니다. 그건: 
+ *
+ *                     tg->weight * grq->load.weight
+ *   ge->load.weight = -----------------------------               (1)
+ *                       \Sum grq->load.weight
+ *  
+ *  이제 그 합계를 계산하는 것은 엄청나게 비용이 많이 들기 때문에(거기에 있었고, 
+ *  완료했습니다) 우리는 이 평균값으로 근사합니다. 평균은 느리게 이동하므로 근사값이 더 
+ *  저렴하고 안정적입니다.
+ *
+ *  따라서 위의 대신 다음을 대체합니다. 
+ *
+ *  grq->load.weight -> grq->avg.load_avg (2)
+ *
+ *  결과는 다음과 같습니다. 
+ *
+ *
+ *                     tg->weight * grq->avg.load_avg
+ *   ge->load.weight = ------------------------------              (3)
+ *                             tg->load_avg
+ *
+ *  (\Sum grep->load.weight가 의미론적으로 tg->load_avg와 일치한다. )
+ *
+ * Where: tg->load_avg ~= \Sum grq->avg.load_avg
+ *
+ * 그것은 share_avg이며, 맞습니다(주어진 근사치(2)).
+ *
+ * 문제는 평균이 느리기 때문에(당연히 정확히 그렇게 설계되었으므로) 경계 조건에서 과도 
+ * 현상이 발생한다는 것입니다. 특히 그룹이 유휴 상태이고 하나의 작업을 시작하는 경우입니다. 
+ * CPU의 grq->avg.load_avg가 쌓이는 데 시간이 걸리고 대기 시간이 좋지 않습니다. 
+ *
+ * 이제 특별한 경우 (1)은 다음과 같이 줄어듭니다.
+ *
+ *                     tg->weight * grq->load.weight
+ *   ge->load.weight = ----------------------------- = tg->weight   (4)
+ *                         grp->load.weight
+ *                         
+ * 즉, 다른 모든 CPU가 유휴 상태이므로 합계가 축소됩니다. UP 시나리오.
+ *
+ * 따라서 우리가 하는 일은 다음과 같이 (가까운) UP 사례에서 (4)에 접근하도록 근사치 (3)을 
+ * 수정하는 것입니다.
+ *
+ *   ge->load.weight =
+ *
+ *              tg->weight * grq->load.weight
+ *     ---------------------------------------------------         (5)
+ *     tg->load_avg - grq->avg.load_avg + grq->load.weight
+ *  
+ *  (
+ *     ex) rq 2개.
+ *         rq 1개가 idle. 1개가 tg의 load를 100%했을때. 즉 UP와 다름 없는 상황.
+ *         tg->load_avg == grp->avg.load_avg
+ *
+ *              tg->weight * grq->load.weight
+ *     ---------------------------------------------------         
+ *     tg->load_avg - tg->load_avg + grq->load.weight
+ *
+ *     =
+ *              tg->weight * grq->load.weight
+ *     --------------------------------------------------- = tg->weight
+ *                     grq->load.weight
+ *
+ *     ex) rq 2개.
+ *         rq 1개가 50%. 1개가 50%했을때. 
+ *
+ *         tg->load_avg / 2 == grp->avg.load_avg
+ *
+ *              tg->weight * grq->load.weight
+ *     ---------------------------------------------------         
+ *     tg->load_avg - tg->load_avg / 2 + grq->load.weight
+ *
+ *     =
+ *              tg->weight * grq->load.weight
+ *     ---------------------------------------------------
+ *           tg->load_avg / 2 + grq->load.weigh
+ *
+ *     ex) rq 2개.
+ *         rq 1개가 70%. 1개가 30%했을때. 70%의 기준의 계산
+ *
+ *         tg->load_avg * 7 / 10 == grp->avg.load_avg
+ *
+ *              tg->weight * grq->load.weight
+ *     ---------------------------------------------------         
+ *     tg->load_avg - tg->load_avg * 7 / 10 + grq->load.weight
+ *
+ *     =
+ *              tg->weight * grq->load.weight
+ *     ---------------------------------------------------
+ *           tg->load_avg * 3 / 10 + grq->load.weigh
+ *
+ *
+ *    30%%의 기준의 결과값.
+ *
+ *              tg->weight * grq->load.weight
+ *     ---------------------------------------------------
+ *           tg->load_avg * 7 / 10 + grq->load.weigh
+ *  )
+ *
+ * 그러나 grq->load.weight가 0으로 떨어질 수 있으므로 결과적으로 0으로 나누기 때문에 
+ * grq->avg.load_avg를 하한으로 사용해야 합니다. 그런 다음 다음을 제공합니다.
+ *
+ *
+ *                     tg->weight * grq->load.weight
+ *   ge->load.weight = -----------------------------           (6)
+ *                             tg_load_avg'
+ *
+ * Where:
+ *
+ *   tg_load_avg' = tg->load_avg - grq->avg.load_avg +
+ *                  max(grq->load.weight, grq->avg.load_avg)
+ *
+ * 그리고 그것은 share_weight이고 엉뚱합니다. (가까운) UP 경우에는 (4)에 접근하고 일반적인 
+ * 경우에는 (3)에 접근합니다. ge->load.weight를 일관되게 과대평가하므로 다음과 같습니다.
+ *
+ *   \Sum ge->load.weight >= tg->weight
+ *
+ * hence icky!
+ *
+ * - @cfs_rq의 tg에 대한 기여도만큼 shares을 n등분을 하여 reweight를 한다.
+ * - ex) tg shares = 1024,
+ *       tg load_avg = 512
+ *       cpu0 cfs_rq->tg_load_avg_contrib = 100, load = 95
+ *       cpu1 cfs_rq->tg_load_avg_contrib = 412, load = 400
+ *
+ *       1) cpu0
+ *       tg_weight = 512 - 100 + 95 = 507
+ *       shares / tg_weight = 1024 * 95 / 507 = 191
+ *       2) cpu1
+ *       tg_weight = 512 - 412 + 400 = 500
+ *       shares / tg_weight = 1024 * 400 / 500 = 819
+ *
+ *
+ * - tg->shares에 대해서 cfs_rq의 load 기여도에따른 비율의 근사값으로
+ *   shares 값을 구한다.
+ */
 static long calc_group_shares(struct cfs_rq *cfs_rq)
 {
     long tg_weight, tg_shares, load, shares;
     struct task_group *tg = cfs_rq->tg;
 
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - 6번식을 수행한다.
+ *                     tg->weight * grq->load.weight
+ *   ge->load.weight = -----------------------------           (6)
+ *                             tg_load_avg'
+ *
+ * Where:
+ *
+ *   tg_load_avg' = tg->load_avg - grq->avg.load_avg +
+ *                  max(grq->load.weight, grq->avg.load_avg)
+ *
+ * - tg->weight => tg->shares로 치환해서 생각한다.
+ *   grq->avg.load_avg => cfs_rq->tg_load_avg_contrib로 치환해서 생각한다.
+ *
+ *
+ * - 풀어쓰기 
+ *   load = max(scale_load_down(cfs_rq->load.weight), cfs_rq->avg.load_avg);
+ *
+ *                     tg->weight * grq->load.weight
+ *   ge->load.weight = -----------------------------           
+ *                             tg_load_avg'
+ *
+ *   =>
+ *                          tg->shares * load
+ *   return = --------------------------------------------------
+ *             tg->load_avg - cfs_rq->tg_load_avg_contrib + load
+ *             
+ */
     tg_shares = READ_ONCE(tg->shares);
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - @weight보다는 높은 load avg를 사용한다. weight가 0일수도있어서 거기에 대한
+ *   예외처리.
+ */
     load = max(scale_load_down(cfs_rq->load.weight), cfs_rq->avg.load_avg);
 
     tg_weight = atomic_long_read(&tg->load_avg);
@@ -3415,6 +3692,7 @@ static long calc_group_shares(struct cfs_rq *cfs_rq)
     tg_weight += load;
 
     shares = (tg_shares * load);
+
     if (tg_weight)
         shares /= tg_weight;
 
@@ -3430,6 +3708,18 @@ static long calc_group_shares(struct cfs_rq *cfs_rq)
      * case no task is runnable on a CPU MIN_SHARES=2 should be returned
      * instead of 0.
      */
+/*
+ * IAMROOT, 2023.01.07:
+ * - papago
+ *   MIN_SHARES는 tg->shares 값이 작은 그룹의 CPU당 파티셔닝을 지원하기 위해 
+ *   여기에서 크기를 조정하지 않아야 합니다. CPU에서 그룹을 나타내는 
+ *   sched_entity에 최소 load.weight로 할당되는 floor 값입니다. 
+ *
+ *   예를 들어 64비트에서 tg->shares of scale_load(15)=15*1024 그룹의 경우 
+ *   하나의 CPU 공유에서 각각 실행 가능한 8개의 작업이 있는 8코어 시스템에서 
+ *   15*1024*1/8=1920이 되어야 합니다. scale_load(MIN_SHARES)=2*1024. 
+ *   CPU에서 실행할 수 있는 작업이 없는 경우 MIN_SHARES=2가 0 대신 반환되어야 합니다. 
+ */
     return clamp_t(long, shares, MIN_SHARES, tg_shares);
 }
 #endif /* CONFIG_SMP */
@@ -3440,26 +3730,60 @@ static inline int throttled_hierarchy(struct cfs_rq *cfs_rq);
  * Recomputes the group entity based on the current state of its group
  * runqueue.
  */
+/*
+ * IAMROOT, 2023.01.07:
+ * - @se에 group인경우 tg의 기여도에따른 shares를 weight로
+ *   가져와 update한다.
+ */
 static void update_cfs_group(struct sched_entity *se)
 {
     struct cfs_rq *gcfs_rq = group_cfs_rq(se);
     long shares;
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - @se가 task인경우는 gcfs_rq가 없다. group에 대한 처리를
+ *   수행하므로 return.
+ */
     if (!gcfs_rq)
         return;
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - throttle중이면 return.
+ */
     if (throttled_hierarchy(gcfs_rq))
         return;
 
 #ifndef CONFIG_SMP
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - UMP일 경우.
+ * - @se weight와 group의 shares가 같으면 return.
+ *   reweight을 할 필요가 없다.
+ *   초기값은 shares기준으로 만들어지기때문이다. 
+ *   shares나 weight이 변경되는 경우만 아래로 진입할것이다.
+ */
     shares = READ_ONCE(gcfs_rq->tg->shares);
 
     if (likely(se->load.weight == shares))
         return;
 #else
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - @gcfs_rq의 load 기여도에 따른 shares을 구한다.
+ */
     shares   = calc_group_shares(gcfs_rq);
 #endif
 
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - shares값을 @se의 weight에 적용하고 se의 rq에 변경된 값들을
+ *   재적용한다.
+ */
     reweight_entity(cfs_rq_of(se), se, shares);
 }
 
@@ -3469,6 +3793,11 @@ static inline void update_cfs_group(struct sched_entity *se)
 }
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - @cfs_rq가 root이면 cpufreq_update_util을 호출해준다.
+ *   @cfs_rq의 상태에 따라 cpu freq를 변경할수도있다.
+ */
 static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq, int flags)
 {
     struct rq *rq = rq_of(cfs_rq);
@@ -3488,6 +3817,20 @@ static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq, int flags)
          *
          * See cpu_util().
          */
+/*
+ * IAMROOT, 2023.01.07:
+ * - papago
+ *   이것이 놓칠 수 있는 몇 가지 경계 사례가 있지만 실제 문제가 되지 않도록 
+ *   충분히 자주 호출되어야 합니다. 
+ *
+ *   유휴 스레드가 다른 클래스(!fair)이기 때문에 유휴 상태일 때 호출되지 않으며 
+ *   사용률에 RT 작업과 같은 항목이 포함되지 않습니다.
+ *
+ *   있는 그대로, util 번호는 freq-invariant가 아닙니다(이를 위해 
+ *   arch_scale_freq_capacity()를 구현해야 합니다). 
+ *
+ *   cpu_util()을 참조하십시오. 
+ */
         cpufreq_update_util(rq, flags);
     }
 }
@@ -3577,6 +3920,23 @@ static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq)
  *
  * Updating tg's load_avg is necessary before update_cfs_share().
  */
+/*
+ * IAMROOT, 2023.01.07:
+ * - papago
+ *   update_tg_load_avg - update the tg's load avg 
+ *   @cfs_rq: the cfs_rq whose avg changed
+ *
+ *   이 기능은 다음을 '보장'합니다. tg->load_avg := \Sum tg->cfs_rq[]->avg.load.
+ *   그러나 tg->load_avg는 전역 값이므로 성능을 고려해야 합니다.
+ *
+ *   다른 cfs_rq를 볼 필요가 없도록 전파한 마지막 값을 저장하는 차등 업데이트를 사용합니다. 
+ *   차등이 '작은' 경우 업데이트를 건너뛸 수 있습니다.
+ *
+ *   update_cfs_share() 전에 tg의 load_avg 업데이트가 필요합니다.
+ *
+ * - task group에 update한다. 적당한 값이상으로 변화된 경우에만 (직전값의 1 / 64보다 큰값)
+ *   update한다.
+ */
 static inline void update_tg_load_avg(struct cfs_rq *cfs_rq)
 {
     long delta = cfs_rq->avg.load_avg - cfs_rq->tg_load_avg_contrib;
@@ -3587,6 +3947,13 @@ static inline void update_tg_load_avg(struct cfs_rq *cfs_rq)
     if (cfs_rq->tg == &root_task_group)
         return;
 
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - @cfs_rq의 taskgroup에 delta를 추가한다.
+ *   방금 추가한 @cfs_rq에 대한 load_avg를 tg_load_avg_contrib에 기록해놓는다.
+ * - delta가 어느정도 이상인 경우만 update한다.
+ */
     if (abs(delta) > cfs_rq->tg_load_avg_contrib / 64) {
         atomic_long_add(delta, &cfs_rq->tg->load_avg);
         cfs_rq->tg_load_avg_contrib = cfs_rq->avg.load_avg;
@@ -4030,19 +4397,8 @@ update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq
  * IAMROOT, 2022.12.31:
  * - 감소됬다면 task runnable이 균등하게 계산한다는 관점으로 avg와 weight로 
  *   재계산한다.
- *   재계산시에는 위에서 유도한 식을 토대로 적용한다.
  *
- *                      ge->load.weight * grq->avg.load_avg
- *   ge->avg.load_avg = -----------------------------------     (4)
- *                               grq->load.weight
- *
- *   여기서 
- *
- *  grq->avg.load_avg
- * --------------------
- *   grq->load.weight
- *  
- *  이것만 계산해두고 뒤에서 ge->load.weight를 곱한다.
+ *   runnable_sum = grq->avg.load_sum / grq->load.weight 
  */
         /*
          * Estimate the new unweighted runnable_sum of the gcfs_rq by
@@ -4081,6 +4437,10 @@ update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq
 /*
  * IAMROOT, 2022.12.31:
  * - se에 대한 load_avg를 weights가중치를 포함해 계산한다.
+ *
+ *                      ge->load.weight * grq->avg.load_avg
+ *   ge->avg.load_avg = -----------------------------------        (4)
+ *                               grq->load.weight
  */
     load_sum = (s64)se_weight(se) * runnable_sum;
     load_avg = div_s64(load_sum, divider);
@@ -4115,7 +4475,9 @@ static inline void add_tg_cfs_propagate(struct cfs_rq *cfs_rq, long runnable_sum
 /* Update task and its cfs_rq load average */
 /*
  * IAMROOT, 2022.12.31:
- * - ING
+ * @return 1 propagate 요청있었음. 0. 없엇음.
+ * 1. propagate 확인 및 상위에 전달.
+ * 2. @se와 @cfs_rq에 대해 util, runnable, load update.
  */
 static inline int propagate_entity_load_avg(struct sched_entity *se)
 {
@@ -4327,6 +4689,14 @@ update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
  * Must call update_cfs_rq_load_avg() before this, since we rely on
  * cfs_rq->avg.last_update_time being current.
  */
+/*
+ * IAMROOT, 2023.01.07:
+ * - @se가 @cfs_rq에 attach되는 상황. @se의 값들을 @cfs_rq에 update하고 상위에 전파한다.
+ * - task일 경우 방금 생겻을경우 load가 없을수 있지만, group일 경우 기존에 load가 있을수있다는
+ *   걸 고려한다.
+ * - sum 값들의 경우
+ *   sum = avg * time 의 개념으로 sum을 만들어 넣는다.
+ */
 static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
 {
     /*
@@ -4342,6 +4712,13 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
      *
      * XXX illustrate
      */
+/*
+ * IAMROOT, 2023.01.07:
+ * - papago
+ *   @se를 @cfs_rq에 첨부할 때 decay window 을 정렬해야 합니다. 그렇지 않으면 정말 이상하고 
+ *   멋진 일이 발생할 수 있기 때문입니다.
+ *   (entity 입장에서의 decay window에 대한 정렬을 의미)
+ */
     se->avg.last_update_time = cfs_rq->avg.last_update_time;
     se->avg.period_contrib = cfs_rq->avg.period_contrib;
 
@@ -4351,22 +4728,49 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
      * entirely outside of the PELT hierarchy, nobody cares if we truncate
      * _sum a little.
      */
+/*
+ * IAMROOT, 2023.01.07:
+ * - papago
+ *   Hell(o) 불쾌한 물건.. 새 period_contrib를 기반으로 _sum을 다시 계산해야 합니다. 
+ *   이것은 정확하지는 않지만 우리는 완전히 PELT 계층 구조 밖에 있기 때문에 _sum을 
+ *   약간 잘라도 아무도 신경 쓰지 않습니다.
+ */
     se->avg.util_sum = se->avg.util_avg * divider;
 
     se->avg.runnable_sum = se->avg.runnable_avg * divider;
 
     se->avg.load_sum = divider;
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - se_weight(se) == 0 때는 se->avg.load_sum = divider로 사용한다.
+ */
     if (se_weight(se)) {
         se->avg.load_sum =
             div_u64(se->avg.load_avg * se->avg.load_sum, se_weight(se));
     }
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - @cfs_rq load_avg, load_sum update.
+ */
     enqueue_load_avg(cfs_rq, se);
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - util은 사용률의 개념이라 그냥 적산.
+ * - runnable은 이미 weight가 적용되있으므로 그냥 적산.
+ */
     cfs_rq->avg.util_avg += se->avg.util_avg;
     cfs_rq->avg.util_sum += se->avg.util_sum;
     cfs_rq->avg.runnable_avg += se->avg.runnable_avg;
     cfs_rq->avg.runnable_sum += se->avg.runnable_sum;
 
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - @cfs_rq에 들어왔으니까, 상위한테도 이를 전파한다.
+ */
     add_tg_cfs_propagate(cfs_rq, se->avg.load_sum);
 
     cfs_rq_util_change(cfs_rq, 0);
@@ -4421,6 +4825,13 @@ static void detach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
  * @flags entity_tick에서 불러졌을경우 : UPDATE_TG
  *        enqueue_entity의 경우 : UPDATE_TG | DO_ATTACH
  *        attach_entity_cfs_rq  : ATTACH_AGE_LOAD sched_feat가 없는경우 SKIP_AGE_LOAD
+ *
+ *  - 1. update를 했던 @se인 경우, @se에 대한 load sum, load avg 재계산.
+ *    2. @cfs_rq에 대한 load avg 계산.
+ *    3. @se에 대한 전파 처리.
+ *    4. @se가 attach인 경우 @cfs_rq에 attach.
+ *    5. decay됫거나 attach인경우 
+ *       cpu freq 변경시도, taskgroup에 변경을 알려야되는경우 update.
  */
 static inline void update_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
 {
@@ -4445,6 +4856,8 @@ static inline void update_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
 /*
  * IAMROOT, 2022.12.31:
  * - cfs_rq에 대한 removed 처리 및, load update.
+ *   se에대한 propagate처리.
+ * - decay가 됬거나 propagate를 했으면 decayed != 0
  */
     decayed  = update_cfs_rq_load_avg(now, cfs_rq);
     decayed |= propagate_entity_load_avg(se);
@@ -4462,12 +4875,27 @@ static inline void update_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
          *
          * IOW we're enqueueing a task on a new CPU.
          */
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - 최초이므로, @se를 @cfs_rq에 attach시킨다.
+ *   task group에도 update.
+ */
         attach_entity_load_avg(cfs_rq, se);
         update_tg_load_avg(cfs_rq);
 
     } else if (decayed) {
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - cpu freq 변경시도.
+ */
         cfs_rq_util_change(cfs_rq, 0);
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - taskgrup upate를 해야되면 한다.
+ */
         if (flags & UPDATE_TG)
             update_tg_load_avg(cfs_rq);
     }
@@ -5040,6 +5468,10 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
 /*
  * Preempt the current task with a newly woken task if needed:
  */
+/*
+ * IAMROOT, 2023.01.07:
+ * - @resched_curr 요청을 할지 결정한다.
+ */
 static void
 check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
 {
@@ -5047,6 +5479,11 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
     struct sched_entity *se;
     s64 delta;
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - @curr runtime을 종료된것을 검사한다. 다 사용됬으면 
+ *   @cfs_rq의 cpu한테 reschedule 요청을 한다.
+ */
     ideal_runtime = sched_slice(cfs_rq, curr);
     delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime;
     if (delta_exec > ideal_runtime) {
@@ -5064,6 +5501,10 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
      * narrow margin doesn't have to wait for a full slice.
      * This also mitigates buddy induced latencies under load.
      */
+/*
+ * IAMROOT, 2023.01.07:
+ * - config적으로 제한값을 검사한다.
+ */
     if (delta_exec < sysctl_sched_min_granularity)
         return;
 
@@ -5202,6 +5643,9 @@ static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
  * - @curr 
  *   ex) A:33%, B:33%, C:34%
  *   A가 33%에 대한 분배 시간을 다 마치고 이함수에 진입했을때 curr는 B가 된다.
+ * - queued
+ *   scheduler_tick에서 task_tick() callback을 통해 task_tick_fair()로 호출됫을때
+ *   queued == 0
  */
 static void
 entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
@@ -5209,12 +5653,26 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
     /*
      * Update run-time statistics of the 'current'.
      */
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - runtime관련 처리.(vruntime, runtime, cfs bandwidth등)
+ */
     update_curr(cfs_rq);
 
     /*
      * Ensure that runnable average is periodically updated.
      */
+/*
+ * IAMROOT, 2023.01.07:
+ * - @cfs_rq, @curr에 대한 load관련 처리(avg, sum, 전파, attach등)
+ */
     update_load_avg(cfs_rq, curr, UPDATE_TG);
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - @curr의 weight를 재갱신한다.
+ */
     update_cfs_group(curr);
 
 #ifdef CONFIG_SCHED_HRTICK
@@ -5222,18 +5680,45 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
      * queued ticks are scheduled to match the slice, so don't bother
      * validating it and just reschedule.
      */
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - 일반 schedule tick에서는 queued가 0이므로 reschedule을 안한다.
+ */
     if (queued) {
+/*
+ * IAMROOT, 2023.01.07:
+ * - cfs_rq 의 cpu에 reschedule 요청을 한다.
+ */
         resched_curr(rq_of(cfs_rq));
         return;
     }
     /*
      * don't let the period tick interfere with the hrtick preemption
      */
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - DOUBLE_TICK
+ *   1000hz + hrtick 둘다 사용한다는것.
+ *
+ * - double tick을 사용안하고 있는 상황에서
+ *   일반 schedule tick으로 들어온 경우엔 hrtick_timer가 active인 상황이므로
+ *   여기서 return.
+ */
     if (!sched_feat(DOUBLE_TICK) &&
             hrtimer_active(&rq_of(cfs_rq)->hrtick_timer))
         return;
 #endif
 
+/*
+ * IAMROOT, 2023.01.07:
+ * - double tick을 사용하는 경우 일반 schedule tick에서도 진입한다.
+ * - double tick을 사용하지 않은경우 여기에 진입하는 경우는 hrtimer가
+ *   이 함수를 호출한 상황이다.(이 경우 hrtimer_active()는 false가 되므로.)
+ * - task가 2개이상 돌고있으면 진입한다.
+ * - @cfs_rq에 reschedule을 요청할지 결정한다.
+ */
     if (cfs_rq->nr_running > 1)
         check_preempt_tick(cfs_rq, curr);
 }
@@ -5503,6 +5988,11 @@ static inline int cfs_rq_throttled(struct cfs_rq *cfs_rq)
 }
 
 /* check whether cfs_rq, or any parent, is throttled */
+/*
+ * IAMROOT, 2023.01.07:
+ * - cfs_bandwidth를 사용하는 상태. 즉 throttled 관련 기능
+ *   @cfs_rq가 throttle중 인지 확인한다.
+ */
 static inline int throttled_hierarchy(struct cfs_rq *cfs_rq)
 {
     return cfs_bandwidth_used() && cfs_rq->throttle_count;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 21700cd929c5..c339377b9797 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -695,7 +695,7 @@ struct cfs_rq {
  *  부호 없는 정수이지만 유휴 스케줄링 정책이 있는 작업만 포함합니다. 
  *
  *  - nr_running
- *    cfs rq에서 현재 실행가능한 task 수
+ *    cfs rq에서 현재 실행가능한 entity 수
  *  - h_nr_running
  *    하위 그룹까지 포함한 실행가능한 task 수.
  *    (throttled된 하위 cfs rq는 제외).
@@ -758,6 +758,12 @@ struct cfs_rq {
     } removed;
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
+
+/*
+ * IAMROOT, 2023.01.07:
+ * - 직전에 tg->load_avg에 적용된 cfs_rq의 load_avg.
+ *   (update_tg_load_avg() 참고)
+ */
     unsigned long        tg_load_avg_contrib;
 
 /*
@@ -3240,6 +3246,10 @@ DECLARE_PER_CPU(struct update_util_data __rcu *, cpufreq_update_util_data);
  * but that really is a band-aid.  Going forward it should be replaced with
  * solutions targeted more specifically at RT tasks.
  */
+/*
+ * IAMROOT, 2023.01.07:
+ * - @rq의 변화에 따라 cpu freq를 바꿀수있는 기능이 있으면 이를 수행한다.
+ */
 static inline void cpufreq_update_util(struct rq *rq, unsigned int flags)
 {
     struct update_util_data *data;
 

 

 

번호 제목 글쓴이 날짜 조회 수
공지 [공지] 스터디 정리 노트 공간입니다. woos 2016.05.14 617
182 [커널 18차] 90주차 kkr 2023.02.13 63
181 [커널 19차] 38 주차 Min 2023.02.11 44
180 [커널 19차] 37 주차 Min 2023.02.04 478
179 [커널 19차] 36 주차 Min 2023.01.28 85
178 [커널 18차] 88주차 kkr 2023.01.28 54
177 [커널 19차] 35 주차 Min 2023.01.14 93
176 [커널 17차] 120 ~ 121주차 ㅇㅇㅇ 2023.01.08 110
» [커널 18차] 85주차 kkr 2023.01.07 53
174 [커널 19차] 34 주차 Min 2023.01.07 42
173 [커널 18차] 84주차 kkr 2022.12.31 101
172 [커널 19차] 33 주차 Min 2022.12.31 50
171 [커널 17차] 117 ~ 119주차 ㅇㅇㅇ 2022.12.25 60
170 [커널 19차] 31 주차 Min 2022.12.17 63
169 [커널 19차] 30 주차 Min 2022.12.10 61
168 [커널 17차] 112 ~ 116주차 ㅇㅇㅇ 2022.12.05 71
167 [커널 18차] 80주차 kkr 2022.12.03 154
166 [커널 19차] 28 ~ 29 주차 Min 2022.12.03 35
165 [커널 19차] 27 주차 Min 2022.11.22 82
164 [커널 18차] 78주차 kkr 2022.11.19 181
163 [커널 19차] 25 ~ 26 주차 Min 2022.11.14 70
XE Login