2012-04-24 39 views
7

Tôi nhìn qua một số mã để xem xét và đã đi qua một chờ đợi bận rộn như vậy:Liệu một vòng trống cho vòng lặp được sử dụng như một giấc ngủ có được tối ưu hóa không?

int loop = us*32; 
int x; 
for(x = 0;x<loop;x++) 
{ 
    /*do nothing*/  
} 

tôi dường như nhớ lại đọc rằng những vòng rỗng có thể được tối ưu hóa đi. Đây có phải là những gì sẽ xảy ra ở đây hoặc có thể làm việc này?

+1

http://stackoverflow.com/questions/3527829/is-this -a-bug-in-the-intel-c-compiler-icc/3527862 # 3527862 –

+1

có ............ –

+0

'us'? nếu mã này hoạt động thì đó phải là một CPU thực sự chậm. –

Trả lời

12

Bạn đang ở lòng thương xót của trình biên dịch. Thật vậy nếu nó thông minh nó sẽ phát hiện nó là một noop. Ngẫu nhiên, Neil Butterworth có một số nice post nơi ông cũng chạm vào chủ đề này.

+3

Nếu bạn bật tối ưu hóa. – Kevin

+0

Cảm ơn câu trả lời. Đó là một cái gì đó trong tâm trí của tôi nói rằng loại điều này có thể là một vấn đề – Firedragon

+0

Không thực sự, ngay cả khi bạn không thể phát ra mã lắp ráp nội tuyến trình biên dịch sẽ không (và không thể) vứt bỏ các biểu thức với phía địa phương- hiệu ứng. –

2

Một số trình biên dịch, như gcc, sẽ phát hiện ra rằng đó là vòng trống cho vòng lặp và đặc biệt pessimize cho điều đó, với kỳ vọng rằng bạn đặt nó trong đó như là một vòng lặp chậm trễ. Bạn có thể đọc thêm về điều đó tại số http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Non_002dbugs.html

Tâm trí bạn, đây là trình biên dịch cụ thể, vì vậy đừng tính vào nó với tất cả trình biên dịch.

+1

Thật vậy, tôi đã chạy vào điều này với mingw/msvc, nơi tôi đã phải gỡ lỗi mã làm một chờ đợi bận rộn trên một biến được sửa đổi bởi chủ đề khác, và vòng lặp đã được tối ưu hóa (trong trường hợp mingw chỉ với -O2) vào một câu lệnh jmp nhảy tới chính nó (tức là một vòng lặp vô hạn), nhiều điều thú vị đã được gỡ lỗi đó. :) – aphax

4

Đó là điều gì đó khủng khiếp không di động.

Trong một số trình biên dịch một trong những có thể công trình (nhưng bạn phải kiểm tra với tối ưu hóa đầy đủ kích hoạt, hướng dẫn sản phẩm nào có thể được vứt bỏ):

for (i = 0; i < spinCount;) 
    ++i; // yes, HERE 

hay:

for (i = 0; i < spinCount; ++i) 
    ((void)0);  

Nếu bạn đủ may mắn sau đó trình biên dịch của bạn có thể cung cấp một macro hoặc một chức năng nội tại sẽ được biên dịch theo hướng dẫn lắp ráp nop, giống như __noop trong MSVC.

tài nguyên Như cuối cùng bạn chỉ có thể thêm một hướng dẫn lắp ráp duy nhất (đó là biên dịch phụ thuộc, nó có thể là __asm ​​hoặc một cái gì đó như thế) để thực hiện ... không có gì, như thế này:

for (i = 0; i < spinCount; ++i) 
    __asm nop 

hoặc (đánh dấu của bạn tài liệu biên dịch):

for (i = 0; i < spinCount; ++i) 
    asm("nop"); 

EDIT
Nếu bạn không có một hướng dẫn noop và bạn không thể thêm mã lắp ráp (tôi xin lỗi, những loại com piler bạn đang sử dụng?) bạn có thể dựa vào giả định rằng một hướng dẫn với một hiệu ứng phụ sẽ không được tối ưu hóa đi (hoặc, như được đăng bởi @ouah, một truy cập vào một biến tuyên bố volatile).

13

Câu trả lời là có, trình biên dịch có thể tối ưu hóa vòng lặp.

Sử dụng volatile vòng loại để tránh việc tối ưu hóa:

int loop = us * 32; 
volatile int x; 
for (x = 0; x < loop; x++) 
{ 
    /*do nothing*/  
} 

Nếu bạn đang lập trình trong thế giới nhúng đọc tài liệu của trình biên dịch của bạn khi họ thường cung cấp các chức năng chậm trễ mà chờ đợi cho một số lượng nhất định của chu kỳ hoặc micro được thông qua trong tham số.

Ví dụ, avr-gcc có chức năng sau đây trong util/delay.h:

void _delay_us(double __us); 
+0

Nhận xét rất hữu ích. Cảm ơn bạn – Firedragon

+0

Đọc hướng dẫn tuyệt đẹp về lý do tại sao từ khóa dễ bay hơi nên được sử dụng: http://www.embedded.com/electronics-blogs/beginner-s-corner/4023801/Giới thiệu-to-the-Volatile-Keyword – Prabhpreet

2

Không có gì trong các tiêu chuẩn ngôn ngữ cấm nó, vì vậy trình biên dịch có thể làm điều đó nếu họ có thể.

Hãy ngược GCC 4.8 để xem những gì nó đang

Input:

int main() { 
    int i; 
    for(i = 0; i < 16; i++) 
     ; 
} 

Compile và biên soạn lại:

gcc -c -g -std=c99 -O0 a.c 
objudmp -S a.o 

Output:

a.o:  file format elf64-x86-64 


Disassembly of section .text: 

0000000000000000 <main>: 
int main() { 
    0: 55      push %rbp 
    1: 48 89 e5    mov %rsp,%rbp 
    int i; 
    for(i = 0; i < 16; i++) 
    4: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) 
    b: eb 04     jmp 11 <main+0x11> 
    d: 83 45 fc 01    addl $0x1,-0x4(%rbp) 
    11: 83 7d fc 0f    cmpl $0xf,-0x4(%rbp) 
    15: 7e f6     jle d <main+0xd> 
    17: b8 00 00 00 00   mov $0x0,%eax 
     ; 
} 
    1c: 5d      pop %rbp 
    1d: c3      retq 

Vòng lặp có ở đó: jle nhảy trở lại.

Với -O3:

0000000000000000 <main>: 
    0: 31 c0     xor %eax,%eax 
    2: c3      retq 

mà chỉ trả về 0. Vì vậy, nó đã hoàn toàn tối ưu hóa đi.

Phân tích tương tự có thể được thực hiện cho bất kỳ trình biên dịch nào.

Xem thêm

Các vấn đề liên quan