[커널 18차] 80주차
2022.12.03 22:22
periodic tick 진행
git : https://github.com/iamroot18/5.10/commit/db584c473c5b37e2e74fc3e0b927e9299e94483a
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 27a4e3e69e12..4dc971ea1479 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -45,6 +45,10 @@ enum clock_event_state {
*/
# define CLOCK_EVT_FEAT_PERIODIC 0x000001
# define CLOCK_EVT_FEAT_ONESHOT 0x000002
+/*
+ * IAMROOT, 2022.12.03:
+ * - ktime_t로 설정이 가능하다는것.
+ */
# define CLOCK_EVT_FEAT_KTIME 0x000004
/*
@@ -53,6 +57,11 @@ enum clock_event_state {
* - Clockevent source stops in C3 State and needs broadcast support.
* - Local APIC timer is used as a dummy device.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - C3
+ * clock 절전기능. 전원은 끄지 않고 clock만 멈추는 기능.
+ */
# define CLOCK_EVT_FEAT_C3STOP 0x000008
# define CLOCK_EVT_FEAT_DUMMY 0x000010
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 5ce4c3706d18..5b3ca379a006 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -150,6 +150,10 @@ struct clocksource {
#define CLOCK_SOURCE_MUST_VERIFY 0x02
#define CLOCK_SOURCE_WATCHDOG 0x10
+/*
+ * IAMROOT, 2022.12.03:
+ * - HIGH Resolution timer
+ */
#define CLOCK_SOURCE_VALID_FOR_HRES 0x20
#define CLOCK_SOURCE_UNSTABLE 0x40
#define CLOCK_SOURCE_SUSPEND_NONSTOP 0x80
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 575be407c243..72ab73abd8a4 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -270,6 +270,10 @@ struct hrtimer_cpu_base {
struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES];
} ____cacheline_aligned;
+/*
+ * IAMROOT, 2022.12.03:
+ * - @timer에 @time을 set한다.
+ */
static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time)
{
timer->node.expires = time;
@@ -549,6 +553,10 @@ hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval);
* Note: This only updates the timer expiry value and does not requeue
* the timer.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - 현재 시각을 기준으로 interval후에 expire된다.
+ */
static inline u64 hrtimer_forward_now(struct hrtimer *timer,
ktime_t interval)
{
diff --git a/include/linux/prandom.h b/include/linux/prandom.h
index 056d31317e49..6de0da0816f9 100644
--- a/include/linux/prandom.h
+++ b/include/linux/prandom.h
@@ -18,6 +18,10 @@ void prandom_reseed_late(void);
DECLARE_PER_CPU(unsigned long, net_rand_noise);
+/*
+ * IAMROOT, 2022.12.03:
+ * -
+ */
#define PRANDOM_ADD_NOISE(a, b, c, d) \
prandom_u32_add_noise((unsigned long)(a), (unsigned long)(b), \
(unsigned long)(c), (unsigned long)(d))
@@ -56,6 +60,10 @@ DECLARE_PER_CPU(unsigned long, net_rand_noise);
#error Unsupported BITS_PER_LONG
#endif
+/*
+ * IAMROOT, 2022.12.03:
+ * - 인자를 가지고 pcpu net_rand_noise에 랜덤값을 구해놓는다.
+ */
static inline void prandom_u32_add_noise(unsigned long a, unsigned long b,
unsigned long c, unsigned long d)
{
diff --git a/include/linux/sched/loadavg.h b/include/linux/sched/loadavg.h
index 9f2a2b4cdc0c..5d8b54854d4f 100644
--- a/include/linux/sched/loadavg.h
+++ b/include/linux/sched/loadavg.h
@@ -16,12 +16,32 @@ extern unsigned long avenrun[]; /* Load averages */
extern void get_avenrun(unsigned long *loads, unsigned long offset, int shift);
#define FSHIFT 11 /* nr of bits of precision */
+/*
+ * IAMROOT, 2022.12.03:
+ * - 이진화정수화한 정밀도. 2^11 = 2048
+ */
#define FIXED_1 (1<<FSHIFT) /* 1.0 as fixed-point */
/*
* IAMROOT, 2022.11.26:
* - 5초지난후 다음 tick.
*/
#define LOAD_FREQ (5*HZ+1) /* 5 sec intervals */
+/*
+ * IAMROOT, 2022.12.03:
+ * - e = 2.718281828459045...
+ *
+ * - new값을 old대비 몇 % 비율을 넣느냐를 이진화정수화 해서 결정한다.
+ * EXP_1 : 1분은 약 92%
+ * EXP_5 : 5분은 약 98.35%
+ * EXP_15 : 15분은 약 99.45%
+ * 이값을 100%를 2048로 이진화정수화 하여 계산한다.
+ *
+ * - e^(-1/12) = 0.9200..
+ * 이값에 이진화정수 정밀도 적용
+ * 0.9200 * 2048 = 1884
+ * - e^(-1/60) =
+ * - e^(-1/180)
+ */
#define EXP_1 1884 /* 1/exp(5sec/1min) as fixed-point */
#define EXP_5 2014 /* 1/exp(5sec/5min) */
#define EXP_15 2037 /* 1/exp(5sec/15min) */
@@ -29,15 +49,50 @@ extern void get_avenrun(unsigned long *loads, unsigned long offset, int shift);
/*
* a1 = a0 * e + a * (1 - e)
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - ex) task1개 만큼 증가한 case.
+ * load = 1024, exp = 1884, active = 2048
+ * newload = 1024 * 1884 + 2048 * (2048 - 1884)
+ * = 2,265,088
+ * return = (2,265,088 + 2047)/ 2048
+ * = 1106
+ * - ex) task가 안돌때 감소한 case.
+ * load = 1024, exp = 1884, active = 0
+ * newload = 1024 * 1884 + 0 * (2048 - 1884)
+ * = 1,929,216
+ * return = 1,929,216 / 2048
+ * = 942
+ */
static inline unsigned long
calc_load(unsigned long load, unsigned long exp, unsigned long active)
{
unsigned long newload;
+/*
+ * IAMROOT, 2022.12.03:
+ * - old * k + new * ( 1 - k)
+ */
newload = load * exp + active * (FIXED_1 - exp);
+/*
+ * IAMROOT, 2022.12.03:
+ * - new값이 old보다 크거나 같으면 2048 - 1을 더해준다.
+ * new값이 클경우 올림처리.
+ * - 글로벌 cpu 로드를 처리하는데 장시간 idle 상태인데에도 각 주기별로 0.00, 0.01, 0.05 이하 값이 더 이상 하강하지 않는 버그가 있어 수정하였다.
+ * - 참고)
+ * https://github.com/torvalds/linux/commit/20878232c52329f92423d27a60e48b6a6389e0dd#diff-3a8f0c7004315fef3f3985bfd1945858*
+ */
if (active >= load)
newload += FIXED_1-1;
+/*
+ * IAMROOT, 2022.12.03:
+ * - 100 -> * 10 -> 1000
+ * 50 * 10 -> 500
+ * 20 * 10 -> 200
+ *
+ * 700 / 10 = 70
+ */
return newload / FIXED_1;
}
diff --git a/kernel/irq_work.c b/kernel/irq_work.c
index db8c248ebc8c..d6165f8cdf95 100644
--- a/kernel/irq_work.c
+++ b/kernel/irq_work.c
@@ -162,6 +162,10 @@ void irq_work_single(void *arg)
(void)atomic_cmpxchg(&work->node.a_flags, flags, flags & ~IRQ_WORK_BUSY);
}
+/*
+ * IAMROOT, 2022.12.03:
+ * - @list에 있는걸 즉시 수행한다.
+ */
static void irq_work_run_list(struct llist_head *list)
{
struct irq_work *work, *tmp;
@@ -188,12 +192,27 @@ void irq_work_run(void)
}
EXPORT_SYMBOL_GPL(irq_work_run);
+/*
+ * IAMROOT, 2022.12.03:
+ * - irq 내부일경우 irq tick수행.
+ * arm64의 경우 lazy만 여기서 수행한다.
+ */
void irq_work_tick(void)
{
struct llist_head *raised = this_cpu_ptr(&raised_list);
+/*
+ * IAMROOT, 2022.12.03:
+ * - 조건에 맞으면 이 로직에서 즉시 수행한다.
+ * arm64는 arch_irq_work_has_interrupt가 true이므로 수행된진않는다.
+ */
if (!llist_empty(raised) && !arch_irq_work_has_interrupt())
irq_work_run_list(raised);
+
+/*
+ * IAMROOT, 2022.12.03:
+ * - lazy_list에 있는것만 호출한다.
+ */
irq_work_run_list(this_cpu_ptr(&lazy_list));
}
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index bfdd5e7307ca..a95e7b288778 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5276,6 +5276,10 @@ static inline u64 cpu_resched_latency(struct rq *rq) { return 0; }
* This function gets called by the timer code, with HZ frequency.
* We call it with interrupts disabled.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - TODO
+ */
void scheduler_tick(void)
{
int cpu = smp_processor_id();
@@ -5293,6 +5297,10 @@ void scheduler_tick(void)
update_rq_clock(rq);
thermal_pressure = arch_scale_thermal_pressure(cpu_of(rq));
update_thermal_load_avg(rq_clock_thermal(rq), rq, thermal_pressure);
+/*
+ * IAMROOT, 2022.12.03:
+ * - 현재 진행중인 current task의 scheduler한테 tick공급.
+ */
curr->sched_class->task_tick(rq, curr, 0);
if (sched_feat(LATENCY_WARN))
resched_latency = cpu_resched_latency(rq);
diff --git a/kernel/sched/loadavg.c b/kernel/sched/loadavg.c
index 954b229868d9..7723e73a4dc3 100644
--- a/kernel/sched/loadavg.c
+++ b/kernel/sched/loadavg.c
@@ -57,6 +57,11 @@
/* Variables and functions for calc_load */
atomic_long_t calc_load_tasks;
+
+/*
+ * IAMROOT, 2022.12.03:
+ * - calc_global_load에서 load를 계산해야될 시각.(jiffies)
+ */
unsigned long calc_load_update;
unsigned long avenrun[3];
EXPORT_SYMBOL(avenrun); /* should be removed */
@@ -76,6 +81,10 @@ void get_avenrun(unsigned long *loads, unsigned long offset, int shift)
loads[2] = (avenrun[2] + offset) << shift;
}
+/*
+ * IAMROOT, 2022.12.03:
+ * - running + uninterruptible의 변화된값을 return한다.
+ */
long calc_load_fold_active(struct rq *this_rq, long adjust)
{
long nr_active, delta = 0;
@@ -106,6 +115,10 @@ long calc_load_fold_active(struct rq *this_rq, long adjust)
* of course trivially computable in O(log_2 n), the length of our binary
* vector.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - e^N의 이진화정수 계산.
+ */
static unsigned long
fixed_power_int(unsigned long x, unsigned int frac_bits, unsigned int n)
{
@@ -153,6 +166,17 @@ fixed_power_int(unsigned long x, unsigned int frac_bits, unsigned int n)
* S_n := \Sum x^i = -------------
* i=0 1 - x
*/
+
+/*
+ * IAMROOT, 2022.12.03:
+ * n = 1 ) x1 = old * e + new * (1 - e)
+ * n = 2 ) x2 = x1 * e + new * (1 - e)
+ * n = 3 ) x3 = x2 * e + new * (1 - e)
+ *
+ * n = N ) x1 = old * e^(N) + new * (1 - e^(N))
+ *
+ * - old * e^n + new * (1 - e^n)
+ */
unsigned long
calc_load_n(unsigned long load, unsigned long exp,
unsigned long active, unsigned int n)
@@ -203,9 +227,33 @@ calc_load_n(unsigned long load, unsigned long exp,
*
* When making the ILB scale, we should try to pull this in as well.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - 이전 task개수(running + uninterruptible)와 현재 task개수의 변화값.
+ * 사용되면 0으로 초기화된다.
+ */
static atomic_long_t calc_load_nohz[2];
+
+/*
+ * IAMROOT, 2022.12.03:
+ * - calc_load_nohz의 lock
+ */
static int calc_load_idx;
+/*
+ * IAMROOT, 2022.12.03:
+ * 0s 5s 10s 15s
+ * +10 +10 +10 +10
+ * |-|-----------|-|-----------|-|-----------|-|
+ * r:0 0 1 1 0 0 1 1 0
+ * w:0 1 1 0 0 1 1 0 0
+ * ^ ^ ^ ^
+ * calc_load_idx 0 1 2 3 4
+ *
+ * - idx == 0 이였던경우 reader는 idx == 0을 계속 읽을것이고
+ * writer는 idx = 1에 write를한다. write를 다했으면 idx++ 하여
+ * reader가 완전히 write된 idx = 1에 접근할수있게 할것이다.
+ */
static inline int calc_load_write_idx(void)
{
int idx = calc_load_idx;
@@ -226,11 +274,19 @@ static inline int calc_load_write_idx(void)
return idx & 1;
}
+/*
+ * IAMROOT, 2022.12.03:
+ * - calc_global_nohz()에 의해 증가된 calc_load_idx의 홀/짝여부를 가져온다.
+ */
static inline int calc_load_read_idx(void)
{
return calc_load_idx & 1;
}
+/*
+ * IAMROOT, 2022.12.03:
+ * - task개수 변동이 생겼으면 변동값을 calc_load_nohz에 저장한다.
+ */
static void calc_load_nohz_fold(struct rq *rq)
{
long delta;
@@ -243,6 +299,11 @@ static void calc_load_nohz_fold(struct rq *rq)
}
}
+/*
+ * IAMROOT, 2022.12.03:
+ * - nohz가 시작될시 진입한다.
+ * task개수 변화를 감지하여 calc_load_nohz에 갱신한다.
+ */
void calc_load_nohz_start(void)
{
/*
@@ -281,11 +342,23 @@ void calc_load_nohz_stop(void)
this_rq->calc_load_update += LOAD_FREQ;
}
+/*
+ * IAMROOT, 2022.12.03:
+ * - calc_load_idx의 홀짝에 따른 delta값을 가져온다. 없다면 return 0.
+ */
static long calc_load_nohz_read(void)
{
+/*
+ * IAMROOT, 2022.12.03:
+ * - idx는 0 or 1
+ */
int idx = calc_load_read_idx();
long delta = 0;
+/*
+ * IAMROOT, 2022.12.03:
+ * - read를 해서 0이 아니라면 어떤 값(delta)이 있다는것. 0와 xchg를 하여 가져와서 return한다.
+ */
if (atomic_long_read(&calc_load_nohz[idx]))
delta = atomic_long_xchg(&calc_load_nohz[idx], 0);
@@ -301,11 +374,38 @@ static long calc_load_nohz_read(void)
* Once we've updated the global active value, we need to apply the exponential
* weights adjusted to the number of cycles missed.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - papago
+ * NO_HZ는 calc_load_fold_active()를 호출하는 모든 CPU당 틱을 놓치게 할 수 있지만,
+ * NO_HZ CPU는 calc_load_nohz_start()마다 델타를 calc_load_nohz로 접기 때문에 NO_HZ 기간이
+ * 로드 사이클을 넘으면 보류 중인 NO_HZ 델타를 접기만 하면 됩니다. 경계.
+ *
+ * 전역 활성 값을 업데이트한 후에는 놓친 주기 수에 맞게 조정된 지수 가중치를 적용해야
+ * 합니다.
+ *
+ * - nohz구간이 존재한다면 해당구간의 시간을 보정해준다.
+ * - calc_load_idx를 증가시켜 write가 완료됫음을 알린다.
+ */
static void calc_global_nohz(void)
{
unsigned long sample_window;
long delta, active, n;
+/*
+ * IAMROOT, 2022.12.03:
+ * - calc_global_load()에서 이함수를 진입한경우 calc_global_load가 old에서 LOAD_FREQ만큼
+ * 증가됫을것이다. 증가 됬음에도 불구하고 현재시간 + 10보다 이전이라면 calc_load를 다시
+ * 수행한다.
+ * - 결국 sleep으로 인해서 고려가 안된 시간만큼 n회를 더 수행하기 위함
+ *
+ * - ex)
+ * | sleep | sleep | wakeup |
+ * ^last갱신 ^new갱신
+ * ^miss ^miss
+ * miss가 2번 발생했다.
+ * new갱신은 calc_global_load()에서 했지만 2번을 못해줬다. 2번에 대해서 여기서 처리한다.
+ */
sample_window = READ_ONCE(calc_load_update);
if (!time_before(jiffies, sample_window + 10)) {
/*
@@ -317,6 +417,10 @@ static void calc_global_nohz(void)
active = atomic_long_read(&calc_load_tasks);
active = active > 0 ? active * FIXED_1 : 0;
+/*
+ * IAMROOT, 2022.12.03:
+ * - n회를 구하여 n만큼 load를 구한다.
+ */
avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n);
avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n);
avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n);
@@ -331,6 +435,13 @@ static void calc_global_nohz(void)
* calc_load_write_idx() will see the new time when it reads the new
* index, this avoids a double flip messing things up.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - papago
+ * NO_HZ 인덱스 뒤집기...
+ * 먼저 새 시간을 쓴 다음 색인을 뒤집어 calc_load_write_idx()가 새 색인을 읽을 때 새 시간을
+ * 볼 수 있도록 해야 합니다. 이렇게 하면 이중 뒤집기가 일을 망치는 것을 방지할 수 있습니다.
+ */
smp_wmb();
calc_load_idx++;
}
@@ -347,11 +458,22 @@ static inline void calc_global_nohz(void) { }
*
* Called from the global timer code.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - sample_window이후의 시간(5초마다)일때 avenrun, load를 갱신한다.
+ * 또한 nohz 구간이 있었을경우 해당 구간을 고려한다.
+ */
void calc_global_load(void)
{
unsigned long sample_window;
long active, delta;
+/*
+ * IAMROOT, 2022.12.03:
+ * - sample_window + 10 전이라면 return.
+ * - 10의 의미.
+ * task들이 동작을할때 calc_load_tasks를 갱신해줘야되는데 이 시간을 조금 고려한거 같다.
+ */
sample_window = READ_ONCE(calc_load_update);
if (time_before(jiffies, sample_window + 10))
return;
@@ -360,16 +482,41 @@ void calc_global_load(void)
* Fold the 'old' NO_HZ-delta to include all NO_HZ CPUs.
*/
delta = calc_load_nohz_read();
+/*
+ * IAMROOT, 2022.12.03:
+ * - nohz때 계산된 delta값을 calc_load_tasks에 더해준다.
+ */
if (delta)
atomic_long_add(delta, &calc_load_tasks);
+/*
+ * IAMROOT, 2022.12.03:
+ * - active는 task숫자라고 생각하면된다.
+ */
active = atomic_long_read(&calc_load_tasks);
+
+/*
+ * IAMROOT, 2022.12.03:
+ * - active * 2048
+ */
active = active > 0 ? active * FIXED_1 : 0;
+/*
+ * IAMROOT, 2022.12.03:
+ * - /proc/loadavg
+ * ex) 1.33 0.63 0.40 1/712 40301
+ * ^0 ^1 ^2
+ * 1분 5분 15분
+ */
avenrun[0] = calc_load(avenrun[0], EXP_1, active);
avenrun[1] = calc_load(avenrun[1], EXP_5, active);
avenrun[2] = calc_load(avenrun[2], EXP_15, active);
+/*
+ * IAMROOT, 2022.12.03:
+ * - 이전 update시각 + LOAD_FREQ(5초 + 1tck)이후로 next update시각을 정한다.
+ * 최종적으로 next update시각은 sample_window + LOAD_FREQ + 10tick이 될것이다.
+ */
WRITE_ONCE(calc_load_update, sample_window + LOAD_FREQ);
/*
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 9ca6673d3eef..2c2ee32f540e 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1123,6 +1123,11 @@ struct rq {
/* calc_load related fields */
unsigned long calc_load_update;
+
+/*
+ * IAMROOT, 2022.12.03:
+ * - runing + nr_uninterruptible. calc_load_fold_active() 참고
+ */
long calc_load_active;
#ifdef CONFIG_SCHED_HRTICK
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 61eb67d4fd16..561503f35243 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -135,6 +135,10 @@ u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
}
EXPORT_SYMBOL_GPL(clockevent_delta2ns);
+/*
+ * IAMROOT, 2022.12.03:
+ * - @state에따라 필요한 callback 함수를 실행한다.
+ */
static int __clockevents_switch_state(struct clock_event_device *dev,
enum clock_event_state state)
{
@@ -191,6 +195,10 @@ static int __clockevents_switch_state(struct clock_event_device *dev,
*
* Must be called with interrupts disabled !
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - @state에 따른 callback을 수행하고 @dev의 state을 @state로 변경한다.
+ */
void clockevents_switch_state(struct clock_event_device *dev,
enum clock_event_state state)
{
@@ -316,12 +324,22 @@ static int clockevents_program_min_delta(struct clock_event_device *dev)
*
* Returns 0 on success, -ETIME when the retry loop failed.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - @set_next_event callback을 실행한다.
+ */
static int clockevents_program_min_delta(struct clock_event_device *dev)
{
unsigned long long clc;
int64_t delta = 0;
int i;
+/*
+ * IAMROOT, 2022.12.03:
+ * - retry 10.
+ * programming이 불가능할 정도로 term이 짧은경우가 있을수있기 때문에 조금씩 늘려서
+ * 재시도를 한다. 즉 최대 min_delta_ns * 10이후에 실행될수도 있게 된다.
+ */
for (i = 0; i < 10; i++) {
delta += dev->min_delta_ns;
dev->next_event = ktime_add_ns(ktime_get(), delta);
@@ -330,6 +348,10 @@ static int clockevents_program_min_delta(struct clock_event_device *dev)
return 0;
dev->retries++;
+/*
+ * IAMROOT, 2022.12.03:
+ * - mult shift로 ns -> cycle화 한다.
+ */
clc = ((unsigned long long) delta * dev->mult) >> dev->shift;
if (dev->set_next_event((unsigned long) clc, dev) == 0)
return 0;
@@ -347,6 +369,10 @@ static int clockevents_program_min_delta(struct clock_event_device *dev)
*
* Returns 0 on success, -ETIME when the event is in the past.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - exipires시간으로 program한다.
+ */
int clockevents_program_event(struct clock_event_device *dev, ktime_t expires,
bool force)
{
@@ -367,19 +393,42 @@ int clockevents_program_event(struct clock_event_device *dev, ktime_t expires,
clockevent_get_state(dev));
/* Shortcut for clockevent devices that can deal with ktime. */
+/*
+ * IAMROOT, 2022.12.03:
+ * - ktime으로 timer로 설정이가능한경우.
+ */
if (dev->features & CLOCK_EVT_FEAT_KTIME)
return dev->set_next_ktime(expires, dev);
delta = ktime_to_ns(ktime_sub(expires, ktime_get()));
+/*
+ * IAMROOT, 2022.12.03:
+ * - 이전시간이면 force가 있는경우에 한해서만 시도한다.
+ */
if (delta <= 0)
return force ? clockevents_program_min_delta(dev) : -ETIME;
+/*
+ * IAMROOT, 2022.12.03:
+ * - 요청한 expires값을 clamp하여 program을 시도한다.
+ */
delta = min(delta, (int64_t) dev->max_delta_ns);
delta = max(delta, (int64_t) dev->min_delta_ns);
clc = ((unsigned long long) delta * dev->mult) >> dev->shift;
+
+/*
+ * IAMROOT, 2022.12.03:
+ * - prgram 시도.
+ */
rc = dev->set_next_event((unsigned long) clc, dev);
+/*
+ * IAMROOT, 2022.12.03:
+ * - rc != 0 실패.
+ * force가 있다면 가능한한 시도해야되므로 clockevents_program_min_delta()를 수행한다.
+ * 그게 아니거나(rc == 0) 성공했으면 return rc.
+ */
return (rc && force) ? clockevents_program_min_delta(dev) : rc;
}
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index ba19d7aaa26a..08cad711bf91 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -946,6 +946,10 @@ static void retrigger_next_event(void *arg);
/*
* Switch to high resolution mode
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - hrtimer로 전환.
+ */
static void hrtimer_switch_to_hres(void)
{
struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases);
@@ -955,6 +959,11 @@ static void hrtimer_switch_to_hres(void)
base->cpu);
return;
}
+
+/*
+ * IAMROOT, 2022.12.03:
+ * - hrtimer로 설정에 성공.
+ */
base->hres_active = 1;
hrtimer_resolution = HIGH_RES_NSEC;
@@ -982,6 +991,19 @@ static inline void hrtimer_switch_to_hres(void) { }
* are optimized out it vanishes as well, i.e. no need for lots of
* #ifdeffery.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - papago
+ * Retrigger 다음 이벤트는 SMP 함수 호출을 통해 또는 낮은 수준의 재개
+ * 코드에서 직접 인터럽트가 비활성화된 상태에서 시계가 설정된 후 호출됩니다.
+ *
+ * 다음과 같은 경우에만 호출됩니다.
+ * - CONFIG_HIGH_RES_TIMERS가 활성화되었습니다.
+ * - CONFIG_NOHZ_COMMON이 활성화됨
+ *
+ * 다른 경우에는 이 함수가 비어 있고 호출 사이트가 최적화되었기 때문에
+ * 사라집니다. 즉, 많은 #ifdeffery가 필요하지 않습니다.
+ */
static void retrigger_next_event(void *arg)
{
struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases);
@@ -1000,6 +1022,21 @@ static void retrigger_next_event(void *arg)
* function call will take care of the reprogramming in case the
* CPU was in a NOHZ idle sleep.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - papago
+ * 고해상도 모드 또는 nohz가 활성화되면 CLOCK_REALTIME/TAI/BOOTTIME의
+ * 오프셋을 업데이트해야 합니다. 그렇지 않으면 다음 틱이 처리합니다.
+ *
+ * 고해상도 모드가 활성화되면 다음 만료 타이머를 재평가해야 하며
+ * 필요한 경우 클록 이벤트 장치를 다시 프로그래밍해야 합니다.
+ *
+ * NOHZ의 경우 오프셋 업데이트 및 다음 만료 타이머의 재평가로 충분합니다.
+ * SMP 함수 호출로부터의 반환은 CPU가 NOHZ 유휴 수면 상태인 경우 재프로그래밍을 처리합니다.
+ *
+ * - hres mode active or nohz active가 되면 clock의 offset을 update 및
+ * reprogram을 한다.
+ */
if (!__hrtimer_hres_active(base) && !tick_nohz_active)
return;
@@ -2500,6 +2537,13 @@ static __latent_entropy void hrtimer_run_softirq(struct softirq_action *h)
* High resolution timer interrupt
* Called with interrupts disabled
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - schedule tick
+ * hrtimer가 활성화된후 timer interrupt가 이함수로 진입해서
+ * schedule tick에 대한것은 tick_sched_timer가 호출된다.
+ * 그 전까지는 tick_handle_periodic으로 진입한다.
+ */
void hrtimer_interrupt(struct clock_event_device *dev)
{
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
@@ -2613,12 +2657,22 @@ static inline void __hrtimer_peek_ahead_timers(void) { }
/*
* Called from run_local_timers in hardirq context every jiffy
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - periodic tick에서 hrtimer가 아직 활성화안될경우 hrtimer를 직접 가동한다.
+ * hrtimer switch가 가능한 상태가 되면 switch를 수행하고, 이미 hrtimer가
+ * 전환됬으면 아무도일도 안할것이다.
+ */
void hrtimer_run_queues(void)
{
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
unsigned long flags;
ktime_t now;
+/*
+ * IAMROOT, 2022.12.03:
+ * - hrtimer가 이미동작 하고있으므로 return.
+ */
if (__hrtimer_hres_active(cpu_base))
return;
@@ -2629,17 +2683,38 @@ void hrtimer_run_queues(void)
* there only sets the check bit in the tick_oneshot code,
* otherwise we might deadlock vs. xtime_lock.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - papago
+ * This _is_ ugly: highres 및/또는 nohz 모드로 전환할 수 있는지 주기적으로 확인해야 합니다.
+ * clocksource 스위치는 xtime_lock이 유지된 상태에서 발생합니다. 그곳으로부터의 알림은
+ * tick_oneshot 코드의 확인 비트만 설정합니다. 그렇지 않으면 xtime_lock과 교착
+ * 상태에 빠질 수 있습니다.*
+ */
if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) {
+/*
+ * IAMROOT, 2022.12.03:
+ * - hres전환.
+ */
hrtimer_switch_to_hres();
return;
}
+/*
+ * IAMROOT, 2022.12.03:
+ * - hrtimer로 아직전환이 안된경우 아래 로직이 동작한다.
+ * hrtimer의 invoke 함수를 호출한다.
+ */
raw_spin_lock_irqsave(&cpu_base->lock, flags);
now = hrtimer_update_base(cpu_base);
if (!ktime_before(now, cpu_base->softirq_expires_next)) {
cpu_base->softirq_expires_next = KTIME_MAX;
cpu_base->softirq_activated = 1;
+/*
+ * IAMROOT, 2022.12.03:
+ * - hrtimer 동작.
+ */
raise_softirq_irqoff(HRTIMER_SOFTIRQ);
}
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index 2d7dfe856c66..6968e2e2a1d7 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -1361,6 +1361,11 @@ static void handle_posix_cpu_timers(struct task_struct *tsk)
* already updated our counts. We need to check if any timers fire now.
* Interrupts are disabled.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - PASS
+ * user task의 수행시간을 누적 or timer 하기 위한용도.
+ */
void run_posix_cpu_timers(void)
{
struct task_struct *tsk = current;
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index f7fe6fe36173..4b943cf5cd91 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -159,6 +159,10 @@ static bool tick_set_oneshot_wakeup_device(struct clock_event_device *newdev,
/*
* Conditionally install/replace broadcast device
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - broadcast 인경우에만 동작한다.
+ */
void tick_install_broadcast_device(struct clock_event_device *dev, int cpu)
{
struct clock_event_device *cur = tick_broadcast_device.evtdev;
@@ -1063,6 +1067,11 @@ static void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
/*
* Select oneshot operating mode for the broadcast device
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - broadcast 설정을 한다. 설정만 할뿐 고성능 arm계열에서는
+ * 거의 사용하지 않는다.
+ */
void tick_broadcast_switch_to_oneshot(void)
{
struct clock_event_device *bc;
@@ -1071,6 +1080,10 @@ void tick_broadcast_switch_to_oneshot(void)
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
tick_broadcast_device.mode = TICKDEV_MODE_ONESHOT;
+/*
+ * IAMROOT, 2022.12.03:
+ * - 설정되있는경우에만 setup.
+ */
bc = tick_broadcast_device.evtdev;
if (bc)
tick_broadcast_setup_oneshot(bc);
@@ -1123,6 +1136,10 @@ int tick_broadcast_oneshot_active(void)
/*
* Check whether the broadcast device supports oneshot.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - CLOCK_EVT_FEAT_ONESHOT 이 있는지 확인.
+ */
bool tick_broadcast_oneshot_available(void)
{
struct clock_event_device *bc = tick_broadcast_device.evtdev;
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index 4d3756a801d3..4c76c1475e60 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -35,6 +35,14 @@ DEFINE_PER_CPU(struct tick_device, tick_cpu_device);
* CPU which handles the tick and protected by jiffies_lock. There is
* no requirement to write hold the jiffies seqcount for it.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - papago
+ * 다음 이벤트 선택: 틱 시간을 추적합니다. 틱을 처리하는 CPU에 의해 업데이트되고
+ * jiffies_lock에 의해 보호됩니다. 그것에 대한 jiffies seqcount를 보류할 필요는 없습니다.
+ *
+ * - 1tick이 더해진 next period를 저장해놓는다.
+ */
ktime_t tick_next_period;
/*
@@ -51,6 +59,21 @@ ktime_t tick_next_period;
* at it will take over and keep the time keeping alive. The handover
* procedure also covers cpu hotplug.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - papago
+ * tick_do_timer_cpu는 do_timer() 호출을 담당하는 CPU NR을 보유하는 타이머 코어 내부
+ * 변수입니다. 이 변수에는 두 가지 기능이 있습니다.
+ *
+ * 1) 시간 기록 잠금을 한 번에 모두 잡으려고 시도하는 수많은 CPU의 천둥 무리 문제를
+ * 방지합니다. 업데이트를 수행하도록 할당된 CPU만 업데이트를 처리합니다.
+ *
+ * 2) 값을 TICK_DO_TIMER_NONE(즉, 존재하지 않는 CPU)으로 설정하여 NOHZ 유휴 상태에서 작업을
+ * 해제합니다. 따라서 그것을 보는 다음 CPU가 시간을 이어받아 계속 살아있게 합니다. 핸드오버
+ * 절차에는 CPU 핫플러그도 포함됩니다.
+ *
+ * - 시간 갱신을 하는 cpu가 저장된다. 결정되기 전에는 TICK_DO_TIMER_BOOT가 저장되있다.
+ */
int tick_do_timer_cpu __read_mostly = TICK_DO_TIMER_BOOT;
#ifdef CONFIG_NO_HZ_FULL
/*
@@ -72,12 +95,23 @@ struct tick_device *tick_get_device(int cpu)
/**
* tick_is_oneshot_available - check for a oneshot capable event device
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - oneshot이 enable되있는지 확인한다.
+ */
int tick_is_oneshot_available(void)
{
struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);
if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT))
return 0;
+
+/*
+ * IAMROOT, 2022.12.03:
+ * - clock 절전기능이 없으면 return 1.
+ * 이 기능이 없는경우 전원을 아에 껏다가 켜야되는데, 짧은 시간을 껏다 켜야되는경우
+ * 성능이 오히려 느려져 시스템에 영향이 있다.
+ */
if (!(dev->features & CLOCK_EVT_FEAT_C3STOP))
return 1;
return tick_broadcast_oneshot_available();
@@ -86,13 +120,25 @@ int tick_is_oneshot_available(void)
/*
* Periodic tick
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - periodic tick 작업 수행.
+ */
static void tick_periodic(int cpu)
{
+/*
+ * IAMROOT, 2022.12.03:
+ * - @cpu가 jiffies을 계산하는 cpu가 맞다면 시간갱신을한다.
+ */
if (tick_do_timer_cpu == cpu) {
raw_spin_lock(&jiffies_lock);
write_seqcount_begin(&jiffies_seq);
/* Keep track of the next tick event */
+/*
+ * IAMROOT, 2022.12.03:
+ * - +1 tick
+ */
tick_next_period = ktime_add_ns(tick_next_period, TICK_NSEC);
do_timer(1);
@@ -108,6 +154,13 @@ static void tick_periodic(int cpu)
/*
* Event handler for periodic ticks
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - event_handler에 등록되서 사용된다. timer interrupt
+ * hrtimer가 활성화 되기 전에 timer interrupt가 이 함수로 진입한다.
+ * - schedule tick의 경우
+ * 활성화가 된후에는 hrtimer_interrupt를 통해서 tick_sched_timer가 호출된다.
+ */
void tick_handle_periodic(struct clock_event_device *dev)
{
int cpu = smp_processor_id();
@@ -206,6 +259,10 @@ static void tick_take_do_timer_from_boot(void)
/*
* Setup the tick device
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - 최초의 진입이라면(tick device setup) @cpu를 tick_do_timer_cpu로 정한다.
+ */
static void tick_setup_device(struct tick_device *td,
struct clock_event_device *newdev, int cpu,
const struct cpumask *cpumask)
@@ -221,6 +278,10 @@ static void tick_setup_device(struct tick_device *td,
* If no cpu took the do_timer update, assign it to
* this cpu:
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - @cpu로 tick_next_period를 정한다.
+ */
if (tick_do_timer_cpu == TICK_DO_TIMER_BOOT) {
tick_do_timer_cpu = cpu;
@@ -344,7 +405,7 @@ bool tick_check_replacement(struct clock_event_device *curdev,
*/
/*
* IAMROOT, 2022.08.27:
- * - TODO
+ * - @newdev를 검사하여 tick_do_timer_cpu등을 결정한다.
*/
void tick_check_new_device(struct clock_event_device *newdev)
{
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index 3a6176519ba3..c5dc3d24f583 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -138,6 +138,11 @@ extern struct cpumask *tick_get_broadcast_oneshot_mask(void);
static inline void tick_broadcast_switch_to_oneshot(void) { }
static inline int tick_broadcast_oneshot_active(void) { return 0; }
static inline void tick_check_oneshot_broadcast_this_cpu(void) { }
+
+/*
+ * IAMROOT, 2022.12.03:
+ * - oneshot이 가능한지 확인.
+ */
static inline bool tick_broadcast_oneshot_available(void) { return tick_oneshot_possible(); }
#endif /* !(BROADCAST && ONESHOT) */
diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c
index 475ecceda768..7e1c407adf1a 100644
--- a/kernel/time/tick-oneshot.c
+++ b/kernel/time/tick-oneshot.c
@@ -20,6 +20,18 @@
/**
* tick_program_event
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - @expire == KTIME_MAX
+ * stop
+ * - tick_cpu_device가 stop상태였다면.
+ * oneshot mode로 변경후 program.
+ * - @expires로 program한다.
+ *
+ * - @force == 1인 경우
+ * expires가 현재시각 이전이여도 prgram을 시도하고,
+ * program을 실패해도 min_delta_ns * 10의 시간까지 최대 10번을 재시도한다.
+ */
int tick_program_event(ktime_t expires, int force)
{
struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);
@@ -70,6 +82,10 @@ void tick_setup_oneshot(struct clock_event_device *newdev,
/**
* tick_switch_to_oneshot - switch to oneshot mode
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - oneshot 모드로 동작되면 return 0
+ */
int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *))
{
struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
@@ -121,6 +137,10 @@ int tick_oneshot_mode_active(void)
*
* Called with interrupts disabled.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - hrtimer_interrupt oneshot event_handler를 사용한다.
+ */
int tick_init_highres(void)
{
return tick_switch_to_oneshot(hrtimer_interrupt);
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 6bffe5af8cb1..14bf9c3bc4e8 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -49,11 +49,24 @@ struct tick_sched *tick_get_tick_sched(int cpu)
* jiffies_lock and jiffies_seq. tick_nohz_next_event() needs to get a
* consistent view of jiffies and last_jiffies_update.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - papago
+ * 마지막 jiffy 업데이트가 발생한 시간입니다. 쓰기 액세스는 jiffies_lock 및 jiffies_seq를
+ * 보유해야 합니다. tick_nohz_next_event()는 jiffies 및 last_jiffies_update의 일관된 보기를
+ * 가져와야 합니다.
+ */
static ktime_t last_jiffies_update;
/*
* Must be called with interrupts disabled !
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - @now를 기준으로 jiffies_64를 갱신한다.
+ * - tick_next_period는 acquire-release barrier를 통해서 동기화를 한다.
+ * jiffies_64는 spinlock + seqlock으로 동기화한다.
+ */
static void tick_do_update_jiffies64(ktime_t now)
{
unsigned long ticks = 1;
@@ -68,6 +81,19 @@ static void tick_do_update_jiffies64(ktime_t now)
* consists of two 32bit stores and the first store could move it
* to a random point in the future.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - papago
+ * 64비트는 jiffies 잠금을 유지하지 않고 시퀀스 카운트를 보지 않고
+ * 빠른 검사를 수행할 수 있습니다. smp_load_acquire()는 이 함수에서
+ * 나중에 수행되는 업데이트와 쌍을 이룹니다.
+ *
+ * tick_next_period의 저장소는 두 개의 32비트 저장소로 구성되어 있고
+ * 첫 번째 저장소는 향후 임의의 지점으로 이동할 수 있기 때문에
+ * 32비트는 그렇게 할 수 없습니다.
+ *
+ * - smp_store_release와 쌍으로 barrier.
+ */
if (IS_ENABLED(CONFIG_64BIT)) {
if (ktime_before(now, smp_load_acquire(&tick_next_period)))
return;
@@ -101,6 +127,11 @@ static void tick_do_update_jiffies64(ktime_t now)
write_seqcount_begin(&jiffies_seq);
delta = ktime_sub(now, tick_next_period);
+
+/*
+ * IAMROOT, 2022.12.03:
+ * - TICK_NSEC보다 많이 지났으면 단위개수만큼 ticks를 더 고려해준다.
+ */
if (unlikely(delta >= TICK_NSEC)) {
/* Slow path for long idle sleep times */
s64 incr = TICK_NSEC;
@@ -115,6 +146,10 @@ static void tick_do_update_jiffies64(ktime_t now)
}
/* Advance jiffies to complete the jiffies_seq protected job */
+/*
+ * IAMROOT, 2022.12.03:
+ * - 계산된 ticks을 더해준다.
+ */
jiffies_64 += ticks;
/*
@@ -129,6 +164,13 @@ static void tick_do_update_jiffies64(ktime_t now)
* not reordered vs. the store to tick_next_period, neither
* by the compiler nor by the CPU.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - papago
+ * 위의 잠금 없는 빠른 검사에서 smp_load_acquire()와 쌍을 이루고
+ * jiffies_64에 대한 업데이트가 컴파일러나 CPU에 의해 tick_next_period에
+ * 대한 저장에 대해 재정렬되지 않도록 합니다.
+ */
smp_store_release(&tick_next_period, nextp);
} else {
/*
@@ -145,6 +187,10 @@ static void tick_do_update_jiffies64(ktime_t now)
*/
write_seqcount_end(&jiffies_seq);
+/*
+ * IAMROOT, 2022.12.03:
+ * - jiffies_64가 변경됬으므로 global load계산을 재수행한다.
+ */
calc_global_load();
raw_spin_unlock(&jiffies_lock);
@@ -154,6 +200,10 @@ static void tick_do_update_jiffies64(ktime_t now)
/*
* Initialize and return retrieve the jiffies update.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - lock을 통해서 last_jiffies_update를 가져온다.
+ */
static ktime_t tick_init_jiffy_update(void)
{
ktime_t period;
@@ -161,6 +211,10 @@ static ktime_t tick_init_jiffy_update(void)
raw_spin_lock(&jiffies_lock);
write_seqcount_begin(&jiffies_seq);
/* Did we start the jiffies update yet ? */
+/*
+ * IAMROOT, 2022.12.03:
+ * - 업데이트한적이 없는경우 tick_next_period로 last_jiffies_update를 갱신한다.
+ */
if (last_jiffies_update == 0)
last_jiffies_update = tick_next_period;
period = last_jiffies_update;
@@ -169,6 +223,10 @@ static ktime_t tick_init_jiffy_update(void)
return period;
}
+/*
+ * IAMROOT, 2022.12.03:
+ * - jiffies update
+ */
static void tick_sched_do_timer(struct tick_sched *ts, ktime_t now)
{
int cpu = smp_processor_id();
@@ -184,6 +242,20 @@ static void tick_sched_do_timer(struct tick_sched *ts, ktime_t now)
* If nohz_full is enabled, this should not happen because the
* tick_do_timer_cpu never relinquishes.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - papago
+ * do_timer duty가 drop되었는지 확인합니다. 우리는 동시성에 대해
+ * 신경 쓰지 않습니다. 이것은 담당 CPU가 긴 수면에 들어간
+ * 경우에만 발생합니다. 두 개의 CPU가 이 작업에 자신을 할당하는
+ * 경우 jiffies 업데이트는 여전히 jiffies_lock에 의해 직렬화됩니다.
+ *
+ * nohz_full이 활성화된 경우 tick_do_timer_cpu가 절대 포기하지 않기
+ * 때문에 이런 일이 발생하지 않아야 합니다.
+ *
+ * - 동시성에 신경쓰지 않아 경쟁상황인 경우도 있다. 별로 상관없지만
+ * 검사는 수행한다.
+ */
if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE)) {
#ifdef CONFIG_NO_HZ_FULL
WARN_ON(tick_nohz_full_running);
@@ -200,6 +272,11 @@ static void tick_sched_do_timer(struct tick_sched *ts, ktime_t now)
ts->got_idle_tick = 1;
}
+/*
+ * IAMROOT, 2022.12.03:
+ * - update_process_times수행
+ * (tick이 증가하면서 수행해야될 작업들)
+ */
static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs)
{
#ifdef CONFIG_NO_HZ_COMMON
@@ -211,6 +288,14 @@ static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs)
* idle" jiffy stamp so the idle accounting adjustment we do
* when we go busy again does not account too much ticks.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - papago
+ * idle 상태이고 틱이 중지되면 정말 오랜 시간 동안 일정을 잡지 않을 수 있으므로
+ * 워치독을 터치해야 합니다. 이것은 로그인 프롬프트를 기다리는 동안 완전한 idle
+ * SMP 시스템에서 발생합니다. 또한 idle jiffy 스탬프의 시작을 증가시켜 다시 바쁠
+ * 때 수행하는 idle accounting 조정이 너무 많은 틱을 고려하지 않도록 합니다.
+ */
if (ts->tick_stopped) {
touch_softlockup_watchdog_sched();
if (is_idle_task(current))
@@ -220,6 +305,12 @@ static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs)
* expiration, make sure we don't bypass the next clock reprogramming
* to the same deadline.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - papago
+ * 현재 틱이 예상 만료 시간보다 너무 일찍 실행되는 경우 동일한 데드라인으로
+ * 재프로그래밍되는 다음 클록을 우회하지 않도록 합니다.
+ */
ts->next_tick = 0;
}
#endif
@@ -572,6 +663,10 @@ void __init tick_nohz_init(void)
/*
* NO HZ enabled ?
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - nohz= 로 설정한다. default true.
+ */
bool tick_nohz_enabled __read_mostly = true;
unsigned long tick_nohz_active __read_mostly;
/*
@@ -1327,12 +1422,21 @@ static void tick_nohz_handler(struct clock_event_device *dev)
tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1);
}
+/*
+ * IAMROOT, 2022.12.03:
+ * - @mode를 nohz_mode로 설정한다. schedule에 nohz enable을 예약한다.
+ */
static inline void tick_nohz_activate(struct tick_sched *ts, int mode)
{
if (!tick_nohz_enabled)
return;
ts->nohz_mode = mode;
/* One update is enough */
+/*
+ * IAMROOT, 2022.12.03:
+ * - active == 0인 경우 bit0 set을 하면서 timers_update_nohz()를 수행한다.
+ * 즉 최초에 수행.
+ */
if (!test_and_set_bit(0, &tick_nohz_active))
timers_update_nohz();
}
@@ -1340,6 +1444,10 @@ static inline void tick_nohz_activate(struct tick_sched *ts, int mode)
/**
* tick_nohz_switch_to_nohz - switch to nohz mode
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - nohz로 switch한다. schedule동작할때 nohz가 active되도록 예약한다.
+ */
static void tick_nohz_switch_to_nohz(void)
{
struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
@@ -1348,6 +1456,10 @@ static void tick_nohz_switch_to_nohz(void)
if (!tick_nohz_enabled)
return;
+/*
+ * IAMROOT, 2022.12.03:
+ * - oneshot이 아니면 경우 return.
+ */
if (tick_switch_to_oneshot(tick_nohz_handler))
return;
@@ -1360,6 +1472,10 @@ static void tick_nohz_switch_to_nohz(void)
next = tick_init_jiffy_update();
hrtimer_set_expires(&ts->sched_timer, next);
+/*
+ * IAMROOT, 2022.12.03:
+ * - hrtimer최초 시작. 1tick 시작.
+ */
hrtimer_forward_now(&ts->sched_timer, TICK_NSEC);
tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1);
tick_nohz_activate(ts, NOHZ_MODE_LOWRES);
@@ -1404,6 +1520,10 @@ void tick_irq_enter(void)
* We rearm the timer until we get disabled by the idle code.
* Called with interrupts disabled.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - jiffies갱신 및 tick 작업 수행 및 hrtimer tick 생성.
+ */
static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
{
struct tick_sched *ts =
@@ -1423,14 +1543,28 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
ts->next_tick = 0;
/* No need to reprogram if we are in idle or full dynticks mode */
+
+/*
+ * IAMROOT, 2022.12.03:
+ * - stop상태인 경우 여기서 return.
+ */
if (unlikely(ts->tick_stopped))
return HRTIMER_NORESTART;
+/*
+ * IAMROOT, 2022.12.03:
+ * - tick 생성.
+ */
hrtimer_forward(timer, now, TICK_NSEC);
return HRTIMER_RESTART;
}
+/*
+ * IAMROOT, 2022.12.03:
+ * - 0 or 1
+ * TICK / 2 의 시간을 cpu개수로 나눠서 어긋나게 schedule을 수행한다.
+ */
static int sched_skew_tick;
static int __init skew_tick(char *str)
@@ -1444,6 +1578,11 @@ early_param("skew_tick", skew_tick);
/**
* tick_setup_sched_timer - setup the tick emulation timer
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - sched timer를 tick_sched_timer로 설정한다.
+ * nohz를 NOHZ_MODE_HIGHRES로 설정한다.(arm계열이 자주사용한다)
+ */
void tick_setup_sched_timer(void)
{
struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
@@ -1459,6 +1598,11 @@ void tick_setup_sched_timer(void)
hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update());
/* Offset the tick to avert jiffies_lock contention. */
+/*
+ * IAMROOT, 2022.12.03:
+ * - sched_skew_tick option이 켜져있으면 반틱을 cpu개수로 나눠서 어긋나게 schedule이
+ * 수행하도록 보정한다.
+ */
if (sched_skew_tick) {
u64 offset = TICK_NSEC >> 1;
do_div(offset, num_possible_cpus());
@@ -1466,6 +1610,10 @@ void tick_setup_sched_timer(void)
hrtimer_add_expires_ns(&ts->sched_timer, offset);
}
+/*
+ * IAMROOT, 2022.12.03:
+ * - 실제 hrtimer 첫 틱 생성 시작.
+ */
hrtimer_forward(&ts->sched_timer, now, TICK_NSEC);
hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED_HARD);
tick_nohz_activate(ts, NOHZ_MODE_HIGHRES);
@@ -1515,16 +1663,42 @@ void tick_oneshot_notify(void)
* mode, because high resolution timers are disabled (either compile
* or runtime). Called with interrupts disabled.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - papago
+ * 원샷이 가능한 변화가 있는지 확인합니다.
+ *
+ * hrtimer softirq(타이머 softirq에 의해 구동됨) allow_nohz 신호에서 주기적으로
+ * 호출되며 고해상도 타이머가 비활성화되기 때문에(컴파일 또는 런타임) 저해상도
+ * nohz 모드로 전환할 수 있습니다. 인터럽트가 비활성화된 상태에서 호출됩니다.
+ *
+ * - oneshot nohz enable.
+ * return 0. 이미되있거나 switch 성공.
+ * return 1. 수행안함.
+ */
int tick_check_oneshot_change(int allow_nohz)
{
struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched);
+/*
+ * IAMROOT, 2022.12.03:
+ * - clocksource가 바뀌지 않았으면 return.
+ */
if (!test_and_clear_bit(0, &ts->check_clocks))
return 0;
+/*
+ * IAMROOT, 2022.12.03:
+ * - NOHZ_MODE_HIGHRES 인경우 return.
+ * inactive만 아니면 이미 전환됬다고 판단한다.
+ */
if (ts->nohz_mode != NOHZ_MODE_INACTIVE)
return 0;
+/*
+ * IAMROOT, 2022.12.03:
+ * - hres가 아니거나 oneshot이 안켜져있으면 return.
+ */
if (!timekeeping_valid_for_hres() || !tick_is_oneshot_available())
return 0;
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index a55105afa33c..18f3548776b9 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1538,6 +1538,10 @@ EXPORT_SYMBOL(ktime_get_raw_ts64);
/**
* timekeeping_valid_for_hres - Check if timekeeping is suitable for hres
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - CLOCK_SOURCE_VALID_FOR_HRES가 set되있는지 확인.
+ */
int timekeeping_valid_for_hres(void)
{
struct timekeeper *tk = &tk_core.timekeeper;
@@ -2228,6 +2232,10 @@ static bool timekeeping_advance(enum timekeeping_adv_mode mode)
* update_wall_time - Uses the current clocksource to increment the wall time
*
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - TODO
+ */
void update_wall_time(void)
{
if (timekeeping_advance(TK_ADV_TICK))
@@ -2288,6 +2296,11 @@ EXPORT_SYMBOL(ktime_get_coarse_ts64);
/*
* Must hold jiffies_lock
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - jiffies_64에 ticks증가.
+ * cpu global load.
+ */
void do_timer(unsigned long ticks)
{
jiffies_64 += ticks;
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 142e2cbee7ab..b5881e761d2f 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -295,6 +295,12 @@ static void timer_update_keys(struct work_struct *work)
mutex_unlock(&timer_keys_mutex);
}
+/*
+ * IAMROOT, 2022.12.03:
+ * - timers_nohz_active,timers_migration_enabled enable.
+ * schedule이 동작하고나서부터 돌라는 사전 예약의 의미가 있다.
+ * (schedule이 동작안하고 있을때에는 nohz가 필요없기때문)
+ */
void timers_update_nohz(void)
{
schedule_work(&timer_update_work);
@@ -2349,12 +2355,22 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h)
/*
* Called by the local, per-CPU timer interrupt on SMP.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - expiry time을 확인하여 lowres timer를 동작시킨다.
+ * hrtimer가 아직 활성화가 안된경우 hrtimer까지 수행한다.
+ */
static void run_local_timers(void)
{
struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
hrtimer_run_queues();
/* Raise the softirq only if required. */
+/*
+ * IAMROOT, 2022.12.03:
+ * - expiry 시간 전이면 return.
+ * nohz가 켜져있으면 deferred 까지 검사한다.
+ */
if (time_before(jiffies, base->next_expiry)) {
if (!IS_ENABLED(CONFIG_NO_HZ_COMMON))
return;
@@ -2363,6 +2379,10 @@ static void run_local_timers(void)
if (time_before(jiffies, base->next_expiry))
return;
}
+/*
+ * IAMROOT, 2022.12.03:
+ * - lowres timer 동작.
+ */
raise_softirq(TIMER_SOFTIRQ);
}
@@ -2370,6 +2390,14 @@ static void run_local_timers(void)
* Called from the timer interrupt handler to charge one tick to the current
* process. user_tick is 1 if the tick is user time, 0 for system.
*/
+/*
+ * IAMROOT, 2022.12.03:
+ * - user상태인경우 @user_tick == 1.
+ * kernel인경우 @user_tick == 0
+ *
+ * - tick이 update될시 수행할 모든일을 수행한다.
+ * 수행하는 일이 많으므로 내부 api각각 참조.
+ */
void update_process_times(int user_tick)
{
struct task_struct *p = current;
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
공지 | [공지] 스터디 정리 노트 공간입니다. | woos | 2016.05.14 | 623 |
185 | [커널 18차] 93주차 | kkr | 2023.03.04 | 53 |
184 | [커널 18차] 91주차 | kkr | 2023.02.18 | 95 |
183 | [커널 19차] 39 주차 | Min | 2023.02.18 | 53 |
182 | [커널 18차] 90주차 | kkr | 2023.02.13 | 63 |
181 | [커널 19차] 38 주차 | Min | 2023.02.11 | 45 |
180 | [커널 19차] 37 주차 | Min | 2023.02.04 | 478 |
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 | 110 |
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 | 61 |
170 | [커널 19차] 31 주차 | Min | 2022.12.17 | 63 |
169 | [커널 19차] 30 주차 | Min | 2022.12.10 | 61 |
168 | [커널 17차] 112 ~ 116주차 | ㅇㅇㅇ | 2022.12.05 | 72 |
» | [커널 18차] 80주차 | kkr | 2022.12.03 | 156 |
166 | [커널 19차] 28 ~ 29 주차 | Min | 2022.12.03 | 35 |
.