<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://rntlqvnf.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://rntlqvnf.github.io/" rel="alternate" type="text/html" /><updated>2026-04-19T17:10:29+09:00</updated><id>https://rntlqvnf.github.io/feed.xml</id><title type="html">Blog Hajae</title><subtitle>Personal Homepage</subtitle><author><name>Jaehyun Ha</name><email>yshajae@postech.ac.kr</email></author><entry><title type="html">리뷰어들의 질문 패턴을 이해하기</title><link href="https://rntlqvnf.github.io/reflections/review-pattern/" rel="alternate" type="text/html" title="리뷰어들의 질문 패턴을 이해하기" /><published>2025-10-30T00:00:00+09:00</published><updated>2025-10-30T00:00:00+09:00</updated><id>https://rntlqvnf.github.io/reflections/review-pattern</id><content type="html" xml:base="https://rntlqvnf.github.io/reflections/review-pattern/"><![CDATA[<h3 id="연구란-리뷰어의-질문을-디펜스하는-과정">연구란 리뷰어의 질문을 디펜스하는 과정</h3>

<p>연구 생활을 수년 하면서 깨닫는 것은, 연구란 결국 질문에 대한 대답을 계속 해나가는 과정이라는 점이다. 어떤 문제가 있을지 질문하고 그에 대한 답을 찾으며, 문제를 찾았다면 그것을 해결하기 위한 답을 다시 질문한다. 답을 찾았다면, 그것이 정말 옳은지 또다시 질문한다. 논문은 이 끝없는 질문과 대답의 기록이다.</p>

<p>리뷰어는 그 기록을 읽으며, 자신의 질문에 대해 이미 논문에 답이 적혀있는지, 그리고 그 답이 타당한지 검증한다. 연구자는 리뷰어의 질문을 미리 예상하고, 그에 대한 답을 논문에 충분히 담아내야 한다.</p>

<p>결국 ‘연구 실력’이란 리뷰어의 질문 패턴을 얼마나 잘 이해하고, 그에 대한 답을 논문에 미리 설득력 있게 담아내느냐로 정의될 수 있다. 박사과정은 그런 질문 패턴을 몸으로 익히는 시간이며, 지도교수가 엄격한 리뷰어일수록 그 패턴을 더 빠르고 깊게 익히게 된다.</p>

<h3 id="자주-나오는-리뷰어의-질문-패턴">자주 나오는 리뷰어의 질문 패턴</h3>

<p>리뷰어의 질문 패턴은 대체로 비슷하다. 이를 크게 네 가지, <strong>의심(Skepticism)</strong>, <strong>비교(Comparison)</strong>, <strong>한계(Scope)</strong>, 그리고 <strong>호기심(Curiosity)</strong> 으로 분류할 수 있다.</p>

<h4 id="1-의심-skepticism-그-주장이-정말-맞습니까">1. 의심 (Skepticism): “그 주장이 정말 맞습니까?”</h4>

<p>리뷰어는 연구자의 주장이 정말 옳은지 근본적으로 의심한다. 그래서 연구자가 주장하는 핵심 아이디어가 타당한지, 실험 결과가 그 주장을 뒷받침하는지, 그리고 근거가 충분한지 꼼꼼히 살핀다.</p>

<p>이 질문은 보통 연구자의 주장이 과장되어 보이거나, 실험 결과가 비현실적으로 좋아 보이거나, 주장을 뒷받침하는 근거가 부족해 보일 때 등장한다. 구체적으로. 다양한 패턴이 있다.</p>

<ol>
  <li><strong>문제 전제 공격 (The “Is-it-really-a-problem?” Attack)</strong>
    <ul>
      <li>“SOTA 시스템 <code class="language-plaintext highlighter-rouge">GraphChi</code>가 P1~P4 문제를 겪는다고 하셨는데, 그건 튜닝을 잘못했기 때문 아닐까요? 저희 랩에서 돌렸을 때는 <code class="language-plaintext highlighter-rouge">PSW</code> 모델이 그 정도까지 비효율적이지 않았습니다.”</li>
      <li>“논문에서 제시한 P1~P4 문제는 실제로 존재하는 문제인가요? 기존 연구들에서는 그런 문제가 보고된 적이 없습니다.”</li>
    </ul>
  </li>
  <li><strong>가정 공격 (The “Assumption” Attack)</strong>
    <ul>
      <li>“제안하신 모델이 100억 간선(edge) 그래프까지 스케일 된다고 하셨는데, 이는 사용하신 데이터셋(e.g., ClueWeb)의 특정 분포 특성 때문일 수 있습니다. 파워로(power-law) 분포가 더 극단적인 실제 소셜 그래프에서도 동일한 가정이 성립합니까?”</li>
    </ul>
  </li>
  <li><strong>기술적 타당성 공격 (The “Feasibility” Attack)</strong>
    <ul>
      <li>“제안하신 <code class="language-plaintext highlighter-rouge">FINDNEC</code> 알고리즘의 시간 복잡도가 $O(N \log N)$이라고 하셨는데, 최악의 경우(worst-case) 모든 정점이 동일한 이웃 집합을 가질 때 $O(N^2)$이 되는 반례(counterexample)가 존재합니다. 이 부분을 다시 분석해 주시겠습니까?”</li>
      <li>“메모리 사용량이 적다고 하셨지만, 제안하신 인덱스 구조는 데이터 편향(skew)이 심할 경우 특정 파티션에 데이터가 몰려 메모리 요구량이 급증할 것 같습니다. 이에 대한 분석이 있습니까?”</li>
    </ul>
  </li>
</ol>

<h4 id="2-비교-comparison-그게-sota보다-낫다는-것을-어떻게-압니까">2. 비교 (Comparison): “그게 SOTA보다 낫다는 것을 어떻게 압니까?”</h4>

<p>리뷰어는 연구자가 제시하는 방법이 기존의 SOTA(State-of-the-Art) 방법보다 낫다는 것을 의심한다. 그래서 제안하는 방법이 SOTA와 비교해 정말 더 나은지, 그리고 그 비교가 ‘공정하게’ 이루어졌는지 꼼꼼히 살핀다.</p>

<ol>
  <li><strong>누락된 SOTA 공격 (The “Missing Baseline” Attack)</strong>
    <ul>
      <li>“실험 결과를 잘 봤습니다. 그런데 왜 최근에 SIGMOD’17에서 나온 <code class="language-plaintext highlighter-rouge">[경쟁 시스템 Y]</code>와의 비교는 빠져있습니까? 그 시스템이 이 문제를 더 잘 푸는 것으로 알고 있습니다.”</li>
    </ul>
  </li>
  <li><strong>불공정 튜닝 공격 (The “Unfair Tuning” Attack)</strong>
    <ul>
      <li>“Figure 1에서 <code class="language-plaintext highlighter-rouge">Gemini</code>가 OOM(Out-of-Memory)으로 중단되었는데, <code class="language-plaintext highlighter-rouge">Gemini</code>의 힙 메모리 설정은 얼마로 하셨습니까? 저희가 보기엔 경쟁 시스템의 튜닝을 일부러 비관적으로(pessimistically) 하신 것 같습니다.”</li>
    </ul>
  </li>
  <li><strong>편향된 워크로드 공격 (The “Biased Workload” Attack)</strong>
    <ul>
      <li>“실험에 사용하신 TPC-H 벤치마크는 제안하신 <code class="language-plaintext highlighter-rouge">TurboGraph++</code>에 유리한 데이터 분포를 가진 것 같습니다. 데이터 분포가 다른 실제 소셜 네트워크 데이터(e.g., Twitter)에서도 동일한 성능 향상을 보장할 수 있습니까?”</li>
    </ul>
  </li>
</ol>

<h4 id="3-한계-scope-그-방법이-어디까지-통용됩니까">3. 한계 (Scope): “그 방법이 어디까지 통용됩니까?”</h4>

<p>리뷰어는 제안된 방법의 한계를 파악하려고 한다. 그래서 이 방법이 어떤 상황에서 잘 작동하고, 어떤 상황에서는 잘 작동하지 않는지 그 경계(boundary)를 꼼꼼히 살핀다.</p>

<ol>
  <li><strong>일반화 가능성 질문 (The “Generalizability” Probe)</strong>
    <ul>
      <li>“제안하신 <code class="language-plaintext highlighter-rouge">pin-and-slide</code> 모델은 FlashSSD에서는 잘 작동하는 것을 확인했습니다. 하지만 만약 백엔드 스토리지가 HDD라면 이 모델이 오히려 성능 저하를 일으키지 않을까요?”</li>
    </ul>
  </li>
  <li><strong>한계점 확인 질문 (The “Limitation” Probe)</strong>
    <ul>
      <li>“이 시스템의 근본적인 한계(fundamental limitation)는 무엇이라고 생각하십니까? 예를 들어, 어떤 종류의 쿼리에서는 <code class="language-plaintext highlighter-rouge">TurboGraph++</code>가 <code class="language-plaintext highlighter-rouge">Gemini</code>보다 항상 느릴 수밖에 없는지 궁금합니다.”</li>
    </ul>
  </li>
  <li><strong>파라미터 민감도 질문 (The “Sensitivity” Probe)</strong>
    <ul>
      <li>“제안하신 <code class="language-plaintext highlighter-rouge">BBP</code> 파티셔닝에 <code class="language-plaintext highlighter-rouge">p</code>, <code class="language-plaintext highlighter-rouge">q</code>, <code class="language-plaintext highlighter-rouge">r</code> 등 여러 파라미터가 있는데, 이 파라미터 튜닝이 성능에 얼마나 민감합니까? 사용자가 이걸 쉽게 튜닝할 수 있나요?”</li>
    </ul>
  </li>
</ol>

<h4 id="4-호기심-curiosity-이-방법을-더-확장할-수는-없나요">4. 호기심 (Curiosity): “이 방법을 더 확장할 수는 없나요?”</h4>

<p>리뷰어가 제안한 방법을 더 확장할 수 있는지 궁금해하는, 대체로 긍정적인 의도의 질문이다. 제안한 방법이 다른 문제에도 적용될 수 있는지, 혹은 더 발전시킬 수 있는지 관심을 보인다.</p>

<ol>
  <li><strong>확장/응용 질문 (The “Extension” Probe)</strong>
    <ul>
      <li>“정말 훌륭한 연구입니다. 이 <code class="language-plaintext highlighter-rouge">nested windowed streaming</code> 아이디어를 혹시 그래프가 아닌 시계열(Time-series) 데이터베이스의 윈도우 처리에도 적용해 볼 생각을 해보셨습니까?”</li>
    </ul>
  </li>
  <li><strong>‘왜?’ 질문 (The “Why” Probe)</strong>
    <ul>
      <li>“실험 결과 중 한 부분이 매우 흥미로웠습니다. 데이터셋 A에서는 기법 X가, 데이터셋 B에서는 기법 Y가 더 빨랐는데, 그 근본적인 이유가 무엇이라고 분석하십니까?”</li>
    </ul>
  </li>
  <li><strong>관련 연구 질문 (The “Connection” Probe)</strong>
    <ul>
      <li>“(자신의 연구를 언급하며) 저희는 최근 [관련 연구]를 하고 있는데, 오늘 제안하신 아이디어가 저희 문제를 푸는 데 큰 도움이 될 것 같습니다. 혹시 [특정 세부 사항]에 대해 더 자세히 설명해 주실 수 있습니까?”</li>
    </ul>
  </li>
</ol>

<h3 id="예상-질의응답-목록을-만들어라">예상 질의응답 목록을 만들어라</h3>

<p>리뷰어의 질문 패턴을 이해했다면, 이제 <strong>예상 질의응답 목록(FAQ)</strong> 을 만들어야 한다. 논문에 제기될 법한 질문들을 미리 뽑아내고, 그에 대한 답변을 미리 준비하는 것이다. 이 목록을 만들면 논문 작성 과정에서 어떤 부분을 더 보강해야 할지 명확해지고, 실제 리뷰어의 질문이나 발표 Q&amp;A 세션에서 더 효과적으로 대응할 수 있다.</p>]]></content><author><name>Jaehyun Ha</name><email>yshajae@postech.ac.kr</email></author><category term="Reflections" /><summary type="html"><![CDATA[연구란 리뷰어의 질문을 디펜스하는 과정]]></summary></entry><entry><title type="html">애매한 고소득자가 빠지는 함정</title><link href="https://rntlqvnf.github.io/wealth/high-income-pitfall/" rel="alternate" type="text/html" title="애매한 고소득자가 빠지는 함정" /><published>2025-09-12T00:00:00+09:00</published><updated>2025-09-12T00:00:00+09:00</updated><id>https://rntlqvnf.github.io/wealth/high-income-pitfall</id><content type="html" xml:base="https://rntlqvnf.github.io/wealth/high-income-pitfall/"><![CDATA[<p>최근 슈카월드에서 <a href="https://youtu.be/iihuaYmq0To?si=3OlKrx06Bwkf2NuR">‘고소득 흙수저’라는 주제를 다루었다</a>. 높은 소득으로 과도한 세금은 부과받지만, 그에 상응하는 혜택은 없어 영원한 소득의 쳇바퀴에 갇히는 계층에 대한 분석이다.</p>

<p>이것은 남의 이야기가 아니다. 나는 이 문제의 정확한 당사자다.</p>

<h3 id="함정의-정의-높은-소득-낮은-효용"><strong>함정의 정의: 높은 소득, 낮은 효용</strong></h3>

<p>나는 향후 교수가 될 것이고, 교수는 애매하게 돈을 번다. 연봉 8~9천만 원은 대한민국 청년 복지 제도의 거의 모든 수혜 자격에서 나를 탈락시킨다.</p>

<p>동시에 시스템은 우리에게 35%에 달하는 높은 세율을 부과한다. 공제 항목을 제외하면 실질 소득은 연봉 6천만 원을 버는 사람과 큰 차이가 없는, 소득의 효율이 급격히 떨어지는 구간에 진입하는 것이다.</p>

<p>겉보기엔 풍족하지만, 실제로는 자신의 노동력을 연료로 끊임없이 페달을 밟아야만 현상 유지가 가능한 소득의 쳇바퀴. 이것이 바로 애매한 고소득자가 마주한 함정이다.</p>

<h3 id="시스템의-본질-불평이-아닌-생존을-도모하라"><strong>시스템의 본질: 불평이 아닌 생존을 도모하라</strong></h3>

<p>이런 이야기를 하면 “많이 버는 만큼 더 내는 게 당연한데, 세금 내기 싫다는 거냐”는 식의 비난이 따른다. 물론 맞는 말이다. 애초에 높은 세율이란 사회 유지를 위한 기본 시스템이기 때문이다.</p>

<p>어떤 이들은 이 시스템을 비난하거나, 이민을 통해 회피하려 한다. 하지만 나는 그것이 최선의 전략이라고 보지 않는다. 이 기본 규칙은 어느 사회에나 존재하며, 설령 지금 없다 해도 언제든 생겨날 수 있다. 그때마다 새로운 판을 찾아 떠날 것인가? 판을 새로 익히고 적응하는 데에는 언제나 막대한 비용이 든다.</p>

<p>따라서 가장 효율적인 선택은 매번 새로운 판을 찾아 헤매는 것이 아니다. 안정화된 사회의 큰 틀은 이미 정해져 있고, 세부적인 것들만 변할 뿐이다. 완전히 새로운 규칙을 익히는 것보다, 기존의 큰 틀 안에서 변화를 예측하고 틈을 찾는 것이 훨씬 더 쉬운 문제다. 적어도 나는 이것이 더 경제적인 생존법이라고 본다.</p>

<p>그렇다면 이 소득의 쳇바퀴는 어떻게 돌파해야 하는가?</p>

<h3 id="유일한-탈출구-두-개의-전선에서-싸워라"><strong>유일한 탈출구: 두 개의 전선에서 싸워라</strong></h3>

<p>이 함정에서 탈출하기 위한 첫걸음은, ‘겉보기에만 많은 소득’이라는 자기만족의 함정에서 벗어나는 것이다. 전략은 두 개의 전선에서 동시에 전개되어야 한다.</p>

<p><strong>첫째, 소득의 효용이 급격히 떨어지는 현재 구간을 탈출하기 위해 발악해야 한다.</strong> 단순히 월급이 오르기만 기다리는 것은 현상 유지일 뿐이다. 시스템이 허용하는 범위 내에서, 가장 효율적으로 소득의 절대량을 늘릴 방법을 찾아내야만 한다.</p>

<p><strong>둘째, 노동 소득 자체를 대체할 강력한 자본 소득 시스템을 구축하기 위해 끝없이 고민해야 한다.</strong> 월급은 영원하지 않다. 내 노동력이 아닌, 내 자본이 나를 위해 일하는 구조를 만드는 것만이 이 쳇바퀴를 부수는 유일한 길이다.</p>

<h3 id="생존-전략-규칙을-역이용하여-돌파구를-열어라"><strong>생존 전략: 규칙을 역이용하여 돌파구를 열어라</strong></h3>

<p>이것이 과연 가능한 일인가? 다행히, 시스템의 규칙을 아주 깊게 이해하면 파고들 길은 반드시 보인다.</p>

<p>가령, 청년창업세액감면이라는 강력한 무기가 있다. 35세 이전까지, 특정 조건 하에 소득세와 법인세를 최대 100%까지 감면해 준다. 이는 시스템이 몇 안되게 허락한, 합법적인 절세 경로다. 결론은 명확하다. 애매한 고소득자에게 창업은 선택이 아닌 필수다.</p>

<p>그렇다면 교수가 가장 적은 비용으로 창업을 성공시킬 방법은 무엇인가? 나는 그것이 유튜브와 같은 인플루언서의 길이라고 잠정적으로 결론 내렸다. 지적 자본을 즉시 현금화할 수 있는 가장 효율적인 모델이기 때문이다.</p>

<p>그러면 자본 소득은 어떻게 구축해야 하는가? 세법을 공부하다보니 개인과 법인을 적절히 활용하여 세금 부담을 최소화하고 자산 증식 속도를 높이는 여러 경로가 존재한다는 걸 알게 되었다. 가령, 창업을 통해 얻은 소득을 개인으로 귀속시키는 것이 아니라, 법인의 이름으로 투자하고 자산을 불려 나가는 것이다.</p>

<p>이 두 전략은 서로 맞물려 돌아간다. 35세라는 제한 시간 안에 창업으로 소득을 극대화하고, 그 소득을 법인이라는 방패 뒤에서 자본으로 치환하여 안정적인 기반을 마련하는 것. 이것이 애매한 고소득자가 선택할 수 있는 가장 현실적인 생존 전략이 아닐까.</p>

<p>세상에서 살아남는 것은 단순히 내 분야의 문제만 잘 푼다고 되는 것이 아니다. 유휴 자원을 활용해 끊임없이 경제적 문제에 대한 답을 찾아야한다.</p>

<p>단기적으로는 본업의 시간을 뺏는 손해처럼 보일 것이다. 하지만 이것은 더 큰 자유를 얻기 위한 시간 투자다. 이 과정을 통해 경제적 자유를 빠르게 구축해야만, 역설적으로 나중에 온전히 내가 사랑하는 컴퓨터공학에 모든 시간을 쏟아부을 수 있게 되지 않을까.</p>]]></content><author><name>Jaehyun Ha</name><email>yshajae@postech.ac.kr</email></author><category term="Wealth" /><summary type="html"><![CDATA[최근 슈카월드에서 ‘고소득 흙수저’라는 주제를 다루었다. 높은 소득으로 과도한 세금은 부과받지만, 그에 상응하는 혜택은 없어 영원한 소득의 쳇바퀴에 갇히는 계층에 대한 분석이다.]]></summary></entry><entry><title type="html">가치투자는 왜 실패하는가?</title><link href="https://rntlqvnf.github.io/wealth/failure-of-value-invest/" rel="alternate" type="text/html" title="가치투자는 왜 실패하는가?" /><published>2025-09-11T00:00:00+09:00</published><updated>2025-09-11T00:00:00+09:00</updated><id>https://rntlqvnf.github.io/wealth/failure-of-value-invest</id><content type="html" xml:base="https://rntlqvnf.github.io/wealth/failure-of-value-invest/"><![CDATA[<p>피터 린치의 책, 월가의 영웅을 펼쳤다. 초반부는 주식 초보조차 들어봤을 그 유명한 가치 투자를 다룬다. “일상의 지식으로 이해하는 기업에 투자하라.” 이 얼마나 달콤한 제안인가.</p>

<p>아직 책의 뒷부분을 읽지는 않았지만, 나는 이 책이 무엇을 말하려 하는지 짐작할 수 있다. 이토록 명쾌해 보이는 원칙이 왜 수많은 실패를 낳는지, 그 본질을 파고들 것이 분명하다.</p>

<p>현실을 보자. 이 쉬워 보이는 투자법으로 대중은 처참히 실패한다. 멀리 갈 것도 없다. 슈카월드의 니니는 모두가 이용하는 이마트에 투자했지만 뼈아픈 실패를 맛보았다. 수많은 사람이 자신이 애용한다는 이유만으로 카카오나 삼성전자를 매수하고 손실의 수렁에 빠진다.</p>

<p>여기서 우리는 거대한 간극을 발견해야 한다. 가치 투자는 좋은 투자의 출발점일 뿐, 그 자체가 성공을 보장하는 종착지가 아니라는 사실이다.</p>

<p>그렇다면 사람들은 왜 실패하는가? <strong>그들은 가치 투자의 본질을 거대한 필터링 알고리즘의 첫 단계일 뿐이라는 사실을 인지하지 못하기 때문이다.</strong></p>

<p>대중이 이해하는 가치 투자란, 수천 개에 달하는 종목 중에서 내가 아는 몇 개의 후보군을 추려내는 강력한 <strong>1차 필터링</strong> 그 이상도 이하도 아니다. 문제는, 이 필터링을 거친 결과물이 보물 지도가 아니라는 점이다.</p>

<p>이것은 대박과 쪽박, 즉 옥석이 마구 뒤섞여 있는 혼돈의 목록일 뿐이다. 진짜 투자는 바로 이 목록을 받아 든 다음부터 시작되어야 한다. 하지만 대부분은 필터링이 곧 정답이라 믿고 그 첫 번째 종목에 자신의 자산을 던져 넣는다. 쉬운 길이기 때문이다.</p>

<p>아마도 이것이 실패의 본질이다. 진정한 가치 투자란, 1차 필터링으로 걸러낸 그 후보군 안에서 진짜 옥석을 가려내는 지난한 과정 전체를 의미해야 한다. 이마트는 왜 오르지 않았는가? 카카오의 성장 동력은 과연 주주 가치와 연결되어 있는가? 그 기업이 주가를 올리는 것이 과연 그들에게 이득인가? 이 질문들에 답하는 것이 바로 2차, 3차 필터링의 과정이다.</p>

<p>이해라는 단어의 깊이는 교수와 학생만큼이나 다르다. ‘가치 투자를 하랬지, 조가치 투자를 하랬냐’는 우스갯소리는 바로 이 격차를 꿰뚫는 경고이다.</p>

<p>아마도 책은 뒷부분이 설명하려는 것은 이것일 테다. 1차 필터링 이후, 진짜 보석을 찾아내기 위해 당신은 어떤 기준과 원칙으로 자신만의 다음 필터링 알고리즘을 만들 것인가?</p>]]></content><author><name>Jaehyun Ha</name><email>yshajae@postech.ac.kr</email></author><category term="Wealth" /><summary type="html"><![CDATA[피터 린치의 책, 월가의 영웅을 펼쳤다. 초반부는 주식 초보조차 들어봤을 그 유명한 가치 투자를 다룬다. “일상의 지식으로 이해하는 기업에 투자하라.” 이 얼마나 달콤한 제안인가.]]></summary></entry><entry><title type="html">소비하는 삶에서 생산하는 삶으로</title><link href="https://rntlqvnf.github.io/reflections/consume-to-produce/" rel="alternate" type="text/html" title="소비하는 삶에서 생산하는 삶으로" /><published>2025-09-02T00:00:00+09:00</published><updated>2025-09-02T00:00:00+09:00</updated><id>https://rntlqvnf.github.io/reflections/consume-to-produce</id><content type="html" xml:base="https://rntlqvnf.github.io/reflections/consume-to-produce/"><![CDATA[<h4 id="출력을-잃어버린-시스템-쾌락의-쳇바퀴">출력을 잃어버린 시스템, 쾌락의 쳇바퀴</h4>

<p>혼자 있는 시간이 길어지면서, 나는 휴대폰을 내려놓지 못하는 자신을 발견했다. 인스타그램, 유튜브, 스레드, 심지어는 블라인드까지. 재미있는 콘텐츠를 찾기 위해 플랫폼을 번갈아가며 스크롤하는 무한 루프에 빠져있다.</p>

<p>쾌락의 쳇바퀴다. 본디 시작은 즐거움의 추구였을 지언정, 시간이 지나 쾌락의 역치가 올라가며 행위의 목적은 지루함의 회피로 변질되었다. 찾는 시간은 기하급수적으로 늘고, 즐기는 시간은 그에 반비례해 줄어든다. 목적은 없이 그저 소비에만 몰두하게 된다.</p>

<p>이 현상의 본질은 무엇인가? 컴퓨터공학자의 시선으로 본다면, 이것은 <strong>출력 없이 자원만 소모하는 비효율적인 프로세스</strong>와 완벽히 동일하다. 나의 뇌라는 시스템이 유휴 상태에 빠지는 것을 막기 위해, 의미 없는 연산을 반복하며 시간과 집중력이라는 자원을 낭비하는 것이다. 시스템의 성능이 명백히 저하된 상태다.</p>

<p>컴퓨터라면 무엇을 해야 하는가? 답은 명확하다. 해당 프로세스를 즉시 강제 종료하고, 낭비되던 자원을 회수하여 가치 있는 결과물을 만드는 핵심 작업에 재할당해야 한다. 삶도 마찬가지다. 이 무한 스크롤의 쳇바퀴는 의식적으로 끊어내야만 한다.</p>

<h4 id="읽기-전용의-삶에서-쓰기-권한을-쟁취하는-삶으로">읽기 전용의 삶에서 쓰기 권한을 쟁취하는 삶으로</h4>

<p>시간은 누구에게나 절대적으로 주어진 자원이다. 그 시간을 맹목적인 소비에 쏟아부은 뒤 남는 것은 무엇인가. 그저 무의식 속에 잔상으로 남아있을 뿐, 그 외에는 아무것도 없다.</p>

<p>이는 우리가 세상을 <strong>읽기 전용 모드</strong>로 대하고 있기 때문이다. 수많은 정보를 받아들이지만, 그것을 내면에 기록할 쓰기 권한은 사용하지 않는다. 읽기만 한 정보는 컴퓨터를 껐다 켜면 사라지는 휘발성 캐시처럼, 하룻밤이면 대부분 공중으로 분해된다.</p>

<p>어떻게 해야 이 데이터가 사라지지 않고 나의 자산이 될 것인가? 방법은 단 하나, <strong>쓰기 권한을 쟁취하고 생산하는 것</strong>이다. 정보를 받아들이는 데서 그치지 않고, 그것을 가공하여 나만의 결과물로 기록해야 한다. 그것이 글이든, 코드든, 요리든 상관없다. 내 안에 지식과 경험이라는 자산을 쌓는 유일한 길은 생산뿐이다.</p>

<h4 id="사용자와-개발자의-차이-어려움의-본질">사용자와 개발자의 차이, 어려움의 본질</h4>

<p>물론 생산의 세계로 넘어가는 길은 결코 쉽지 않다. 소설을 읽는 것과 쓰는 것은 완전히 다른 차원의 행위다. 우리는 소비자로서 잘 다듬어진 최종 결과물만 볼 뿐, 그 이면의 처절한 과정을 보지 못한다.</p>

<p>컴퓨터 측면에서 해석하자면, <strong>사용자와 개발자의 격차</strong>라 할 수 있다. 사용자는 편리한 인터페이스를 경험하지만, 개발자는 그 뒤에 숨은 복잡한 소스코드와 끝없는 버그와 싸운다. 개발자는 어떻게 그 복잡함을 이겨내는가? 수없이 실패하고 원인을 파고드는 디버깅을 통해 문제를 해결하고 시스템을 완성한다. 그들은 이 고통스러운 과정이야말로 시스템의 본질을 이해하는 유일한 길임을 안다.</p>

<p>생산 활동에서 마주하는 어려움이 바로 이 디버깅 과정이다. 글이 막히고 코드가 동작하지 않는 순간은, 우리가 사용자 수준을 넘어 해당 분야의 구조를 이해하는 개발자로 성장하고 있다는 가장 확실한 증거다. 이 어려움의 경험이야말로 진짜 자산이다.</p>

<h4 id="성장의-정체기-새로운-알고리즘을-찾아라">성장의 정체기, 새로운 알고리즘을 찾아라</h4>

<p>생산의 길에도 한계는 찾아온다. 어느 순간 실력이 늘지 않는 정체기, 즉 플래토(Plateau)를 마주하게 된다. 노력하는데도 결과물이 나아지지 않는 답답한 구간이다.</p>

<p>이것은 컴퓨터 과학의 <strong>최적화 문제</strong>와 같다. 시스템의 성능이 한계에 부딪혔을 때, 기존 방식을 맹목적으로 반복하는 무차별 대입 방식으로는 결코 그 한계를 넘을 수 없다. 현재 사용 중인 알고리즘의 효율이 다했다는 신호다.</p>

<p>그렇다면 이 한계는 어떻게 돌파해야 하는가? 더 많은 노력이 아니라 <strong>더 나은 알고리즘</strong>이 필요하다. 문제에 대한 접근법 자체를 바꾸거나, 새로운 기술을 학습해 기존의 비효율을 극복해야 한다. 성장의 정체기는 좌절의 신호가 아니라, 다음 단계로 도약하기 위해 새로운 전략이 필요하다는 명확한 알림이다.</p>

<p>26세. 생산성을 극대화하고 성장이라는 자산을 쌓아야 할 최적의 시기다. 도파민만을 추구하는 수동적인 삶에서 벗어나, 내 모든 자원을 성장에 쏟아붓는 것. 그것이 지금 내가 내릴 수 있는 유일하게 현명한 선택이다.</p>]]></content><author><name>Jaehyun Ha</name><email>yshajae@postech.ac.kr</email></author><category term="Reflections" /><summary type="html"><![CDATA[출력을 잃어버린 시스템, 쾌락의 쳇바퀴]]></summary></entry><entry><title type="html">컴퓨터공학자로서 AI 시대를 살아남기</title><link href="https://rntlqvnf.github.io/reflections/survival_ai_as_cs/" rel="alternate" type="text/html" title="컴퓨터공학자로서 AI 시대를 살아남기" /><published>2025-08-28T00:00:00+09:00</published><updated>2025-08-28T00:00:00+09:00</updated><id>https://rntlqvnf.github.io/reflections/survival_ai_as_cs</id><content type="html" xml:base="https://rntlqvnf.github.io/reflections/survival_ai_as_cs/"><![CDATA[<h3 id="스스로를-대체할-무기를-만든-자들">스스로를 대체할 무기를 만든 자들</h3>

<p>컴퓨터공학은 스스로를 죽일 무기를 만들어냈다. 바로 인공지능(AI)이다. 수년 내로 AI는 컴퓨터로 할 수 있는 대부분의 지식 노동을 대체할 것이다. 특히, 코딩이라는 행위 자체의 가치는 급격히 하락하고 있다.</p>

<p>이 거대한 파도 앞에서 우리는 단 하나의 질문을 던져야 한다: <strong>“어떻게 해야 AI가 나를 대체하지 못할 것인가?”</strong></p>

<hr />

<h3 id="실리콘밸리가-보여주는-초격차의-시대">실리콘밸리가 보여주는 ‘초격차’의 시대</h3>

<p>아직 이 변화를 체감하지 못하는 사람도 많을 거다. 한 가지 예시를 들어보자.</p>

<p>내가 이 애플 스타일의 블로그를 만드는데 과연 몇 일이 걸렸을까? 단 하루다. 나는 프론트엔드 개발자도, 디자이너도 아닌 시스템 연구자다.</p>

<p>이제 기업의 입장에서 생각해 보자. 어중간한 개발자 여러 명을 고용하느니, 뛰어난 엔지니어 한 명에게 최고 수준의 AI 도구를 쥐여주는 것이 훨씬 효율적이지 않을까? 당연한 흐름이다. 최근 메타(Meta)가 <a href="https://www.hankyung.com/article/2025080276807">수천억을 들여 톱클래스 한 명를 영입했다는 뉴스</a>는 바로 이 현상의 증거다. 잡다한 100명이 아닌, 압도적인 1명에게 모든 자원을 집중하는 ‘초격차’의 시대가 이미 시작됐다. 이 흐름은 돈이 걸린 문제이기에, 네이버든 카카오든 그 어떤 SW 기업도 거스를 수 없다.</p>

<hr />

<h3 id="대체-불가능한-탑-티어-전문가가-되는-길">대체 불가능한 ‘탑 티어’ 전문가가 되는 길</h3>

<p>그렇다면 어떻게 살아남을 것인가? 해답은 AI의 본질적인 한계에 있다. AI는 결국 정교한 확률 모델일 뿐, 두 가지 명확한 약점을 가진다.</p>

<ol>
  <li><strong>입력의 종속성 (Dependency on Input):</strong> 쓰레기를 넣으면 쓰레기가 나온다.</li>
  <li><strong>출력의 불확실성 (Uncertainty of Output):</strong> 그럴듯한 거짓말을 너무나도 잘한다.</li>
</ol>

<p>이 두 가지 약점을 해결하는 사람만이 살아남는다. 즉, <strong>AI를 압도하는 두 종류의 능력</strong>을 갖춰야 한다.</p>

<ul>
  <li><strong>질문하는 능력:</strong> 복잡하고 추상적인 문제를 AI가 이해할 수 있는 명확한 언어로 정의(Define)하고 질문(Prompt)할 수 있는 능력.</li>
  <li><strong>검증하는 능력:</strong> AI가 내놓은 수많은 결과물 속에서 무엇이 옳고 그른지 판별(Verify)하고, 틀렸을 경우 더 나은 질문으로 개선(Refine)할 수 있는 능력.</li>
</ul>

<p>그리고 이 두 능력을 모두 갖춘 사람은, 결국 그 분야의 ‘탑 티어 전문가’일 수밖에 없다. 어중간한 지식으로는 AI에게 올바른 질문을 던질 수도, 그 답을 검증할 수도 없기 때문이다.</p>

<hr />

<h3 id="전문가의-격格은-어떻게-차이를-만드는가">전문가의 ‘격(格)’은 어떻게 차이를 만드는가</h3>

<p>“AI가 어차피 똑똑하니, 전문가든 아니든 결과는 비슷하지 않나?” 라고 생각할 수 있다. 오히려 그 반대다. AI는 지능의 격차를 줄이는 것이 아니라 <strong>증폭시킨다.</strong> 뛰어난 전문가는 AI를 통해 더 압도적이 되고, 비전문가는 약간 더 나아지는 수준에 그친다.</p>

<p>탑 티어 연구자인 교수님과 주니어 티연구자인 나를 비교해보자. 같은 AI 도구가 내 손에 쥐어져도, 교수님의 연구 능력에 비할 바가 못 된다. 나는 올바른 질문을 던지고 답을 검증하는 능력이 압도적으로 부족하기 때문이다.</p>

<p>예를 들어, LLM을 이용한 데이터베이스 분석 도구를 개발할 때, 나는 ‘LLM을 반복적으로 호출해서 플랜을 고치면 되겠지’라는 단순한 생각에 갇혀 있었다. 실제로도 문제는 어느정도 해결되니까. 내 아이디어에 대한 비판을 멈춘 것이다.</p>

<p><img src="/assets/survival/bayesian.png" alt="슬랙" /></p>

<p>그때 교수님은 내가 생각지도 못한 ‘베이지안 최적화’를 도입하는 아이디어를 AI에게 물어 대뜸 공유해주셨다. 훌륭하게 작동하는 아이디어였다.</p>

<p>왜 교수님은 이런 질문을 할 수 있었고, 나는 못했을까? 그분은 내 아이디어가 가진 한계를 의심하고 더 나은 해답을 찾아냈지만, 나는 ‘이 정도면 되겠지’라며 사고를 멈췄기 때문이다.</p>

<p>좋은 질문을 던져야 좋은 답이 돌아오는 것은 사람이나 AI나 마찬가지다. 전문가의 수준 차이가 AI 활용의 격차를 극단적으로 벌리는 것이다.</p>

<hr />

<h3 id="어려운-문제에-도전하라">‘어려운 문제’에 도전하라</h3>

<p>“AI가 더 발전하면 질문과 검증도 스스로 하게 되지 않을까?” 물론 언젠가는 가능할지도 모른다. 하지만 AI가 스스로의 한계를 인지하고 극복하는 수준에 이르면, 그건 더 이상 도구가 아니라 진정한 의미의 ‘지능’이다. 그 시대의 생존법은 지금과는 완전히 다를 것이다.</p>

<p>내가 은퇴하기 전까지는, 적어도 고품질 데이터의 한계로 인해 그 정도의 AI가 나오기는 어렵다고 본다. 논문들조차 논리가 이상한 것들이 수두룩한데, AI가 학습할 초고품질의 논리 데이터가 과연 얼마나 되겠는가?</p>

<p>그렇기에 현재 우리의 생존 전략은 명확하다. 교수든 연구원이든 분야를 막론하고, 어려운 것에 도전해야 한다. 전문가조차 질문을 던지기 어려운 문제, 지금의 인간에게도 극도로 어려운 문제. 수천만 라인의 코드를 파악하고 분석해야 하는 것처럼, 복잡하고, 거대하고, 남들이 피하는 문제를 파고들어야 한다.</p>

<p>쉬운 문제는 모두 AI에게 정복당할 것이다. 살아남는 길은 아주 어려운 문제를 푸는 대체 불가능한 전문가가 되는 것, 그뿐이다.</p>]]></content><author><name>Jaehyun Ha</name><email>yshajae@postech.ac.kr</email></author><category term="Reflections" /><category term="Survival" /><category term="Career" /><category term="AI" /><summary type="html"><![CDATA[스스로를 대체할 무기를 만든 자들]]></summary></entry><entry><title type="html">[OS] File System Implementation (1)</title><link href="https://rntlqvnf.github.io/lecture%20notes/os-file-impl-1/" rel="alternate" type="text/html" title="[OS] File System Implementation (1)" /><published>2020-12-18T00:00:00+09:00</published><updated>2020-12-18T00:00:00+09:00</updated><id>https://rntlqvnf.github.io/lecture%20notes/os-file-impl-1</id><content type="html" xml:base="https://rntlqvnf.github.io/lecture%20notes/os-file-impl-1/"><![CDATA[<blockquote>
  <p>이 글은 포스텍 박찬익 교수님의 CSED312 운영체제 수업의 강의 내용과 자료를 기반으로 하고 있습니다.</p>
</blockquote>

<p>아 진짜.. 공부해야 하는데 소설 보면서 뒹굴뒹굴 하고 있다..</p>

<p>갑자기 오토마타 진도도 폭주해서 할 것도 많은데 으아아아ㅏ</p>

<p>빨리 졸업하고 싶다..</p>

<h1 id="1-overview">1. Overview</h1>

<p>지난 시간은 file system의 개념과 기본 구조에 대해서 배웠다.</p>

<p>이번 시간은 file system을 구현함에 알아야 하는 여러가지 issue와 해결법에 대해서 알아볼 것이다.</p>

<p>우선 file system을 구현함에 있어서 필요한 것들이 무엇인지 알아보자.</p>

<p>File system이 필수적으로 구현해야 하는 data strcuture는 다음과 같다.</p>

<ul>
  <li><strong>Directories</strong>
    <blockquote>
      <p>file name -&gt; file metadata</p>
    </blockquote>
    <ul>
      <li>Store directories as files</li>
    </ul>
  </li>
  <li><strong>File metadata</strong>
    <blockquote>
      <p>how to find file data blocks</p>
    </blockquote>
  </li>
  <li><strong>Free map</strong>
    <blockquote>
      <p>list of free disk blocks</p>
    </blockquote>
  </li>
</ul>

<p>이 DS와 더불어, file system을 구현함에 있어서 마주해야 하는 challenges는 다음과 같다.</p>

<ul>
  <li><strong>Index strcuture</strong>
    <blockquote>
      <p>How do we locate the blocks of a file?</p>
    </blockquote>
  </li>
  <li><strong>Index granularity</strong>
    <blockquote>
      <p>What block size do we use?</p>
    </blockquote>
  </li>
  <li><strong>Free space</strong>
    <blockquote>
      <p>How do we find unused blocks on disk?</p>
    </blockquote>
  </li>
  <li><strong>Locality</strong>
    <blockquote>
      <p>How do we preserve spatial locality?</p>
    </blockquote>
  </li>
  <li><strong>Reliability</strong>
    <blockquote>
      <p>What if machine crashes in middle of a file system op?</p>
    </blockquote>
  </li>
</ul>

<p><img src="/assets/lecture/os/impl/named.PNG" alt="Index" /></p>

<p>여기서 index structure란, 파일이 disk상에서 어디에 있는지를 결정하는 구조이다.</p>

<p>Index strcuture가 정의되어야지만 디스크에 있는 파일에 접근할 수 있다.</p>

<p>한편 위의 그림에서 file number란 UNIX에서의 inode number와 같은 것으로 생각하면 된다.</p>

<p><img src="/assets/lecture/os/impl/layout.PNG" alt="Layout" /></p>

<p>Inode란, file header(file attributes except name)를 담는 data stucture이다.</p>

<p>모든 파일은 각자의 inode를 가지며, 각 inode는 해당하는 파일의 정보를 담고 있다고 보면 된다.</p>

<p><img src="/assets/lecture/os/impl/inode.PNG" alt="Inode" /></p>

<p>한편 Inode는 위 그림처럼 fixed-size inode array에 의해 관리된다.</p>

<p>이때 array의 index가 바로 <strong>i-number</strong>(inode number)인 것이다.</p>

<p>곧, directory는 file name to inode의 매핑을 저장한다고 생각하면 된다.</p>

<p>이에 관해서 저번 포스트에서 잠깐 언급했었다.</p>

<p>한편 File system challenges를 기반으로 file system components를 나누면 아래와 같다.</p>

<ol>
  <li>
    <p><strong>Disk management</strong></p>
  </li>
  <li>
    <p><strong>Naming and directories</strong></p>
  </li>
  <li>
    <p><strong>Efficiency and performance</strong></p>
  </li>
  <li>
    <p><strong>Reliability and protection</strong></p>
  </li>
</ol>

<p>우리는 오늘 이 중 위 3개를 알아볼 것이다.</p>

<h1 id="2-disk-management">2. Disk Management</h1>

<p>File system은 아래 두 가지 정보를 추적해야 한다.</p>

<ol>
  <li>
    <p>Where is your file data?</p>
  </li>
  <li>
    <p>Where is free space?</p>
  </li>
</ol>

<p>그냥 심플하게 전체 file system에 대해서 순회하며 (1)번 정보를 구하면 자연스레 (2)번도 구할 수 있겠지만, 이는 굉장히 비효율적이다.</p>

<p>어떻게 해야 효율적으로 위 두 물음에 답할 수 있을까?</p>

<p>이번 챕터에서는 이에 대해 두 파트에 걸쳐 답할 것이다.</p>

<ul>
  <li>
    <p><a href="#free-space-management">Free Space Management</a></p>
  </li>
  <li>
    <p><a href="#allocation">Allocation</a></p>
  </li>
</ul>

<h2 id="21-free-space-management">2.1 Free Space Management</h2>

<h3 id="211-bitmap">2.1.1 Bitmap</h3>

<blockquote>
  <p>Array of bits, with Nth bit indicating whether Nth block is free</p>
</blockquote>

<p>Bitmap으로 free space를 표현하는 법이다.</p>

<ul>
  <li><strong>장점</strong>
    <ul>
      <li>
        <p>Easy to find contiguous space</p>
      </li>
      <li>
        <p>Low space overhead</p>
        <blockquote>
          <p>각 block 대비 차지하는 영역이 1bit 밖에 안됨</p>
        </blockquote>
      </li>
    </ul>
  </li>
  <li><strong>단점</strong>
    <ul>
      <li>Requires extra space for a bitmap
        <ul>
          <li>ex) 1 GB file system (2^30 / 2^12 = 2^18), 32KB bitmap</li>
          <li>ex) 1 PB file system (2^50), 32GB bitmap</li>
        </ul>
      </li>
      <li><strong>Not scalable</strong>
        <blockquote>
          <p>File system 크기가 크면 bitmap의 일부는 disk에 있어야 하고, 이는 현저한 성능 저하를 일으킴</p>
        </blockquote>
      </li>
    </ul>
  </li>
</ul>

<p>이 단점을 극복하기 위해 나온 variation이 있다.</p>

<blockquote>
  <p>Breaking a bitmap into small chunks(e.g. smaller bitmaps) and keeping track of the number of bits set in each chunk</p>
</blockquote>

<p>예를 들어, 1 PB file system (2^50), 32GB bitmap이 주어졌다고 하자.</p>

<p>이걸 10^6개의 bitmap으로 자르는 것이다.</p>

<p>그리고 각 bitmap이 얼마만큼의 free space를 갖고 있는지 표시하는 10^6개의 integer를 관리하는 것이다.</p>

<p>이러면 메인 메모리에 문제없이 들어간다!</p>

<h3 id="211-linked-list">2.1.1 Linked List</h3>

<p><img src="/assets/lecture/os/impl/freelist.PNG" alt="Free List" /></p>

<blockquote>
  <p>Linked list of free space</p>
</blockquote>

<p>Free spaces를 linked list로 엮어서 관리하는 방법이다.</p>

<p>이 경우, bitmap과 다르게 extra space를 소모하진 않는다.</p>

<p>그러나 연속된 free space를 얻어내기가 어렵다.</p>

<h2 id="22-allocation">2.2 Allocation</h2>

<p>Allocation의 목표은 두 가지이다.</p>

<ul>
  <li>Space on disk utilized effectively</li>
  <li>File can be accessed quickly</li>
</ul>

<p>이 두 목표를 최대한 잘 만족하는 것이 좋은 allocation scheme이라 할 수 있겠다.</p>

<h3 id="221-contiguous-allocation">2.2.1 Contiguous Allocation</h3>

<p><img src="/assets/lecture/os/impl/allocation.PNG" alt="Contiguous Allocation" /></p>

<blockquote>
  <p>requires that each file occupy a set of contiguous blocks on the disk.</p>
</blockquote>

<p>연속된 영역에 할당하는 방법이다.</p>

<p>FIle header에는 파일의 first sector와 그 길이만 표현해주면 파일이 어디에 위치하는지 알 수 있다.</p>

<ul>
  <li><strong>장점</strong>
    <ul>
      <li>
        <p>Fast sequential access</p>
      </li>
      <li>
        <p>Easy random access</p>
      </li>
    </ul>
  </li>
  <li><strong>단점</strong>
    <ul>
      <li>
        <p>External fragmentation</p>
      </li>
      <li>
        <p>Hard to grow files</p>
      </li>
    </ul>
  </li>
</ul>

<h4 id="extent">Extent</h4>

<p>Contiguous Allocation를 약간 변형시킨 버전이다.</p>

<p>Contiguous blocks of disk(a.k.a <strong>Extent</strong>)를 allocation의 단위로 두는 것이다.</p>

<p>곧, 파일은 한개 이상의 extent로 이뤄지게 된다.</p>

<p>할당에 있어서 조금 더 선택지가 많아졌지만, large extent로 인한 <strong>internal fragmentation</strong>과 varying size로 인한 <strong>external fragmentation</strong> 문제는 피할 수 없다.</p>

<h3 id="222-linked-allocation">2.2.2 Linked Allocation</h3>

<p><img src="/assets/lecture/os/impl/linked.PNG" alt="Linked" /></p>

<blockquote>
  <p>each file is a linked list of disk blocks; the disk blocks may be scattered anywhere on the disk</p>
</blockquote>

<p>각 disk block을 pointer area / data area로 나누어 linked list를 구현한 것이다.</p>

<p>File header에는 시작 노드와 끝 노드의 pointer만 기록해주면 파일이 어디 block에 위치하는지 구할 수 있다.</p>

<p>이는 Contiguous Allocation의 문제를 훌륭하게 해결할 수 있다.</p>

<p>왜냐하면 Linked list로 구현하게 되면 임의의 위치의 block들을 이어붙일 수 있으므로 External fragmentation이 생기지 않고, 또 확장도 어렵지 않기 때문이다.</p>

<ul>
  <li><strong>장점</strong>
    <ul>
      <li>
        <p>Can grow files dynamically</p>
      </li>
      <li>
        <p>Free list is similar to a file</p>
      </li>
      <li>
        <p>No waste of space</p>
      </li>
    </ul>
  </li>
  <li><strong>단점</strong>
    <ul>
      <li><strong>random access: horrible</strong>
        <blockquote>
          <p>매번 linked list를 탐색해야 하므로, 엄청나게 느리다. 게다가 각 pointer는 모두 disk에 있다!</p>
        </blockquote>
      </li>
      <li>unreliable: losing a block means losing the rest
        <blockquote>
          <p>중간에 끊겨버리면 탐색을 할 수 없음</p>
        </blockquote>
      </li>
      <li>space overhead
        <blockquote>
          <p>각 block에 pointer를 저장하기 위한 공간이 필요함</p>
        </blockquote>
      </li>
    </ul>
  </li>
</ul>

<h4 id="fat">FAT</h4>

<p>Linked Allocation의 구현을 살짝 수정한 버전이다.</p>

<p><img src="/assets/lecture/os/impl/fat.PNG" alt="FAT" /></p>

<p>Random access performance를 올리기 위해, pointer를 separate linked list로 관리하는 것이다.</p>

<p>이러면 탐색을 main memory에서 할 수 있으므로 상대적으로 random access의 속도가 올라간다.</p>

<ul>
  <li><strong>장점</strong>
    <ul>
      <li>
        <p>Easy to find free block</p>
      </li>
      <li>
        <p>Easy to append to a file</p>
      </li>
      <li>
        <p>Easy to delete a file</p>
      </li>
    </ul>
  </li>
  <li><strong>단점</strong>
    <ul>
      <li>
        <p>Small file access is slow</p>
      </li>
      <li>Random access is stil very slow
        <blockquote>
          <p>기존 구현보다는 빠르지만, 일단 탐색해야 한다는 것 자체가 성능 저하를 야기한다.</p>
        </blockquote>
      </li>
      <li>Poor locality
        <blockquote>
          <p>FAT implementations typically use simple allocation strategies such as next fit. These can lead to badly fragmented files</p>
        </blockquote>
      </li>
    </ul>
  </li>
</ul>

<h3 id="223-single-level-indexed-allocation">2.2.3 Single-Level Indexed Allocation</h3>

<p><img src="/assets/lecture/os/impl/index.PNG" alt="Index" /></p>

<blockquote>
  <p>Each file is array of scattered disk block</p>
</blockquote>

<p>Linked Allocation의 random access 문제를 해결하기 위해, array를 통해 efficient direct access를 지원하는 방법이다.</p>

<ul>
  <li><strong>장점</strong>
    <ul>
      <li>
        <p>Can grow up to a limit</p>
      </li>
      <li>
        <p>Random access is fast</p>
      </li>
      <li>
        <p>No external fragementation</p>
        <blockquote>
          <p>Any block can be allocated</p>
        </blockquote>
      </li>
    </ul>
  </li>
  <li><strong>단점</strong>
    <ul>
      <li>Clumsy to grow beyond the limit
        <blockquote>
          <p>처음에 array 사이즈를 고정해서 만들기 때문에, array size의 한계에 다다르면 확장하기가 어렵다.</p>
        </blockquote>
      </li>
      <li>Still lots of seeks
        <blockquote>
          <p>Due to scattered disk blocks, need to seek many times</p>
        </blockquote>
      </li>
    </ul>
  </li>
</ul>

<h3 id="224-multi-level-indexed-allocation">2.2.4 Multi-Level Indexed Allocation</h3>

<p><img src="/assets/lecture/os/impl/multi.PNG" alt="Multi level" /></p>

<p>Size를 넘어서 확장하기 어렵다는 문제를 해결하려면 multi-level을 도입하면 된다.</p>

<p>이전에 배웠던 multi-level page table과 동일한 방식이다.</p>

<p>다만 구현이 두가지로 나뉘는데, 하나는 linked list로 구현하는 방식이고 하나는 multilevel index로 구현하는 방식이다.</p>

<h3 id="225-combined-scheme">2.2.5 Combined Scheme</h3>

<p><img src="/assets/lecture/os/impl/combined.PNG" alt="Combined" /></p>

<p>Unix에서는 Multi-Level Indexed Allocation을 변형한 combined scheme을 사용한다.</p>

<p>각 레벨 별로 관리를 하는 것이 핵심 아이디어이다.</p>

<p>이 구현은 확장하기도 쉽고, 작은 파일이든 큰 파일이든 효율적으로 할당할 수 있다는 장점이 있다.</p>

<p>그러나 아직도 lots of seeks 문제는 해결하지 못했다.</p>

<p>간단한 예제를 통해 이해도를 높여보자.</p>

<blockquote>
  <p>Q. Which block should be accessed?</p>
</blockquote>

<ul>
  <li>Block size = 1KB</li>
  <li>Pointer size = 4byte</li>
</ul>

<ol>
  <li>
    <p>Access byte offset = 9000</p>

    <p><img src="/assets/lecture/os/impl/sol1.PNG" alt="Sol1" /></p>

    <p>9000 = 1024*8 + 808</p>
  </li>
  <li>
    <p>Access byte offset = 350000</p>

    <p><img src="/assets/lecture/os/impl/sol2.PNG" alt="Sol2" /></p>

    <p>한 페이지(1KB=2^10)당 가리킬 수 있는 페이지의 수 = 2^10 / 2^2 = 2^8 = 256</p>

    <p>350000 = 1024* 10 + 339760</p>

    <p>339760 = 1024 * 256 + 77616</p>

    <p>77616 = 1024 * 75 + 816</p>
  </li>
</ol>

<h1 id="3-naming-and-directories">3. Naming and Directories</h1>

<p>파일에 접근하는 방법(naming)에는 크게 3가지 종류가 있다.</p>

<ul>
  <li><strong>Use index</strong>
    <blockquote>
      <p>Ask users specify inode number</p>
    </blockquote>
  </li>
  <li><strong>Text name</strong>
    <blockquote>
      <p>name to index mapping</p>
    </blockquote>
  </li>
  <li><strong>Icon</strong>
    <blockquote>
      <p>icon to name mapping or icon to index mapping</p>
    </blockquote>
  </li>
</ul>

<p>또한 directory를 구현하는 방법에도 크게 3가지가 있다.</p>

<ol>
  <li>Have a single directory for entire system</li>
  <li>Have a single directory for each user</li>
  <li>Hierarchical name spaces</li>
</ol>

<p>지난 시간에 다 배웠던 것들이다.</p>

<p>오늘은 Hierarchical name spaces 구현에 대해 조금 더 깊게 알아보자.</p>

<p><img src="/assets/lecture/os/impl/hie.PNG" alt="HIE" /></p>

<p>Hierarchical name spaces 내지는 Hierarchical UNIX는 위와 같은 계층형 구조를 말한다.</p>

<p>계층을 이루게 하는 핵심 요소는 directory이다.</p>

<p>Directory는 근본적으로 -name to inode mapping을 저장하는- 파일이다.</p>

<p>그냥 파일 읽듯이 읽을 수 있고, 파일 저장하듯 저장하면 된다.</p>

<p>한편 계층구조를 탐색하기 위해서는 몇가지 magic이 필요하다.</p>

<p>우선 root directory가 필요하다.</p>

<p>Root directory는 file system이 로드될 때, 자동적으로 inode #2에 할당된다.</p>

<p>이는 “/”로 접근할 수 있다.</p>

<p>이외에도</p>

<ul>
  <li>Current directory: “.”</li>
  <li>Parent directory: “..”</li>
  <li>User’s home directory: “~”</li>
</ul>

<p>등 여러가지 predefine path가 존재한다.</p>

<p>간단한 예제를 통해 이해도를 높여보자.</p>

<p><img src="/assets/lecture/os/impl/ex.PNG" alt="Ex" /></p>

<p>“/a/b/c.c”는 어떤 과정에 의해 찾아질까?</p>

<p>우선 “/” (root directory)가 2번에 있으므로, 여길 참조해서 a의 위치를 얻어낸다.</p>

<p>얻어내보니 3번이고, 3번을 참조해서 b의 위치를 얻어낸다.</p>

<p>얻어내보니 5번이고, 5번을 참조해서 c.c의 위치를 얻어낸다.</p>

<p>얻어내보니 14번이고, 14번을 참조해서 c.c의 저장 위치를 얻어낸다.</p>

<p>이후 c.c의 저장 위치에 접근하여 파일을 읽어들인다.</p>

<p>그런데 이처럼 매번 root directory부터 path를 명시하기에는 너무 귀찮다.</p>

<p>그래서 만약 path가 “/”로 시작하지 않는 경우, 자동적으로 path의 앞에 current working directory가 붙는다.</p>

<p>흔히 상대경로라고 한다.</p>

<p>자 이제, 지금까지 배운 내용을 종합해서 UNIX basic system call의 동작 과정을 자세하게 알아보자.</p>

<ul>
  <li>
    <p>open-read-close cycle</p>

    <p><img src="/assets/lecture/os/impl/1.PNG" alt="Open" /></p>

    <p>우선 path를 분석하여 file inode를 얻어낸다.</p>

    <p><img src="/assets/lecture/os/impl/name.PNG" alt="Namei" /></p>

    <p>namei는 위의 코드를 의미한다.</p>

    <p>그냥 path를 파싱해서 inode를 얻어내는 것이다.</p>

    <p>그리고 process wide descriptor table에 새로운 entry를 할당해준다.</p>

    <p>이때, entry의 index가 fd가 된다.</p>

    <p><img src="/assets/lecture/os/impl/2.PNG" alt="Read" /></p>

    <p>Read는 block 단위로 이뤄진다.</p>

    <p>위에서 배웠던 combined sheme을 적용해서, block 위치를 구해내면 된다.</p>

    <p>읽은 데이터는 buffer cache로 들어오게 된다.</p>

    <p>그냥 한번 읽어보면 금방 이해가 갈 것이다.</p>
  </li>
  <li>
    <p>create-write-close cycle</p>

    <p><img src="/assets/lecture/os/impl/3.PNG" alt="9" /></p>

    <p><img src="/assets/lecture/os/impl/4.PNG" alt="10" /></p>

    <p>위의 것과 비슷하다.</p>
  </li>
</ul>

<h1 id="4-efficiency-and-performance">4. Efficiency and Performance</h1>

<p>이제까지 block-allocatin과 directory-managment options에 대해 배웠다.</p>

<p>이제 어떻게 하면 Efficiency and Performance에 대해서 다룰 차례이다.</p>

<p>기본적으로 efficient use of disk space는 disk allocation and directory algorithms에 크게 영향을 받는다.</p>

<p>또한 file’s directory entry에 저장되는 데이터의 타입또한 영향을 미친다.</p>

<p>이게 무슨 소린가 싶을 건데, 간단히 “last access date” attribute를 생각해보자.</p>

<p>이 attribute는 파일에 접근할 때마다 갱신되어야 하기 때문에, 매 접근마다 파일의 메타데이터 또한 수정해서 다시 디스크에 써야한다.</p>

<p>이는 상당한 overhead를 발생시키기 때문에, 유용성 대비 성능 소모가 얼마나 되는지 잘 판단하여 해당 attribute를 유지할 지 심각히 고려해야 한다.</p>

<p>이런 식으로 각 파일에 얽힌 여러 data item들은 모두 성능 측면에서 심각한 고려가 필요하다는 의미이다.</p>

<p>이런 걸 다 고려해서 최대한 최적의 option을 골랐더라도, 아직 더 성능을 향상시킬 수 있다!</p>

<p>아래는 성능을 향상시킬 수 있는 방법들이다.</p>

<ul>
  <li>
    <p><strong>disk controller cache</strong></p>

    <p><img src="/assets/lecture/os/impl/disk.PNG" alt="Disk" /></p>

    <p>첫 번째 방법은 disk controller에 작은 on-board cache를 추가하는 방법이다.</p>

    <p>이 cache는 한 번에 접근하는 track을 저장하기에 충분한 크기라서, operation이 disk를 접근하지 않고도 일어날 수 있게 해준다.</p>

    <p>참고로 main memory의 block buffer는 읽어들여온 disk block을 저장하는 cache다.</p>
  </li>
  <li>
    <p><strong>free-behind and read-ahead</strong></p>

    <ul>
      <li><strong>Free-behind</strong>
        <blockquote>
          <p>Remove a page from the buffer as soon as the next page is requested. The previous pages are not likely to be used again and waste buffer space</p>
        </blockquote>
      </li>
      <li><strong>Read-ahead</strong>
        <blockquote>
          <p>A requested page and several subsequent pages that are likely to be requested after the current page is processes are read and cached</p>
        </blockquote>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>Improve PC performance by dedicating section of memory as virtual disk, or RAM disk</strong></p>

    <p>Temporal file은 자주 생성되고 자주 삭제되고 자주 접근된다.</p>

    <p>그래서 이런 파일들은 디스크에 저장하기 보단, main memory 쪽에 놔두는 것이 성능 측면이나 저장 측면이나 훨씬 낫다.</p>

    <p>그래서 main memorty 일부를 virtual disk 혹은 RAM disk로 쓰자는 것이다.</p>
  </li>
  <li>
    <p><strong>Unified buffer cache</strong></p>

    <p><img src="/assets/lecture/os/impl/unified.PNG" alt="Unified" /></p>

    <p>일부 시스템은 다시 쓰일 block 들을 저장하두는 <strong>buffer cache</strong>를 제공한다.</p>

    <p>또 메인 메모리 상에서는 block보다 page 친화적이므로, 일부 시스템은 이를 page 형태로 저장하는 <strong>page cache</strong>를 제공한다.</p>

    <p>위 두가지 cache가 주어졌을 때, 그냥 그대로 설치하면 좌측같이 서로 분리된 형태가 나온다.</p>

    <p>그런데 이 경우, mmap I/O가 double caching이 발생하므로 매우 비효율적이다.</p>

    <p>또한 쓸데없이 두 cache 간에 데이터를 옮긴다고 cycle을 소모하기도 한다.</p>

    <p>그래서 그대신 두 cache를 합친 <strong>unified buffer cache</strong>를 주로 사용하는 편이다.</p>
  </li>
</ul>]]></content><author><name>Jaehyun Ha</name><email>yshajae@postech.ac.kr</email></author><category term="Lecture Notes" /><category term="OS" /><category term="CSED312" /><summary type="html"><![CDATA[이 글은 포스텍 박찬익 교수님의 CSED312 운영체제 수업의 강의 내용과 자료를 기반으로 하고 있습니다.]]></summary></entry><entry><title type="html">[OS] File and Directories</title><link href="https://rntlqvnf.github.io/lecture%20notes/os-file/" rel="alternate" type="text/html" title="[OS] File and Directories" /><published>2020-12-16T00:00:00+09:00</published><updated>2020-12-16T00:00:00+09:00</updated><id>https://rntlqvnf.github.io/lecture%20notes/os-file</id><content type="html" xml:base="https://rntlqvnf.github.io/lecture%20notes/os-file/"><![CDATA[<blockquote>
  <p>이 글은 포스텍 박찬익 교수님의 CSED312 운영체제 수업의 강의 내용과 자료를 기반으로 하고 있습니다.</p>
</blockquote>

<p>이제 학기가 얼마 남지 않았다.</p>

<p>벌써 3학년 2학기의 끝이라니, 별로 한 것도 없는데 시간이 훅훅 간다.</p>

<p>한편으론 아직 1년이나 더 남았다는 사실이 참 슬프기도 하다.</p>

<p>문제는 졸업해도 대학원을 가야 한다는 것이다 아..</p>

<p>음.. 여하튼 이번 File system chapter는 정말 글을 쓰기가 어려웠다.</p>

<p>Implementation part에 있어야 할게 나오질 않나, 교과서에 없는 내용이 뜬금없는 위치에 나오질 않나, 전체적인 순서도 이상했다.</p>

<p>흐름이 없으니 글이 매끄럽게 써지지 않았고, 몇 번이나 고쳐야 했다.</p>

<p>유독 OS글을 쓸 때마다 매번 이런 하소연을 하는 것 같다 ㅋㅋ</p>

<p>이 글을 볼 후배님들은 이 글을 읽음으로써 고생을 적게 할 수 있길 바란다 ㅎ</p>

<p>OS는 pintos에 고통받는 것 하나만으로도 충분하다 ㅋㅋㅋㅋ</p>

<p>아 참고로 pintos는 이번 방학 때 간단한 공략집을 올릴 예정이다.</p>

<p>여러가지 세팅이라던가, 기초적으로 알아야 할 지식에 대해 포스팅할 예정이다.</p>

<p>개인적으로 Pintos에 너무 고통을 받았었기 때문에, 후배님들은 이런거에 시달리지 말고 행복한 학기를 살라는 마음에서 포스팅한다 ㅎ</p>

<h1 id="overview">Overview</h1>

<p>이번 포스트에서는 File System Abstraction과 API에 대해서 배운다.</p>

<p>PPT의 순서와 많이 다르니 주의하자!</p>

<h1 id="1-file-concept">1. File Concept</h1>

<p>컴퓨터는 자기 테이프, SDD, HDD 등 많은 storage media에 데이터를 담고 있다.</p>

<p>OS는 이런 데이터들을 좀 더 편하게 다루기 위해, uniform logical view of stored information을 제공한다.</p>

<p>다시 말해 OS는 higer-level abstraction from underlying physical storage device to logical storage unit, <strong>file</strong>을 제공한다.</p>

<p>이로부터 얻어지는 <strong>File</strong>의 정확한 정의는 다음과 같다.</p>

<blockquote>
  <p>A file is a named collection of related information that is recorded on secondary storage</p>
</blockquote>

<p>여기서 secondary storage는 주로 nonvolatile이기 때문에 system reboot를 해도 데이터가 보존된다.</p>

<p>한편 File의 정보는 두가지로 나뉜다. <strong>Metadata</strong>와 <strong>data</strong>가 그것이다.</p>

<ul>
  <li>
    <p><strong>File Metadata</strong></p>

    <p><img src="/assets/lecture/os/file/meta_1.jpg" alt="File MetaData란" /></p>

    <blockquote>
      <p>A file’s metadata is information about file that is understood and managed by the OS</p>
    </blockquote>

    <p>간단히 데이터에 대한 데이터, 내지는 파일에 대한 데이터라고 생각하면 된다.</p>

    <p>예를 들어 파일 사이즈, 최종 수정 시간, 생성한 사람 등등이 있다.</p>
  </li>
  <li>
    <p><strong>File Data</strong></p>

    <blockquote>
      <p>A file’s data can ve whatever information a user or application puts in it.</p>
    </blockquote>

    <p>간단히 데이터 그 자체라고 생각하면 된다.</p>

    <p>데이터 타입에는 numeric, alphabetic, alphanumeric 혹은 binary 정도가 있다.</p>

    <p><img src="/assets/lecture/os/file/data.PNG" alt="File View" /></p>

    <p>File system 관점에서 file’s data란 an array of <strong>untypes</strong> bytes, 좀 더 근본적으론 a sequence of physical block에 불과하다.</p>

    <p>그러나 application 관점에서는 file’s data를 <strong>type</strong> bytes, 즉 특정한 포맷으로 데이터를 저장할 수 있는 record로 간주한다.</p>

    <p>마지막으로 user 관점에서는 persistent data structure로써 file’s data를 바라보게 된다.</p>

    <p>이 관점들은 어떻게 file이 physical storage device를 abstaction 했는지를 알려준다.</p>

    <p>이 Abstraction으로 인해 user level과 system level에서의 file 접근 방법이 사뭇 달라지게 된다.</p>

    <p><img src="/assets/lecture/os/file/diff.PNG" alt="Diff" /></p>

    <p>보다시피, user level에서는 bytes 단위로 명령을 내리지만, 실제로는 block 단위로 명령을 수행하게 된다.</p>
  </li>
</ul>

<p>곧, file system이란 file metadata 및 data와 관련된 여러 기능들을 담당하는 SW라 할 수 있겠다.</p>

<p>좀 더 구체적으로는 아래의 기능들을 담당한다.</p>

<ul>
  <li>Creating, destroying, reading, writing, modifying, moving files</li>
  <li>Controlling access to files</li>
  <li>Management of resources used by files</li>
</ul>

<h2 id="file-attributes">File Attributes</h2>

<p>File Metadata란 곧 file attributes를 말한다.</p>

<p>구체적으로 어떤 attributes가 있는지 알아보자.</p>

<ul>
  <li><strong>Name</strong>
    <blockquote>
      <p>The symbolic file name is the only information kept in humanreadable form.</p>
    </blockquote>
  </li>
  <li><strong>Identifier</strong>
    <blockquote>
      <p>This unique tag, usually a number, <strong>identifies the file within the file system</strong>; it is the non-human-readable name for the file</p>
    </blockquote>
  </li>
  <li><strong>Type</strong>
    <blockquote>
      <p>This information is needed for systems that support different types of files.</p>
    </blockquote>
  </li>
  <li><strong>Location</strong>
    <blockquote>
      <p>This information is a pointer to a device and to the location of the file on that device</p>
    </blockquote>
  </li>
  <li><strong>Size</strong>
    <blockquote>
      <p>The current size of the file (in bytes, words, or blocks) and possibly the maximum allowed size are included in this attribute</p>
    </blockquote>
  </li>
  <li><strong>Protection</strong>
    <blockquote>
      <p>Access-control information determines who can do reading,
writing, executing, and so on.</p>
    </blockquote>
  </li>
  <li><strong>Time, date, and user identification</strong>
    <blockquote>
      <p>This information may be kept for creation, last modification, and last use. These data can be useful for protection, security, and usage monitoring.</p>
    </blockquote>
  </li>
</ul>

<h2 id="file-types">File Types</h2>

<p>File system을 디자인 할 때 아주 중요한 것 중 하나는 OS가 file type을 인식하고 이를 지원할 수 있도록 하는 것이다.</p>

<p>File type을 구현하는 가장 흔히 쓰이는 방법은 file name에 file type을 포함시키는 것이다.</p>

<p>File name은 ‘.’ 을 기준으로 앞은 name, 뒤는 extension이 된다.</p>

<p>예를 들어 hello.cpp 에서 hello는 name, cpp는 extension이다.</p>

<p>OS는 이 extension을 통해 file type을 판단하고, 그에 맞는 적절한 동작을 수행한다.</p>

<p>일반적으로 OS가 지원하는 file types는 다음과 같다.</p>

<p><img src="/assets/lecture/os/file/type.PNG" alt="File types" /></p>

<h2 id="file-structures">File Structures</h2>

<p>File type은 file internal structure을 표시하는데 쓰이기도 한다.</p>

<p>File structure는 그 파일을 읽어들일 프로그램과의 협약이라 할 수 있다.</p>

<p>OS의 경우도 마찬가지이다.</p>

<p>예를 들어 executable file의 경우, OS가 instruction의 위치와 로드할 데이터를 구분할 수 있는 특정 구조를 가져야만 한다.</p>

<p>여기서 질문.</p>

<blockquote>
  <p>Supporting multiple file structures by OS is OK?</p>
</blockquote>

<p>답: NO!</p>

<p>이 경우, OS의 크기가 지나치케 커진다.</p>

<p>예를 들어 5개의 다른 structure를 지원하려면 OS는 5개의 다른 코드를 짜야만 한다.</p>

<p>대신, minimum number of file structure만 지원하고 나머지는 application에게 맡기는 것이 훨씬 효율적이다.</p>

<h1 id="2-directory-and-disk-structure">2. Directory and Disk Structure</h1>

<p>이제 file을 어떻게 저장하는지 알아보자.</p>

<p><img src="/assets/lecture/os/file/div.PNG" alt="Div" /></p>

<p>Storage device는 그 전체가 file system을 저장하는데 쓰일 수도 있지만 finer-grained control을 위해 <strong>하나 혹은 그 이상의 partitions</strong>로 나눠질 수 있다.</p>

<p>이 Partition는 file system로 쓸 수도 있고, swap space 로 쓸 수도 있고, unformatted (raw) disk로 놔둘 수도 있다.</p>

<p>만약 partition에 file system이 들어간다면, 이를 <strong>volume</strong>이라고 부른다.</p>

<p><strong>Volume</strong>은 subset of device, whole device, 혹은 multiple deivce linked together (그림에서 오른쪽) 중 하나의 형태로 나타난다.</p>

<p>한편 volume은 반드시 자신이 갖고있는 file system에 대한 정보를 담고 있어야 한다.</p>

<p>이 정보가 담겨있는 곳이 바로 <strong>device directory</strong>이다.</p>

<p><strong>Device directory</strong>는 각 파일에 대한 file attributes를 저장하고 있다.</p>

<h2 id="storage-structure">Storage Structure</h2>

<p>앞서 보았듯, 한 컴퓨터는 여러가지 형태의 file system을 가질 수 있다.</p>

<p>예를 들어, Solaris는 아래의 file system으로 구성되어 있다.</p>

<p><img src="/assets/lecture/os/file/solr.PNG" alt="Solor" /></p>

<ul>
  <li><strong>tmpfs</strong>
    <blockquote>
      <p>“temporary” file system that is created in volatile main memory and has its contents erased if the system reboots or crashes</p>
    </blockquote>
  </li>
  <li><strong>objfs</strong>
    <blockquote>
      <p>“virtual” file system (essentially an interface to the kernel that looks like a file system) that gives debuggers access to kernel symbols</p>
    </blockquote>
  </li>
  <li><strong>ctfs</strong>
    <blockquote>
      <p>a virtual file system that maintains “contract” information to manage which processes start when the system boots and must continue to run during operation</p>
    </blockquote>
  </li>
  <li><strong>lofs</strong>
    <blockquote>
      <p>a “loop back” file system that allows one file system to be accessed in place of another one</p>
    </blockquote>
  </li>
  <li><strong>procfs</strong>
    <blockquote>
      <p>a virtual file system that presents information on all processes as a file system</p>
    </blockquote>
  </li>
  <li><strong>ufs, zfs</strong>
    <blockquote>
      <p>general-purpose file systems</p>
    </blockquote>
  </li>
</ul>

<p>우리가 다룰 것은 이중 general-purpose file systems 이다.</p>

<h2 id="directory">Directory</h2>

<p>앞서 directory란 각 파일에 대한 file attributes를 담고 있는 공간이라고 했다.</p>

<p>좀 더 구체적으로 정의하자면 아래와 같다.</p>

<blockquote>
  <p>A symbol table that <strong>translates file names into their directory entries</strong></p>
</blockquote>

<p>이 관점에서 보았을 때, directory는 아래의 기능을 지원해야 할 것이다.</p>

<ul>
  <li>insert entry</li>
  <li>delete entry</li>
  <li>search for named entry</li>
  <li>list all the entries in the directory</li>
</ul>

<p>이 사실을 염두에 두고, directory를 구현하는 몇 가지 방법들에 대해 알아보자.</p>

<h3 id="single-level-directory">Single-Level Directory</h3>

<p><img src="/assets/lecture/os/file/single.PNG" alt="Single" /></p>

<blockquote>
  <p>A single directory for all users</p>
</blockquote>

<ul>
  <li><strong>단점</strong>
    <ul>
      <li><strong>Naming problem</strong>
        <blockquote>
          <p>파일의 숫자가 늘어나고 시스템이 여러 유저에 의해 사용되면 모든 파일들은 같은 디렉토리에 있으므로 unique name을 가져야 한다. 파일이 엄청 늘어나면 이름을 기억하기도 힘들어 질 것이다.</p>
        </blockquote>
      </li>
      <li><strong>Grouping problem</strong>
        <blockquote>
          <p>Grouping이 지원이 안된다.</p>
        </blockquote>
      </li>
    </ul>
  </li>
</ul>

<h3 id="two-level-directory">Two-Level Directory</h3>

<p><img src="/assets/lecture/os/file/two.PNG" alt="Two" /></p>

<blockquote>
  <p>Separate directory for each user</p>
</blockquote>

<ul>
  <li><strong>장점</strong>
    <ul>
      <li>
        <p><strong>Efficent Search</strong></p>
      </li>
      <li>
        <p><strong>Can have the same file name for different user</strong></p>
        <blockquote>
          <p>사용자가 파일을 접근 할 때는 오직 자신의 UFD(user file directory)만 검색한다. 그러므로 다른 파일 이름을 가질 수 있다.</p>
        </blockquote>
      </li>
    </ul>
  </li>
  <li><strong>단점</strong>
    <ul>
      <li><strong>No grouping capability</strong>
        <blockquote>
          <p>여전히 Grouping이 지원이 안된다.</p>
        </blockquote>
      </li>
      <li><strong>Isolation</strong>
        <blockquote>
          <p>한 사용자를 다른 사용자로부터 고립시킨다. 이것은 장점이 될 수도 있지만 태스크를 공유하고 싶을 때는 단점이 된다.</p>
        </blockquote>
      </li>
    </ul>
  </li>
</ul>

<h3 id="tree-structured-directory">Tree-Structured Directory</h3>

<p><img src="/assets/lecture/os/file/tree.PNG" alt="Tree" /></p>

<blockquote>
  <p>Extend the directory structure to a tree of arbitrary height</p>
</blockquote>

<ul>
  <li><strong>장점</strong>
    <ul>
      <li>
        <p><strong>Efficent Search</strong></p>
      </li>
      <li>
        <p><strong>Grouping capability</strong></p>
        <blockquote>
          <p>Subdirectory를 이용한 grouping이 지원된다.</p>
        </blockquote>
      </li>
    </ul>
  </li>
  <li><strong>단점</strong>
    <ul>
      <li><strong>No co-pointing</strong>
        <blockquote>
          <p>하나의 파일이 하나만 가리키므로 하나의 파일을 여러개가 동시에 접근 불가능</p>
        </blockquote>
      </li>
    </ul>
  </li>
  <li><strong>새로운 개념</strong>
    <ul>
      <li><strong>Subdirectory</strong>
        <blockquote>
          <p>하위 directory. Directory considered as file!</p>
        </blockquote>
      </li>
      <li><strong>Current directory</strong> (a.k.a working directory)
        <ul>
          <li>eg) <strong>cd</strong> / spell/mail/prog</li>
        </ul>
      </li>
      <li><strong>Path name</strong>
        <ul>
          <li><strong>Absolute</strong>
            <blockquote>
              <p>begins at the root and follows a path down to the specified file, giving the directory names on the path</p>
            </blockquote>

            <ul>
              <li>ex) root/spell/mail/prt/first</li>
            </ul>
          </li>
          <li><strong>Relative</strong>
            <blockquote>
              <p>defines a path from the current directory</p>
            </blockquote>

            <ul>
              <li>ex) prt/first</li>
            </ul>
          </li>
          <li><strong>Speical path name</strong>
            <ul>
              <li><strong>’.’</strong>  :  working directory</li>
              <li><strong>’..’</strong>  :  parent directory</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li><strong>논의</strong>
    <ul>
      <li>Deleting a directory?
        <blockquote>
          <p>디렉토리가 비어있으면 그냥 지우면 되지만 안비어 있으면 2가지중 하나를 선택해야 한다. 첫째는 지우지 못하도록 하는 것이고 둘째는 옵션을 주는 것이다. 내용들을 날리거나 지우지 않거나 선택하게 한다. 두번째가 편리하지만 위험할 수 있다.</p>
        </blockquote>
      </li>
    </ul>
  </li>
</ul>

<h3 id="acyclic-graph-directory">Acyclic-Graph Directory</h3>

<p><img src="/assets/lecture/os/file/acy.PNG" alt="Acy" /></p>

<ul>
  <li><strong>장점</strong>
    <ul>
      <li><strong>Allow co-pointing</strong>
        <blockquote>
          <p>Tree-Structured에선 지원하지 않던 서로 다른 이름이 같은 파일 pointing 가능</p>
        </blockquote>
      </li>
    </ul>
  </li>
  <li><strong>단점</strong>
    <ul>
      <li><strong>Overhead when traversing</strong>
        <blockquote>
          <p>똑같은 파일을 두 번 탐색할 가능성</p>
        </blockquote>
      </li>
    </ul>
  </li>
  <li><strong>새로운 개념</strong>
    <ul>
      <li><strong>New directory entry type</strong>
        <ul>
          <li><strong>Link</strong>
            <blockquote>
              <p>Another name to an existing file</p>
            </blockquote>
          </li>
          <li><strong>Resolve the link</strong>
            <blockquote>
              <p>Follow pointer to locate the file</p>
            </blockquote>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li><strong>논의</strong>
    <ul>
      <li><strong>Dangling pointer</strong>
        <blockquote>
          <p>하나의 파일을 삭제하였을 때 그 파일을 공유하고 있던 다른 파일은 잘못된 pointer를 가지는 현상</p>
        </blockquote>

        <ul>
          <li>Solution: Reference count를 세서, count가 0이 될 때만 삭제되도록 함</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<h4 id="hard-link">Hard Link</h4>

<p><a href="https://jybaek.tistory.com/578">추천 블로그</a></p>

<p>Link에 대한 개념을 좀 더 심화시켜보자.</p>

<p><strong>Hard Link</strong>란, a directory mapping from a file name directly to an underlying file을 말한다.</p>

<p>곧, 우리가 파일을 만들 때(e.g., /a/b) 생기는 directory entry는 새로운 파일과의 hard link가 된다.</p>

<p>만약 같은 파일에 link()를 써서 hard link를 하나 더 만든다는 것은(e.g. link(“/a/b”, “/c/d”)), 같은 파일에 다른 두 개의 이름을 주는 것이 된다.</p>

<p>그리고 만약 unlink(“/a/b”)를 한다면, “/c/d”가 해당 파일을 가리키는 유일한 valid name으로 남는다.</p>

<p>거기에 이어 unlink(“/c/d”)를 해서 모든 hard link가 사라지면(reference count == 0) file이 삭제된다.</p>

<h4 id="soft-link">Soft Link</h4>

<p><strong>Soft link</strong> or <strong>Symbolic link</strong>란, directory mappings from a file name to <strong>another file name</strong>을 말한다.</p>

<p>Soft link로 원래 file을 얻어내는 과정은 이렇다.</p>

<ol>
  <li>
    <p>Soft link로 파일을 연다.</p>
  </li>
  <li>
    <p>파일로부터 target name을 구해낸다.</p>
  </li>
  <li>
    <p>Target name을 통해 target file을 연다.</p>
  </li>
</ol>

<p>Soft link는 file이 아니라, file 이름을 가리키는 link다.</p>

<p>실제로 inode를 찍어보면 hard link의 inode와 soft link의 inode는 다르다.</p>

<p>따라서 hard link reference count에 속하지 않으므로 모든 hard link가 제거되면 설령 soft link가 남아있더라도 파일은 삭제되며, soft link는 유효하지 않은 link가 된다.</p>

<p>예를 들어 만약 “/a/b”를 만들고, “/a/b”로의 soft link “/c/d”를 만든 다음 unlink(“/a/b”)를 한다면 open(“/c/d”)는 실패하게 된다.</p>

<p>일종의 바로가기라고 생각하면 이해하기 쉽다.</p>

<h1 id="3-file-system-apis">3. File System APIs</h1>

<p>기초적인 file system의 구조에 대해선 알아봤고, 이제 file system이 제공해야 하는 기능에 대해 구체적으로 알아보자.</p>

<p>File system에서 제공하는 기능, 즉 API를 몇가지 중요한 것만 추려보면 다음과 같다.</p>

<ul>
  <li>create, link, unlink, mkdir, rmdir, rename</li>
  <li>open, close, read, write, seek</li>
  <li>fsync
    <ul>
      <li>Force modification in cache (volatile memory) to disk</li>
    </ul>
  </li>
  <li>stat
    <ul>
      <li>Show the file metadata</li>
    </ul>
  </li>
</ul>

<p>create, link, unlink는 간단히 알아보았고, 이번 챕터에선 open, read, write에 대해 알아보자.</p>

<h2 id="open">open()</h2>

<p>open()을 이해하기 위해선 in-memory file data structure에 대해 이해해야 한다.</p>

<p><img src="/assets/lecture/os/file/ds.PNG" alt="DS" /></p>

<p>File system은 Disk, non-volatile memory에는 우측의 구조로 저장되어 있다.</p>

<p>빠른 파일 접근을 위해, 이 중 file descriptor, 즉 file metadata part를 메모리에 불러 들이는 것이 목적이다.</p>

<p>그런데 이 메타데이터를 바로 process가 바로 쓰는 것이 아니라, 중간에 system wide table을 하나 거쳐야 한다.</p>

<p>System-wide open file table은 process간에 공유하는 table로써, file pos, reference count 등 파일 접근에 관한 데이터를 담고 있다.</p>

<p>한편 process-wide open file table은 process 고유의 table로, 현재 process가 어떤 file을 열고 있는지 표시하고 각각의 entry(file)에 file descriptor number를 부여하는 역할을 한다.</p>

<p><img src="/assets/lecture/os/file/2.PNG" alt="2" /></p>

<p>system-wide table이 왜 필요한지 살짝 감이 안 잡힐 수 있다.</p>

<p>예를 들어 Process가 open을 두 번 불렀을 때를 상정해보자.</p>

<p>만약 system-wide table이 없다면 각각의 호출에서 얻은 descriptor는 아무 차이가 없게 되고, 이는 의미없는 동작이 되어버린다.</p>

<p>반대로 system-wide table을 도입한다면 같은 파일을 사용하지만 서로 독립적으로 동작하는 descriptor를 얻을 수 있다.</p>

<p><img src="/assets/lecture/os/file/unix.PNG" alt="Unix" /></p>

<p>위는 UNIX 에서의 in-memory structure이다. (Inode index는 file에 주어지는 고유 번호이다)</p>

<p>자 이제 open()의 동작을 구체적으로 알아보자.</p>

<p><img src="/assets/lecture/os/file/open.PNG" alt="Open" /></p>

<p>아마 in-memory data structure을 제대로 이해했다면 굉장히 쉬울 것이다.</p>

<p>그냥 각 table에 entry를 만들어줄 뿐이다.</p>

<h2 id="read">read()</h2>

<p><img src="/assets/lecture/os/file/read.PNG" alt="READ" /></p>

<p>흐름만 알면 쉽다.</p>

<p>fd가 주어지면, Process-wide open file table을 조회하여 system-wide table entry를 얻어낸다.</p>

<p>여기서 한 단계 더 타서 file metadata를 얻어내어, user to file system translation(desc to device, buf to block)을 해준다.</p>

<p>디스크에서 읽어들인 값은 cache를 지나 최종적으로 userBuf에 들어가게 된다.</p>

<p>Buffer cache에 대해서는 다음 시간에 배울 것이고, 지금은 그냥 디스크와 메모리 사이에서 전달되는 데이터를 캐시하는 공간으로 생각하면 된다.</p>

<h2 id="write">write()</h2>

<p><img src="/assets/lecture/os/file/write.PNG" alt="Write" /></p>

<p>read()와 전혀 다를 바가 없다.</p>

<p>다만 위에서는 디스크에서 들어오는 데이터를 캐시하는 용도였던 buffer cache가 지금은 write buffer로써 역할을 하는 것만 기억하면 된다.</p>

<h1 id="4-file-system-mounting">4. File System Mounting</h1>

<p>File system의 구조와 동작에 대해서 알아보았다.</p>

<p>이제는 file system을 어떻게 로드하는지 알아볼 차례이다.</p>

<p>File system은 그냥 디스크에 있다고 적용되는게 아니라, os에 mount를 해야 한다.</p>

<p>사용하고 싶은 파일을 소유한 파일 시스템을 특정한 directory(a.k.a <strong>mount point</strong>)에 mount하면 그 때부터 그 파일을 사용 가능한 것이다.</p>

<p>일반적으로 mount point는 비어있는 directory이다.</p>

<p><img src="/assets/lecture/os/file/mount.PNG" alt="Mount" /></p>

<p>위는 간단한 예시이다.</p>

<p>(a)의 경우, 우측에 있는 /sue, /jane 등은 현재 접근 불가능하다.</p>

<p>(b)는 우측의 file system을 /users에 mounting 한 것이다. 이제야 비로소 /sue, /jane이 접근 가능하다.</p>

<h1 id="5-file-sharing-and-protection">5. File Sharing And Protection</h1>

<p>딱히 교수님이 이 부분을 설명하시진 않았지만, 혹시 모르니 간단하게 짚고 넘어가려고 한다.</p>

<p>User간에 file sharing은 필수적인 기능이다.</p>

<p>그러나 항상 sharing은 protection issue를 낳는다.</p>

<p>Protection issue를 해결하기 위한 가장 기본적인 아이디어는 access permission을 제어하는 것이다.</p>

<p>다만 multi-user 환경이기 때문에, 좀 더 세밀한 권한 제어를 위해 <strong>file owner</strong>와 <strong>group</strong>이라는 개념을 도입한다.</p>

<p><strong>Owner</strong>는 파일의 attributes를 바꿀 수 있고, 접근 권한을 부여할 수 있는 등 파일에 대한 최대한의 권한을 갖는 user를 말한다.</p>

<p><strong>Group</strong>는 접근 권한을 공유하는 user 집합을 의미한다.</p>

<p>이 개념을 적용하면, 파일에의 접근 권한을 owner / group / public (other user)로 세분화 할 수 있다.</p>

<p><img src="/assets/lecture/os/file/cm.PNG" alt="CM" /></p>

<p><img src="/assets/lecture/os/file/per.PNG" alt="Per" /></p>

<p>이때, UNIX에서는 접근 권한을 3 bit 로 표현한다.</p>

<p>파일에 접근 권한을 지정하는 명령어는 <code class="language-plaintext highlighter-rouge">chmod</code>이다.</p>

<p><img src="/assets/lecture/os/file/chmod.PNG" alt="CHMOD" /></p>

<p>예를 들어 위의 명령어는 game 파일의 접근 권한을 owner는 rwx, group은 rw-, public은 –x 로 지정한다.</p>

<h1 id="6-참고자료">6. 참고자료</h1>

<ul>
  <li><a href="https://bywords.tistory.com/category/Computer%20Science">건빵의 블로그</a></li>
</ul>]]></content><author><name>Jaehyun Ha</name><email>yshajae@postech.ac.kr</email></author><category term="Lecture Notes" /><category term="OS" /><category term="CSED312" /><summary type="html"><![CDATA[이 글은 포스텍 박찬익 교수님의 CSED312 운영체제 수업의 강의 내용과 자료를 기반으로 하고 있습니다.]]></summary></entry><entry><title type="html">[OS] Cache and Virtual Memory</title><link href="https://rntlqvnf.github.io/lecture%20notes/os-cache/" rel="alternate" type="text/html" title="[OS] Cache and Virtual Memory" /><published>2020-12-14T00:00:00+09:00</published><updated>2020-12-14T00:00:00+09:00</updated><id>https://rntlqvnf.github.io/lecture%20notes/os-cache</id><content type="html" xml:base="https://rntlqvnf.github.io/lecture%20notes/os-cache/"><![CDATA[<blockquote>
  <p>이 글은 포스텍 박찬익 교수님의 CSED312 운영체제 수업의 강의 내용과 자료를 기반으로 하고 있습니다.</p>
</blockquote>

<p>지난번 OS 포스트가 무려 예상 읽는시간 19분을 달성했다.</p>

<p>그렇게 오래 걸린 글은 난생 처음이었다.</p>

<p>근데 이번 포스트는 지난번 보다 더 어려울 것 같다.</p>

<p>PPT 순서가 너무 꼬여있다.</p>

<p>이전에는 그래도 나름 전공책 순서를 따라가기라도 했는데, 이번 PPT는 아예 완전 섞어놨다.</p>

<p>이래서 OS 글쓰기가 참 싫다..</p>

<h1 id="1-demand-paging">1. Demand Paging</h1>

<p>지난 포스트에선 Address Translation Technique이 제공하는 몇가지 기능들에 대해 알아보았었다.</p>

<p>오늘은 아래의 남은 기능들에 대해서 알아볼 것이다.</p>

<ul>
  <li>Demand Paging</li>
  <li>Memory mapped files</li>
  <li>Modified bit emulation</li>
  <li>Use bit emulation</li>
</ul>

<p>가장 먼저 알아볼 것은 <strong>demand paging</strong>이다.</p>

<p>프로그램이 disk에서 memory로 로드되는 상황을 생각해보자.</p>

<p>가장 간단한 구현 방법은 전체 프로그램을 memory에 올리는 것이다.</p>

<p>그러나 프로그램을 실행하는데에 있어서 굳이 전체 프로그램을 memory에 올려야만 할까?</p>

<p>필요한 것만 그때그때 올리면 훨씬 더 효율적이지 않을까?</p>

<p>이 아이디어가 바로 <strong>demand paging</strong>이다.</p>

<p>Demand-paged virtual memory에서 page는 프로그램이 실행되면서 해당 page가 필요해질 때에 비로소 로드된다.</p>

<p>따라서 프로그램이 실행될 동안 한 번도 접근하지 않은 page는 memory로 로드되지 않는다.</p>

<p>이를 통해 memory 공간을 효율적으로 사용할 수 있고, 더 많은 프로그램을 동시에 실행할 수 있게 만든다.</p>

<p>Demand paging 구현의 핵심은 <strong>page fault trap</strong>이다.</p>

<p>Page fault는 memory에 적재되지 않은 page를, 즉 invalid page를 접근하려고 할 때 발생한다.</p>

<p>Page fault handler는 이 상황을 두 경우로 나누어 처리한다.</p>

<ol>
  <li><strong>Illegal reference</strong>
    <blockquote>
      <p>Abort</p>
    </blockquote>
  </li>
  <li><strong>Legal but not-in-memory</strong>
    <blockquote>
      <p>Bring page to memory from disk, Set valid bit in page table</p>
    </blockquote>
  </li>
</ol>

<p>2번 과정이 demand paging의 구현의 핵심이다.</p>

<p>OS는 모든 page를 처음에 invalidate 상태로 초기화한다.</p>

<p>이후 page에 처음으로 접근한다면 page fault가 발생할 것이고 2번 과정에 의해 demand paging이 구현되는 것이다.</p>

<p><img src="/assets/lecture/os/cache/pagefault.PNG" alt="Page Fault" /></p>

<p>구체적으론 위 그림의 순서대로 일어난다.</p>

<p>그런데 재밌는 점은 HW-loaded TLB인지 SW-loaded TLB인지에 따라 과정이 약간 다르다.</p>

<ul>
  <li>
    <p><strong>Demand Paging in HW-loaded TLB</strong></p>

    <ol>
      <li><strong>TLB miss</strong></li>
      <li><strong>Page table walk</strong></li>
      <li>Page fault</li>
      <li>Trap to kernel</li>
      <li>Convert virtual address to file + offset
        <blockquote>
          <p>Page data is part of file in secondary storage(disk). File could be program file, swap file or some other files.</p>
        </blockquote>
      </li>
      <li>Allocate page frame (<strong>Evict page if needed</strong>)
        <blockquote>
          <p>We have to make empty room first to write data from disk.</p>
        </blockquote>
      </li>
      <li>Initiate disk block read into page frame</li>
      <li>Disk interrupt when DMA complete</li>
      <li>Mark page as valid</li>
      <li>Resume process at faulting instruction</li>
      <li><strong>TLB miss</strong></li>
      <li><strong>Page table walk to fetch translation</strong></li>
      <li>Execute instruction</li>
    </ol>

    <p><br />
12, 13 번 과정을 보면, 다시 TLB miss가 일어났다.</p>

    <p>왜 이렇게 될까?</p>

    <p>만약 page fault(SW)가 발생하지 않았다면 HW가 translation을 완료한 다음 TLB에 로드를 했겠지만, page fault(SW)로 과정이 넘어갔으므로 그렇게 하지 못한 것이다.</p>

    <p>그러면 SW가 translation (page table walk)를 담당한다면 TLB도 로드할 수 있을 것이다.</p>

    <p>이것이 Demand Paging in <strong>SW-loaded TLB</strong>와 in <strong>HW-loaded TLB</strong>이 가지는 차이점이다.</p>
  </li>
  <li>
    <p><strong>Demand Paging in SW-loaded TLB</strong></p>

    <ol>
      <li><strong>TLB miss</strong></li>
      <li><strong>Trap to kernel</strong></li>
      <li>Page table walk</li>
      <li>Find page is invalid</li>
      <li>Convert virtual address to file + offset
        <blockquote>
          <p>Page data is part of program file in secondary storage (disk)</p>
        </blockquote>
      </li>
      <li>Allocate page frame (<strong>Evict page if needed</strong>)
        <blockquote>
          <p>We have to make empty room first to write data from disk</p>
        </blockquote>
      </li>
      <li>Initiate disk block read into page frame</li>
      <li>Disk interrupt when DMA complete</li>
      <li>Mark page as valid</li>
      <li><strong>Load TLB entry</strong></li>
      <li>Resume process at faulting instruction</li>
      <li>Execute instruction</li>
    </ol>

    <p><br />
보다시피, SW-loaded TLB에서는 SW가 translation을 담당하므로 TLB miss가 난 후 Page table walk가 아닌 kernel trap이 발생하게 된다.</p>

    <p>이 Trap handler에서 translation을 마친 뒤, TLB에 load를 하므로 이후에 또 TLB miss를 발생시키지 않는다.</p>

    <p>이것만 보면 이게 무조건 좋아보이지만, 기본적으로 SW는 HW보다 느리다는 사실을 까먹으면 안된다.</p>
  </li>
</ul>

<p>한편 위 과정에서 눈여겨봐야 할 부분은 <strong>Allocate page frame</strong> 과정이다.</p>

<p>괄호에서 언급했듯, 만약 free space가 없다면 page를 하나 버려서 공간을 비워줘야 한다.</p>

<p>이 Eviction 과정이 상당히 까다롭다.</p>

<p>일단 버릴 페이지를 어떤 기준으로 골라야 하는지도 꽤 어려운 문제이다.</p>

<p>이에 관해서는 <a href="#3-page-replacement-policy">3. Page Replacement Policy</a>에서 얘기하도록 하고 지금은 어떻게 잘 골랐다고 해보자.</p>

<p>그러면 우선 이 old page를 가리키고 있는 모든 page table entries를 invalidate 해야한다. (여기서 core map이 사용된다)</p>

<p>거기에 추가로 TLB shootdown을 통해 모든 TLB에서 관련된 entry를 지워야 한다.</p>

<p>그리고 마지막으로 old page가 dirty page인 경우 disk로의 write back도 해야한다.</p>

<p>그런데 마지막 과정에서 약간 의문이 든다.</p>

<blockquote>
  <p>어떻게 page가 dirty인지 알 수 있을까?</p>
</blockquote>

<p>가장 효율적인 방법은 page table entry에 해당 page가 modified 되었는지 표시하는 additional bit를 저장하는 것이다. (a.k.a <strong>bookkeeping</strong>)</p>

<p>이 additional bit, 즉 dirty bit는 OS에 의해 0으로 초기화 된다.</p>

<p>이후 해당 page로의 wirte 가 발생하면 HW에 의해 자동으로 1로 바뀌며 dirty 임을 표시하는 것이다.</p>

<p>한편 TLB는 page table entry의 copy를 저장하므로, TLB도 당연히 dirty bit을 가진다.</p>

<p>주의할 점은 TLB의 dirty dit가 0에서 1로 올라갈 때 이와 연관된 page table entry도 업데이트 해야 한다는 점이다.</p>

<p>참고로 dirty bit 뿐만이 아니라 해당 page가 최근에 used 되었는지 표시하는 used bit도 같이 저장하는 편이다.</p>

<p>아래의 두 그림은 first store instruction이 발생했을 때의 TLB, page table, memory, disk의 동작을 보여준다.</p>

<p><img src="/assets/lecture/os/cache/ex1.PNG" alt="Ex1" /></p>

<p><img src="/assets/lecture/os/cache/ex2.PNG" alt="Ex2" /></p>

<p>다시 질문으로 돌아와서, <strong>어떻게 page가 dirty(modified)인지 알 수 있을까?</strong></p>

<p>한 page를 가리키는 여러개의 page table entry가 존재할 수 있으므로, 이 여러개의 entry 중 dirty bit가 1인 entry가 하나 이상 존재한다면 <strong>modified</strong>라고 판단한다.</p>

<p>반대로 모든 entry의 dirty bit가 0이라면 <strong>unmodified</strong>라고 판단한다.</p>

<h2 id="emulating">Emulating</h2>

<p>재미있게도, hardware support for a dirty/use bit가 꼭 필요한 것은 아니다.</p>

<p>OS는 dirty/use bit를 access permission을 이용해서 dirty/use bit을 emulate(모방)할 수 있다.</p>

<p>구체적은 구현법은 TLB의 종류에 따라 두 가지로 나뉜다.</p>

<ul>
  <li>
    <p><strong>Emulating modified/use bit (HW loaded TLB)</strong></p>

    <p>Page table access permission을 통해 dirty bit를 모방하는 것이 핵심 아이디어다.</p>

    <p>동작 과정은 아래와 같다.</p>

    <ul>
      <li>
        <p>모든 clean page를 <strong>read-only</strong>로 초기화한다.</p>
      </li>
      <li>
        <p>Page로의 <strong>first write</strong>가 발생하면, HW에 의해 memory exception이 발생한다.</p>
      </li>
      <li>
        <p>OS는 page의 permission을 <strong>read-write</strong>로 바꾸어 dirty 임을 기록한다.</p>
      </li>
    </ul>

    <p>보다시피, true page table permission과 current page table permission 두 가지를 유지해야 한다.</p>

    <p>Used bit를 구현하는 것도 거의 동일하다.</p>

    <p>다만 first <strong>read/write</strong>를 모두 감지해야 하기 때문에, page를 read-only가 아니라 <strong>invalid</strong>로 초기화해야 한다.</p>

    <ul>
      <li>
        <p>모든 clean page를 <strong>invalid</strong>로 초기화한다.</p>
      </li>
      <li>
        <p>Page로의 <strong>first read/write</strong>가 발생하면, HW에 의해 exception이 발생한다.</p>
      </li>
      <li>
        <p>OS는 page의 permission을 <strong>read or read-write</strong>로 바꾸어 used 임을 기록한다.</p>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>Emulating modified/use bit (SW loaded TLB)</strong></p>

    <p>SW loaded TLB에서는 TLB miss 또는 permission exception이 발생했을 때 <strong>trap to kernel</strong>이 발생한다.</p>

    <p>그래서 HW loaded TLB는 달리, page table walk 까지 가지 않고 trap handler에서 곧바로 emulation을 구현할 수 있다.</p>

    <p>구체적인 동작 과정은 아래와 같다.</p>

    <ul>
      <li><strong>On a TLB read miss</strong>
        <ul>
          <li>If page is <strong>clean</strong>, load TLB entry as <strong>read-only</strong></li>
          <li>If page is <strong>dirty</strong>, load as <strong>r/w</strong></li>
          <li>Mark page as recently used</li>
        </ul>
      </li>
      <li><strong>On a TLB write to an unmodified page</strong>
        <ul>
          <li>Kernel marks page as modified in its page table</li>
          <li><strong>Reset</strong> TLB entry to be read-write (Already entry is in TLB, so re-set)</li>
          <li>Mark page as recently used</li>
        </ul>
      </li>
      <li><strong>On a TLB write miss</strong>
        <ul>
          <li>Kernel marks page as modified in its page table</li>
          <li><strong>Load</strong> TLB entry ad read-write (No entry in TLB, so load)</li>
          <li>Mark page as recently used</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<h1 id="2-memory-mapped-files">2. Memory-Mapped Files</h1>

<p>File I/O를 수행하는 두 가지 모델이 있다.</p>
<ol>
  <li><strong>Explicit read/write system call</strong>
    <ul>
      <li>
        <p>Read/write system calls allow the program to work on a copy of file data</p>
      </li>
      <li>
        <p><strong>Read syscall</strong>: Copy chunks of file data into buffers in the program’s address space</p>
      </li>
      <li>
        <p><strong>Write syscall</strong>: Use to write changes back to the file. Write the data from the copy of file in program buffers out to disk.</p>
      </li>
      <li>
        <p>Simple to understand, reasonably efficient for small file.</p>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>Memory-mapped files</strong></p>

    <blockquote>
      <p>Map file contents into the program’s virtual address space</p>
    </blockquote>

    <p><img src="/assets/lecture/os/cache/seg.PNG" alt="Seg" /></p>

    <p>이 모델의 핵심은 file을 <strong>program segment</strong>로 간주하는 것이다.</p>

    <p>다시 말해, file을 별도의 data structure로 생각하지 말고 그냥 우리가 이제껏 해왔던 paging을 적용해 file을 page 단위로 잘라서 여타 page와 동일하게 동작하게 하는 것이다.</p>

    <p>곧, 1번처럼 복잡하게 copy를 할 필요 없이, 그냥 physical memory를 disk에 대한 write-back cache로 간주하여 direct access를 할 수 있는 것이다.</p>

    <p>이러면 우리가 이제까지 해왔던 demand paging, copy on write 등의 feature들의 혜택을 그대로 누릴 수 있다!</p>

    <p>이외에 어떤 장점들이 있을까?</p>

    <ul>
      <li><strong>Zero copy I/O</strong>
        <blockquote>
          <p><strong>The operating system does not need to copy file data from kernel buffers into user memory and back</strong>; rather, it just changes the program’s page table entry to point to the physical page frame containing that portion of the file.</p>
        </blockquote>
      </li>
      <li><strong>Pipelining</strong>
        <blockquote>
          <p><strong>The program can start operating on the data in the file as soon as the page tables have been set up</strong>; it does not need to wait for the entire file to be read into memory.</p>
        </blockquote>
      </li>
      <li><strong>Interprocess communication</strong>
        <blockquote>
          <p>Two or more processes <strong>can share information instantaneously through a memory-mapped file</strong> without needing to shuffle data back and forth to the kernel or to disk</p>
        </blockquote>
      </li>
      <li><strong>Large files</strong>
        <blockquote>
          <p>As long as the page table for the file can fit in physical memory, <strong>the only limit on the size of a memory-mapped file is the size of the virtual address space</strong></p>
        </blockquote>
      </li>
    </ul>
  </li>
</ol>

<h1 id="3-page-replacement-policy">3. Page Replacement Policy</h1>

<blockquote>
  <p>On a page eviction, how do we choose which entry to replace?</p>
</blockquote>

<p>자 이제 1번에서 예고했던 Page Replacement Policy에 관해서 다뤄볼 차례이다.</p>

<p>지지난 포스트의 scheduling policy와 큰 차이는 없다.</p>

<p><a href="#clock-algorithm">Clock algorithm</a> 정도만 제대로 이해하면 된다.</p>

<h2 id="fifo">FIFO</h2>

<blockquote>
  <p>Replace the entry that has been in the cache the longest time</p>
</blockquote>

<p><img src="/assets/lecture/os/cache/fifo.PNG" alt="FIFO" /></p>

<h2 id="min-lru-lfu">MIN, LRU, LFU</h2>

<ul>
  <li><strong>MIN</strong>
    <blockquote>
      <p>Replace the cache entry that <strong>will not used for the longest time into the future</strong></p>
    </blockquote>

    <ul>
      <li>
        <p>Optimal: Minimum cache miss</p>
      </li>
      <li>
        <p>Not feasible: Have to predict future</p>
      </li>
    </ul>
  </li>
  <li><strong>LRU</strong>
    <blockquote>
      <p>Replace the cache entry that <strong>has not been used for the longest time in the past</strong></p>
    </blockquote>

    <ul>
      <li>Approximation of MIN</li>
    </ul>
  </li>
  <li><strong>LFU</strong>
    <blockquote>
      <p>Replace the cache entry <strong>used the lest often (int the recent past)</strong></p>
    </blockquote>
  </li>
</ul>

<p><img src="/assets/lecture/os/cache/lru_min.PNG" alt="LRU MIN" /></p>

<h2 id="beladys-anomaly">Belady’s anomaly</h2>

<p>여기서 질문!</p>

<blockquote>
  <p>Page frame을 더 많이 만들면 miss가 더 적게 날까?</p>
</blockquote>

<p>되게 당연해보이지만, 놀랍게도 정답은 <strong>그렇지 않다</strong></p>

<p>FIFO policy를 사용한다고 하자.</p>

<p><img src="/assets/lecture/os/cache/anomaly.PNG" alt="Anomaly" /></p>

<ul>
  <li><strong>3 page frames</strong>
    <ul>
      <li>A, B, C, D, A, B, E, A, B, C, D, E</li>
      <li>9 page fault(miss)</li>
    </ul>
  </li>
  <li><strong>4 page frames</strong>
    <ul>
      <li>A, B, C, D, A, B, E, A, B, C, D, E</li>
      <li>10 page faule(miss)</li>
    </ul>
  </li>
</ul>

<p>보다시피, page frame의 수를 늘렸지만 오히려 page fault의 수가 늘어났다!</p>

<p>이같은 기이한 현상을 <strong>belady’s anomaly</strong>라고 한다.</p>

<h2 id="clock-algorithm">Clock Algorithm</h2>

<p>자세히 다루지는 않았지만, LRU를 구현하기 위해서는 counter, stack 등 여러가지 HW support가 필요하다.</p>

<p>이걸 전부 지원하면 LRU를 쓰면 되겠지만, 그렇지 않은 경우에는 LRU를 근사하는 알고리즘이 필요하다.</p>

<p>이것이 <strong>clock algorithm</strong>이다.</p>

<p><img src="/assets/lecture/os/cache/clock.PNG" alt="Clock" /></p>

<p>Clock algorithm은 page frame을 circular list로 관리한다.</p>

<p>Page fault가 일어나면, clock algorithm은 page frame circular list를 시계 방향으로 돌면서 아래의 동작을 수행한다.</p>

<ul>
  <li>If used bit == 1, change to 0 and go on next page frame</li>
  <li>If used bit == 0, select this page frame to replace</li>
</ul>

<p>이때, used bit가 1인 page에게 한 번 기회를 준다는 의미에서 <strong>second chance algorithm</strong>이라고 불리기도 한다.</p>

<h2 id="n-th-chance-algorithm">N-th Chance Algorithm</h2>

<p>Second chance가 있으면 N-th chance도 있어야 하지 않을까?</p>

<p><img src="/assets/lecture/os/cache/n.PNG" alt="N" /></p>

<p>N-th chance algorithm은 second chance algorithm을 약간 확장한 것이다.</p>

<p>판단 기준을 used bit가 아닌, 최대 N까지 늘어나는 정수로 두는 것에 불과하다.</p>

<p>한편으론 N번 돌 때까지 쓰이지 않은 frame을 버린다고 해서 <strong>not recently used policy</strong> 라고 부르기도 한다.</p>

<h3 id="implementation-node">Implementation Node</h3>

<p>Clock 과 N-th Change algorithm을 구현하는 방법은 크게 두가지로 나뉜다.</p>

<ul>
  <li><strong>Synchronously</strong>
    <ul>
      <li>
        <p>Use in Pintos project 3</p>
      </li>
      <li>
        <p>Sync = Run algorithm only when needs (page fault occurs)</p>
      </li>
      <li>
        <p>In page fault handler, if evicion needs, run algorithm find next page to evict</p>
      </li>
      <li>
        <p>If dirty, write back to disk</p>
      </li>
    </ul>
  </li>
  <li><strong>Asynchronously</strong>
    <ul>
      <li>
        <p>Async = Run in background</p>
      </li>
      <li>
        <p>With enhanced second-chance algorithm</p>

        <ol>
          <li>
            <p>(0, 0) neither recently used nor modified</p>
          </li>
          <li>
            <p>(0, 1) not recently used but modified</p>
          </li>
          <li>
            <p>(1, 0) recently used but clean</p>
          </li>
          <li>
            <p>(1, 1) recently used and modified</p>
          </li>
        </ol>
      </li>
      <li>
        <p>Create a thread to maintain a pool of (0, 0) pages</p>
      </li>
      <li>
        <p>Periodically run algorithm below</p>

        <ul>
          <li>
            <p>If found (0, 1) page, write back to disk and change to (0, 0)</p>
          </li>
          <li>
            <p>If found (0, 0) page, mark as invalid and move to pool</p>
          </li>
        </ul>
      </li>
      <li>
        <p>On page fault, check if requested page is in pool</p>
      </li>
      <li>
        <p>If exist, change to (1, 0) or (1, 1) and remove from pool (recover page)</p>
      </li>
      <li>
        <p>If not exist, select any page in pool, and evict (replace page)</p>
      </li>
    </ul>
  </li>
</ul>

<h1 id="4-allocation-of-frames">4. Allocation of Frames</h1>

<div class="notice--danger">
<p><b>주의</b></p>
<p>이 챕터에서는 page와 page frame의 차이를 엄밀하게 구분하고 있지 않다.</p>
<p>원래대로라면 관리 측면에선 page를, 할당 측면에서는 frame이라는 단어를 써야한다. </p>
<p>그러나 PPT는 이를 엄밀하게 구분하지 않고, 그냥 page를 <b>메모리 단위</b>로서의 의미로 사용하고 있으므로, 이를 그대로 차용하였다. </p>
<p>Frame은 PM! Page는 VM 이런 식으로 구분하지 말고, 그냥 둘 다 메모리 단위라고 받아들이면 된다.</p>
</div>

<p>Eviction에 대해선 전부 알아보았고, 이제 allocation 자체에 문제를 알아보자.</p>

<p>궁극적으로 우리는 아래의 질문에 답하는 것을 목표로 한다.</p>

<blockquote>
  <p>How many frames allocated to each process?</p>
</blockquote>

<h2 id="minimum-number-of-frames">Minimum Number of Frames</h2>

<p>Frame allocation의 기본 제약은 Process가 무사히 동작하기 위한 최소한의 수 이상을 할당해야 한다는 것이다.</p>

<p>왤까? 가장 주된 이유는 성능 향상을 위해서이다.</p>

<p>최소한의 수가 보장되지 않는다면 page fault가 일어날 가능성이 매우 높고, 이로 인해 process의 성능이 크게 하락하기 때문이다.</p>

<p>이때, process의 실행단위는 instruction 이므로 Process가 무사히 동작하기 위한 최소한의 수는 <strong>single instruction을 실행하기 충분한 양의 page</strong>를 의미함을 알 수 있다.</p>

<p>아키를 수강했다면 알겠지만 single instruction을 실행하는데 필요한 frame의 수는 computer architecture에 의해 결정된다.</p>

<p>예를 들어, IBM 370라면 SS MOVE instruction이 총 6 frame를 사용하므로 Process에게 최소 6 frame를 할당해줘야 한다.</p>

<h2 id="allocation-algorithms">Allocation Algorithms</h2>

<p>제약은 알아봤으니, 이제 할당할 차례이다.</p>

<p>Physical memory(frames)라는 한정 자원을 어떻게 process들에게 잘 나눠주느냐? 가 메인 문제다.</p>

<p>이 문제를 해결하는 알고리즘은 고정된 property만 사용하는 Fixed allocation과 임의로 지정할 수 있는 property(ex: priority)를 사용하는 priority allocation으로 나뉜다.</p>

<ul>
  <li>
    <p><strong>Fixed allocation</strong></p>

    <ul>
      <li>Equal allocation
        <blockquote>
          <p>Allocate equal size of frames to proccesses (1/n)</p>
        </blockquote>
      </li>
      <li>Proportional allocation
        <blockquote>
          <p>Allocate according to the size of proccess</p>
        </blockquote>

        <p><img src="/assets/lecture/os/cache/prop.PNG" alt="Prop" /></p>
      </li>
    </ul>
  </li>
  <li>
    <p><strong>Priority allocaion</strong></p>
    <blockquote>
      <p>the ratio of frames depends on the <strong>priorities of processes</strong> or on a <strong>combination of size and priority</strong>.</p>
    </blockquote>
  </li>
</ul>

<h2 id="global-versus-local-allocation">Global versus Local Allocation</h2>

<p>Frame allocation에 있어서 또 한가지 중요한 요소는 page replacement이다.</p>

<p>Multiprocess 환경에서 page replacement policy는 크게 두가지로 나뉜다.</p>

<ul>
  <li><strong>Global replacement</strong>
    <blockquote>
      <p>Select frame from the set of <strong>all frames</strong>; One process can take a frame from another</p>
    </blockquote>

    <ul>
      <li>
        <p>ex) In priority allocation, select for replacement a frame from a process with <strong>lower priority number</strong></p>
      </li>
      <li><strong>장점</strong>
        <ul>
          <li>Greater system throuput</li>
        </ul>
      </li>
      <li><strong>단점</strong>
        <ul>
          <li>Process cannot control its own page-fault rate
            <blockquote>
              <p>The set of pages in memory for a process depends not only on the paging behavior of that process but <strong>also on the paging behavior of other processes</strong></p>
            </blockquote>
          </li>
        </ul>
      </li>
    </ul>
  </li>
  <li><strong>Local replacement</strong>
    <blockquote>
      <p>Select frame from its <strong>own set of allocate frames</strong></p>
    </blockquote>

    <ul>
      <li>
        <p>ex) In priority allocation, select for replacement one of its frames.</p>
      </li>
      <li><strong>장점</strong>
        <ul>
          <li>Paging behavior is affected by only own process</li>
        </ul>
      </li>
      <li><strong>단점</strong>
        <ul>
          <li>Less system throuput (Less use of pages)</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

<p>일반적으로 성능의 이점 때문에 Global replacement를 채택하는 편이다.</p>

<h1 id="5-thrashing">5. Thrashing</h1>

<p>그런데 이렇게 할당을 하고 나면 위에서 알아보았던 minimum Number을 보장받지 못하는 (low priority) process가 생길 수 있다.</p>

<p>아마 이 process는 page fault가 곧바로 발생할 것이다.</p>

<p>그러면 instruction을 실행하기 위해 in-active인 page를 evict해야 한다.</p>

<p>그런데 In-active page는 이후에 다시 접근할 가능성이 높은 page이므로, 아마 또다시 page fault가 발생할 것이고 그러면 또 다른 In-active page를 evict해야 한다.</p>

<p>그러면 또 다시 page fault가 발생할 것이다.</p>

<p>이렇게 계속해서 page fault가 발생하는, 일명 high paging acitivy를 <strong>thrashing</strong>이라고 한다.</p>

<p>Thrasing이 발생하는 원인은 크게 세가지가 있다.</p>

<ul>
  <li>
    <p>Process doesn’t reuse memory, so caching doesn’t work</p>
  </li>
  <li>
    <p>Process does reuse memory, but it does not fit</p>
  </li>
  <li>
    <p>Individually, all processed fit and reuse memory but too many for system</p>
  </li>
</ul>

<p>이 중 첫 번째와 두 번째는 process 자체의 문제이므로 해결하기가 어렵다.</p>

<p>그러면 세 번째 문제는 어떻게 해결할 수 있을까?</p>

<h2 id="working-set-model">Working-Set Model</h2>

<p>세 번째 문제를 해결하기 위해선 process가 얼마만큼의 frame을 사용하는지 알아야 한다.</p>

<p>그런데 그걸 어떻게 알 수 있을까?</p>

<p>몇 가지 방법이 있지만, 우리가 알아볼 것은 <strong>Working-Set Model</strong>이다.</p>

<p><strong>Working-Set</strong>이란, locality에 기반하여 process가 일정 시간동안 원활하게 수행되게 위해 한꺼번에 메모리에 올라와 있어야 하는 페이지들의 집합을 말한다.</p>

<p>Working-Set Model에서는 이 working set을 process가 할당받아야 하는 최소한의 양, 즉 threadhold로 본다.</p>

<p>따라서 Working-Set Model은 working set이 전부 올라와 있지 못한 process를 swap-out 시키게 되고, 이를 통해 thrashing을 방지하고 multiprogramming degree를 조절할 수 있다.</p>

<p>참고로 working set은 시간에 따라 변화한다.</p>

<h2 id="page-coloring">Page Coloring</h2>

<p>한편 프로그램에 어느 위치의 frame을 할당해주는지도 성능에 있어서 꽤 큰 영향을 미친다.</p>

<p><img src="/assets/lecture/os/cache/color.PNG" alt="Color" /></p>

<p>예를 들어 8MB directed cache와 4KB page가 주어졌다고 하자.</p>

<p>1 of every 2K pages는 cache 상에서 같은 라인에 위치한다.</p>

<p>그런데 이 같은 라인에 위치하는 page들을 프로그램에 할당했다고 하자.</p>

<p>그러면 계속해서 cache eviction이 발생할 것이므로 성능이 급격하게 떨어지게 된다.</p>

<p>이런 문제를 방지하기 위해 OS는 <strong>page coloring</strong> 이라는 기법을 사용한다</p>

<p><strong>Page coloring</strong>은 physical page frames를 어떤 cache bucket에 들어갈지를 기준으로 구분하는 걸 말한다.</p>

<p>예를 들어 2MB 8-way set associative cache와 4KB page가 주어졌다고 하자.</p>

<p>그러면 page를 2 * 2^20 / 4 * 2^10 / 8 = 64 개의 color(or separate set)로 구분하게 된다.</p>

<p>Page coloring을 사용하는 OS는 (프로그램) page를 할당할 때, 이 color가 최대한 겹치지 않도록 할당한다.</p>]]></content><author><name>Jaehyun Ha</name><email>yshajae@postech.ac.kr</email></author><category term="Lecture Notes" /><category term="OS" /><category term="CSED312" /><summary type="html"><![CDATA[이 글은 포스텍 박찬익 교수님의 CSED312 운영체제 수업의 강의 내용과 자료를 기반으로 하고 있습니다.]]></summary></entry><entry><title type="html">[Algorithm] Exponential Algorithm</title><link href="https://rntlqvnf.github.io/lecture%20notes/algorithm-exp-1/" rel="alternate" type="text/html" title="[Algorithm] Exponential Algorithm" /><published>2020-12-13T00:00:00+09:00</published><updated>2020-12-13T00:00:00+09:00</updated><id>https://rntlqvnf.github.io/lecture%20notes/algorithm-exp-1</id><content type="html" xml:base="https://rntlqvnf.github.io/lecture%20notes/algorithm-exp-1/"><![CDATA[<blockquote>
  <p>이 글은 포스텍 오은진 교수님의 CSED331 알고리즘 수업의 강의 내용과 자료를 기반으로 하고 있습니다.</p>
</blockquote>

<p>공부하기 싫다!! 내용도 도통 뭔 소린지 모르겠고 ㅠㅠ</p>

<p>개인적으로 최근 ~~ algorithm 파트들이 제일 싫다.</p>

<p>뭔 소린지도 모르겠고, 대체 어떻게 문제를 낼 지도 모르겠다.</p>

<h1 id="1-exponential-algorithm">1. Exponential Algorithm</h1>

<p>우리가 지금까지 배운 Approximation / Parametrized algorithm은 이론 수학자가 NP-complete / NP-hard 문제를 다루는 방법들이다.</p>

<p><strong>Approximation</strong>은 근사를 통해 poly-time algorithm을 만든다.</p>

<p><strong>Parametrized</strong>는 output param을 도입해서 input size에 대해선 polytime을 만든다.</p>

<p>그런데 위 두가지 방법을 적용해도 polytime을 만들 수 없는 경우가 존재한다.</p>

<p>이 경우, 그냥 efficient(poly-time) 조건 자체를 완화하여 Exponential Algorithm을 찾아야 한다.</p>

<p>오늘 우리가 배울 것은 바로 이 Exponential Algorithm case이다.</p>

<h1 id="2-maximum-clique-problem">2. Maximum Clique Problem</h1>

<p><img src="/assets/lecture/algo/exp/max.PNG" alt="Max" /></p>

<p>Maximum Clique problem이란, clique 중에 가장 큰 놈을 찾는 문제이다.</p>

<p>슬프게도, $P=NP$가 아닌 이상 이 문제를 polynomial time에 풀 수는 없다.</p>

<h2 id="algorithms">Algorithms</h2>

<p>지난 시간에 배웠던 아이디어를 도입하여 ouput size를 고정하면 어떻게 될까?</p>

<p><img src="/assets/lecture/algo/exp/fix.PNG" alt="OUT" /></p>

<p>놀랍게도 $O(m^{3/2})$로 줄어든다.</p>

<p>이 일고리즘은 <a href="#2-maximum-clique-problem">3번</a>에서 알아볼 것이다.</p>

<p>그럼 원래의 maximum clique는 얼마나 걸릴까?</p>

<p><img src="/assets/lecture/algo/exp/max_cli.PNG" alt="max cliq" /></p>

<p>가장 빠른건 $O(2^{0.249n})$이지만, 오늘은 가장 느린 것을 알아볼 것이다.</p>

<h1 id="3-finding-all-cliques-of-size-3">3. Finding All Cliques of Size 3</h1>

<p>알고리즘의 아이디어를 차근차근 밟아보자.</p>

<ol>
  <li>
    <blockquote>
      <p>모든 vertex가 constant degree를 가진다면 가장 빠른 알고리즘은 무엇일까?</p>
    </blockquote>

    <p><img src="/assets/lecture/algo/exp/const.PNG" alt="COnst" /></p>

    <p>각 vertex의 이웃들을 조합하면서 triangle을 이룰 수 있는지 검사해보면 된다.</p>
  </li>
  <li>
    <blockquote>
      <p>아이디어를 조금 발전시켜서, 모든 vertex가 $O(\sqrt{m})$의 degree를 가진다면 가장 빠른 알고리즘은 무엇일까? ($m$은 edge의 개수)</p>
    </blockquote>

    <p>똑같이, 모든 조합에 대해서 조사해보면 된다.</p>

    <p>시간 복잡도를 구해보자.</p>

    <p>$n$개의 vertex가 주어졌다고 하자.</p>

    <p>각 vertex 당 조합의 개수가 $O(m)$이다.</p>

    <p>이때, 각각의 조합이 triangle을 이루는지 조사하는데 걸리는 시간은 $O(1)$이므로 총 $O(nm)$ 시간이 걸린다.</p>
  </li>
  <li>
    <blockquote>
      <p>아이디어를 조금 더 발전시켜서, $O(\sqrt{m})$ degree를 가지는 vertex가 있고 $\Omega (\sqrt{m})$ degree를 가지는 vertex가 있으면 어떻게 될까?</p>
    </blockquote>

    <p>이게 우리가 알아야 할 $O(m^{3/2})$ 알고리즘이다.</p>

    <p>이때 $\Omega (\sqrt{m})$ degree를 가지는 vertex를 <strong>heavy vertex</strong>라고 한다.</p>

    <p>반대로 $O(\sqrt{m})$ degree를 가지는 vertex를 <strong>light vertex</strong>라고 한다.</p>

    <p>한 가지 중요한 observation은, heavy vertex는 $O(\sqrt{m})$개 존재한다는 것이다.</p>

    <p>간단히 증명해보자.</p>

    <p>$\sqrt{m} \cdot \sharp h \leq 2m$</p>

    <p>$\sharp h \leq 2 \sqrt{m}$</p>

    <p>$\therefore \sharp h = O(\sqrt{m})$</p>

    <p>자, 이제 본격적으로 증명해보자.</p>

    <p>Triangle을 두 가지로 type으로 나눠서 증명할 것이다.</p>

    <ul>
      <li>
        <p><strong>Type-1 Triangle</strong></p>

        <blockquote>
          <p>All vertices are heavy</p>
        </blockquote>

        <p>이 경우, 그냥 가능한 heavy vertex의 triple에 대해 조사하면 된다.</p>

        <p>이때 가능한 triple의 수는 observation에 의해 $O(\sqrt{m} \cdot \sqrt{m} \cdot \sqrt{m})=O(m^{3/2})$이고, 조사하는 시간은 $O(1)$이므로</p>

        <p>총 $O(m^{3/2})$ 시간이 걸린다.</p>
      </li>
      <li>
        <p><strong>Type-2 Triangle</strong></p>

        <blockquote>
          <p>At least one vertex is light</p>
        </blockquote>

        <p>2번째 알고리즘과 동일하다.</p>

        <p>각 light vertex의 이웃들을 조합하며 triangle을 형성하는지 알아보면 된다.</p>

        <p>시간 복잡도는 어떻게 될까?</p>

        <p>각 light vertex의 degree를 $d(v)$라 하면, 조합의 수는 $O(d(v^2))$이므로, 이를 모든 light vertex에 대해 더하면 된다.</p>

        <p><img src="/assets/lecture/algo/exp/type2.PNG" alt="Type2" /></p>

        <p>첫 번째 등식은 light vertex의 정의에 따라 $O(\sqrt{m})$을 빼낸 것이다.</p>

        <p>두 번째 등식은 $\sum_{light\; v}d(v) \leq \sum d(v) = 2m$ 이므로, $O(m\sqrt{m})=O(m^{3/2})$가 된 것이다.</p>

        <p>결국 다 합쳐서 총 $O(m^{3/2})$ 시간에 모든 size 3 clique를 찾을 수 있다.</p>
      </li>
    </ul>
  </li>
</ol>

<h1 id="4-exact-algorithm-for-maximum-clique">4. Exact Algorithm for Maximum Clique</h1>

<p><img src="/assets/lecture/algo/exp/lem.PNG" alt="Lem" /></p>

<p>위 theorem이 우리가 알아볼 maximum clique algorithm이다.</p>

<p>이때 theorem에서 maxi<strong>mal</strong> clique라는 표현을 썼는데, maximum과 헷갈리면 안된다.</p>

<p><strong>Maximal</strong> clique란, 아래의 조건을 만족하는 집합 $S\subseteq V$를 의미한다.</p>

<ol>
  <li>$S$ is a clique and</li>
  <li>For any vertex $v\in S$, $S \cup \lbrace v \rbrace$ is not clique</li>
</ol>

<p>한편, <strong>Maximum</strong> clique란, maximal clique 중 최대를 의미한다.</p>

<p>우리가 알아볼 알고리즘은 모든 maximal clique를 찾아낸 다음, 이 중 최대를 골라내는 것이다.</p>

<p>알고리즘은 아래와 같다.</p>

<p><img src="/assets/lecture/algo/exp/algo.PNG" alt="Algo" /></p>

<p>핵심은 $v$를 제외한 graph $G$에 $v$를 추가할 때 두 가지 케이스가 발생한다는 것이다.</p>

<p>만약 $v$가 $C$의 vertices 중 not connected vertex가 존재한다면, $v$를 추가하면 안된다.</p>

<p>반대로 $v$가 $C$의 vertex들과 모두 connected 되어있다면 ($C-N(v) = \phi$) $v$를 추가해도 clique는 유지가 된다.</p>

<p>그런데 maximal도 유지가 될까?</p>

<blockquote>
  <p>그렇지 않다.</p>
</blockquote>

<p>$C$의 바깥에 있는 vertex가 $(C\cap N(v)) \cup \lbrace v \rbrace$와는 fully connected 일 수 있기 때문이다.</p>

<p>그래서  $(C\cap N(v)) \cup \lbrace v \rbrace$를 만들고, 이것이 maximal인지 판단해서 맞다면 반환해야 한다.</p>

<p>이 알고리즘을 재귀적으로 돌리면 모든 maximal clique를 구할 수 있다.</p>

<p>시간 복잡도를 구해보자.</p>

<p><img src="/assets/lecture/algo/exp/lem.PNG" alt="Lem" /></p>

<p>Lemma에 의해, $G$는 $O(3^{n/3})$개의 maximal cliques를 가지고 있다.</p>

<p>재귀를 하면 두 번째 단계에서는 $O(3^{n-1/3})$, 세 번째에서는 $O(3^{n-2/3})$, $i$ 번째에서는 $O(3^{n-i+1/3})$이 될 것이다.</p>

<p>이걸 전부 합하면 $O(3^{n/3})$이 나온다.</p>

<p>한편 각 step에서 $C-N(v) = \phi$ 를 판단하고,  $(C\cap N(v)) \cup \lbrace v \rbrace$가 maximal인지 판단하는데 $O(m)$이 걸린다. (incident edge를 조사하므로)</p>

<p>따라서 총 $O(m\cdot 3^{n/3})$이 걸린다.</p>

<p>이로부터 간단한 corollary도 얻을 수 있다.</p>

<blockquote>
  <p>All maxiaml cliques of a graph can be generated in $O(mn)$ time per clique</p>
</blockquote>]]></content><author><name>Jaehyun Ha</name><email>yshajae@postech.ac.kr</email></author><category term="Lecture Notes" /><category term="Algorithm" /><category term="CSED331" /><summary type="html"><![CDATA[이 글은 포스텍 오은진 교수님의 CSED331 알고리즘 수업의 강의 내용과 자료를 기반으로 하고 있습니다.]]></summary></entry><entry><title type="html">[Algorithm] Approximation Algorithm</title><link href="https://rntlqvnf.github.io/lecture%20notes/algorithm-app-1/" rel="alternate" type="text/html" title="[Algorithm] Approximation Algorithm" /><published>2020-12-12T00:00:00+09:00</published><updated>2020-12-12T00:00:00+09:00</updated><id>https://rntlqvnf.github.io/lecture%20notes/algorithm-app-1</id><content type="html" xml:base="https://rntlqvnf.github.io/lecture%20notes/algorithm-app-1/"><![CDATA[<blockquote>
  <p>이 글은 포스텍 오은진 교수님의 CSED331 알고리즘 수업의 강의 내용과 자료를 기반으로 하고 있습니다.</p>
</blockquote>

<p>요즘 알고리즘 무슨 내용인지 알아듣기가 힘들다.</p>

<p>NP-complete 증명까지는 어떻게든 이해했는데, 요즘 뭐.. approximation이니 parametrized니.. 이게 뭔지, 왜 하는지도 모르겠다.</p>

<p>심지어 블로그는 고사하고 교과서 찾아봐도 관련된 내용이 없어서 독학도 어렵다!</p>

<p>아.. 인생 재밌다.</p>

<h1 id="1-approximation-algorithm">1. Approximation Algorithm</h1>

<p>Optimization problem이란 어떤 instance <em>I</em>가 주어졌을 때, 그에 따른 optimum solution을 찾는 문제를 말한다.</p>

<p>이때 이 optimum solution을 $OPT(I)$라고 적는다.</p>

<p>이후 여러 논의들을 간단하게 하기 위해 $OPT(I)$가 항상 positive integer 라고 가정한다.</p>

<p>Optimization problem은 흔히 minimization problem과 maximization problem으로 나뉜다.</p>

<p>이 중, minimization problem을 생각해보자. (maximization problem에도 동일하게 적용할 수 있다!)</p>

<p>Minimization problem을 풀기 위해 우리가 만들어낸 알고리즘을 $A$라고 하고, solution을 $A(I)$라고 하자.</p>

<p>이때 <strong>approximation ratio</strong> of algorithm A는 아래와 같이 정의된다.</p>

<p><img src="/assets/lecture/algo/app/ratio.PNG" alt="Approximation ratio" /></p>

<p>곧, $\alpha_A$는 우리가 만든 알고리즘의 solution이 optimal solution보다 얼마나 큰지를 말해주는 값이라 할 수 있다.</p>

<p>우리가 왜 approximation ratio를 알아야 할까?</p>

<p>이는 approximation ratio가 NP-complete optimization problem을 푸는 알고리즘을 평가하는 매우 중요한 지표이기 때문이다.</p>

<p>근데 잘 생각해보면 좀 의아한 점이 있다.</p>

<blockquote>
  <p>Optimal solution은 어떻게 구하는데? 애초에 뭐가 optimum인지 어떻게 아는데?</p>
</blockquote>

<p>바로 이 문제가 오늘 강의의 핵심이다.</p>

<p>우리는 오늘 몇 가지 예시를 통해 어떻게 optimal solution을 추측하고, $\alpha$를 구하는지를 배울 것이다.</p>

<h1 id="2-vertex-cover">2. Vertex Cover</h1>

<p>Vertex cover 문제는 너무 자주 봐서 아마 다시 설명할 필요는 없을 것이다.</p>

<p>우리가 할 것은 아래의 알고리즘이 factor-2 approximation algorithm 이라는 것을 증명하는 것이다.</p>

<p><img src="/assets/lecture/algo/app/vc.PNG" alt="VC" /></p>

<p>우선 $C$가 vertex cover임을 증명하자.</p>

<blockquote>
  <p>Claim: $C$ is a vertex cover</p>
</blockquote>

<ul>
  <li>
    <p><strong>Proof</strong></p>

    <p>만약 $C$가 vertex cover가 아니라고 하자.</p>

    <p>그러면 $C$가 cover하지 못하는 edge가 존재한다는 의미이다.</p>

    <p>그러나 그런 edge가 존재한다면 알고리즘에 의해 발견될 것이므로, 이는 모순이다.</p>

    <p>따라서 $C$는 vertex cover이다.</p>
  </li>
</ul>

<p>factor-2를 증명하기 위한 보조 정리로 $M$의 edge들은 vertex를 공유하지 않음을 증명하자.</p>

<blockquote>
  <p>Claim: No two edges of $M$ share a common vertex</p>
</blockquote>

<ul>
  <li>
    <p><strong>Proof</strong></p>

    <p>어떤 edge $(a,b)$가 선택되었다고 해보자.</p>

    <p>그러면 $a$와 $b$를 endpoint로 가지는 모든 edge들은 cover 가능한 edge로 분류되므로, 알고리즘에 의해 선택되지 않는다.</p>

    <p>따라서 $M$의 어떤 edge라도 vertex를 공유하지 않는다.</p>
  </li>
</ul>

<p>이제 factor-2 algorithm 임을 증명하자.</p>

<blockquote>
  <p>Claim: $\lvert C \rvert \leq 2\cdot OPT$</p>
</blockquote>

<ul>
  <li>
    <p><strong>Proof</strong></p>

    <p>Vertex cover는 $M$의 edge들을 cover하기 위해, $M$의 각 edge의 endpoint 중 최소 하나는 가져야만 한다.</p>

    <p>두 번째 claim에 의해 $M$은 vertex를 공유하지 않으므로, optimal solution은 아래의 부등식을 만족한다.</p>

    <p>$OPT \geq \lvert M \rvert$</p>

    <p>이때, $\lvert C \rvert = 2\lvert M \rvert$ 이므로</p>

    <p>$\lvert C \rvert = 2\lvert M \rvert \leq 2 \cdot OPT$이다.</p>

    <p>곧, factor-2 algorithm이다.</p>
  </li>
</ul>

<p>아마 이제 어떻게 $OPT$를 계산하는지 알았을 것이다.</p>

<p>이 기세를 이어 나머지 것도 알아보자.</p>

<h1 id="3-weighted-vertex-cover">3. Weighted Vertex Cover</h1>

<p><img src="/assets/lecture/algo/app/wvc.PNG" alt="WVC" /></p>

<p>Weighted vertex cover는 vertex cover 중에서 경로 비용의 합을 최소인 놈을 찾는 문제이다.</p>

<p>이 문제를 좀 더 formal 하게 LP로 적어보자.</p>

<p><img src="/assets/lecture/algo/app/lp.PNG" alt="LP" /></p>

<p>굉장히 직관적이어서 바로 알아들을 수 있을 것이다.</p>

<p>이때 LP-relaxation이란, 원래의 LP는 $x_u$와 $x_v$ 중 하나만 포함되도록 강제했지만, 이를 완화하여 둘 중 하나 이상이 포함되도록 바꿨다는 말이다.</p>

<p>우리가 할 것은 아래의 알고리즘이 factor-2 approximation algorithm 이라는 것을 증명하는 것이다.</p>

<p><img src="/assets/lecture/algo/app/wvc_2.PNG" alt="WVC2" /></p>

<p>우선 $S$가 vertex cover임을 증명하자</p>

<blockquote>
  <p>Claim: $S$ is a vertex cover</p>
</blockquote>

<ul>
  <li>
    <p><strong>Proof</strong></p>

    <p>$E$의 edge를 $(u,v)$라 하자.</p>

    <p>$x_u^{\ast}+x_v^{\ast} \geq 1$이므로, $x_u^{\ast} \geq 1/2$ 또는 $x_v^{\ast} \geq 1/2$ 이어야만 한다.</p>

    <p>곧, $u$나 $v$는 $S$ 안에 포함되어 있다.</p>

    <p>따라서 $S$는 vertex cover이다.</p>
  </li>
</ul>

<p>이제 factor-2 algorithm 임을 증명하자.</p>

<blockquote>
  <p>Claim: $c(S)\leq 2\cdot OPT$</p>
</blockquote>

<ul>
  <li>
    <p><strong>Proof</strong></p>

    <p>LP-relaxation의 해를 $OPT_{LP}=\sum_v c(v)x_v$라고 하자.</p>

    <p>LP-relaxation은 원래의 Integer LP를 완화한 것이다.</p>

    <p>곧, Integer LP는 0, 1 밖에 가지지 못하지만 LP-relaxation은 0~1의 실수를 택할 수 있으므로, $\sum_{v\in V}c(v)x_v$를 더 작게 만들 수 있다.</p>

    <p>따라서 $OPT \leq OPT_{LP}$이다.</p>

    <p>이때 우리의 알고리즘은 LP-relaxation의 해에서 $x\geq 1/2$인 것들만 골라낸 것이므로 아래의 관계가 성립한다.</p>

    <p>$OPT_{LP} \geq \sum_{v\in S} 1/2 c(v)$</p>

    <p>이때 $\sum_{v\in S} c(v)=c(S)$이므로, $c(S)\leq 2\cdot OPT$이 된다.</p>
  </li>
</ul>

<h1 id="4-tsp">4. TSP</h1>

<p>TSP 문제에서는 역으로 polynomial time $t$-approximation algorithm이 존재하지 않는다는 것을 보일 것이다.</p>

<p><img src="/assets/lecture/algo/app/pnp.PNG" alt="PNP" /></p>

<p>아이디어는 hamiltonian cycle to TSP reduction이다.</p>

<ul>
  <li>
    <p><strong>Proof</strong></p>

    <p>Hamiltonian cycle 문제에 graph $G=(V,E)$가 주어졌다고 하자.</p>

    <p>우리는 이걸 complete graph $H=(V, E^{\backprime})$으로 변형하여, TSP 문제로 reduction을 할 것이다.</p>

    <p>아래는 $H=(V, E^{\backprime})$의 정의이다.</p>

    <p><img src="/assets/lecture/algo/app/ham.PNG" alt="Ham" /></p>

    <p>TSP의 polynomial time $t$-approximation algorithm $A$가 존재한다고 가정하자.</p>

    <p>우리가 보일 것은 $A$가 tour of length $\lvert V \rvert$를 반환하는 것은 $G$가 hamiltonian cycle을 갖는 것과 동치라는 것이다.</p>

    <blockquote>
      <p>Claim: $A$ returns a tour of length $\lvert V \rvert$ for $H$ iff $G$ has a Hamiltonian cycle</p>
    </blockquote>

    <ul>
      <li>
        <p><strong>If</strong></p>

        <p><img src="/assets/lecture/algo/app/if.PNG" alt="If" /></p>

        <p>Hamiltonian cycle을 TSP도 solution으로 채택할 것이므로 동일하다는 의미이다.</p>
      </li>
      <li>
        <p><strong>Only If</strong></p>

        <p>Length가 $\lvert V \rvert$라는 말은 $e\in E$인 edge들만 방문했다는 얘기이다.</p>

        <p>이는 곧 $G$에서의 Hamiltonian cycle을 의미한다.</p>
      </li>
    </ul>
  </li>
</ul>

<p>이로부터, TSP가 polynomial time <strong>approximation algorithm</strong>을 가진다는 말은 NP-complete <strong>hamiltonian cycle</strong> problem을 푸는 polynomial time algorithm이 존재한다는 말이 된다.</p>

<p>곧, $P=NP$가 아니라면 TSP를 푸는 polynomial time approximation algorithm이 존재하지 않는다.</p>

<h1 id="5-metric-tsp">5. Metric TSP</h1>

<p><img src="/assets/lecture/algo/app/metric.PNG" alt="Metric TSP" /></p>

<p>Metrix TSP는 triangle inequaility를 만족하는 TSP를 의미한다.</p>

<p>Triangle inequaility란, 삼각형 $(a,b,c)$가 있을 때 $a$에서 $c$로 바로 가는 것이 $b$를 경유해서 가는 것 보다 빨라야 한다는 제약이다.</p>

<p>놀랍게도 이걸 추가하면 factor-2 approximation algorithm이 존재한다!</p>

<p>알고리즘의 아이디어는 MST를 이용하는 것이다.</p>

<p>정확하게는, MST의 시작점과 끝점을 잇고, 경유 경로를 삭제하는 것이다.</p>

<p>이게 무슨 소리인지 예제를 통해 알아보자.</p>

<p>다음과 같은 점들이 주어졌다고 해보자. (원래는 그래프지만 대충 알아들으면 된다)</p>

<p><img src="/assets/lecture/algo/app/mst.PNG" alt="MST" /></p>

<p>이 점들의의 MST는 다음과 같다.</p>

<p><img src="/assets/lecture/algo/app/mst_2.PNG" alt="MST_2" /></p>

<p>A를 TSP의 시작점, B를 끝점이라고 하자. (정확하게는 A로 돌아가기 전 마지막에 방문하는 점이다)</p>

<p>MST를 따라 A에서 B로 이동하면서 모든 vertex를 방문하려면 어떻게 해야할까?</p>

<p><img src="/assets/lecture/algo/app/mst_3.PNG" alt="MST_3" /></p>

<p>이렇게 갔던 점을 갔다가 다시 되돌아와야 할 것이다.</p>

<p><img src="/assets/lecture/algo/app/2mst.PNG" alt="2MST" /></p>

<p>아마 최악의 경우에는 이렇게 죄다 왔다갔다 해야할 것이다.</p>

<p>곧, 모든 edge를 두 번씩 방문해야 한다. ($2\cdot cost(MST)$)</p>

<p>그런데 이렇게 되면 TSP의 조건을 어기고 점을 두 번 방문하는 셈이다.</p>

<p>이를 개선하기 위해, 경유해서 가야하는 경로를 없애주자.</p>

<p><img src="/assets/lecture/algo/app/mst_4.PNG" alt="MST_4" /></p>

<p>triangle inequaility에 의해, 이 tour는 두 번씩 방문하는 것보다 훨씬 적은 비용이 든다.</p>

<p>따라서 $cost(tour) \leq 2\cdot cost(MST)$이다.</p>

<p>이때 한편 $cost(MST) \leq cost(TSP)$이므로, 이를 종합하면 아래의 부등식을 얻는다.</p>

<blockquote>
  <p>$cost(tour) \leq 2\cdot cost(MST) \leq 2\cdot cost(TSP)$</p>
</blockquote>

<p>따라서 factor-2 approximation algorithm 이다.</p>]]></content><author><name>Jaehyun Ha</name><email>yshajae@postech.ac.kr</email></author><category term="Lecture Notes" /><category term="Algorithm" /><category term="CSED331" /><summary type="html"><![CDATA[이 글은 포스텍 오은진 교수님의 CSED331 알고리즘 수업의 강의 내용과 자료를 기반으로 하고 있습니다.]]></summary></entry></feed>