루프 언롤링
Loop unrolling루프 언롤링(loop unrolling)은 또한 루프 언월딩(loop unwinding)이라고도 하며, 시공간 트레이드오프(tradeoff)라고 알려진 바이너리 크기를 희생하여 프로그램의 실행 속도를 최적화하려는 루프 변환 기법이다.변환은 프로그래머 또는 최적화 컴파일러에 의해 수동으로 수행될 수 있습니다.최신 프로세서에서는 코드 사이즈가 증가하면 캐시 누락이 증가할 수 있기 때문에 루프 언롤링은 종종 역효과를 가져옵니다.더프의 장치.[1]
루프 언와인딩의 목적은 포인터 산술과 각 [2]반복에 대한 "루프의 끝" 테스트와 같은 루프를 제어하는 명령을 줄이거나 제거함으로써 프로그램의 속도를 높이는 것입니다. 분기 패널티를 줄이고 메모리에서 [3]데이터를 읽는 지연을 포함한 지연을 숨기는 것입니다.이 계산 오버헤드를 제거하기 위해 루프는 유사한 독립 스테이트먼트의 [4]반복 시퀀스로 다시 쓸 수 있습니다.
루프 언롤링은 특정 형식 검증 기법, 특히 경계 모델 확인의 [5]일부이기도 합니다.
이점
"엄격한" 루프의 오버헤드는 종종 "루프의 끝" 테스트뿐만 아니라 배열의 다음 요소에 대한 포인터 또는 인덱스를 증가시키는 명령으로 구성됩니다.최적화 컴파일러 또는 어셈블러가 개별적으로 참조되는 각 배열 변수에 대해 오프셋을 미리 계산할 수 있는 경우, 이들은 머신 코드 명령에 직접 내장될 수 있으며, 따라서 런타임에 추가적인 산술 연산이 필요하지 않습니다.
- 실행 명령의 감소가 프로그램 크기의 증가로 인한 성능 저하를 보상하면 상당한 이득을 얻을 수 있습니다.
- 브랜치 패널티가 [6]최소화됩니다.
- 루프 내의 스테이트먼트가 서로 독립되어 있는 경우(즉, 루프 내에서 이전에 발생한 스테이트먼트가 그 뒤에 이어지는 스테이트먼트에 영향을 주지 않는 경우), 스테이트먼트는 잠재적으로 병렬로 실행될 수 있습니다.
- 컴파일 시에 어레이 요소의 수를 알 수 없는 경우(Duff의 디바이스와 같이) 동적으로 구현할 수 있습니다.
컴파일러를 최적화하면 자동으로 또는 요청에 따라 언롤이 수행될 수 있습니다.
단점들
- 프로그램 코드 크기 증가(특히 임베디드 애플리케이션에서는 바람직하지 않을 수 있음)또한 명령 캐시 누락이 증가하여 성능에 악영향을 미칠 수 있습니다.
- 최적화 컴파일러에 의해 투과적으로 실행되지 않는 한 코드는 읽기 어려워질 수 있습니다.
- 루프 본체의 코드가 함수 호출을 수반하는 경우 코드 사이즈의 증가가 과도할 수 있기 때문에 언롤링과 인라인링을 조합할 수 없을 수 있습니다.따라서 두 최적화 사이에 트레이드오프가 있을 수 있습니다.
- 임시 변수를[dubious ] 저장하기 위해 단일 반복으로 레지스터 사용량이 증가할 수 있으며, 이로 인해 성능이 저하될 수 있습니다. 단,[7] 대부분의 경우 가능한 최적화에 따라 달라집니다.
- 매우 작고 단순한 코드를 제외하고 브랜치를 포함하는 롤되지 않은 루프는 [8]재귀보다 더 느립니다.
정적/수동 루프 풀림
수동(또는 정적) 루프 언롤링은 프로그래머가 루프를 분석하고 반복을 일련의 명령으로 해석하여 루프 오버헤드를 줄입니다.이는 컴파일러에 의해 실행되는 동적 언롤링과는 대조적입니다.
C의 간단한 매뉴얼 예시
컴퓨터 프로그램의 절차는 컬렉션에서 100개의 항목을 삭제하는 것입니다.이것은 통상, 다음의 방법으로 행해집니다.for
- 루프 - delete(item_number) 함수를 호출합니다.프로그램의 이 부분이 최적화되어 루프의 오버헤드가 delete(x) 함수에 비해 상당한 자원을 필요로 하는 경우, 언와인딩은 이를 고속화하기 위해 사용될 수 있다.
노멀 루프 | 루프 언롤링 후 |
---|---|
인트 x; 위해서 (x = 0; x < > 100; x++) { 삭제하다(x); } | 인트 x; 위해서 (x = 0; x < > 100; x += 5 ) { 삭제하다(x); 삭제하다(x + 1); 삭제하다(x + 2); 삭제하다(x + 3); 삭제하다(x + 4); } |
이 변경으로 인해 새 프로그램은 100회 반복이 아닌 20회만 반복하면 됩니다.그 후 점프와 조건부 브랜치 중 20%만 수행하면 되며, 이는 여러 번의 반복에 걸쳐 루프 관리 오버헤드가 현저하게 감소할 수 있음을 나타냅니다.최적의 이점을 얻으려면 포인터 산술이 필요한 변수를 언롤 코드에 지정해야 합니다.여기에는 일반적으로 인덱스 참조가 아닌 "기본값 + 오프셋" 주소 지정이 필요합니다.
한편, 이 수동 루프 언롤링은 소스 코드 크기를 3줄에서7줄로 확장하여 생성, 체크 및 디버깅을 해야 합니다.또한 컴파일러는 확장된 루프[dubious ] 반복에서 변수를 저장하기 위해 더 많은 레지스터를 할당해야 할 수도 있습니다.또, 루프 제어 변수와 언롤 루프 구조내의 동작의 수를 신중하게 선택해, 원래의 코드와 같은 결과를 얻을 필요가 있습니다(이것은 이미 동작하고 있는 코드에 대한 후의 최적화인 것을 전제로 합니다.예를 들어 반복 횟수가 5로 나누어지지 않은 경우의 영향을 고려합니다.시험 조건이 변수인 경우 필요한 수동 수정도 다소 복잡해진다.Duff의 디바이스도 참조해 주세요.
초기 복잡성
단순한 경우 루프 제어는 생산적인 스테이트먼트를 배치하는 관리상의 오버헤드일 뿐입니다.루프 자체는 원하는 결과에는 아무런 도움이 되지 않으며, 단순히 프로그래머가 리플리케이션을 생성하는 프리프로세서 또는 텍스트에디터에 의해 이루어졌을 수 있는 코드를 백 번 복제하는 번거로움을 덜어줍니다.유사하게,if
-스테이트먼트 및 기타 흐름 제어문은 코드 복제로 대체될 수 있습니다.단, 코드 블러트는 그 결과일 수 있습니다.컴퓨터 프로그램은 그 조합을 쉽게 추적하지만 프로그래머들은 이 반복이 지루하고 실수를 한다.고려사항:
노멀 루프 | 루프 언롤링 후 |
---|---|
i : = 1:8은 i mod 2 = 0이면 do_even_stuff(i) 그렇지 않으면 do_odd_stuff(i); 다음 i; | do_odd_stuff(1); do_even_stuff(2); do_odd_stuff(3); d_even_stuff(4); do_od_stuff(5); do_od_stuff(7); do_even_stuff(8); |
단, 물론 실행되는 코드가 프로시저의 호출일 필요는 없으며 다음 예에서는 계산 시 인덱스 변수를 포함합니다.
노멀 루프 | 루프 언롤링 후 |
---|---|
x(1) := 1, i := 2:9 do x(i) := x(i - 1) * i, 인쇄 i, x(i); 다음 i; | x(1) := 1, x(2) := x(1) * 2, x(2), x(3) := x(2) * 3, x(3), x(4) := x(3) * 4, x(4) := x(3) * 4, x(4) 등입니다. |
컴파일되면 많은 코드가 생성될 수 있지만(인쇄문은 악명 높다) 추가적인 최적화가 가능합니다.이 예에서는 루프 내의 x(i)와 x(i - 1)만을 참조하고 있습니다(후자는 새로운 값 x(i)를 개발하기 위해서만 참조합니다).따라서 여기서 개발된 배열 x에 대한 이후 참조가 없기 때문에 그 용도는 단순한 변수로 대체될 수 있습니다.그러나 이러한 변화는 값이 변경되는 단순한 변수를 의미할 수 있습니다. 반면, 배열과 함께 있는 경우, 컴파일러의 분석은 배열의 값이 각각 이전 상수에서 파생된 상수이며, 따라서 코드가 다음과 같이 전달되도록 상수 값을 전달할 수 있습니다.
2, 2, 3, 6, 4, 24, ...등을 인쇄합니다.
일반적으로 루프의 내용은 복잡한 어레이 인덱싱을 수반하는 대규모일 수 있습니다.이러한 경우는 컴파일러의 최적화를 통해 전개하는 것이 좋습니다.가장 안쪽 루프를 반복하면 많은 가능한 최적화가 가능하지만 n이 크지 않은 한 작은 이득만 얻을 수 있다.
WHIN 루프 해제 중
다음과 같은 의사 코드 WHY 루프를 검토합니다.
노멀 루프 | 루프 언롤링 후 | 언롤링 및 "트위칭" 루프 |
---|---|---|
WHILE (조건) 작업을 수행합니다.ENDWHILE . . . . . . | (조건) 동작 중 (조건) 동작 중 (조건) 동작 후 (조건) 동작 중 (조건) 동작 후 라벨 브레이크 동작 종료: | 만약 (조건)이 아니라면 액션을 반복하고, 그렇지 않다면 (조건) goto break 액션을 반복하고, 그렇지 않으면 goto break 액션을 실행하며, 라벨은 (조건) break 합니다. |
이 경우 ENDWHILE(루프 시작까지의 점프)가 66% 적게 실행되므로 언롤링이 더 빠릅니다.
더 좋은 것은 일부 최적화 컴파일러에 의해 자동으로 실행되어 무조건적인 점프를 완전히 제거하는 "트위킹" 의사 코드 예제입니다.
동적 언롤링
루프 롤링의 이점은 어레이의 크기에 따라 달라지는 경우가 많기 때문에 (실행 시간까지 알 수 없는 경우가 많습니다)JIT 컴파일러(예를 들어)는 "표준" 루프 시퀀스를 호출할지, 각 요소에 대해 (상대적으로 짧은) 개별 명령 시퀀스를 생성할지를 결정할 수 있습니다.이 유연성은 저스트 인 타임(just-in-time) 기법의 장점 중 하나입니다.루프 언롤링의 경우 정적 또는 수동 최적화에 비해 우수합니다.이 상황에서는 절약이 여전히 유용한 경우 n의 비교적 작은 값을 사용하는 경우가 많습니다.이는 프로그램사이즈의 전체적인 증가(있는 경우)를 필요로 합니다(표준 라이브러리의 일부로서1회만 포함할 수 있습니다).
어셈블리 언어 프로그래머(컴파일러 라이터의 최적화를 포함한다)도 효율적인 분기 테이블에 사용되는 것과 유사한 방법을 사용하여 동적 루프 롤링의 기술로부터 이익을 얻을 수 있습니다.여기서 이 이점은 특정 배열에서 참조되는 필드의 최대 오프셋이 기계 명령으로 지정할 수 있는 최대 오프셋보다 작을 때(초과 시 어셈블러에 의해 플래그가 지정됨) 가장 큽니다.
어셈블러의 예(IBM/360 또는 Z/아키텍처)
이 예는 IBM/360 또는 Z/Architecture 어셈블러를 대상으로 하며, 100바이트의 필드(오프셋0의 경우)를 어레이 FROM에서 어레이 TO로 복사하는 것으로 가정합니다.둘 다 요소 길이가 256바이트인 50개의 엔트리가 있습니다.
* 반송 주소는 R14 입니다. * 레지스터 R15, R0, R1 및 R2의 말미에 정의된 데이터에서 초기화* 라벨 INIT/MAXM1로 시작하는 프로그램.LM R15, R2,INIT Set R15 = MVC의 최대 수* 지침(MAXM1 = 16),* R0 = 어레이의 엔트리 수* R1 = 'FROM' 배열의 주소 및* R2 = 'TO' 배열의 주소입니다. ** 여기서부터 루프가 시작됩니다. LOUP EQU * LOUP 라벨을 정의합니다. * 이 시점에서 R15는 항상 숫자 16(MAXM1)을 포함합니다. SR R15,R0 나머지 수를 뺀 값* R15부터 어레이(R0)에 엔트리를 입력합니다. BNP ALL R15가 양수가 아닌 경우, 즉,* 16개 이상의 엔트리가 남아 있습니다.* 어레이에서 전체 작업 수행* MVC 시퀀스 후 반복합니다. ** 무조건 브랜치의 오프셋(MVC 시퀀스 시작부터)을 계산합니다.* 아래의 '감지 해제' MVC 루프. * 어레이 내의 나머지 엔트리의 수가 0일 경우 R15는 16이 됩니다.* 모든 MVC 명령은 바이패스됩니다. MH R15,=AL2(ILEN) R15에 길이 1을 곱합니다.* MVC 설명 B ALL(R15) ALL+R15로 점프하여* 계산된 특정 MVC 명령* 나머지 분들에게 전해주세요. ** MVC 명령 '표' * 첫 번째 엔트리의 최대 허용 오프셋은 단일 레지스터 = 16진수 F00입니다.* (15*256) 입니다. * 다음 MVC('문자 이동') 명령 16개 모두 베이스 플러스 오프셋을 사용합니다.* 어드레싱과 각 어드레싱 오프셋은 1개의 어레이 요소의 길이만큼 감소합니다.* (256).이것에 의해, 각 요소에 대해서 포인터 산술이 필요 없게 됩니다.* 16진수 FFF 명령 내 최대 허용 오프셋* (15*256+255).명령어는 오프셋을 줄이는 순서로 되어 있기 때문에 마지막은* 세트의 요소가 먼저 이동됩니다. 모든 MVC 15*256(100,R2),15*256(R1) 16번째 엔트리의 100바이트 이동처* 어레이 1에서 어레이 2 (포함)* 드롭 스루). ILEN EQU *-ALL ILEN을 이전 길이로 설정합니다.* MVC 설명 MVC 14*256(100,R2),14*256(R1) 15번째 엔트리의 100바이트를 이동합니다. MVC 13*256(100,R2),13*256(R1) 14번째 엔트리의 100바이트를 이동합니다. MVC 12*256(100,R2),12*256(R1) 13번째 엔트리의 100바이트를 이동합니다. MVC 11*256(100,R2),11*256(R1) 12번째 엔트리의 100바이트를 이동합니다. MVC 10*256(100,R2), 10*256(R1) 11번째 엔트리의 100바이트를 이동합니다. MVC 09*256(100,R2),09*256(R1) 10번째 엔트리의 100바이트를 이동합니다. MVC 08*256(100,R2),08*256(R1) 9번째 엔트리의 100바이트를 이동합니다. MVC 07*256(100,R2),07*256(R1) 8번째 엔트리의 100바이트를 이동합니다. MVC 06*256(100,R2),06*256(R1) 7번째 엔트리의 100바이트를 이동합니다. MVC 05*256(100,R2),05*256(R1) 6번째 엔트리의 100바이트를 이동합니다. MVC 04*256(100,R2),04*256(R1) 5번째 엔트리의 100바이트를 이동합니다. MVC 03*256(100,R2),03*256(R1) 4번째 엔트리의 100바이트를 이동합니다. MVC 02*256(100,R2),02*256(R1) 세 번째 엔트리의 100바이트를 이동합니다. MVC 01*256(100,R2),01*256(R1) 두 번째 엔트리의 100바이트를 이동합니다. MVC 00*256(100,R2),00*256(R1) 첫 번째 엔트리의 100바이트를 이동합니다. *S R0,MAXM1 나머지 엔트리 수 감소* 처리하겠습니다. BNPR R14 처리할 엔트리가 더 이상 없는 경우 반환* R14에 기재되어 있습니다. AH R1,=AL2(16*256) 'FROM' 어레이 포인터 증가* 첫 번째 세트입니다. AH R2,=AL2(16*256) 증분'TO' 배열 포인터 초과* 첫 번째 세트입니다. L R15,MAXM1 MVC의 최대 수 새로고침* R15에 대한 배치별 명령* (의 계산에 의해 계산됩니다)* 루프의 첫 번째 명령). B LOUP 이그제큐트 루프를 다시 실행합니다. ** 정적 상수 및 변수(이것들은 매개 변수로 전달될 수 있습니다. 단,* MAXM1) INIT DS 0A 4개의 주소(포인트)는* 'LM' 명령이 프리 로드되어 있습니다.* 프로그램 시작 부분에 있습니다. MAXM1 DC A(16) MVC 명령의 최대 수* 배치당 실행 수 N DC A(50) 어레이 내의 실제 엔트리 수(a)* 변수, 다른 곳에 설정). 어레이 1의 DC A(FROM) 시작 주소* ("구체적") 직류 A(클로즈 가)주소 배열 2의 시작.*("포인터"). **정적 배열(이들 한계를 동적으로 얻어질 수 있). 256바이트 각각 50항목의 DS50CL256 정열은 FROM. 50항목 256바이트 각각 DS50CL256 정열은 해요.
반면에 위의 동적 코드만 약 89지침(약 56%나 절약)이 필요할 것이다 이 예에서는, 대략 202호 명령은"전통적인"루프(50반복)로, 요구될 것이다.배열만 둘로 구성되어 있었지만 그것은 여전히 원본 감겨 있지 않은 루프로 대략 같은 시간에 실행할 것이다.번호 크기의 증가율은 겨우 약 108바이트 –으면 배열의 항목이 몇 천 있다.
다수의 지침서가 결합된 명령어 길이 그에 따라 조정된 연관되어 있다 유사한 기법이 물론 사용될 수 있다.예를 들어, 이 같은 예에서, 만약 직후 100바이트 필드 추가적인 명확한 instruction,를 모방했고 nulls에 각각의 배열 항목의 나머지가 필요 있다.XC xx*256+100(156,R1),xx*256+100(R2)
시퀀스 내의 모든 MVC 뒤에 바로 추가할 수 있습니다(여기서xx
위의 MVC 값과 일치합니다).
물론 단일 어셈블러 매크로 문을 사용하여 위의 코드 "인라인"을 생성하는 것은 완벽하게 가능하며, 4~5개의 오퍼랜드(또는 라이브러리 서브루틴으로 만들어 단순한 호출로 액세스하고 파라미터 목록을 전달)를 지정함으로써 최적화에 쉽게 접근할 수 있습니다.
C의 예
다음 예시는 C로 기술된 단순한 프로그램의 다이내믹루프 롤링을 나타내고 있습니다.위의 어셈블러 예시와 달리 포인터/인덱스 산술은 변수(i)가 어레이 요소를 어드레싱하기 위해 여전히 사용되기 때문에 이 예시에서 컴파일러에 의해 생성됩니다.완전한 최적화는 대체 문장에서 절대 인덱스를 사용하는 경우에만 가능합니다.
#실패하다 <stdio.h> /* 루프 반복마다 처리되는 엔트리의 수.*/ /* 이 숫자는 아래 코드를 반영하는 '상수'입니다.*/ #정의 번치 사이즈 (8) 인트 주된(무효) { 인트 i = 0; /* 카운터 */ 인트 엔트리 = 50; /* 처리할 총 수 */ 인트 따라하다; /* while 반복 횟수*/ 인트 왼쪽 = 0; /* 잔량(나중에 처리) */ /* 요소의 수를 BUNTCHSIZE로 나눌 수 없는 경우 */ /* while loop에서 대부분의 처리를 수행하는 데 필요한 반복 시간을 얻을 수 있습니다.* 따라하다 = (엔트리 / 번치 사이즈); /* 반복 횟수 */ 왼쪽 = (엔트리 % 번치 사이즈); /* 나머지 계산 */ /* 루프를 8개의 '번치'로 펼칩니다*/ 하는 동안에 (따라하다--) { 인쇄물("프로세스(%d)\n", i ); 인쇄물("프로세스(%d)\n", i + 1); 인쇄물("프로세스(%d)\n", i + 2); 인쇄물("프로세스(%d)\n", i + 3); 인쇄물("프로세스(%d)\n", i + 4); 인쇄물("프로세스(%d)\n", i + 5); 인쇄물("프로세스(%d)\n", i + 6); 인쇄물("프로세스(%d)\n", i + 7); /* 한 번에 처리된 금액에 따라 인덱스를 갱신합니다 */ i += 번치 사이즈; } /* switch 문을 사용하여 케이스 라벨로 이동하여 나머지 처리를 수행합니다.* / /* 라벨에 기재되어 있습니다.이 라벨은 드롭되어 세트를 완성합니다. 전환하다 (왼쪽) { 사례. 7 : 인쇄물("프로세스(%d)\n", i + 6); /* 프로세스 및 드롭에 의존 */를 통해 사례. 6 : 인쇄물("프로세스(%d)\n", i + 5); 사례. 5 : 인쇄물("프로세스(%d)\n", i + 4); 사례. 4 : 인쇄물("프로세스(%d)\n", i + 3); 사례. 3 : 인쇄물("프로세스(%d)\n", i + 2); 사례. 2 : 인쇄물("프로세스(%d)\n", i + 1); /* 두 개 왼쪽 */ 사례. 1 : 인쇄물("프로세스(%d)\n", i); /* 이제1개만 처리해주세요*/ 사례. 0 : ; /* 남은 건 없어 */ } }
코드 중복은 Duff의 장치와 같이 두 부분을 함께 쓰는 것으로 피할 수 있었다.
C to MIPS 어셈블리 언어 루프 롤링[9] 예시
다음 예제에서는 두 종류의 100 엔트리 벡터 A와 B의 도트 곱을 계산합니다.double
C의 코드는 다음과 같습니다.
이중으로 하다 닷 제품 = 0; 위해서 (인트 i = 0; i < > 100; i++) { 닷 제품 += A[i]*B[i]; }
MIPS 어셈블리 언어로 변환
다음으로 루프 언롤링을 구현하기 전에 100 엔트리 벡터 A와 B의 닷 곱을 계산하는 MIPS 어셈블리 코드를 나타냅니다.다음 코드에서는 루프 초기화가 생략됩니다.
- 루프 카운트($7)를 100으로 초기화합니다.
- 도트 제품($f10)을 0으로 초기화합니다.
- 초기화
A[i]
기본 주소로 포인터 ($5)A
. - 초기화
B[i]
포인터 ($6)의 베이스 주소B
.
어레이의 1개 요소의 크기(a)에 주의해 주세요.double
)는 8바이트입니다.
loop3: 신원 확인 f10달러, 0($5) ; $f10 ← A[i] 신원 확인 f12달러, 0($6) ; $f12 ← B[i] 멀티 f10달러, f10달러, f12달러 ; $f10 ← A[i]*B[i] add. f8달러, f8달러, f10달러 ; $f8 ← $f8 + A[i]*B[i] 추가 $5, $5, 8 ; A[i]의 포인터를 크기만큼 증가시킵니다. ; 2루타. 추가 $6, $6, 8 ; B[i]의 포인터를 크기만큼 증가시킵니다. ; 2루타. 추가 $7, $7, -1 ; 감소 루프 수 테스트: bgtz $7, 루프 3 ; 루프 카운트가 0을 넘으면 속행합니다.
MIPS에서의 루프 언롤
다음은 위와 동일하지만 루프 언롤링이 4배수로 구현되어 있습니다.어레이의 1개 요소의 크기(a)에 주의해 주십시오.double
)는 8바이트입니다.따라서 각 루프에서 0, 8, 16, 24의 치환과 32의 치환입니다.
loop3: 신원 확인 f10달러, 0($5) ; 변위 0을 사용하여 반복한다. 신원 확인 f12달러, 0($6) 멀티 f10달러, f10달러, f12달러 add. f8달러, f8달러, f10달러 신원 확인 f10달러, 8($5) ; 치환 8을 사용하여 반복한다. 신원 확인 f12달러, 8($6) 멀티 f10달러, f10달러, f12달러 add. f8달러, f8달러, f10달러 신원 확인 f10달러, 16($5) ; 치환으로 반복 16 신원 확인 f12달러, 16($6) 멀티 f10달러, f10달러, f12달러 add. f8달러, f8달러, f10달러 신원 확인 f10달러, 24($5) ; 치환으로 반복 24 신원 확인 f12달러, 24($6) 멀티 f10달러, f10달러, f12달러 add. f8달러, f8달러, f10달러 추가 $5, $5, 32 추가 $6, $6, 32 추가 $7, $7, -4 테스트: bgtz $7, 루프 3 ; $7 > 0인 경우 루프를 계속합니다.
「 」를 참조해 주세요.
레퍼런스
- ^ Tso, Ted (August 22, 2000). "Re: [PATCH] Re: Move of input drivers, some word needed from you". lkml.indiana.edu. Linux kernel mailing list. Retrieved August 22, 2014.
Jim Gettys has a wonderful explanation of this effect in the X server. It turns out that with branch predictions and the relative speed of CPU vs. memory changing over the past decade, loop unrolling is pretty much pointless. In fact, by eliminating all instances of Duff's Device from the XFree86 4.0 server, the server shrunk in size by _half_ _a_ _megabyte_ (!!!), and was faster to boot, because the elimination of all that excess code meant that the X server wasn't thrashing the cache lines as much.
- ^ Ullman, Jeffrey D.; Aho, Alfred V. (1977). Principles of compiler design. Reading, Mass: Addison-Wesley Pub. Co. pp. 471–2. ISBN 0-201-10073-8.
- ^ Petersen, W.P., Arbenz, P. (2004). Introduction to Parallel Computing. Oxford University Press. p. 10.
{{cite book}}
: CS1 maint: 여러 이름: 작성자 목록(링크) - ^ Nicolau, Alexandru (1985). "Loop Quantization: Unwinding for Fine-Grain Parallelism Exploitation". Dept. of Computer Science Technical Report. Ithaca, NY: Cornell University. OCLC 14638257.
{{cite journal}}
:Cite 저널 요구 사항journal=
(도움말) - ^ SMT를 사용한 모델 확인 및 목록 이론
- ^ Fog, Agner (2012-02-29). "Optimizing subroutines in assembly language" (PDF). Copenhagen University College of Engineering. p. 100. Retrieved 2012-09-22.
12.11 Loop unrolling
- ^ Sarkar, Vivek (2001). "Optimized Unrolling of Nested Loops". International Journal of Parallel Programming. 29 (5): 545–581. doi:10.1023/A:1012246031671. S2CID 3353104.
- ^ Adam Horvath "코드 풀림 - 성능 향상"
- ^ "Loop Unrolling". University of Minnesota.
추가 정보
- Kennedy, Ken; Allen, Randy (2001). Optimizing Compilers for Modern Architectures: A Dependence-based Approach. Morgan Kaufmann. ISBN 1-55860-286-0.