2011-07-19 27 views
11

Tôi đang cố triển khai một lớp điểm cố định trong C++, nhưng tôi gặp phải các vấn đề với hiệu năng. Tôi đã giảm bớt vấn đề với một trình bao bọc đơn giản của kiểu float và nó vẫn còn chậm. Câu hỏi của tôi là - tại sao trình biên dịch không thể tối ưu hóa nó hoàn toàn?Làm cách nào để tối ưu hóa lớp trình bao bọc kiểu số đơn giản trong C++?

Phiên bản 'nổi' nhanh hơn 50% so với 'Float'. Tại sao?!

(Tôi sử dụng Visual C++ 2008, tất cả các tùy chọn của trình biên dịch có thể được kiểm tra, Cấu hình phát hành của khóa học).

Xem mã bên dưới:

#include <cstdio> 
#include <cstdlib> 
#include "Clock.h"  // just for measuring time 

#define real Float  // Option 1 
//#define real float  // Option 2 

struct Float 
{ 
private: 
    float value; 

public: 
    Float(float value) : value(value) {} 
    operator float() { return value; } 

    Float& operator=(const Float& rhs) 
    { 
     value = rhs.value; 
     return *this; 
    } 

    Float operator+ (const Float& rhs) const 
    { 
     return Float(value + rhs.value); 
    } 

    Float operator- (const Float& rhs) const 
    { 
     return Float(value - rhs.value); 
    } 

    Float operator* (const Float& rhs) const 
    { 
     return Float(value * rhs.value); 
    } 

    bool operator< (const Float& rhs) const 
    { 
     return value < rhs.value; 
    } 
}; 

struct Point 
{ 
    Point() : x(0), y(0) {} 
    Point(real x, real y) : x(x), y(y) {} 

    real x; 
    real y; 
}; 

int main() 
{ 
    // Generate data 
    const int N = 30000; 
    Point points[N]; 
    for (int i = 0; i < N; ++i) 
    { 
     points[i].x = (real)(640.0f * rand()/RAND_MAX); 
     points[i].y = (real)(640.0f * rand()/RAND_MAX); 
    } 

    real limit(20 * 20); 

    // Check how many pairs of points are closer than 20 
    Clock clk; 

    int count = 0; 
    for (int i = 0; i < N; ++i) 
    { 
     for (int j = i + 1; j < N; ++j) 
     { 
      real dx = points[i].x - points[j].x; 
      real dy = points[i].y - points[j].y; 
      real d2 = dx * dx + dy * dy; 
      if (d2 < limit) 
      { 
       count++; 
      } 
     } 
    } 

    double time = clk.time(); 

    printf("%d\n", count); 
    printf("TIME: %lf\n", time); 

    return 0; 
} 
+2

Bạn đã bật cờ tối ưu hóa tối đa chưa. Tôi đã thấy các phép thuật xảy ra khi bạn BẬT chúng. – iammilind

+0

Tạo lắp ráp và kiểm tra các vị trí khác nhau ... –

+0

Bạn có thể thử đánh dấu tất cả các phương thức một cách rõ ràng là 'nội tuyến' –

Trả lời

4

IMO, Nó đã làm với cờ tối ưu. Tôi đã kiểm tra chương trình của bạn bằng máy g ++ linux-64. Nếu không có bất kỳ tối ưu hóa nào, nó cho kết quả tương tự như bạn đã cho biết số ít hơn 50%.

Với việc tối ưu hóa tối ưu hóa được bật (ví dụ: -O4). Cả hai phiên bản đều giống nhau. Bật tối ưu hóa và kiểm tra.

+1

Tôi đã cài đặt GCC và trên thực tế nó hoạt động tốt! Với GCC thời gian là 1.13 s, trong khi với VC++ nó là 1.70 s (float) hoặc 2.58 s (Float). Tôi cũng phát hiện ra rằng việc di chuyển 'dx * dx + dy * dy' trực tiếp đến điều kiện cải thiện hiệu năng trên VC++ lên 21%! VC++ có thể tối ưu hóa như thế nào? Tôi có tất cả các tùy chọn tối ưu hóa có thể được bật và thử nghiệm nhiều kết hợp khác nhau. –

+0

Chà ... Khi tôi chuyển từ nền tảng 'Win32' sang 'x64', thời gian thực hiện giảm từ 2,58 xuống 0,77 giây! Và nó cũng tương tự như 'float' và cho 'Float'. –

2

Sau khi điều tra thêm, tôi hoàn toàn tin rằng đây là vấn đề với đường ống tối ưu hóa của trình biên dịch. Mã được tạo trong trường hợp này là đáng kể xấu so với việc sử dụng một mã không được đóng gói float. Đề xuất của tôi là báo cáo vấn đề tiềm ẩn này cho Microsoft và xem họ phải nói gì về vấn đề này. Tôi cũng khuyên bạn nên chuyển sang triển khai phiên bản điểm cố định đã lên kế hoạch của lớp này vì mã được tạo cho các số nguyên xuất hiện tối ưu.

4

Hãy thử không bằng cách tham chiếu. Lớp học của bạn là đủ nhỏ mà các chi phí của đi qua nó bằng cách tham khảo (có có trên không nếu trình biên dịch không tối ưu hóa nó ra), có thể cao hơn chỉ cần sao chép các lớp học. Vì vậy, đây ...

Float operator+ (const Float& rhs) const 
{ 
    return Float(value + rhs.value); 
} 

trở thành một cái gì đó như thế này ...

Float operator+ (Float rhs) const 
{ 
    rhs.value+=value; 
    return rhs; 
} 

mà tránh một đối tượng tạm thời và có thể tránh được một số gián tiếp của một dereference con trỏ.

+2

Tôi đã thử - không hoạt động. Nó thậm chí còn tăng thời gian thêm 59% nữa. –

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