Nó cũng phụ thuộc vào hỗn hợp lệnh. Bộ vi xử lý của bạn sẽ có một số đơn vị tính toán đứng bất cứ lúc nào, và bạn sẽ nhận được thông lượng tối đa nếu tất cả chúng được lấp đầy mọi lúc. Vì vậy, thực hiện một vòng lặp của mul chỉ là nhanh như thực hiện một vòng lặp hoặc thêm - nhưng cùng không giữ nếu biểu thức trở nên phức tạp hơn.
Ví dụ, đi vòng lặp này:
for(int j=0;j<NUMITER;j++) {
for(int i=1;i<NUMEL;i++) {
bla += 2.1 + arr1[i] + arr2[i] + arr3[i] + arr4[i] ;
}
}
cho NUMITER = 10^7, NUMEL = 10^2, cả hai mảng khởi tạo các số dương nhỏ (NaN là chậm hơn nhiều), điều này mất 6,0 giây sử dụng tăng gấp đôi trên một proc 64-bit. Nếu tôi thay thế các vòng lặp với
bla += 2.1 * arr1[i] + arr2[i] + arr3[i] * arr4[i] ;
Nó chỉ mất 1,7 giây ... do đó, vì chúng ta "overdid" những bổ sung, các muls về cơ bản miễn phí; và việc giảm bổ sung đã giúp. Nó trở nên khó hiểu hơn:
bla += 2.1 + arr1[i] * arr2[i] + arr3[i] * arr4[i] ;
- cùng phân bổ/thêm phân phối, nhưng bây giờ hằng số được thêm vào thay vì nhân lên - mất 3,7 giây. Bộ xử lý của bạn có khả năng được tối ưu hóa để thực hiện các phép tính số điển hình hiệu quả hơn; Vì vậy, dot-sản phẩm như tổng của muls và tổng số tiền là về tốt như nó được; việc thêm các hằng số gần như không phổ biến, vì vậy chậm hơn ...
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; /*someval == 2.1*/
lại mất 1,7 giây.
bla += someval + arr1[i] + arr2[i] + arr3[i] + arr4[i] ; /*someval == 2.1*/
(giống như vòng lặp ban đầu, nhưng không có thêm liên tục đắt tiền: 2.1 giây)
bla += someval * arr1[i] * arr2[i] * arr3[i] * arr4[i] ; /*someval == 2.1*/
(chủ yếu muls, nhưng một trong những bổ sung: 1,9 giây)
Vì vậy, về cơ bản; thật khó để nói nhanh hơn, nhưng nếu bạn muốn tránh tắc nghẽn, quan trọng hơn là phải có một hỗn hợp lành mạnh, tránh NaN hoặc INF, tránh thêm các hằng số. Dù bạn làm gì, hãy chắc chắn rằng bạn kiểm tra, và kiểm tra các thiết lập trình biên dịch khác nhau, vì những thay đổi nhỏ thường chỉ có thể tạo ra sự khác biệt.
Một số chi tiết các trường hợp:
bla *= someval; // someval very near 1.0; takes 2.1 seconds
bla *= arr1[i] ;// arr1[i] all very near 1.0; takes 66(!) seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; // 1.6 seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; //32-bit mode, 2.2 seconds
bla += someval + arr1[i] * arr2[i] + arr3[i] * arr4[i] ; //32-bit mode, floats 2.2 seconds
bla += someval * arr1[i]* arr2[i];// 0.9 in x64, 1.6 in x86
bla += someval * arr1[i];// 0.55 in x64, 0.8 in x86
bla += arr1[i] * arr2[i];// 0.8 in x64, 0.8 in x86, 0.95 in CLR+x64, 0.8 in CLR+x86
Kết hợp hướng dẫn là một điểm tốt, tôi có những người tôi làm việc với người nhấn mạnh rằng một điểm nổi 200 DSP sẽ thực hiện một 600 điểm DSP cố định. Họ hoàn toàn không xử lý vòng lặp chặt chẽ, và dành nhiều thời gian xử lý I/O hơn làm calcuations. Một bộ xử lý điểm cố định nhanh hơn sẽ giành chiến thắng dựa trên hỗn hợp lệnh tổng thể, nhưng mọi người chỉ nghĩ rằng các đơn vị FP là ma thuật chứ không phải là việc thực hiện HW của một cơ sở dữ liệu. – NoMoreZealots
Ah vâng, appproach ma thuật ;-) - thật không may. –
giải thích tốt đẹp với các ví dụ trực quan! –