์ค์ OS ์ค์ผ์ค๋ฌ 3์ข (Basic Priority, MLFQS, CFS)์ ๋ชฉํ ๊ธฐ๋ฐ ํ ์คํธ๋ก ๋น๊ตํ๋ Streamlit ๋ฒค์น๋งํฌ์ ๋๋ค. (๋ผ์ด๋ธ ๋ฐ๋ชจ: http://34.47.105.226:8501)
- ์ฐจ๋ณ์ : ๋ชจ๋ ์กฐํฉ ๋น๊ต๊ฐ ์๋ ํ ์คํธ ๋ชฉํ๋ณ๋ก ์ค์ผ์ค๋ฌ๋ฅผ ์ ํํด ๊ณต์ ์ฑยท์ ํ์ฑ์ ํ๋ณด.
- ๊ตฌ์ฑ: 18๊ฐ ํ ์คํธ, 6๊ฐ ์นดํ ๊ณ ๋ฆฌ, 9๊ฐ ์ํฌ๋ก๋, ์ค์๊ฐ ๊ทธ๋ํ/๋ฆฌํฌํธ ์ ๊ณต.
- ์ํ: GCP์์ 24/7 ๊ตฌ๋, run.sh๋ก ๋ฐ๋ก ์คํ ๊ฐ๋ฅ.
- ํต์ฌ ์คํ ๋ฆฌ: time slice ๋ฏธ๊ตฌํ, CFS ์ ๋ฐ๋, Basic FIFO ๋ฑ 6๊ฐ ํฌ๋ฆฌํฐ์ปฌ ๋ฒ๊ทธ๋ฅผ ์ก์ผ๋ฉฐ ์๊ณ ๋ฆฌ์ฆ-์ธก์ -์ค๊ณ ์ธ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌ.
git clone https://github.com/dvktdr78/scheduler_benchmark.git
cd scheduler_benchmark/python_webapp
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt
streamlit run app.py # ๋๋ ํ๋ก์ ํธ ๋ฃจํธ์์ ./run.sh| ๋ชฉํ/์๋๋ฆฌ์ค | ์น์/ํน์ง | ์ด์ |
|---|---|---|
| CPU-boundยท์์ ์ฒ๋ฆฌ๋ | Basic (๊ฐ๋จ) | ์ค๋ฒํค๋ ์ต์, ์์ธก ๊ฐ๋ฅํ ์คํ ์์ |
| I/O/๋ํํ ์๋ต์ฑ | MLFQS | recent_cpu ๊ธฐ๋ฐ ๋์ ์ฐ์ ์์๋ก I/O ์ฐ๋ |
| ๊ณต์ ์ฑยท์ผ๊ด์ฑ(P99/CV) | CFS | vruntime ๊ฐ์ค์น ๊ธฐ๋ฐ ๊ณต์ ๋ถ๋ฐฐ, starvation ์์ |
| Nice ๊ทน๋จ ํ ์คํธ | MLFQS: ๊ทน๋จ์ ํจ๊ณผ / CFS: ๊ฐ์ค์น ๋น๋ก | MLFQS ์ฐ์ ์์ ๊ณต์์ ํฐ nice ๋ณด์ , CFS๋ weight ๊ธฐ๋ฐ ๊ท ํ |
| Starvation ์ํ | CFS 0%, Basic ์ํ | ์ ์ ์ฐ์ ์์๋ ๊ธฐ์ ๊ฐ๋ฅ, CFS๋ ๊ณต์ ์ฑ ์ ์ง |
| ํ ์คํธ | ์ฃผ์ ์์น (๋ฎ์์๋ก ์ข์*) | ์น์ |
|---|---|---|
| I/O-bound avg_wait | Basic 7,603 / MLFQS 7,474 / CFS 7,495 | MLFQS |
| CPU-bound avg_turnaround | Basic 22,924 / MLFQS 22,908 / CFS 22,918 | MLFQS |
| ๊ณต์ ์ฑ(mixed, fairness) | MLFQS 0.509 (starvation 32%) / CFS 0.999 (starvation 0%) | CFS |
| Nice ํจ๊ณผ(cpu_time_ratio, log) | MLFQS 4,999ร (starvation 48%) / CFS 199ร | CFS* |
| P99 ๋๊ธฐ(consistency_p99) | Basic 28,262 / CFS 28,262 / MLFQS 28,338 | Basic (P99) |
* nice_effect๋ CPU ์๊ฐ ๋น์จ์ด ๋ฎ์์๋ก ๊ฐ์ค์น ๋น๋ก์ ๊ฐ๊น์.
* ๋จ์: ticks. ๋ชจ๋ ํ
์คํธ๋ ์ ์๋ thread_count, max_ticks, seed=42 ๊ทธ๋๋ก ์คํ.
์ผ๋ฐยท์ค์ ์ํฌ๋ก๋
| ํ ์คํธ | ๋ฉํธ๋ฆญ | ์น์ | ํต์ฌ ์์น |
|---|---|---|---|
| ์ผ๋ฐ ํผํฉ | avg_wait | Basic | 8,085 (MLFQS 9,700 / CFS 10,838) |
| CPU-bound | avg_turnaround | MLFQS | 22,908 (Basic 22,924 / CFS 22,918) |
| I/O-bound | avg_wait | MLFQS | 7,474 (Basic 7,603 / CFS 7,495) |
| ์น ์๋ฒ | avg_turnaround | Basic | 1,062 (MLFQS 1,065 / CFS 1,082) |
| ๋ฐ์ดํฐ๋ฒ ์ด์ค | avg_turnaround | CFS | 5,332 (MLFQS 5,338 / Basic 5,381) |
| ๋ฐฐ์น ์ฒ๋ฆฌ | avg_turnaround | MLFQS | 25,388 (Basic 25,406 / CFS 25,408) |
| ๊ฒ์/์ค์๊ฐ | avg_wait | Basic | 8,813 (MLFQS 8,813 / CFS 8,925) |
๊ณต์ ์ฑยท์ผ๊ด์ฑยทNice ํจ๊ณผ
| ํ ์คํธ | ๋ฉํธ๋ฆญ | ์น์ | ํต์ฌ ์์น |
|---|---|---|---|
| ๊ณต์ ์ฑ (mixed) | fairness | CFS | 0.999 vs MLFQS 0.509 (starvation 32%) |
| ๊ณต์ ์ฑ (extreme nice) | fairness | CFS | 0.525 vs MLFQS 0.500 (starvation 50%) |
| Nice ํจ๊ณผ | cpu_time_ratio | CFS | 199ร vs MLFQS 4,999ร (starvation 48%) |
| ์ผ๊ด์ฑ (CV) | cv_wait | CFS | 29.6% vs Basic 54.5% / MLFQS 43.3% |
| ์ผ๊ด์ฑ (P99) | p99_wait | Basic | 28,262 vs CFS 28,262 / MLFQS 28,338 |
| ์ผ๊ด์ฑ (worst/avg) | worst_ratio | CFS | 1.40 vs MLFQS 1.59 / Basic 1.87 |
| ๊ธฐ์ ๋ฐฉ์ง | starvation_pct | CFS | 0% vs Basic/MLFQS 48% |
ํ์ฅ์ฑ
| ํ ์คํธ | ๋ฉํธ๋ฆญ | ์น์ | ํต์ฌ ์์น |
|---|---|---|---|
| 10 ์ค๋ ๋ | context_switches | Basic | 361 vs MLFQS 644 / CFS 682 |
| 100 ์ค๋ ๋ | avg_wait | Basic | 15,183 vs MLFQS 17,836 / CFS 20,188 |
| 500 ์ค๋ ๋ | avg_wait | CFS | 34,697 vs Basic 31,696*, MLFQS 34,424* (starvation Basic 76% / MLFQS 48%) |
โป *starvation์ด ๋์ ์ค์ผ์ค๋ฌ๋ ์น์ ์ ์ ์์ ์ ์ธ๋ฉ๋๋ค.
- Time slice ๋ฏธ๊ตฌํ โ FCFSํ: ์๋ฎฌ๋ ์ดํฐ์ ์ ์ ๋ก์ง์ ๋ฃ์ด ์ค์ผ์ค๋ฌ ์ฐจ์ด๋ฅผ ๋ณต์.
- CFS vruntime ์ ๋ฐ๋ 0: ์ ์ ๋๋์ ์ค์ผ์ผ์ 1000๋ฐฐ๋ก ์ฌ๋ ค ๊ฐ์ค์น ๋น๋ก ๊ณต์ ์ฑ์ ํ๋ณต.
- Basic FIFO ์ค๋ฅ: TID ๊ธฐ๋ฐ ์ ํ์ ํ ์ฝ์ ์์ ๊ธฐ๋ฐ FIFO๋ก ์์ ํด ํธํฅ ์ ๊ฑฐ.
- ๋น ๋ฅธ ์์ฝ
- ๋น ๋ฅธ ์คํ
- ๊ฒฐ๊ณผ ํ๋์ ๋ณด๊ธฐ
- ํต์ฌ ๋ฒ๊ทธ/์ธ์ฌ์ดํธ Top3
- ๊ฐ์
- ์ํคํ ์ฒ
- ์ค์น ๋ฐ ์คํ
- ์ค์ผ์ค๋ฌ ์์ธ
- ํ ์คํธ ์นดํ ๊ณ ๋ฆฌ
- ์ํฌ๋ก๋
- ํ์ผ ๊ตฌ์กฐ
- ์ฃผ์ ๋ฐ๊ฒฌ์ฌํญ
- ์ค๊ณ ๊ฒฐ์ ์ฌํญ
- ์ค์ผ์ค๋ฌ ๋ฒค์น๋งํฌ ํ๋ก์ ํธ ์๊ฐ๋ฌธ
์ค์ ์ด์์ฒด์ ์์ ์ฌ์ฉ๋๋ 3๊ฐ์ง CPU ์ค์ผ์ค๋ง ์๊ณ ๋ฆฌ์ฆ์ ๊ณต์ ํ๊ฒ ๋น๊ตํ๊ณ , ๊ฐ๊ฐ์ ์ฅ๋จ์ ์ ์ ๋์ ์ผ๋ก ์ธก์ ํฉ๋๋ค.
- โ ๋ชฉํ ๊ธฐ๋ฐ ํ ์คํธ: ์ค์ผ์ค๋ฌ์ ์ค๋ฆฝ์ ์ธ ๋ชฉํ๋ก ํ ์คํธ ์ ์
- โ ์ ํ์ ๋น๊ต: ๊ฐ ํ ์คํธ๋ง๋ค ์๋ฏธ์๋ ์ค์ผ์ค๋ฌ ์กฐํฉ๋ง ๋น๊ต
- โ ์ค์๊ฐ ์๊ฐํ: Streamlit ์น UI๋ก ์ฆ์ ๊ฒฐ๊ณผ ํ์ธ
- โ ๊ฒ์ฆ๋ ๊ตฌํ: ๊ฐ ์ค์ผ์ค๋ฌ๋ ์ค์ OS ๊ตฌํ์ ๊ธฐ๋ฐ์ผ๋ก ๊ฒ์ฆ๋จ
- Basic Priority - ์ ์ ์ฐ์ ์์ ์ค์ผ์ค๋ฌ (Baseline)
- MLFQS (64-Queue) - ๋์ ์ฐ์ ์์, O(1) ์ค์ผ์ค๋ง
- CFS - Linux ์ปค๋์ ๊ณต์ ์ฑ ์ค์ผ์ค๋ฌ
๊ธฐ์กด์ "๋ชจ๋ ํ ์คํธ์์ 3๊ฐ ์ค์ผ์ค๋ฌ๋ฅผ ํญ์ ๋น๊ต" ๋ฐฉ์ ๋์ , ๊ฐ ํ ์คํธ์ ๋ชฉํ์ ๋ง๋ ์ค์ผ์ค๋ฌ๋ง ์ ํ์ ์ผ๋ก ๋น๊ตํฉ๋๋ค.
-
ํ ์คํธ๋ "๋ชฉํ"๋ก ์ ์ (scheduler-neutral)
- ์: "Interactive ์๋ต์ฑ", "๊ณต์ ํ CPU ๋ฐฐ๋ถ", "Nice ํจ๊ณผ ์ธก์ "
-
๊ฐ ํ ์คํธ๋ง๋ค ์ ์ ํ ์ค์ผ์ค๋ฌ๋ง ๋น๊ต
- ์ผ๋ฐ ์ํฌ๋ก๋: Basic + MLFQS + CFS (3-way)
- ๊ณต์ ์ฑ ํ ์คํธ: MLFQS + CFS๋ง (Basic์ starvation ์ํ)
- Nice ํจ๊ณผ: MLFQS + CFS๋ง (Basic์ nice๋ ์ ์ ์ฐ์ ์์)
-
๊ฐ ์ค์ผ์ค๋ฌ๊ฐ ์์ ์ ๋ฐฉ์์ผ๋ก ๋ชฉํ ๋ฌ์ฑ
- Basic: ์ ์ ์ฐ์ ์์
- MLFQS: ๋์ ์ฐ์ ์์ ์กฐ์
- CFS: ๊ณต์ ํ CPU ์๊ฐ ๋ฐฐ๋ถ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Streamlit Web UI (app.py) โ
โ - ํ
์คํธ ์ ํ (์นดํ
๊ณ ๋ฆฌ๋ณ) โ
โ - ์ค์๊ฐ ์งํ์ํฉ ํ์ โ
โ - ๊ฒฐ๊ณผ ์๊ฐํ (๊ทธ๋ํ, ๋ฉํธ๋ฆญ) โ
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Benchmark Tests (benchmark/tests.py) โ
โ - 18๊ฐ ํ
์คํธ ์ ์ โ
โ - 6๊ฐ ์นดํ
๊ณ ๋ฆฌ ๋ถ๋ฅ โ
โ - ์ค์ผ์ค๋ฌ ์กฐํฉ ๋ช
์ โ
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโดโโโโโโโโโ
โ โ
โโโโโโโโโโผโโโโโโโ โโโโโโโโผโโโโโโโโโโ
โ Workload โ โ Simulator โ
โ Generator โ โ (simulator/ โ
โ (workload/) โ โ simulator.py)โ
โ โ โ โ
โ - 9๊ฐ์ง ํจํด โ โ - Time slice โ
โ - Seed ๊ณ ์ โ โ - Context SW โ
โโโโโโโโโโโโโโโโโ โ - I/O ์ฒ๋ฆฌ โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโ
โ โ โ
โโโโโโโโโโผโโโโโโโ โโโโโโโโโโผโโโโโโโ โโโโโโโโโผโโโโโโโโ
โ Basic โ โ MLFQS โ โ CFS โ
โ Priority โ โ (64-Queue) โ โ (vruntime) โ
โ (scheduler/ โ โ (scheduler/ โ โ (scheduler/ โ
โ basic_*.py) โ โ mlfqs.py) โ โ cfs.py) โ
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
โ โ โ
โโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโผโโโโโโโโโ
โ Analysis โ
โ (analysis/ โ
โ insights.py) โ
โ โ
โ - Metrics ๊ณ์ฐ โ
โ - ์น์ ๊ฒฐ์ โ
โ - Insight ์์ฑ โ
โโโโโโโโโโโโโโโโโโโ
- Python 3.8 ์ด์
- Linux ํ๊ฒฝ ๊ถ์ฅ (Ubuntu 20.04+)
# ์ ์ฅ์ ํด๋ก
git clone https://github.com/dvktdr78/scheduler_benchmark.git
cd scheduler-benchmark/python_webapp
# ๊ฐ์ํ๊ฒฝ ์์ฑ
python3 -m venv venv
# ๊ฐ์ํ๊ฒฝ ํ์ฑํ
source venv/bin/activate
# ์์กด์ฑ ์ค์น
pip install -r requirements.txt# ๊ฐ์ํ๊ฒฝ ํ์ฑํ (ํ์์)
source venv/bin/activate
# Streamlit ์ฑ ์คํ
streamlit run app.py# ํ๋ก์ ํธ ๋ฃจํธ์์
./run.sh- ๊ฐ๋ : ์ฌ์ฉ์๊ฐ ์ฃผ๋ โ์๋ณด๋โ ํํธ. ๋ฎ์์๋ก ์ฐ์ ์์ โ, ๋์์๋ก ์ฐ์ ์์ โ (๋ฐ๋น๋ก).
- ๋ฒ์: -20(๊ฐ์ฅ ๋์ ์ฐ์ ์์) ~ +19(๊ฐ์ฅ ๋ฎ์ ์ฐ์ ์์), ๊ธฐ๋ณธ 0.
- ์ ์ฉ ๋ฐฉ์: Basic์
priority = 31 - nice๋ก ์ ์ ๋ณํ, MLFQS๋priority = PRI_MAX - (recent_cpu/4) - 2*nice์ ๋ฐ์, CFS๋ ๊ฐ์ค์น ํ ์ด๋ธ๋ก ๋ณํํด CPU ์๊ฐ ๋น์จ์ ์กฐ์ .
๊ฐ์: ์ ์ ์ฐ์ ์์ ๊ธฐ๋ฐ ์ ์ ํ ์ค์ผ์ค๋ฌ (Baseline)
ํต์ฌ ์๊ณ ๋ฆฌ์ฆ:
- Nice ๊ฐ์ ์ ์ ์ฐ์ ์์๋ก ๋ณํ:
priority = PRI_DEFAULT(31) - nice - ์ฐ์ ์์ ๋ฒ์: 0-63 (63์ด ์ต๊ณ ์ฐ์ ์์)
- ๊ฐ์ ์ฐ์ ์์ ๋ด์์ FIFO ๋ฐฉ์
๊ตฌํ ํน์ง:
- Round-robin ๋ฐฉ์ (time slice = 4 ticks)
- Preemptive (๋์ ์ฐ์ ์์ ์ค๋ ๋๊ฐ ๋์ฐฉํ๋ฉด ์ ์ )
- Aging ๋ฏธ์ง์ (starvation ์ํ ์กด์ฌ)
์ฅ์ :
- ๋จ์ํ๊ณ ์์ธก ๊ฐ๋ฅ
- ์ค๋ฒํค๋ ์ต์
- ์ค์๊ฐ ์์คํ ์ ์ ํฉ
๋จ์ :
- Starvation ์ํ (๋ฎ์ ์ฐ์ ์์ ์ค๋ ๋)
- ๋์ ์กฐ์ ๋ถ๊ฐ
- I/O bound ์ค๋ ๋์ ๋ถ๋ฆฌ
์ฝ๋ ์์น: scheduler/basic_priority.py
๊ฐ์: 64๊ฐ ๋ ๋ฆฝ ํ๋ฅผ ์ฌ์ฉํ๋ ๋์ ์ฐ์ ์์ ์ค์ผ์ค๋ฌ (FreeBSD ๋ฐฉ์)
ํต์ฌ ์๊ณ ๋ฆฌ์ฆ:
priority = PRI_MAX - (recent_cpu / 4) - (nice * 2)
recent_cpu = (2 * load_avg) / (2 * load_avg + 1) * recent_cpu + nice
load_avg = (59/60) * load_avg + (1/60) * ready_threads
๊ตฌํ ํน์ง:
- 64๊ฐ ๋ ๋ฆฝ ํ (์ฐ์ ์์ 0-63)
- O(1) pick_next (๊ธฐ์กด O(n) โ O(64) = O(1))
- O(1) thread_yield (๊ธฐ์กด O(n log n) โ O(1))
- 17.14 ๊ณ ์ ์์์ ์ฐ์ฐ (F = 1 << 14 = 16384)
์ ๋ฐ์ดํธ ์ฃผ๊ธฐ:
recent_cpu++: ๋งค tick (์คํ ์ค์ธ ์ค๋ ๋๋ง)priority ์ฌ๊ณ์ฐ: 4 ticks๋ง๋คload_avg, recent_cpu ์ฌ๊ณ์ฐ: 100 ticks๋ง๋ค
์ฅ์ :
- I/O bound ์ค๋ ๋ ์๋ ์ฐ๋
- Starvation ๋ฐฉ์ง (recent_cpu๊ฐ ์๊ฐ์ ๋ฐ๋ผ ๊ฐ์)
- ๋์ ๋ถํ ์กฐ์
๋จ์ :
- Nice ํจ๊ณผ๊ฐ ์ฝํจ (nice๋ priority์ -2๋ฐฐ๋ง ๊ธฐ์ฌ)
- ๋ณต์กํ ๊ณ์ฐ (๊ณ ์ ์์์ )
- ๊ณต์ ์ฑ์ด CFS๋ณด๋ค ๋ฎ์
์ฝ๋ ์์น:
๊ฐ์: Linux ์ปค๋์ ๊ณต์ ์ฑ ์ค์ผ์ค๋ฌ (vruntime ๊ธฐ๋ฐ)
ํต์ฌ ์๊ณ ๋ฆฌ์ฆ:
delta_vruntime = delta * (NICE_0_WEIGHT / weight)
weight = PRIO_TO_WEIGHT[nice + 20]
์ต์ vruntime ์ค๋ ๋๋ฅผ ์ ํ (Red-Black Tree ๋์ SortedList ์ฌ์ฉ)
๊ตฌํ ํน์ง:
- Linux ์ปค๋ ๊ฐ์ค์น ํ ์ด๋ธ 100% ๋์ผ ์ฌ์ฉ
- vruntime์ผ๋ก ์๋ ์ ๋ ฌ (SortedList)
- 1000๋ฐฐ ์ค์ผ์ผ ์ฆ๊ฐ๋ก ์ ๋ฐ๋ ํฅ์ (
(delta * 1024 * 1000) // weight)
๊ฐ์ค์น ํ ์ด๋ธ ์์:
- nice -20 โ weight 88761 (์ต๊ณ ์ฐ์ ์์)
- nice 0 โ weight 1024 (๊ธฐ๋ณธ)
- nice 19 โ weight 15 (์ต์ ์ฐ์ ์์)
์ด๋ก ์ CPU ์๊ฐ ๋น์จ:
- nice -20 vs nice 19: 88761 / 15 โ 5917:1
์ฅ์ :
- ์๋ฒฝํ ๊ณต์ ์ฑ (Jain Index > 0.95)
- Nice ํจ๊ณผ๊ฐ ๊ฐํจ (๊ฐ์ค์น ๊ธฐ๋ฐ)
- Starvation ์์ ๋ฐฉ์ง
๋จ์ :
- I/O bound ์ค๋ ๋์ ํน๋ณํ ์ฐ๋ ์์
- ์ฝ๊ฐ์ ์ค๋ฒํค๋ (SortedList ๊ด๋ฆฌ)
์ฝ๋ ์์น: scheduler/cfs.py
์ด 17๊ฐ ํ ์คํธ, 6๊ฐ ์นดํ ๊ณ ๋ฆฌ๋ก ๊ตฌ์ฑ
๋ชฉ์ : ๋ค์ํ ์ผ๋ฐ์ ์ธ ์ํฌ๋ก๋ ํจํด ๋น๊ต
| ํ ์คํธ | ์ํฌ๋ก๋ | ์ฃผ์ ๋ฉํธ๋ฆญ | ๋น๊ต ๋์ |
|---|---|---|---|
| ์ผ๋ฐ ํผํฉ ์ํฌ๋ก๋ | mixed | avg_wait | Basic + MLFQS + CFS |
| CPU ์ง์ฝ์ ์ํฌ๋ก๋ | cpu_bound | avg_turnaround | Basic + MLFQS + CFS |
| I/O ์ง์ฝ์ ์ํฌ๋ก๋ | io_bound | avg_wait | Basic + MLFQS + CFS |
ํน์ง:
- mixed: Nice -5~5 (์ฝํ ์ฐจ์ด)
- cpu_bound: Nice 0 (์์ ์๊ณ ๋ฆฌ์ฆ ํจ์จ์ฑ ๋น๊ต)
- io_bound: 60% I/O + 40% CPU ๊ฒฝ์์ ํผํฉ (MLFQS I/O ์ฐ๋ ํ ์คํธ)
๋ชฉ์ : ์ค์ ์์คํ ํจํด ์๋ฎฌ๋ ์ด์
| ํ ์คํธ | ์ํฌ๋ก๋ | ํจํด | ๋น๊ต ๋์ |
|---|---|---|---|
| ์น ์๋ฒ ํจํด | web_server | 90% ์งง์ ์์ฒญ (Nice -5) + 10% ๊ธด ์์ฒญ (Nice 5) | Basic + MLFQS + CFS |
| ๋ฐ์ดํฐ๋ฒ ์ด์ค ํจํด | database | 70% SELECT + 30% ํธ๋์ญ์ | Basic + MLFQS + CFS |
| ๋ฐฐ์น ์ฒ๋ฆฌ ํจํด | batch | CPU-heavy, ์์ฐจ ๋์ฐฉ | Basic + MLFQS + CFS |
| ๊ฒ์/์ค์๊ฐ ํจํด | gaming | 30% ๋ ๋๋ง (Nice -10) + 70% AI (Nice 10) | Basic + MLFQS + CFS |
ํน์ง:
- ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ๋์ ๋ชจ๋ฐฉ
- web_server/gaming: Nice ์ฐจ์ด๋ก ์ฐ์ ์์ ์ฒ๋ฆฌ ๋ฅ๋ ฅ ํ ์คํธ
- database/batch: Nice 0์ผ๋ก ํต์ผ
๋ชฉ์ : CPU ์๊ฐ ๋ฐฐ๋ถ์ ๊ณต์ ์ฑ ์ธก์
| ํ ์คํธ | ์ํฌ๋ก๋ | ์ฃผ์ ๋ฉํธ๋ฆญ | ๋น๊ต ๋์ |
|---|---|---|---|
| ๊ณต์ ์ฑ: ํผํฉ ์ํฌ๋ก๋ | mixed | fairness | MLFQS + CFS |
| ๊ณต์ ์ฑ: ๊ทน๋จ Nice ๊ฐ์ค์น | extreme_nice_fairness | fairness | MLFQS + CFS |
Note: cpu_bound ์ํฌ๋ก๋๋ ๋ชจ๋ ์ค๋ ๋๊ฐ Nice 0์ผ๋ก ๋์ผํ์ฌ ์ค์ผ์ค๋ฌ ๊ฐ ๊ณต์ ์ฑ ์ฐจ์ด๊ฐ ์์ด ํ ์คํธ์์ ์ ์ธ๋จ.
์ Basic์ ์ ์ธํ๋๊ฐ?
- Basic Priority๋ ์ ์ ์ฐ์ ์์ ๊ธฐ๋ฐ์ผ๋ก starvation ์ํ ์กด์ฌ
- ๊ณต์ ์ฑ ์ธก์ ์ ๋ถ์ ํฉ (์ ์ด์ ๊ณต์ ์ฑ์ ๋ชฉํ๋ก ํ์ง ์์)
๋ฉํธ๋ฆญ: Jain's Fairness Index (1.0์ ๊ฐ๊น์ธ์๋ก ๊ณต์ )
๊ณต์ ์ฑ ์ ์(ํ์ฌ ๊ตฌํ):
- ๊ฐ ์ค๋ ๋๊ฐ ์ค์ ๋ก ์คํ ๊ฐ๋ฅํ ์๊ฐ(READY/RUNNING) ๋์ ๊ฐ์ ธ์ผ ํ ๋ชซ์
niceโweight๋ก ๊ณ์ฐํฉ๋๋ค. ์: nice -20์ weight๊ฐ ํฌ๋ ๋ ํฐ ๋ชซ์ ๊ฐ์ต๋๋ค. - ๊ด์ฐฐ ๊ตฌ๊ฐ์์ ๋ฐ์ **CPU ๋น์ค รท (runnable_time ร weight ๋น์ค)**์ ๊ตฌํด, ๋ชจ๋ ์ค๋ ๋์ ๊ฐ์ด 1์ ๊ฐ๊น์ฐ๋ฉด ๊ณต์ ํฉ๋๋ค.
- ์ด ๋น์จ๋ค์ Jain Index๋ฅผ ์ ์ฉํด 0~1 ์ฌ์ด ๊ฐ์ผ๋ก ํํํฉ๋๋ค(1.0 = ์ด์์ ๋น๋ก ๋ฐฐ๋ถ).
- runnable ์๊ฐ์ด 0์ด๊ฑฐ๋ ์๋ฃ ์ค๋ ๋๊ฐ ์์ผ๋ฉด ํด๋น ๊ฐ์
N/A๋ก ํ์ํด 0.0๊ณผ ํผ๋ํ์ง ์์ต๋๋ค.
๋ชฉ์ : ๋๊ธฐ ์๊ฐ์ ์์ธก ๊ฐ๋ฅ์ฑ๊ณผ ์ผ๊ด์ฑ ์ธก์ (CFS ์ ๋ฆฌ)
| ํ ์คํธ | ์ํฌ๋ก๋ | ์ฃผ์ ๋ฉํธ๋ฆญ | ๋น๊ต ๋์ |
|---|---|---|---|
| ์ผ๊ด์ฑ: ๋ณ๋๊ณ์ | mixed | cv_wait | Basic + MLFQS + CFS |
| ์ผ๊ด์ฑ: P99 ๋ ์ดํด์ | mixed | p99_wait | Basic + MLFQS + CFS |
| ์ผ๊ด์ฑ: ์ต์ /ํ๊ท ๋น์จ | mixed | worst_ratio | Basic + MLFQS + CFS |
| ๊ธฐ์ ๋ฐฉ์ง: ๊ทน๋จ์ Nice | extreme_nice | starvation_pct | Basic + MLFQS + CFS |
๋ฉํธ๋ฆญ ์ค๋ช :
- cv_wait: ๋ณ๋๊ณ์ (ํ์คํธ์ฐจ/ํ๊ท ร 100), ๋ฎ์์๋ก ์์ธก ๊ฐ๋ฅ
- p99_wait: 99 ํผ์ผํ์ผ ๋๊ธฐ ์๊ฐ, ๋ฎ์์๋ก ํ ์ผ ๋ ์ดํด์ ์ํธ
- worst_ratio: ์ต์ /ํ๊ท ๋๊ธฐ ์๊ฐ ๋น์จ, 1.0์ ๊ฐ๊น์ธ์๋ก ๊ท ์ผ
- starvation_pct: ์คํ ์๋ ์ค๋ ๋ ๋น์จ, 0%๊ฐ ์ด์์
๋ชฉ์ : Nice ๊ฐ์ ์ค์ ํจ๊ณผ ๊ฒ์ฆ
| ํ ์คํธ | ์ํฌ๋ก๋ | ์ฃผ์ ๋ฉํธ๋ฆญ | ๋น๊ต ๋์ |
|---|---|---|---|
| Nice ๊ฐ ํจ๊ณผ ๊ฒ์ฆ | extreme_nice | cpu_time_ratio | MLFQS + CFS |
์ Basic์ ์ ์ธํ๋๊ฐ?
- Basic์ nice๋ ์ ์ ์ฐ์ ์์๋ก ๋ณํ (๋ค๋ฅธ ์๋ฏธ)
- MLFQS/CFS๋ nice๋ก CPU ์๊ฐ ๋น์จ ์กฐ์ (๊ฐ์ค์น ๊ธฐ๋ฐ)
ํ ์คํธ ๋ฐฉ๋ฒ:
- ์ ๋ฐ: nice -20 (์ต๊ณ ์ฐ์ ์์)
- ์ ๋ฐ: nice 19 (์ต์ ์ฐ์ ์์)
- burst_time = 2,000 ticks (MLFQS ์ฑ๋ฅ ๊ณ ๋ คํ์ฌ ์ถ์)
- 20% ์๊ฐ์ ์ค๋จ (์ผ๋ถ๋ง ์๋ฃํ์ฌ CPU ์๊ฐ ๋น์จ ์ธก์ , max_ticks=20,000)
๋ฉํธ๋ฆญ: CPU ์๊ฐ ๋น์จ (nice -20 ๊ทธ๋ฃน / nice 19 ๊ทธ๋ฃน)
๊ด์ฐฐ: MLFQS๋ ๋งค์ฐ ๊ฐํ nice ํจ๊ณผ๋ฅผ, CFS๋ ๊ฐ์ค์น ๋น๋ก ๋ฐฐ๋ถ์ ๋ณด์
๋ชฉ์ : ์ค๋ ๋ ์์ ๋ฐ๋ฅธ ์ฑ๋ฅ ๋ณํ
| ํ ์คํธ | ์ค๋ ๋ ์ | ์ฃผ์ ๋ฉํธ๋ฆญ | ๋น๊ต ๋์ |
|---|---|---|---|
| ํ์ฅ์ฑ: 10 ์ค๋ ๋ | 10 | context_switches | Basic + MLFQS + CFS |
| ํ์ฅ์ฑ: 100 ์ค๋ ๋ | 100 | avg_wait | Basic + MLFQS + CFS |
| ํ์ฅ์ฑ: 500 ์ค๋ ๋ | 500 | avg_wait | Basic + MLFQS + CFS |
๋ชฉํ: ์ค์ผ์ผ๋ง ๋ฅ๋ ฅ ๋ฐ ์ค๋ฒํค๋ ์ธก์
- CPU burst: 100-500 ticks
- I/O: ๋ค์ (๋น๋ 0-500, ์ง์ 0-200)
- Nice: -5 ~ 5
- ์ฉ๋: ์ผ๋ฐ์ ์ธ ๋ฉํฐํ์คํน ํ๊ฒฝ
- CPU burst: 300-800 ticks
- I/O: ์์
- Nice: 0
- ์ฉ๋: ๊ณผํ ๊ณ์ฐ, ์ปดํ์ผ (์์ ์๊ณ ๋ฆฌ์ฆ ํจ์จ์ฑ ๋น๊ต)
- 60% I/O-bound: CPU burst 30-100, I/O ๋น๋ 10-30 (๋งค์ฐ ์ฆ์)
- 40% CPU-bound ๊ฒฝ์์: CPU burst 500-1000, I/O ์์
- Nice: 0
- ์ฉ๋: MLFQS์ I/O ์ฐ๋ ๋ฅ๋ ฅ ํ ์คํธ
- 90% ์งง์ ์์ฒญ: 10-50 ticks (Nice -5)
- 10% ๊ธด ์์ฒญ: 200-600 ticks (Nice 5)
- ๋ชจ๋ฐฉ: Nginx, Apache (์งง์ ์์ฒญ ์ฐ์ ์ฒ๋ฆฌ)
- 70% SELECT ์ฟผ๋ฆฌ: 30-150 ticks
- 30% ํธ๋์ญ์ : 200-600 ticks
- Nice: 0
- ๋ชจ๋ฐฉ: PostgreSQL, MySQL
- CPU burst: 400-800 ticks
- ์์ฐจ ๋์ฐฉ (i * 10 ticks)
- Nice: 0
- ๋ชจ๋ฐฉ: ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ, ๋น๋ ์์คํ
- 30% ๋ ๋๋ง: 50-150 ticks, 16ms ๊ฐ๊ฒฉ ๋์ฐฉ (Nice -10)
- 70% AI/๋ฌผ๋ฆฌ: 200-500 ticks (Nice 10)
- ๋ชฉํ: 60 FPS ์ ์ง (๋ ๋๋ง ์ฐ์ )
- ์ ๋ฐ: nice -20, burst_time 2,000
- ์ ๋ฐ: nice 19, burst_time 2,000
- I/O: ์์
- ์ฉ๋: Nice ํจ๊ณผ ๊ฒ์ฆ (MLFQS ์ฑ๋ฅ ๊ณ ๋ คํ์ฌ ์ถ์)
- ์ ๋ฐ: nice -20, burst_time 1,000
- ์ ๋ฐ: nice 19, burst_time 1,000
- I/O: ์์
- ์ฉ๋: ์ ํ๋ ์๊ฐ ๋ด ๊ฐ์ค์น ๋น๋ก ๊ณต์ ์ฑ ์ธก์
์ฝ๋ ์์น: workload/generator.py
standalone_scheduler/
โโโ python_webapp/
โ โโโ app.py # Streamlit ๋ฉ์ธ UI
โ โโโ requirements.txt # Python ์์กด์ฑ
โ โ
โ โโโ scheduler/ # ์ค์ผ์ค๋ฌ ๊ตฌํ
โ โ โโโ thread.py # Thread ๋ฐ์ดํฐ ํด๋์ค
โ โ โโโ basic_priority.py # Basic Priority ์ค์ผ์ค๋ฌ
โ โ โโโ mlfqs.py # MLFQS ์ค์ผ์ค๋ฌ
โ โ โโโ cfs.py # CFS ์ค์ผ์ค๋ฌ
โ โ โโโ fixed_point.py # 17.14 ๊ณ ์ ์์์ ์ฐ์ฐ
โ โ
โ โโโ workload/ # ์ํฌ๋ก๋ ์์ฑ
โ โ โโโ generator.py # 8๊ฐ์ง ์ํฌ๋ก๋ ์์ฑ๊ธฐ
โ โ
โ โโโ simulator/ # ์๋ฎฌ๋ ์ด์
์์ง
โ โ โโโ simulator.py # ๋จ์ผ CPU ์๋ฎฌ๋ ์ดํฐ
โ โ
โ โโโ analysis/ # ๋ถ์ ๋๊ตฌ
โ โ โโโ metrics.py # ๋ฉํธ๋ฆญ ๊ณ์ฐ ํจ์
โ โ โโโ insights.py # Insight ์์ฑ ๋ฐ ๋น๊ต ๋ณด๊ณ ์
โ โ
โ โโโ benchmark/ # ๋ฒค์น๋งํฌ ์ ์
โ โโโ tests.py # 18๊ฐ ํ
์คํธ ์ ์
โ
โโโ run.sh # ๋น ๋ฅธ ์คํ ์คํฌ๋ฆฝํธ
โโโ README.md # ์ด ํ์ผ
์ฆ์: ๊ฒฐ๊ณผ๊ฐ ์ฆ์ ๋์ค๊ณ ๋ชจ๋ ๋ฉํธ๋ฆญ์ด ๋์ผ (tie)
์์ธ: ์ค๋ ๋๊ฐ ์๋ฃ๋ ๋๊น์ง ๊ณ์ ์คํ (์ ์ ์์)
ํด๊ฒฐ:
- Simulator์
time_slice=4์ถ๊ฐ current_slice_remaining์ถ์ - Time slice ๋ง๋ฃ ์
thread_yield()ํธ์ถ
์์น: simulator/simulator.py:94-137
์ฆ์: Basic์ด ๊ฑฐ์ ํญ์ ์น๋ฆฌ
์์ธ: max(key=lambda t: (t.priority, -t.tid))๊ฐ ํญ์ ์ต์ TID ์ ํ (FIFO๊ฐ ์๋)
ํด๊ฒฐ:
# ์ต๊ณ ์ฐ์ ์์ ์ฐพ๊ธฐ
max_priority = max(t.priority for t in self.ready_queue)
# ๊ฐ์ ์ฐ์ ์์ ์ค ์ฒซ ๋ฒ์งธ ์ค๋ ๋ ์ ํ (์ง์ง FIFO)
for thread in self.ready_queue:
if thread.priority == max_priority:
self.ready_queue.remove(thread)
return thread์์น: scheduler/basic_priority.py:41-67
์ฆ์: MLFQS์์ ๋ชจ๋ ์ค๋ ๋์ nice๊ฐ 0์ด ๋จ
์์ธ: add_thread()์์ thread.nice = 0 ์คํ
ํด๊ฒฐ: ํด๋น ๋ผ์ธ ์ ๊ฑฐ, ์ํฌ๋ก๋์์ ์ค์ ํ nice ๊ฐ ์ ์ง
์์น: scheduler/mlfqs.py:99-109
์ฆ์: CFS vruntime์ด ํญ์ 0
์์ธ: ์ ์ ๋๋์
(delta * 1024) // weight์์ weight=88761์ผ ๋ ๊ฒฐ๊ณผ๊ฐ 0
๋ถ์:
delta = 1
1024 / 88761 = 0.0115... โ ์ ์ ๋๋์
์ผ๋ก 0
ํด๊ฒฐ: 1000๋ฐฐ ์ค์ผ์ผ ์ฆ๊ฐ
return (delta * 1024 * 1000) // weight
# nice -20 (weight 88761): delta_vruntime = 11
# nice 19 (weight 15): delta_vruntime = 68266์์น: scheduler/cfs.py:52-64
์ฆ์: CPU ์๊ฐ ๋น์จ์ด 1:1๋ก ๋์ด (์์: ์์ฒ:1)
์์ธ: ๋ชจ๋ ์ค๋ ๋๊ฐ ์๋ฃ โ ๊ฐ์ ์ ํํ burst_time๋งํผ CPU ์ฌ์ฉ โ ๋น์จ 1:1
ํด๊ฒฐ:
extreme_nice์ํฌ๋ก๋์ burst_time: 300 โ 2,000 (MLFQS ์ฑ๋ฅ ๊ณ ๋ ค)- Nice ํจ๊ณผ ํ ์คํธ๋ง 20% ์๊ฐ์ ์๋ฎฌ๋ ์ด์ ์ค๋จ (max_ticks=20,000)
if selected_test.test_id == "nice_effect":
total_work = sum(t.burst_time for t in base_threads)
actual_max_ticks = int(total_work * 0.5) # 50% ์๊ฐ๋ง ์คํ๊ฒฐ๊ณผ: MLFQS๋ ๋งค์ฐ ๊ฐํ nice ํจ๊ณผ, CFS๋ ๊ฐ์ค์น ๋น๋ก ๋ฐฐ๋ถ
์์น:
์ฆ์: ํ์ฅ์ฑ ํ
์คํธ์ ์ฃผ์ ๋ฉํธ๋ฆญ context_switches๊ฐ ํญ์ 0์ผ๋ก ๋์ ๊ฐ์ ์จ์ด 0% ๊ณ ์
์์ธ:
- ์ปจํ ์คํธ ์ค์์น ์นด์ดํธ๊ฐ ์ค๋ ๋์ ์ ๋ฌ๋์ง ์์
- ๋ง์ง๋ง ์คํ ์ค๋ ๋ ID๋ฅผ ์ถ์ ํ์ง ์์ ์นด์ดํธ๊ฐ ๋๋ฝ
ํด๊ฒฐ:
prev_running_tid๋ก ์ปจํ ์คํธ ์ค์์น ์์ ์ ์ ํํ ํ์- ์๋ฎฌ๋ ์ด์
์ข
๋ฃ ์ ๋ชจ๋ ์ค๋ ๋์
context_switches๊ธฐ๋ก - ๋ฉํธ๋ฆญ ๊ณ์ฐ์์
context_switches๋ฅผ ์ง์
์์น:
๊ฐ ์ค์ผ์ค๋ฌ๊ฐ ์์ ์ ๊ฐ์ ์ ๋ง๋ ์ํฌ๋ก๋์์ ์น๋ฆฌํ๋ฉฐ, ํน์ ์ค์ผ์ค๋ฌ๊ฐ ์๋์ ์ผ๋ก ์ ๋ฆฌํ์ง ์์.
์ง๋ฌธ: "bursttime์ vruntime ๊ฐ์ ๋ณ์์ ๋ง๊ฒ ๋์ ์ผ๋ก ๋๋ ค์ผ ํ๋?"
๋ต๋ณ: NO
์ด์ :
burst_time์ "์ค์ ๋ก ํ์ํ ์์ ๋"์ ๋ํ๋- ํ๋ก์ธ์ค๊ฐ ์๋ฃํ๋ ค๋ฉด burst_time๋งํผ์ CPU๊ฐ ํ์
- ์ค์ผ์ค๋ฌ๋ ์ด๋ฅผ ์ด๋ป๊ฒ ๋ฐฐ๋ถํ ์ง ๊ฒฐ์ ํ ๋ฟ, ์์ ๋ ์์ฒด๋ ๋ณํ์ง ์์
- ๋์ ์ผ๋ก ๋ณ๊ฒฝํ๋ฉด "์ค์ผ์ค๋ฌ ์ฑ๋ฅ" ๋์ "์ํฌ๋ก๋ ์์ฒด"๊ฐ ๋ฌ๋ผ์ง
Nice ํจ๊ณผ ์ธก์ ์:
- burst_time 2,000 ์ฌ์ฉ (MLFQS ์ฑ๋ฅ ๊ณ ๋ ค)
- 20% ์๊ฐ์ ์ค๋จํ์ฌ ๋ถ๋ถ ์๋ฃ ๊ด์ฐฐ (max_ticks=20,000)
- ์ด๊ฒ์ด ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ
Basic Priority:
- Nice โ ์ ์ ์ฐ์ ์์ ๋ณํ
priority = 31 - nice- ์ฐ์ ์์ ์์ฒด๊ฐ ๋ณ๊ฒฝ๋จ
MLFQS:
- Nice โ ๋์ ์ฐ์ ์์ ๊ณ์ฐ์ ๊ธฐ์ฌ
priority = PRI_MAX - (recent_cpu/4) - (nice*2)- nice๋ -2๋ฐฐ๋ก๋ง ๊ธฐ์ฌ (์ฝํ ํจ๊ณผ)
CFS:
- Nice โ ๊ฐ์ค์น ๋ณํ
weight = PRIO_TO_WEIGHT[nice + 20]- CPU ์๊ฐ ๋น์จ ๊ฒฐ์ (๊ฐํ ํจ๊ณผ)
๊ฒฐ๋ก : Nice๊ฐ ํฌํจ๋ ์ํฌ๋ก๋๋ ์ค์ผ์ค๋ฌ๋ง๋ค ๋ค๋ฅด๊ฒ ํด์๋๋ฏ๋ก, ๊ณต์ ํ ๋น๊ต๋ฅผ ์ํด ๋๋ถ๋ถ์ ํ ์คํธ์์ nice=0 ์ฌ์ฉ
์ด์ :
- Basic Priority๋ ์ ์ ์ฐ์ ์์ ๊ธฐ๋ฐ (starvation ์ํ)
- ๊ณต์ ์ฑ์ ๋ชฉํ๋ก ์ค๊ณ๋์ง ์์
- Nice์ ์๋ฏธ๊ฐ ๋ค๋ฆ (์ฐ์ ์์ vs ๊ฐ์ค์น)
๊ฒฐ๊ณผ:
- ์๋ฏธ ์๋ ๋น๊ต๋ง ์ํ
- ๊ฐ ์ค์ผ์ค๋ฌ์ ๊ฐ์ ์ ๊ณต์ ํ๊ฒ ํ๊ฐ
์ด์ :
- 50๊ฐ ์ค๋ ๋ ์๋ฃ์ ํ์ํ ์๊ฐ: ~30,000 ticks
- ์ฌ์ ๋ฅผ ๋๊ณ 35,000 ticks๋ก ์ค์
- Nice ํจ๊ณผ ํ ์คํธ๋ ์์ธ (50% ์๊ฐ์ ์ค๋จ)
์ด์ :
- ๋๋ฌด ์งง์ผ๋ฉด: Context switch ์ค๋ฒํค๋ ์ฆ๊ฐ
- ๋๋ฌด ๊ธธ๋ฉด: ์๋ต์ฑ ์ ํ
- 4 ticks๋ ์ผ๋ฐ์ ์ธ Round-robin ์ค์
- MLFQS: 4.4BSD Scheduler, FreeBSD Implementation
- CFS: "Inside the Linux 2.6 Completely Fair Scheduler" (IBM DeveloperWorks)
- Fixed Point Arithmetic: Pintos Documentation (17.14 format)
- Linux ์ปค๋
kernel/sched/core.c(PRIO_TO_WEIGHT ํ ์ด๋ธ) - FreeBSD
sys/kern/sched_4bsd.c(MLFQS ๊ตฌํ)
- Jain's Fairness Index: "Quantitative Measure of Fairness" (Jain et al., 1984)
CPU ์ค์ผ์ค๋ฌ ๋ฒค์น๋งํฌ ์์คํ : Basic Priority, MLFQS, CFS ๋น๊ต ๋ถ์
- ์ธ์ด: Python 3.8+
- ํ๋ ์์ํฌ: Streamlit
- ๋ฐฐํฌ: GCP VM (Ubuntu 24.04), http://34.47.105.226:8501
- ๋ฒ์ ๊ด๋ฆฌ: Git/GitHub
3๊ฐ์ง ์ค์ ์ด์์ฒด์ ์ค์ผ์ค๋ฌ(Basic Priority, MLFQS 64-Queue, Linux CFS)๋ฅผ ๋ชฉํ ๊ธฐ๋ฐ ํ ์คํธ๋ก ๋น๊ตํ๋ ๋ฒค์น๋งํฌ ์์คํ . 18๊ฐ ํ ์คํธ, 6๊ฐ ์นดํ ๊ณ ๋ฆฌ๋ก ๊ตฌ์ฑ๋์ด ๊ฐ ์ค์ผ์ค๋ฌ์ ๊ฐ์ ๊ณผ ์ฝ์ ์ ์ ๋์ ์ผ๋ก ์ธก์ .
ํ๋ก์ ํธ๋ฅผ ์์ํ๋ฉด์ ๊ฐ์ฅ ํฐ ๊ณ ๋ฏผ์ **"์ด๋ป๊ฒ ํ๋ฉด ์ด์์ฒด์ ์ด๋ก ์ ์ค์ ๋ก ๊ฒ์ฆํ ์ ์์๊น?"**์์ต๋๋ค. OS๋ฅผ ํ์ตํ๋ฉด์ ๋ฐฐ์ด CPU ์ค์ผ์ค๋ง ์๊ณ ๋ฆฌ์ฆ๋ค์ ์ด๋ก ์ ์ผ๋ก๋ ๋ช ํํ์ง๋ง, ์ค์ ๋ก ์ด๋ ๊ฒ์ด ๋ ์ข์์ง, ์ Linux๊ฐ CFS๋ฅผ ์ฑํํ๋์ง, MLFQS๋ ์ด๋ค ์ํฉ์์ ์ ๋ฆฌํ์ง ๋ฑ์ ์ง๋ฌธ์ ๋ํ ๋ช ํํ ๋ต์ด ์์์ต๋๋ค.
๋จ์ํ "์ด๋ก ์ ์๋ค"๋ ๊ฒ๊ณผ "์ค์ ๋ก ๊ตฌํํ๊ณ ์ธก์ ํ๋ค"๋ ๊ฒ ์ฌ์ด์๋ ํฐ ์ฐจ์ด๊ฐ ์๋ค๋ ๊ฒ์ ๊นจ๋ฌ์๊ณ , ์ง์ ๊ตฌํํด๋ณด๊ธฐ๋ก ๊ฒฐ์ฌํ์ต๋๋ค.
์ฒ์์๋ ๋จ์ํ "3๊ฐ ์ค์ผ์ค๋ฌ๋ฅผ ๊ตฌํํ๊ณ ๋ชจ๋ ํ ์คํธ์์ ๋น๊ต"ํ๋ ๊ฒ์ ์๊ฐํ์ต๋๋ค. ํ์ง๋ง ๊ณง ์ฌ๋ฌ ๋ฌธ์ ์ ์ ๋ฐ๊ฒฌํ์ต๋๋ค:
์ด๋ค ๋ฉํธ๋ฆญ์ผ๋ก "๋ ์ข๋ค"๋ฅผ ํ๋จํ ๊ฒ์ธ๊ฐ? ํ๊ท ๋๊ธฐ ์๊ฐ? ๋ฐํ ์๊ฐ? ๊ณต์ ์ฑ? ๊ฐ ์ค์ผ์ค๋ฌ๋ ์๋ก ๋ค๋ฅธ ๋ชฉํ๋ฅผ ๊ฐ์ง๊ณ ์ค๊ณ๋์๋๋ฐ, ๋จ์ผ ๋ฉํธ๋ฆญ์ผ๋ก ๋น๊ตํ๋ ๊ฒ์ด ๊ณต์ ํ๊ฐ?
Basic Priority๋ ์ ์ด์ ๊ณต์ ์ฑ์ ๋ชฉํ๋ก ํ์ง ์์ต๋๋ค. ์ ์ ์ฐ์ ์์ ๊ธฐ๋ฐ์ด๋ฏ๋ก ๋ฎ์ ์ฐ์ ์์ ์ค๋ ๋๋ starvation ์ํ์ด ์์ต๋๋ค. ์ด๋ฐ ์ค์ผ์ค๋ฌ๋ฅผ "๊ณต์ ์ฑ ํ ์คํธ"์ ํฌํจ์ํค๋ ๊ฒ์ ๋ถ์ ์ ํฉ๋๋ค.
- Basic Priority: nice โ ์ ์ ์ฐ์ ์์ ๋ณํ (
priority = 31 - nice) - MLFQS: nice โ ๋์ ์ฐ์ ์์ ๊ณ์ฐ์ ๊ธฐ์ฌ (
priority = PRI_MAX - recent_cpu/4 - 2*nice) - CFS: nice โ ๊ฐ์ค์น ๋ณํ (Linux PRIO_TO_WEIGHT ํ ์ด๋ธ)
๊ฐ ์ค์ผ์ค๋ฌ๊ฐ nice๋ฅผ ์์ ํ ๋ค๋ฅด๊ฒ ํด์ํ๋๋ฐ, ๋์ผํ nice ๊ฐ์ผ๋ก ๋น๊ตํ๋ ๊ฒ์ด ์๋ฏธ๊ฐ ์๋๊ฐ?
๊ณ ๋ฏผ ๋์ ๋๋ฌํ ํด๋ต์ **"ํ ์คํธ๋ฅผ ๋ชฉํ/๊ฐ๋ ์ผ๋ก ์ ์ํ๊ณ , ๊ฐ ํ ์คํธ๋ง๋ค ์๋ฏธ ์๋ ์ค์ผ์ค๋ฌ๋ง ์ ํ์ ์ผ๋ก ๋น๊ต"**ํ๋ ๊ฒ์ด์์ต๋๋ค.
์๋ฅผ ๋ค์ด:
-
์ผ๋ฐ ์ํฌ๋ก๋ ํ ์คํธ: 3๊ฐ ๋ชจ๋ ๋น๊ต (์์ ์๊ณ ๋ฆฌ์ฆ ํจ์จ์ฑ)
- nice ๊ฐ์ 0 ๋๋ ์ฝํ ์ฐจ์ด(-5~5)
- ๋ชฉํ: ์ค์ผ์ค๋ง ์๊ณ ๋ฆฌ์ฆ ์์ฒด์ ํจ์จ์ฑ ๋น๊ต
-
๊ณต์ ์ฑ ํ ์คํธ: MLFQS vs CFS๋ง
- Basic์ starvation ์ํ์ด ์์ด ์ ์ธ
- ๋ชฉํ: CPU ์๊ฐ ๋ฐฐ๋ถ์ ๊ณต์ ์ฑ ์ธก์
-
Nice ํจ๊ณผ ํ ์คํธ: MLFQS vs CFS๋ง
- Basic์ nice๋ ๋ค๋ฅธ ์๋ฏธ(์ ์ ์ฐ์ ์์)
- ๋ชฉํ: nice ๊ฐ์ด ์ค์ CPU ์๊ฐ ๋ฐฐ๋ถ์ ๋ฏธ์น๋ ์ํฅ
์ด ๊ฒฐ์ ์ด ํ๋ก์ ํธ์ ๊ฐ์ฅ ์ค์ํ ์ฐจ๋ณ์ ์ด ๋์์ต๋๋ค. ๋จ์ํ "๋ชจ๋ ์กฐํฉ ๋น๊ต"๊ฐ ์๋๋ผ, ๊ฐ ํ ์คํธ์ ๋ชฉํ์ ๋ง๋ ๊ณต์ ํ ๋น๊ต๋ฅผ ์ํํ๊ฒ ๋ ๊ฒ์ ๋๋ค.
์ค์ผ์ค๋ฌ ์ ํ์์๋ ์ ์คํ ๊ณ ๋ฏผ์ด ํ์ํ์ต๋๋ค:
- ์ค์ ์ด์์ฒด์ ์์ ์ฌ์ฉ: ๊ฒ์ฆ๋ ์๊ณ ๋ฆฌ์ฆ
- ๋ณต์ก๋ ์คํํธ๋ผ: ๋จ์ โ ๋ณต์ก
- ๊ตฌํ ๊ฐ๋ฅ์ฑ: ์ ํ๋ ์๊ฐ ๋ด ์์ฑ ๊ฐ๋ฅ
ํต์ฌ ๊ฐ๋ : Basic Priority๋ ๊ฐ์ฅ ์ง๊ด์ ์ธ ์ค์ผ์ค๋ฌ์ ๋๋ค. ๊ฐ ์ค๋ ๋์ "์ฐ์ ์์ ์ซ์"๋ฅผ ๋ถ์ฌํ๊ณ , ํญ์ ๊ฐ์ฅ ๋์ ์ฐ์ ์์๋ฅผ ๊ฐ์ง ์ค๋ ๋๋ฅผ ๋จผ์ ์คํํฉ๋๋ค.
์๋ ๋ฐฉ์:
Step 1: Nice ๊ฐ์ ์ฐ์ ์์๋ก ๋ณํ
- nice -20 โ priority 51 (์ต๊ณ ์ฐ์ ์์)
- nice 0 โ priority 31 (๋ณดํต)
- nice 19 โ priority 12 (์ต์ ์ฐ์ ์์)
Step 2: Pick Next ์คํ ์
- Ready queue์์ priority๊ฐ ๊ฐ์ฅ ๋์ ์ค๋ ๋ ์ฐพ๊ธฐ
- ๊ฐ์ priority๋ฉด ๋จผ์ ๋ค์ด์จ ๊ฒ ์ ํ (FIFO)
Step 3: Time Slice ๋ง๋ฃ ์
- ์ค๋ ๋๋ฅผ ready queue ๋งจ ๋ค์ ์ฌ์ฝ์
- ์ฐ์ ์์๋ ์ ๋ ๋ณํ์ง ์์ (์ ์ ์ฐ์ ์์)
์ฅ์ :
- ๋จ์ํจ: ๊ตฌํ์ด ์ฝ๊ณ , ๋์์ด ์์ธก ๊ฐ๋ฅ
- ๋ฎ์ ์ค๋ฒํค๋: ์ฐ์ ์์ ์ฌ๊ณ์ฐ ์์
- CPU-bound์ ์ ๋ฆฌ: ๋ณต์กํ ๊ณ์ฐ ์์ด ๋ฐ๋ก ์คํ
๋จ์ :
- ๋ถ๊ณต์ ์ฑ: ๋์ ์ฐ์ ์์ ์ค๋ ๋๊ฐ ๋ ์ ๊ฐ๋ฅ
- Starvation ์ํ: ๋ฎ์ ์ฐ์ ์์๋ ์์ํ ๋๊ธฐํ ์ ์์
- I/O ์๋ต์ฑ ๋ถ์กฑ: I/O ์ค๋ ๋๋ฅผ ์๋์ผ๋ก ์ฐ๋ํ์ง ์์
์ค์ ์ฌ์ฉ์ฒ: ๋ง์ RTOS(Real-Time Operating System)์์ ์ฌ์ฉ. ์์ธก ๊ฐ๋ฅ์ฑ์ด ์ค์ํ ์๋ฒ ๋๋ ์์คํ ์ ์ ํฉํฉ๋๋ค.
ํต์ฌ ๊ฐ๋ : MLFQS๋ "์ค๋ ๋๊ฐ ์ด๋ป๊ฒ ํ๋ํ๋์ง ๊ด์ฐฐํ๊ณ , ๊ทธ์ ๋ง๊ฒ ์ฐ์ ์์๋ฅผ ๋์ ์ผ๋ก ์กฐ์ "ํ๋ ์ค์ผ์ค๋ฌ์ ๋๋ค. CPU๋ฅผ ๋ง์ด ์ฐ๋ ์ค๋ ๋๋ ์ฐ์ ์์๊ฐ ๋ด๋ ค๊ฐ๊ณ , I/O ๋๊ธฐ๊ฐ ๋ง์ ์ค๋ ๋๋ ์ฐ์ ์์๊ฐ ์ฌ๋ผ๊ฐ๋๋ค.
์๋ ๋ฐฉ์:
Step 1: 64๊ฐ์ ์ฐ์ ์์ ํ ์ค๋น
- ๊ฐ ์ฐ์ ์์(0~63)๋ง๋ค ๋
๋ฆฝ๋ ํ
- ๋์ ์ฐ์ ์์ ํ๋ถํฐ ๊ฒ์ โ O(1) ์ฑ๋ฅ
Step 2: ์ค๋ ๋ ์คํ ์ recent_cpu ์ฆ๊ฐ
- ๋งค tick๋ง๋ค running ์ค๋ ๋์ recent_cpu++
- "์ต๊ทผ ์ผ๋ง๋ CPU๋ฅผ ์ฌ์ฉํ๋๊ฐ"๋ฅผ ์ถ์
Step 3: 4 ticks๋ง๋ค ์ฐ์ ์์ ์ฌ๊ณ์ฐ (๋ชจ๋ ์ค๋ ๋)
priority = PRI_MAX - (recent_cpu / 4) - (nice * 2)
์์:
- Thread A: recent_cpu=100, nice=0
โ priority = 63 - (100/4) - 0 = 38
- Thread B: recent_cpu=10, nice=0 (I/O ๋๊ธฐ๊ฐ ๋ง์์)
โ priority = 63 - (10/4) - 0 = 60 (๋์ ์ฐ์ ์์!)
Step 4: 100 ticks๋ง๋ค recent_cpu ๊ฐ์
recent_cpu = (2*load_avg)/(2*load_avg+1) * recent_cpu
์ด ๊ณต์์ "์ค๋๋ CPU ์ฌ์ฉ์ ์ ์ฐจ ์์ด๋ฒ๋ฆผ"์ ์๋ฏธํฉ๋๋ค.
์: recent_cpu=1000 โ 800 โ 640 โ 512... (์ ์ ๊ฐ์)
17.14 ๊ณ ์ ์์์ ์ด๋? MLFQS๋ ๋ถ๋์์์ ์ฐ์ฐ์ ํผํ๊ธฐ ์ํด "17.14" ํ์์ ์ฌ์ฉํฉ๋๋ค:
- ์ ์๋ฅผ 16384(2^14)๋ฐฐ ํ๋ํด์ ์ ์ฅ
- ์: 1.5๋ฅผ ์ ์ฅํ๋ ค๋ฉด โ 1.5 ร 16384 = 24576 ์ ์ฅ
- ๋๋์
:
a // 16384 - ๊ณฑ์
:
(a * b) // 16384
์ด๋ ๊ฒ ํ๋ฉด ์ ์ ์ฐ์ฐ๋ง์ผ๋ก ์์์ ๊ณ์ฐ์ด ๊ฐ๋ฅํฉ๋๋ค.
์ฅ์ :
- I/O ์๋ต์ฑ ์ฐ์: I/O ๋๊ธฐ ์ค์๋ recent_cpu๊ฐ ์ฆ๊ฐํ์ง ์์ ์ฐ์ ์์ ์ ์ง
- CPU-bound ์๋ ๊ฐ์ง: CPU๋ฅผ ๋ง์ด ์ฐ๋ฉด ์ฐ์ ์์ ์๋ ํ๋ฝ
- ๋์ ์ ์: ์ํฌ๋ก๋ ํจํด ๋ณํ์ ์๋์ผ๋ก ๋์
๋จ์ :
- ๋ณต์กํ ๊ณ์ฐ: 4 ticks๋ง๋ค ๋ชจ๋ ์ค๋ ๋ ์ฌ๊ณ์ฐ, 100 ticks๋ง๋ค load_avg ์ฌ๊ณ์ฐ
- Nice ํจ๊ณผ ์ฝํจ: recent_cpu ์ฆ๊ฐ๊ฐ nice ๊ฐ์ ์๋ํ ์ ์์
- ์์ธก ์ด๋ ค์: ์ฐ์ ์์๊ฐ ๋์ ์ผ๋ก ๋ณํ๋ฏ๋ก ์คํ ์์ ์์ธก ๊ณค๋
์ค์ ์ฌ์ฉ์ฒ: FreeBSD 4.4BSD์ ๊ธฐ๋ณธ ์ค์ผ์ค๋ฌ. ๋ฒ์ฉ ์๋ฒ/๋ฐ์คํฌํฑ ํ๊ฒฝ์ ์ ํฉํฉ๋๋ค.
ํต์ฌ ๊ฐ๋ : CFS๋ "๋ชจ๋ ์ค๋ ๋๊ฐ ์ ํํ ๊ณตํํ๊ฒ CPU ์๊ฐ์ ๋ฐ์์ผ ํ๋ค"๋ ์ฒ ํ์ ๊ฐ์ง ์ค์ผ์ค๋ฌ์ ๋๋ค. "Virtual Runtime(vruntime)"์ด๋ผ๋ ๊ฐ๋ ์ผ๋ก "๋๊ฐ CPU๋ฅผ ๋ ๋ฐ์๋๊ฐ"๋ฅผ ์ถ์ ํ๊ณ , ํญ์ ๊ฐ์ฅ ์ ๊ฒ ๋ฐ์ ์ค๋ ๋๋ฅผ ๋ค์์ ์คํํฉ๋๋ค.
์๋ ๋ฐฉ์:
Step 1: ๊ฐ ์ค๋ ๋๋ vruntime ๊ฐ์ ๊ฐ์ง (์ฒ์์ ๋ชจ๋ 0)
Step 2: ์ค๋ ๋๊ฐ 1 tick ์คํ๋๋ฉด vruntime ์ฆ๊ฐ
delta_vruntime = (1 tick ร NICE_0_WEIGHT) / weight
vruntime += delta_vruntime
weight๋ nice ๊ฐ์ ๋ฐ๋ผ ๋ค๋ฆ:
- nice -20 โ weight 88761 (๋งค์ฐ ํผ)
- nice 0 โ weight 1024
- nice 19 โ weight 15 (๋งค์ฐ ์์)
Step 3: ๊ตฌ์ฒด์ ์ธ ๊ณ์ฐ ์์
1 tick ์คํ ํ vruntime ์ฆ๊ฐ๋:
nice -20 (weight=88761):
delta = (1 ร 1024 ร 1000) / 88761 = 11
โ vruntime์ด ์์ฃผ ์ฒ์ฒํ ์ฆ๊ฐ
nice 0 (weight=1024):
delta = (1 ร 1024 ร 1000) / 1024 = 1000
โ ๊ธฐ์ค ์๋๋ก ์ฆ๊ฐ
nice 19 (weight=15):
delta = (1 ร 1024 ร 1000) / 15 = 68266
โ vruntime์ด ๋งค์ฐ ๋น ๋ฅด๊ฒ ์ฆ๊ฐ
Step 4: Pick Next ์คํ ์
- vruntime์ด ๊ฐ์ฅ ์์ ์ค๋ ๋ ์ ํ
- "CPU๋ฅผ ๊ฐ์ฅ ์ ๊ฒ ๋ฐ์ ์ค๋ ๋"๋ฅผ ์๋ฏธ
์ ์ด๊ฒ ๊ณต์ ํ๊ฐ?
์์: Thread A (nice -20), Thread B (nice 0)
Tick 1: A ์คํ โ vruntime_A = 0+11 = 11
Tick 2: B ์คํ โ vruntime_B = 0+1000 = 1000
Tick 3: A ์คํ (11 < 1000์ด๋ฏ๋ก) โ vruntime_A = 11+11 = 22
Tick 4: A ์คํ (22 < 1000์ด๋ฏ๋ก) โ vruntime_A = 22+11 = 33
...
Tick 92: A ์คํ โ vruntime_A = 1001
Tick 93: B ์คํ (1001 > 1000์ด๋ฏ๋ก) โ vruntime_B = 1000+1000 = 2000
๊ฒฐ๊ณผ: A๊ฐ 91 ticks, B๊ฐ 1 tick ์คํ
๋น์จ: 91:1 โ weight ๋น์จ (88761:1024 โ 87:1)
vruntime์ ๋ชจ๋ ์ค๋ ๋๋ฅผ "๊ฐ์์ ๊ณตํํ ์ฒ๋"๋ก ๋ณํํฉ๋๋ค. ์ค์ ์คํ ์๊ฐ์ ๋ค๋ฅด์ง๋ง, vruntime์ ๊ฑฐ์ ๊ฐ์ ์๋๋ก ์ฆ๊ฐํ๋๋ก ์กฐ์ ๋ฉ๋๋ค.
Linux PRIO_TO_WEIGHT ํ ์ด๋ธ: CFS๋ Linux ์ปค๋๊ณผ ์ ํํ ๋์ผํ ๊ฐ์ค์น ํ ์ด๋ธ์ ์ฌ์ฉํฉ๋๋ค:
[88761, 71755, 56483, 46273, 36291, # nice -20 ~ -16
29154, 23254, 18705, 14949, 11916, # nice -15 ~ -11
9548, 7620, 6100, 4904, 3906, # nice -10 ~ -6
3121, 2501, 1991, 1586, 1277, # nice -5 ~ -1
1024, # nice 0 (๊ธฐ์ค๊ฐ)
820, 655, 526, 423, 335, # nice 1 ~ 5
272, 215, 172, 137, 110, # nice 6 ~ 10
87, 70, 56, 45, 36, # nice 11 ~ 15
29, 23, 18, 15] # nice 16 ~ 19์ด ํ ์ด๋ธ์ ํต์ฌ์: nice 1 ์ฐจ์ด = ์ฝ 1.25๋ฐฐ ๊ฐ์ค์น ์ฐจ์ด = ์ฝ 10% CPU ์๊ฐ ์ฐจ์ด์ ๋๋ค.
์ฅ์ :
- ์๋ฒฝํ ๊ณต์ ์ฑ: ๋ชจ๋ ์ค๋ ๋๊ฐ weight์ ๋น๋กํ์ฌ ์ ํํ CPU ๋ฐ์
- ๊ฐํ nice ํจ๊ณผ: nice ๊ฐ์ด CPU ์๊ฐ์ ์ง์ ์ ์ผ๋ก ์ํฅ
- ์์ธก ๊ฐ๋ฅ์ฑ: vruntime ๊ณ์ฐ์ด ๋จ์ํ๊ณ ๋ช ํ
๋จ์ :
- I/O ์ฐ๋ ์์: I/O ๋๊ธฐ ์ค์๋ vruntime์ ์ฆ๊ฐํ์ง ์์ง๋ง, ํน๋ณํ ์ฐ๋ํ์ง๋ ์์
- ์ฝ๊ฐ์ ์ค๋ฒํค๋: ๋งค tick๋ง๋ค vruntime ๊ณ์ฐ ๋ฐ ์ฌ์ ๋ ฌ ํ์
์ค์ ์ฌ์ฉ์ฒ: Linux 2.6.23 ์ดํ ๊ธฐ๋ณธ ์ค์ผ์ค๋ฌ. ๋ฐ์คํฌํฑ, ์๋ฒ, ๋ชจ๋ฐ์ผ ๋ฑ ๊ฑฐ์ ๋ชจ๋ Linux ์์คํ .
์ด ์กฐํฉ์ ๋ณต์ก๋์ ์คํํธ๋ผ(Basic โ MLFQS โ CFS)์ ์ ํํํ๋ฉด์๋, ๊ฐ๊ฐ์ด ์ค์ ์ด์์ฒด์ ์์ ์ฌ์ฉ๋๋ ๊ฒ์ฆ๋ ์๊ณ ๋ฆฌ์ฆ์ด๋ผ๋ ์ ์์ ์๋ฏธ๊ฐ ์์์ต๋๋ค.
์ฒ์ ๋ฒค์น๋งํฌ๋ฅผ ์คํํ์ ๋ ๋ชจ๋ ์ค์ผ์ค๋ฌ๊ฐ ์ ํํ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋์ต๋๋ค. ํ๊ท ๋๊ธฐ ์๊ฐ, ๋ฐํ ์๊ฐ, ๊ณต์ ์ฑ ์ง์ ๋ชจ๋ ๋์ผ. ๊ฐ์ ์จ์ ๋ชจ๋ 0%, ์น์๋ ํญ์ tie.
๋๋ฒ๊น ์ ์์ํ์ต๋๋ค. ๊ฐ ์ค์ผ์ค๋ฌ์ pick_next() ํจ์๋ ์ ๋๋ก ์๋ํ์ต๋๋ค. ์ฐ์ ์์ ๊ณ์ฐ๋ ์ ์์ด์์ต๋๋ค. ๋ฌธ์ ๋ ์๋ฎฌ๋ ์ดํฐ์ ์์์ต๋๋ค.
# ๋ฌธ์ ๊ฐ ์๋ ์ด๊ธฐ ์ฝ๋
while not scheduler.is_empty():
thread = scheduler.pick_next()
# ์ค๋ ๋๊ฐ ์๋ฃ๋ ๋๊น์ง ๊ณ์ ์คํ!
while thread.remaining_time > 0:
thread.remaining_time -= 1
current_tick += 1
# ์๋ฃ๋ ์ค๋ ๋ ์ฒ๋ฆฌ์ค๋ ๋๊ฐ ์๋ฃ๋ ๋๊น์ง ๊ณ์ ์คํ๋๊ณ ์์์ต๋๋ค. ์ ์ (preemption)์ด ์ ํ ์ผ์ด๋์ง ์์๋ ๊ฒ์ ๋๋ค. ์๋ฎฌ๋ ์ดํฐ์ time slice ๊ฐ๋ ์์ฒด๊ฐ ์์์ต๋๋ค.
์ด๊ฒ์ ์น๋ช ์ ์ธ ์ค๋ฅ์์ต๋๋ค. Round-robin์ ํต์ฌ์ time slice์ธ๋ฐ, ์ด๊ฒ ์์ด๋ ๋ชจ๋ ์ค์ผ์ค๋ฌ๊ฐ ์ฌ์ค์ FCFS(First-Come, First-Served)๋ก ๋์ํ๊ฒ ๋ฉ๋๋ค.
- Time slice ์์ ์ ์:
TIME_SLICE = 4 ticks - ํ์ฌ time slice ์ถ์ :
current_slice_remaining๋ณ์ ์ถ๊ฐ - Time slice ๋ง๋ฃ ์ฒ๋ฆฌ: ๋ง๋ฃ ์ thread_yield() ํธ์ถ
# ์์ ๋ ์ฝ๋
TIME_SLICE = 4
while not scheduler.is_empty():
thread = scheduler.pick_next()
current_slice_remaining = TIME_SLICE
while thread.remaining_time > 0 and current_slice_remaining > 0:
# CPU ์ฌ์ฉ
thread.remaining_time -= 1
current_slice_remaining -= 1
current_tick += 1
# I/O ์ฒ๋ฆฌ ๋ฑ...
# Time slice ๋ง๋ฃํ์ง๋ง ์ค๋ ๋๋ ์์ง ์๋ฃ ์ ๋จ
if thread.remaining_time > 0:
scheduler.thread_yield(thread) # ๋ค์ ready queue๋กTime slice๋ฅผ ์ถ๊ฐํ ํ, ๋๋์ด ๊ฐ ์ค์ผ์ค๋ฌ๊ฐ ์๋ก ๋ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ด๊ธฐ ์์ํ์ต๋๋ค. ์์ ์ ์๋ ๋ชจ๋ ์ค์ผ์ค๋ฌ์ ๊ฒฐ๊ณผ๊ฐ ๋์ผํ์ง๋ง, ์์ ํ์๋ ๊ฐ ์ค์ผ์ค๋ฌ๊ฐ ์์ ๋ง์ ํน์ฑ์ ๋ฐ๋ผ ๋ค๋ฅธ ์ฑ๋ฅ์ ๋ณด์ฌ์ฃผ์์ต๋๋ค.
- ์ด๋ก ๊ณผ ๊ตฌํ์ ๊ดด๋ฆฌ: ์ด๋ก ์์๋ "Round-robin์ time slice๋ฅผ ์ฌ์ฉํ๋ค"๊ฐ ๋น์ฐํ์ง๋ง, ๊ตฌํ์์๋ ๋ช ์์ ์ผ๋ก ์ถ๊ฐํด์ผ ํฉ๋๋ค.
- ํ ์คํธ์ ์ค์์ฑ: "๋ชจ๋ ๊ฐ๋ค"๋ ๊ฒ์ ๋ช ๋ฐฑํ ์ด์ํ ๊ฒฐ๊ณผ์๊ณ , ์ด๋ฅผ ๋ฏผ๊ฐํ๊ฒ ๊ฐ์งํ ๊ฒ์ด ๋ฒ๊ทธ ๋ฐ๊ฒฌ์ ์์์ด์์ต๋๋ค.
CFS๋ฅผ ๊ตฌํํ๊ณ ํ ์คํธํ์ ๋, ์ด์ํ ํ์์ด ๋ฐ์ํ์ต๋๋ค. ๋ชจ๋ ์ค๋ ๋์ vruntime์ด ํญ์ 0์ด์์ต๋๋ค:
Thread 1 (nice -20, weight 88761): vruntime=0
Thread 2 (nice 0, weight 1024): vruntime=0
Thread 3 (nice 19, weight 15): vruntime=0nice ๊ฐ์ด ๊ทน๋จ์ ์ผ๋ก ๋ค๋ฅธ๋ฐ๋ vruntime์ด ๋ชจ๋ 0์ผ๋ก ๋์ผํ์ต๋๋ค. ์ด๊ฒ์ CFS์ ํต์ฌ ๋ฉ์ปค๋์ฆ์ด ์๋ํ์ง ์๋๋ค๋ ์๋ฏธ์์ต๋๋ค.
๋ฌธ์ ๋ delta vruntime ๊ณ์ฐ ํจ์์ ์์์ต๋๋ค:
# Linux ์ปค๋ ์คํ์ผ ๊ณต์ (์ด๋ก )
delta_vruntime = delta_exec * (NICE_0_WEIGHT / weight)
# ์๋ชป๋ ๊ตฌํ (์ ์ ๋๋์
)
def calc_delta_vruntime(delta, weight):
return (delta * 1024) // weightnice -20์ผ ๋ weight๋ 88761์ ๋๋ค. ๊ณ์ฐํด๋ณด๋ฉด:
delta = 1 (1 tick ์คํ)
(1 * 1024) // 88761 = 1024 // 88761 = 0
Python์ //๋ ์ ์ ๋๋์
(floor division)์ด๋ฏ๋ก, 1024๋ฅผ 88761๋ก ๋๋๋ฉด 0์ด ๋ฉ๋๋ค!
์ด๊ฒ์ nice -20(์ต๊ณ ์ฐ์ ์์)์ผ ๋ vruntime์ด ์ ํ ์ฆ๊ฐํ์ง ์๋๋ค๋ ์๋ฏธ์ ๋๋ค. ๋ฐ๋๋ก nice 19(์ต์ ์ฐ์ ์์)์ผ ๋๋:
(1 * 1024) // 15 = 68
ํ์ง๋ง ์ด๊ฒ๋ ์ด๋ก ๊ฐ(68266)๊ณผ๋ ํฌ๊ฒ ๋ค๋ฆ ๋๋ค.
์ ๋ฐ๋๋ฅผ ํ๋ณดํ๊ธฐ ์ํด 1000๋ฐฐ ์ค์ผ์ผ์ ์ฆ๊ฐ์์ผฐ์ต๋๋ค:
# ์์ ๋ ์ฝ๋
def calc_delta_vruntime(delta, weight):
# 1000๋ฐฐ ์ค์ผ์ผ ์ฆ๊ฐ๋ก ์ ๋ฐ๋ ํ๋ณด
return (delta * 1024 * 1000) // weight์ด์ ๊ณ์ฐํด๋ณด๋ฉด:
nice -20 (weight 88761):
(1 * 1024 * 1000) // 88761 = 1,024,000 // 88761 = 11
nice 0 (weight 1024):
(1 * 1024 * 1000) // 1024 = 1,024,000 // 1024 = 1000
nice 19 (weight 15):
(1 * 1024 * 1000) // 15 = 1,024,000 // 15 = 68,266
์ด๋ก ์ ์ผ๋ก nice -20๊ณผ nice 19์ CPU ์๊ฐ ๋น์จ์:
weight(-20) / weight(19) = 88761 / 15 โ 5917:1
vruntime ์ฆ๊ฐ ๋น์จ์ ๊ทธ ์ญ์์ด๋ฏ๋ก:
delta_vruntime(19) / delta_vruntime(-20) = 68266 / 11 โ 6206
์ด๋ ์ด๋ก ๊ฐ๊ณผ ๋งค์ฐ ๊ฐ๊น์ต๋๋ค.
Before fix:
All threads: vruntime=0 (no differentiation)
CFS behaves like FIFO
After fix:
nice -20: vruntime += 11/tick (๋งค์ฐ ๋๋ฆฌ๊ฒ ์ฆ๊ฐ)
nice 19: vruntime += 68266/tick (๋งค์ฐ ๋น ๋ฅด๊ฒ ์ฆ๊ฐ)
โ nice -20 ์ค๋ ๋๊ฐ ํจ์ฌ ์์ฃผ ์ ํ๋จ (์๋๋๋ก!)
- ์ ์ ์ฐ์ฐ์ ํจ์ : Python๋
//๋ ์ ์ ๋๋์ ์ ๋๋ค. ๋ถ๋์์์ ์ ํผํ๋ฉด์ ์ ๋ฐ๋๋ฅผ ์ ์งํ๋ ค๋ฉด ์ถฉ๋ถํ ํฐ ์ค์ผ์ผ์ด ํ์ํฉ๋๋ค. - Linux ์ปค๋์ ์งํ: ์ค์ Linux ์ปค๋๋
NICE_0_LOAD = 1024๋ฅผ ์ฌ์ฉํ๋ฉฐ, ์ด๋ ์ ๋ฐ๋์ ์ฑ๋ฅ์ ๊ท ํ์ ๋๋ค. - ์ด๋ก vs ๊ตฌํ: ์ํ์ ์ผ๋ก๋
delta / weight์ง๋ง, ์ปดํจํฐ์์๋(delta * scale) // weight๋ก ๋ณํํด์ผ ํฉ๋๋ค. - ๊ณ ์ ์์์ ์ฐ์ฐ: ์ด์์ฒด์ ๋ ๋ถ๋์์์ ์ ํผํ๊ณ , ๋์ ๊ณ ์ ๋ ์ค์ผ์ผ์ ์ฌ์ฉํฉ๋๋ค (MLFQS์ 17.14, CFS์ 1024ร1000).
"Nice ํจ๊ณผ ํ ์คํธ"๋ฅผ ์คํํ์ ๋, MLFQS์ ๊ฒฐ๊ณผ๊ฐ ์ด์ํ์ต๋๋ค:
Expected: nice -20 vs nice 19 โ CPU time ratio ~1000:1
Actual: CPU time ratio = 1:1
CFS๋ ์ ๋๋ก ์๋ํ๋๋ฐ, MLFQS๋ง 1:1์ด์์ต๋๋ค.
MLFQS ์ฝ๋๋ฅผ ๋๋ฒ๊น
ํ๋ ์ค, add_thread() ํจ์์์ ์ถฉ๊ฒฉ์ ์ธ ๋ฐ๊ฒฌ์ ํ์ต๋๋ค:
# MLFQS์ add_thread() ์ฝ๋
def add_thread(self, thread):
thread.nice = 0 # โ ์ด ๋ผ์ธ!
thread.recent_cpu = 0
thread.priority = self.PRI_MAX
self.queues[thread.priority].append(thread)์ํฌ๋ก๋ ์์ฑ ์ ์ค์ ํ nice ๊ฐ(-20, 19)์ด ์ค์ผ์ค๋ฌ ์ถ๊ฐ ์ ๋ชจ๋ 0์ผ๋ก ๋ฎ์ด์จ์ง๊ณ ์์์ต๋๋ค!
์ด๊ฒ์ ์ ์ค์์์ต๋๋ค. recent_cpu์ priority๋ ์ด๊ธฐํํด์ผ ํ์ง๋ง, nice๋ ์ํฌ๋ก๋์์ ์ค์ ํ ๊ฐ์ ๋ณด์กดํด์ผ ํฉ๋๋ค.
# ์์ ๋ ์ฝ๋
def add_thread(self, thread):
# thread.nice = 0 โ ์ด ๋ผ์ธ ์ ๊ฑฐ!
if thread.recent_cpu is None:
thread.recent_cpu = 0
thread.priority = self.PRI_MAX - (thread.recent_cpu // 4) - (thread.nice * 2)
self.queues[thread.priority].append(thread)Before: CPU time ratio = 1:1 (๋ชจ๋ ์ค๋ ๋ nice=0์ด๋ฏ๋ก)
After: CPU time ratio์์ nice -20๊ณผ nice 19์ ๊ทน๋จ์ ์ฐจ์ด ๋ฐ์
- ์ด๊ธฐํ vs ๋ณด์กด: ์ด๋ค ๊ฐ์ ์ด๊ธฐํํด์ผ ํ๊ณ (recent_cpu, priority), ์ด๋ค ๊ฐ์ ๋ณด์กดํด์ผ ํฉ๋๋ค(nice, burst_time).
- ์ฑ ์์ ๋ถ๋ฆฌ: ์ํฌ๋ก๋ ์์ฑ๊ธฐ๋ ์ค๋ ๋์ ํน์ฑ(nice, burst_time)์ ์ค์ ํ๊ณ , ์ค์ผ์ค๋ฌ๋ ์ด๋ฅผ ์กด์คํ๋ฉฐ ์์ ์ ๋ด๋ถ ์ํ(recent_cpu, priority)๋ง ๊ด๋ฆฌํด์ผ ํฉ๋๋ค.
- ํ ์คํธ์ ์ค์์ฑ: Nice ํจ๊ณผ ํ ์คํธ๊ฐ ์์๋ค๋ฉด ์ด ๋ฒ๊ทธ๋ฅผ ๋ฐ๊ฒฌํ์ง ๋ชปํ์ ๊ฒ์ ๋๋ค.
MLFQS Nice ๋ฒ๊ทธ๋ฅผ ์์ ํ ํ์๋ ์ฌ์ ํ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค. CPU time ratio๊ฐ 1:1๋ก ๋์์ต๋๋ค.
๋ฌธ์ ๋ ์ธก์ ๋ฐฉ๋ฒ์ ์์์ต๋๋ค. ์๋ฎฌ๋ ์ด์ ์ด ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋ฉด, ๋ชจ๋ ์ค๋ ๋๊ฐ ์๋ฃ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ฉด:
Thread 1 (nice -20, burst_time=300): cpu_time=300 (์๋ฃ)
Thread 2 (nice 19, burst_time=300): cpu_time=300 (์๋ฃ)
Ratio: 300/300 = 1:1
๊ฐ ์ค๋ ๋๋ ์ ํํ burst_time๋งํผ CPU๋ฅผ ์ฌ์ฉํฉ๋๋ค. nice ๊ฐ๊ณผ ๋ฌด๊ดํ๊ฒ!
Nice๋ "์ผ๋ง๋ ๋นจ๋ฆฌ ์๋ฃ๋๋๊ฐ"์ ์ํฅ์ ์ฃผ์ง, "์ต์ข CPU ์๊ฐ"์๋ ์ํฅ์ ์ฃผ์ง ์์ต๋๋ค.
nice -20 ์ค๋ ๋๋ 1000 tick์ ์๋ฃ๋๊ณ , nice 19 ์ค๋ ๋๋ 10000 tick์ ์๋ฃ๋์ง๋ง, ๋ ๋ค ์ต์ข ์ ์ผ๋ก๋ burst_time๋งํผ CPU๋ฅผ ์ฌ์ฉํฉ๋๋ค.
Nice ํจ๊ณผ๋ฅผ ์ธก์ ํ๋ ค๋ฉด ์ผ๋ถ๋ง ์๋ฃํด์ผ ํฉ๋๋ค:
- burst_time ์ฆ๊ฐ: 300 โ 2,000 (MLFQS ์ฑ๋ฅ ๊ณ ๋ ค)
- ์๋ฎฌ๋ ์ด์ ์กฐ๊ธฐ ์ข ๋ฃ: 20% ์๊ฐ์ ์ค๋จ (max_ticks=20,000)
# app.py์ ์ถ๊ฐ๋ ์ฝ๋
if selected_test.test_id == "nice_effect":
total_work = sum(t.burst_time for t in base_threads)
actual_max_ticks = int(total_work * 0.5) # 50% ์๊ฐ๋ง ์คํ
st.info(f"Nice ํจ๊ณผ ์ธก์ : {actual_max_ticks:,} ticks์์ ์ค๋จ")์ด๋ ๊ฒ ํ๋ฉด:
nice -20 ์ค๋ ๋: ๋๋ถ๋ถ ์๋ฃ
nice 19 ์ค๋ ๋: ๊ฑฐ์ ์์ ์ ํจ
โ CPU time ratio์์ ํฐ ์ฐจ์ด ๋ฐ์
MLFQS๋ ๋งค์ฐ ๊ฐํ nice ํจ๊ณผ๋ฅผ, CFS๋ ๊ฐ์ค์น ๋น๋ก ๋ฐฐ๋ถ์ ๋ณด์.
- ์ธก์ ๋ฐฉ๋ฒ๋ก ์ ์ค์์ฑ: "๋ฌด์์ ์ธก์ ํ ๊ฒ์ธ๊ฐ"๋งํผ "์ด๋ป๊ฒ ์ธก์ ํ ๊ฒ์ธ๊ฐ"๋ ์ค์ํฉ๋๋ค.
- ์๋ฃ vs ์งํ ์ค: Nice ํจ๊ณผ๋ "์งํ ์ค"์ผ ๋ ๋๋ฌ๋๋ฏ๋ก, ์๋์ ์ผ๋ก ์ค๋จํด์ผ ํฉ๋๋ค.
- ์ด๋ก ๊ณผ ์คํ์ ์ฐจ์ด: ์ด๋ก ๊ฐ๊ณผ ์ค์ ๊ฐ์ ์ฐจ์ด๋ ์ปจํ ์คํธ ์ค์์น ์ค๋ฒํค๋, time slice ํฌ๊ธฐ ๋ฑ ์ค์ ํ๊ฒฝ์ ์ํฅ์ ๋๋ค.
ํ ์คํธ๋ฅผ ๋ฐ๋ณตํ๋ ์ค, Basic Priority๊ฐ ์ด์ํ๊ฒ ์์ฃผ ์น๋ฆฌํ์ต๋๋ค. MLFQS๋ CFS๋ณด๋ค ๊ฑฐ์ ํญ์ ๋น ๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์์ต๋๋ค.
์ด๊ฒ์ ์์ฌ์ค๋ฌ์ ์ต๋๋ค. Basic Priority๋ ๊ฐ์ฅ ๋จ์ํ ์ค์ผ์ค๋ฌ์ธ๋ฐ, ์ ํญ์ ์ด๊ธธ๊น์?
Basic Priority์ pick_next() ํจ์๋ฅผ ์์ธํ ์ดํด๋ดค์ต๋๋ค:
# ๋ฌธ์ ๊ฐ ์๋ ์ฝ๋
def pick_next(self):
if not self.ready_queue:
return None
thread = max(self.ready_queue, key=lambda t: (t.priority, -t.tid))
self.ready_queue.remove(thread)
return thread์ด ์ฝ๋๋ "๊ฐ์ ์ฐ์ ์์ ์ค TID๊ฐ ๊ฐ์ฅ ์์ ๊ฒ"์ ์ ํํฉ๋๋ค. ํ์ง๋ง ์ด๊ฒ์ FIFO๊ฐ ์๋๋๋ค!
์์๋ก ์ค๋ช ํ๋ฉด:
Scenario 1:
Ready queue: [Thread 1 (pri=31), Thread 5 (pri=31), Thread 3 (pri=31)]
Expected (FIFO): Thread 1 ์ ํ (๋จผ์ ๋ค์ด์ด)
Actual: Thread 1 ์ ํ (TID ์ต์, ์ฐ์ฐํ ์ผ์น)
Scenario 2:
Ready queue: [Thread 5 (pri=31), Thread 1 (pri=31), Thread 3 (pri=31)]
Expected (FIFO): Thread 5 ์ ํ (๋จผ์ ๋ค์ด์ด)
Actual: Thread 1 ์ ํ โ ์๋ชป๋จ!
TID๊ฐ ์๋ค๊ณ ๋จผ์ ๋์ฐฉํ ๊ฒ์ด ์๋๋๋ค. TID๋ ์ค๋ ๋ ์์ฑ ์์์ผ ๋ฟ, ready queue ์ฝ์ ์์์๋ ๋ค๋ฆ ๋๋ค.
์ด ๋ฒ๊ทธ๋ก ์ธํด ํน์ ์ํฌ๋ก๋์์ Basic Priority๊ฐ ์ฐ์ฐํ ์ ๋ฆฌํ ์์๋ก ์ค๋ ๋๋ฅผ ์ ํํ๊ณ , ๊ฒฐ๊ณผ์ ์ผ๋ก ๋ ์ข์ ์ฑ๋ฅ์ ๋ณด์ธ ๊ฒ์ ๋๋ค.
# ์์ ๋ ์ฝ๋
def pick_next(self):
if not self.ready_queue:
return None
# 1. ์ต๊ณ ์ฐ์ ์์ ์ฐพ๊ธฐ
max_priority = max(t.priority for t in self.ready_queue)
# 2. ๊ฐ์ ์ฐ์ ์์ ์ค ์ฒซ ๋ฒ์งธ ์ ํ (์ง์ง FIFO)
for thread in self.ready_queue:
if thread.priority == max_priority:
self.ready_queue.remove(thread)
return thread
return NonePython list๋ ์ฝ์ ์์๋ฅผ ์ ์งํ๋ฏ๋ก, ์ํํ๋ฉด์ ์ฒซ ๋ฒ์งธ๋ก ์ผ์นํ๋ ๊ฒ์ ์ฐพ์ผ๋ฉด FIFO๊ฐ ๋ณด์ฅ๋ฉ๋๋ค.
์์ ํ, Basic์ ๋ถ๋นํ ์ด์ ์ด ์ ๊ฑฐ๋์๊ณ ๊ฐ ์ค์ผ์ค๋ฌ๊ฐ ์์ ์ ์ง์ง ๊ฐ์ ์์๋ง ์น๋ฆฌํ๊ฒ ๋์์ต๋๋ค.
- FIFO์ ์ ํํ ์๋ฏธ: FIFO๋ "First-In, First-Out"์ด๋ฉฐ, ์ด๊ฒ์ TID๊ฐ ์๋๋ผ ํ ์ฝ์ ์์๋ฅผ ์๋ฏธํฉ๋๋ค.
- Python list์ ํน์ฑ: list๋ ์ฝ์
์์๋ฅผ ์ ์งํ๊ณ ,
remove()๋ ์ฒซ ๋ฒ์งธ ์ผ์น ํญ๋ชฉ์ ์ ๊ฑฐํฉ๋๋ค. - ์ฐ์ฐํ ์น๋ฆฌ๋ ์์ฌ: ํ ์๊ณ ๋ฆฌ์ฆ์ด ์๋์ ์ผ๋ก ์ด๊ธฐ๋ฉด, ๊ตฌํ ๋ฒ๊ทธ์ผ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค.
- ๊ณต์ ํ ํ ์คํธ: ๋ฒ๊ทธ๋ฅผ ์์ ํ ํ์์ผ ๋น๋ก์ "๊ณต์ ํ ๋น๊ต"๊ฐ ๊ฐ๋ฅํ์ต๋๋ค.
ํ์ฅ์ฑ ํ
์คํธ๋ฅผ ์คํํ์ ๋, ์ฃผ์ ๋ฉํธ๋ฆญ์ธ context_switches๊ฐ ํญ์ 0์ผ๋ก ๋์์ต๋๋ค:
10 threads: context_switches=0
100 threads: context_switches=0
500 threads: context_switches=0
- ์นด์ดํธ ๋ฏธ์ ๋ฌ: ์๋ฎฌ๋ ์ดํฐ๊ฐ ์ปจํ ์คํธ ์ค์์น๋ฅผ ์นด์ดํธํ์ง ์์
- ์ด์ ์ค๋ ๋ ๋ฏธ์ถ์ : "์ด์ ์ค๋ ๋ โ ํ์ฌ ์ค๋ ๋"๋ฅผ ๊ฐ์งํ ๋ฐฉ๋ฒ์ด ์์
# ๋ฌธ์ ๊ฐ ์๋ ์ฝ๋
def run(self, max_ticks):
while current_tick < max_ticks and not self.scheduler.is_empty():
thread = self.scheduler.pick_next()
# ์ฌ๊ธฐ์ ์ปจํ
์คํธ ์ค์์น๊ฐ ๋ฐ์ํ๋์ง ์ ์ ์์!
...# ์์ ๋ ์ฝ๋
class Simulator:
def __init__(self, scheduler, threads):
self.scheduler = scheduler
self.prev_running_tid = None # ์ด์ ์คํ ์ค๋ ๋ ์ถ์
self.total_context_switches = 0
def run(self, max_ticks):
current_tick = 0
while current_tick < max_ticks and not self.scheduler.is_empty():
thread = self.scheduler.pick_next()
# ์ปจํ
์คํธ ์ค์์น ๊ฐ์ง
if self.prev_running_tid is not None and \
self.prev_running_tid != thread.tid:
self.total_context_switches += 1
self.prev_running_tid = thread.tid
# Time slice ์คํ...
# ์๋ฎฌ๋ ์ด์
์ข
๋ฃ ์ ๋ชจ๋ ์ค๋ ๋์ ๊ธฐ๋ก
all_threads = (self.scheduler.ready_queue +
self.scheduler.waiting_queue +
[self.scheduler.running] if self.scheduler.running else [])
for t in all_threads:
t.context_switches = self.total_context_switches
return self.create_dataframe()์์ ์ ์๋ context_switches๊ฐ ํญ์ 0์ผ๋ก ๋์์ง๋ง, ์์ ํ์๋ ์๋ฏธ ์๋ ์ธก์ ์ด ๊ฐ๋ฅํด์ก์ต๋๋ค. CFS๊ฐ ์ฝ๊ฐ ๋ ๋ง์ ์ปจํ ์คํธ ์ค์์น๋ฅผ ๋ฐ์์ํค์ง๋ง, ์ฐจ์ด๋ ํฌ์ง ์์ต๋๋ค.
- ์ํ ์ถ์ : ์ปจํ ์คํธ ์ค์์น๋ "์ด์ ์ค๋ ๋ โ ํ์ฌ ์ค๋ ๋"๋ก ๊ฐ์งํด์ผ ํฉ๋๋ค.
- ๋ฉํธ๋ฆญ ์ ํ: ์๋ฎฌ๋ ์ดํฐ๊ฐ ์ธก์ ํ ๊ฐ์ ์ค๋ ๋ ๊ฐ์ฒด์ ์ ๋ฌํด์ผ ๋ถ์ ๋จ๊ณ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ์ธํ๋ผ์ ์ค์์ฑ: ์๊ณ ๋ฆฌ์ฆ๋ง ์ค์ํ ๊ฒ์ด ์๋๋ผ, ์ด๋ฅผ ์ธก์ ํ๋ ์ธํ๋ผ(์๋ฎฌ๋ ์ดํฐ, ๋ฉํธ๋ฆญ ์์ง)๋ ์ ํํด์ผ ํฉ๋๋ค.
@dataclass
class Test:
test_id: str
name: str
schedulers: List[str] # ๋น๊ตํ ์ค์ผ์ค๋ฌ ๋ช
์
workload_type: str
thread_count: int
goal: str
primary_metric: str
description: str# ๊ณต์ ์ฑ ํ
์คํธ: MLFQS vs CFS๋ง (Nice ์ฐจ์ด๊ฐ ์๋ ์ํฌ๋ก๋)
Test(
test_id="fairness_mixed",
name="๊ณต์ ์ฑ: ํผํฉ ์ํฌ๋ก๋",
schedulers=["mlfqs", "cfs"], # Basic ์ ์ธ!
workload_type="mixed",
goal="๊ณต์ ํ CPU ๋ฐฐ๋ถ",
primary_metric="fairness",
description="..."
)
# ์ผ๋ฐ ์ํฌ๋ก๋: 3๊ฐ ๋ชจ๋
Test(
test_id="general_mixed",
name="์ผ๋ฐ ํผํฉ ์ํฌ๋ก๋",
schedulers=["basic", "mlfqs", "cfs"], # ๋ชจ๋ ํฌํจ
workload_type="mixed",
goal="๋ค์ํ ์์
์ ์ ๋ฐ์ ์ฑ๋ฅ",
primary_metric="avg_wait"
)- ์ผ๋ฐ ์ํฌ๋ก๋: 3๊ฐ ร 3-way = 9๊ฐ
- ์ค์ ์์ฉ: 4๊ฐ ร 3-way = 12๊ฐ
- ๊ณต์ ์ฑ: 2๊ฐ ร 2-way = 4๊ฐ
- ์ผ๊ด์ฑ: 4๊ฐ ร 3-way = 12๊ฐ
- Nice ํจ๊ณผ: 1๊ฐ ร 2-way = 2๊ฐ
- ํ์ฅ์ฑ: 3๊ฐ ร 3-way = 9๊ฐ
- ์ด 48๊ฐ ๋น๊ต (17๊ฐ ํ ์คํธ)
ํ๋ก์ ํธ ์ค๊ฐ์ ์ค์ค๋ก์๊ฒ ๋ฌผ์์ต๋๋ค: "burst_time์ vruntime์ด๋ priority์ ๋ง๊ฒ ๋์ ์ผ๋ก ์กฐ์ ํด์ผ ํ๋?"
์ด์ :
burst_time์ "์ค์ ๋ก ํ์ํ ์์
๋"์ ๋ํ๋
๋๋ค. ์๋ฅผ ๋ค์ด:
- ์ปดํ์ผ ์์ : burst_time = 1000 (1000 ticks์ CPU ํ์)
- ์งง์ ์ฟผ๋ฆฌ: burst_time = 50
ํ๋ก์ธ์ค๊ฐ ์๋ฃํ๋ ค๋ฉด ์ ํํ burst_time๋งํผ์ CPU๊ฐ ํ์ํฉ๋๋ค. ์ค์ผ์ค๋ฌ๋ ์ด๋ฅผ ์ด๋ป๊ฒ ๋ฐฐ๋ถํ ์ง ๊ฒฐ์ ํ ๋ฟ, ์์ ๋ ์์ฒด๋ ๋ณํ์ง ์์ต๋๋ค.
๋น์ :
burst_time = ํ์ผ ํฌ๊ธฐ (100MB)
scheduler = ์ ์ก ์์ ๋ฐ ๋์ญํญ ๊ฒฐ์
ํ์ผ ํฌ๊ธฐ๋ ๊ณ ์ ์ด๊ณ , ์ค์ผ์ค๋ฌ๋:
- ์ด๋ ํ์ผ์ ๋จผ์ ์ ์กํ ์ง (pick_next)
- ๊ฐ ํ์ผ์ ์ผ๋ง๋ ๋นจ๋ฆฌ ์ ์กํ ์ง (nice, priority)
๋ฅผ ๊ฒฐ์ ํ ๋ฟ์
๋๋ค.
์์ ๋์ ๋ฐ๊พธ์ง ๋ง๊ณ , ์ธก์ ์์ ์ ๋ฐ๊ฟ๋๋ค:
- ๋ชจ๋ ์ค๋ ๋ ์๋ฃ ํ ์ธก์ : Nice ํจ๊ณผ ์ธก์ ๋ถ๊ฐ (๋ชจ๋ burst_time๋งํผ ์ฌ์ฉ)
- 50% ์๊ฐ์ ์ค๋จ: Nice ํจ๊ณผ ๋ช ํํ ๋๋ฌ๋จ
์ด๊ฒ์ด Nice ํจ๊ณผ ํ ์คํธ์์ ์๋ฎฌ๋ ์ด์ ์ ์กฐ๊ธฐ ์ข ๋ฃํ ์ด์ ์ ๋๋ค.
์ ํ ์ด์ :
- ๋๋ฌด ์งง์ผ๋ฉด (1-2 ticks): ์ปจํ ์คํธ ์ค์์น ์ค๋ฒํค๋ ๊ณผ๋ค
- ๋๋ฌด ๊ธธ๋ฉด (10+ ticks): ์๋ต์ฑ ์ ํ, I/O bound ์ค๋ ๋ ๋ถ๋ฆฌ
- 4 ticks: ์ผ๋ฐ์ ์ธ Round-robin ์ค์ , Linux ๊ธฐ๋ณธ๊ฐ(4ms)๊ณผ ์ ์ฌ
๊ฒ์ฆ: ์ค์ ๋ก 4 ticks๋ 50๊ฐ ์ค๋ ๋ ํ๊ฒฝ์์ ์ ์ ํ ๊ท ํ์ ๋ณด์ฌ์คฌ์ต๋๋ค. ์ปจํ ์คํธ ์ค์์น๋ ์ถฉ๋ถํ ์์ฃผ ๋ฐ์ํ์ง๋ง(500+ ํ), ์ค๋ฒํค๋๋ ๋ฌด์ํ ์์ค์ด์์ต๋๋ค.
๊ณ์ฐ ๊ทผ๊ฑฐ:
- ํ๊ท burst_time: ~500-600 ticks
- ์ค๋ ๋ ์: 50๊ฐ
- ํ์ํ ์ด CPU: 50 ร 600 = 30,000 ticks
- ์ฌ์ : +5,000 ticks (I/O ๋๊ธฐ, ์ปจํ ์คํธ ์ค์์น ์ค๋ฒํค๋)
์์ธ: Nice ํจ๊ณผ ํ ์คํธ๋ 50% ์๊ฐ(total_work ร 0.5)์ ์ค๋จ
์ ํ ์ด์ :
- ๋๋ฌด ์ ์ผ๋ฉด (10): ์ค์ผ์ค๋ฌ ์ฐจ์ด๊ฐ ๋๋ฌ๋์ง ์์
- ๋๋ฌด ๋ง์ผ๋ฉด (500): ์๋ฎฌ๋ ์ด์ ์๊ฐ ๊ณผ๋ค (10์ด+)
- 50: ์๋ฏธ ์๋ ์ฐจ์ด๋ฅผ ๋ณด์ด๋ฉด์๋ ๋น ๋ฅธ ์คํ (2-3์ด)
ํ์ฅ์ฑ ํ ์คํธ: 10, 100, 500์ผ๋ก ๋ณ๊ฒฝํ์ฌ ์ค์ผ์ผ๋ง ๋ฅ๋ ฅ ์ธก์
- ์ด๋ก : "Round-robin์ time slice๋ฅผ ์ฌ์ฉํ๋ค" (์๋ฌต์ )
- ๊ตฌํ:
TIME_SLICE = 4; current_slice_remaining = TIME_SLICE(๋ช ์์ )
- ์ด๋ก : "๋จผ์ ์จ ๊ฒ์ ๋จผ์ ์ฒ๋ฆฌ" (๋ชจํธํจ)
- ๊ตฌํ: "ready_queue์ ์ฝ์ ์์" (์ ํํจ, TID โ ๋์ฐฉ ์์)
- ์ด๋ก :
delta / weight(์ํ์ ) - ๊ตฌํ:
(delta * 1024 * 1000) // weight(์ ์ ์ฐ์ฐ + ์ค์ผ์ผ)
์ด์์ฒด์ ๋ ์ ๋ถ๋์์์ ์ ํผํ ๊น์?
| ์ธก๋ฉด | ๋ถ๋์์์ (float) | ์ ์ + ์ค์ผ์ผ |
|---|---|---|
| ์ ๋ฐ๋ | ๋์ (ํ์ง๋ง ์์ธก ๋ถ๊ฐ๋ฅ) | ์ถฉ๋ถ (์์ธก ๊ฐ๋ฅ) |
| ์ฑ๋ฅ | ๋๋ฆผ (FPU ํ์) | ๋น ๋ฆ (ALU๋ง) |
| ๊ฒฐ์ ์ฑ | ๋ฎ์ (๋ฐ์ฌ๋ฆผ ์ค์ฐจ) | ๋์ (์ ํ) |
| ์ฌ์ฉ์ฒ | ๊ณผํ ๊ณ์ฐ | ์ค์๊ฐ ์์คํ , OS |
์ค์ ์ฌ์ฉ ์:
-
MLFQS: 17.14 ๊ณ ์ ์์์ (F = 1 << 14 = 16384)
recent_cpu = (2 * load_avg * F) // (2 * load_avg + 1 * F) * recent_cpu // F
-
CFS: 1024 ร 1000 ์ค์ผ์ผ
delta_vruntime = (delta * 1024 * 1000) // weight
| ๋ชฉํ | ์๋ชป๋ ๋ฐฉ๋ฒ | ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ | ์ด์ |
|---|---|---|---|
| Nice ํจ๊ณผ | ๋ชจ๋ ์๋ฃ ํ CPU ์๊ฐ ์ธก์ | 20% ์๊ฐ์ ์ค๋จ | ์๋ฃ๋๋ฉด ๋ชจ๋ burst_time๋งํผ ์ฌ์ฉ (1:1) |
| ๊ณต์ ์ฑ | ๋ชจ๋ ์ค์ผ์ค๋ฌ ๋น๊ต | ๊ณต์ ์ฑ ๋ชฉํ๋ง ๋น๊ต | Basic์ starvation ์ํ (๋ค๋ฅธ ๋ชฉํ) |
| ํ์ฅ์ฑ | ๋จ์ผ ์ค๋ ๋ ์ ํ ์คํธ | 10, 100, 500 ๋น๊ต | ์ค์ผ์ผ๋ง ํจํด์ ๋ณด๋ ค๋ฉด ์ฌ๋ฌ ์ ํ์ |
- ๋ชจ๋ ๊ฒฐ๊ณผ๊ฐ ๊ฐ์ (tie) โ Time slice ๋ฏธ๊ตฌํ
- ํ ์ค์ผ์ค๋ฌ๊ฐ ์๋์ โ ๊ตฌํ ๋ฒ๊ทธ (Basic FIFO)
- ๋ฉํธ๋ฆญ์ด ํญ์ 0 โ ์ธก์ ์ค๋ฅ (vruntime, context_switches)
- ์ด๋ก ๊ณผ ํฌ๊ฒ ๋ค๋ฆ โ ์ธก์ ๋ฐฉ๋ฒ ์ค๋ฅ (Nice ํจ๊ณผ 1:1)
- ๊ด์ฐฐ: ์ด์ํ ๊ฒฐ๊ณผ ์ธ์
- ๊ฐ์ค: "Time slice๊ฐ ์๋?", "์ ์ ๋๋์ ๋ฌธ์ ?"
- ์คํ: print() ๋๋ฒ๊น , ๋จ๊ณ๋ณ ์คํ, ๋จ์ํ๋ ํ ์คํธ
- ๊ฒ์ฆ: ์์ ํ ๊ฒฐ๊ณผ ํ์ธ, ์ด๋ก ๊ฐ๊ณผ ๋น๊ต
๊ฐ ์ค์ผ์ค๋ฌ์ ์ค์ ๋ณต์ก๋:
- ๊ฐ์ฅ ๋จ์ํ์ง๋ง, FIFO ๊ตฌํ๋ ์ฃผ์ ํ์
- ์ฐ์ ์์ ๊ด๋ฆฌ, ์ ์ ์ฒ๋ฆฌ
- 3๊ฐ์ง ์
๋ฐ์ดํธ ์ฃผ๊ธฐ:
- ๋งค tick:
recent_cpu++(์คํ ์ค์ธ ์ค๋ ๋๋ง) - 4 ticks๋ง๋ค:
priority์ฌ๊ณ์ฐ (๋ชจ๋ ์ค๋ ๋) - 100 ticks๋ง๋ค:
load_avg,recent_cpu์ฌ๊ณ์ฐ (๋ชจ๋ ์ค๋ ๋)
- ๋งค tick:
- 17.14 ๊ณ ์ ์์์ ์ฐ์ฐ
- 64๊ฐ ๋ ๋ฆฝ ํ ๊ด๋ฆฌ
- Linux ๊ฐ์ค์น ํ ์ด๋ธ 40๊ฐ ํญ๋ชฉ
- vruntime ์ค์ผ์ผ ์กฐ์ (1024ร1000)
- SortedList๋ก ์๋ ์ ๋ ฌ (Red-Black Tree ๋์ )
- min_vruntime ์ถ์
- ์ด ๋ผ์ธ ์: 2,939์ค
- ํ์ผ ์: 21๊ฐ
- ์ค์ผ์ค๋ฌ ๊ตฌํ:
- Basic Priority: 67์ค
- MLFQS: 250์ค
- CFS: 100์ค
- ์ํฌ๋ก๋: 9๊ฐ์ง ํจํด
- ํ ์คํธ: 18๊ฐ, 6๊ฐ ์นดํ ๊ณ ๋ฆฌ
- ๋ฐ๊ฒฌ: 6๊ฐ major bugs
- ์์ ๋ฅ : 100%
- ์ฌ๋ฐ: 0๊ฐ
์ ์๋ฏธํ ํธํฅ ์์ โ ๊ฐ ์ค์ผ์ค๋ฌ๊ฐ ์์ ์ ๊ฐ์ ์์๋ง ์น๋ฆฌ
- ํ๋ซํผ: GCP VM (Ubuntu 24.04, 16GB RAM, 4 vCPU)
- ์น ํ๋ ์์ํฌ: Streamlit
- ์ ๊ทผ์ฑ: ๊ณต๊ฐ URL (http://34.47.105.226:8501)
- ๊ฐ๋์๊ฐ: systemd ์๋น์ค๋ก 24/7 ์ด์
- ๋คํธ์ํฌ: ํฌํธ 80 โ 8501 ํฌ์๋ฉ (iptables)
-
โ 3๊ฐ์ง ์ค์ผ์ค๋ฌ ๊น์ ์ดํด
- ๋จ์ ์๊ธฐ๊ฐ ์๋ ๊ตฌํ์ ํตํ ์ดํด
- ๊ฐ ์๊ณ ๋ฆฌ์ฆ์ ํธ๋ ์ด๋์คํ ์ฒดํ
-
โ ์ค์ OS ์ฐ๊ฒฐ
- FreeBSD 4.4BSD MLFQS ๊ตฌํ ์ฐธ์กฐ
- Linux CFS PRIO_TO_WEIGHT ํ ์ด๋ธ ๋์ผ ์ฌ์ฉ
- PintOS ๋ฌธ์์ 17.14 ๊ณ ์ ์์์
-
โ ์ ๋์ ๋ถ์ ๋ฅ๋ ฅ
- "๋๋"์ด ์๋ ๋ฉํธ๋ฆญ ๊ธฐ๋ฐ ๋น๊ต
- Jain's Fairness Index, ์ปจํ ์คํธ ์ค์์น ์ ๋ฑ
-
โ ์ค๊ณ ๋ฐฉ๋ฒ๋ก
- ๋ชฉํ ๊ธฐ๋ฐ ํ ์คํธ ์ค๊ณ
- ๊ณต์ ํ ๋น๊ต ๋ฐฉ๋ฒ๋ก
์ด ์น์ ์์๋ ์ค์ ํ ์คํธ ๊ฒฐ๊ณผ์์ ๋ฐ๊ฒฌํ ํฅ๋ฏธ๋ก์ด ํจํด๋ค์ ์์ธํ ๋ถ์ํฉ๋๋ค.
์ธก์ ๊ฒฐ๊ณผ: MLFQS๋ ๋งค์ฐ ๊ฐํ nice ํจ๊ณผ๋ฅผ, CFS๋ ๊ฐ์ค์น ๋น๋ก ๋ฐฐ๋ถ์ ๋ณด์.
์ MLFQS๊ฐ ํจ์ฌ ๊ทน๋จ์ ์ธ๊ฐ?
MLFQS์ ์ฐ์ ์์ ๊ณต์์ ๋ค์ ์ดํด๋ณด๋ฉด:
priority = 63 - (recent_cpu / 4) - (nice * 2)
nice -20 ์ค๋ ๋:
- ์ด๊ธฐ: priority = 63 - 0 - (-20*2) = 63 - 0 + 40 = 103 (์ต๋๊ฐ์ผ๋ก clamped โ 63)
- ์คํ ํ: recent_cpu๊ฐ ์ฆ๊ฐํด๋ nice*2 = 40์ด ๋งค์ฐ ํฐ ๋ณด์
- ์: recent_cpu=100์ผ ๋ โ priority = 63 - 25 + 40 = 78 (์ฌ์ ํ ๋งค์ฐ ๋์)
nice 19 ์ค๋ ๋:
- ์ด๊ธฐ: priority = 63 - 0 - (19*2) = 63 - 38 = 25
- ์คํ ํ: recent_cpu=100์ผ ๋ โ priority = 63 - 25 - 38 = 0 (์ต์ )
ํต์ฌ ์ฐจ์ด์ :
- nice -20 ์ค๋ ๋๋ recent_cpu๊ฐ ์ฆ๊ฐํด๋ +40 ๋ณด์ ์ด ์๋์ ์ด์ด์ ์ฐ์ ์์๊ฐ ๊ฑฐ์ ์ ๋จ์ด์ง
- nice 19 ์ค๋ ๋๋ -38 ํ๋ํฐ๋ก ์์ํด์ ์กฐ๊ธ๋ง ์คํํด๋ ์ฐ์ ์์ ๋ฐ๋ฅ
๊ฒฐ๊ณผ: nice -20 ์ค๋ ๋๊ฐ ๊ฑฐ์ ๋ ์ ์ ์ผ๋ก ์คํ๋๊ณ , nice 19 ์ค๋ ๋๋ ๊ฑฐ์ ์คํ ๊ธฐํ๋ฅผ ๋ชป ๋ฐ์.
์ CFS๋ ์ด๋ก ๊ฐ๋ณด๋ค ์ฝํ๊ฐ?
์ด๋ก ์ ์ผ๋ก CFS๋ ์ ํํ weight ๋น์จ๋๋ก CPU๋ฅผ ๋ฐฐ๋ถํด์ผ ํฉ๋๋ค. ํ์ง๋ง ์ค์ ๊ฒฐ๊ณผ๋ ์ด๋ก ๊ฐ๋ณด๋ค ์ฝํฉ๋๋ค.
์์ธ 1: Time Slice ๊ฒฝ๊ณ ํจ๊ณผ
Time slice = 4 ticks
์๋๋ฆฌ์ค:
- nice -20 ์ค๋ ๋๊ฐ 4 ticks ์คํ โ vruntime += 11*4 = 44
- nice 19 ์ค๋ ๋๊ฐ 4 ticks ์คํ โ vruntime += 68266*4 = 273,064
์ด์์ : 44์ 273,064๊ฐ ๊ฐ์์ง ๋๊น์ง nice -20์ด ์คํ
์ค์ : 4 tick ๋จ์๋ก ๋์ด์ง๋ฏ๋ก nice 19๋ ์ต์ 4 ticks๋ ๋ฐ์
nice 19 ์ค๋ ๋๊ฐ "4 tick ๋จ์๋ก ๊ฐ์ ์คํ"๋๋ฉด์ ์์๋ณด๋ค ๋ง์ CPU๋ฅผ ๋ฐ๊ฒ ๋ฉ๋๋ค.
์์ธ 2: ์๋ฎฌ๋ ์ด์ ์กฐ๊ธฐ ์ข ๋ฃ
Nice ํจ๊ณผ ํ ์คํธ๋ total_work์ 50%์์ ์ค๋จํฉ๋๋ค. ์ด ์์ ์์ nice -20 ์ค๋ ๋๋ ๋๋ถ๋ถ ์๋ฃ๋์ง๋ง, nice 19 ์ค๋ ๋๋ ๊ฑฐ์ ์์๋ ๋ชป ํฉ๋๋ค. ํ์ง๋ง time slice ๋๋ฌธ์ nice 19๋ ์ต์ํ์ ์งํ์ ํ๋ฉด์, ์ด๋ก ๊ฐ๋ณด๋ค ์ฝํด์ง๋๋ค.
์์ธ 3: ์ปจํ ์คํธ ์ค์์น ์ค๋ฒํค๋
๋งค๋ฒ ์ค๋ ๋๋ฅผ ๋ฐ๊ฟ ๋:
- vruntime ๊ณ์ฐ (๋๋์ ์ฐ์ฐ)
- SortedList ์ฌ์ ๋ ฌ
- ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ
์ด ์ค๋ฒํค๋๋ ์ธก์ ๋์ง ์์ง๋ง ์ค์ ๋ก ์๊ฐ์ ์๋ชจํฉ๋๋ค. nice -20์ด ์๋์ ์ผ๋ก ์์ฃผ ์คํ๋๋ฏ๋ก, ์๋์ ์ผ๋ก ์ค๋ฒํค๋์ ์ํฅ์ ๋ ๋ฐ์ต๋๋ค.
๊ฒฐ๋ก : CFS์ ๊ฒฐ๊ณผ๋ "์ด๋ก ๊ฐ๋ณด๋ค ์ฝํ๋ค"๋ ๊ฒ์ด ์๋๋ผ, **"ํ์ค ์ธ๊ณ์ ์ ์ฝ(time slice, ์ค๋ฒํค๋) ์์์ ๋ฌ์ฑํ ๊ฐ๋ ฅํ nice ํจ๊ณผ"**์ ๋๋ค.
์ธ ์ค์ผ์ค๋ฌ๊ฐ ๋น์ทํ ์น๋ฅ ์ ๋ณด์ ๋๋ค. ์ฒ์ ๋ณด๋ ์ฌ๋์ ์ด์ํ๊ฒ ์๊ฐํ ์ ์์ต๋๋ค. "๊ฐ์ฅ ๋จ์ํ Basic์ด ๊ฐ์ฅ ๋ณต์กํ CFS๋งํผ ์ด๊ธด๋ค๊ณ ?"
์ Basic์ด ์น๋ฆฌํ๋๊ฐ?
Basic์ด ์น๋ฆฌํ ํ ์คํธ๋ค์ ๋ถ์ํ๋ฉด:
- CPU-bound ์ํฌ๋ก๋ (์ผ๋ฐ ์ํฌ๋ก๋ ํ ์คํธ ์ค ์ผ๋ถ)
- I/O๊ฐ ๊ฑฐ์ ์๋ ํ ์คํธ
- Nice ๊ฐ์ด ์ฝํ๊ฑฐ๋ ๋์ผํ ๊ฒฝ์ฐ (nice 0 ๋๋ -5~5)
์น๋ฆฌ ์ด์ 1: ์ต์ ์ค๋ฒํค๋
๋งค tick๋ง๋ค ์ํํ๋ ์์
:
Basic Priority:
- pick_next(): O(n) - ready queue ์ ํ ํ์
- ์ฐ์ ์์ ์ฌ๊ณ์ฐ: 0ํ (์ ์ ์ฐ์ ์์)
- ์ถ๊ฐ ์ฐ์ฐ: ์์
MLFQS:
- pick_next(): O(1) - 64๊ฐ ํ์์ ์ฒซ ๋ฒ์งธ ๋น์ด์์ง ์์ ํ
- ๋งค tick: recent_cpu++ (์คํ ์ค์ธ ์ค๋ ๋)
- 4 ticks๋ง๋ค: ๋ชจ๋ ์ค๋ ๋์ priority ์ฌ๊ณ์ฐ (O(n))
- 100 ticks๋ง๋ค: load_avg, recent_cpu ์ฌ๊ณ์ฐ (O(n))
CFS:
- pick_next(): O(log n) - SortedList์์ ์ต์ vruntime
- ๋งค tick: delta_vruntime ๊ณ์ฐ (๋๋์
) + vruntime ์
๋ฐ์ดํธ
- ๋งค yield: SortedList ์ฌ์ ๋ ฌ (O(log n))
์ค๋ ๋ ์๊ฐ 50๊ฐ ์ ๋์ด๊ณ CPU-bound์ผ ๋:
- Basic์ O(n) ์ ํ ํ์: ๋งค์ฐ ๋น ๋ฆ (50๋ฒ ๋น๊ต)
- MLFQS์ ์ฃผ๊ธฐ์ ์ฌ๊ณ์ฐ: 4 ticks๋ง๋ค 50๊ฐ ์ฌ๊ณ์ฐ
- CFS์ ๋ก๊ทธ ์๊ฐ ์ ๋ ฌ: ๋งค๋ฒ log(50) โ 5.6 ๋น๊ต
๋๋ผ์ด ์ : Basic์ ์ ํ ํ์์ด ์ค์ ๋ก๋ ๋งค์ฐ ๋น ๋ฆ ๋๋ค!
- CPU ์บ์ ์นํ์ (์์ฐจ ์ ๊ทผ)
- ๋ถ๊ธฐ ์์ธก ์ฑ๊ณต๋ฅ ๋์
- ์ถ๊ฐ ๊ณ์ฐ ์ ํ ์์
์น๋ฆฌ ์ด์ 2: ์์ธก ๊ฐ๋ฅ์ฑ
Basic์ ์ฐ์ ์์๊ฐ ์ ๋ ์ ๋ณํ๋ฏ๋ก:
์ฒ์: Thread 1(pri=31), Thread 2(pri=31), Thread 3(pri=25)
์คํ ์์: 1 โ 2 โ 1 โ 2 โ 1 โ 2 โ ... โ 3
MLFQS:
์ฒ์: Thread 1(pri=50), Thread 2(pri=50), Thread 3(pri=50)
10 ticks ํ: Thread 1(pri=45), Thread 2(pri=48), Thread 3(pri=47)
20 ticks ํ: Thread 1(pri=40), Thread 2(pri=46), Thread 3(pri=44)
โ ๊ณ์ ๋ณํจ, ์์ธก ๋ถ๊ฐ
์์ธก ๊ฐ๋ฅํ ์์๋ ์บ์ ํํธ์จ์ ๋์ ๋๋ค. ๊ฐ์ ์ค๋ ๋๊ฐ ๊ท์น์ ์ผ๋ก ์คํ๋๋ฉด ํด๋น ์ค๋ ๋์ ๋ฐ์ดํฐ๊ฐ ์บ์์ ๋จ์์์ ํ๋ฅ ์ด ๋์ต๋๋ค.
์น๋ฆฌ ์ด์ 3: Nice ๊ฐ์ด ์ฝํ ๋ ์ฐจ์ด ์์
nice 0์ผ๋ก ๋ชจ๋ ๋์ผํ๊ฑฐ๋, nice -5~5 ๋ฒ์์ผ ๋:
- Basic: priority ์ฐจ์ด ์ต๋ 10 (26~36)
- MLFQS: nice*2 ์ฐจ์ด ์ต๋ 20, ํ์ง๋ง recent_cpu๊ฐ ๋ ํฐ ์ํฅ
- CFS: weight ์ฐจ์ด ์ฝ 3๋ฐฐ, ํ์ง๋ง ์ฌ์ ํ ๋ชจ๋ ๋น์ทํ ์์ค
โ ์ธ ์ค์ผ์ค๋ฌ ๋ชจ๋ ๊ฑฐ์ ๋ผ์ด๋ ๋ก๋น์ฒ๋ผ ๋์ โ ์ค๋ฒํค๋๊ฐ ๊ฐ์ฅ ์ ์ Basic์ด ์น๋ฆฌ
๊ฒฐ๋ก : Basic Priority๊ฐ ์น๋ฆฌํ๋ ๊ฒ์ ๋ฒ๊ทธ๊ฐ ์๋๋ผ, **"ํน์ ์ํฌ๋ก๋(CPU-bound, ์ฝํ nice)์์ ๋จ์ํจ์ด ์ต์ "**์ด๋ผ๋ ๊ตํ์ ๋๋ค. ๊ณผ๋ํ ์ต์ ํ๋ ๋ณต์กํ ๊ณต์ ์ฑ์ด ์คํ๋ ค ์ฑ๋ฅ์ ํด์น ์ ์์ต๋๋ค.
์ธก์ ๊ฒฐ๊ณผ (500 ์ค๋ ๋ ํ ์คํธ): CFS๊ฐ ์ฝ๊ฐ ๋ ๋ง์ ์ปจํ ์คํธ ์ค์์น๋ฅผ ๋ฐ์์ํต๋๋ค.
์ CFS๊ฐ ๋ ๋ง์๊ฐ?
์ปจํ ์คํธ ์ค์์น๊ฐ ๋ฐ์ํ๋ ๊ฒฝ์ฐ:
- Time slice ๋ง๋ฃ
- I/O ๋๊ธฐ ์์
- ์ค๋ ๋ ์๋ฃ
CFS์ ํน์ฑ:
vruntime ๊ธฐ๋ฐ ์ ํ โ ํญ์ "๊ฐ์ฅ ๋ ๋ฐ์ ์ค๋ ๋" ์ ํ
์์ (5๊ฐ ์ค๋ ๋):
vruntime: [1000, 1001, 1002, 1003, 1004]
Basic/MLFQS:
- ์ฐ์ ์์๊ฐ ๊ฐ์ผ๋ฉด ๊ฐ์ ์ค๋ ๋๊ฐ ์ฌ๋ฌ time slice ์ฐ์ ์คํ ๊ฐ๋ฅ
- ์: Thread 1์ด 4 slice ์ฐ์ ์คํ โ ์ปจํ
์คํธ ์ค์์น 3ํ ๊ฐ์
CFS:
- ๋งค slice ํ vruntime ์ฆ๊ฐ โ ๋ค์ pick_next()์์ ๋ค๋ฅธ ์ค๋ ๋ ์ ํ๋ ๊ฐ๋ฅ์ฑ ๋์
- Thread 1(vruntime=1000) ์คํ โ vruntime=2000
- ๋ค์: Thread 2(vruntime=1001) ์ ํ (๊ฐ์ฅ ์์)
- Thread 2 ์คํ โ vruntime=2001
- ๋ค์: Thread 3(vruntime=1002) ์ ํ
โ ๋งค๋ฒ ๋ค๋ฅธ ์ค๋ ๋๋ก ์ ํ!
๊ฒฐ๊ณผ: CFS๋ ๊ณต์ ์ฑ์ ์ํด ์ค๋ ๋๋ฅผ ์์ฃผ ๋ฐ๊ฟ๋๋ค โ ์ปจํ ์คํธ ์ค์์น ์ฆ๊ฐ
๊ทธ๋ฐ๋ฐ ์ ์ฐจ์ด๊ฐ ์์๊น?
์ฐจ์ด๊ฐ ์์ ์ด์ ๋:
-
๋๋ถ๋ถ์ ์ปจํ ์คํธ ์ค์์น๋ I/O ๋๋ฌธ
- I/O ๋๊ธฐ ์์ โ ๋ฌด์กฐ๊ฑด ์ปจํ ์คํธ ์ค์์น
- ์ด๊ฒ์ ๋ชจ๋ ์ค์ผ์ค๋ฌ์์ ๋์ผ
-
Time slice๊ฐ ์ถฉ๋ถํ ๊ธธ๋ค (4 ticks)
- ๋๋ฌด ์งง์ผ๋ฉด ๋งค tick๋ง๋ค ์ ํ โ 100% ์ฐจ์ด
- 4 ticks๋ ์ฌ๋ฌ ์ค๋ ๋๊ฐ time slice ๋ด์ ๋น์ทํ progress๋ฅผ ๋ง๋ฆ
-
500๊ฐ ์ค๋ ๋ โ ๋๋ถ๋ถ ๋๊ธฐ ์ค
- Ready queue์ ์๋ ์ค๋ ๋: ํ๊ท 10-20๊ฐ
- ๋๋จธ์ง๋ I/O ๋๊ธฐ ๋๋ ์๋ฃ
- Ready ์ค๋ ๋๊ฐ ์ ์ผ๋ฉด ์ ํ์ง๊ฐ ์ ํ์ โ ์ฐจ์ด ๊ฐ์
๊ฒฐ๋ก : CFS์ ์ฝ๊ฐ ๋ ๋ง์ ์ปจํ ์คํธ ์ค์์น๋ **"๊ณต์ ์ฑ์ ๋๊ฐ๋ก ์ถฉ๋ถํ ๋ฐ์๋ค์ผ ๋งํ ์์ค"**์ ๋๋ค. ๊ฑฐ์ ๋ฌด์ํ ์ ์๋ ์ค๋ฒํค๋์ ๋๋ค.
์ค์ Linux ์์คํ ์์๋ CFS์ ์ปจํ ์คํธ ์ค์์น ์ค๋ฒํค๋๋ ์ธก์ ํ๊ธฐ ์ด๋ ค์ธ ์ ๋๋ก ์์ผ๋ฉฐ, ๊ทธ ๋๊ฐ๋ก ์ป๋ ๊ฐ์ค์น ๊ธฐ๋ฐ ๊ณต์ ์ฑ์ ํจ์ฌ ํฐ ๊ฐ์น๊ฐ ์์ต๋๋ค.
์ธก์ ๊ฒฐ๊ณผ (I/O-bound ํ ์คํธ):
ํ์ฌ ์๋ฎฌ๋ ์ด์ ์์๋ ์ธ ์ค์ผ์ค๋ฌ๊ฐ ์ ์ฌํ ์ฑ๋ฅ์ ๋ณด์ ๋๋ค. ์ด๋ I/O ํจํด์ด ๋จ์ํ๋์ด ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ฐธ๊ณ : ์ค์ Linux ํ๊ฒฝ์์ MLFQS(BSD ์คํ์ผ)๊ฐ I/O-bound ์์
์์ ๊ฐ์ ์ ๋ณด์ด๋ ์ด์ ๋ ์๋์ ์ค๋ช
๋ recent_cpu ๋ฉ์ปค๋์ฆ ๋๋ฌธ์
๋๋ค.
MLFQS์ I/O ์ฐ๋ ๋ฉ์ปค๋์ฆ (์ด๋ก ):
MLFQS์ recent_cpu ๋ฉ์ปค๋์ฆ์ ์ดํดํด์ผ ํฉ๋๋ค:
๋งค tick:
- ์คํ ์ค์ธ ์ค๋ ๋: recent_cpu++
- I/O ๋๊ธฐ ์ค์ธ ์ค๋ ๋: recent_cpu ์ฆ๊ฐ ์ ํจ (๋ณํ ์์)
100 ticks๋ง๋ค:
recent_cpu = (2*load_avg)/(2*load_avg+1) * recent_cpu
โ ๋ชจ๋ ์ค๋ ๋์ recent_cpu ๊ฐ์
์์:
Thread A (CPU-bound):
- 0~100 ticks: ๊ณ์ ์คํ โ recent_cpu = 100
- 100 tick ์์ : recent_cpu = (2*5)/(2*5+1) * 100 โ 91 (์ฝ๊ฐ ๊ฐ์ )
- 101~200 ticks: ๊ณ์ ์คํ โ recent_cpu = 191
- 200 tick ์์ : recent_cpu = 0.91 * 191 โ 174
โ recent_cpu๊ฐ ์ง์์ ์ผ๋ก ๋์
Thread B (I/O-bound, 80% I/O ๋๊ธฐ):
- 0~100 ticks: 20 ticks๋ง ์คํ โ recent_cpu = 20
- 100 tick ์์ : recent_cpu = 0.91 * 20 โ 18
- 101~200 ticks: 20 ticks๋ง ์คํ โ recent_cpu = 38
- 200 tick ์์ : recent_cpu = 0.91 * 38 โ 35
โ recent_cpu๊ฐ ๋ฎ๊ฒ ์ ์ง๋จ
์ฐ์ ์์ ์ฐจ์ด:
priority = 63 - (recent_cpu / 4) - (nice * 2)
Thread A (CPU-bound, recent_cpu=174, nice=0):
priority = 63 - 43 - 0 = 20 (๋ฎ์ ์ฐ์ ์์)
Thread B (I/O-bound, recent_cpu=35, nice=0):
priority = 63 - 8 - 0 = 55 (๋์ ์ฐ์ ์์!)
๊ฒฐ๊ณผ: I/O-bound ์ค๋ ๋๊ฐ I/O ์๋ฃ ํ ready queue์ ๋์์ค๋ฉด:
- MLFQS: ๋์ ์ฐ์ ์์ (55) โ ์ฆ์ ์ ํ๋จ โ ๋น ๋ฅธ ์๋ต
- Basic: ์ ์ ์ฐ์ ์์ (31) โ ๋ค๋ฅธ ์ค๋ ๋๋ค๊ณผ ๋๋ฑ โ ๋๋ฆฐ ์๋ต
- CFS: vruntime ๊ธฐ๋ฐ โ I/O ๋๊ธฐ ์ค vruntime ์ฆ๊ฐ ์ ํ์ผ๋ฏ๋ก ์ฝ๊ฐ ์ ๋ฆฌ, ํ์ง๋ง ๋ช ์์ ์ฐ๋๋ ์์
์ ์ด๊ฒ ์ค์ํ๊ฐ?
I/O-bound ์์ ์ ๋ณดํต ์ฌ์ฉ์ ๋ํํ ์์ ์ ๋๋ค:
- ์น ๋ธ๋ผ์ฐ์ (๋คํธ์ํฌ I/O)
- ํ ์คํธ ์๋ํฐ (ํค๋ณด๋ ์ ๋ ฅ)
- ๋น๋์ค ํ๋ ์ด์ด (ํ์ผ I/O)
์ด๋ฐ ์์ ๋ค์ CPU๋ฅผ ์กฐ๊ธ๋ง ์ฐ๊ณ ๋ฐ๋ก I/O ๋๊ธฐ์ ๋ค์ด๊ฐ๋๋ค. MLFQS๋ ์ด๋ฅผ ์๋์ผ๋ก ๊ฐ์งํ๊ณ ์ฐ๋ํ์ฌ ์ฌ์ฉ์๊ฐ ๋๋ผ๋ ์๋ต์ฑ์ ํฌ๊ฒ ํฅ์์ํต๋๋ค.
CFS๋ ์ I/O ์ฐ๋๊ฐ ์๋?
CFS์ ์ฒ ํ์ "Completely Fair"์ ๋๋ค:
- ๋ชจ๋ ์ค๋ ๋๋ weight์ ๋น๋กํ์ฌ ์ ํํ ๊ณตํํ๊ฒ CPU๋ฅผ ๋ฐ์์ผ ํจ
- I/O ๋๊ธฐ ์ค์ด๋ CPU ์ฌ์ฉ ์ค์ด๋ , ๊ทธ๊ฒ์ ์ค๋ ๋์ ์ ํ์ด์ง ์ค์ผ์ค๋ฌ๊ฐ ํ๋จํ ๋ฌธ์ ๊ฐ ์๋
์ด๊ฒ์ ์ฒ ํ์ ์ฐจ์ด์ ๋๋ค:
- MLFQS: "I/O ๋๊ธฐ๊ฐ ๋ง์ผ๋ฉด ๋ํํ ์์ ์ผ ๊ฒ์ด๋ค โ ์ฐ๋ํ์"
- CFS: "๋ชจ๋ ์ค๋ ๋๋ฅผ ๊ณตํํ๊ฒ, I/O๋ CPU๋ ์๊ด์์ด"
๊ฒฐ๋ก : MLFQS๊ฐ I/O-bound์์ ์น๋ฆฌํ๋ ๊ฒ์ ์ฐ์ฐ์ด ์๋๋ผ, "์ํฌ๋ก๋ ํจํด์ ๊ด์ฐฐํ๊ณ ์ ์"ํ๋ ์ค๊ณ์ ๊ฒฐ๊ณผ์ ๋๋ค. ์ด๊ฒ์ด FreeBSD๊ฐ ์ค๋ซ๋์ MLFQS ๊ณ์ด ์ค์ผ์ค๋ฌ๋ฅผ ์ ์งํ ์ด์ ์ด๊ธฐ๋ ํฉ๋๋ค.
- ํ์ฌ: ๋จ์ผ CPU ์๋ฎฌ๋ ์ด์
- ํ์: Load balancing, cache coherency, migration cost
- ์ํฅ: ํ๋ ๋ฉํฐ์ฝ์ด ํ๊ฒฝ์ ์ค์ ๋์ ๋ฐ์ ๋ชป ํจ
- ํ์ฌ: Fair ์ค์ผ์ค๋ฌ๋ง (Basic, MLFQS, CFS)
- ๋ถ์ฌ: SCHED_FIFO, SCHED_RR, SCHED_DEADLINE
- ์ด์ : ํ ์คํธ ๋ฐฉ๋ฒ๋ก ์ด ๋ค๋ฆ (deadline, response time)
- ํ์ฌ: I/O๋ ๋จ์ ๋๊ธฐ๋ก ๋ชจ๋ธ๋ง
- ์ด์: Block I/O scheduler์ ํตํฉ (CFQ, Deadline, NOOP)
CFS์ ์ค์ ์ธก์ ๊ฐ์ด ์ด๋ก ์ weight ๋น์จ๋ณด๋ค ์ฝํ๊ฒ ๋์ต๋๋ค.
๊ฐ๋ฅํ ์์ธ:
- ์ปจํ ์คํธ ์ค์์น ์ค๋ฒํค๋ (4 ticks time slice)
- vruntime ์ค์ผ์ผ์ ๋ถ์์ฉ
- ์๋ฎฌ๋ ์ด์ ์กฐ๊ธฐ ์ข ๋ฃ์ ์ํฅ
์ถ๊ฐ ๋ถ์ ํ์: ๋ ๊ธด ์๋ฎฌ๋ ์ด์ , ๋ ํฐ burst_time์ผ๋ก ์ฌํ ์คํธ
- ํ์ฌ: "has_starvation" boolean ํ๋๊ทธ๋ง
- ์ด์: ์ค์ ๋๊ธฐ ์๊ฐ ๋ถํฌ, ์ต์ ์ผ์ด์ค ๋๊ธฐ ์๊ฐ, P99 latency
- ํ์ฌ: 500 ์ค๋ ๋ ํ ์คํธ 10์ด ์ด์ ์์
- ๊ฐ์ : Python ๋ฉํฐ์ค๋ ๋ฉ, Cython ์ต์ ํ, C ํ์ฅ ๋ชจ๋
- ํ์ฌ: ๊ธฐ๋ณธ์ ์ธ ๋ง๋ ๊ทธ๋ํ
- ์ด์:
- ์๊ฐ์ ๋ฐ๋ฅธ ready queue ๋ณํ ์ ๋๋ฉ์ด์
- vruntime/priority ๋ณํ ์ถ์ด ๊ทธ๋ํ
- ๊ฐํธ ์ฐจํธ (Gantt chart)
- ์ค๋ ๋๋ณ ์คํ ํ์๋ผ์ธ
- CPU ์ค์ผ์ค๋ง: ์ด๋ก ์ ๊ฐ๋ (FIFO, SJF, RR, Priority)
- ์ด์์ฒด์ : "์ด๋ ต๊ณ ๋ณต์กํ ๊ฒ"
- ๋๋ฒ๊น : print() ๋จ๋ฐ, ๋ง์ฐํ ์ถ์ธก
- CPU ์ค์ผ์ค๋ง: ๊ตฌํ ๊ฐ๋ฅํ ์๊ณ ๋ฆฌ์ฆ, ์ธก์ ๊ฐ๋ฅํ ํธ๋ ์ด๋์คํ
- ์ด์์ฒด์ : "๋ณต์กํ์ง๋ง ์ดํด ๊ฐ๋ฅํ ์์คํ "
- ๋๋ฒ๊น : ๊ฐ์ค ์๋ฆฝ โ ๊ฒ์ฆ โ ์์ ์ ์ฒด๊ณ์ ์ ๊ทผ
- Basic Priority: ๋จ์, ์์ธก ๊ฐ๋ฅ, ์ค๋ฒํค๋ ์ต์ โ ํ์ง๋ง ๋ถ๊ณต์ , starvation ์ํ
- MLFQS: ๋์ , ์๋ต์ฑ ์ฐ์, I/O ์ฐ๋ โ ํ์ง๋ง ๋ณต์ก, nice ํจ๊ณผ ์ฝํจ
- CFS: ์๋ฒฝํ ๊ณต์ ์ฑ, ๊ฐํ nice ํจ๊ณผ โ ํ์ง๋ง I/O ์ฐ๋ ์์, ์ฝ๊ฐ์ ์ค๋ฒํค๋
์๋ฒฝํ ์ค์ผ์ค๋ฌ๋ ์์ต๋๋ค. ๊ฐ ์ํฌ๋ก๋, ๊ฐ ์์คํ ์๊ตฌ์ฌํญ์ ๋ง๋ ์ ํ์ด ํ์ํฉ๋๋ค.
"CFS๊ฐ ๋ฌด์กฐ๊ฑด ์ข๋ค"๋ ๋ง์ฐํ ๋ฏฟ์์ด ์์์ง๋ง, ์ค์ ์ธก์ ๊ฒฐ๊ณผ:
- I/O-bound ์ํฌ๋ก๋: MLFQS ์น๋ฆฌ
- CPU-bound ์ํฌ๋ก๋: Basic ์น๋ฆฌ (์ค๋ฒํค๋ ์ต์)
- ๊ณต์ ์ฑ: CFS ์น๋ฆฌ
์ํฉ์ ๋ฐ๋ผ ๋ค๋ฆ ๋๋ค.
- ๊ด์ฐฐ: ์ด์ํ ๊ฒฐ๊ณผ (vruntime=0, ๋ชจ๋ tie, ํ ์ชฝ ์์น)
- ๊ฐ์ค: "Time slice๊ฐ ์๋?", "์ ์ ๋๋์ ๋ฌธ์ ?", "FIFO ์์ ๋ฌธ์ ?"
- ์คํ: print() ๋๋ฒ๊น , ๋จ์ํ๋ ํ ์คํธ ์ผ์ด์ค, ๋จ๊ณ๋ณ ์คํ
- ๊ฒ์ฆ: ์์ ํ ๊ฒฐ๊ณผ ํ์ธ, ์ด๋ก ๊ฐ๊ณผ ๋น๊ต, ๋ค๋ฅธ ํ ์คํธ์์๋ ํ์ธ
์ด ํ๋ก์ ํธ๋ ๋จ์ํ "์ค์ผ์ค๋ฌ 3๊ฐ๋ฅผ ๊ตฌํ"ํ๋ ๊ฒ์ ๋์ด์, ์ด์์ฒด์ ์ ํต์ฌ ํธ๋ ์ด๋์คํ๋ฅผ ์ง์ ์ฒดํํ๋ ์ฌ์ ์ด์์ต๋๋ค.
6๊ฐ์ง ์ฃผ์ ๋ฒ๊ทธ๋ฅผ ์์ ํ๋ฉด์:
- ์ด๋ก ๊ณผ ๊ตฌํ์ ๊ดด๋ฆฌ๋ฅผ ๊น์ด ์ดํดํ๊ณ
- ์ ์ ์ฐ์ฐ๊ณผ ๊ณ ์ ์์์ ์ ์ค์์ฑ์ ์ฒดํํ์ผ๋ฉฐ
- ์ธก์ ๋ฐฉ๋ฒ๋ก ์ ์ค์์ฑ์ ๊นจ๋ฌ์์ต๋๋ค
๋ชฉํ ๊ธฐ๋ฐ ํ ์คํธ ์ค๊ณ๋ฅผ ํตํด:
- ๊ณต์ ํ ๋น๊ต ๋ฐฉ๋ฒ๋ก ์ ํ๋ฆฝํ๊ณ
- ๊ฐ ์ค์ผ์ค๋ฌ์ ์ง์ง ๊ฐ์ ์ ๋ฐ๊ฒฌํ์ต๋๋ค
- ์ฝ๋: 3๊ฐ ์ค์ผ์ค๋ฌ, 9๊ฐ์ง ์ํฌ๋ก๋, 18๊ฐ ํ ์คํธ
- ๋ฐฐํฌ: GCP VM์ 24/7 ์ด์ ์ค (http://34.47.105.226:8501)
- ๊ฒฐ๊ณผ: ์ ์๋ฏธํ ํธํฅ ์๋ ๊ณต์ ํ ๋น๊ต
- ๊ฐ ์ค์ผ์ค๋ฌ๊ฐ ์์ ์ ๊ฐ์ ์์๋ง ์น๋ฆฌ
Before: CPU ์ค์ผ์ค๋ง์ ํ์ ๊ณผ ๋๋จ์ด์ง OS ๊ณต๋ถ์ฉ ์ด๋ก After: ์ค์ ๋ก ๊ตฌํ ๊ฐ๋ฅํ๊ณ , ๊ฐ๊ฐ์ ํธ๋ ์ด๋์คํ๋ฅผ ์ ๋์ ์ผ๋ก ์ธก์ ํ ์ ์๋ ์๊ณ ๋ฆฌ์ฆ
์ด์ "์ Linux๊ฐ CFS๋ฅผ ์ ํํ๋๊ฐ?"๋ผ๋ ์ง๋ฌธ์ ๋ตํ ์ ์์ต๋๋ค:
- ๊ทน๋จ์ nice ๊ฐ์ค์น์์ ๊ณต์ ์ฑ ์ฐ์: ๋ค์ํ nice ๊ฐ์ด ์์ธ ์ํฌ๋ก๋์์ CFS๊ฐ ๋ ์ ํํ ๋น๋ก ๋ฐฐ๋ถ
- ์์ธก ๊ฐ๋ฅ์ฑ: vruntime์ ๋จ์ํ๊ณ ์์ธก ๊ฐ๋ฅ
- ๋จ์ ๊ฐ์: I/O ์ฐ๋ ์์, ์ฝ๊ฐ์ ์ค๋ฒํค๋ โ ๊ณต์ ์ฑ์ ๋๊ฐ๋ก ๋ฐ์๋ค์
์ด ํ๋ก์ ํธ๋ ๋ค์์ ๋์์ผ๋ก ๊ฐ๋ฅํ์ต๋๋ค:
- PintOS ๋ฌธ์: MLFQS 17.14 ๊ณ ์ ์์์ ์ฐ์ฐ ์์ธ ์ค๋ช
- Linux ์ปค๋ ์์ค: CFS PRIO_TO_WEIGHT ํ ์ด๋ธ (kernel/sched/core.c)
- FreeBSD ์์ค: MLFQS ๊ตฌํ ์ฐธ์กฐ (sys/kern/sched_4bsd.c)
- StackOverflow: ์ ์ ๋๋์ ์ ๋ฐ๋ ๋ฌธ์ ํด๊ฒฐ ํํธ
- Operating System: Three Easy Pieces: ์ด์์ฒด์ ๋ฅผ 3๊ฐ์ง ํญ๋ชฉ์ผ๋ก ๋ถ๋ฅํ์ฌ ์ด์์ฒด์ ์ดํด ์์ฒด์ ๊ฒฐ์ ์ ์ธ ๋์์ ์ ์ฌ, ์ด ์ฑ ์ด ์๋์์ผ๋ฉด ์ด ํ๋ก์ ํธ๋ ์ ๋ ๋ง๋ฌด๋ฆฌ ๋ ์ ์์์ต๋๋ค
- ๊ทธ๋ฆฌ๊ณ ๋ฌด์๋ณด๋ค, ๋๊น์ง ํฌ๊ธฐํ์ง ์์ ๋ ์์ ์๊ฒ.
ํ๋ก์ ํธ ์ ๋ณด
- ์ ์ฅ์: https://github.com/dvktdr78/scheduler_benchmark
- ์์ฑ์ผ: 2025๋ 11์ 24์ผ




