거북이의 쉼터

기말 대비용 정리 노트 (Lecture 1) 본문

코딩 삽질/HW 요약 정리

기말 대비용 정리 노트 (Lecture 1)

onlim 2022. 9. 23. 17:00

HW 특강이 실질적으로 기말 100%라 정리를 어느 정도 해야겠다는 생각에 문서를 작성한다.

 

디지털 시스템이란 좁은 의미로는 컴퓨터, 넓은 의미로는 IT 장비, 전자칩이 들어가는 여러가지 제품(냉장고, 토스트, 자율 주행 차량 등) 을 포함한다. 각 디지털 시스템에는 그를 위한 아키텍쳐가 있으며, 주로 튜링 머신과 폰 노이만 구조에서 부터 이어져 온 아래와 같은 구조를 채택한다.

 

 

각 시스템은 IO 장치, CPU 역할을 하는 유닛, 메모리 역할을 하는 유닛, 그리고 특정 역할을 수행하는 것을 가속/보조하기 위한 유닛인 커스텀 HW로 구성된다. 각 시스템은 크고 작은 security hole이 있으며, 위와 같이 전형적인 구성으로 이루어진 구조에는 전형적인 공격 패턴 양상이 있다. 이번 학기 수업에는 이러한 공격 양상을 배울 것이다.

 

본격적인 과정을 시작하기 전에 한 가지 질문을 짚어보고 넘어간다. 세상은 아날로그인데, 컴퓨터는 왜 연산/저장에서 디지털 형태를 채택할까? 실제로 곱셈의 경우 아날로그 방식이 더 간단하기 때문에 곱셈이 많이 들어가는 perceptron logic을 위한 아날로그 칩도 개발이 되고 있으며, 디지털로는 트랜지스터가 수 백개 사용될 것을 아날로그 형태로는 단 한 개로 해결할 수 있기 때문에 AI inference 분야에서는 많이 사용되고 있다. 아래 영상에서는 아날로그 칩이 AI에 사용될 수 있는 보다 자세한 원리가 설명되어 있다.

 

 

그럼에도 대부분의 시스템이 디지털 방식으로 연산/저장을 채택하는 이유는 noise와 error에 적게 영향을 받아 결과의 정확성과 재현을 기대할 수 있기 때문이다. 폰 노이만 구조는 굳이 디지털로 만들 필요가 없다. 그러나 아날로그 방식은 공정 과정에 의한 에러가 있을 수 있기 때문에 결과의 정밀성과 특정 연산을 반복할 때 결과의 재현을 반드시 기대할 수 없다. 반면 디지털 방식에서는 일정 이상의 자극은 모두 1, 그 이하는 모두 0으로 처리함으로서 칩 자체의 fabrication, 물리적 오차와 파워 서플라이의 전류 흐름 변화에 강건하도록 하여 noise에 적게 영향을 받게 하는 것이다. 저장할 때도 마찬가지로 저장 유닛에 충전된 charge가 시간에 따라 소모됨에 따라 값이 변동되는 사태를 어느정도 방지할 수 있다. 이렇듯 가장 단순한 값만 취하는 특성상 디지털 시스템에는 트랜지스터가 많이 소모되게 되는 것이다. 

 

아날로그와 디지털을 병합하여 AI칩을 개발하기도 한다. 하나의 플래시 메모리 셀에 4비트의 데이터를 저장하는 방식인 QLC(Quad Level Cell)을 생각해보자. QLC에는 0000부터 1111까지 16개의 값을 저장할 수 있는데, 4개의 비트 영역에 전자가 얼마나 charge 됐는지에 따라 그 값이 0인지 1인지가 결정된다. 저장된 전자에 따라 플래시 메모리 하단에 얼마나 전자가 모일지, 밀려나갈지가 결정되며, 하단의 전자의 양에 따라 같은 전압을 걸더라도 전류의 양이 달라지게 된다. 즉 저항 값을 16개의 값 중 결정할 수 있게 되는데 I = 1/R * V이므로 1/R을 weight로, V를 input값으로 생각하여 하나의 셀을 4 bit inference chip처럼 여길 수 있다. 이는 현재 연구되고 있는 영역으로 아날로그와 디지털 방식이 결합된 칩이라고 볼 수 있다. 전자를 셀의 각 영역에 넣는 것은 플래시 메모리를 다룰 때 자세히 설명할 것이다.

 


 

무어의 법칙은 1965년 무어가 발견한 반도체칩 기술의 발전속도에 관한 관찰 결과로, 반도체칩에 집적할 수 있는 트랜지스터의 숫자가 1년마다 2배씩 증가한다는 법칙이다. 실제로는 약 3년마다 2배씩 CPU의 연산 능력(트랜지스터 수)이 좋아졌다. 이는 애초에 경험적 모델에 근간한 경험 법칙이었지만, 전자 산업계가 따라야할 덕목으로서 이름이 붙여졌으며, 기업들이 해당 법칙에 따라 칩 개발을 목표로 삼다보니 50년 정도 예측이 맞아 떨어지게 되었다. 또한 특정 프로토콜을 지원하기 위해서는 CPU와 메모리 모두에서 어느 정도의 동등한 연산 능력이 요구되기 때문에 이러한 상호작용에 의해 싱크를 맞춰가면서 발전하게 되었다. 요즘은 low level 공정에 있어 경쟁력있는 회사가 줄어서 무어의 법칙의 기울기가 줄긴 했다. 

 

무어의 법칙에 따라 트랜지스터의 개수는 계속 늘어나지만 칩이 소모하는 전력은 어느정도 유지되던 때가 있다. 이는 트랜지스터의 크기를 계속 줄여온 것과, 전압을 낮춰서 유지해 온 것이다. 그러나 트랜지스터의 크기는 무한히 줄일 수 없고, 전압을 일정 이하로 낮추면 noise에 강건하지 않아 결과가 불안정해지기 때문에 한계치까지 낮아져 있다. 이 때문에 트랜지스터의 개수를 늘리면 전력소모가 증가하기 시작하는 등 한계에 부딫히고 있다. 이 때문에 Cerebras 같이 칩 자체를 크게 만들어서 한계를 극복하려는 등 여러 시도가 이루어지고 있으나, 혁신이 필요한 시점인 것은 맞다.

 

구현해야 할 칩의 복잡도가 급격하게 증가함에 따라 현대 칩 디자인이 난해해졌다. 칩의 마지막 단계까지 가면 디버깅 하나만 해도 3개월 정도 걸리는 것만 봐도 얼마나 어려워졌는지 알 수 있다. 이 때문에 abstaction으로 칩의 complexity를 숨기는 것과 함께 instruction set 중심의 일반적인 작업을 할 수 있는 general HW를 개발하고, 나머지 복잡한 연산은 SW의 영역으로 넘기는 것이 일반적인 발전 과정이 되었다.

 

 

Instruction Set Architecture를 기준으로 아래쪽은 HW, 위쪽은 SW의 영역으로 나누어 아래쪽은 일반성을 살린 대량생산, 위쪽은 complexity를 cover하기 위한 자유도를 담당하고 있다. 우리가 배울 것은 HW 쪽의 특성을 활용하여 SW 쪽에서 공격하는 법이다. 

 


 

HW와 SW 설계에서 공통적으로 들어가는 fundamental한 사상인 10가지 Key Tools for System Architecture (시험 출제 예정, 각각의 정의와 예시를 확실히 알고 넘어가야 한다)

1. Pipelining

어셈블리 라인 위에 각 노동자가 정해진 일만 하도록 만든 포드사를 생각해보자. 하나의 자동차가 완전히 만들어지기 전에 다음 자동차가 조립이 되듯, pipelining의 핵심은 전체 작업의 단계를 나누고, 개별적인 실행 단계에 걸쳐 여러 실행을 중첩시키는 것에 있다. (overlap the execution of tasks through different states) 일상 생활 속에서 pipelining이 적용된 예시는 학식, 급식 배분 같은 것을 생각할 수 있다. 

 

Pipelining의 가장 큰 문제는 나눠진 단계 중 특정 작업이 진행이 더디거나 해당 작업으로 몰릴 때 효율이 감소한다는 것이다. 각 단계가 무사히 진행이 되어야 하고, 하나라도 멈추면 전체가 멈추기 때문에 단계별 작업의 밸런스도 중요하다. 

2. Parallelism

어떤 작업을 시행할 때, 복수의 worker를 두고 task를 분배한다. 일상 생활 속에서 parallelism이 적용된 사례로는 지하철 개찰구, 엘리베이터를 여러 대 두는 것 등이 있다. 

3. Out of Order Execution

명령 실행 효율을 높이기 위해 작업들을 정의된 순서에 따라 처리하지 않고, 준비된 작업부터 순서대로 처리하는 기법이다. Dependency가 없는 작업에 대해 순서를 바꾸면 더 효율적으로 일이 처리될 수 있는 가능성이 있기 때문에 유용하다. 상황에 따라서 예정된 순서를 바꾸는 작업이 진행되면 모두 OOO라고 할 수 있다. 

4. Prediction (Speculation)

특정되지 않은 정보에 대해서 일정 정보(경험, history)를 기반으로 예측을 함으로, 미래에 이루어질 작업의 dependency를 깨는 것이다. Branch prediction이 대표적인 예시이며, prediction을 통해 특정 루트의 instruction을 미리 fetch하는 등의 작업을 진행한다. 일상 생활 속에서 prediction이 적용된 사례로는 과거 경험으로 특정 가게가 몰릴 것으로 예상되는 날에는 가게를 가지 않는 판단을 들 수 있다.

 

특정 경험을 누적시켜 한 루트로 prediction을 편향시킨 뒤, 이를 이용해 leak을 내는 공격하는 방식이 존재한다. (Spectre)

5. Locality & Caching

Temporal Locality와 Spatial Locality 두 가지의 locality가 존재한다. Temporal Locality는 한 번 사용된 값이 또 사용될 가능성이 높다는 것을 나타내며, Spatial Locality는 한 번 사용된 값의 인접한 주소의 값이 사용될 가능성이 높다는 것을 나타낸다. 일종의 데이터 특성으로서, 아키텍쳐는 이를 활용하는 방안으로 설계한다. 대표적인 예시가 caching으로 최근에 접근한 데이터와 그 인근 데이터를 cache에 저장해서 보다 빠르게 접근이 가능하도록 하는 것이다. 일상 생활에서는 자주 쓰는 물건을 가까이 두고, 아닌 것은 멀리 두는 것이 locality와 caching이 적용된 사례라고 할 수 있다. 

 

Locality를 악용하여 특정 셀에 집중적으로 접근시 인근 셀이 전기적 영향에 의해 바뀔 수 있다는 것을 활용한 공격이 있다.

6. Indirection

어떠한 자원에 접근할 때, 직접 접근보다 간접적인 이름, 참조, 컨테이너 등의 중간 대리 매체을 두어 접근하는 방식이다. virtual memory가 여기에 해당하는 개념이다. 중간에 entity를 두어 간접적으로 참조하는 방식이기 때문에 자원까지의 거리가 멀어져 비용은 추가되지만, 가상화 및 추상화를 거쳐 단순화, 일반화를 시킬 수 있기 때문에 얻을 수 있는 이익도 있다. 실생활에서 찾을 수 있는 indirection이 적용된 사례로는 전화 상담시 자동 응답 시스템을 두는 것이나 GUI의 적용, 주식 투자형 펀드를 통해 내가 직접적으로 돈을 투자하는 것이 아닌 간접적으로 투자하는 것 등을 들 수 있다. 

7. Amortization

조금 난해할 수 있는 개념이다. 

실생활에서 amortization이 적용된 것은 드라마 비디오를 다운 받아 시청하는 경우를 생각해보자. 드라마 1편을 다운 받은 뒤 해당 연상을 끝까지 시청하고, 2편을 받아 시청하고, 이런식으로 반복한다면 중간에 많은 시간이 낭비된다. 드라마를 보기 위해서는 필연적으로 다운을 받는 시간이 필요한데, 이를 좀 더 효율적으로 한다고 하면 드라마를 시청하고 있는 사이에 다음 볼 드라마의 비디오를 다운 받는 것이다. 필요한 overhead를 비슷한 작업을 같이 수행함으로서 숨기는 것이다.

 

Pipelining은 원래 프로세싱을 작은 세부 단계로 분할하여 각각의 일을 따로 맡기고 중첩시키는 것이었다. Amortization은 그에 비해 원래 해야 할 일과는 관계 없이 해당 일을 위해 필요한 overhead에 해당하는 것을 원래 해야 할 일과 병행하여 숨기는 것이다. 하나의 instruction에 대해 fetch가 끝났다면 바로 다음 instruction이 fetch가 되어 중첩 작업이 이루어지는 것은 pipelining이며, 그 instruction을 들고 올 때 필요한 overhead를 없애기 위해 미리 들고 오는 것이 amortization이다.

8. Redundancy

필요한 정보 또는 부품의 사본을 많이 만들어 사본들을 이용해 fault handling을 할 수 있도록 하는 것이다. Parallelism과 유사해보이지만 사본을 만드는 이유에서 차이가 있다. 만약 하나만 있어도 충분한데, 속도를 가속화하기 위해서라면 parallelism이라 할 수 있다. 그러나 만약 사본을 만드는 이유가 fault tolerence 때문이라면 redundancy이다. 비행기 엔진이 3개만 달아도 되지만 하나가 망가지더라도 비행이 가능하도록 4개를 달았다면 이는 redundancy에 해당한다. Redundancy는 fault tolerence만 담당하면 되기 때문에 반드시 원본과 같은 사본이 있을 필요는 없으며, 디스크의 백업이라 하면 자기 테이프로도 가능하다.

9. Specialization

일반적인 operation을 고려할 때 발생하는 overhead를 줄이기 위해 특정 목적에 맞게끔 부품을 최적화, 전문화하는 것이다. 실생활에서 Specialization이 적용되는 것으로는 공장에서의 분업, 전공을 택해 계속 공부하면서 특정 분야에서 강해지는 것을 사례로 들 수 있다.

10. Focus on Common Case

많이 보편적인 경우를 최적화해야 가장 극적인 개선 효과가 있다. 이는 아무리 최적화를 하더라도 이 최적화로부터 영향받지 않는 다른 부분으로 그 효과는 제한적일 수 있다는 것이라는 암달의 법칙과 일맥상통한다. 즉 성능을 개선할 때 헛된 곳에 시간 등의 자원을 낭비하지 말고 가장 critical한 issue에 집중해서 해결해야 하는 것을 의미한다. 해결해야 할 문제 중 우선적으로 해결해야 할 문제 선택과 관련된 조항이다.  

 

간단히 영어로 정리하면 아래와 같다. (사실 이것만 외워도 될듯)

 

  1. Pipelining: overlap steps in execution; watch out for dependencies
  2. Parallelism: execute independent tasks in parallel
  3. Out-of-order execution: execute task in order of true dependencies
  4. Prediction: better to ask for forgiveness than permission…
  5. Caching: keep close a copy of frequently used information
  6. Indirection: go through a translation step to allow intervention
  7. Amortization: coarse-grain actions to amortize start/end overheads
  8. Redundancy: extra information or resources to recover from errors 
  9. Specialization: trim overheads of general-purpose systems
  10. Focus on the common case: optimize only the critical aspects of the system
Comments