[커널 18차] 90주차
2023.02.13 16:07
rt : pick_next_task_rt, put_prev_task_rt완
set_next_task_rt 측 push_rt_tasks 진행중
git : https://github.com/iamroot18/5.10/commit/079ea9f374ecac6ebec54e1da0eefe33172593b2
diff --git a/README.md b/README.md
index 7f0622735a1d..256d75ad8736 100644
--- a/README.md
+++ b/README.md
@@ -385,3 +385,7 @@
- 2023.02.04, Zoom 온라인(6명 참석)
- 스케줄러 진행중(rt)
+### 90주차
+- 2023.02.11, Zoom 온라인(6명 참석)
+- 스케줄러 진행중(rt)
+
diff --git a/include/asm-generic/bitops/sched.h b/include/asm-generic/bitops/sched.h
index 86470cfcef60..6998a93599da 100644
--- a/include/asm-generic/bitops/sched.h
+++ b/include/asm-generic/bitops/sched.h
@@ -10,6 +10,14 @@
* way of searching a 100-bit bitmap. It's guaranteed that at least
* one of the 100 bits is cleared.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * 모든 아키텍처는 이 기능을 정의해야 합니다. 100비트 비트맵을
+ * 검색하는 가장 빠른 방법입니다. 100비트 중 적어도 하나는
+ * 지워지는 것이 보장됩니다.
+ * - sched 전용으로 100개 전용으로 비트맵 검색을 만든것.
+ */
static inline int sched_find_first_bit(const unsigned long *b)
{
#if BITS_PER_LONG == 64
diff --git a/include/linux/sched/sd_flags.h b/include/linux/sched/sd_flags.h
index 57bde66d95f7..66b64745e816 100644
--- a/include/linux/sched/sd_flags.h
+++ b/include/linux/sched/sd_flags.h
@@ -79,6 +79,16 @@ SD_FLAG(SD_BALANCE_WAKE, SDF_SHARED_CHILD | SDF_NEEDS_GROUPS)
*
* SHARED_CHILD: Set from the base domain up to the NUMA reclaim level.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * ---
+ * task가 잠들엇다 일어날때 가장 좋은방법은 같은 cpu에서 깨어나는것이다.
+ * 만약 그렇지 못할 경우 다른 cpu를 선택해야되는데 그 경우에 대한것이다.
+ * domain내의 idle sibling중인 cpu에 대해서 선택한다는것이다.
+ * ---
+ * - idle상태에서 깨어난 cpu가 domain내의 idle sibling 선택을 허용한다.
+ *
+ */
SD_FLAG(SD_WAKE_AFFINE, SDF_SHARED_CHILD)
/*
diff --git a/include/linux/sched/topology.h b/include/linux/sched/topology.h
index 8f0f778b7c91..fd0e62bdb315 100644
--- a/include/linux/sched/topology.h
+++ b/include/linux/sched/topology.h
@@ -153,6 +153,10 @@ struct sched_domain {
unsigned long span[];
};
+/*
+ * IAMROOT, 2023.02.11:
+ * - @sd에 소속되있는 cpumask
+ */
static inline struct cpumask *sched_domain_span(struct sched_domain *sd)
{
return to_cpumask(sd->span);
diff --git a/kernel/irq_work.c b/kernel/irq_work.c
index d6165f8cdf95..10c2c3380c20 100644
--- a/kernel/irq_work.c
+++ b/kernel/irq_work.c
@@ -85,6 +85,10 @@ EXPORT_SYMBOL_GPL(irq_work_queue);
*
* Can be re-enqueued while the callback is still in progress.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - irq가 끝나고 나서 해소되는 work
+ */
bool irq_work_queue_on(struct irq_work *work, int cpu)
{
#ifndef CONFIG_SMP
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 5ddda52f0ecd..6e3c6d39442e 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -935,6 +935,10 @@ static bool set_nr_if_polling(struct task_struct *p)
#endif
#endif
+/*
+ * IAMROOT, 2023.02.11:
+ * - @head에 @task를 추가한다.
+ */
static bool __wake_q_add(struct wake_q_head *head, struct task_struct *task)
{
struct wake_q_node *node = &task->wake_q;
@@ -971,6 +975,10 @@ static bool __wake_q_add(struct wake_q_head *head, struct task_struct *task)
* This function must be used as-if it were wake_up_process(); IOW the task
* must be ready to be woken at this location.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - @head에 @task를 추가한다. 성공했으면 ref up.
+ */
void wake_q_add(struct wake_q_head *head, struct task_struct *task)
{
if (__wake_q_add(head, task))
@@ -1000,6 +1008,11 @@ void wake_q_add_safe(struct wake_q_head *head, struct task_struct *task)
put_task_struct(task);
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - TODO
+ * @head의 task들를 깨운다.
+ */
void wake_up_q(struct wake_q_head *head)
{
struct wake_q_node *node = head->first;
@@ -2704,6 +2717,11 @@ static int migration_cpu_stop(void *data)
return 0;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - this rq에서 task보다 낮은 lowest_rq를 찾아 balance를 수행한다.
+ * (this rq와 task rq가 같은 경우에 한해서)
+ */
int push_cpu_stop(void *arg)
{
struct rq *lowest_rq = NULL, *rq = this_rq();
@@ -2712,6 +2730,11 @@ int push_cpu_stop(void *arg)
raw_spin_lock_irq(&p->pi_lock);
raw_spin_rq_lock(rq);
+/*
+ * IAMROOT, 2023.02.11:
+ * - lock만 하고 find_lock_rq에서 double lock을 잡기전 한번
+ * 검사를 한다.
+ */
if (task_rq(p) != rq)
goto out_unlock;
@@ -2722,6 +2745,13 @@ int push_cpu_stop(void *arg)
p->migration_flags &= ~MDF_PUSH;
+/*
+ * IAMROOT, 2023.02.11:
+ * - rt : find_lock_lowest_rq()
+ * @p보다 우선순위가 낮은 lowest_rq를 찾아온다. 찾아지면 double lock
+ * 이 걸려있는 상태가 된다.
+ *
+ */
if (p->sched_class->find_lock_rq)
lowest_rq = p->sched_class->find_lock_rq(p, rq);
@@ -2729,6 +2759,14 @@ int push_cpu_stop(void *arg)
goto out_unlock;
// XXX validate p is still the highest prio task
+/*
+ * IAMROOT, 2023.02.11:
+ * - doublelock을 얻은후에 한번더 task rq와 this rq가 같은지 검사를
+ * 한다.
+ *
+ * - this rq에서 @p를 deactivate시킨후 lowest_rq에 activate를 시키고,
+ * lowest_rq를 curr로 reschedule 한다.
+ */
if (task_rq(p) == rq) {
deactivate_task(rq, p, 0);
set_task_cpu(p, lowest_rq->cpu);
@@ -8901,6 +8939,10 @@ SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len,
return ret;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - yield 처리후 schedule 수행.
+ */
static void do_sched_yield(void)
{
struct rq_flags rf;
@@ -9056,6 +9098,10 @@ EXPORT_SYMBOL(__cond_resched_rwlock_write);
* If you want to use yield() to be 'nice' for others, use cond_resched().
* If you still want to use yield(), do not!
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - yield 처리 후 schedule 처리한다.
+ */
void __sched yield(void)
{
set_current_state(TASK_RUNNING);
diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c
index 27005b1d1a6c..c77bd4457553 100644
--- a/kernel/sched/cpupri.c
+++ b/kernel/sched/cpupri.c
@@ -40,6 +40,16 @@
*
* 100 100 (CPUPRI_HIGHER)
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - 원래 prio는 낮을수록 우선순위가 높은데, 이를 역으로 변환하여
+ * 높을수록 우선순위가 높도록 한다.
+ * (cpupri 또는 user 관점 priority는 번호가 높을수록 우선순위가 높다.)
+ * ----
+ * - 옛날에는 102개 체재 였다(idle이란게 있었다.). 지금은 idle이 빠져
+ * 101개 체재가 됬다.
+ * 101개 체재에선 RT100을 NORMAL과 동일하게 처리한다.
+ */
static int convert_prio(int prio)
{
int cpupri;
@@ -58,6 +68,10 @@ static int convert_prio(int prio)
break;
case MAX_RT_PRIO:
+/*
+ * IAMROOT, 2023.02.11:
+ * - deadline 용인듯 싶다.
+ */
cpupri = CPUPRI_HIGHER; /* 100 */
break;
}
@@ -65,9 +79,20 @@ static int convert_prio(int prio)
return cpupri;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - @p->cpumask와 @idx 우선순위에 해당하는 cpupri에 둘다 포함되는 cpu가
+ * 있으면 return 1.
+ * @lowest_mask 가 NULL이 아니면 겹치는 cpu가 lowest_mask에 기록된다.
+ */
static inline int __cpupri_find(struct cpupri *cp, struct task_struct *p,
struct cpumask *lowest_mask, int idx)
{
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - @cp의 @idx에
+ */
struct cpupri_vec *vec = &cp->pri_to_cpu[idx];
int skip = 0;
@@ -91,15 +116,46 @@ static inline int __cpupri_find(struct cpupri *cp, struct task_struct *p,
* pull this task if the run queue is running at a lower
* priority.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * 벡터를 볼 때 카운터를 읽고 메모리 배리어를 수행한 다음 마스크를 읽어야
+ * 합니다.
+ *
+ * Note: 이것은 여전히 정교하지만 처리 할 수 있습니다.
+ * 이상적으로는 설정된 마스크만 보고자 합니다.
+ *
+ * 마스크가 설정되지 않은 경우 유일한 잘못된 점은 필요한 것보다 조금 더
+ * 많은 작업을 수행한 것입니다.
+ *
+ * 메모리 장벽으로 인해 0 카운트를 읽었지만 마스크가 설정된 경우 실행
+ * 대기열에 대한 가장 높은 우선 순위 작업이 실행 대기열을 떠났을 때만
+ * 발생할 수 있으며 이 경우 풀이 이어집니다. 우리가 처리하고 있는 작업이
+ * 갈 적절한 위치를 찾는 데 실패하면 실행 대기열이 낮은 우선순위에서 실행
+ * 중인 경우 풀 요청이 이 작업을 풀합니다.
+ */
smp_rmb();
/* Need to do the rmb for every iteration */
+/*
+ * IAMROOT, 2023.02.11:
+ * - 해당 우선순위에 해당하는 cpu가 하나도 없으면 return.
+ */
if (skip)
return 0;
+/*
+ * IAMROOT, 2023.02.11:
+ * - 미포함. return 0.
+ */
if (cpumask_any_and(&p->cpus_mask, vec->mask) >= nr_cpu_ids)
return 0;
+/*
+ * IAMROOT, 2023.02.11:
+ * - cpu_mask와 vec mask 와 겹치는 mask가 있으면 return 1.
+ * 없으면 return 0
+ */
if (lowest_mask) {
cpumask_and(lowest_mask, &p->cpus_mask, vec->mask);
@@ -111,6 +167,14 @@ static inline int __cpupri_find(struct cpupri *cp, struct task_struct *p,
* condition, simply act as though we never hit this
* priority level and continue on.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * vec->mask의 첫 번째 읽기와 두 번째 읽기 사이에 맵이 동시에 비워질
+ * 수 있기 때문에 배열에 적어도 하나의 비트가 여전히 설정되어 있는지
+ * 확인해야 합니다. 이 조건에 도달하면 이 우선 순위 수준에 도달하지 않은
+ * 것처럼 행동하고 계속 진행하십시오.
+ */
if (cpumask_empty(lowest_mask))
return 0;
}
@@ -118,6 +182,11 @@ static inline int __cpupri_find(struct cpupri *cp, struct task_struct *p,
return 1;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - fitness_fn 수행을 안하고 그냥 @p의 우선순위 범위에 대해서 @cp에
+ * 해당하는 cpu를 찾는다.
+ */
int cpupri_find(struct cpupri *cp, struct task_struct *p,
struct cpumask *lowest_mask)
{
@@ -141,26 +210,76 @@ int cpupri_find(struct cpupri *cp, struct task_struct *p,
*
* Return: (int)bool - CPUs were found
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * cpupri_find_fitness - 시스템에서 최상의(가장 낮은 pri) CPU 찾기
+ * @cp: cpupri 컨텍스트
+ * @p: 작업
+ * @lowest_mask: 선택한 CPU(또는 NULL)로 채울 마스크
+ * @fitness_fn: 사용자 지정 검사를 수행하는 함수에 대한 포인터는 해당
+ * CPU만 반환하도록 CPU가 특정 기준에 맞는지 여부를 확인합니다.
+ *
+ * 참고: 이 함수는 현재 호출 중에 계산된 권장 CPU를 반환합니다.
+ * 호출이 반환될 때까지 CPU는 실제로 여러 번 우선 순위를 변경했을 수
+ * 있습니다. 이상적이지는 않지만 일반 리밸런서 로직이 현재 우선 순위
+ * 구성의 불확실성에 대한 경주로 인해 생성된 모든 불일치를 수정하므로
+ * 정확성의 문제는 아닙니다.
+ *
+ * return: (int)bool - CPU가 발견되었습니다.
+ *
+ * - 1. @p의 우선순위범위에서 @cp 범위와 겹치는 cpu를 찾는다.
+ * 2. @lowest_mask, @fitness_fn 이 있는 경우 찾은 cpu를 기록하고
+ * fitness_fn을 수행하여 성공한 cpu를 lowest_mask에 기록한다.
+ * 3. @fitness_fn이 없는 경우 cpu를 찾기만 하고 끝낸다.
+ */
int cpupri_find_fitness(struct cpupri *cp, struct task_struct *p,
struct cpumask *lowest_mask,
bool (*fitness_fn)(struct task_struct *p, int cpu))
{
+/*
+ * IAMROOT, 2023.02.11:
+ * - task priority로 max priority를 구한다.
+ * 자신보다 낮는것을 찾아야되는 상황이다.
+ */
int task_pri = convert_prio(p->prio);
int idx, cpu;
BUG_ON(task_pri >= CPUPRI_NR_PRIORITIES);
+/*
+ * IAMROOT, 2023.02.11:
+ * - 낮은것부터 높은순으로 iterate
+ */
for (idx = 0; idx < task_pri; idx++) {
+/*
+ * IAMROOT, 2023.02.11:
+ * - @cp의 idx 우선순위의 cpumask와 @p의 cpumask 둘다 포함되는 cpu를
+ * lowest_mask에 기록한다. 없으면 continue.
+ */
if (!__cpupri_find(cp, p, lowest_mask, idx))
continue;
+/*
+ * IAMROOT, 2023.02.11:
+ * - @lowest_mask, fitness_fn 가 인자로 안들어왔으면 그냥 cpu를 찾고
+ * 끝낸다.
+ */
if (!lowest_mask || !fitness_fn)
return 1;
/* Ensure the capacity of the CPUs fit the task */
+/*
+ * IAMROOT, 2023.02.11:
+ * - 찾아낸 lowest_mask에 대해서 @fitness_fn을 수행한다.
+ */
for_each_cpu(cpu, lowest_mask) {
if (!fitness_fn(p, cpu))
+/*
+ * IAMROOT, 2023.02.11:
+ * - 적합하지 않으면 lowest_mask에서 해당 cpu를 clear한다.
+ */
cpumask_clear_cpu(cpu, lowest_mask);
}
@@ -168,9 +287,18 @@ int cpupri_find_fitness(struct cpupri *cp, struct task_struct *p,
* If no CPU at the current priority can fit the task
* continue looking
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - 전부 실패한 개념이되므로 다음 priority로 이동.
+ */
if (cpumask_empty(lowest_mask))
continue;
+/*
+ * IAMROOT, 2023.02.11:
+ * - fitness_fn을 해당 priority에서 성공한 lowest_mask cpu가 있었다면
+ * return 1.
+ */
return 1;
}
@@ -191,9 +319,35 @@ int cpupri_find_fitness(struct cpupri *cp, struct task_struct *p,
* must do proper RT planning to avoid overloading the system if they
* really care.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * 적합한 최하위 마스크를 찾지 못한 경우 이번에는 적합성 기준을 고려하지
+ * 않고 새 검색을 시작합니다.
+ *
+ * 이 규칙은 올바른 CPU에 작업을 맞추는 것보다 우선 순위를 존중하는 것을
+ * 선호합니다(현재 용량 인식이 유일한 사용자임).
+ * 아이디어는 더 높은 우선 순위 작업이 실행될 수 있는 경우 적합하지 않은
+ * CPU에서 종료되더라도 실행되어야 한다는 것입니다.
+ *
+ * 이 트레이드 오프의 비용은 완전히 명확하지 않으며 일부 워크로드에는 좋고
+ * 다른 워크로드에는 좋지 않을 수 있습니다.
+ *
+ * 여기서 주요 아이디어는 일부 CPU가 과도하게 커밋된 경우 스케줄러가
+ * 전통적으로 수행한 대로 확산을 시도한다는 것입니다. 시스템 관리자는
+ * 정말로 관심이 있는 경우 시스템 과부하를 피하기 위해 적절한 RT 계획을
+ * 수행해야 합니다.
+ *
+ * - lowest cpu를 priority범위에서 하나도 못찾았다. fitness_fn 함수 수행
+ * 없이 한번더 시도한다.
+ */
if (fitness_fn)
return cpupri_find(cp, p, lowest_mask);
+/*
+ * IAMROOT, 2023.02.11:
+ * - fitness_fn 수행요청없이도 cpu를 못찾은상태. return 0.
+ */
return 0;
}
diff --git a/kernel/sched/cpupri.h b/kernel/sched/cpupri.h
index 25b5e3451ff9..f087c25e9c05 100644
--- a/kernel/sched/cpupri.h
+++ b/kernel/sched/cpupri.h
@@ -2,6 +2,10 @@
#define CPUPRI_NR_PRIORITIES (MAX_RT_PRIO+1)
+/*
+ * IAMROOT, 2023.02.11:
+ * - cpupri는 번호가 높을수록 우선순위가 높다.
+ */
#define CPUPRI_INVALID -1
#define CPUPRI_NORMAL 0
/* values 1-99 are for RT1-RT99 priorities */
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index f97323486f3a..c662ff50cad0 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -94,7 +94,7 @@ unsigned int sysctl_sched_child_runs_first __read_mostly;
* - papago
* SCHED_OTHER 깨우기 세분성입니다.
*
- * 이 옵션은 분리된 워크로드의 선점 효과를 지연시키고 과도한 스케줄링을 줄입니다.
+ * 이 옵션은 분리된 워크로드의 선점 효과를 지연시키고 과도한 스케줄링을 줄입니다.
* 동기식 워크로드에는 여전히 즉각적인 깨우기/절전 대기 시간이 있습니다.
*
* (default: 1 msec * (1 + ilog(ncpus)), units: nanoseconds)
@@ -279,7 +279,7 @@ static void __update_inv_weight(struct load_weight *lw)
*
* - 실제론 이미 계산된 1 / lw.weight값을 사용해서 이진화 정수계산으로
* 구한다 (위 주석 참고)
- * - 계산을 수행하면서 발생할수있는 32bit overflow에 대한 처리와,
+ * - 계산을 수행하면서 발생할수있는 32bit overflow에 대한 처리와,
* 그에 따른 정밀도 감소처리가 있다.
*
* - calc_delta_fair 에서 호출 하였을 때
@@ -713,20 +713,20 @@ static inline bool entity_before(struct sched_entity *a,
* 2. curr가 없거나 on_rq가 아닌 상태면 leftmost_se->vruntime으로 처리
* 3. 그게 아니면 min_vruntime유지
*
- * - 보통은 curr->vruntime이 가장 빠른 시간으로 설정되고, 그에따라
+ * - 보통은 curr->vruntime이 가장 빠른 시간으로 설정되고, 그에따라
* 아래 조건들로 해서도 왠간해선 curr->vruntime이 선택 될것이다.
* 그러나 어찌됫든 혹시나 모를 상황에 대비해 min, max비교등을 수행해서
* min_vruntime이 갱신된다.
*
* --- vruntime이 min_vruntime보다 클경우(chat open ai. 검증필요. 참고만)
- * 1. task이 이전에 선점되었고 나중에 재개된 경우입니다. task가 선점되면
- * 해당 vruntime이 일시적으로 중지될 수 있으며 다시 시작되면 해당
- * vruntime이 현재 시간으로 업데이트될 수 있습니다. task가 min_vruntime
+ * 1. task이 이전에 선점되었고 나중에 재개된 경우입니다. task가 선점되면
+ * 해당 vruntime이 일시적으로 중지될 수 있으며 다시 시작되면 해당
+ * vruntime이 현재 시간으로 업데이트될 수 있습니다. task가 min_vruntime
* 값보다 나중에 재개되면 해당 vruntime이 min_vruntime보다 클 수 있습니다.
*
- * 2. 현재 실행 중인 task이 cfs_rq의 다른 task보다 높은 우선 순위를
- * 가지고 있어 더 많은 CPU 시간을 받은 경우입니다. 이 경우 현재 실행 중인
- * task의 vruntime이 아직 실행되지 않은 task의 vruntime보다 클 수
+ * 2. 현재 실행 중인 task이 cfs_rq의 다른 task보다 높은 우선 순위를
+ * 가지고 있어 더 많은 CPU 시간을 받은 경우입니다. 이 경우 현재 실행 중인
+ * task의 vruntime이 아직 실행되지 않은 task의 vruntime보다 클 수
* 있으므로 min_vruntime 값보다 클 수 있습니다.
*/
static void update_min_vruntime(struct cfs_rq *cfs_rq)
@@ -740,14 +740,14 @@ static void update_min_vruntime(struct cfs_rq *cfs_rq)
* IAMROOT, 2022.12.21:
* - min_vruntime과 비교될 vruntime을 결정한다.
*
- * 1. curr가 rq에 들어있다. leftmost
+ * 1. curr가 rq에 들어있다. leftmost
* 1. curr가 rq에 들어있고, leftmost가 존재.
* vruntime = min_vruntime(curr->vruntime, leftmost_se->vruntime)
* 2. leftmost가 있고 curr가 없는 상태.
* vruntime = leftmost_se->vruntime
*
* curr on_rq leftmost (compare max_vruntime cfs_rq->min_vruntime)
- * X - X -
+ * X - X -
* X - O leftmost_se->vruntime
* O X X -
* O X O leftmost_se->vruntime
@@ -762,7 +762,7 @@ static void update_min_vruntime(struct cfs_rq *cfs_rq)
* - leftmost가 없는 상황이면 curr->vruntime이 min_vruntime과 비교되서
* 들어가는데 보통은 같다.
*
- * -
+ * -
*/
if (curr) {
/*
@@ -956,7 +956,7 @@ static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se)
*/
unsigned int nr_running = cfs_rq->nr_running;
u64 slice;
-
+
/*
* IAMROOT, 2023.01.07:
* - 계층구조의 task 수로 갱신한다.
@@ -3439,7 +3439,7 @@ dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
*
* reweight_entity 진입전 값들정리(cpu0 = 50%)
* cfs_rq load weight = 1024
- * cfs_rq load avg = 1024
+ * cfs_rq load avg = 1024
* cfs_rq load sum = 47742
*
* se load weight = 512
@@ -3617,22 +3617,22 @@ void reweight_task(struct task_struct *p, int prio)
* - 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
@@ -3645,19 +3645,19 @@ void reweight_task(struct task_struct *p, int prio)
*
* 그것은 share_avg이며, 맞습니다(주어진 근사치(2)).
*
- * 문제는 평균이 느리기 때문에(당연히 정확히 그렇게 설계되었으므로) 경계 조건에서 과도
- * 현상이 발생한다는 것입니다. 특히 그룹이 유휴 상태이고 하나의 작업을 시작하는 경우입니다.
- * CPU의 grq->avg.load_avg가 쌓이는 데 시간이 걸리고 대기 시간이 좋지 않습니다.
+ * 문제는 평균이 느리기 때문에(당연히 정확히 그렇게 설계되었으므로) 경계 조건에서 과도
+ * 현상이 발생한다는 것입니다. 특히 그룹이 유휴 상태이고 하나의 작업을 시작하는 경우입니다.
+ * 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)을
+ * 따라서 우리가 하는 일은 다음과 같이 (가까운) UP 사례에서 (4)에 접근하도록 근사치 (3)을
* 수정하는 것입니다.
*
* ge->load.weight =
@@ -3665,14 +3665,14 @@ void reweight_task(struct task_struct *p, int prio)
* 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
*
* =
@@ -3681,12 +3681,12 @@ void reweight_task(struct task_struct *p, int prio)
* grq->load.weight
*
* ex) rq 2개.
- * rq 1개가 50%. 1개가 50%했을때.
+ * 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
*
* =
@@ -3700,7 +3700,7 @@ void reweight_task(struct task_struct *p, int prio)
* 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
*
* =
@@ -3716,7 +3716,7 @@ void reweight_task(struct task_struct *p, int prio)
* tg->load_avg * 7 / 10 + grq->load.weigh
* )
*
- * 그러나 grq->load.weight가 0으로 떨어질 수 있으므로 결과적으로 0으로 나누기 때문에
+ * 그러나 grq->load.weight가 0으로 떨어질 수 있으므로 결과적으로 0으로 나누기 때문에
* grq->avg.load_avg를 하한으로 사용해야 합니다. 그런 다음 다음을 제공합니다.
*
*
@@ -3729,7 +3729,7 @@ void reweight_task(struct task_struct *p, int prio)
* tg_load_avg' = tg->load_avg - grq->avg.load_avg +
* max(grq->load.weight, grq->avg.load_avg)
*
- * 그리고 그것은 share_weight이고 엉뚱합니다. (가까운) UP 경우에는 (4)에 접근하고 일반적인
+ * 그리고 그것은 share_weight이고 엉뚱합니다. (가까운) UP 경우에는 (4)에 접근하고 일반적인
* 경우에는 (3)에 접근합니다. ge->load.weight를 일관되게 과대평가하므로 다음과 같습니다.
*
* \Sum ge->load.weight >= tg->weight
@@ -3775,18 +3775,18 @@ static long calc_group_shares(struct cfs_rq *cfs_rq)
* 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 = -----------------------------
+ * 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);
@@ -3823,14 +3823,14 @@ static long calc_group_shares(struct cfs_rq *cfs_rq)
/*
* IAMROOT, 2023.01.07:
* - papago
- * MIN_SHARES는 tg->shares 값이 작은 그룹의 CPU당 파티셔닝을 지원하기 위해
- * 여기에서 크기를 조정하지 않아야 합니다. CPU에서 그룹을 나타내는
- * sched_entity에 최소 load.weight로 할당되는 floor 값입니다.
+ * 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 대신 반환되어야 합니다.
+ * 예를 들어 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);
}
@@ -3874,7 +3874,7 @@ static void update_cfs_group(struct sched_entity *se)
* - UMP일 경우.
* - @se weight와 group의 shares가 같으면 return.
* reweight을 할 필요가 없다.
- * 초기값은 shares기준으로 만들어지기때문이다.
+ * 초기값은 shares기준으로 만들어지기때문이다.
* shares나 weight이 변경되는 경우만 아래로 진입할것이다.
*/
shares = READ_ONCE(gcfs_rq->tg->shares);
@@ -3932,16 +3932,16 @@ static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq, int flags)
/*
* IAMROOT, 2023.01.07:
* - papago
- * 이것이 놓칠 수 있는 몇 가지 경계 사례가 있지만 실제 문제가 되지 않도록
- * 충분히 자주 호출되어야 합니다.
+ * 이것이 놓칠 수 있는 몇 가지 경계 사례가 있지만 실제 문제가 되지 않도록
+ * 충분히 자주 호출되어야 합니다.
*
- * 유휴 스레드가 다른 클래스(!fair)이기 때문에 유휴 상태일 때 호출되지 않으며
+ * 유휴 스레드가 다른 클래스(!fair)이기 때문에 유휴 상태일 때 호출되지 않으며
* 사용률에 RT 작업과 같은 항목이 포함되지 않습니다.
*
- * 있는 그대로, util 번호는 freq-invariant가 아닙니다(이를 위해
- * arch_scale_freq_capacity()를 구현해야 합니다).
+ * 있는 그대로, util 번호는 freq-invariant가 아닙니다(이를 위해
+ * arch_scale_freq_capacity()를 구현해야 합니다).
*
- * cpu_util()을 참조하십시오.
+ * cpu_util()을 참조하십시오.
*/
cpufreq_update_util(rq, flags);
}
@@ -3961,10 +3961,10 @@ static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq, int flags)
* IAMROOT, 2022.12.27:
* - TODO
* - papago
- * list_add_leaf_cfs_rq는 항상 상위 cfs_rq 바로 앞에 하위 cfs_rq를
- * 목록에 배치하고 cfs_rqs는 목록 상향식에서 제거하기 때문에 목록에서
- * 우리 앞에 있는 cfs_rq가 하위인지 여부만 테스트하면 됩니다.
- * cfs_rq가 목록에 없으면 분기를 트리에 연결하기 위해 자식을 추가해야
+ * list_add_leaf_cfs_rq는 항상 상위 cfs_rq 바로 앞에 하위 cfs_rq를
+ * 목록에 배치하고 cfs_rqs는 목록 상향식에서 제거하기 때문에 목록에서
+ * 우리 앞에 있는 cfs_rq가 하위인지 여부만 테스트하면 됩니다.
+ * cfs_rq가 목록에 없으면 분기를 트리에 연결하기 위해 자식을 추가해야
* 하는지 여부를 테스트합니다 * (자세한 내용은 list_add_leaf_cfs_rq() 참조)
*/
static inline bool child_cfs_rq_on_list(struct cfs_rq *cfs_rq)
@@ -4035,13 +4035,13 @@ static inline bool cfs_rq_is_decayed(struct cfs_rq *cfs_rq)
/*
* IAMROOT, 2023.01.07:
* - papago
- * update_tg_load_avg - update the tg's load avg
+ * 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를 볼 필요가 없도록 전파한 마지막 값을 저장하는 차등 업데이트를 사용합니다.
+ * 다른 cfs_rq를 볼 필요가 없도록 전파한 마지막 값을 저장하는 차등 업데이트를 사용합니다.
* 차등이 '작은' 경우 업데이트를 건너뛸 수 있습니다.
*
* update_cfs_share() 전에 tg의 load_avg 업데이트가 필요합니다.
@@ -4193,198 +4193,198 @@ void set_task_rq_fair(struct sched_entity *se,
/*
* IAMROOT, 2022.12.31:
* - papago
- * 마이그레이션 중에 sched_entity가 PELT 계층 구조에 합류/탈퇴할 때 기여도를
- * 전파해야 합니다. 이 전파의 핵심은 각 그룹에 대한 불변성입니다.
+ * 마이그레이션 중에 sched_entity가 PELT 계층 구조에 합류/탈퇴할 때 기여도를
+ * 전파해야 합니다. 이 전파의 핵심은 각 그룹에 대한 불변성입니다.
*
* ge->avg == grq->avg (1)
*
- * IFF_ 순수한 running 및 runnable sum을 봅니다. 계층 구조의 다른 지점에서
+ * IFF_ 순수한 running 및 runnable sum을 봅니다. 계층 구조의 다른 지점에서
* 매우 동일한 entity를 나타내기 때문입니다.
*
- * 위의 update_tg_cfs_util() 및 update_tg_cfs_runnable()은 사소하고 단순히
- * running/runnable sum을 복사합니다(그러나 그룹 엔티티 및 그룹 rq에 PELT
- * window가 정렬되어 있지 않기 때문에 여전히 잘못됨).
+ * 위의 update_tg_cfs_util() 및 update_tg_cfs_runnable()은 사소하고 단순히
+ * running/runnable sum을 복사합니다(그러나 그룹 엔티티 및 그룹 rq에 PELT
+ * window가 정렬되어 있지 않기 때문에 여전히 잘못됨).
*
- * 그러나 update_tg_cfs_load()는 더 복잡합니다. 그래서 우리는:
+ * 그러나 update_tg_cfs_load()는 더 복잡합니다. 그래서 우리는:
*
* ge->avg.load_avg = ge->load.weight * ge->avg.runnable_avg (2)
*
- * 그리고 util과 마찬가지로 runnable을 직접 양도할 수 있어야 하므로
+ * 그리고 util과 마찬가지로 runnable을 직접 양도할 수 있어야 하므로
* 다음과 같이 간단하게 접근할 수 있습니다.
*
* grq->avg.load_avg = grq->load.weight * grq->avg.runnable_avg (3)
*
- * 그리고 (1)에 따라 다음이 있습니다.
+ * 그리고 (1)에 따라 다음이 있습니다.
*
- * ge->avg.runnable_avg == grq->avg.runnable_avg
+ * ge->avg.runnable_avg == grq->avg.runnable_avg
*
- * 다음을 제공합니다.
+ * 다음을 제공합니다.
*
* ge->load.weight * grq->avg.load_avg
* ge->avg.load_avg = ----------------------------------- (4)
* grq->load.weight
- *
+ *
* 틀린 것만 빼면!
*
- * entity의 경우 historical weight는 중요하지 않고 실제로는 미래에만 관심이
- * 있으므로 순수 runnable sum을 고려할 수 있지만 rq는 이를 수행할 수
+ * entity의 경우 historical weight는 중요하지 않고 실제로는 미래에만 관심이
+ * 있으므로 순수 runnable sum을 고려할 수 있지만 rq는 이를 수행할 수
* 없습니다.
* (se는 weight 필요없이 runnable값으로만 계산해도 상관없지만, cfs_rq는
* 필요해서 결국 weight를 고려해야된다는 말이다.)
*
- * 우리는 특히 rq가 historical weight를 포함하는 load_avg를 갖기를 원합니다.
- * 그것들은 blocked load, 즉 (곧) 우리에게 돌아올 것으로 예상되는 load를
- * 나타냅니다.
- * 이것은 weight를 sum의 필수적인 부분으로 유지해야만 작동합니다. 따라서
- * (3)에 따라 분해할 수 없습니다.
- * (historical weight load_avg가 rq에 필요하기 때문에 결국 load sum을
+ * 우리는 특히 rq가 historical weight를 포함하는 load_avg를 갖기를 원합니다.
+ * 그것들은 blocked load, 즉 (곧) 우리에게 돌아올 것으로 예상되는 load를
+ * 나타냅니다.
+ * 이것은 weight를 sum의 필수적인 부분으로 유지해야만 작동합니다. 따라서
+ * (3)에 따라 분해할 수 없습니다.
+ * (historical weight load_avg가 rq에 필요하기 때문에 결국 load sum을
* 계산할때 weight를 사용해야된다는 의미.)
*
- * 이것이 작동하지 않는 또 다른 이유는 runnable이 0-sum entity가 아니기
- * 때문입니다.
- * 각각 2/3 시간 동안 runnable 2개의 작업이 있는 rq를 상상해 보십시오.
- * 그런 다음 rq 자체는 이러한 작업의 runnable 섹션이 겹치는 방식
- * (또는 겹치지 않음)에 따라 2/3에서 1 사이 어디에서나 runnable 가능합니다.
- * rq를 전체적으로 완벽하게 정렬하려면 시간의 2/3를 runnable 수 있습니다.
- * 그러나 항상 최소한 하나의 runnable 작업이 있는 경우 전체 rq는 항상
+ * 이것이 작동하지 않는 또 다른 이유는 runnable이 0-sum entity가 아니기
+ * 때문입니다.
+ * 각각 2/3 시간 동안 runnable 2개의 작업이 있는 rq를 상상해 보십시오.
+ * 그런 다음 rq 자체는 이러한 작업의 runnable 섹션이 겹치는 방식
+ * (또는 겹치지 않음)에 따라 2/3에서 1 사이 어디에서나 runnable 가능합니다.
+ * rq를 전체적으로 완벽하게 정렬하려면 시간의 2/3를 runnable 수 있습니다.
+ * 그러나 항상 최소한 하나의 runnable 작업이 있는 경우 전체 rq는 항상
* runnable 가능합니다.
* (각 task runnable시간의 sum이 group의 sum보다 같거나 작을수박에
* 없다는의미.)
*
- * 그래서 우리는 근사해야 할 것입니다.. :/
+ * 그래서 우리는 근사해야 할 것입니다.. :/
*
- * 주어진 제약조건:
+ * 주어진 제약조건:
*
- * ge->avg.running_sum <= ge->avg.runnable_sum <= LOAD_AVG_MAX
+ * ge->avg.running_sum <= ge->avg.runnable_sum <= LOAD_AVG_MAX
*
* 최소한의 overlap을 가정하여 rq에 runnable을 추가하는 규칙을 구성할 수 있습니다.
* (runnable이 양수인경우엔 overlap의 개념을 도입해서 적당히 그냥 add만
* 한다는 의미.)
*
- * 제거할 때 각 작업이 동등하게 runnable이라고가정합니다. 결과는 다음과
+ * 제거할 때 각 작업이 동등하게 runnable이라고가정합니다. 결과는 다음과
* 같습니다.
*
- * grq->avg.runnable_sum = grq->avg.load_sum / grq->load.weight
+ * grq->avg.runnable_sum = grq->avg.load_sum / grq->load.weight
*
- * (runnable이 음수일때는 제거되는 과정이 되므로 overlap된값을 결국 배제하고
+ * (runnable이 음수일때는 제거되는 과정이 되므로 overlap된값을 결국 배제하고
* 좀 정확히 계산해야되므로 식을 사용해 계산해야된다는 의미.)
*
- * XXX:
- * runnable > running ? 부분에 대해서만 이 작업을 수행합니다.
+ * XXX:
+ * runnable > running ? 부분에 대해서만 이 작업을 수행합니다.
*
* ------------------ chat open ai --------------------------------------
* --- 주석의 줄임말
- * - "IFF"는 "if and only if"의 약자입니다. 명제가 특정 조건에서만 참임을
+ * - "IFF"는 "if and only if"의 약자입니다. 명제가 특정 조건에서만 참임을
* 나타내는 데 사용됩니다.
*
* -"XXX"는 수행해야 하거나 추가 주의가 필요한 작업에 대한 자리 표시자입니다.
-* 검토하거나 수정해야 하는 영역을 나타내기 위해 코드 주석에서 자주
-* 사용됩니다.
+* 검토하거나 수정해야 하는 영역을 나타내기 위해 코드 주석에서 자주
+* 사용됩니다.
*
* - 0-sum entity
-* 스케줄러에서 "runnable" entity의 개념입니다.
-* "0-sum"이라는 용어는 작업 그룹에 대한 "runnable" 시간의 sum가 그룹이
-* 실행 가능한 총 시간과 반드시 같지는 않다는 사실을 나타냅니다. 이는 그룹의
-* 작업이 항상 동시에 실행되지 않을 수 있기 때문에 그룹 전체가 개별 작업의
-* 실행 가능한 시간의 합보다 더 긴 시간 동안 실행될 수 있기 때문입니다.
+* 스케줄러에서 "runnable" entity의 개념입니다.
+* "0-sum"이라는 용어는 작업 그룹에 대한 "runnable" 시간의 sum가 그룹이
+* 실행 가능한 총 시간과 반드시 같지는 않다는 사실을 나타냅니다. 이는 그룹의
+* 작업이 항상 동시에 실행되지 않을 수 있기 때문에 그룹 전체가 개별 작업의
+* 실행 가능한 시간의 합보다 더 긴 시간 동안 실행될 수 있기 때문입니다.
* --------------------
* --- PELT 관련 용어 ---
* - PELT window
-* task 또는 task gorup의 load 및 util을 추적하는 기간입니다. PELT window의
-* 크기는 task 또는 task group의 load 및 util avg이 업데이트되는 빈도에 따라
-* 결정됩니다.
+* task 또는 task gorup의 load 및 util을 추적하는 기간입니다. PELT window의
+* 크기는 task 또는 task group의 load 및 util avg이 업데이트되는 빈도에 따라
+* 결정됩니다.
*
-* PELT window의 크기는 task 또는 task group의 load 및 util avg이
-* 업데이트되는 빈도에 따라 결정됩니다. load 및 uitl avg은 일반적으로
-* 1ms의 정기적인 간격으로 업데이트됩니다. 즉, PELT window의 크기도
+* PELT window의 크기는 task 또는 task group의 load 및 util avg이
+* 업데이트되는 빈도에 따라 결정됩니다. load 및 uitl avg은 일반적으로
+* 1ms의 정기적인 간격으로 업데이트됩니다. 즉, PELT window의 크기도
* 1ms이며 업데이트 간격과 동시에 시작하고 끝납니다.
*
* - PELT window align
-* 서로 다른 task 및 task group의 PELT window을 서로 정렬하면 크기와
-* 시작 및 종료 시간이 동일함을 의미합니다. PELT 창을 정렬하면 task 및
-* task group에 대해 계산된 load 및 util avg의 정확도를 개선하는 데 도움이
+* 서로 다른 task 및 task group의 PELT window을 서로 정렬하면 크기와
+* 시작 및 종료 시간이 동일함을 의미합니다. PELT 창을 정렬하면 task 및
+* task group에 대해 계산된 load 및 util avg의 정확도를 개선하는 데 도움이
* 될 수 있습니다.
*
-* 예를 들어 A와 B라는 두 개의 task과 CPU에서 실행되는 G라는 task group이
-* 있다고 가정합니다. A, B, G의 load 및 util avg은 PELT 알고리즘을 사용하여
+* 예를 들어 A와 B라는 두 개의 task과 CPU에서 실행되는 G라는 task group이
+* 있다고 가정합니다. A, B, G의 load 및 util avg은 PELT 알고리즘을 사용하여
* 계산되며 각 task 및 task group에는 자체 PELT window가 있습니다.
*
-* A, B, G의 PELT window가 서로 정렬되어 있지 않으면 크기나 시작 시간과
-* 종료 시간이 같지 않다는 의미입니다. PELT 알고리즘은 서로 다른 기간
-* 동안 task 및 task group의 load 및 util을 추적하므로 각 task 및
+* A, B, G의 PELT window가 서로 정렬되어 있지 않으면 크기나 시작 시간과
+* 종료 시간이 같지 않다는 의미입니다. PELT 알고리즘은 서로 다른 기간
+* 동안 task 및 task group의 load 및 util을 추적하므로 각 task 및
* task group에 대해 계산된 load 및 util avg이 부정확해질 수 있습니다.
*
-* 반면에 A, B, G의 PELT 창들이 서로 정렬되어 있다면 크기와 시작 시간과
-* 종료 시간이 같다는 뜻입니다. 이를 통해 PELT 알고리즘은 동일한 기간 동안
-* task 및 task group의 load 및 util을 추적하므로 각 task 및 task group에
+* 반면에 A, B, G의 PELT 창들이 서로 정렬되어 있다면 크기와 시작 시간과
+* 종료 시간이 같다는 뜻입니다. 이를 통해 PELT 알고리즘은 동일한 기간 동안
+* task 및 task group의 load 및 util을 추적하므로 각 task 및 task group에
* 대해 계산된 load 및 util avg의 정확도를 개선하는 데 도움이 될 수 있습니다.
* --------------------
* --- load 관련 용어 ---
* - historical weigth
-* 과거에 작업 또는 작업 그룹에 주어진 CPU 시간의 양을 나타냅니다.
-* 스케줄러에서 작업 또는 작업 그룹의 "load_avg"는 향후 소비할 것으로
-* 예상되는 CPU 시간을 측정한 것입니다. 이 load_avg 값은 작업 또는 그룹의
-* 현재 및 과거 CPU 사용량을 기반으로 하는 경우가 많습니다.
+* 과거에 작업 또는 작업 그룹에 주어진 CPU 시간의 양을 나타냅니다.
+* 스케줄러에서 작업 또는 작업 그룹의 "load_avg"는 향후 소비할 것으로
+* 예상되는 CPU 시간을 측정한 것입니다. 이 load_avg 값은 작업 또는 그룹의
+* 현재 및 과거 CPU 사용량을 기반으로 하는 경우가 많습니다.
*
-* 예를 들어 오랫동안 CPU에서 실행되어 온 작업 그룹을 생각해 보십시오.
-* 이 그룹은 과거에 많은 CPU 시간을 소비했기 때문에 높은 "역사적 가중치"를
-* 갖게 됩니다. 그룹이 앞으로도 비슷한 양의 CPU 시간을 계속 사용할 것으로
-* 예상되면 해당 load_avg 값이 높아집니다. 반면에 그룹이 앞으로 더 적은
+* 예를 들어 오랫동안 CPU에서 실행되어 온 작업 그룹을 생각해 보십시오.
+* 이 그룹은 과거에 많은 CPU 시간을 소비했기 때문에 높은 "역사적 가중치"를
+* 갖게 됩니다. 그룹이 앞으로도 비슷한 양의 CPU 시간을 계속 사용할 것으로
+* 예상되면 해당 load_avg 값이 높아집니다. 반면에 그룹이 앞으로 더 적은
* CPU 시간을 소비할 것으로 예상되는 경우에는 load_avg 값이 더 낮아집니다.
*
* - blocked load
-* 현재 예약 대기 중이며 현재 CPU에서 실행되고 있지 않은 작업의 load입니다.
-* 이러한 task은 스케줄러에서 CPU를 할당할 때까지 실행할 수 없기 때문에
-* "block"된 것으로 간주됩니다.
+* 현재 예약 대기 중이며 현재 CPU에서 실행되고 있지 않은 작업의 load입니다.
+* 이러한 task은 스케줄러에서 CPU를 할당할 때까지 실행할 수 없기 때문에
+* "block"된 것으로 간주됩니다.
*
-* blocked load는 block task가 실행 가능해지고 CPU에서 실행되도록 예약된 후
-* task 또는 task group이 반환될 것으로 예상되는 load를 나타내기 때문에
+* blocked load는 block task가 실행 가능해지고 CPU에서 실행되도록 예약된 후
+* task 또는 task group이 반환될 것으로 예상되는 load를 나타내기 때문에
* task 또는 task group의 load avg에 포함됩니다. load avg에 block load를
-* 포함함으로써 스케줄러는 예약 대기 중인 작업의 CPU 리소스 사용량을
-* 고려하고 다른 task 및 task group에 CPU 시간을 할당하는 방법에 대해 더 많은
+* 포함함으로써 스케줄러는 예약 대기 중인 작업의 CPU 리소스 사용량을
+* 고려하고 다른 task 및 task group에 CPU 시간을 할당하는 방법에 대해 더 많은
* 정보에 입각한 결정을 내릴 수 있습니다.
*
-* blocked load는 task 또는 task group의 avg load를 계산하는 데 사용되기
-* 때문에 load sum의 필수 부분으로 유지됩니다. 하중 avg은 하중 sum를
-* PELT window의 크기로 나누어 계산합니다. blocked load가 load sum의 필수
-* 부분으로 포함되지 않은 경우 load avg에 정확하게 반영되지 않으며
-* 스케줄러는 task 또는 task group의 CPU 리소스 사용에 대한 완전한 그림을
-* 갖지 못할 것입니다.
+* blocked load는 task 또는 task group의 avg load를 계산하는 데 사용되기
+* 때문에 load sum의 필수 부분으로 유지됩니다. 하중 avg은 하중 sum를
+* PELT window의 크기로 나누어 계산합니다. blocked load가 load sum의 필수
+* 부분으로 포함되지 않은 경우 load avg에 정확하게 반영되지 않으며
+* 스케줄러는 task 또는 task group의 CPU 리소스 사용에 대한 완전한 그림을
+* 갖지 못할 것입니다.
*
* - overlap
-* A와 B라는 두 개의 작업이 있는 실행 대기열이 있다고 상상해 보십시오.
-* 작업 A는 실행 가능한 시간의 50%이고 작업 B는 실행 가능한 시간의
-* 40%입니다. 이 경우 두 작업의 실행 가능한 기간이 완전히 겹치기 때문에
-* runqueue는 항상 실행 가능합니다. 작업 A가 실행 가능할 때 작업 B도 실행
-* 가능한 시간의 40%이고 작업 B가 실행 가능한 경우 작업 A도 실행 가능한
-* 시간의 50%이기 때문입니다.
+* A와 B라는 두 개의 작업이 있는 실행 대기열이 있다고 상상해 보십시오.
+* 작업 A는 실행 가능한 시간의 50%이고 작업 B는 실행 가능한 시간의
+* 40%입니다. 이 경우 두 작업의 실행 가능한 기간이 완전히 겹치기 때문에
+* runqueue는 항상 실행 가능합니다. 작업 A가 실행 가능할 때 작업 B도 실행
+* 가능한 시간의 40%이고 작업 B가 실행 가능한 경우 작업 A도 실행 가능한
+* 시간의 50%이기 때문입니다.
*
-* 이제 C와 D라는 두 개의 작업이 있는 실행 대기열이 있다고 상상해 보십시오.
-* 작업 C는 실행 가능한 시간의 60%이고 작업 D는 실행 가능한 시간의
-* 70%입니다. 이 경우 runqueue는 두 작업의 실행 가능한 기간이 겹치는 방식에
-* 따라 시간의 60%에서 100% 사이 어디에서나 실행할 수 있습니다. 두 작업을
-* 동시에 실행할 수 없는 경우 실행 대기열은 시간의 60%만 실행할 수
-* 있습니다(각 작업이 실행 가능한 최소 시간). 두 작업이 항상 동시에 실행
-* 가능한 경우 실행 대기열은 시간의 100% 실행 가능합니다(각 작업이 실행
-* 가능한 최대 시간). 두 작업의 실행 가능 기간이 겹치면 실행 대기열
-* 실행 가능 시간이 60%에서 100% 사이가 됩니다.
+* 이제 C와 D라는 두 개의 작업이 있는 실행 대기열이 있다고 상상해 보십시오.
+* 작업 C는 실행 가능한 시간의 60%이고 작업 D는 실행 가능한 시간의
+* 70%입니다. 이 경우 runqueue는 두 작업의 실행 가능한 기간이 겹치는 방식에
+* 따라 시간의 60%에서 100% 사이 어디에서나 실행할 수 있습니다. 두 작업을
+* 동시에 실행할 수 없는 경우 실행 대기열은 시간의 60%만 실행할 수
+* 있습니다(각 작업이 실행 가능한 최소 시간). 두 작업이 항상 동시에 실행
+* 가능한 경우 실행 대기열은 시간의 100% 실행 가능합니다(각 작업이 실행
+* 가능한 최대 시간). 두 작업의 실행 가능 기간이 겹치면 실행 대기열
+* 실행 가능 시간이 60%에서 100% 사이가 됩니다.
*
* - assuming minimal overlap
-* runqueue(rq)에 대한 실행 가능 시간을 계산할 때 runqueue에 있는 작업의
-* 실행 가능 기간이 많이 겹치지 않는다고 가정하는 것을 의미합니다. 이로
+* runqueue(rq)에 대한 실행 가능 시간을 계산할 때 runqueue에 있는 작업의
+* 실행 가능 기간이 많이 겹치지 않는다고 가정하는 것을 의미합니다. 이로
* 인해 runqueue의 실행 가능한 시간에 대한 추정치가 낮아집니다.
*
-* 예를 들어 E와 F라는 두 개의 작업이 있는 실행 대기열이 있고 실행 대기열의
-* 실행 가능 시간을 계산하려는 경우 두 작업의 실행 가능 기간이 전혀 겹치지
-* 않는다고 가정할 수 있습니다. 이 경우 실행 대기열에 대한 총 실행 가능
-* 시간을 얻기 위해 각 작업에 대한 실행 가능 시간을 추가하기만 하면 됩니다.
-* 이렇게 하면 두 작업 간의 중복이 최소화된다고 가정하기 때문에 실행
+* 예를 들어 E와 F라는 두 개의 작업이 있는 실행 대기열이 있고 실행 대기열의
+* 실행 가능 시간을 계산하려는 경우 두 작업의 실행 가능 기간이 전혀 겹치지
+* 않는다고 가정할 수 있습니다. 이 경우 실행 대기열에 대한 총 실행 가능
+* 시간을 얻기 위해 각 작업에 대한 실행 가능 시간을 추가하기만 하면 됩니다.
+* 이렇게 하면 두 작업 간의 중복이 최소화된다고 가정하기 때문에 실행
* 대기열의 실행 가능한 시간에 대한 추정치가 낮아집니다.
*
-* 반면에 두 작업의 실행 가능한 기간이 상당히 겹친다고 가정하면 실행
-* 대기열의 실행 가능한 시간에 대해 더 높은 추정치를 얻을 수 있습니다.
-* 작업이 동시에 더 자주 실행될 수 있다고 가정하기 때문에 실행 대기열의
-* 전체 실행 가능 시간이 늘어납니다.
+* 반면에 두 작업의 실행 가능한 기간이 상당히 겹친다고 가정하면 실행
+* 대기열의 실행 가능한 시간에 대해 더 높은 추정치를 얻을 수 있습니다.
+* 작업이 동시에 더 자주 실행될 수 있다고 가정하기 때문에 실행 대기열의
+* 전체 실행 가능 시간이 늘어납니다.
* --------------------
* ----------------------------------------------------------------------
* - @gcfs_rq나 @se에 변화가 생긴경우 @se, @cfs를 update한다.
@@ -4461,12 +4461,12 @@ update_tg_cfs_runnable(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cf
* - propagate runnable sum값의 증감 유무에 따라 @se의 load를 update하고
* 변경된 값만큼 @cfs_rq의 load를 재계산한다.
*
- * 1. 증가하는경우 assuming minimal overlap을 적용하는 개념으로
+ * 1. 증가하는경우 assuming minimal overlap을 적용하는 개념으로
* add 와 divider에 대한 min처리만 수행한다.
*
* 2. 감소하는 경우는 weight를 고려한다. 위쪽 주석의 식에 따라
* ge->load.weight * grq->avg.load_avg
- * ge->avg.load_avg = -----------------------------------
+ * ge->avg.load_avg = -----------------------------------
* grq->load.weight
*
* 를 사용하여 재계산한다. 단 재계산값이 증가했을 경우엔 min처리를 한다.
@@ -4507,10 +4507,10 @@ update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se, struct cfs_rq
/*
* IAMROOT, 2022.12.31:
- * - 감소됬다면 task runnable이 균등하게 계산한다는 관점으로 avg와 weight로
+ * - 감소됬다면 task runnable이 균등하게 계산한다는 관점으로 avg와 weight로
* 재계산한다.
*
- * runnable_sum = grq->avg.load_sum / grq->load.weight
+ * runnable_sum = grq->avg.load_sum / grq->load.weight
*/
/*
* Estimate the new unweighted runnable_sum of the gcfs_rq by
@@ -4768,7 +4768,7 @@ update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
/*
* IAMROOT, 2022.12.31:
* - papago
- * removed_runnable은 removed_load의 비가중 버전이므로 removed_load_sum을
+ * removed_runnable은 removed_load의 비가중 버전이므로 removed_load_sum을
* 추정하는 데 사용할 수 있습니다.
*
* - 감소된값을 propagate해야된다. 감소된값을 기록한다.
@@ -4827,7 +4827,7 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
/*
* IAMROOT, 2023.01.07:
* - papago
- * @se를 @cfs_rq에 첨부할 때 decay window 을 정렬해야 합니다. 그렇지 않으면 정말 이상하고
+ * @se를 @cfs_rq에 첨부할 때 decay window 을 정렬해야 합니다. 그렇지 않으면 정말 이상하고
* 멋진 일이 발생할 수 있기 때문입니다.
* (entity 입장에서의 decay window에 대한 정렬을 의미)
*/
@@ -4843,8 +4843,8 @@ static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
/*
* IAMROOT, 2023.01.07:
* - papago
- * Hell(o) 불쾌한 물건.. 새 period_contrib를 기반으로 _sum을 다시 계산해야 합니다.
- * 이것은 정확하지는 않지만 우리는 완전히 PELT 계층 구조 밖에 있기 때문에 _sum을
+ * Hell(o) 불쾌한 물건.. 새 period_contrib를 기반으로 _sum을 다시 계산해야 합니다.
+ * 이것은 정확하지는 않지만 우리는 완전히 PELT 계층 구조 밖에 있기 때문에 _sum을
* 약간 잘라도 아무도 신경 쓰지 않습니다.
*/
se->avg.util_sum = se->avg.util_avg * divider;
@@ -4942,7 +4942,7 @@ static void detach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *s
* 2. @cfs_rq에 대한 load avg 계산.
* 3. @se에 대한 전파 처리.
* 4. @se가 attach인 경우 @cfs_rq에 attach.
- * 5. decay됫거나 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)
@@ -5607,7 +5607,7 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
/*
* IAMROOT, 2023.01.07:
- * - @curr runtime을 종료된것을 검사한다. 다 사용됬으면
+ * - @curr runtime을 종료된것을 검사한다. 다 사용됬으면
* @cfs_rq의 cpu한테 reschedule 요청을 한다.
*/
@@ -5706,7 +5706,7 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
/*
* IAMROOT, 2023.01.28:
* - papago
- * CPU 부하가 자체 무게의 두 배 이상인 경우 최대 슬라이스 길이를 추적합니다(즉, 주변에 더
+ * CPU 부하가 자체 무게의 두 배 이상인 경우 최대 슬라이스 길이를 추적합니다(즉, 주변에 더
* 가벼운 작업만 있는 경우 추적하지 않음).
*/
if (schedstat_enabled() &&
@@ -5757,9 +5757,9 @@ pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr)
/*
* IAMROOT, 2023.01.28:
* - papago
- * curr이 설정되어 있으면 트리에 아무 것도 없는 경우 가장 왼쪽 엔터티의 왼쪽이 여전히
+ * curr이 설정되어 있으면 트리에 아무 것도 없는 경우 가장 왼쪽 엔터티의 왼쪽이 여전히
* 트리에 있는지 확인해야 합니다.
- *
+ *
* - curr가 left보다 왼쪽인지 확인한다. 더 왼쪽이면 left = curr.
*/
if (!left || (curr && entity_before(curr, left)))
@@ -5812,7 +5812,7 @@ pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr)
/*
* IAMROOT, 2023.01.28:
* - next를 가장 높은 우선순위로 고려한다.
- * - next가 left 보다 너무 앞서있는경우가 아니면 se를 next로 선택한다.
+ * - next가 left 보다 너무 앞서있는경우가 아니면 se를 next로 선택한다.
*/
if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1) {
/*
@@ -5874,7 +5874,7 @@ static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
/*
* IAMROOT, 2022.12.21:
- * - @curr
+ * - @curr
* ex) A:33%, B:33%, C:34%
* A가 33%에 대한 분배 시간을 다 마치고 이함수에 진입했을때 curr는 B가 된다.
* - queued
@@ -6006,7 +6006,7 @@ static inline u64 default_cfs_period(void)
/*
* IAMROOT, 2022.12.22:
- * - nsec 단위로 return. 기본값 5ms
+ * - nsec 단위로 return. 기본값 5ms
*/
static inline u64 sched_cfs_bandwidth_slice(void)
{
@@ -6023,7 +6023,7 @@ static inline u64 sched_cfs_bandwidth_slice(void)
/*
* IAMROOT, 2022.12.23:
* - papago
- * 할당량에 따라 런타임을 보충합니다. rq->lock 주변에 추가 동기화를 추가하지
+ * 할당량에 따라 런타임을 보충합니다. rq->lock 주변에 추가 동기화를 추가하지
* 않도록 rq->clock 대신 sched_clock_cpu를 직접 사용합니다.
*
* cfs_b->잠금이 필요합니다.
@@ -6056,15 +6056,15 @@ static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg)
*
* 1) quota == RUNTIME_INF. bandwidth 사용안하는 경우
* cfs_b | runtime_ | cfs_b || timer | runtime_ |
- * qouta | remaining | runtime || 예약 | remaining | runtime
+ * qouta | remaining | runtime || 예약 | remaining | runtime
* +-----+-----------+---------++-------+-----------+--------
- * | ~0 | - | - || X | 5ms | 유지
+ * | ~0 | - | - || X | 5ms | 유지
*
* 2) runtime_remain 이 target_runtime이 될때까지 불충분한 경우
* 남아있는 runtime만큼 runtime_remain이 충전된다.
*
* | runtime_ | cfs_b || timer | runtime_ |
- * | remaining | runtime || 예약 | remaining | runtime
+ * | remaining | runtime || 예약 | remaining | runtime
* +-----------+---------++-------+-----------+--------
* | 0ms | 0ms || O | 0ms | 0ms
* | 0ms | 1ms || O | 1ms | 0ms
@@ -6078,7 +6078,7 @@ static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg)
* 3) runtime_remain이 target_runtime이 될때까지 충분한 경우
*
* | runtime_ | cfs_b || timer | runtime_ |
- * | remaining | runtime || 예약 | remaining | runtime
+ * | remaining | runtime || 예약 | remaining | runtime
* +-----------+---------++-------+-----------+--------
* | 0ms | 5ms || O | 5ms | 0ms
* | 5ms | 0ms || O | 5ms | 0ms
@@ -6122,7 +6122,7 @@ static int __assign_cfs_rq_runtime(struct cfs_bandwidth *cfs_b,
/*
* IAMROOT, 2022.12.22:
- * - runtime 이미 남아있다면 amount만큼 빼준다. 그리고 뺀만큼을
+ * - runtime 이미 남아있다면 amount만큼 빼준다. 그리고 뺀만큼을
* runtime_remaining에 추가한다.
*/
if (cfs_b->runtime > 0) {
@@ -6187,7 +6187,7 @@ static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec)
* - likely(cfs_rq->curr)
* 현재 실행중
* - assign_cfs_rq_runtime(cfs_rq)
- * runtime_remain을 얻어오고 period_timer 예약
+ * runtime_remain을 얻어오고 period_timer 예약
* - runtime_remain을 얻어오는데 실패했는데 실행중이면 resched_curr 요청.
*/
/*
@@ -6501,7 +6501,7 @@ static void distribute_cfs_runtime(struct cfs_bandwidth *cfs_b)
rq_lock_irqsave(rq, &rf);
/*
* IAMROOT, 2022.12.23:
- * - bandwidth 사용중인지, throttle이 남아있는지 확인
+ * - bandwidth 사용중인지, throttle이 남아있는지 확인
*/
if (!cfs_rq_throttled(cfs_rq))
goto next;
@@ -6558,11 +6558,11 @@ static void distribute_cfs_runtime(struct cfs_bandwidth *cfs_b)
/*
* IAMROOT, 2022.12.23:
* - papago
- * task_group의 대역폭을 다시 채우고 cfs_rqs를 적절하게 조절 해제하는 일을 담당합니다. 마지막 기간
- * 내에 활동이 없으면 예약이 재개될 때까지 타이머가 비활성화됩니다. cfs_b->idle은 이 상태를 추적하는
- * 데 사용됩니다.
+ * task_group의 대역폭을 다시 채우고 cfs_rqs를 적절하게 조절 해제하는 일을 담당합니다. 마지막 기간
+ * 내에 활동이 없으면 예약이 재개될 때까지 타이머가 비활성화됩니다. cfs_b->idle은 이 상태를 추적하는
+ * 데 사용됩니다.
*
- * @return 0 : timer restart.
+ * @return 0 : timer restart.
* 1 : timer 종료.
*
* 1. @cfs_b runtime refill
@@ -6590,9 +6590,9 @@ static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun, u
*/
/*
* IAMROOT, 2022.12.23:
- * - papago
- * 유휴는 !throttled(적자가 큰 경우)에 따라 달라지며 비활성 상태가 되면 다른
- * 모든 작업을 연기할 수 있습니다.
+ * - papago
+ * 유휴는 !throttled(적자가 큰 경우)에 따라 달라지며 비활성 상태가 되면 다른
+ * 모든 작업을 연기할 수 있습니다.
*
* - 이미 idle이 되어있는데 throttled rq도 없는 상황. timer 종료
*/
@@ -6640,8 +6640,8 @@ static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun, u
/*
* IAMROOT, 2022.12.27:
* - papago
- * 스로틀 해제 후 기간 동안 활동이 보장되지만 새 대역폭이 기존 대역폭
- * 부족을 충당하기에 불충분한 경우도 포함됩니다. (조절된 entity가 있는
+ * 스로틀 해제 후 기간 동안 활동이 보장되지만 새 대역폭이 기존 대역폭
+ * 부족을 충당하기에 불충분한 경우도 포함됩니다. (조절된 entity가 있는
* 동안 타이머가 활성 상태를 유지하도록 합니다.).
*/
cfs_b->idle = 0;
@@ -6899,7 +6899,7 @@ static enum hrtimer_restart sched_cfs_period_timer(struct hrtimer *timer)
*/
/*
* IAMROOT, 2022.12.23:
- * - 너무 자주 발생한다.
+ * - 너무 자주 발생한다.
* 1. period를 2배로 늘리는걸 시도 한다.
* 2. period동안 사용할 수있는 cpu 작업양 2배로 늘린다.
* 3. period동안 single burst를 수행하는 cpu 수행 양을 늘린다.
@@ -6950,7 +6950,7 @@ static enum hrtimer_restart sched_cfs_period_timer(struct hrtimer *timer)
* period를 쓰는 정도.
* ex) period = 1, quota = -1인 경우 (편의상 ns를 sec로 하여 1로 표현)
* cfs process A, B가 있는 경우 각각 50%씩 사용. (합쳐서 100%)
- *
+ *
* ex) perioid = 1, quota = 0.3인 경우,
* cfs process A, B가 있는 경우 각각 16.66%씩 사용. (33%)
*
@@ -6986,7 +6986,7 @@ static void init_cfs_rq_runtime(struct cfs_rq *cfs_rq)
/*
* IAMROOT, 2022.12.22:
- * - perioid_timer(sched_cfs_period_timer)를 cfs_b->period후에
+ * - perioid_timer(sched_cfs_period_timer)를 cfs_b->period후에
* 시작하도록한다.
*/
void start_cfs_bandwidth(struct cfs_bandwidth *cfs_b)
@@ -8702,7 +8702,7 @@ static unsigned long wakeup_gran(struct sched_entity *se)
* 이제 curr가 실행되기 때문에 gran을 실시간에서 가상 시간으로 단위로 변환하십시오.
*
* 'curr' 대신 'se'를 사용하여 가벼운 작업에 페널티를 주어 더 쉽게 선점할 수 있습니다.
- * 즉, 'se' < 'curr'이면 결과 gran이 더 커지므로 더 가벼운 작업에 페널티를 주고,
+ * 즉, 'se' < 'curr'이면 결과 gran이 더 커지므로 더 가벼운 작업에 페널티를 주고,
* otoh 'se' > 'curr'이면 결과 gran이 더 작아지므로 더 가벼운 작업에 페널티를 줍니다.
*
* 이것은 가장 왼쪽 작업이 버디보다 우선순위가 높을 때 버디에게 특히 중요합니다.
@@ -8734,10 +8734,10 @@ static unsigned long wakeup_gran(struct sched_entity *se)
*
* - curr | se : -1
*
- * - gran
+ * - gran
* se | curr | : 0
*
- * - gran
+ * - gran
* se | | curr : 1
*/
static int
@@ -8947,10 +8947,10 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
/*
* IAMROOT, 2023.01.28:
* - papago
- * dequeue_task_fair()의 set_next_buddy() 때문에 다음 작업이 현재 작업과 동일한 cgroup에서
+ * dequeue_task_fair()의 set_next_buddy() 때문에 다음 작업이 현재 작업과 동일한 cgroup에서
* 나올 가능성이 높습니다.
*
- * 따라서 전체 cgroup 계층 구조를 넣거나 설정하는 것을 피하고 실제로 변경되는 부분만
+ * 따라서 전체 cgroup 계층 구조를 넣거나 설정하는 것을 피하고 실제로 변경되는 부분만
* 변경하십시오.
*
* - 계층구조로 내려가면서 curr의 next를 순회한다. 최종적으로 마지막 next로 선택된것을
@@ -8968,8 +8968,8 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
/*
* IAMROOT, 2023.01.28:
* - papago
- * put_prev_entity()를 수행하지 않고 여기에 왔기 때문에 cfs_rq->curr도 고려해야 합니다.
- * 여전히 실행 가능한 엔터티인 경우 update_curr()는 vruntime을 업데이트하고, 그렇지 않으면
+ * put_prev_entity()를 수행하지 않고 여기에 왔기 때문에 cfs_rq->curr도 고려해야 합니다.
+ * 여전히 실행 가능한 엔터티인 경우 update_curr()는 vruntime을 업데이트하고, 그렇지 않으면
* 우리가 본 적이 있다는 사실을 잊어버립니다.
*/
if (curr) {
@@ -8992,9 +8992,9 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
/*
* IAMROOT, 2023.01.28:
* - papago
- * check_cfs_rq_runtime()에 대한 이 호출은 스로틀링을 수행하고 상위 항목의 대기열에서
+ * check_cfs_rq_runtime()에 대한 이 호출은 스로틀링을 수행하고 상위 항목의 대기열에서
* 제외합니다.
- * 따라서 nr_running 테스트는 실제로 정확합니다.
+ * 따라서 nr_running 테스트는 실제로 정확합니다.
* - throttle인지 확인한다.
*/
if (unlikely(check_cfs_rq_runtime(cfs_rq))) {
@@ -9021,7 +9021,7 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
/*
* IAMROOT, 2023.01.28:
* - papago
- * 아직 put_prev_entity를 수행하지 않았고 선택한 작업이 시작과 다른 작업인 경우 최소량의
+ * 아직 put_prev_entity를 수행하지 않았고 선택한 작업이 시작과 다른 작업인 경우 최소량의
* cfs_rq를 터치해 봅니다.
*
* - 선택한 p(se)가 @prev가 다르다면 prev se를 put하고, 새로운 p(se)를 set한다.
@@ -9034,7 +9034,7 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
* - se, pse가 같은 cfs_rq소속일때까지 반복하며
* pse를 cfs_rq에 enqueue, se를 cfs_rq에서 dequeue를 하고, se를 curr로 update한다.
*
- * O
+ * O
* / \
* O <----same_group
* / \
@@ -9046,12 +9046,11 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
int se_depth = se->depth;
int pse_depth = pse->depth;
- p
/*
* IAMROOT, 2023.01.28:
* - pse가 se보다 더 깊거나 같은 위치. pse를 put해준다.
* - ex)
- * O
+ * O
* / \
* O <----same_group
* / \
@@ -9072,7 +9071,7 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
* IAMROOT, 2023.01.28:
* - se가 pse보다 더 깊거나 같은 위치. curr를 update해준다.
* - ex)
- * O
+ * O
* / \
* O <----same_group
* / \
@@ -9152,6 +9151,11 @@ done: __maybe_unused;
if (!rf)
return NULL;
+/*
+ * IAMROOT, 2023.02.11:
+ * - 아래 코드들이 balancing.
+ * next task를 못고른 상태가 되어 idle이 되기전에 가져올수 있는 task를 찾는다.
+ */
new_tasks = newidle_balance(rq, rf);
/*
diff --git a/kernel/sched/features.h b/kernel/sched/features.h
index 7f8dace0964c..8af70bd23b03 100644
--- a/kernel/sched/features.h
+++ b/kernel/sched/features.h
@@ -74,6 +74,17 @@ SCHED_FEAT(WARN_DOUBLE_CLOCK, false)
* IPI to that CPU and let that CPU push the RT task to where
* it should go may be a better scenario.
*/
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * 동시에 우선 순위를 낮추고 마이그레이션할 수 있고 실행 대기 중인
+ * RT 작업이 있는 단일 CPU가 있는 CPU의 thundering herd attack을 피하기
+ * 위해 다른 CPU가 해당 CPU를 차지하려고 합니다. rq를 잠그고 가능하면
+ * 대규모 경합을 생성하여 해당 CPU에 IPI를 보내고 해당 CPU가 RT
+ * 작업을 가야 할 곳으로 푸시하도록 하는 것이 더 나은 시나리오일
+ * 수 있습니다.
+ */
SCHED_FEAT(RT_PUSH_IPI, true)
#endif
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 245a0aef0f6a..5a0a3a7d73e2 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -314,12 +314,20 @@ int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent)
static void pull_rt_task(struct rq *this_rq);
+/*
+ * IAMROOT, 2023.02.11:
+ * - @rq가 online이고 @prev 우선순위보다 낮다면(숫자가 낮을수록 높음) return true
+ */
static inline bool need_pull_rt_task(struct rq *rq, struct task_struct *prev)
{
/* Try to pull RT tasks here if we lower this rq's prio */
return rq->online && rq->rt.highest_prio.curr > prev->prio;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - rt overloaded task 수를 return한다.
+ */
static inline int rt_overloaded(struct rq *rq)
{
return atomic_read(&rq->rd->rto_count);
@@ -401,6 +409,11 @@ static void dec_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
update_rt_migration(rt_rq);
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - pushable_tasks가 있으면 return 1
+ */
+
static inline int has_pushable_tasks(struct rq *rq)
{
return !plist_head_empty(&rq->rt.pushable_tasks);
@@ -412,6 +425,12 @@ static DEFINE_PER_CPU(struct callback_head, rt_pull_head);
static void push_rt_tasks(struct rq *);
static void pull_rt_task(struct rq *);
+/*
+ * IAMROOT, 2023.02.11:
+ * - pushable_tasks가 있으면 push를 지정(push_rt_tasks)한다.
+ * (pull의 경우 pull_rt_task가 지정된다.)
+ *
+ */
static inline void rt_queue_push_tasks(struct rq *rq)
{
if (!has_pushable_tasks(rq))
@@ -425,22 +444,46 @@ static inline void rt_queue_pull_task(struct rq *rq)
queue_balance_callback(rq, &per_cpu(rt_pull_head, rq->cpu), pull_rt_task);
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - @p를 pushable task로 enqueue한다.
+ */
static void enqueue_pushable_task(struct rq *rq, struct task_struct *p)
{
+/*
+ * IAMROOT, 2023.02.11:
+ * - 이미 등록된 상황일 수도 있다. 일단 삭제하고 다시 추가한다.
+ */
plist_del(&p->pushable_tasks, &rq->rt.pushable_tasks);
plist_node_init(&p->pushable_tasks, p->prio);
plist_add(&p->pushable_tasks, &rq->rt.pushable_tasks);
/* Update the highest prio pushable task */
+/*
+ * IAMROOT, 2023.02.11:
+ * - highest_prio.next 갱신.
+ */
if (p->prio < rq->rt.highest_prio.next)
rq->rt.highest_prio.next = p->prio;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - pushable_tasks
+ * 같은 cpu에서 두개 이상의 rt task가 있는 경우 다른 cpu로 밀어내기
+ * 위한것
+ * - pushable_tasks에 등록되있는 경우 일단 dequeue한다.
+ */
static void dequeue_pushable_task(struct rq *rq, struct task_struct *p)
{
plist_del(&p->pushable_tasks, &rq->rt.pushable_tasks);
/* Update the new highest prio pushable task */
+/*
+ * IAMROOT, 2023.02.11:
+ * - 여전시 pushable tasks가 있으면 highest prio를 기록하고 그게 아니면
+ * max로 설정한다.
+ */
if (has_pushable_tasks(rq)) {
p = plist_first_entry(&rq->rt.pushable_tasks,
struct task_struct, pushable_tasks);
@@ -487,6 +530,10 @@ static inline void rt_queue_push_tasks(struct rq *rq)
static void enqueue_top_rt_rq(struct rt_rq *rt_rq);
static void dequeue_top_rt_rq(struct rt_rq *rt_rq);
+/*
+ * IAMROOT, 2023.02.11:
+ * - rq에 들어있는지 확인.
+ */
static inline int on_rt_rq(struct sched_rt_entity *rt_se)
{
return rt_se->on_rq;
@@ -507,6 +554,33 @@ static inline int on_rt_rq(struct sched_rt_entity *rt_se)
* Note that uclamp_min will be clamped to uclamp_max if uclamp_min
* > uclamp_max.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * uclamp 설정을 고려하여 @cpu에서 실행할 작업 @p의 적합성을 확인합니다.
+ *
+ * 이 검사는 uclamp_min 값이 @cpu의 용량보다 큰 이기종 시스템에서만
+ * 중요합니다. 이기종 시스템이 아닌 경우 이 함수는 항상 true를 반환합니다.
+ *
+ * 이 함수는 @cpu의 용량이 >= uclamp_min이면 true를 반환하고 그렇지
+ * 않으면 false를 반환합니다.
+ *
+ * uclamp_min > uclamp_max인 경우 uclamp_min은 uclamp_max로 고정됩니다.
+ *
+ * --- UCLAMP ---
+ * - application의 경우 background, forground등에서 동작한다.
+ * 어떤것들은 절전모드에서 조그맣게 동작하는걸 원하고,
+ * 어떤것들은 강력하게 동작하는것을 원한다.
+ * 예를들어 A라는 app이 background에서 가끔돌아도 cpu를 많이 사용해야된다
+ * 라던가
+ * 벤치마킹 프로그램처럼 무조건 cpu를 많이 사용해야되는 것이 있다.
+ * 이러한 상황들을 위해 제한을 시킨다.
+ * max는 Big cpu의 max freq 기준으로 정한다.
+ * --------------
+ *
+ * - @p에서 설정한 uclamp의 min/max중 @cpu의 rq가 최소값을 넘으면
+ * return true.
+ */
static inline bool rt_task_fits_capacity(struct task_struct *p, int cpu)
{
unsigned int min_cap;
@@ -573,6 +647,12 @@ static inline struct task_group *next_task_group(struct task_group *tg)
#define for_each_sched_rt_entity(rt_se) \
for (; rt_se; rt_se = rt_se->parent)
+/*
+ * IAMROOT, 2023.02.11:
+ * - @rt_se가 entity인지 task인지 확인한다. my_q가 있으면 entity(group)
+ * return != NULL : group entity이며 my_q를 가져옴.
+ * NULL : task
+ */
static inline struct rt_rq *group_rt_rq(struct sched_rt_entity *rt_se)
{
return rt_se->my_q;
@@ -1043,15 +1123,27 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun)
return idle;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - group entity이면 가장 높은 prio, task면 task prio를 return.
+ */
static inline int rt_se_prio(struct sched_rt_entity *rt_se)
{
#ifdef CONFIG_RT_GROUP_SCHED
struct rt_rq *rt_rq = group_rt_rq(rt_se);
+/*
+ * IAMROOT, 2023.02.11:
+ * - 자기꺼중에 가장 높은 prio를 가진것을 return.
+ */
if (rt_rq)
return rt_rq->highest_prio.curr;
#endif
+/*
+ * IAMROOT, 2023.02.11:
+ * - task prio가져온다.
+ */
return rt_task_of(rt_se)->prio;
}
@@ -1587,6 +1679,11 @@ static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags)
* Put task to the head or the end of the run list without the overhead of
* dequeue followed by enqueue.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - @rt_se priority list에 @head에 따라 requeue한다.
+ * - group entity의 경우엔 group entity에서 가장 높은 우선순위로 옮긴다.
+ */
static void
requeue_rt_entity(struct rt_rq *rt_rq, struct sched_rt_entity *rt_se, int head)
{
@@ -1603,7 +1700,8 @@ requeue_rt_entity(struct rt_rq *rt_rq, struct sched_rt_entity *rt_se, int head)
/*
* IAMROOT, 2023.02.10:
- * - TODO
+ * - @p의 rt_se부터 시작하여 parent까지 올라가면서 @head따라 head / tail로
+ * requeue를 한다.
*/
static void requeue_task_rt(struct rq *rq, struct task_struct *p, int head)
{
@@ -1616,6 +1714,11 @@ static void requeue_task_rt(struct rq *rq, struct task_struct *p, int head)
}
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - rt의 경우 가장높은 우선순위 태스크가 한개밖에 없으면 yield가
+ * 안될 것이다.
+ */
static void yield_task_rt(struct rq *rq)
{
requeue_task_rt(rq, rq->curr, 0);
@@ -1725,6 +1828,12 @@ static void check_preempt_equal_prio(struct rq *rq, struct task_struct *p)
static int balance_rt(struct rq *rq, struct task_struct *p, struct rq_flags *rf)
{
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - @p가 아직 rq에 없고, @rq(현재 task)보다 @p가(요청한 task)
+ * 우선순위가 높다면 pull작업을 수행한다.
+ */
if (!on_rt_rq(&p->rt) && need_pull_rt_task(rq, p)) {
/*
* This is OK, because current is on_cpu, which avoids it being
@@ -1732,6 +1841,13 @@ static int balance_rt(struct rq *rq, struct task_struct *p, struct rq_flags *rf)
* disabled avoiding further scheduler activity on it and we've
* not yet started the picking loop.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * current는 on_cpu이므로 부하 분산 및 선점/IRQ가 추가 스케줄러 활동을
+ * 방지하기 위해 여전히 비활성화되어 있고 아직 선택 루프를 시작하지
+ * 않았기 때문에 괜찮습니다.
+ */
rq_unpin_lock(rq, rf);
pull_rt_task(rq);
rq_repin_lock(rq, rf);
@@ -1769,11 +1885,25 @@ static void check_preempt_curr_rt(struct rq *rq, struct task_struct *p, int flag
#endif
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - exec_start를 갱신하고 선택된 @p를 pushable에서 dequeue한다.
+ * - pick_next_task에서 불러지는 경우 @first = true
+ * set_next_task에서는 @first = false
+ */
static inline void set_next_task_rt(struct rq *rq, struct task_struct *p, bool first)
{
+/*
+ * IAMROOT, 2023.02.11:
+ * - 현재 시각으로 (@rq의 clock_task)로 @p의 exec_start를 갱신한다.
+ */
p->se.exec_start = rq_clock_task(rq);
/* The running task is never eligible for pushing */
+/*
+ * IAMROOT, 2023.02.11:
+ * - @p가 선택된 상황이니, @p를 pushable task에서 dequeue한다.
+ */
dequeue_pushable_task(rq, p);
if (!first)
@@ -1784,12 +1914,25 @@ static inline void set_next_task_rt(struct rq *rq, struct task_struct *p, bool f
* utilization. We only care of the case where we start to schedule a
* rt task
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * 이전 작업이 rt인 경우 put_prev_task()는 이미 사용률을
+ * 업데이트했습니다. 우리는 rt 작업을 예약하기 시작하는 경우에만
+ * 관심이 있습니다.
+ * - 이전 task가 rt였다면 put_prev_task_rt()에서 load avg를 갱신했었다.
+ * 이전 task가 rt가 아닌 경우에만 수행한다.
+ */
if (rq->curr->sched_class != &rt_sched_class)
update_rt_rq_load_avg(rq_clock_pelt(rq), rq, 0);
rt_queue_push_tasks(rq);
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - 가장 높은 우선순위주에서도 제일 앞에 있는 rt_se를 가져온다.
+ */
static struct sched_rt_entity *pick_next_rt_entity(struct rq *rq,
struct rt_rq *rt_rq)
{
@@ -1798,6 +1941,11 @@ static struct sched_rt_entity *pick_next_rt_entity(struct rq *rq,
struct list_head *queue;
int idx;
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - 제일 높은 priority를 가져온다.
+ */
idx = sched_find_first_bit(array->bitmap);
BUG_ON(idx >= MAX_RT_PRIO);
@@ -1807,6 +1955,10 @@ static struct sched_rt_entity *pick_next_rt_entity(struct rq *rq,
return next;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - 제일 높은 priority를 가진 task를 가져온다.
+ */
static struct task_struct *_pick_next_task_rt(struct rq *rq)
{
struct sched_rt_entity *rt_se;
@@ -1815,12 +1967,22 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq)
do {
rt_se = pick_next_rt_entity(rq, rt_rq);
BUG_ON(!rt_se);
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - rt_rq가 NULL이면 @rt_se가 task라는 의미가 되여 while이 종료되며
+ * task가 찾아지는 원리이다.
+ */
rt_rq = group_rt_rq(rt_se);
} while (rt_rq);
return rt_task_of(rt_se);
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - 제일 높은 priority를 가진 task를 가져온다.
+ */
static struct task_struct *pick_task_rt(struct rq *rq)
{
struct task_struct *p;
@@ -1833,6 +1995,11 @@ static struct task_struct *pick_task_rt(struct rq *rq)
return p;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - 제일높은 task를 선택한다. 선택됬으면 exec_start를 갱신하고
+ * pushable 상황일때는 push task를 지정(queue_balance_callback)한다.
+ */
static struct task_struct *pick_next_task_rt(struct rq *rq)
{
struct task_struct *p = pick_task_rt(rq);
@@ -1843,6 +2010,13 @@ static struct task_struct *pick_next_task_rt(struct rq *rq)
return p;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - 기존 태스크(@p)에 대해 다음과 같은걸 처리한다.
+ * 1. sum_exec_runtime 갱신 및 runtime 초과 처리
+ * 2. load avg 갱신
+ * 3. 동작할 수 있는 cpu가 2개 이상인경우 pushable task로 enqueue
+ */
static void put_prev_task_rt(struct rq *rq, struct task_struct *p)
{
update_curr_rt(rq);
@@ -1853,6 +2027,13 @@ static void put_prev_task_rt(struct rq *rq, struct task_struct *p)
* The previous task needs to be made eligible for pushing
* if it is still active
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - rq에 on상태이고 허락된 cpu가 2개 이상인 경우 pushable_tasks로
+ * enqueue한다.
+ * - 이 상황이되면 rt task가 이미 2개 이상인 상황에서, 다른 rt task에
+ * 우선순위나 RR 정책에 밀려난 상황이된다.
+ */
if (on_rt_rq(&p->rt) && p->nr_cpus_allowed > 1)
enqueue_pushable_task(rq, p);
}
@@ -1893,6 +2074,27 @@ static struct task_struct *pick_highest_pushable_task(struct rq *rq, int cpu)
static DEFINE_PER_CPU(cpumask_var_t, local_cpu_mask);
+/*
+ * IAMROOT, 2023.02.11:
+ * - 가장 낮은 우선순위를 가진 cpu rq를 선택한다.
+ * idle -> cfs만 있는 rq -> rt task 순으로 낮을 것이다.
+ *
+ * - task의 우선순위범위내(최저 우선순위 부터 tsak 우선순위까지)에서
+ * cpupri와 겹치며 uclamp조건을 만족하는 cpu를 lowest_mask에 기록한다.
+ * 최종적으로 선택하는 조건은 다음 우선순위로 따른다.
+ * 1. task cpu (l1 cache공유) :
+ * task가 동작했던 cpu가 lowest_mask에 있는경우
+ * 2. this cpu (l2 cache 이상 공유) :
+ * this cpu가 lowest_mask에 있고 해당 domain span에 포함되있는경우
+ * 3. best cpu(l2 cache 이상 공유) :
+ * lowest_mask에 있고 해당 domain span에 포함되있는경우.
+ * 4. domain에서 못찾은 경우 :
+ * lowest_mask에 this cpu가 있는 경우
+ * 5. this cpu도 lowest_mask에 없는 경우 :
+ * lowest_mask에서 아무거나 한개.
+ *
+ * 5번까지 조건에도 없으면 return -1.
+ */
static int find_lowest_rq(struct task_struct *task)
{
struct sched_domain *sd;
@@ -1913,16 +2115,31 @@ static int find_lowest_rq(struct task_struct *task)
* of the CPUs when searching for the lowest_mask.
*/
if (static_branch_unlikely(&sched_asym_cpucapacity)) {
-
+/*
+ * IAMROOT, 2023.02.11:
+ * - HMP의 경우이다.
+ * - @task의 우선순위범위에서 cpupri 범위와 겹치는 cpu를 찾아서
+ * uclamp 범위에 적합한지 검사(rt_task_fits_capacity)하여
+ * lowest_mask에 기록한다.
+ */
ret = cpupri_find_fitness(&task_rq(task)->rd->cpupri,
task, lowest_mask,
rt_task_fits_capacity);
} else {
+/*
+ * IAMROOT, 2023.02.11:
+ * - @task의 우선순위범위에서 cpupri 범위와 겹치는 cpu를 찾아서 겹치는걸
+ * lowest_mask에 기록한다.
+ */
ret = cpupri_find(&task_rq(task)->rd->cpupri,
task, lowest_mask);
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - 위에서 못찾았다. return -1
+ */
if (!ret)
return -1; /* No targets found */
@@ -1934,6 +2151,21 @@ static int find_lowest_rq(struct task_struct *task)
* We prioritize the last CPU that the task executed on since
* it is most likely cache-hot in that location.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * 이 시점에서 우리는 시스템에서 가장 낮은 우선 순위 작업을 나타내는
+ * CPU 마스크를 만들었습니다. 이제 우리는 선호도와 토폴로지를 기반으로
+ * 최고의 것을 선택하려고 합니다.
+ *
+ * 작업이 실행된 마지막 CPU는 해당 위치에서 캐시 핫일 가능성이 높기
+ * 때문에 우선 순위를 지정합니다.
+ *
+ * - @task의 cpu가 lowest_mask에 존재한다면 cache hot이라고
+ * 생각하여 즉시 task cpu로 return한다.
+ * - 마지막에 동작한 task가 task의 cpu에 기록되있으므로 가능하면
+ * @task의 cpu와 같은게 좋다.
+ */
if (cpumask_test_cpu(cpu, lowest_mask))
return cpu;
@@ -1941,11 +2173,24 @@ static int find_lowest_rq(struct task_struct *task)
* Otherwise, we consult the sched_domains span maps to figure
* out which CPU is logically closest to our hot cache data.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - current cpu가 lowest_mask에 속해있지 않은지를 검사한다.
+ */
if (!cpumask_test_cpu(this_cpu, lowest_mask))
this_cpu = -1; /* Skip this_cpu opt if not among lowest */
rcu_read_lock();
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - 밑에서부터 위로 올라간다.
+ */
for_each_domain(cpu, sd) {
+/*
+ * IAMROOT, 2023.02.11:
+ * - SD_WAKE_AFFINE이 있는 domain을 찾는다.
+ */
if (sd->flags & SD_WAKE_AFFINE) {
int best_cpu;
@@ -1953,18 +2198,31 @@ static int find_lowest_rq(struct task_struct *task)
* "this_cpu" is cheaper to preempt than a
* remote processor.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - current cpu를 선택할수 있는 상황에서 sd에 current cpu가 포함되있다면
+ * 바로 선택한다.
+ */
if (this_cpu != -1 &&
cpumask_test_cpu(this_cpu, sched_domain_span(sd))) {
rcu_read_unlock();
return this_cpu;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - 위의 상황이 아니라면 best_cpu를 찾는다.(그냥 적당히 숝서대로찾는다)
+ */
best_cpu = cpumask_any_and_distribute(lowest_mask,
sched_domain_span(sd));
if (best_cpu < nr_cpu_ids) {
rcu_read_unlock();
return best_cpu;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - 여기까지 왔으면 sd에 소속되있지 않다. 상위 domain으로 간다.
+ */
}
}
rcu_read_unlock();
@@ -1974,17 +2232,35 @@ static int find_lowest_rq(struct task_struct *task)
* just give the caller *something* to work with from the compatible
* locations.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - domain에서 못찾았으면, lowest_mask에 current cpu가 있엇을 경우 그냥
+ * current cpu로 선택한다.
+ */
if (this_cpu != -1)
return this_cpu;
+/*
+ * IAMROOT, 2023.02.11:
+ * - lowest_mask에서 아무거나 고른다.
+ */
cpu = cpumask_any_distribute(lowest_mask);
if (cpu < nr_cpu_ids)
return cpu;
+/*
+ * IAMROOT, 2023.02.11:
+ * - lowest도 못찾앗다..
+ */
return -1;
}
/* Will lock the rq it finds */
+/*
+ * IAMROOT, 2023.02.11:
+ * - @task보다 우선순위가 낮은 lowest_rq를 찾는다.
+ * 찾아지면 double lock 건채로 lowest_rq return.
+ */
static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq)
{
struct rq *lowest_rq = NULL;
@@ -1994,6 +2270,10 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq)
for (tries = 0; tries < RT_MAX_TRIES; tries++) {
cpu = find_lowest_rq(task);
+/*
+ * IAMROOT, 2023.02.11:
+ * - 찾는데 실패했거나 rq cpu와 같으면 break.
+ */
if ((cpu == -1) || (cpu == rq->cpu))
break;
@@ -2005,6 +2285,15 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq)
* retrying does not release any lock and is unlikely
* to yield a different result.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * 대상 rq에는 우선 순위가 같거나 더 높은 작업이 있으며 재시도해도
+ * 잠금이 해제되지 않으며 다른 결과가 나올 가능성이 없습니다.
+.
+ * - lowest를 찾았는데 lowest가 @task보다 우선순위가 높은 상태.
+ * 그냥 빠져나간다.
+ */
lowest_rq = NULL;
break;
}
@@ -2017,18 +2306,37 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq)
* migrated already or had its affinity changed.
* Also make sure that it wasn't scheduled on its rq.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * 실행 대기열을 잠금 해제해야 했습니다. 그 동안 작업이 이미
+ * 마이그레이션되었거나 선호도가 변경되었을 수 있습니다.
+ * 또한 rq에서 예약되지 않았는지 확인하십시오.
+ *
+ * - double lock을 얻는 중에 경합이 발생됬다. 변동이 발생됬을수도
+ * 있는 상황이라 확인해야된다.
+ */
if (unlikely(task_rq(task) != rq ||
!cpumask_test_cpu(lowest_rq->cpu, &task->cpus_mask) ||
task_running(rq, task) ||
!rt_task(task) ||
!task_on_rq_queued(task))) {
-
+/*
+ * IAMROOT, 2023.02.11:
+ * - 바뀐 상황. break.
+ */
double_unlock_balance(rq, lowest_rq);
lowest_rq = NULL;
break;
}
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - 경합이 발생안했거나 경합이 발햇어도 조건에 맞는 상황.
+ * lock을 얻은 상태에서 다시한번 우선순위 비교를 해본다.
+ * task보다 낮은 우선순위가 찾아졌으면 break.
+ */
/* If this rq is still suitable use it. */
if (lowest_rq->rt.highest_prio.curr > task->prio)
break;
@@ -2041,6 +2349,10 @@ static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq)
return lowest_rq;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - pushable task를 한개 빼온다.
+ */
static struct task_struct *pick_next_pushable_task(struct rq *rq)
{
struct task_struct *p;
@@ -2066,20 +2378,47 @@ static struct task_struct *pick_next_pushable_task(struct rq *rq)
* running task can migrate over to a CPU that is running a task
* of lesser priority.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * 현재 CPU에 RT 작업이 두 개 이상 있는 경우 실행되지 않는 작업이
+ * 우선 순위가 낮은 작업을 실행 중인 CPU로 마이그레이션할 수 있는지
+ * 확인합니다.
+ * @pull push_rt_tasks에서는 fasle
+ */
static int push_rt_task(struct rq *rq, bool pull)
{
struct task_struct *next_task;
struct rq *lowest_rq;
int ret = 0;
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - overload가 안된경우(2개 미만의 task가 있는 경우) push
+ * 할 필요가 없다.
+ */
if (!rq->rt.overloaded)
return 0;
+/*
+ * IAMROOT, 2023.02.11:
+ * - push할 task를 한개 고른다.
+ */
next_task = pick_next_pushable_task(rq);
if (!next_task)
return 0;
+/*
+ * IAMROOT, 2023.02.11:
+ * - TODO
+ */
retry:
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - migrate가 안되는 tasdk들은
+ */
if (is_migration_disabled(next_task)) {
struct task_struct *push_task = NULL;
int cpu;
@@ -2087,6 +2426,10 @@ static int push_rt_task(struct rq *rq, bool pull)
if (!pull || rq->push_busy)
return 0;
+/*
+ * IAMROOT, 2023.02.11:
+ * - 아에 못찾았거나 rq의 cpu와 같은경우 return 0.
+ */
cpu = find_lowest_rq(rq->curr);
if (cpu == -1 || cpu == rq->cpu)
return 0;
@@ -2097,6 +2440,15 @@ static int push_rt_task(struct rq *rq, bool pull)
* to this other CPU, instead attempt to push the current
* running task on this CPU away.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * @next_task보다 우선 순위가 낮은 CPU를 찾았으므로 실행 중이어야 합니다.
+ * 그러나 이를 다른 CPU로 마이그레이션할 수는 없으며 대신 이 CPU에서
+ * 현재 실행 중인 작업을 밀어내려고 시도합니다.
+ *
+ * - @rq->curr가 push가 가능하면 stop을 시킨후 꺼낸다. (push_cpu_stop 실행)
+ */
push_task = get_push_task(rq);
if (push_task) {
raw_spin_rq_unlock(rq);
@@ -2108,6 +2460,10 @@ static int push_rt_task(struct rq *rq, bool pull)
return 0;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - TODO
+ */
if (WARN_ON(next_task == rq->curr))
return 0;
@@ -2172,6 +2528,10 @@ static int push_rt_task(struct rq *rq, bool pull)
return ret;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - TODO
+ */
static void push_rt_tasks(struct rq *rq)
{
/* push_rt_task will return true if it moved an RT */
@@ -2222,6 +2582,48 @@ static void push_rt_tasks(struct rq *rq)
* the rt_loop_next will cause the iterator to perform another scan.
*
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * 우선 순위가 높은 작업이 CPU에서 예약되고 우선 순위가 낮은 작업이
+ * 예약되면 우선 순위가 더 높은 RT 작업이 현재 CPU에서 실행 중이기
+ * 때문에 다른 CPU에서 실행 대기 중인 RT 작업이 있는지 확인합니다.
+ * 이 경우 여러 RT 작업이 대기열에 있는(오버로드된) CPU는 실행되지
+ * 않는 대기열에 있는 RT 작업 중 하나를 실행할 수 있는 CPU가 열렸음을
+ * 알려야 합니다.
+ *
+ * 과부하된 RT 작업이 있는 모든 CPU는 현재 실행 대기 중인 작업의 우선
+ * 순위가 가장 높은 CPU를 알 수 있는 방법이 없기 때문에 알림을 받아야
+ * 합니다. CPU가 많은 컴퓨터에서 수행할 때 대기 시간이 길어지는 것으로
+ * 나타난 이러한 각 CPU에서 스핀록을 시도하는 대신 CPU에 IPI를 보내
+ * 실행 대기 중인 과부하된 RT 작업을 푸시하도록 합니다.
+ *
+ * 각 CPU에 IPI를 보내는 것만으로도 문제가 됩니다. 많은 수의 CPU
+ * 머신에서와 같이 이것은 CPU에서 IPI 스톰을 유발할 수 있습니다.
+ * 우선 순위가 낮은 작업을 동시에 수행합니다.
+ *
+ * 각 루트 도메인에는 RT 과부하 작업으로 모든 CPU를 반복할 수 있는
+ * 자체 irq 작업 기능이 있습니다. 과부하된 RT 작업이 있는 모든 CPU는
+ * 우선 순위를 낮추는 CPU가 하나 이상 있는 경우 확인해야 하므로 실행
+ * 대기 중인 RT 작업을 푸시 오프하려고 시도하는 단일 irq 작업 반복기가
+ * 있습니다.
+ *
+ * CPU가 우선 순위가 낮은 작업을 예약하면 과부하된 RT 작업이 있는
+ * 각 CPU로 이동하는 irq 작업 반복자를 시작합니다.
+ * 우선 순위가 낮은 작업을 예약하는 첫 번째 CPU만 프로세스를 시작하기
+ * 때문에 rto_start 변수가 증가하고 원자 결과가 1인 경우 해당 CPU는
+ * rto_lock을 사용하려고 시도합니다.
+ * 이렇게 하면 프로세스가 우선 순위가 낮은 작업을 예약하는 모든
+ * CPU를 처리하므로 잠금에 대한 높은 경합이 방지됩니다.
+ *
+ * 우선 순위가 낮은 작업을 예약하는 모든 CPU는 rt_loop_next 변수를
+ * 증가시킵니다. 이렇게 하면 irq 작업 반복자가 CPU가 새로운 낮은 우선
+ * 순위 작업을 예약할 때마다 반복자가 스캔 중에 있더라도 모든 RT
+ * 오버로드 CPU를 확인합니다. rt_loop_next를 증가시키면 반복자가 다른
+ * 스캔을 수행하게 됩니다.
+ *
+ * - rto_mask중에서 그전(rto_cpu)의 next cpu를 고른다.
+ */
static int rto_next_cpu(struct root_domain *rd)
{
int next;
@@ -2240,9 +2642,34 @@ static int rto_next_cpu(struct root_domain *rd)
* the rto_lock held, but any CPU may increment the rto_loop_next
* without any locking.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * IPI RT 푸시를 시작할 때 rto_cpu는 -1로 설정되고 rt_next_cpu()는
+ * 단순히 rto_mask에서 발견된 첫 번째 CPU를 반환합니다.
+ *
+ * rto_next_cpu()가 rto_cpu가 유효한 CPU로 호출되면 rto_mask에서
+ * 발견된 다음 CPU를 반환합니다.
+ *
+ * rto_mask에 남아 있는 CPU가 더 이상 없으면 rto_loop 및
+ * rto_loop_next에 대해 확인합니다. rto_loop는 rto_lock이 유지된
+ * 상태에서만 업데이트되지만 모든 CPU는 잠금 없이 rto_loop_next를
+ * 증가시킬 수 있습니다.
+ */
for (;;) {
/* When rto_cpu is -1 this acts like cpumask_first() */
+/*
+ * IAMROOT, 2023.02.11:
+ * - -1부터 시작한다. rto_mask중에서 다음에 선택할 cpu를 정한다.
+ *
+ * - rto_cpu가 -1인 경우
+ * IPI RT push를 시작하였다. rto_mask에서 발견도니 첫번째 cpu로
+ * return될 것이다.
+ *
+ * - rto_cpu가 유효한 cpu번호 인경우
+ * rto_cpu의 다음 cpu로 정해진다.
+ */
cpu = cpumask_next(rd->rto_cpu, rd->rto_mask);
rd->rto_cpu = cpu;
@@ -2250,6 +2677,13 @@ static int rto_next_cpu(struct root_domain *rd)
if (cpu < nr_cpu_ids)
return cpu;
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - rto_cpu가 유효한 cpu번호 인경우에 대해서 만약 rto_mask에 더 이상
+ * 남아있는 cpu가 없으면 아래로 진입한다.
+ * rto_cpu를 다시 -1로 설정한다.
+ */
rd->rto_cpu = -1;
/*
@@ -2258,6 +2692,17 @@ static int rto_next_cpu(struct root_domain *rd)
*
* Matches WMB in rt_set_overload().
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * ACQUIRE는 @next 값이 관찰되기 전에 이루어진 @rto_mask 변경 사항을
+ * 확인하도록 합니다.
+ *
+ * rt_set_overload()에서 WMB와 일치합니다.
+ *
+ * - loop가 일어나면 rto_loop와 비교한다. 변경이 발생됬으면 갱신하고
+ * 다시 loop로 동작한다. 그게 아닌 경우 return -1
+ */
next = atomic_read_acquire(&rd->rto_loop_next);
if (rd->rto_loop == next)
@@ -2279,6 +2724,12 @@ static inline void rto_start_unlock(atomic_t *v)
atomic_set_release(v, 0);
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - IPI RT 푸시 상태인경우 cpu를 골라와서 해당 cpu에 ipi work on을 해준다.
+ * - pull 이 필요한 cpu가 overload된 cpu에 대해서 자신한테 push를 하라는
+ * ipi를 보내는 상황이다.
+ */
static void tell_cpu_to_push(struct rq *rq)
{
int cpu = -1;
@@ -2298,6 +2749,17 @@ static void tell_cpu_to_push(struct rq *rq)
* update to loop_next, and nothing needs to be done here.
* Otherwise it is finishing up and an ipi needs to be sent.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * rto_cpu는 잠금 상태에서 업데이트됩니다. 유효한 CPU가 있는 경우
+ * IPI는 여전히 실행 중이고 loop_next에 대한 업데이트로 인해 계속
+ * 실행되며 여기서 수행할 작업은 없습니다.
+ * 그렇지 않으면 완료되고 ipi를 보내야 합니다.
+ *
+ * - rto_cpu < 0 : *IPI RT 푸시를 시작한 상태. 이 경우
+ * cpu를 골라 온다.
+ */
if (rq->rd->rto_cpu < 0)
cpu = rto_next_cpu(rq->rd);
@@ -2305,6 +2767,12 @@ static void tell_cpu_to_push(struct rq *rq)
rto_start_unlock(&rq->rd->rto_loop_start);
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - 위에서 cpu가 골라졌으면 해당 cpu에 ipi work on을 해준다.
+ * ex) rto_push_irq_work_func
+ */
if (cpu >= 0) {
/* Make sure the rd does not get freed while pushing */
sched_get_rd(rq->rd);
@@ -2313,6 +2781,12 @@ static void tell_cpu_to_push(struct rq *rq)
}
/* Called from hardirq context */
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - @rq의 모든 pushable task를 push하고, 그 다음 cpu한테도
+ * (있을 경우) irq work on 요청을 한다.
+ */
void rto_push_irq_work_func(struct irq_work *work)
{
struct root_domain *rd =
@@ -2326,6 +2800,10 @@ void rto_push_irq_work_func(struct irq_work *work)
* We do not need to grab the lock to check for has_pushable_tasks.
* When it gets updated, a check is made if a push is possible.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - push task를 전부 push 한다.
+ */
if (has_pushable_tasks(rq)) {
raw_spin_rq_lock(rq);
while (push_rt_task(rq, true))
@@ -2336,6 +2814,10 @@ void rto_push_irq_work_func(struct irq_work *work)
raw_spin_lock(&rd->rto_lock);
/* Pass the IPI to the next rt overloaded queue */
+/*
+ * IAMROOT, 2023.02.11:
+ * - 다음 cpu한테도 push 작업을 하게 한다.
+ */
cpu = rto_next_cpu(rd);
raw_spin_unlock(&rd->rto_lock);
@@ -2350,6 +2832,10 @@ void rto_push_irq_work_func(struct irq_work *work)
}
#endif /* HAVE_RT_PUSH_IPI */
+/*
+ * IAMROOT, 2023.02.11:
+ * -
+ */
static void pull_rt_task(struct rq *this_rq)
{
int this_cpu = this_rq->cpu, cpu;
@@ -2368,6 +2854,11 @@ static void pull_rt_task(struct rq *this_rq)
smp_rmb();
/* If we are the only overloaded CPU do nothing */
+/*
+ * IAMROOT, 2023.02.11:
+ * - 현재 cpu에 overloaded 되있다면 return.
+ * 즉 자기가 overload를 시켜놓은 상태.
+ */
if (rt_overload_count == 1 &&
cpumask_test_cpu(this_rq->cpu, this_rq->rd->rto_mask))
return;
@@ -2655,7 +3146,11 @@ static inline void watchdog(struct rq *rq, struct task_struct *p) { }
*/
/*
* IAMROOT, 2023.02.10:
- * - ING. requeue_task_rt 할차례
+ * - 1. exec_runtime 및 rt_runtime 누적
+ * 2. rt_runtime 초과에 따른 reschedule 처리
+ * 3. load sun / avg update
+ * 4. runtime balance
+ * 5. SCHED_RR 처리.
*/
static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued)
{
@@ -2703,14 +3198,13 @@ static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued)
for_each_sched_rt_entity(rt_se) {
/*
* IAMROOT, 2023.02.10:
- * - prev != next 라면 유일한 task가 아니라는 의미.
- * task가 한개면 그것만 돌리면 되므로 task가 두개이상이여야
- * rescheule을 하는 의미가 있다.
+ * - prev != next 라면 유일한 rt entity가 아니라는 의미.
+ * 즉 같은 우선순위의 entity가 두개이상일때 reschedule을 한다.
*/
if (rt_se->run_list.prev != rt_se->run_list.next) {
/*
* IAMROOT, 2023.02.10:
- * - @p를 rq의 tail에 넣고 rescheduled 요청을 한다. 제일 뒤의 순서로
+ * - @p를 rt_rq의 tail에 넣고 rescheduled 요청을 한다. 제일 뒤의 순서로
* 옮기는 개념.
*/
requeue_task_rt(rq, p, 0);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index e855e4f571c9..0841d2248e1d 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -883,6 +883,11 @@ struct rt_rq {
#ifdef CONFIG_SMP
unsigned int rt_nr_migratory;
unsigned int rt_nr_total;
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - 두개 이상의 rt_task가 있는 경우 1.
+ */
int overloaded;
struct plist_head pushable_tasks;
@@ -1050,6 +1055,10 @@ struct perf_domain {
*/
struct root_domain {
atomic_t refcount;
+/*
+ * IAMROOT, 2023.02.11:
+ * - rt overloaded task 숫자
+ */
atomic_t rto_count;
struct rcu_head rcu;
/*
@@ -1096,6 +1105,10 @@ struct root_domain {
raw_spinlock_t rto_lock;
/* These are only updated and read within rto_lock */
int rto_loop;
+/*
+ * IAMROOT, 2023.02.11:
+ * - IPI RT 푸시를 시작할 때 rto_cpu는 -1로 설정된다.
+ */
int rto_cpu;
/* These atomics are updated outside of a lock */
atomic_t rto_loop_next;
@@ -1308,6 +1321,10 @@ struct rq {
struct sched_domain __rcu *sd;
unsigned long cpu_capacity;
+/*
+ * IAMROOT, 2023.02.11:
+ * - 현재 cpu성능.
+ */
unsigned long cpu_capacity_orig;
struct callback_head *balance_callback;
@@ -1454,6 +1471,10 @@ static inline int cpu_of(struct rq *rq)
#define MDF_PUSH 0x01
+/*
+ * IAMROOT, 2023.02.11:
+ * - migration이 안되는 task면 return true.
+ */
static inline bool is_migration_disabled(struct task_struct *p)
{
#ifdef CONFIG_SMP
@@ -1836,6 +1857,10 @@ static inline u64 rq_clock(struct rq *rq)
return rq->clock;
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - 현재시각
+ */
static inline u64 rq_clock_task(struct rq *rq)
{
lockdep_assert_rq_held(rq);
@@ -2075,6 +2100,12 @@ init_numa_balancing(unsigned long clone_flags, struct task_struct *p)
#ifdef CONFIG_SMP
+/*
+ * IAMROOT, 2023.02.11:
+ * - @func를 등록시켜준다.
+ * - @func : push_rt_tasks
+ * pull_rt_task
+ */
static inline void
queue_balance_callback(struct rq *rq,
struct callback_head *head,
@@ -2103,7 +2134,29 @@ queue_balance_callback(struct rq *rq,
*/
/*
* IAMROOT, 2022.09.03:
- * - tree 구조로 되있다. sched domain 위로 올라간다.
+ */
+/*
+ * IAMROOT, 2023.02.11:
+ * ----
+ * - schedule domain
+ * -- SMT : l1 cache 공유
+ * -- MC : l2 cache 공유
+ * -- DIE : l3 cache 공유
+ * -- NUMA : memory 공유 numa level 1, 2, 3, 4로 세분화되기도한다.
+ * ex) SMT : 0, 1, MC : 0, 1, 2, 3, DIE : 0, 1, 2, 3, 4, 5, 6, 7
+ * 이라고 가정.
+ * 0번 cpu기준으로 SMT의 1번이 가장 가깝고 그다음 MC의 2, 3이 가깝고
+ * 그다음 DIE의 4, 5, 6, 7이 가까울것이다.
+ * 이런 묶음으로 domain을 구성하여 가까운 cpu를 찾아가는 개념.
+ *
+ * -- 자기가 속한 domain은 span을 보고 금방 알아낸다.
+ *
+ * - schedule group
+ * -- cgroup의 group schedule과는 다른 개념.
+ * -- schedule domain의 아래 단계 개념
+ * ---
+ * - tree 구조로 되있다. sched domain 위로(SMT -> MC -> DIE -> NUMA)
+ * 올라간다.
*/
#define for_each_domain(cpu, __sd) \
for (__sd = rcu_dereference_check_sched_domain(cpu_rq(cpu)->sd); \
@@ -2692,6 +2745,11 @@ static inline void put_prev_task(struct rq *rq, struct task_struct *prev)
prev->sched_class->put_prev_task(rq, prev);
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - exec_start를 갱신하고 선택된 @p를 pushable에서 dequeue한다.
+ * ex) rt : set_next_task_rt()
+ */
static inline void set_next_task(struct rq *rq, struct task_struct *next)
{
next->sched_class->set_next_task(rq, next, false);
@@ -2770,18 +2828,35 @@ extern void trigger_load_balance(struct rq *rq);
extern void set_cpus_allowed_common(struct task_struct *p, const struct cpumask *new_mask, u32 flags);
+/*
+ * IAMROOT, 2023.02.11:
+ * - @rq->curr가 움직일수있는 상태인지 확인한다. 가능하면 ref를 얻고
+ * return task.
+ */
static inline struct task_struct *get_push_task(struct rq *rq)
{
struct task_struct *p = rq->curr;
lockdep_assert_rq_held(rq);
+/*
+ * IAMROOT, 2023.02.11:
+ * - 이미 누군가 push를 할려고한다.
+ */
if (rq->push_busy)
return NULL;
+/*
+ * IAMROOT, 2023.02.11:
+ * - 이 task은 허락된 cpu가 한개밖에 없어 이동을 못한다.
+ */
if (p->nr_cpus_allowed == 1)
return NULL;
+/*
+ * IAMROOT, 2023.02.11:
+ * - migrate disable
+ */
if (p->migration_disabled)
return NULL;
@@ -3049,6 +3124,19 @@ extern void double_rq_lock(struct rq *rq1, struct rq *rq2);
* reduces latency compared to the unfair variant below. However, it
* also adds more overhead and therefore may reduce throughput.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * fair double_lock_balance: 모든 호출에서 추가 원자적 작업을 강제하는
+ * 비용으로 공정한 방식으로 두 rq-> 잠금을 안전하게 획득합니다. 이렇게
+ * 하면 이 아키텍처에서 spinlock_t와 동일한 기본 정책을 사용하여
+ * double_lock을 획득할 수 있으므로 아래의 불공평한 변형에 비해 대기
+ * 시간이 줄어듭니다. 그러나 더 많은 오버헤드가 추가되므로 처리량이
+ * 줄어들 수 있습니다.
+ *
+ * - double lock을 얻는다. preempt은 무조건 경합한다.
+ * return 1.
+ */
static inline int _double_lock_balance(struct rq *this_rq, struct rq *busiest)
__releases(this_rq->lock)
__acquires(busiest->lock)
@@ -3068,6 +3156,17 @@ static inline int _double_lock_balance(struct rq *this_rq, struct rq *busiest)
* grant the double lock to lower CPUs over higher ids under contention,
* regardless of entry order into the function.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - papago
+ * Unfair double_lock_balance: 진입 시 잠금이 이미 적절한 순서로 되어
+ * 있는 경우 추가적인 원자적 작업을 제거하여 대기 시간을 희생하여
+ * 처리량을 최적화합니다. 이것은 더 낮은 CPU ID를 선호하며 함수에 대한
+ * 항목 순서에 관계없이 경합 중인 더 높은 ID보다 더 낮은 CPU에 이중
+ * 잠금을 부여합니다.
+ *
+ * - double lock을 얻는다. 경합없이 얻으면 return 0. 있으면 return 1.
+ */
static inline int _double_lock_balance(struct rq *this_rq, struct rq *busiest)
__releases(this_rq->lock)
__acquires(busiest->lock)
@@ -3095,6 +3194,11 @@ static inline int _double_lock_balance(struct rq *this_rq, struct rq *busiest)
/*
* double_lock_balance - lock the busiest runqueue, this_rq is locked already.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - double lock 획득.
+ * - double lock을 얻는다. 경합없이 얻으면 return 0. 있으면 return 1.
+ */
static inline int double_lock_balance(struct rq *this_rq, struct rq *busiest)
{
lockdep_assert_irqs_disabled();
diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c
index 905b40d6ad8c..1eea6dbc9c06 100644
--- a/kernel/sched/topology.c
+++ b/kernel/sched/topology.c
@@ -508,6 +508,10 @@ void rq_attach_root(struct rq *rq, struct root_domain *rd)
call_rcu(&old_rd->rcu, free_rootdomain);
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - ref up
+ */
void sched_get_rd(struct root_domain *rd)
{
atomic_inc(&rd->refcount);
@@ -667,6 +671,11 @@ DEFINE_PER_CPU(struct sched_domain_shared __rcu *, sd_llc_shared);
DEFINE_PER_CPU(struct sched_domain __rcu *, sd_numa);
DEFINE_PER_CPU(struct sched_domain __rcu *, sd_asym_packing);
DEFINE_PER_CPU(struct sched_domain __rcu *, sd_asym_cpucapacity);
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - HMP로 동작하는 경우.
+ */
DEFINE_STATIC_KEY_FALSE(sched_asym_cpucapacity);
static void update_top_cache_domain(int cpu)
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index 05ee3eaecb5f..e2d7720c17e5 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -75,12 +75,21 @@ static void cpu_stop_init_done(struct cpu_stop_done *done, unsigned int nr_todo)
}
/* signal completion unless @done is NULL */
+/*
+ * IAMROOT, 2023.02.11:
+ * - @done에 대해서 complete를 해준다.
+ */
static void cpu_stop_signal_done(struct cpu_stop_done *done)
{
if (atomic_dec_and_test(&done->nr_todo))
complete(&done->completion);
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - @work에 @stopper->works를 추가한다.
+ * @wakeq에 @stopper task를 추가한다.
+ */
static void __cpu_stop_queue_work(struct cpu_stopper *stopper,
struct cpu_stop_work *work,
struct wake_q_head *wakeq)
@@ -90,6 +99,11 @@ static void __cpu_stop_queue_work(struct cpu_stopper *stopper,
}
/* queue @work to @stopper. if offline, @work is completed immediately */
+/*
+ * IAMROOT, 2023.02.11:
+ * - stop queue work에 @work를 넣고 깨운다.
+ * 동작중인 task를 강제로 stop시키고 빼오기 위함이다
+ */
static bool cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work)
{
struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
@@ -100,12 +114,23 @@ static bool cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work)
preempt_disable();
raw_spin_lock_irqsave(&stopper->lock, flags);
enabled = stopper->enabled;
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - enable : queue work동작을 한다.,
+ * work->done : 기존 작업이 done인 상태. complete전송.
+ *
+ */
if (enabled)
__cpu_stop_queue_work(stopper, work, &wakeq);
else if (work->done)
cpu_stop_signal_done(work->done);
raw_spin_unlock_irqrestore(&stopper->lock, flags);
+/*
+ * IAMROOT, 2023.02.11:
+ * - stopper를 깨운다.
+ */
wake_up_q(&wakeq);
preempt_enable();
@@ -381,6 +406,10 @@ int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *
* true if cpu_stop_work was queued successfully and @fn will be called,
* false otherwise.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - stopper는 cpu_stopper_thread함수를 통해서 work의 @fn을 호출할것이다.
+ */
bool stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
struct cpu_stop_work *work_buf)
{
@@ -539,8 +568,7 @@ extern void sched_set_stop_task(int cpu, struct task_struct *stop);
static void cpu_stop_create(unsigned int cpu)
{
- sched_set_stop_task(cpu, per_cpu(cpu_stopper.thread, cpu));
-}
+ sched_set_stop_task(cpu, per_cpu(cpu_stopper.thread, cpu)); }
static void cpu_stop_park(unsigned int cpu)
{
@@ -549,6 +577,10 @@ static void cpu_stop_park(unsigned int cpu)
WARN_ON(!list_empty(&stopper->works));
}
+/*
+ * IAMROOT, 2023.02.11:
+ * - @cpu에 대한 stopper를 enable하고 thread를 unpark한다.
+ */
void stop_machine_unpark(int cpu)
{
struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
@@ -567,6 +599,14 @@ static struct smp_hotplug_thread cpu_stop_threads = {
.selfparking = true,
};
+/*
+ * IAMROOT, 2023.02.11:
+ * - cpu_stopper 초기화. smpboot_register_percpu_thread()함수에서
+ * thread가 만들어지고, stopper실행시 cpu_stopper_thread()을 통해
+ * cpu_stop_work에 등록되는 fn들이 호출될것이다.
+ * - ps -ef를 통해서 migration/X가 항상 있는게 확인된다.
+ * - stopper thread는 deadline보다도 높은 우선순위를 가진다.
+ */
static int __init cpu_stop_init(void)
{
unsigned int cpu;
diff --git a/lib/cpumask.c b/lib/cpumask.c
index a0434997fd0e..134a1ad9a650 100644
--- a/lib/cpumask.c
+++ b/lib/cpumask.c
@@ -260,18 +260,35 @@ static DEFINE_PER_CPU(int, distribute_cpu_mask_prev);
*
* Returns >= nr_cpu_ids if the intersection is empty.
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - 이전에 사용한 cpu의 next번호를 @src1p, @src2p의 and에서 찾는다.
+ */
int cpumask_any_and_distribute(const struct cpumask *src1p,
const struct cpumask *src2p)
{
int next, prev;
/* NOTE: our first selection will skip 0. */
+/*
+ * IAMROOT, 2023.02.11:
+ * - 이전에 선택한 cpu의 next를 src1p, src2p가 겹치는 것중에서 고른다.
+ */
prev = __this_cpu_read(distribute_cpu_mask_prev);
next = cpumask_next_and(prev, src1p, src2p);
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - 못찾앗으면 그냥 겹치는것중에 처음것을 고른다.
+ */
if (next >= nr_cpu_ids)
next = cpumask_first_and(src1p, src2p);
+/*
+ * IAMROOT, 2023.02.11:
+ * - 찾앗으면 prev로 기록한다.
+ */
if (next < nr_cpu_ids)
__this_cpu_write(distribute_cpu_mask_prev, next);
diff --git a/lib/plist.c b/lib/plist.c
index 0d86ed7a76ac..f18ec2c50402 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -109,11 +109,28 @@ void plist_add(struct plist_node *node, struct plist_head *head)
* @node: &struct plist_node pointer - entry to be removed
* @head: &struct plist_head pointer - list head
*/
+/*
+ * IAMROOT, 2023.02.11:
+ * - plist(priority list)
+ * 우선순위가 동일한것을 생략한 list한개와, 모두 포함되있는 list 한개가
+ * 있는 개념의 list.
+ * - node_list, prio_list에서 각각 한개씩 지운다.
+ * 단 prio_list에서 삭제함으로써 비워지게 되면 다음 node를 추가한다.
+ */
void plist_del(struct plist_node *node, struct plist_head *head)
{
plist_check_head(head);
+/*
+ * IAMROOT, 2023.02.11:
+ * - node단위의 prio_list 에서
+ */
if (!list_empty(&node->prio_list)) {
+
+/*
+ * IAMROOT, 2023.02.11:
+ * - 2개 이상인 경우에 next가 empty인 경우 prio_list 한개를 next에 옮긴다.
+ */
if (node->node_list.next != &head->node_list) {
struct plist_node *next;
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
공지 | [공지] 스터디 정리 노트 공간입니다. | woos | 2016.05.14 | 629 |
188 | [커널 19차] 43, 44 주차 | 이태백 | 2023.03.26 | 184 |
187 | [커널 18차] 95주차 | kkr | 2023.03.20 | 123 |
186 | [커널 19차] 41 주차 | 이태백 | 2023.03.04 | 101 |
185 | [커널 18차] 93주차 | kkr | 2023.03.04 | 54 |
184 | [커널 18차] 91주차 | kkr | 2023.02.18 | 98 |
183 | [커널 19차] 39 주차 | Min | 2023.02.18 | 53 |
» | [커널 18차] 90주차 | kkr | 2023.02.13 | 63 |
181 | [커널 19차] 38 주차 | Min | 2023.02.11 | 45 |
180 | [커널 19차] 37 주차 | Min | 2023.02.04 | 479 |
179 | [커널 19차] 36 주차 | Min | 2023.01.28 | 85 |
178 | [커널 18차] 88주차 | kkr | 2023.01.28 | 55 |
177 | [커널 19차] 35 주차 | Min | 2023.01.14 | 93 |
176 | [커널 17차] 120 ~ 121주차 | ㅇㅇㅇ | 2023.01.08 | 111 |
175 | [커널 18차] 85주차 | kkr | 2023.01.07 | 53 |
174 | [커널 19차] 34 주차 | Min | 2023.01.07 | 42 |
173 | [커널 18차] 84주차 | kkr | 2022.12.31 | 104 |
172 | [커널 19차] 33 주차 | Min | 2022.12.31 | 51 |
171 | [커널 17차] 117 ~ 119주차 | ㅇㅇㅇ | 2022.12.25 | 63 |
170 | [커널 19차] 31 주차 | Min | 2022.12.17 | 63 |
169 | [커널 19차] 30 주차 | Min | 2022.12.10 | 61 |
.