우선 주 메모리 액세스는 매우 비쌉니다. 현재 2GHz CPU (가장 느린 속도)에는 초당 2G 틱 (사이클)이 있습니다. CPU (현재 가상 코어)는 틱당 한 번 레지스터에서 값을 가져올 수 있습니다. 가상 코어는 여러 처리 장치 (ALU-산술 논리 장치, FPU 등)로 구성되므로 가능한 경우 특정 명령을 실제로 병렬로 처리 할 수 있습니다.
메인 메모리 액세스 비용은 약 70ns ~ 100ns입니다 (DDR4가 약간 빠름). 이번에는 기본적으로 L1, L2 및 L3 캐시를 찾고 메모리 (메모리 컨트롤러에 명령을 보내 메모리 뱅크로 전송)를 누르고 응답을 기다렸다가 완료합니다.
100ns는 약 200 틱을 의미합니다. 따라서 기본적으로 프로그램이 항상 각 메모리가 액세스하는 캐시를 놓치면 CPU는 메모리를 기다리는 동안 유휴 상태 (메모리 만 읽는 경우)의 약 99,5 %를 소비합니다.
속도를 높이기 위해 L1, L2, L3 캐시가 있습니다. 그들은 칩에 직접 놓인 메모리를 사용하고 다른 종류의 트랜지스터 회로를 사용하여 주어진 비트를 저장합니다. CPU는 일반적으로 고급 기술을 사용하여 생성되고 L1, L2, L3 메모리에서 생산 오류가 발생하여 CPU를 쓸모 없게 만들 수 있기 때문에 더 많은 공간과 에너지가 필요하며 주 메모리보다 비용이 많이 듭니다. 큰 L1, L2, L3 캐시는 오류율을 증가시켜 ROI를 직접 감소시키는 수율을 감소시킵니다. 따라서 사용 가능한 캐시 크기와 관련하여 큰 절충안이 있습니다.
(현재 실제 생산 결함이 캐시 메모리 영역이 CPU 결함을 전체적으로 렌더링 할 가능성을 줄이기 위해 특정 부분을 비활성화 할 수 있도록 L1, L2, L3 캐시를 더 생성합니다).
타이밍 아이디어를 제공하려면 (출처 : 캐시 및 메모리 액세스 비용 )
- L1 캐시 : 1ns ~ 2ns (2-4주기)
- L2 캐시 : 3ns ~ 5ns (6-10 사이클)
- L3 캐시 : 12ns ~ 20ns (24-40주기)
- RAM : 60ns (120 회)
우리는 서로 다른 CPU 유형을 혼합하기 때문에 추정치 일 뿐이지 만 메모리 값을 가져올 때 실제로 어떤 일이 발생하는지 알고 특정 캐시 계층에서 적중이나 누락이 발생할 수 있습니다.
따라서 캐시는 기본적으로 메모리 액세스 속도를 크게 향상시킵니다 (60ns 대 1ns).
값을 가져 와서 다시 읽을 수 있도록 캐시에 저장하면 자주 액세스하는 변수에는 적합하지만 메모리 복사 작업의 경우 값을 읽고 어딘가에 값을 쓰고 절대 읽지 않기 때문에 여전히 느려집니다. 다시 ... 캐시 적중이없고, 죽은 느린 (이것은 우리가 순서가 잘못되어 병렬로 발생할 수 있습니다).
이 메모리 사본은 매우 중요하므로 속도를 높일 수있는 다른 방법이 있습니다. 초기에는 메모리가 종종 CPU 외부의 메모리를 복사 할 수있었습니다. 메모리 컨트롤러에서 직접 처리했기 때문에 메모리 복사 작업으로 인해 캐시가 오염되지 않았습니다.
그러나 일반 메모리 사본 외에도 메모리의 다른 직렬 액세스가 매우 일반적이었습니다. 일련의 정보를 분석하는 것이 한 예입니다. 정수 배열을 가지며 합계, 평균, 평균 또는 더 간단한 특정 값 찾기 (필터 / 검색)는 범용 CPU에서 매번 실행되는 또 다른 매우 중요한 알고리즘 클래스였습니다.
따라서 메모리 액세스 패턴을 분석함으로써 데이터를 매우 자주 읽는다는 것이 명백해졌습니다. 프로그램이 인덱스 i에서 값을 읽는 경우 프로그램도 값 i + 1을 읽을 가능성이 높습니다. 이 확률은 같은 프로그램이 i + 2 등을 읽는 확률보다 약간 높습니다.
따라서 메모리 주소가 주어지면 미리 읽고 추가 값을 가져 오는 것이 좋습니다. 이것이 부스트 모드가있는 이유입니다.
부스트 모드에서의 메모리 액세스는 주소가 전송되고 여러 값이 순차적으로 전송됨을 의미합니다. 각각의 추가 값 전송에는 추가로 약 10ns (또는 그 이하)가 소요됩니다.
또 다른 문제는 주소였습니다. 주소를 보내는 데 시간이 걸립니다. 메모리의 많은 부분을 처리하려면 큰 주소를 보내야합니다. 초기에는 주소 버스가 단일주기 (틱)로 주소를 전송하기에 충분히 크지 않았으며 더 많은 지연을 추가하여 주소를 전송하기 위해 하나 이상의주기가 필요했습니다.
예를 들어 64 바이트의 캐시 라인은 메모리가 64 바이트 크기의 별개의 (겹치지 않는) 메모리 블록으로 분할됨을 의미합니다. 64 바이트는 각 블록의 시작 주소가 가장 낮은 6 개의 주소 비트를 가지며 항상 0임을 의미합니다. 따라서 매번이 6 개의 0 비트를 전송할 필요가 없으며, 주소 버스 폭에 관계없이 주소 공간을 64 배 늘릴 필요가 없습니다 (환영).
캐시 라인이 해결하는 또 다른 문제 (주소 버스에서 6 비트를 저장 / 해제 / 저장하는 것 외에)는 캐시가 구성되는 방식에 있습니다. 예를 들어, 캐시가 8 바이트 (64 비트) 블록 (셀)으로 분할 될 경우, 메모리 셀의 주소를 저장해야하는 경우이 캐시 셀은 그와 함께 값을 보유합니다. 주소가 64 비트 일 경우 이는 캐시 크기의 절반이 주소에서 소비되어 100 %의 오버 헤드가 발생 함을 의미합니다.
캐시 라인이 64 바이트이고 CPU가 64 비트-6 비트 = 58 비트 (0 비트를 너무 정확하게 저장할 필요가 없음)를 사용할 수 있으므로 오버 헤드 58 비트 (11 % 오버 헤드)로 64 바이트 또는 512 비트를 캐시 할 수 있습니다. 실제로 저장된 주소는 이보다 훨씬 작지만 상태 정보가 있습니다 (캐시 라인이 유효하고 정확하고 더럽고 램으로 다시 써야하는 등).
또 다른 측면은 세트 연관 캐시가 있다는 것입니다. 모든 캐시 셀이 특정 주소를 저장할 수있는 것은 아니며 일부 주소 만 저장할 수 있습니다. 이것은 필요한 저장된 주소 비트를 더 작게 만들고, 캐시의 병렬 액세스를 허용합니다 (각 서브 세트는 한 번 액세스 할 수 있지만 다른 서브 세트와는 독립적 임).
다른 가상 코어, 코어 당 독립적 인 다중 처리 장치 및 하나의 메인 보드 (최대 48 개 이상의 프로세서를 수용하는 보드가 있음)에 여러 개의 프로세서간에 캐시 / 메모리 액세스를 동기화 할 때 더욱 특히 문제가 있습니다.
이것이 기본적으로 현재 캐시 라인을 가진 이유입니다. 미리 읽는 것의 이점은 매우 높으며 캐시 라인에서 단일 바이트를 읽고 다시 읽지 않는 최악의 경우는 확률이 매우 얇기 때문에 매우 얇습니다.
캐시 라인 (64)의 크기는 더 큰 캐시 라인들 사이에서 현명하게 선택된 트레이드 오프 (trade-off)로서, 가까운 미래에도 전체 캐시 라인을 페치하는 데 걸리는 시간 동안 마지막 바이트가 읽히지 않을 수있다 메모리에서 (및 다시 쓰기) 캐시 구성의 오버 헤드와 캐시 및 메모리 액세스의 병렬화.