ARC: A Self-Tuning, Low Overhead Replacement Cache

한종우·2021년 12월 20일
0

Paper Review

목록 보기
5/7
post-thumbnail

사담

학기 중에 논문을 쓰고 수업을 듣느라 블로그 관리를 못했는데 운영체제 수업에서 논문을 많이 읽어서 아카이브용으로 블로그에 좋았던 논문들을 정리하려고 한다.
ARC는 처음에는 수식이 많아서 읽기가 꺼려졌는데 읽어보니 오히려 설명을 잘해서 진짜 잘 쓴 논문이구나 싶던 논문이다. 아이디어 자체는 기존의 FRCpFRC_p를 개선시킨 것에 지나지 않는데 상당히 유명한 논문인 것을 보면 대학원생 입장에서는 목표로 삼을만한 이상적인 논문이다.

Intro

메모리 분야에서 cache는 최적화를 하기에 가장 제일 먼저 떠올릴 수 있는 아이디어다. 당연히 전체 메모리가 빠르고 크면 좋겠지만, 비용의 문제 때문에 일반적으로 cache는 main memory보다 훨씬 작은 크기를 가진다. 따라서 cache가 꽉 차면 기존의 page 중 하나를 page out (evict)해야 하는데, 이 cache replacement policy에 따라 cache의 성능이 크게 영향을 받기 때문에 잘 정하는 것이 중요하다. 일반적으로는 LRU를 쓰지만 여러 연구들이 더 나은 cache replacement policy를 만들었고, 이 논문 역시 overhead를 낮추면서 hit rate를 최대화한다는 것이 주요 목표다.

Contribution

page size가 동일할 때 (superpage가 없을 때) demand paging 시나리오에서 새로운 cache replacement policy인 ARC(Adaptive Replacement Cache)를 제안한다.
ARC는 기존의 policy들에 비해 여러 장점을 가지는데

  1. recency와 frequency를 모두 고려
    • correlated reference도 고려
  2. online algorithm이다.
    • workload, cache size에 따른 parameter tuning이 필요없다.
    • 실행 도중에 worload pattern이 변하더라도 self-tuning한다.
  3. computational overhead, space overhead가 작다.
    • computational overhead : O(1) (LRU와 동일)
    • space overhead : LRU의 2배
  4. scan에 강하다.
    • scan은 one-time-only sequential read request를 의미한다.

Backgrounds

기존의 Page Replacement Policy들은 아래와 같다.

MIN

Belady가 제안. 가장 큰 forward distance의 page를 교체. online policy에 대한 상한선 제공

LRU (Least Recent Used)

  • 가장 오래된 page를 교체
  • workload가 LRU SDD(stack depth distribution)인 경우 optimal
  • SDD는 recency를 고려하지만 frequency는 고려하지 않는다. 따라서 불균일한 page reference에 대해서는 성능이 좋지 않다.

LFU (Least Frequency Used)

  • frequency를 고려하는 IRM (Independent Reference Model) 모델에서 optimal
  • O(log n)O(log\ n) 시간 복잡도
  • recent history를 아예 고려하지 않아서 correlated reference page (옛날에 빈도가 높게 접근했으나 최근에는 access하지 않는 page)가 계속 남아있는 문제가 있다.

LRU-2

  • 2번째 reference가 가장 오래된 page를 교체. LFU에 대해 적응성 개선
  • O(log n)O(log\ n) 시간 복잡도
  • CIP (Correlated Information Period) : 한번만 본 page를 어느 시간만큼 저장할 지 결정. cache size c에 따라 가장 높은 hit rate를 보이는 CIP/c가 다르다.

2Q

  • O(1) 복잡도로 LRU-2 근사
  • AmA_m : hot page, A1A_1 : cold page, correlated page
  • A1A_1KinK_{in}개 만큼의 cache와 KoutK_{out}개의 ghost cache를 저장한다.
  • hot page가 분리되어있어 scan-resistant하다.
  • cache size cc에 따라 KinK_{in}, KoutK_{out} tuning해야 한다.

LIRS (Low Inter-reference Recency Set)

  • IRR : stack distance와 유사한 개념. 이전 reference부터 현재 reference까지 다른 unique한 page가 몇 개 access되었는지를 의미한다.
  • IRR이 크면 교체 후보가 된다.
    • LlirsL_{lirs} : 최근 RmaxR_{max} 안에 두 번 이상 본 page
    • LhirsL_{hirs} : 최근 RmaxR_{max} 안에 한번만 본 page
  • LhirsL_{hirs}, RmaxR_{max}를 tuning해야 함.
  • stack pruning도 필요하다고 한다.

FBR (Frequency-Based Replacement)

  • LRU list를 new, middle, old로 나눈다.
  • cache hit 시 new 안에 있는 MRU로 이동
    • middle, old에 있었던 경우 count가 증가
    • new section에 있으면 hit여도 count 증가 x (corrlated frequency에 의한 cache pollution 방지)
  • count의 rescale이 필요하다. 평균 count가 AmaxA_{max} 이상이 되면 모든 count를 반으로 줄인다.
  • new, old 길이, AmaxA_{max} 등을 tuning해야 한다.

LRFU (Least Recency/Frequency Used)

C(x)={1+2λC(x),if x is referenced at time t2λC(x),o.w.C(x) = \begin{cases} 1+2^{-\lambda}C(x), \text{if x is referenced at time t}\\ 2^{-\lambda}C(x), \text{o.w.} \end{cases}
  • 처음에는 C(x)=0C(x) = 0이다가 위 식대로 update하면서 제일 작은 C(x)C(x)를 가진 page를 교체
  • λ가 0에 가까워지면 frequency 고려하는 비중이 커져서 LFU, 1에 가까워지면 recency 고려하는 비중이 커져서 LRU가 된다.
  • λ에 따라 성능이 많이 바뀜 (tuning이 필요하다)
  • ALRFU (Adaptive LRFU) : λ를 동적으로 조정하도록 수정한 알고리즘. 하지만 추가적인 tunable parameter가 존재하며, O(log n)O(log\ n) 복잡도여서 λ가 작으면 LRU보다 50배까지도 느리다고 한다.

MQ

  • LRU queue m개 (Q0,,Qm1Q_0, \dots, Q_{m-1})를 사용
    QiQ_i : 최근에 2i2^i 이상 2i+112^{i+1} - 1 이하 access한 page
  • hit 시 page frequency가 증가하고 각 queue의 MRU로 이동, expire time은 currentTime + lifeTime으로 설정됨.
  • expire되면 다음 queue로 보내며 Q_out에서 교체
  • peak temporal distance의 큰 변화가 있을 때에 동적으로 adapt함. (ARC는 tick마다 계속 적응한다.)
  • n개 queue가 있어서 LRU, ARC, 2Q보다 space overhead는 크다.

c.f. Ghost Cache (Shadow Cache)

underlying cache를 지원하는 것보다 더 큰 크기의 cache directory를 사용하는 경우 이 directory를 ghost cache라고 한다. 최근에 evict된 cache page의 metadata를 저장할 때 사용한다. 일반적으로 DRAM에 저장되며 block address, pointer 정도를 저장한다.
2Q, MQ, LRU-2, ALRFU, LIRS 등에서 ghost cache를 사용한다.

[요약]

A CLASS OF REPLACEMENT POLICIES

replacement policy와 관련해서 하도 많은 policy가 나와서인지 아예 policy들의 class를 정의해놓았다. ARC는 DBL(2c)DBL(2c)를 확장한 Π(c)\Pi(c)에 속하는 FRCp(c)FRC_p(c)에서 p를 동적으로 변환하는 policy이다.

  • cc : page 수 (cache 크기)
  • π,π(c)\pi, \pi(c) : replacement policy를 의미
  • DBL(2c)DBL(2c) : page 수의 2배를 관리하고 기억하는 정책
  • Π(c)\Pi(c) : 제안하는 class

[DBL(2c)][DBL(2c)]

  • 두 개의 가변 크기 list L1L_1, L2L_2를 유지
  • L1L_1 : 한 번만 본 page (evict된 후 처음이거나 아예 처음)
  • L2L_2 : 2번 이상 본 page

두 개 합이 2c보다 많아지거나 L1L_1이 c개보다 많아지면 교체하는데, L1L_1cc개의 page가 있는 경우 L1L_1에서 replace하고, 아닌 경우 L2L_2에서 하나 빼고 L1L_1의 MRU에 새로 넣는다.

  • 0L1+L22c,0L1c,0L22c0 \le | L_1 | + | L_2 | \le 2c,0 \le | L_1 | \le c, 0 \le | L_2 | \le 2c

[π(c)Π(c)][\pi(c) ∈ \Pi(c)]

DBL에서 관리하는 2c2c의 cache를 가지지만, physically하게는 cc개의 page만을 가진다. (나머지 cc개는 ghost cache다.) 2c2c개를 관리하는 이유는 더 작으면 1, 2, ..., c에 대해 loop reference할 때 hit ratio가 0이라서 그렇다고 한다.

π(c)\pi(c)는 아래의 특성들을 가진다.

  1. L1=T1πB1π,L2=T2πB2πL_1 = T_1^{\pi} \cup B_1^{\pi}, L_2 = T_2^{\pi} \cup B_2^{\pi}
  2. L1L2<c| L_1 \cup L_2 | < c 인 경우 B1πB_1^{\pi}, B2πB_2^{\pi}는 비어있음.
  3. L1L2c| L_1 \cup L_2 | \ge c 인 경우 T1πT2π=c| T_1^{\pi} \cup T_2^{\pi} | = c
  4. T1πT_1^{\pi}B1πB_1^{\pi}이 비어있지 않으면, T1πT_1^{\pi}의 LRU가 B1πB_1^{\pi}의 MRU보다 더 최근에 access했다. (2도 동일)
  5. T1πT2πT_1^{\pi} \cup T_2^{\pi} 에는 policy π(c)\pi(c)로 남은 page들만 남아있다.
  • TT (physical cache) : policy에서 남은 것 중 c개를 가지고 있음
  • BB (ghost cache) : 여기서 miss난 경우에는 이전 access를 기억함.

space overhead는 LRU의 2배다. 4번 특성은 어떤 page가 L1L_1에 caching되어있다면, 그 page보다 recent한 page들은 모두 caching되어있다는 것을 내포한다. 또한 cache가 꽉 찼다는 것은 T1πT2π=c| T_1^{\pi} \cup T_2^{\pi} | = c 라는 의미이므로 T1πT_1^{\pi}T2πT_2^{\pi} 둘 중에서 뭘 replace할지만 policy에서 정하면 된다.

Adaptive Replacement Cache

Fixed Replacement Cache

FRCp(c)FRC_p(c) : Π(c)\Pi(c)에 속함. p는 0pc0 \le p \le c의 parameter

T1,pT1FRCp(c)T_{1, p} \equiv T_1^{FRC_p(c)}, T2,pT2FRCp(c)T_{2, p} \equiv T_2^{FRC_p(c)}, B1,pB1FRCp(c)B_{1, p} \equiv B_1^{FRC_p(c)}, B2,pB2FRCp(c)B_{2, p} \equiv B_2^{FRC_p(c)} 라 할 때 T1,pT_{1, p}pp개의 page, T2,pT_{2, p}cpc-p개의 page를 최대한 유지하려고 함

Replacement Policy : Replace(x_t, p)

  • T1,p>p|T_{1, p}| > p 인 경우 T1,pT_{1, p} 의 LRU를 replace
  • T1,p<p|T_{1, p}| < p 인 경우 T2,pT_{2, p} 의 LRU를 replace
  • T1,p=p|T_{1, p}| = p 인 경우 L_1에서 miss난 경우 L_1에서 replace, L_2에서 miss난 경우 L_2에서 replace

ARC

[adaptation parameter]

  • p[0,c]p \in [0,c]
  • FRCpFRC_p와 replacement는 정확히 동일하게 동작하지만, FRC와 다르게 p가 계속 변함.
  • p의 직관적인 의미는 T1T_1에 저장할 target size
  • p가 0에 가까워지면 L2L_2에 favor를 주겠다는 것이고, c에 가까워지면 L1L_1에 favor를 줌.

편의를 위해 T1T1ARCT_{1} \equiv T_1^{ARC}, T2T2ARCT_{2} \equiv T_2^{ARC}, B1B1ARCB_{1} \equiv B_1^{ARC}, B2B2ARCB_{2} \equiv B_2^{ARC}라고 가정한다.

[알고리즘]

input stream x1,,xt,x_1, \dots, x_t, \dots 에 대해

  1. cache hit (xtT1T2x_t \in T_1 \cup T_2)
    T2T_2의 MRU로 옮김

  2. cache miss in B_1 (xtB1x_t \in B_1)
    p를 δ1\delta_1 만큼 증가 → replace → xtx_tT2T_2의 MRU로 옮김

  3. cache miss in B_2 (xtB2x_t \in B_2)
    p를 δ2\delta_2 만큼 감소 → replace → xtx_tT2T_2의 MRU로 옮김

  4. cache miss not in L (xtL1L2x_t \notin L_1 \cup L_2)

    1. L1=c|L_1| = c
      1. T1<c|T_1| < c : B1B_1의 LRU page를 evict → replace
      2. T1=c|T_1| = c : B1B_1이 비어있으므로 T1T_1의 LRU를 지움
    2. L1<c|L_1| < c
      1. L1+L2c| L_1 | + | L_2 | \ge c : 꽉 찼으면 B2B_2에서 LRU page를 evict → replace
      2. L1+L2<c| L_1 | + | L_2 | < c : TT도 다 안 찼으므로 그냥 넣어도 상관없음

    이후 xtx_tT1T_1의 MRU로 옮김

(p가 동적으로 바뀌므로 순간적으로는 T가 p보다 훨씬 커질 수도 있음)

[Learning]

  • intuition : B_1에서 miss가 나면 T_1의 size를 늘리고 (p 증가), B_2에서 miss가 나면 T_2의 size를 늘린다 (p 감소).
  • idea : 더 좋은 성능을 보이는 쪽의 list에 invest함
  • learning rate δ1\delta_1, δ2\delta_2 : p를 한번에 얼마나 변경할 것인지를 결정함.
  1. B1B_1에서 miss인 경우
    δ1={1,if B1B2B2/B1,o.w.\delta_1 = \begin{cases} 1, {if\ |B_1| \ge |B_2|}\\ |B_2| / |B_1|, \text{o.w.} \end{cases}
  2. B2B_2에서 miss인 경우
    δ2={1,if B2B1B1/B2,o.w.\delta_2 = \begin{cases} 1, {if\ |B_2| \ge |B_1|}\\ |B_1| / |B_2|, \text{o.w.} \end{cases}

(B_1에서 miss가 났다는 건 B_1 크기가 1 이상이라는 거고 소수만큼을 할 순 없으니 자른 것으로 보인다.)

ARC의 장점

[Self-Tunable]
ARC는 쉬지 않고 적응하고 learning한다. 따라서 stable한 IRM에서 transient SDD로 바뀌더라도 잘 적응할 수 있다.

[Scan-Resistant]

L1L_1, L2L_2에 없던 큰 page가 access되는 경우 L1L_1의 MRU에만 계속 들어가고 중요한 page들인 L2L_2에 영향을 주지 않는다.
또 scan의 경우 B1B_1에서 다시 access되는 (B1B_1 miss) 경우가 거의 없으므로 T2T_2의 크기가 계속 늘어난다. 따라서 scan에 점점 더 강해진다.

Evaluation

기본적으로 가장 좋은 parameter로 tuning한 offline 알고리즘들보다도 성능이 대체적으로 좋고, online 알고리즘보다도 좋다고 한다.

또한 FRCpFRC_p에 대해 workload 별로 가장 좋은 성능을 보이는 pp를 고정해놓고 ARC와 비교한 결과에서의 특이점은 아래와 같다고 한다.

  • P4P_4 : workload pattern이 많이 변하는데 FRCpFRC_p의 경우에는 고정된 p를 가지므로 적응하지 못해서 성능이 더 안 좋다.
  • P8P_8 : workload pattern이 거의 일정한데 이 경우에는 ARC의 적응 알고리즘 등으로 인해 ARC가 약간 cost가 높다.

Reference

  • Megiddo, N., & Modha, D. S. (2003, March). ARC: A Self-Tuning, Low Overhead Replacement Cache. In Fast (Vol. 3, No. 2003, pp. 115-130).
profile
고양이를 좋아하는 개발자

0개의 댓글