2013-02-17 22 views
7

Tôi đang cố gắng kẹp một giá trị giữa -127 và 127 trên Cortex-M dựa trên microcontroller.C Đây có phải là hack không nhánh thực sự nhanh hơn không?

Tôi có hai chức năng cạnh tranh, một sử dụng điều kiện khác sử dụng hack không nhánh tôi tìm thấy here.

// Using conditional statements 
int clamp(int val) { return ((val > 127) ? 127 : (val < -127) ? -127 : val); } 

// Using branchless hacks 
int clamp(int val) { 
    val -= -127; 
    val &= (~val) >> 31; 
    val += -127; 
    val -= 127; 
    val &= val >> 31; 
    val += 127; 

    return val; 
} 

Bây giờ tôi biết rằng trong một số trường hợp một trong những phương pháp này có thể là nhanh hơn so với người kia, và ngược lại nhưng nhìn chung là nó có giá trị nó để sử dụng kỹ thuật không cành thấy như nó không thực sự quan trọng với tôi mà tôi sử dụng, cả hai đều sẽ làm việc tốt trong trường hợp của tôi?

Một nền tảng nhỏ trên vi điều khiển, đó là một vi điều khiển dựa trên ARM chạy ở 90 MIPS với đường ống 3 giai đoạn, tìm nạp, giải mã và thực thi và dường như có một số loại dự báo chi nhánh nhưng tôi không thể khai thác chi tiết.

+10

Bạn đã đánh giá nó? –

+3

Có vẻ như tối ưu hóa bị tắt khi mã được biên dịch. –

+8

Bạn quan tâm đến hiệu suất trên ARM, nhưng bạn đang xem ASM được tạo cho x86. Điều đó sẽ không đưa bạn đến đâu cả. – hobbs

Trả lời

4

mã ARM (GCC 4.6.3 với -O3):

clamp1: 
    mvn r3, #126 
    cmp r0, r3 
    movlt r0, r3 
    cmp r0, #127 
    movge r0, #127 
    bx lr 

clamp2: 
    add r0, r0, #127 
    mvn r3, r0 
    and r0, r0, r3, asr #31 
    sub r0, r0, #254 
    and r0, r0, r0, asr #31 
    add r0, r0, #127 
    bx lr 

đang Thumb:

clamp1: 
    mvn r3, #126 
    cmp r0, r3 
    it lt 
    movlt r0, r3 
    cmp r0, #127 
    it ge 
    movge r0, #127 
    bx lr 

clamp2: 
    adds r0, r0, #127 
    mvns r3, r0 
    and r0, r0, r3, asr #31 
    subs r0, r0, #254 
    and r0, r0, r0, asr #31 
    adds r0, r0, #127 
    bx lr 

Cả hai đều là cành nhờ vào thiết kế thi công có điều kiện của ARM. Tôi sẽ đặt cược bạn về cơ bản là họ có thể so sánh về hiệu suất.

+1

Hiện tại tôi không có bảng ARM, nhưng tôi tò mò muốn biết sự khác nhau về hiệu suất giữa bốn phiên bản này. (Tiền của tôi trên ARM 'clamp1', nhưng sự khác biệt sẽ cực kỳ nhỏ). – nneonneo

3

Điều gì đó để nhận ra là kiến ​​trúc ARM và x86 rất khác khi nói đến hướng dẫn chi nhánh. Thực hiện một bước nhảy làm sạch đường ống dẫn đến việc có thể dẫn đến một số chu kỳ đồng hồ chỉ để 'quay lại vị trí của bạn' về thông lượng.

Để trích dẫn một pdf Tôi tải về các ngày khác (pg14 của http://simplemachines.it/doc/arm_inst.pdf),

Thực hiện Conditional

  • Hầu hết các hướng dẫn bộ chỉ cho phép các chi nhánh để được thực thi có điều kiện.
  • Tuy nhiên, bằng cách sử dụng lại phần cứng đánh giá điều kiện, ARM có hiệu quả làm tăng số lượng hướng dẫn.
  • Tất cả các hướng dẫn đều chứa trường điều kiện xác định liệu CPU có thực thi chúng hay không.
  • Hướng dẫn không được thực hiện sẽ hấp thụ 1 chu kỳ. - Vẫn phải hoàn thành chu kỳ để cho phép tìm nạp và giải mã các hướng dẫn sau.
  • Điều này loại bỏ sự cần thiết cho nhiều chi nhánh, ngăn chặn đường ống (3 chu kỳ để nạp tiền).
  • Cho phép mã nội dòng rất dày đặc, không có nhánh.
  • Hình phạt thời gian không thực hiện một số lệnh có điều kiện thường thấp hơn chi phí của cuộc gọi chi nhánh hoặc chương trình con mà nếu không sẽ cần thiết.
+2

Vâng, về mặt kỹ thuật, chi nhánh vẫn còn đắt tiền trên ARM. Nhưng, thực thi có điều kiện có thể loại bỏ rất nhiều bước nhảy ngắn. – nneonneo

+1

Rất đúng, cảm ơn vì đã làm tốt hơn việc tóm tắt hơn tôi có thể. Bạn đã đặt nó gọn gàng hơn tôi nhiều. : ngón tay cái: – enhzflep

0

No. Ngôn ngữ C không có tốc độ; Đó là một khái niệm được giới thiệu bởi việc triển khai của C. Một trình biên dịch hoàn hảo tối ưu sẽ dịch cả hai của những người cùng một mã máy.

Trình biên dịch C có nhiều khả năng có thể tối ưu hóa mã phù hợp với các kiểu phổ biến và được xác định rõ. Hàm thứ hai không được xác định rõ.

Các bổ sung và phép trừ đó có thể gây tràn số nguyên. Các luồng tràn số nguyên là hành vi không xác định, vì vậy chúng có thể khiến chương trình của bạn hoạt động không đúng. Optimistically, phần cứng của bạn có thể thực hiện gói hoặc bão hòa. Ít lạc quan hơn, hệ điều hành hoặc trình biên dịch của bạn có thể triển khai các tín hiệu hoặc biểu diễn bẫy cho các luồng tràn số nguyên. Phát hiện tràn số nguyên có thể ảnh hưởng đến hiệu suất xử lý thay đổi của một biến. Trường hợp xấu nhất là chương trình của bạn mất tính toàn vẹn của nó.

Nhà cung cấp & và >> có các khía cạnh được xác định thực hiện cho các loại đã ký. Chúng có thể dẫn đến một số không âm, đó là một ví dụ về biểu diễn bẫy. Sử dụng biểu diễn bẫy là hành vi không xác định, vì vậy chương trình của bạn có thể mất tính toàn vẹn của nó.

Có lẽ hệ điều hành hoặc trình biên dịch của bạn thực hiện kiểm tra bit chẵn lẻ đối với các đối tượng int. Trong trường hợp này, hãy thử tưởng tượng tính toán lại các bit chẵn lẻ mỗi khi một biến thay đổi và xác minh các bit chẵn lẻ mỗi khi một biến được đọc. Nếu kiểm tra chẵn lẻ không thành công, chương trình của bạn có thể mất tính toàn vẹn của nó.

Sử dụng chức năng đầu tiên. Ít nhất nó cũng được xác định. Nếu chương trình của bạn dường như chạy chậm, việc tối ưu hóa mã này có thể sẽ không tăng tốc độ chương trình của bạn một cách đáng kể; Sử dụng một hồ sơ để tìm thêm tối ưu quan trọng, sử dụng một hệ điều hành tối ưu hơn hoặc trình biên dịch hoặc mua phần cứng nhanh hơn.

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