일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 컴퓨터과학
- 데이터구조
- 클라우드컴퓨팅
- 보안
- 데이터과학
- 프로그래밍
- 네트워크
- 딥러닝
- 2
- 프로그래밍언어
- I'm Sorry
- 인공지능
- 머신러닝
- 데이터분석
- 코딩
- 자료구조
- 웹개발
- 소프트웨어공학
- 빅데이터
- 파이썬
- 알고리즘
- 소프트웨어
- 자바스크립트
- 컴퓨터비전
- 버전관리
- 데이터베이스
- 네트워크보안
- 컴퓨터공학
- Yes
- 사이버보안
- Today
- Total
스택큐힙리스트
성능은 프로세서 폭의 배수가 아닌 uop 수를 가진 루프를 실행할 때 감소합니까? 본문
저는 최근 x86 프로세서에서 다양한 크기의 루프가 uop의 개수에 따라 어떻게 수행되는지 궁금합니다.
마이크로 퓨전 및 주소 지정 모드 에서 4의 배수가 아닌 카운트에 대한 문제를 제기한 Peter Cordes 의 인용입니다.
또한, 루프 버퍼 바깥의 UOP 대역폭이 주기당 상수 4가 아니라는 것을 발견했습니다. 만약 루프가 4의 배수가 아닌 경우 (즉, abc, abc, ... 형식이 아닌 경우), Agner Fog의 마이크로아키텍처 문서에서는 이러한 루프 버퍼의 제한 사항에 대해 명확하게 설명되지 않았습니다.
문제는 루프가 최대 uop 처리량으로 실행되기 위해 N 개의 uop의 배수여야 하는지에 대한 것입니다. 여기서 N은 프로세서의 너비를 의미합니다 (예 : 최근 Intel 프로세서의 경우 4입니다). 너비와 uop 수에 대해 이야기할 때는 많은 복잡한 요소들이 있지만, 대부분 무시하고 싶습니다. 특히 마이크로 또는 매크로 퓨전은 가정하지 않습니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하면서 한국어로 번역해주세요..
Peter는 다음과 같은 몸체에 7개의 uop이 있는 루프 예제를 제공합니다:
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하면서 한국어로 번역해주세요..
7-uop 루프는 4|3|4|3|...의 그룹을 발생시킵니다. 루프 버퍼에 들어맞지 않는 큰 루프를 테스트하여, 다음 반복에서 처음 명령어가 해당 분기와 같은 그룹에서 발생할 수 있는지 여부를 확인하지는 않았습니다. 하지만 가능하지 않다고 가정합니다.
더 일반적으로, 주장은 본문 내에서 'x' uop들을 가진 루프의 각 반복이 단순히 'x / 4' 이 아닌 적어도 'ceil(x / 4)' 반복을 가져갈 것이라는 것입니다.
이것은 일부 또는 최근에 출시된 x86 호환 프로세서에 대해 모두 사실입니까?
답변 1
나는 Skylake 상자에서 답변을 돕기 위해 Linux 'perf' 로 인한 조사를 진행하였으며, Haswell 결과는 다른 사용자에 의해 친절하게 제공되었습니다. 아래의 분석은 Skylake에 적용되지만, Haswell과의 비교가 이어집니다.
기타 구조물은 0으로 다양할 수 있으며, 이를 정리하기 위해 추가 결과를 환영합니다. The 'source is available')
이 질문은 주로 프런트 엔드와 관련이 있습니다. 최근 아키텍처에서는 프런트 엔드가 한 사이클당 네 개의 퓨즈 도메인 uop을 강제로 제한하는 하드 리미트를 부과합니다.
여러분은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하면서 한국어로 번역해주세요.
루프 성능에 대한 요약규칙:
먼저, 작은 루프를 처리할 때 주의해야 할 몇 가지 성능 규칙에 대해 요약하겠습니다. 다른 성능 규칙도 많이 있지만, 이 규칙들은 그와 보완적입니다 (즉, 이 규칙들을 따르기 위해 다른 규칙을 깨트리지 않는 한). 이 규칙들은 주로 하스웰 이후의 아키텍처에 직접적으로 적용됩니다 - 이전 아키텍처의 차이에 대한 개요는 'other answer' 를 참조하십시오.
먼저, 루프 내의 마크로 퓨즈된 uop의 수를 세어보세요. Agner의 #$^@^@@$&을(를) 사용하여 각 명령어에 대한 직접 조회를 할 수 있습니다. 그러나 ALU uop과 즉시 후속 브랜치는 일반적으로 하나의 uop으로 퓨즈됩니다. 그런 다음 이 수에 기반하여:
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하면서 한국어로 번역해주세요..
만약 카운트가 4의 배수이면 좋습니다: 이러한 루프는 최적으로 실행됩니다.
만약 카운트가 짝수이고 32보다 작다면 괜찮습니다. 다만 10인 경우, 가능하다면 다른 짝수로 풀어 헤칠 필요가 있습니다.
홀수의 경우, 32보다 작거나 4의 배수인 짝수로 만들어보는 것이 좋습니다.
32개 이상의 uop를 가지는 루프 중 64개 미만인 경우, 이미 4의 배수가 아니라면 언롤링할 수도 있습니다: 64개 이상의 uop를 가지고 있다면, Skylake에서는 모든 값에서 효율적인 성능을 얻을 수 있으며, Haswell에서는 거의 모든 값에 대해 (일부 정렬 관련 여지가 있을 수 있음) 효율적인 성능을 얻을 수 있습니다. 이러한 루프의 비효율성은 여전히 상대적으로 작으며, 피해야 할 값은 첫 번째로 '4N + 1' 수와 이어지는 '4N + 2' 수입니다.
이해결에 대한 요약
당신은 컴퓨터 전문가입니다. 특수 기호를 유지하면서 한국어로 번역해주세요.
uop 캐시에서 제공되는 코드에 대해서는, 4의 배수 효과가 보이지 않습니다. uop의 어떤 수의 루프도 1사이클당 4개의 퓨즈 도메인 uop의 처리량으로 실행될 수 있습니다.
코드가 레거시 디코더에 의해 처리될 경우, 그 반대가 사실입니다: 루프 실행 시간은 정수 개의 사이클로 제한되며, 따라서 4개의 uop을 갖지 못하는 루프는 일부 이슈/실행 슬롯을 낭비하기 때문에 4개의 uop/사이클을 달성할 수 없습니다.
루프 스트림 검출기(LSD)에서 발생하는 코드에 대한 상황은 두 가지를 혼합한 것으로, 자세한 내용은 아래에서 설명합니다. 일반적으로, 32개 아래의 uop을 포함하고 짝수 개의 uop을 가진 루프는 최적으로 실행되지만, 홀수 크기의 루프는 그렇지 않으며, 더 큰 루프는 최적으로 실행되기 위해 4의 배수 개의 uop 카운트가 필요합니다.
인텔(Intel)의 말에 따르면
당신은 컴퓨터 전문가입니다. 특수 기호는 그대로 유지하며 번역해 주세요..
인텔은 실제로 최적화 매뉴얼에 이에 대한 노트를 갖고 있습니다. 자세한 내용은 다른 답변에 있습니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하여 한국어로 번역하십시오..
최근 x86-64 아키텍처에 정통한 사람이라면, 프런트 엔드의 페치와 디코드 부분은 코드 크기와 기타 요소에 따라 여러 가지 모드 중 하나로 작동할 수 있음을 알고 있습니다. 이러한 다른 모드들은 루프 크기 조정에 대해 각각 다른 동작을 합니다. 각각의 모드에 대해 별도로 다루겠습니다.
레거시 디코더
전통적 디코더 1은 코드가 uop 캐싱 메커니즘(LSD 또는 DSB)에 맞지 않을 때 사용되는 완전한 기계 코드에서 uop으로 디코딩하는 장치입니다. 이러한 상황이 발생하는 주요 이유는 코드 작업 세트가 uop 캐시보다 큰 경우(이상적인 경우 약 1500개의 uop, 실제로는 더 적음)입니다. 그러나 이 테스트에서는, 32바이트 정렬된 청크에 18개 이상의 명령이 포함된 경우에도 전통적 디코더가 사용될 수 있다는 사실을 이용할 것입니다.
유산 디코더 동작을 테스트하기 위해 다음과 같은 루프를 사용합니다:
'short_nop:
mov rax, 100_000_000
ALIGN 32
.top:
dec rax
nop
...
jnz .top
ret
'
기본적으로, 셈이 0이 될 때까지 카운트다운하는 간단한 루프입니다. 모든 명령은 단일 단위 연산 4개로 구성되며, 'nop' 로 표시된 위치에서 @!'...' 의 명령어 수가 다르게 변화하여 다양한 크기의 루프를 테스트합니다 (따라서 4개의 단위 연산을 포함한 루프는 'nop' 가 2개입니다). 합성은 항상 ec' and 와 nz' wit 사이에 적어도 하나의 'nop' 를 구분되게 사용하며, 또한 미세 합성은 없습니다. 마지막으로, 메모리 액세스는 (미시 icache 액세스를 제외하고) 없습니다.
주의 사항은 이 루프가 매우 배리어가 있는 것이다. - 각각의 'nop' 명령은 1바이트이므로('perf' 성능 카운터를 검토한 결과와 같이), 루프 내에서 19개의 명령을 돌때 32B 청크 조건의 >18 명령을 즉시 실행시킬 것이다. LSD 5에서 18 uop 루프까지 거의 100%의 명령이 나오지만, 19 uop 이상으로 넘어가면 모두 레거시 디코더에서 나오게 된다.
아무쪼록, 여기에 3부터 99까지의 모든 반복 실행에 대한 사이클/반복문 크기를 제공합니다.
파란 점들은 LSD에 맞는 루프들이며, 약간 복잡한 동작을 보입니다. 우리는 이후에 이들을 살펴볼 것입니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하며 한국어로 번역합니다..
빨간 점들 (19 Uops/반복부터 시작)은 기존 디코더에 의해 처리되며 매우 예측 가능한 패턴을 보여줍니다.
모든 루프는 'N' uops를 사용하며 정확히 'ceiling(N/4)' 반복을 수행합니다.
그래서, 적어도 기존 디코더의 경우, Peter의 관찰은 Skylake에서 정확히 적용됩니다: 4의 배수 uop을 가진 루프는 IPC 4에서 실행될 수 있지만, 다른 개수의 uop은 1, 2 또는 3의 실행 슬롯을 낭비할 것입니다 (각각 '4N+3', '4N+2', '4N+1' 지시어를 갖는 루프에 대하여).
나에게는 이것이 왜 발생하는지 명확하지 않습니다. 16B 청크에서 디코딩이 일어나므로 4 uops/사이클로 디코딩 속도를 고려한다면 4의 배수가 아닌 반복에는 항상 몇 개의 (낭비된) 슬롯이 있을 것으로 보입니다. 그러나 실제 요청 및 디코딩 유닛은 사전디코드와 디코드 단계로 구성되어 있으며 사이에 큐가 있습니다. 사전디코딩 단계는 실제로 6개의 명령을 처리하지만 각 사이클마다 16바이트 경계까지만 디코딩합니다. 이는 루프 끝에서 발생하는 버블이 사전디코더->디코드 큐에 의해 흡수될 수 있다는 것을 시사합니다. 사전디코더의 평균 처리량이 4보다 높기 때문입니다.
내가 어떻게 프리디코더가 작동하는지에 대한 이해를 기반으로 완전히 설명할 수 없어. 비정수적인 사이클 카운트를 방지하는 디코드 또는 프리디코딩에서 추가적인 제한 사항이 있을 수도 있어. 예를 들어, 아마도 레거시 디코더는 점프 뒤의 명령어가 프리디코딩된 큐에 있더라도 점프 양쪽의 명령어를 디코드할 수 없는 것일지도 모르겠어. 아니면 이건 아마도 매크로 퓨전에 필요한 것과 관련이 있을지도 모르겠어. 'handle'
위의 테스트는 루프의 맨 위가 32바이트 경계에 정렬된 동작을 보여줍니다. 아래는 동일한 그래프이지만, 루프의 맨 위가 2바이트 위로 이동하여 정렬이 32N + 30 경계에서 잘못 정렬되었을 때의 효과를 보여주는 추가된 시리즈가 있습니다.
대부분의 루프 크기는 이제 1 또는 2 사이클의 벌금을 받게 됩니다. 1 사이클 벌금은 16B 경계 해독과 사이클당 4개 명령어 해독을 고려할 때 이해되며, 2 사이클 벌금은 루프에서 어떤 이유로 DSB가 루프 내에서 1개 명령어에 사용되는 경우 발생합니다(아마도 'dec' 명령어가 자체 32바이트 청크에 나타나는 경우일 것입니다) 그리고 DSB<->MITE 전환에 일부 벌금이 발생합니다.
일부 경우에는 정렬 문제가 루프의 끝을 더 잘 맞추게 되어 상관이 없습니다. 정렬 문제를 테스트해 보았는데, 이는 200개의 uop 루프까지도 동일한 방식으로 지속됩니다. Predecoder의 설명을 직관적으로 받아들인다면 앞서 언급한 대로 정렬 문제를 숨길 수 있어야하지만 그렇지 않은 것 같습니다 (아마도 큐가 충분히 크지 않을 수도 있습니다).
당신은 컴퓨터 전문가입니다. 특수문자를 그대로 유지하면서 한국어로 번역하십시오..
DSB (Uop Cache)
유포 캐시 (인텔은 이를 DSB라고 부릅니다)는 중간 수준의 명령의 대부분을 캐싱할 수 있습니다. 일반적인 프로그램에서는 대부분의 명령이 이 캐시에서 서비스되기를 희망합니다 7.
우리는 위의 테스트를 반복할 수 있지만, 이제 uop 캐시에서 uop을 제공합니다. 이는 우리의 nops 크기를 2바이트로 늘리는 간단한 문제입니다. 이로 인해 더 이상 18개의 명령 제한에 도달하지 않습니다. 우리는 우리의 루프에서 2바이트 nop 'xchg ax, ax' 를 사용합니다.
'long_nop_test:
mov rax, iters
ALIGN 32
.top:
dec eax
xchg ax, ax ; this is a 2-byte nop
...
xchg ax, ax
jnz .top
ret
'
여기에서 결과는 매우 명확합니다. DSB에서 전달된 모든 테스트된 루프 크기에 대해 필요한 사이클 수는 'N/4'였습니다. 즉, 루프가 4의 배수가 아니더라도 최대 이론 처리량에서 실행되었습니다. 따라서 일반적으로 스카이레이크에서 DSB에서 서비스되는 중간 크기의 루프는 특정 배수의 uop 개수를 충족시키는 데 신경 쓸 필요가 없습니다.
여기는 1,000 uop 루프에 대한 그래프입니다. 눈을 감아도 64 uop(루프가 LSD에 있을 때) 이전의 부적절한 동작을 볼 수 있습니다. 그 이후에는 1,000 uop까지의 전체적으로 일정한 진행 상태입니다(900 근처에서는 내 컴퓨터에 대한 부하 때문에 작은 변동이 있었을 것입니다).
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하면서 한국어로 번역해주세요..
다음으로, uop 캐시에 맞는 크기의 작은 for 루프의 성능을 살펴봅니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하면서 한국어로 번역하십시오.
LSD (루프 스팀 감지기)
중요한 참고사항: 인텔은 아마도 Skylake (SKL150 오류), Kaby Lake (KBL095, KBW095 오류) 칩을 통해 하이퍼스레딩과 악마의 상호작용과 관련된 이유로 미세코드 업데이트를 통해 LSD를 비활성화했습니다. 이러한 칩에 대해서는 아마도 아래 그래프는 64 개의 uop 이상의 흥미로운 영역이 아니라 64 개의 uop 이후의 영역과 동일한 모습을 갖게 될 것입니다.
루프 스트림 검출기는 최대 64 개의 uop (Skylake를 기준으로)을 캐시 할 수 있습니다. 인텔의 최근 문서에서는 성능 기능보다는 전력 절약 메커니즘으로 이 위치에 있으며, LSD 사용에는 확실히 성능 하락이 언급되지 않습니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하면서 한국어로 번역해주세요..
LSD에 들어맞는 루프 크기로 실행하면 다음의 사이클/반복 동작을 얻을 수 있습니다:
여기서 빨간 선은 LSD에서 전달되는 uop의 %입니다. 5에서 56까지의 모든 루프 크기에서 100%로 평평합니다.
3개와 4개의 uop 루프에 대해, 우리는 각각 uop의 16%와 25%가 레거시 디코더로부터 전달되는 이상한 동작을 가지고 있습니다. 흐음? 다행히도, 루프 처리량에는 영향을 미치지 않는 것 같습니다. 두 경우 모두 1 루프/사이클의 최대 처리량을 달성합니다. 이는 MITE<->LSD 전환 패널티가 있을 것으로 예상될 수 있는데도 불구하고입니다.
57와 62 uop의 loop 크기 사이에서, LSD에서 전달되는 uop의 수에는 이상한 동작이 있습니다 - 약 70%의 uop은 LSD에서 전달되고 나머지는 DSB에서 전달됩니다. Skylake는 명시적으로 64-uop의 LSD를 가지고 있으므로 LSD 크기가 초과되기 전에 이러한 종류의 전이가 발생합니다 - 아마도 IDQ(제어 범위 내에서 LSD가 구현된 부분) 내에서 일부만 LSD에 부분적으로 맞게 되는 내부 정렬이 있는 것일 수 있습니다. 이 단계는 짧으며 성능적으로는 주로 이전에 있던 LSD 성능과 이후에 이어지는 전체 DSB 성능의 선형 결합으로 보입니다.
네가 컴퓨터 전문가에요. 5에서 56 uop 사이의 결과의 본주을 살펴봅시다. 우리는 세 가지 명확한 영역을 볼 수 있어요:
3에서 10까지의 uop 순환: 여기서 동작은 복잡합니다. 이는 하나의 순환 실행에서 정적 동작으로 설명할 수 없는 사이클 계수를 볼 수 있는 유일한 영역입니다. 범위가 너무 짧아서 패턴이 있는지 알기 어렵습니다. 4, 6 및 8 uop 순환은 모두 최적으로 실행되며, 'N/4' 사이클에서 (다음 영역과 동일한 패턴) 동작합니다.
10 개의 uop 루프는 한편으로는 반복 당 2.66 사이클로 실행되며, 34 uop 이상의 루프 크기에 도달 할 때까지 최적으로 실행되지 않습니다 (26의 이상치를 제외하고). 이는 '4, 4, 4, 3' 와 같은 반복된 uop/사이클 실행율에 해당합니다. 5 개의 uop 루프의 경우, 이상적인 1.25와 매우 가까우나 정확히는 아닌 1.33 사이클입니다. 이는 '4, 4, 4, 4, 3' 와 같은 실행율에 해당합니다.
이러한 결과는 설명하기 어렵습니다. 결과는 실행마다 반복되며, nop를 실제로 무언가를 수행하는 명령어로 대체하여 변경해도 견고합니다. 이는 모든 루프에 적용되는 2 사이클마다 1 번의 분기 제한과 관련이 있을 수 있습니다. 아마도 uop들이 가끔 이 제한에 맞추어 정렬되어 추가 사이클이 발생하는 것일 수 있습니다. 하지만 12개 이상의 uop에 도달하면 반복마다 최소 3 사이클을 항상 수행하므로 이러한 현상은 발생하지 않습니다.
11에서 32-uops까지의 루프: 우리는 계단식 패턴을 볼 수 있지만 주기는 2입니다. 기본적으로 모든 짝수 개의 uops를 가진 루프는 최적으로 수행됩니다. 즉, 정확히 'N/4' 주기를 가져갑니다. 홀수 개의 uops를 가진 루프는 issue slot 하나를 낭비하며, 한 개의 uop가 더 많은 루프와 동일한 주기로 수행됩니다 (즉, 17 uop 루프는 18 uop 루프와 동일한 4.5 주기를 가집니다). 따라서 여기서 우리는 많은 uop 개수에 대해 'ceiling(N/4)'보다 나은 동작을 가지고 있으며, Skylake가 적어도 비정수 주기로 루프를 실행할 수 있는 첫번째 증거가 있습니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하며 한국어로 번역해주세요..
유일한 이상치는 N=25와 N=26입니다. 이 두 값은 기대값보다 약 1.5% 더 오래 걸립니다. 이는 작지만 재현 가능하며, 파일 내에서 함수를 이동시켜도 결과가 변하지 않습니다. 단순한 반복 효과로 설명될 수 없을 정도로 작습니다. 아니라면, 이는 아마 다른 요인으로 인한 것입니다.
여기서의 전체적인 동작은 하드웨어가 루프를 2 배로 풀어 헤친다는 점을 제외하고는 완전히 일관성을 유지합니다 (25/26 이상 현상을 제외하고).
33에서 ~64 uop까지의 루프 : 우리는 다시 기울어진 계단 모양을 보지만, 주기가 4이며 32 uop 이하의 경우보다 평균 성능이 나쁩니다. 이 동작은 정확히 'ceiling(N/4)' 와 같습니다 - 즉, 기존 디코더와 동일합니다. 그래서 32에서 64 uop의 루프에서는 LSD가이 특정한 제한 사항에 대한 프런트 엔드 처리량에서 기존 디코더보다 명백한 이점을 제공하지 않습니다. 물론, LSD가 더 나은 다른 방법이 많이 있습니다 - 더 복잡하거나 더 긴 명령어의 경우 발생할 수있는 디코딩 병목 현상을 피하고 전력을 절약합니다.
이 모든 것은 상당히 놀랍습니다. 왜냐하면 이는 LSD로부터 전달되는 반복문이 DSB보다 프론트 엔드에서 더 나은 성능을 발휘한다는 것을 의미하기 때문입니다. 일반적으로 LSD가 UOP의 엄격한 권장 소스인 DSB보다 우수한 성능을 가질 것이라고 생각되기 때문에, 반복문을 LSD에 맞출 수 있도록 루프를 작게 유지하려는 권고 사항의 일부로 처리됩니다.
같은 데이터를 보는 또 다른 방법이 있습니다 - 주어진 uop 수에 대한 효율 손실을 최대 이론적 처리량 1 사이클당 4 개의 uop과 비교하여 표시합니다. 10% 효율 손실은 단순한 'N/4' 공식을 통해 계산할 수있는 처리량의 90%만 가지고 있다는 것을 의미합니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지한 채로 이를 한국어로 번역하세요..
여기서의 전반적인 동작은 하드웨어가 어떠한 언롤링도 수행하지 않는다는 사실과 일관성이 있습니다. 이는 32개 이상의 uop으로 이루어진 루프는 64개의 uop 버퍼에서 전혀 언롤링될 수 없기 때문에 이해할 만합니다.
위에서 논의한 세 지역은 다른 색상으로 표시되어 있으며, 최소한 경쟁 효과가 볼 수 있습니다.
특수 기호를 그대로 유지하여 번역하면 됩니다.
모든 것이 동일한 경우, 참여하는 uop의 수가 클수록 효율성 손실이 적습니다. 손실은 반복마다 한 번의 고정된 비용만 발생하므로, 더 큰 루프는 상대적인 비용이 더 낮게 지불됩니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하며 이를 한국어로 번역하시오..
33+ uop 영역으로 이동할 때 효율성의 큰 저하가 발생합니다. 처리량 손실의 크기가 증가할 뿐만 아니라 영향을 받는 uop 개수도 두 배가 되는 것입니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하면서 한국어로 번역하십시오..
첫 번째 영역은 다소 혼돈스럽고, 7 uop는 전체 uop 개수 중에서 가장 나쁩니다.
정렬
DSB 및 LSD 분석은 루프 진입점이 32바이트 경계에 정렬된 경우를 대상으로 합니다. 그러나 정렬되지 않은 경우에도 어느 경우든 심각한 문제가 없는 것으로 보입니다: 정렬된 경우와 실질적으로 차이가 없습니다 (아마 제가 더 조사하지 않은 10개 미만의 uop에 대해 약간의 변동이 있을 수 있습니다).
당신은 컴퓨터 전문가입니다. 특수 기호를 유지한 상태로 한국어로 번역하세요..
'32N-2' 및 '32N+2' (즉, 32B 경계선 이전 및 이후의 상위 2바이트 반복)에 대한 정렬되지 않은 결과는 다음과 같습니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 유지한 채로 한국어로 번역해주세요.
이상적인 'N/4' 라인도 참고로 표시됩니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 유지하며 한국어로 번역하세요..
Haswell
당신은 컴퓨터 전문가입니다. 특수 기호를 유지하면서 번역해주세요.
다음으로 이전의 마이크로아키텍처인 Haswell을 살펴보겠습니다. 여기에 있는 숫자들은 사용자인 LNK2005: VC++에서 이미 정의된 삭제 오류가 친절하게 제공한 것입니다.
LSD + 레거시 디코드 파이프라인
컴퓨터 전문가입니다. 댄스 코드 테스트에서의 결과를 보고드립니다. 해당 테스트는 LSD(작은 uop 수에 대한)와 레거시 파이프라인(큰 uop 수에 대해서는 루프가 DSB를 벗어나지만, 인스트럭션 밀도 때문에 분해점을 생성합니다.)를 테스트합니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하면서 한국어로 번역하십시오..
밀도가 높은 루프에서 각 아키텍처가 LSD로부터 uop을 전달하는 시기에 이미 차이가 보입니다. 아래에서 우리는 스카이레이크와 해스웰을 각각 밀집한 코드 (명령어 당 1바이트)의 짧은 루프와 비교합니다.
위에서 설명한대로, Skylake 루프는 정확히 19 개의 uop까지 LSD에서 제공되며, 이는 코드 영역당 32 바이트 제한에서 예상되는 것입니다. 다른 한편으로, Haswell은 16-uop 및 17-uop 루프의 LSD 제공을 신뢰할 수 없게 중단하는 것으로 보입니다. 이에 대한 설명은 없습니다. 3-uop 케이스에서도 차이가 있습니다. 신기하게도 두 프로세서 모두 LSD에서 3 및 4 uop 케이스에서 일부만 uop을 제공하지만, 4 uop의 경우 정확한 양은 같고 3과는 다릅니다.
주로 실제 성능에 관심이 있죠, 맞나요? 그러니까 32바이트 아이레이닝된 댄스 코드 상황에서의 사이클/이터레이션을 살펴봅시다:
이것은 Skylake에 대한 위와 동일한 데이터이며 (불일치된 시리즈는 제거되었습니다), Haswell이 함께 플롯되었습니다. 즉시 알 수 있는 것은 Haswell의 패턴이 유사하지만 동일하지 않다는 것입니다. 위와 마찬가지로 여기에는 두 개의 지역이 있습니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 유지하면서 한국어로 번역해주세요.
레거시 디코드
당신은 컴퓨터 전문가입니다. 특수 기호 유지한 채로 한국어로 번역해주세요..
~16-18 uops보다 큰 루프(불확실성은 위에서 설명됨)는 유산 디코더로부터 전달됩니다. Haswell의 패턴은 Skylake와 다소 다릅니다.
19-30 개의 사용자 정의 명령어 범위에서는 규칙이 동일하지만 그 이후로는 Haswell에서 규칙이 깨집니다. Skylake는 레거시 디코더에서 전송된 루프에 대해 #$&@#!^$& 사이클을 사용합니다. 반면에 Haswell은 대략 'ceil((N+1)/4) + ceil((N+2)/12) - ceil((N+1)/12)' 와 같은 사이클을 사용하는 것으로 보입니다. 깔끔하지는 않지만 (간단히 말하자면?) 이는 Skylake가 4*N 사이클에 대해 최적으로 루프를 실행하는 것을 의미하며, 즉 4-uops/cycle로 실행됩니다. 하지만 이러한 루프는 (로컬)로는 일반적으로 가장 최적의 개수가 아닙니다 - Skylake보다 이러한 루프를 실행하는 데 한 사이클 더 소요됩니다. 따라서 Haswell에서는 실제로 4N-1 uops의 루프가 가장 좋지만, 16-1N (31, 47, 63 등) 형태인 해당 루프의 25%가 한 사이클 추가로 소요됩니다. 윤년 계산과 비슷하게 들리기 시작하지만, 패턴은 아마 위의 시각적으로 가장 잘 이해될 것입니다.
Haswell에서 uop 디스패치에 내재된 이 패턴은 아니라고 생각합니다. 그러니까 너무 많이 해석하지 말아야 합니다. 이 패턴은 아마 다음과 같이 설명될 수 있는 것 같습니다.
'0000000000455a80
16B cycle
1 1 455a80: ff c8 dec eax
1 1 455a82: 90 nop
1 1 455a83: 90 nop
1 1 455a84: 90 nop
1 2 455a85: 90 nop
1 2 455a86: 90 nop
1 2 455a87: 90 nop
1 2 455a88: 90 nop
1 3 455a89: 90 nop
1 3 455a8a: 90 nop
1 3 455a8b: 90 nop
1 3 455a8c: 90 nop
1 4 455a8d: 90 nop
1 4 455a8e: 90 nop
1 4 455a8f: 90 nop
2 5 455a90: 90 nop
2 5 455a91: 90 nop
2 5 455a92: 90 nop
2 5 455a93: 90 nop
2 6 455a94: 90 nop
2 6 455a95: 90 nop
2 6 455a96: 90 nop
2 6 455a97: 90 nop
2 7 455a98: 90 nop
2 7 455a99: 90 nop
2 7 455a9a: 90 nop
2 7 455a9b: 90 nop
2 8 455a9c: 90 nop
2 8 455a9d: 90 nop
2 8 455a9e: 90 nop
2 8 455a9f: 90 nop
3 9 455aa0: 90 nop
3 9 455aa1: 90 nop
3 9 455aa2: 90 nop
3 9 455aa3: 75 db jne 455a80
'
여기에는 각 명령이 나타나는 16B 디코드 청크 (1-3) 및 해당 사이클이 디코드될 때 기록하였습니다. 이 규칙은 현재 16B 청크 내에 속하는 경우 다음 4개의 명령까지 디코드되지만, 그렇지 않은 경우 다음 사이클까지 기다려야 한다는 것입니다. N=35에 대해, 4번째 사이클에서 1개의 디코드 슬롯 손실이 있는 것을 볼 수 있습니다 (16B 청크 내에는 3개의 명령만 남음), 그러나 그 외에는 루프가 16B 경계와 매우 잘 일치하며 마지막 사이클 (9)에서도 4개의 명령을 디코드할 수 있습니다.
여기에는 루프의 끝을 제외하고 동일한 N=36의 일부가 있습니다.
'0000000000455b20
16B cycle
1 1 455a80: ff c8 dec eax
1 1 455b20: ff c8 dec eax
1 1 455b22: 90 nop
... [29 lines omitted] ...
2 8 455b3f: 90 nop
3 9 455b40: 90 nop
3 9 455b41: 90 nop
3 9 455b42: 90 nop
3 9 455b43: 90 nop
3 10 455b44: 75 da jne 455b20
'
3 번째이자 마지막 16B 청크에서 해독해야 할 지시어는 이제 5 개가 있으므로 추가적인 주기가 필요합니다. 기본적으로 35 개의 지시어는 특정한 지시어 패턴에 대해 16B 비트 경계와 더 잘 일치하며 해독시 한 주기를 절약합니다. 이는 N = 35가 일반적으로 N = 36보다 더 좋다는 의미는 아닙니다! 다른 지시어는 다른 바이트 수를 갖고 다르게 일치할 것입니다. 유사한 정렬 문제로 인해 16 바이트마다 추가 주기가 필요한 것도 설명할 수 있습니다.
'16B cycle
...
2 7 45581b: 90 nop
2 8 45581c: 90 nop
2 8 45581d: 90 nop
2 8 45581e: 90 nop
3 8 45581f: 75 df jne 455800
'
여기에서 최종적인 'jne'은 다음 16B 청크로 미끄러지며 (만약 명령어가 16B 경계에 걸치면, 사실상 후자의 청크에 있다고 간주됩니다), 추가적인 사이클 손실이 발생합니다. 이는 매 16바이트마다만 발생합니다.
해스웰 유산 디코더 결과는 설명이 완벽하게 유산 디코더와 일치합니다. 예를 들어, Agner Fog의 'microarchitecture doc'와 같이 설명된 방식으로 동작하는 유산 디코더에 의해 완벽히 설명됩니다. 사실, 만약 스카이레이크가 1사이클당 5개의 명령을 디코딩할 수 있다고 가정한다면, 이 또한 스카이레이크 결과를 설명하는 것으로 보입니다 (최대 5개의 uop을 전달). 그렇다고 가정한다면, 스카이레이크에서의 유산 디코드 처리량의 점근적인 값은 여전히 4-uops입니다. 왜냐하면 스카이레이크에서 16개의 NOP 블록이 5-5-5-1로 디코드되는 것에 비해 해스웰에서는 4-4-4-4로 디코드되기 때문입니다. 따라서 이점은 가장자리에서만 얻을 수 있습니다. 예를 들어, 위의 N=36 경우에는 스카이레이크가 남은 5개의 명령을 모두 디코드할 수 있지만 해스웰에서는 4-1로 디코드하여 사이클을 절약할 수 있습니다.
요점은 유산 디코더 동작이 상당히 직관적으로 이해될 수 있다는 것으로 보인다는 점이고, 주된 최적화 조언은 코드를 스마트하게 16B에 정렬된 청크로 넣기 위해 계속해서 가공하도록 하는 것이다 (아마도 이것은 바구니 패킹과 같이 NP-하드일지도 모른다.).
당신은 컴퓨터 전문가 입니다. 특수 기호를 그대로 유지한 채로 한국어로 번역하십시오..
DSB (그리고 다시 LSD)
다음으로 우리는 코드가 LSD 또는 DSB에서 제공되는 시나리오를 살펴보겠습니다. long nop 테스트를 사용하여 18-uop 당 32B 청크 제한을 피하고 DSB에 남아있게하는 방법입니다.
하스웰 대 스카이레이크:
특수 기호를 그대로 유지하면서 한국어로 번역해보겠습니다.
LSD 동작에 유의하세요 - 여기에서 Haswell은 LSD의 공개된 크기인 57개의 uop에 정확히 맞춰 쓰여지는 것으로 나타납니다. Skylake에서 볼 수 있는 이상한 전환 기간은 없습니다. Haswell은 또한 3개와 4개의 uop에 대해 LSD에서 약 0%와 40%의 uop가 각각 가져오는 이상한 동작을 가지고 있습니다.
성능 측면에서 Haswell은 주로 Skylake와 일치하며 몇 가지 차이점이 있습니다. 예를 들어, 약 65, 77 및 97 개의 uops는 다음 사이클로 올림 처리되지만, Skylake는 사이클의 정수가 아닌 숫자로 결과가 발생하는 경우에도 항상 4 uops/cycle를 지속할 수 있습니다. 25 및 26 uops에서 예상과 약간 다른 편차가 사라졌습니다. 아마도 Skylake의 6-uop 전달 속도는 Haswell의 4-uop 전달 속도로 인한 uop-cache 정렬 문제를 피하는 데 도움이 되고 있을 것입니다.
다른 아키텍처
다음 추가 아키텍처에 대한 결과는 사용자 Andreas Abel이 친절히 제공했지만, 우리는 여기서 문자 제한으로 인해 추가 분석에 대해 다른 답을 사용해야 합니다.
도움 필요
커뮤니티에서는 많은 플랫폼에 대한 결과를 친절하게 제공해 주었지만, 여전히 Nehalem보다 오래된 칩 및 Coffee Lake보다 새로운 칩 (특히 새로운 마이크로아키텍처 인 Cannon Lake)에 대한 결과에 관심이 있습니다. 이러한 결과를 생성하기 위한 코드는 'is public' 입니다. 또한, 위의 결과는 'are available' 형식으로 GitHub에도 제공됩니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 유지하면서 한국어로 번역해주세요.
0 특히, 스카이레이크에서 유산 디코더의 최대 처리량은 4에서 5 uop로 증가했으며, uop 캐시의 최대 처리량도 4에서 6으로 증가했습니다. 이 두 가지 모두 이곳에서 설명된 결과에 영향을 줄 수 있습니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하며 한국어로 번역하세요..
1 인텔은 실제로 레거시 디코더를 MITE(Micro-instruction Translation Engine)라고 부르는 것을 좋아합니다. 아마도 아키텍처의 어떤 부분에도 '레거시'라는 의미를 명시적으로 표시하는 것은 실수로 여겨질 수 있기 때문일 것입니다.
2 기술적으로 또 다른 느린 uop 소스인 MS (마이크로코드 시퀀싱 엔진)가 있습니다. 이 엔진은 4개의 uop보다 많은 uop을 실행하는 모든 명령을 구현하는 데 사용되지만, 우리의 루프에는 마이크로코드 명령이 포함되어 있지 않으므로 여기에서는 무시합니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하여 번역하십시오..
3 이는 정렬된 32바이트 청크가 최대 3개의 UOP 캐시 슬롯을 사용할 수 있으며 각 슬롯은 최대 6개의 UOP을 보유할 수 있기 때문에 작동합니다. 따라서 32B 청크에서 #$ @ #&@#! $&는이 UOP 캐시에 코드를 저장할 수 없습니다. 이 조건을 실제로 마주칠 가능성은 거의 없을 것입니다. 코드가 매우 밀도가 있어야하며(명령당 2 바이트 미만), 이 조건을 트리거합니다.
당신은 컴퓨터 전문가입니다. 특수 기호를 그대로 유지하면서 한국어로 번역하십시오.
4 'nop' 명령은 하나의 uop로 디코드되지만 실행 전에 제거되지 않습니다 (즉, 실행 포트를 사용하지 않음) - 그러나 여전히 프론트 엔드에서 공간을 차지하므로 우리가 관심을 가지는 다양한 제한과 반대로 계산됩니다.
5 LSD는 루프 스트림 검출기로, 최대 64 (Skylake에서) 개의 작은 루프를 IDQ에 직접 캐시합니다. 이전 아키텍처에서는 28 개의 uop (두 개의 논리 코어 활성화) 또는 56 개의 uop (한 개의 논리 코어 활성화)를 보유할 수 있습니다.
당신은 컴퓨터 전문가입니다. 이 특수 기호를 그대로 유지하며 한국어로 번역해주세요..
6 이 패턴에 2개의 uop 루프를 쉽게 맞출 수 없습니다. 왜냐하면 그렇게 하면 zero 'nop'명령어를 의미하며, 이는 'dec' 그리고 'jnz' 명령어가 매크로 퓨즈되어 uop 카운트의 변화가 있을 것입니다. 단순히 말하자면 4개 이하의 uop으로 구성된 모든 루프는 한 번의 반복 동안 최대 1사이클에 실행됩니다.
컴퓨터 전문가입니다. 특수 기호를 유지한 채로 한국어로 번역해주세요..
7 재미로, 나는 막 Firefox를 실행해서 탭을 여러 개 열고 몇 개의 Stack Overflow 질문을 클릭해봤습니다. 전달된 명령에 대해 DSB에서 46%를 받았고, 레거시 디코더에서 50%를 받았으며, LSD에서는 4%를 받았습니다. 이는 최소한 브라우저와 같은 크고 가지가 많은 코드에 대해서는 DSB가 여전히 대부분의 코드를 포착하지 못한다는 것을 보여줍니다 (다행히 레거시 디코더는 그리 나쁘지 않습니다).
8 다른 사이클 수는 유효한 인티그럴 루프 비용을 uop으로 나눈 것으로 간단히 설명할 수 있으므로 (실제 uop 크기보다 높을 수도 있음), 여기에서는 이를 의미합니다. 이 매우 짧은 루프에서는 이 방법이 작동하지 않습니다 - 어떤 정수를 4로 나누어도 1.333 반복당 사이클에 도달할 수 없습니다. 다른 방식으로 말하면, 다른 모든 영역에서 비용은 어떤 정수 N에 대해 N/4 형태를 갖습니다.
9 실제로 우리는 Skylake가 기존 디코더로부터 한 사이클당 5개의 uop을 전달할 수 있다는 것을 알고 있습니다. 그러나 그 5개의 uop이 5개의 다른 명령어에서 오는지, 아니면 4개 이하인지는 알 수 없습니다. 즉, 우리는 Skylake가 패턴 '2-1-1-1' 를 디코드할 수 있다고 예상하지만, 패턴 '1-1-1-1-1' 를 디코드할 수 있는지는 확신할 수 없습니다. 위의 결과들은 그것이 실제로 '1-1-1-1-1' 를 디코드할 수 있다는 몇 가지 증거를 제시합니다.
답변 2
프로세서 폭의 배수가 아닌 루프를 실행할 때 성능이 감소됩니까?프로세서는 프로그램 루프를 실행할 때 여러 개의 마이크로 연산 단위(uop)를 동시에 처리합니다. 이때 프로세서의 폭은 한 번에 처리할 수 있는 uop 개수를 의미합니다. 프로세서의 폭은 보통 2의 지수인 2, 4, 8 등으로 결정되며, uop 개수가 폭의 배수가 아닐 경우 성능이 감소할 수 있습니다.
이러한 성능 저하는 여러 이유로 발생할 수 있습니다. 첫째, 폭의 배수가 아닌 루프를 실행할 때 프로세서는 루프에서 남은 명령어를 조각내어 병렬로 처리하기 위해 추가적인 논리 게이트와 제어 회로를 사용해야 합니다. 따라서 명령어 조각화 작업과 관련된 오버헤드가 발생하며, 이로 인해 전체적인 실행 시간이 증가합니다.
둘째, 폭의 배수가 아닌 루프를 실행할 때에는 프로세서가 일시적으로 공간적으로 이동하면서 명령어를 가져와야 합니다. 이로 인해 캐시 미스(Cache Miss)가 발생할 가능성이 높아집니다. 캐시는 프로세서의 성능을 향상시키기 위해 사용되는 메모리 계층 구조 중 하나입니다. 따라서 캐시 미스가 발생하면 메인 메모리로부터 데이터를 가져와야 하는데, 이 작업은 시간이 많이 소요됩니다. 결과적으로 루프 실행 시간이 증가하고 성능이 저하될 수 있습니다.
마지막으로, 프로그램 루프가 폭의 배수가 아닌 상태로 돌아갈 경우, 프로세서는 루프 반복을 위한 명령어를 가져올 때마다 남은 비어 있는 비트를 제거해야 합니다. 이는 명령어의 디코딩과 실행의 일부를 차지하는 추가 오버헤드로 이어지며, 전체적인 성능을 떨어뜨릴 수 있습니다.
종합적으로 폭의 배수가 아닌 루프를 실행할 경우, 프로세서는 유효하지 않은 명령어가 포함된 폭의 배수가 아닌 루프들에 대한 추가적인 조작을 수행해야 하므로 성능이 저하될 수 있습니다. 따라서 개발자는 프로그램 루프를 최적화할 때 폭의 배수를 고려하여 설계하는 것이 중요합니다. 성능 향상을 위해서는 폭의 배수에 맞게 루프를 변경하거나 벡터화 등의 최적화 기법을 적용하는 것이 필요합니다.
이에 따라, 프로세서 폭의 배수가 아닌 루프를 실행할 때 발생하는 성능 저하에 대해 설명했습니다. 폭의 배수를 고려하여 프로그램을 최적화하는 것이 중요하며, 이를 통해 성능을 향상시키는데 도움이 되리라 기대합니다.