Từ khóa giới hạn có mang lại lợi ích đáng kể trong gcc/g ++ không?
Nó có thể giảm số lượng hướng dẫn như minh họa trong ví dụ bên dưới, vì vậy hãy sử dụng nó bất cứ khi nào có thể.
GCC 4.8 Linux x86-64 exmample
Input:
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;
}
Compile và biên soạn lại:
gcc -g -std=c99 -O0 -c main.c
objdump -S main.o
Với -O0
, họ đều giống nhau.
Với -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)
Đối với người lãnh đạo, các calling convention là:
rdi
= tham số đầu tiên
rsi
= tham số thứ hai
rdx
= tham số thứ ba
Kết luận: 3 hướng dẫn thay vì 4.
Tất nhiên, hướng dẫn can have different latencies, nhưng điều này mang lại ý tưởng hay.
Tại sao GCC có thể tối ưu hóa điều đó?
Mã trên được lấy từ Wikipedia example là rất chiếu sáng.
Pseudo lắp ráp cho 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 a may be equal to x.
load R1 ← *x
load R2 ← *b
add R2 += R1
set R2 → *b
Đối 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
load R2 ← *b
add R2 += R1
set R2 → *b
Là nó thực sự nào nhanh hơn?
Ermmm ... không cho kiểm tra đơn giản này:
.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
Và sau đó:
as -o a.o a.S && ld a.o && time ./a.out
trên Ubuntu 14.04 AMD64 CPU Intel i5-3210M.
Tôi thú nhận rằng tôi vẫn không hiểu các CPU hiện đại.Hãy cho tôi biết nếu quý vị:
- tìm thấy một lỗ hổng trong phương pháp của tôi
- tìm thấy một trường hợp thử nghiệm lắp ráp, nơi nó trở nên nhanh hơn nhiều
- hiểu tại sao không có một sự khác biệt
vấn đề Aliasing là thường được coi là lý do số 1 tại sao C/C++ kém hiệu quả hơn trong nhiều nhiệm vụ tính toán hơn Fortran. Vì vậy, tôi muốn nói bất kỳ tính năng nào giúp tránh việc tạo bí danh có thể tạo ra sự khác biệt * lớn *. – jalf
có thể trùng lặp với [Sử dụng thực tế từ khóa 'giới hạn' của C99?] (Http://stackoverflow.com/questions/745870/realistic-usage-of-the-c99-restrict-keyword) –