2017-06-03 69 views
9

Tôi nhận thấy rằng một cấu trúc gói một phao đơn là chậm hơn đáng kể so với sử dụng một phao trực tiếp, với khoảng một nửa hiệu suất.Tại sao thêm một trường bổ sung để cấu trúc cải thiện đáng kể hiệu suất của nó?

using System; 
using System.Diagnostics; 

struct Vector1 { 

    public float X; 

    public Vector1(float x) { 
     X = x; 
    } 

    public static Vector1 operator +(Vector1 a, Vector1 b) { 
     a.X = a.X + b.X; 
     return a; 
    } 
} 

Tuy nhiên, khi bổ sung 'thêm' một trường bổ sung, một số ma thuật dường như xảy ra và thực hiện một lần nữa trở nên hợp lý hơn:

struct Vector1Magic { 

    public float X; 
    private bool magic; 

    public Vector1Magic(float x) { 
     X = x; 
     magic = true; 
    } 

    public static Vector1Magic operator +(Vector1Magic a, Vector1Magic b) { 
     a.X = a.X + b.X; 
     return a; 
    } 
} 

Code tôi sử dụng để benchmark những được như sau:

class Program { 
    static void Main(string[] args) { 
     int iterationCount = 1000000000; 
     var sw = new Stopwatch(); 
     sw.Start(); 
     var total = 0.0f; 
     for (int i = 0; i < iterationCount; i++) { 
      var v = (float) i; 
      total = total + v; 
     } 
     sw.Stop(); 
     Console.WriteLine("Float time was {0} for {1} iterations.", sw.Elapsed, iterationCount); 
     Console.WriteLine("total = {0}", total); 
     sw.Reset(); 
     sw.Start(); 
     var totalV = new Vector1(0.0f); 
     for (int i = 0; i < iterationCount; i++) { 
      var v = new Vector1(i); 
      totalV += v; 
     } 
     sw.Stop(); 
     Console.WriteLine("Vector1 time was {0} for {1} iterations.", sw.Elapsed, iterationCount); 
     Console.WriteLine("totalV = {0}", totalV); 
     sw.Reset(); 
     sw.Start(); 
     var totalVm = new Vector1Magic(0.0f); 
     for (int i = 0; i < iterationCount; i++) { 
      var vm = new Vector1Magic(i); 
      totalVm += vm; 
     } 
     sw.Stop(); 
     Console.WriteLine("Vector1Magic time was {0} for {1} iterations.", sw.Elapsed, iterationCount); 
     Console.WriteLine("totalVm = {0}", totalVm); 
     Console.Read(); 
    } 
} 

với những kết quả benchmark:

Float time was 00:00:02.2444910 for 1000000000 iterations. 
Vector1 time was 00:00:04.4490656 for 1000000000 iterations. 
Vector1Magic time was 00:00:02.2262701 for 1000000000 iterations. 

thiết lập trình biên dịch/môi trường: Hệ điều hành: Windows 10 64 bit toolchain: VS2017 Khung: Net 4.6.2 Target: Bất kỳ CPU thích 32 bit

Nếu 64 bit được thiết lập như là mục tiêu, kết quả của chúng tôi được dự kiến ​​được, nhưng còn tồi tệ hơn những gì chúng ta thấy với Vector1Magic trên mục tiêu 32 bit đáng kể:

Float time was 00:00:00.6800014 for 1000000000 iterations. 
Vector1 time was 00:00:04.4572642 for 1000000000 iterations. 
Vector1Magic time was 00:00:05.7806399 for 1000000000 iterations. 

Đối với các trình thuật sĩ sản, tôi đã bao gồm một bãi chứa của IL đây: https://pastebin.com/sz2QLGEx

Điều tra thêm cho thấy rằng điều này có vẻ là cụ thể đối với thời gian chạy Windows, vì trình biên dịch đơn âm tạo ra cùng một IL.

Trên thời gian chạy đơn, cả hai biến thể cấu trúc có hiệu suất gần gấp 2 lần so với phao thô. Điều này hơi khác một chút so với hiệu suất mà chúng ta thấy trên .Net.

Điều gì đang xảy ra ở đây?

* Lưu ý câu hỏi này ban đầu bao gồm quy trình điểm chuẩn không hoàn chỉnh (Cảm ơn Max Payne đã chỉ ra điều này) và đã được cập nhật để phản ánh chính xác hơn thời gian.

+1

Im đoán điều này là do các cấu trúc bao bì bây giờ có sự liên kết bộ nhớ tốt hơn. –

+2

Bạn nên thêm một lần lặp lại để loại trừ nhiễu có thể xảy ra khỏi JIT hoặc xử lý một lần khác. – PetSerAl

+2

Nếu tôi chuyển sang 64 bit, tôi sẽ có hiệu suất kém hơn đối với vectơ "ma thuật" của bạn. – Adrian

Trả lời

0

Điều này sẽ không xảy ra. Điều này rõ ràng là một số loại missalignment buộc JIT không hoạt động như nó cần.

struct Vector1 //Works fast in 32 Bit 
{ 
    public double X; 
} 

struct Vector1 //Works fast in 64 Bit and 32 Bit 
{ 
    public double X; 
    public double X2; 
} 

Bạn cũng phải gọi: Console.WriteLine (tổng cộng); làm tăng thời gian chính xác đến thời gian Vector1Magic có ý nghĩa. Câu hỏi vẫn còn giữ, tại sao Vector1 lại quá chậm.

Có thể cấu trúc không được tối ưu hóa cho sizeof (foo) < 64 Bit ở chế độ 64 bit.

Có vẻ như rằng điều này đã ansered 7 năm trước: Why is 16 byte the recommended size for struct in C#?

+0

"Điều này không nên xảy ra. Điều này rõ ràng là một số loại bỏ ràng buộc buộc JIT không hoạt động như nó cần." - Điều này không thực sự trả lời câu hỏi. Lý do tại sao điều này xảy ra? Lý do đằng sau điều này là gì? – Varon

+0

Sau đó, cho phép upvote cho đến khi ai đó đến xung quanh những người hiểu biết làm thế nào. Net hoạt động nội bộ. Mã IL được sản xuất rất tốt để đọc mà không chỉ cho chúng tôi giải pháp. Vấn đề là sâu hơn, bên trong trình tối ưu hóa JIT. Đây là một tìm kiếm rất thú vị, có lẽ bạn có thể đăng bài này trên diễn đàn nhóm phát triển MSDN .net? –

+0

Vui lòng chèn một dòng cho biết Console.WriteLine (tổng cộng); sau vòng lặp đầu tiên của bạn. JIT sẽ không thực hiện các nút mà kết quả không được sử dụng sau đó. –

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