restrict 키워드는 gcc/g++에 큰 이점이 있습니까?
C/C++ 의 을 본 ?restrict
향상됩니다.gcc/g++는 현실에서 큰 으로 향상됩니다.
그 사용을 추천/비하하는 다양한 기사를 읽었지만, 실제로 어느 쪽의 주장을 입증하는 실제 숫자는 발견하지 못했습니다.
편집
는 그것을 있다.restrict
공식적으로는 C++의 일부가 아니지만 일부 컴파일러에 의해 지원되고 있으며 Christer Ericson의 논문을 읽고 그 사용을 강력히 권장하고 있습니다.
restrict 키워드를 지정하면 달라집니다.
몇 가지 상황(이미지 처리)에서 팩터 2 이상의 개선을 볼 수 있었습니다.하지만 대부분의 경우 그 차이는 크지 않다.10% 정도.
다음은 그 차이를 보여주는 작은 예입니다.테스트로서 매우 기본적인 4x4 벡터 * 행렬 변환을 작성했습니다.함수가 인라인화되지 않도록 강제해야 합니다.그렇지 않으면 GCC는 벤치마크코드에 에일리어스 포인터가 없는 것을 검출하고 인라이닝으로 인해 제한이 영향을 주지 않습니다.
변환 기능을 다른 파일로 옮길 수도 있었습니다.
#include <math.h>
#ifdef USE_RESTRICT
#else
#define __restrict
#endif
void transform (float * __restrict dest, float * __restrict src,
float * __restrict matrix, int n) __attribute__ ((noinline));
void transform (float * __restrict dest, float * __restrict src,
float * __restrict matrix, int n)
{
int i;
// simple transform loop.
// written with aliasing in mind. dest, src and matrix
// are potentially aliasing, so the compiler is forced to reload
// the values of matrix and src for each iteration.
for (i=0; i<n; i++)
{
dest[0] = src[0] * matrix[0] + src[1] * matrix[1] +
src[2] * matrix[2] + src[3] * matrix[3];
dest[1] = src[0] * matrix[4] + src[1] * matrix[5] +
src[2] * matrix[6] + src[3] * matrix[7];
dest[2] = src[0] * matrix[8] + src[1] * matrix[9] +
src[2] * matrix[10] + src[3] * matrix[11];
dest[3] = src[0] * matrix[12] + src[1] * matrix[13] +
src[2] * matrix[14] + src[3] * matrix[15];
src += 4;
dest += 4;
}
}
float srcdata[4*10000];
float dstdata[4*10000];
int main (int argc, char**args)
{
int i,j;
float matrix[16];
// init all source-data, so we don't get NANs
for (i=0; i<16; i++) matrix[i] = 1;
for (i=0; i<4*10000; i++) srcdata[i] = i;
// do a bunch of tests for benchmarking.
for (j=0; j<10000; j++)
transform (dstdata, srcdata, matrix, 10000);
}
결과: (2 Ghz Core Duo에서)
nils@doofnase:~$ gcc -O3 test.c
nils@doofnase:~$ time ./a.out
real 0m2.517s
user 0m2.516s
sys 0m0.004s
nils@doofnase:~$ gcc -O3 -DUSE_RESTRICT test.c
nils@doofnase:~$ time ./a.out
real 0m2.034s
user 0m2.028s
sys 0m0.000s
그 시스템에서 실행 속도가 20% 이상 향상되었습니다.
같은 코드를 Cortex-A8 내장 CPU에서 실행하도록 한 아키텍처에 따라 얼마나 달라지는지를 나타내기 위해 (그렇게 오래 기다리지 않기 때문에 루프 카운트를 약간 조정했습니다)
root@beagleboard:~# gcc -O3 -mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp test.c
root@beagleboard:~# time ./a.out
real 0m 7.64s
user 0m 7.62s
sys 0m 0.00s
root@beagleboard:~# gcc -O3 -mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp -DUSE_RESTRICT test.c
root@beagleboard:~# time ./a.out
real 0m 7.00s
user 0m 6.98s
sys 0m 0.00s
이 경우 차이는 9%에 불과합니다(동일한 컴파일러 btw).
restrict 키워드는 gcc/g++에서 큰 이점을 제공합니까?
아래 예시와 같이 명령의 수를 줄일 수 있으므로 가능하면 사용하십시오.
GCC 4.8 Linux x86-64 예시
입력:
void f(int *a, int *b, int *x) {
*a += *x;
*b += *x;
}
void fr(int *restrict a, int *restrict b, int *restrict x) {
*a += *x;
*b += *x;
}
컴파일 및 디컴파일:
gcc -g -std=c99 -O0 -c main.c
objdump -S main.o
★★★★★★★★★★★★★★★★ -O0
똑같아요.
★★★★★★★★★★★★★★★★ -O3
:
void f(int *a, int *b, int *x) {
*a += *x;
0: 8b 02 mov (%rdx),%eax
2: 01 07 add %eax,(%rdi)
*b += *x;
4: 8b 02 mov (%rdx),%eax
6: 01 06 add %eax,(%rsi)
void fr(int *restrict a, int *restrict b, int *restrict x) {
*a += *x;
10: 8b 02 mov (%rdx),%eax
12: 01 07 add %eax,(%rdi)
*b += *x;
14: 01 06 add %eax,(%rsi)
미개시의 경우, 발신자 규약은 다음과 같습니다.
rdi
= parameter = 첫 번째 파라미터rsi
= parameter = 세컨드 파라미터rdx
= 번째 파라미터 = 세 번째 파라미터
결론: 4가 아닌 3의 지시입니다.
물론 명령어마다 지연 시간이 다를 수 있지만, 이것이 좋은 생각이 됩니다.
왜 GCC가 그것을 최적화할 수 있었을까?
위 코드는 위키피디아의 예에서 따온 것으로 매우 밝습니다.
의 유사 어셈블리f
:
load R1 ← *x ; Load the value of x pointer
load R2 ← *a ; Load the value of a pointer
add R2 += R1 ; Perform Addition
set R2 → *a ; Update the value of a pointer
; Similarly for b, note that x is loaded twice,
; because x may point to a (a aliased by x) thus
; the value of x will change when the value of a
; changes.
load R1 ← *x
load R2 ← *b
add R2 += R1
set R2 → *b
위해서fr
:
load R1 ← *x
load R2 ← *a
add R2 += R1
set R2 → *a
; Note that x is not reloaded,
; because the compiler knows it is unchanged
; "load R1 ← *x" is no longer needed.
load R2 ← *b
add R2 += R1
set R2 → *b
정말 더 빠를까?
음...이 간단한 테스트에는 해당되지 않습니다.
.text
.global _start
_start:
mov $0x10000000, %rbx
mov $x, %rdx
mov $x, %rdi
mov $x, %rsi
loop:
# START of interesting block
mov (%rdx),%eax
add %eax,(%rdi)
mov (%rdx),%eax # Comment out this line.
add %eax,(%rsi)
# END ------------------------
dec %rbx
cmp $0, %rbx
jnz loop
mov $60, %rax
mov $0, %rdi
syscall
.data
x:
.int 0
그 후:
as -o a.o a.S && ld a.o && time ./a.out
Ubuntu 14.04 AMD64 CPU 인텔 i5-3210M 탑재.
나는 아직도 최신 CPU를 이해하지 못한다는 것을 인정한다.다음과 같은 경우 알려 주십시오.
- 내 방법의 결함을 발견했다
- 훨씬 더 빨라진 조립자 테스트 케이스를 발견했다.
- 왜 차이가 없었는지 이해한다
Demystifying The Restrict Keyword(제한 키워드 해제)는 프로그래머 지정 앨리어싱이 나쁜 생각인 이유(pdf)를 참조하고 있습니다.이 문서는 일반적으로 도움이 되지 않으며 이를 뒷받침하는 측정값을 제공합니다.
C++ 컴파일러를 사용하면restrict
키워드로도 무시될 수 있습니다.예를 들어 여기의 경우입니다.
저는 이 C-Program을 테스트했습니다.없이.restrict
완료하는데 12.120초가 걸렸습니다.restrict
12.516.시간을 절약할 수 있을 것 같네요.
언급URL : https://stackoverflow.com/questions/1965487/does-the-restrict-keyword-provide-significant-benefits-in-gcc-g
'source' 카테고리의 다른 글
C : typedef 구조명 {...}; VS typedef 구조{...} 이름 (0) | 2022.08.27 |
---|---|
확장 C 매크로 표시 (0) | 2022.08.27 |
불명확한 에러가 내 컴포넌트 이름이 0으로 시작된다고 한다. (0) | 2022.08.27 |
vue.js 및 부트스트랩 4를 사용한 팝오버 (0) | 2022.08.27 |
-j4 또는 -j8과 함께 make 사용 (0) | 2022.08.27 |