어떻게 캐시를 그렇게 빨리 할 수 ​​있습니까?


37

캐시 벤치 마크의 스크린 샷은 다음과 같습니다.

AIDA64 캐시 및 메모리 벤치 마크 결과

벤치 마크에서 L1 캐시 읽기 속도는 약 186GB / s이며 대기 시간은 약 3-4 클럭주기입니다. 그러한 속도는 어떻게 달성됩니까?

여기에서 메모리를 고려하십시오. 이론상 최대 속도는 665MHz (메모리 주파수) x 2 (이중 데이터 속도) x 64 비트 (버스 폭)이며 약 10.6GB / s이며 벤치 마크 값 9.6GB / s에 더 가깝습니다. .

그러나 L1 캐시를 사용하면 프로세서에서 최대 주파수 (3 GHz)로 모든주기에서 읽을 수 있더라도 비현실적으로 들리는 처리량을 달성하려면 약 496 개의 데이터 라인이 필요합니다. 이것은 다른 캐시에도 적용됩니다.

내가 무엇을 놓치고 있습니까? 매개 변수에서 캐시의 처리량을 어떻게 계산합니까?


14
L1,2,3 캐시가 물리적으로 상주하는 위치가 얼마나 균등한지 고려 했습니까? 팁 : 칩 전체를 소유하고 있다면 버스 표준에 대해 걱정할 필요가 없습니다.
JonRB

2
또한 : 벤치 마크는 테스트하는 일부 데이터가 레지스터 내부에 똑바로 유지되지 않도록하기 위해 수행중인 작업에 대해 충분히 알고 있습니까?
rackandboneman

7
@rackandboneman : AIDA64는 누군가가 C에서 해킹하여 컴파일러가로드를 최적화하도록하는 것이 아니라, 존경받는 벤치 마크입니다! microbenchmark 부품은 SSE 또는 AVX 버전과 함께 어셈블리로 작성되었다고 가정합니다.
Peter Cordes

1
@Peter Cordes 만족스러운 답변-필요한 질문에.
rackandboneman

1
생각을 물리적 관점에두기 위해 : 1.4 나노초 안에 빛은 약 1 피트 반 정도 이동합니다. 즉, 캐시가 마더 보드의 다른쪽에있는 경우 이와 같은 대기 시간은 상대성을 손상시킬 수 있습니다. 또는 측정 오류 일 수 있습니다.
Arthur

답변:


35

이 CPU는 ...

2 코어 각 코어에 대한 32KB 명령어 및 32KB 데이터 1 단계 캐시 (L1)

코어가 두 개이므로 벤치 마크에서 두 개의 스레드를 병렬로 실행할 수 있습니다. 그들의 웹 사이트는 정보를 거의 제공하지 않지만 여기서 살펴보면 코어가 더 많은 CPU는 그에 따라 더 높은 L1 처리량을 제공하는 것으로 보입니다. 그래서 표시되는 것은 모든 코어가 동시에 작동하는 총 처리량이라고 생각합니다. 따라서 CPU의 경우 하나의 코어와 하나의 캐시에 대해 2로 나눕니다.

Read   93 GB/s
Write  47 GB/s
Copy   90 GB/s

이제 "복사"가 "쓰기"보다 2 배 빠르다는 사실은 매우 의심 스럽습니다. 쓸 수있는 것보다 어떻게 빨리 복사 할 수 있습니까? 벤치 마크가 "복사"로 표시하는 것은 읽기 + 쓰기 처리량의 합계이며,이 경우 45GB / s로 읽고 쓸 수 있지만 벤치 마크이므로 90을 표시합니다. 누가 벤치 마크를 신뢰합니까? "복사"를 무시하자.

Read   93 GB/s => 30 bytes/clock
Write  47 GB/s => 15 bytes/clock

이제 하나의 128 비트 레지스터는 16 바이트로 충분히 가까워서이 캐시가 두 개의 128 비트 읽기와 클럭 당 하나의 쓰기를 수행 할 수있는 것처럼 들립니다.

이것은 정확히 SSE 번호 크 런칭 명령 인 사이클 당 읽기 2 개와 쓰기 1 개를 간소화하려는 것입니다.

이것은 많은 병렬 데이터 라인으로 구현 될 가능성이 높으며, 이는 칩 내부에서 많은 데이터를 매우 빠르게 처리하는 일반적인 방법입니다.


4
@ next-hack 문서의 55 페이지에 "내부적으로 액세스는 최대 16 바이트입니다. [...] 사이클마다 2 개의로드 작업과 1 개의 저장 작업을 처리 할 수 ​​있습니다"라고 표시되어 있습니다. 이는 읽기가 두 배 더 빠른 이유를 설명합니다. 한 번의 쓰기를 수행하면서 동일한 작업에서 두 ​​번의 읽기를 수행 할 수 있습니다.
Tom Carpenter

2
예, 사본 BW = 읽기 및 쓰기를 명확하게 계산합니다. 읽기와 쓰기가 병렬로 실행될 수 있다는 점에서 중요하기 때문에 대안과 마찬가지로 유효합니다. L2 / L3의 OP 번호는 쓰기보다 크게 높지 않고 메모리에 대해서는 더 낮습니다. DDR3 메모리 버스는 전이중이 아닙니다. 읽기 및 쓰기에 동일한 데이터 라인이 필요합니다. NT 저장소와 일반 저장소의 x86 memcpy / memset 대역폭에 대한 자세한 내용은 stackoverflow.com/questions/43343231/…을 참조하십시오 .
Peter Cordes

6
IvyBridge는 동일한 클럭주기에서 2 회 읽기 1 회 쓰기를 수행 할 수 있다고 추측합니다 . 당신은 옳은 일이지만 매우 제한된 상황에서만 가능합니다. IvB에는 2 개의 AGU 포트만 있으므로 일반적으로 클럭 당 2 개의 메모리 op로 제한되며 그 중 하나는 저장 될 수 있습니다 . 그러나 256b AVX로드 / 스토어는로드 / 스토어 포트에서 실행하는 데 2주기가 걸리지 만 첫 번째주기에는 AGU 만 필요합니다. 따라서 저장소 주소 UOP는 256b로드의 두 번째주기 동안 포트 2/3에서 실행될 수 있으며로드 대역폭 비용이 들지 않습니다. (저장소 데이터는 포트 4에서 실행됩니다.) 출처 : agner.org/optimize microarch pdf
Peter Cordes

2
AMD 불도저 제품군 또는 Ryzen CPU는 동일한 읽기 = 2x 쓰기 수를 제공하지만 실제로 허점없이 클럭 당 2 개의 메모리 연산 (최대 1 쓰기 가능)으로 제한됩니다. 읽기 / 쓰기 / 복사는 차이를 감지하지 않지만 Triad는 ( a[i] = b[i] + c[i])를 감지 할 수 있습니다 . BTW, Intel Haswell 이상에는 포트 7에 간단한 A (인덱싱되지 않은) 주소 지정 모드를 처리 할 수있는 store-AGU가 있으므로 클록 당 2 개의로드 + 1 개의 상점 uops를 실행할 수 있습니다. (그리고 L1D에 대한 데이터 경로는 256b이므로 L1D 대역폭을 두 배로 늘립니다.) David Kanter의 글을 참조하십시오 : realworldtech.com/haswell-cpu/5
Peter Cordes

1
@AliChen : OP는 어떻게 그렇게 빠른지 물어보기 전에 대역폭 직후 IvyBridge의 4주기로드 사용 대기 시간을 명시했습니다.
Peter Cordes

27

@peufeu의 대답은 이것이 시스템 전체의 집계 대역폭이라는 것을 나타냅니다. L1 및 L2는 Intel Sandybridge 제품군의 개인별 코어 캐시이므로 단일 코어로 수행 할 수있는 것의 수는 2 배입니다. 그러나 여전히 인상적인 높은 대역폭과 낮은 대기 시간을 유지합니다.

L1D 캐시는 CPU 코어에 바로 내장되어 있으며로드 실행 장치 (및 저장소 버퍼)와 매우 밀접하게 연결되어 있습니다. 마찬가지로 L1I 캐시는 코어의 명령 페치 / 디코딩 부분 옆에 있습니다. (실제로 Sandybridge 실리콘 평면도를 보지 않았으므로 이것은 사실이 아닐 수도 있습니다. 프런트 엔드의 문제 / 이름 변경 부분은 아마도 "L0"디코딩 된 uop 캐시에 더 가깝기 때문에 전력을 절약하고 더 나은 대역폭을 제공합니다 디코더보다.)

그러나 L1 캐시를 사용하면 매주기마다 읽을 수 있다고해도 ...

왜 거기서 멈춰? Sandybridge 이후 Intel 및 K8 이후 AMD는 사이클 당 2 개의로드를 실행할 수 있습니다. 멀티 포트 캐시와 TLB는 중요한 것입니다.

David Kanter의 Sandybridge 마이크로 아키텍처 작성 에는 훌륭한 다이어그램이 있습니다 (IvyBridge CPU에도 적용됨).

"통합 스케줄러"에는 입력이 준비되기를 기다리는 및 / 또는 실행 포트를 기다리는 ALU 및 메모리 UOP가 있습니다 (예 : 이전에 아직 실행되지 않은 경우 vmovdqa ymm0, [rdi]기다려야하는로드 UOP로 디코딩) . 예). 문제 / 이름 바꾸기시 포트 인텔 스케줄 마이크로 연산 .이 도면은 단지 메모리 마이크로 연산의 실행 포트를 보이고 있지만, 미 실행 ALU도 그것이 경쟁을 마이크로 연산. 문제 / 이름 바꾸기 단계는 ROB 및 스케줄러 마이크로 연산을 추가 이들은 은퇴 할 때까지 ROB에 머물러 있지만 실행 포트로 발송할 때까지만 스케줄러에 있습니다 (이것은 인텔 용어이며 다른 사람들은 문제를 사용하고 다르게 발송합니다). AMD는 정수 / FP에 별도의 스케줄러를 사용하지만 주소 지정 모드는 항상 정수 레지스터를 사용합니다rdiadd rdi,32

David Kanter의 SnB 메모리 다이어그램

표시된 것처럼, 2 개의 AGU 포트 (주소 생성 장치는 주소 지정 모드 [rdi + rdx*4 + 1024]를 사용하여 선형 주소를 생성 함) 만 있습니다. 클록 당 2 개의 메모리 ops (각 128b / 16 바이트)를 실행할 수 있으며, 그 중 하나는 상점입니다.

그러나 SnB / IvB는 256b AVX로드 / 스토어를 단일 uop으로 실행하여로드 / 스토어 포트에서 2주기를 수행하지만 첫 번째주기에서는 AGU 만 필요합니다. 이를 통해 두 번째주기 동안 포트 2/3의 AGU에서 저장소 주소 UOP를로드 처리량 손실없이 실행할 수 있습니다. 따라서 SnB / IvB는 AVX (Intel Pentium / Celeron CPU가 : /를 지원하지 않음)를 사용하여 이론적으로 사이클 당 2 개의로드 1 개의 스토어를 유지할 수 있습니다.

IvyBridge CPU는 Sandybridge의 축소 과정입니다 ( 이동 제거 , ERMSB (memcpy / memset) 및 다음 페이지 하드웨어 프리 페칭과 같은 일부 마이크로 아키텍처 개선 ). 그 이후의 생성 (Haswell)은 실행 단위에서 L1까지의 데이터 경로를 128b에서 256b로 확장하여 클록 당 L1D 대역폭을 두 배로 늘려 AVX 256b로드가 클록 당 2를 유지할 수 있습니다. 또한 간단한 주소 지정 모드를 위해 추가 상점 AGU 포트가 추가되었습니다.

Haswell / Skylake의 최대 처리량은 클럭 당 96 바이트로드 + 저장이지만 인텔의 최적화 매뉴얼에서는 Skylake의 지속적인 평균 처리량 (여전히 L1D 또는 TLB 누락이 없다고 가정)이 ~ 81B 사이클임을 제안합니다. (스칼라 정수 루프는 SKL에 대한 테스트따라 클록 당 2로드 + 1 스토어를 유지 하여 4 융합 도메인 uops에서 클록 당 7 (퓨전되지 않은 도메인) uops를 실행할 수 있지만 64 비트 피연산자 대신 약간 느려집니다. 32 비트이므로, 약간의 마이크로 아키텍처 리소스 제한이 있으며 이는 단지 저장소 주소 uops를 포트 2/3로 예약하고로드에서 사이클을 훔치는 문제가 아닙니다.)

매개 변수에서 캐시의 처리량을 어떻게 계산합니까?

매개 변수에 실제 처리량 수가 포함되어 있지 않으면 불가능합니다. 위에서 언급했듯이 Skylake의 L1D조차도 256b 벡터에 대한로드 / 스토어 실행 단위를 따라갈 수 없습니다. 가까이 있지만 32 비트 정수가 가능합니다. (캐시가 포트를 읽은 것보다 더 많은로드 단위를 갖는 것은 이치에 맞지 않습니다. 그 반대도 마찬가지입니다. 완전히 활용 될 수없는 하드웨어는 제외하고 싶을 것입니다. L1D에는 라인을 송수신하기위한 추가 포트가있을 수 있습니다. / 코어 내에서 읽기 / 쓰기뿐만 아니라 다른 코어에서 /)

데이터 버스 폭과 시계 만 살펴 보더라도 전체 스토리를 제공하지는 않습니다. L2 및 L3 (및 메모리) 대역폭은 L1 또는 L2가 추적 할 수있는 미결 누락 수에 의해 제한 될 수 있습니다 . 대역폭은 대기 시간 * max_concurrency를 초과 할 수 없으며 대기 시간이 긴 L3 칩 (예 : 많은 코어 Xeon)은 동일한 마이크로 아키텍처의 듀얼 / 쿼드 코어 CPU보다 단일 코어 L3 대역폭이 훨씬 적습니다. 이 SO 답변 의 "대기 시간 바인딩 플랫폼"섹션을 참조하십시오 . Sandybridge 제품군 CPU에는 L1D 미스 (NT 저장소에서도 사용)를 추적하기 위해 10 개의 라인 채우기 버퍼가 있습니다.

(많은 코어가 활성화 된 총 L3 / 메모리 대역폭은 큰 Xeon에서 크지 만 단일 스레드 코드는 코어가 많을수록 링 버스에서 더 많은 정지를 의미하므로 동일한 클럭 속도에서 쿼드 코어보다 더 나쁜 대역폭을 인식합니다. 대기 시간 L3.)


캐시 지연

그러한 속도는 어떻게 달성됩니까?

L1D 캐시의 4주기로드 사용 대기 시간은 특히 놀랍습니다 . 특히 주소 지정 모드로 시작 [rsi + 32]해야하므로 가상 주소 가 있기 전에 추가해야합니다 . 그런 다음 캐시 태그가 일치하는지 확인하려면이를 물리적으로 변환해야합니다.

( [base + 0-2047]Intel Sandybridge 제품군에서 추가주기를 수행하는 것 이외 의 어드레싱 모드는 간단한 어드레싱 모드 (일반적으로로드 사용 지연이 가장 중요하지만 일반적으로 일반적으로 사용되는 포인터 추적 경우)에 대한 AGU의 단축 법입니다. ( Intel의 최적화 매뉴얼 , Sandybridge 섹션 2.3.5.2 L1 DCache를 참조하십시오 .) 또한 세그먼트 재정의가없고 세그먼트 기본 주소 0가 정상적인 것으로 가정합니다 .

또한 스토어 버퍼를 검사하여 이전 스토어와 겹치는 지 확인해야합니다. 그리고 이전의 프로그램 순서로 상점 주소 uop이 아직 실행되지 않았더라도 이것을 알아 내야하므로 상점 주소를 알 수 없습니다. 그러나 L1D 적중 확인과 동시에 발생할 수 있습니다. 저장소 전달이 저장소 버퍼에서 데이터를 제공 할 수 있기 때문에 L1D 데이터가 필요하지 않은 것으로 판명되면 손실이 없습니다.

인텔은 거의 모든 다른 사람들과 마찬가지로 VIPT (Virtually Indexed Physically Tagged) 캐시를 사용하며, VIPT의 속도와 함께 PIPT 캐시 (별칭 없음)처럼 동작하도록 캐시를 작고 충분히 높은 연관성을 갖는 표준 트릭을 사용합니다. TLB 가상-> 물리적 조회와 병행).

인텔의 L1 캐시는 32kiB, 8 방향 연관입니다. 페이지 크기는 4kiB입니다. 이것은 "인덱스"비트 (어떤 주어진 라인을 캐시 할 수있는 8 가지 방법 세트를 선택 함)가 모두 페이지 오프셋 아래에 있음을 의미합니다. 즉, 이러한 주소 비트는 페이지에 대한 오프셋이며 가상 주소와 실제 주소에서 항상 동일합니다.

작은 캐시와 빠른 캐시가 유용하고 가능한 이유에 대한 자세한 내용은 더 큰 캐시와 쌍을 이룰 때 잘 작동하는 이유에 대한 자세한 내용 은 L1D가 왜 L2보다 작고 빠른지 에 대한 대답을 참조하십시오 .

작은 캐시는 태그를 가져 오는 것과 동시에 세트에서 데이터 배열을 가져 오는 것과 같이 더 큰 캐시에서 너무 많은 전력을 소비하는 작업을 수행 할 수 있습니다. 따라서 비교기가 어떤 태그와 일치하는지 찾으면 SRAM에서 이미 가져온 8 개의 64 바이트 캐시 라인 중 하나만 먹여야합니다.

Sandybridge / Ivybridge는 뱅크가 8 바이트 인 16 바이트 청크가있는 뱅킹 L1D 캐시를 사용합니다. 다른 캐시 라인에서 동일한 뱅크에 대한 두 번의 액세스가 동일한 주기로 실행되면 캐시 뱅크 충돌이 발생할 수 있습니다. (8 개의 뱅크가 있으므로 이는 128 개의 배수로 이루어진 주소, 즉 2 개의 캐시 라인에서 발생할 수 있습니다.)

IvyBridge는 64B 캐시 라인 경계를 넘지 않는 한 정렬되지 않은 액세스에 대한 페널티가 없습니다. 낮은 주소 비트를 기반으로 가져올 뱅크를 파악하고 올바른 1 ~ 16 바이트의 데이터를 얻기 위해 어떤 이동이 필요한지 설정합니다.

캐시 라인 분할에서 여전히 단일 uop이지만 여러 캐시 액세스를 수행합니다. 페널티는 4k 분할을 제외하고는 여전히 작습니다. Skylake는 복잡한 주소 지정 모드를 사용하는 일반 캐시 라인 분할과 마찬가지로 약 11주기의 대기 시간으로 4k 분할도 상당히 저렴하게 만듭니다. 그러나 4k 스플릿 처리량은 cl-split non-split보다 훨씬 나쁩니다.


출처 :


1
그것은 매우 명확하고 철저하며 잘 쓰여졌습니다! +1!
next-hack

8

최신 CPU에서 캐시 메모리는 동일한 다이 (칩) 의 CPU 옆 에 있으며 PC의 RAM 모듈에 사용되는 DRAM 보다 훨씬 빠른 SRAM 을 사용하여 만들어집니다 .

메모리 단위 (비트 또는 바이트) 당 SRAM은 DRAM보다 훨씬 비쌉니다. 그래서 PC에서도 DRAM이 사용됩니다.

그러나 SRAM은 CPU 자체와 동일한 기술로 만들어 지므로 CPU만큼 빠릅니다. 또한 처리 할 내부 (CPU) 버스 만 있기 때문에 496 줄 너비의 버스가 필요하다면 아마도 버스 일 것입니다.


관심을 가져 주셔서 감사합니다. 필자는 레지스터 액세스 속도가 300GB / s를 초과한다고 언급 한 몇 권의 책에서 보았습니다.이 경우 3GHz 프로세서의 경우 레지스터 처리량이 100B / 사이클이며 레지스터의 너비는 일반적으로 64/128 비트이므로 불가능합니다. 그들은 그렇게 많이 출력하지 못했습니다. 이것이 저에 관한 것입니다. 처리량을 표현하는 올바른 방법은 GB / sa입니까?
기사

3
@Knight는 IvB (고성능 프로세서)가주기 당 몇 개의 명령어 (예 : 3 개의 ALU ops, 2 개의로드 및 1 개의 store)를 실행합니다. 이들 중 대부분은 2 개의 입력 (인덱싱 된 주소 지정의 경우에도로드)과 3의로드를 취할 수 있습니다. 이는 각각 8 바이트, 104 바이트에서 13 개의 레지스터입니다 (이러한 서사시 조합은 허용되지 않을 수 있지만 그것이 지속될 수는 없지만 IvB의 경우에는 해당되지 않습니다. 벡터 레지스터도 고려하면 해당 숫자가 더 증가합니다.
harold

@harold : related : Haswell과 Skylake는 클럭 당 레지스터 읽기에 제한이있는 것처럼 보이지만 프런트 엔드에있을 수 있으며 일부 입력이 준비된 후 실행 버스트에 영향을 미치지 않습니다. 어쩌면 그것은 다른 마이크로 아키텍처 한계 일지 모르지만 코드에서 병목 현상을 발견하여 시계 당 더 많은 op를 유지할 수있었습니다. agner.org/optimize/blog/read.php?i=415#852 . Haswell에서 가장 좋은 시나리오는 클럭 사이클 당 ~ 6.5 개의 정수 레지스터를 읽었습니다 (지속됨). 나는 또한 Skylake (매장 주소는 상점 주소 + 상점 데이터)에서 시계 발송 / 실행 당 7 uops를 유지했습니다.
Peter Cordes

프런트 엔드가 맞아야하는 @PeterCordes? IIRC는 역사적으로 문제 (PPro에서 Core2까지)였으며 분수가 어떻게 다른 의미가 있는지 잘 모르겠습니다. 내 번호가 있었다 불구하고 어쨌든 오프 비트
해롤드

@ harold : 예, 아마도 이름이 바뀌는 일종의 프론트 엔드 병목 현상이라고 확신합니다. P6의 레지스터 읽기 병목 현상은 영구 레지스터 파일에서 문제의 ROB로 읽어야하는 "콜드"레지스터에있었습니다. 최근 수정 된 레지스터는 여전히 ROB에 있었으며 병목 현상이 없었습니다. HSW / SKL에 대한 콜드 대 핫 레지스를 많이 조사하지 않았습니다. 왜냐하면 어떤 이유로 루프를 4 uops / 이상적으로 반복 당 1c보다 크게 만드는 것을 생각하지 않았기 때문입니다. 죄송합니다. IDK는 전달과 PRF 읽기 (발행 / 이름 변경이 아닌 실행 시간에 발생해야 함) 사이의 차이가 얼마나되는지.
Peter Cordes

4

L1 캐시는 상당히 넓은 메모리 구조입니다. 인텔 프로세서의 L1 캐시 아키텍처는 이 매뉴얼 (다음 핵에서 제공) 에서 찾을 수 있습니다 . 그러나 일부 매개 변수의 해석이 올바르지 않습니다. "캐시 라인 크기"는 "데이터 너비"가 아니며 원자 데이터 액세스의 직렬 블록 크기입니다.

표 2-17 (2.3.5.1 절)은로드 (읽기)시 캐시 대역폭이 CYCLE코어 당 2x16 = 32 바이트 임을 나타냅니다 . 이것만으로도 3GHz 코어에서 이론적으로 96Gb / s의 대역폭을 제공합니다. 인용 된 벤치 마크 보고서에 대해서는 명확하지 않으며 병렬로 작동하는 두 개의 코어를 측정하는 것처럼 보이므로 두 개의 코어에 대해 192Gbps를 만듭니다.


2

게이트 지연은 무엇입니까? 10 피코 초? 전체 파이프 라인 작업의주기 시간은 333 피코 초이며, 다음 디코딩주기가 시작되기 전에 다양한 디코딩 및 버스 활동과 데이터의 플립 플롭 캡처가 가능합니다.

캐시를 읽는 데있어 가장 느린 활동은 비교기 / 래치가 양수를 구현하기 위해 클록 될 수있는 데이터 라인이 충분히 멀리 떨어져있을 때까지 기다리는 것입니다 (예 : 차등 : 하나의 참조 및 읽기 비트의 실제 전하). 작은 전압을 큰 레일-투-레일 로직 레벨 전압 스윙 (약 1V)으로 변환하는 피드백 동작.


1
4주기 L1D 대기 시간에는 주소 생성 (간단한 주소 지정 모드의 경우 [reg + 0-2047]), TLB 조회 및 태그 비교 (8-way 연관) 및 결과에 최대 16 개의 정렬되지 않은 바이트가 포함됩니다. 다른 실행 장치로 전달하기위한로드 장치의 출력 포트. 포인터 추적 루프의 경우 4c 대기 시간입니다 mov rax, [rax].
Peter Cordes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.