2010-03-06 9 views
6

Liên quan đến số other question của tôi, bây giờ tôi đã sửa đổi bộ giải mã ma trận thưa thớt để sử dụng phương pháp SOR (Kế thừa thư giãn). Mã bây giờ được như sau:Tại sao tốc độ của bộ giải SOR này phụ thuộc vào đầu vào?

void SORSolver::step() { 
    float const omega = 1.0f; 
    float const 
     *b = &d_b(1, 1), 
     *w = &d_w(1, 1), *e = &d_e(1, 1), *s = &d_s(1, 1), *n = &d_n(1, 1), 
     *xw = &d_x(0, 1), *xe = &d_x(2, 1), *xs = &d_x(1, 0), *xn = &d_x(1, 2); 
    float *xc = &d_x(1, 1); 
    for (size_t y = 1; y < d_ny - 1; ++y) { 
     for (size_t x = 1; x < d_nx - 1; ++x) { 
      float diff = *b 
       - *xc 
       - *e * *xe 
       - *s * *xs - *n * *xn 
       - *w * *xw; 
      *xc += omega * diff; 
      ++b; 
      ++w; ++e; ++s; ++n; 
      ++xw; ++xe; ++xs; ++xn; 
      ++xc; 
     } 
     b += 2; 
     w += 2; e += 2; s += 2; n += 2; 
     xw += 2; xe += 2; xs += 2; xn += 2; 
     xc += 2; 
    } 
} 

Bây giờ điều lạ là: nếu tôi tăng omega (yếu tố thư giãn), tốc độ thực thi bắt đầu phụ thuộc đáng kể trên các giá trị bên trong các mảng khác nhau!

Đối với omega = 1.0f, thời gian thực hiện ít nhiều liên tục. Đối với omega = 1.8, lần đầu tiên, thường mất khoảng 5 mili giây để thực thi step() 10 lần này, nhưng điều này sẽ dần dần tăng lên gần 100 ms trong khi mô phỏng. Nếu tôi đặt omega = 1.0001f, tôi thấy mức tăng thời gian thực hiện tương đối nhỏ; cao hơn omega đi, thời gian thực hiện nhanh hơn sẽ tăng lên trong quá trình mô phỏng.

Vì tất cả điều này được nhúng bên trong bộ giải dịch, thật khó để có được một ví dụ độc lập. Nhưng tôi đã lưu trạng thái ban đầu và chạy lại trình giải quyết trên trạng thái đó mỗi bước, cũng như giải quyết cho bước thời gian thực tế. Đối với trạng thái ban đầu, nó nhanh, các bước thời gian tiếp theo tăng chậm hơn. Vì tất cả đều khác nhau, điều đó chứng minh rằng tốc độ thực thi của mã này phụ thuộc vào các giá trị trong sáu mảng đó.

Điều này có thể sao chép trên Ubuntu bằng g ++, cũng như trên Windows 7 64 bit khi biên dịch cho 32 bit với VS2008.

Tôi nghe nói rằng giá trị NaN và Inf có thể chậm hơn đối với các phép tính điểm động, nhưng không có NaN hoặc Inf. Có thể là tốc độ của tính toán nổi nếu không phụ thuộc vào giá trị của các số đầu vào?

+0

Bạn có chắc chắn rằng bạn không đo lường một số thuật toán mã khác phụ thuộc vào giá trị của các phép tính không? – ebo

+0

Nếu bạn tiếp tục gặp sự cố về hiệu suất, hãy xem xét sử dụng GPU cho các tính toán này. GPU là rất tốt ở công việc ma trận thưa thớt. – Mark

+0

@ebo: Tôi đã sử dụng đồng hồ thời gian thực trong Linux để chỉ đo cuộc gọi này. Vì vậy, có, tôi khá chắc chắn. – Thomas

Trả lời

5

Câu trả lời ngắn cho câu hỏi cuối cùng của bạn là "có" - số không chuẩn hóa (rất gần bằng 0) yêu cầu xử lý đặc biệt và có thể chậm hơn nhiều. Tôi đoán là họ đang đi vào mô phỏng khi thời gian trôi qua. Xem bài viết SO có liên quan này: Floating Point Math Execution Time

Đặt điều khiển dấu phẩy động để tuôn ra các ký hiệu số không bằng 0 sẽ quan tâm đến những thứ có chất lượng mô phỏng không đáng kể.

+0

Các giá trị không chuẩn hóa thực sự đi vào nó; Tôi đang giải quyết cho áp lực chất lỏng để có được sự phân kỳ ('d_b' ở trên) càng gần bằng không càng tốt. Vì vậy, điều này giải thích nó, và bạn một lần nữa đã dạy tôi điều gì đó. Cảm ơn nhiều!(Sự nhầm lẫn của bạn về '1-omega' có lẽ là do các hàng ma trận được chia tỷ lệ nên có' 1' trên đường chéo. '- * xc' không xuất phát từ đó, nhưng thực ra là thuật ngữ' -omega * * xc' trong dòng mã của bạn. Tôi đang nhận được câu trả lời hợp lý.) – Thomas

+0

Vui vì điều đó đã xảy ra. Tôi đã nghe một câu chuyện kinh dị từ một đồng nghiệp gần đây - ngay trước một chương trình thương mại lớn vài năm trước, chương trình demo đã chậm lại sau khi chạy trong vài phút. Nó bật ra một lỗi trong trình điều khiển đồ họa đã không được đặt lại cờ kiểm soát dấu chấm động đúng cách, và họ đã nhận được denormals từ lặp đi lặp lại nhân của một yếu tố giảm xóc trong mô phỏng cơ thể cứng nhắc. Đơn giản, đủ để sửa chữa một khi họ biết vấn đề, nhưng đã cho họ một hoặc hai ngày gỡ lỗi để theo dõi nó xuống. Dù sao, tôi ngay lập tức nghĩ về điều đó khi tôi đọc mô tả của bạn. – celion

+0

Tôi cũng đã xóa các chỉnh sửa (không chính xác) của tôi về 1-omega để làm cho câu trả lời rõ hơn ... – celion

0

celion's answer hóa ra là chính xác. Bài đăng mà anh ấy liên kết đến nói để bật các giá trị không chuẩn hóa theo phương thức tuôn ra bằng không:

#include <float.h> 
_controlfp(_MCW_DN, _DN_FLUSH); 

Tuy nhiên, đây chỉ là Windows. Sử dụng gcc trên Linux, tôi đã làm điều tương tự với một bộ phận lắp ráp nội tuyến:

int mxcsr; 
__asm__("stmxcsr %0" : "=m"(mxcsr) : :); 
mxcsr |= (1 << 15); // set bit 15: flush-to-zero mode 
__asm__("ldmxcsr %0" : : "m"(mxcsr) :); 

Đây là phiên bản x86 đầu tiên của tôi, vì vậy nó có thể được cải thiện. Nhưng nó thực sự là lừa cho tôi.

+0

Bạn có thể đặt môi trường FP một cách hợp lý với fenv.h (C99). – Jed

+0

Đây là C++, vì vậy sẽ không hoạt động trực tiếp. Nhưng nó có thể có thể ăn cắp thực hiện đó. Cảm ơn! – Thomas