2009-03-11 25 views
8

Điều bất thường, những hậu quả bất ngờ xảy ra về hiệu năng, bộ nhớ, vv khi chuyển từ chạy các ứng dụng .NET của bạn theo JIT 64 bit so với JIT 32 bit? Tôi quan tâm đến điều tốt, nhưng quan tâm hơn đến những vấn đề tồi tệ đáng ngạc nhiên mà mọi người gặp phải.Cơn đau đầu 32 bit của tôi hiện nay là chứng đau nửa đầu 64bit?!? (hoặc 64bit .NET CLR Runtime issues)

Tôi đang trong quá trình viết một ứng dụng .NET mới sẽ được triển khai ở cả 32bit và 64bit. Đã có nhiều câu hỏi liên quan đến các vấn đề với việc chuyển ứng dụng - Tôi không quan tâm đến số "gotchas" from a programming/porting standpoint. (ví dụ: Xử lý bản địa/COM interop một cách chính xác, các loại tham chiếu được nhúng trong cấu trúc thay đổi kích thước của cấu trúc, v.v.)

Tuy nhiên, tôi nghĩ - Tôi có vấn đề gì khác?

Đã có nhiều câu hỏi và bài đăng trên blog đề cập đến vấn đề này hoặc nhấn một khía cạnh của nó, nhưng tôi chưa thấy bất kỳ điều gì được biên soạn một danh sách các vấn đề.

Cụ thể - Ứng dụng của tôi rất bị ràng buộc CPU và có các mẫu sử dụng bộ nhớ rất lớn (do đó cần 64bit ngay từ đầu), cũng như đồ họa trong tự nhiên. Tôi quan tâm đến những vấn đề tiềm ẩn khác có thể tồn tại trong CLR hoặc JIT đang chạy trên Windows 64 bit (sử dụng .NET 3.5sp1).

Dưới đây là một vài vấn đề tôi hiện đã biết về:

Tôi muốn biết những gì khác, cụ thể, vấn đề người đã phát hiện ra trong JIT trên Windows 64bit, và cũng có thể nếu có bất kỳ giải pháp nào cho hiệu năng.

Cảm ơn tất cả!

---- EDIT -----

Chỉ cần làm rõ -

Tôi biết rằng cố gắng để tối ưu hóa sớm là thường xấu. Tôi biết rằng lần thứ hai đoán hệ thống thường là xấu. Tôi cũng biết rằng tính di động đối với 64bit có vấn đề riêng của nó - chúng tôi chạy và thử nghiệm trên các hệ thống 64 bit hàng ngày để trợ giúp việc này. v.v.

Ứng dụng của tôi, tuy nhiên, không phải là ứng dụng doanh nghiệp tiêu biểu của bạn. Đó là một ứng dụng phần mềm khoa học. Chúng tôi có nhiều quy trình mà ngồi bằng cách sử dụng CPU 100% trên tất cả các lõi (nó cao threaded) cho giờ tại một thời điểm.

Tôi dành nhiều thời gian để lược tả đơn đăng ký và điều đó tạo nên sự khác biệt lớn. Tuy nhiên, hầu hết các profilers vô hiệu hóa nhiều tính năng của JIT, do đó, các chi tiết nhỏ trong những thứ như cấp phát bộ nhớ, nội tuyến trong JIT, vv, có thể rất khó khăn để pin xuống khi bạn đang chạy theo một hồ sơ. Do đó tôi cần câu hỏi.

+0

Chuỗi này sẽ hữu ích hơn rất nhiều (dễ tìm với Google hoặc Stacko-search, v.v.) nếu tựa đề được gọi là thời gian chạy .NET 32 và 64 bit. –

Trả lời

3

Tôi nhớ đã nghe sự cố từ kênh IRC mà tôi thường xuyên gặp phải. Nó tối ưu hóa đi các bản sao tạm thời trong trường hợp này:

EventHandler temp = SomeEvent; 
if(temp != null) 
{ 
    temp(this, EventArgs.Empty); 
} 

Đưa điều kiện cuộc đua trở lại và gây ra ngoại lệ null tham chiếu tiềm năng.

+0

Thú vị .... Việc tối ưu hóa chỉ xảy ra trên JIT 64bit, hay nó cũng xảy ra trên JIT 32bit? –

+0

Không xảy ra ở 32 bit.Đó không phải là cuộc trò chuyện của tôi vì vậy tôi không có cách nào để xác nhận điều này, nhưng cuộc trò chuyện diễn ra trong một giờ tốt, vì vậy trừ khi có một số jitter 64 bit khác xung quanh nó cũng có thể là người bạn đang làm việc trên – Quibblesome

+0

IIRC các jitter 32bit thực sự không phù hợp với spec trong trường hợp này và nó nên được tối ưu hóa trong thời trang này anyway. Nhưng đây là một thủ thuật được sử dụng để ngăn chặn các điều kiện chủng tộc khi bắn các sự kiện và tháo gỡ thông qua các chủ đề khác nhau – Quibblesome

-1

Tôi không phải là quen thuộc với các vấn đề 64-bit, nhưng tôi có một bình luận:

Chúng ta nên quên đi nhỏ hiệu quả, nói rằng khoảng 97% thời gian : sớm tối ưu hóa là gốc của tất cả điều ác. - Donald Knuth

+4

Nhưng luôn có 3% damned ... –

+0

Như tôi đã nói, ứng dụng của tôi cực kỳ bị ràng buộc CPU. Tôi có quy trình với 5 giờ runtimes. Các flipside của bình luận của bạn là 3% thời gian, nó không phải là gốc rễ của tất cả các điều ác. Đưa ra nhận xét của Rico Mariani về điều này - nếu nó chỉ quan trọng 3% thời gian, điều đó có nghĩa là một dòng trong 33 vấn đề mã để tối ưu hóa. –

+0

Trong số tò mò, những vấn đề này vẫn còn được trưng bày nếu bạn nhắm mục tiêu nền tảng 64 bit trong VS thay vì bất kỳ CPU mặc định nào? – Powerlord

1

Hầu hết thời gian Visual Studio và trình biên dịch thực hiện một công việc khá tốt để ẩn các sự cố của bạn. Tuy nhiên, tôi biết một vấn đề lớn có thể phát sinh nếu bạn đặt ứng dụng của mình tự động phát hiện nền tảng (x86 vs x64) và cũng là có bất kỳ phụ thuộc nào trên các dll của bên thứ ba 32 bit. Trong trường hợp này, trên nền tảng 64bit, nó sẽ cố gắng gọi các dll sử dụng các quy ước và cấu trúc 64bit, và nó sẽ không hoạt động.

+0

Vâng - Tuy nhiên, tôi không quá quan tâm đến các loại vấn đề này. Tôi quan tâm nhiều hơn đến các vấn đề về hiệu suất/bộ nhớ/thời gian chạy là các gotchas ẩn. –

+0

+1 - Tôi đã gặp sự cố này với một trong các thư viện của bên thứ ba. Tôi phải bao gồm cả phiên bản 32 và 64 bit trong trình cài đặt của mình và cài đặt phiên bản thích hợp. –

1

Bạn đã đề cập đến các vấn đề về cổng, đó là những vấn đề cần quan tâm. Tôi (rõ ràng) không biết ứng dụng của bạn, nhưng cố gắng đoán JIT thường là một sự lãng phí thời gian hoàn toàn. Những người viết JIT có một sự hiểu biết thân mật về kiến ​​trúc chip x86/x64, và trong tất cả các khả năng biết những gì thực hiện tốt hơn và những gì thực hiện tồi tệ hơn có lẽ bất cứ ai khác trên hành tinh. Có, có thể bạn có trường hợp góc khác biệt và độc đáo, nhưng nếu bạn đang "đang viết một ứng dụng mới" thì tôi sẽ không lo lắng về trình biên dịch JIT. Có thể là một vòng lặp ngớ ngẩn có thể tránh được ở đâu đó sẽ giúp bạn mua 100x hiệu suất cải thiện mà bạn sẽ nhận được từ việc cố gắng đoán JIT lần hai. Nhắc tôi về các vấn đề chúng tôi đã viết vào ORM của chúng tôi, chúng tôi sẽ xem xét mã và nghĩ rằng chúng tôi có thể tweek một vài hướng dẫn máy ra khỏi nó ... tất nhiên, mã sau đó đã tắt và kết nối với một máy chủ cơ sở dữ liệu qua mạng , vì vậy chúng tôi đã cắt nhỏ một phần nghìn giây ra khỏi một quá trình đã bị giới hạn bởi mili giây ở một nơi khác.

quy tắc phổ quát của hoạt động tinh chỉnh ... Nếu bạn chưa đo hiệu suất của bạn, bạn không biết nơi tắc nghẽn của bạn, bạn chỉ cần nghĩ bạn biết ... và bạn đang có khả năng sai.

+0

Walden: Tôi đồng ý. Tuy nhiên, ứng dụng của tôi là VERY CPU BOUND. Đó là toán học cao và có nhiều quy trình thời gian chạy nhiều giờ. Tôi dành rất nhiều thời gian để lập hồ sơ và tối ưu hóa các chi tiết đẹp, có thể hữu ích đáng kể. Tuy nhiên, các trình biên dịch rất khó vì chúng vô hiệu hóa các vấn đề JIT. –

1

Về Quibblesome của câu trả lời:

tôi đã cố gắng để chạy các đoạn mã sau trong Windows 7 x64 của tôi trong chế độ Release mà không cần gỡ lỗi, và NullReferenceException chưa bao giờ được ném.

using System; 
using System.Threading; 

namespace EventsMultithreadingTest 
{ 
    public class Program 
    { 
     private static Action<object> _delegate = new Action<object>(Program_Event); 
     public static event Action<object> Event; 

     public static void Main(string[] args) 
     { 
      Thread thread = new Thread(delegate() 
       { 
        while (true) 
        { 
         Action<object> ev = Event; 

         if (ev != null) 
         { 
          ev.Invoke(null); 
         } 
        } 
       }); 
      thread.Start(); 

      while (true) 
      { 
       Event += _delegate; 
       Event -= _delegate; 
      } 
     } 

     static void Program_Event(object obj) 
     { 
      object.Equals(null, null); 
     } 
    } 
} 
+2

Sự cố này chỉ tồn tại trong .NET 1.x trên x64; nó không phải là một vấn đề kể từ khi mô hình bộ nhớ .NET 2.0 được giới thiệu vào năm 2005; xem http://code.logos.com/blog/2008/11/events_and_threads_part_4.html và http://msdn.microsoft.com/magazine/cc163715.aspx –

0

Tôi tin rằng 64 JIT không được phát triển đầy đủ/được chuyển đến tận dụng các CPU 64 kiến ​​trúc chút như vậy nên nó có vấn đề, bạn có thể nhận được 'mô phỏng' hành vi của hội đồng của bạn mà có thể gây ra vấn đề và bất ngờ hành vi. Tôi sẽ xem xét các trường hợp mà điều này có thể tránh được và/hoặc có thể xem nếu có trình biên dịch 64 C++ tốt để ghi thời gian tính toán và thuật toán quan trọng.Nhưng ngay cả khi bạn gặp khó khăn trong việc tìm kiếm thông tin hoặc không có thời gian để đọc thông qua mã đã được giải mã, tôi chắc chắn rằng việc tính toán nặng bên ngoài mã được quản lý sẽ làm giảm bất kỳ vấn đề nào bạn có thể có hiệu suất tăng lên [chắc chắn bạn đã thực hiện điều này nhưng chỉ cần đề cập :)]

0

Trình tạo hồ sơ không ảnh hưởng đáng kể đến kết quả thời gian của bạn. Nếu chi phí hồ sơ profiler thực sự là "đáng kể" thì có thể bạn không thể giảm tốc độ nhiều hơn mã của mình và nên suy nghĩ về việc xem xét tắc nghẽn phần cứng (đĩa, RAM hoặc CPU?) Và nâng cấp. (Âm thanh như bạn bị ràng buộc CPU, vì vậy đó là nơi bắt đầu)

Nói chung, .net và JIT giải phóng bạn khỏi hầu hết các vấn đề về cổng của 64 bit. Như bạn đã biết, có các hiệu ứng liên quan đến kích thước đăng ký (thay đổi bộ nhớ, marshalling thành mã gốc, cần tất cả các phần của chương trình là bản dựng 64 bit) và một số khác biệt về hiệu suất (bản đồ bộ nhớ lớn hơn, đăng ký nhiều hơn, xe buýt rộng hơn) vv), vì vậy tôi không thể nói cho bạn biết bất cứ điều gì nhiều hơn bạn đã biết trên mặt trận đó. Các vấn đề khác tôi đã nhìn thấy là hệ điều hành chứ không phải là C# - hiện có tổ chức đăng ký khác nhau cho các ứng dụng 64-bit và WOW64, do đó, một số truy cập đăng ký phải được viết cẩn thận. Nó thường là một ý tưởng tồi để lo lắng về những gì JIT sẽ làm với mã của bạn và cố gắng điều chỉnh nó để hoạt động tốt hơn, vì JIT có khả năng thay đổi với .net 4 hoặc 5 hoặc 6 và "tối ưu hóa" của bạn có thể biến thành thiếu hiệu quả, hoặc tệ hơn, lỗi. Cũng nên nhớ rằng JIT biên dịch mã đặc biệt cho CPU mà nó đang chạy, vì vậy có khả năng một sự cải thiện trên PC phát triển của bạn có thể không phải là một cải tiến trên một máy tính khác. Những gì bạn nhận được với việc sử dụng JIT ngày hôm nay trên CPU của ngày hôm nay có thể cắn bạn trong một thời gian năm khi bạn nâng cấp một cái gì đó.

Cụ thể, bạn trích dẫn "thuộc tính không được gạch chân trên x64". Bởi thời gian bạn đã chạy qua toàn bộ codebase của bạn chuyển tất cả các thuộc tính của bạn vào các lĩnh vực, có thể cũng có một JIT mới cho 64 bit có thuộc tính inline. Thật vậy, nó có thể hoạt động tốt hơn mã "workaround" của bạn. Hãy để Microsoft tối ưu hóa điều đó cho bạn.

Bạn đúng là chỉ ra rằng cấu hình bộ nhớ của bạn có thể thay đổi. Vì vậy, bạn có thể cần nhiều RAM hơn, đĩa nhanh hơn cho bộ nhớ ảo và bộ đệm CPU lớn hơn. Tất cả các vấn đề về phần cứng. Bạn có thể giảm hiệu ứng bằng cách sử dụng (ví dụ) Int32 thay vì int nhưng điều đó có thể không tạo ra nhiều khác biệt và có khả năng gây hại hiệu suất (vì CPU của bạn có thể xử lý các giá trị 64 bit gốc hiệu quả hơn các giá trị 32 bit nửa kích thước).

Bạn nói "thời gian khởi động có thể dài hơn", nhưng điều đó có vẻ không liên quan trong một ứng dụng mà bạn nói chạy cho giờ ở CPU 100%.

Vì vậy, bạn thực sự lo lắng về điều gì? Có thể thời gian mã của bạn trên một máy tính 32-bit và sau đó thời gian nó làm nhiệm vụ tương tự trên một máy tính 64-bit. Có sự khác biệt nửa giờ trong hơn 4 giờ chạy không? Hoặc là sự khác biệt chỉ có 3 giây? Hoặc là 64 bit PC thực sự nhanh hơn? Có thể bạn đang tìm kiếm giải pháp cho các vấn đề không tồn tại.

Quay lại lời khuyên thông thường, chung chung hơn. Hồ sơ và thời gian để xác định tắc nghẽn. Xem xét các thuật toán và quy trình toán học bạn đang áp dụng và cố gắng cải thiện/thay thế chúng bằng các quy trình hiệu quả hơn. Kiểm tra xem cách tiếp cận đa luồng của bạn có đang giúp thay vì làm tổn hại đến hiệu suất của bạn (nghĩa là tránh và chờ khóa). Cố gắng giảm phân bổ bộ nhớ/deallocation - ví dụ: tái sử dụng các đối tượng thay vì thay thế chúng bằng các đối tượng mới. Cố gắng giảm thiểu việc sử dụng các cuộc gọi chức năng thường xuyên và các chức năng ảo. Chuyển sang C++ và loại bỏ các chi phí vốn có của bộ sưu tập rác, kiểm tra giới hạn, vv mà .net áp đặt. Hừm. Không có điều gì liên quan đến 64 bit, phải không?

4

Một vấn đề hiệu suất đặc biệt phiền hà trong.NET liên quan đến JIT nghèo:

https://connect.microsoft.com/VisualStudio/feedback/details/93858/struct-methods-should-be-inlined?wa=wsignin1.0

Về cơ bản, nội tuyến và cấu trúc không làm việc tốt với nhau trên x64 (mặc dù rằng trang gợi ý nội tuyến hiện đang làm việc nhưng bản redunant tiếp theo không được loại bỏ, mà âm thanh nghi ngờ cho sự khác biệt nhỏ.

Trong mọi trường hợp, sau khi đấu vật với .NET đủ lâu để giải quyết vấn đề này, giải pháp của tôi là sử dụng C++ cho bất kỳ thứ gì có số lượng lớn. Ngay cả trong trường hợp "tốt" cho .NET, nơi bạn không giao dịch với các cấu trúc và sử dụng mảng nơi kiểm tra giới hạn được tối ưu hóa, nhịp C++ .NET hands down.

Nếu bạn đang làm bất cứ điều gì phức tạp hơn các sản phẩm chấm, ảnh sẽ trở nên tồi tệ hơn rất nhanh; mã .NET còn dài hơn + ít dễ đọc hơn (bởi vì bạn cần phải tự nội tuyến và/hoặc không thể sử dụng generics), và chậm hơn nhiều.

Tôi đã chuyển sang sử dụng Eigen bằng C++: tuyệt đối tuyệt vời, dẫn đến mã có thể đọc và hiệu suất cao; một wrapper C++/CLI mỏng sau đó cung cấp keo giữa công cụ tính toán và thế giới .NET.

Eigen hoạt động theo lập trình meta mẫu; trong việc biên dịch các biểu thức vector thành các chỉ lệnh nội tại SSE và thực hiện rất nhiều vòng lặp liên quan đến bộ nhớ đệm nhanh nhất và sắp xếp lại cho bạn; và mặc dù tập trung vào đại số tuyến tính, nó sẽ làm việc với các số nguyên và các biểu thức mảng không ma trận nữa.

Vì vậy, ví dụ, nếu P là một ma trận, loại công cụ này chỉ hoạt động:

1.0/(P.transpose() * P).diagonal().sum(); 

... mà không phân bổ một biến thể tạm thời chuyển vị của P, và không tính toán toàn bộ sản phẩm ma trận nhưng chỉ có các trường cần thiết.

Vì vậy, nếu bạn có thể chạy trong Full Trust - chỉ cần sử dụng C++ qua C++/CLI, nó hoạt động tốt hơn nhiều.

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