2012-04-03 31 views
8

Hy vọng đây là một bài đăng hợp lệ ở đây, đó là sự kết hợp của các vấn đề và phần cứng C#.Hiệu suất C# khác nhau do bộ nhớ

Tôi đang đánh giá máy chủ của mình vì chúng tôi đã tìm thấy vấn đề với hiệu suất của thư viện lượng tử của chúng tôi (được viết bằng C#). Tôi đã mô phỏng các vấn đề hiệu suất tương tự với một số mã C# đơn giản - thực hiện việc sử dụng bộ nhớ rất nặng.

Mã bên dưới là một hàm được sinh ra từ một luồng, tối đa 32 luồng (vì máy chủ của chúng tôi có 4 nhân CPU x 8 lõi).

Đây là tất cả trên Net 3.5

Vấn đề là chúng ta đang nhận được một cách hoang dại khác nhau thực hiện. Tôi chạy hàm dưới 1000 lần. Thời gian trung bình lấy để chạy mã có thể là 3,5 giây, nhưng tốc độ nhanh nhất sẽ chỉ là 1,2 giây và chậm nhất sẽ là 7 giây cho cùng một hàm chính xác!

Tôi đã vẽ đồ thị sử dụng bộ nhớ so với timings và có doesnt dường như bất kỳ mối tương quan với các GC đá trong.

Một điều tôi đã thông báo là khi đang chạy trong một chủ đề duy nhất timings là giống hệt nhau và có không có độ lệch hoang dã. Tôi cũng đã thử nghiệm các thuật toán liên kết CPU và thời gian cũng giống nhau. Điều này đã làm cho chúng tôi tự hỏi nếu xe buýt bộ nhớ chỉ không thể đối phó.

Tôi băn khoăn rằng đây có phải là vấn đề khác .net hoặc C# hay liên quan đến phần cứng của chúng tôi? Đây có phải là trải nghiệm tương tự nếu tôi đã sử dụng C++ hoặc Java ?? Chúng tôi đang sử dụng 4x Intel x7550 với ram 32GB. Có cách nào xung quanh vấn đề này nói chung không?

Stopwatch watch = new Stopwatch(); 
watch.Start(); 
List<byte> list1 = new List<byte>(); 
List<byte> list2 = new List<byte>(); 
List<byte> list3 = new List<byte>(); 


int Size1 = 10000000; 
int Size2 = 2 * Size1; 
int Size3 = Size1; 

for (int i = 0; i < Size1; i++) 
{ 
    list1.Add(57); 
} 

for (int i = 0; i < Size2; i = i + 2) 
{ 
    list2.Add(56); 
} 

for (int i = 0; i < Size3; i++) 
{ 
    byte temp = list1.ElementAt(i); 
    byte temp2 = list2.ElementAt(i); 
    list3.Add(temp); 
    list2[i] = temp; 
    list1[i] = temp2; 
} 
watch.Stop(); 

(mã là chỉ có nghĩa là để nhấn mạnh ra bộ nhớ)

tôi sẽ bao gồm mã threadpool, nhưng chúng tôi sử dụng một thư viện threadpool phi tiêu chuẩn.

EDIT: Tôi đã giảm "size1" xuống 100000, về cơ bản không sử dụng nhiều bộ nhớ và tôi vẫn nhận được rất nhiều jitter. Điều này cho thấy nó không phải là số lượng bộ nhớ được chuyển giao, nhưng tần số của bộ nhớ lấy?

+0

Có bất kỳ quy trình nào khác đang chạy trong điểm chuẩn của bạn không? Ngay cả hệ điều hành cũng cần thời gian CPU. Nếu bạn đang sử dụng tất cả các lõi ảo trong quá trình benchmark của mình, bạn hầu như không thể đảm bảo rằng các quá trình không liên quan sẽ mất thời gian CPU trong quá trình kiểm tra của bạn. –

+5

Chúng tôi không có đủ thông tin để làm bất cứ điều gì nhưng suy đoán. Điều đó nói rằng, tiền của tôi là trên "thư viện threadpool không chuẩn của bạn" không phân bổ đủ luồng để chạy song song. Nếu bạn chạy 50 bản sao và bạn chỉ phân bổ 20 chủ đề (ví dụ), 10 lần lặp lại sẽ phải đợi (trung bình) cho 2 lần lặp khác để hoàn thành cho một chuỗi để giải phóng. Điều đó có thể giải thích cho những sai lệch mà bạn đang thấy. –

+8

Chỉ cần một ý tưởng: Vì bạn xuất hiện để biết kích thước của danh sách, bạn nên truyền nó cho hàm tạo (hoặc chỉ sử dụng mảng). Sau đó, bạn tránh việc phân bổ lại nếu các mảng bên dưới. –

Trả lời

0

Danh sách sử dụng mảng nội bộ để lưu trữ. Tôi tin rằng nó sẽ cố gắng tăng gấp đôi kích thước của mảng mỗi khi nó đạt đến giới hạn không gian trống trong Danh sách.

Khi bạn đi vào vòng lặp, nó cần khối lớn hơn và lớn hơn của bộ nhớ tiếp giáp để phân bổ các mảng mới khi danh sách phát triển. Với một chủ đề, điều này khá dễ dàng. Với hơn 2 chủ đề, bạn đang cạnh tranh cho một lượng lớn bộ nhớ tiếp giáp. Nó sẽ kích hoạt GC tại các thời điểm ngẫu nhiên vì các mảng có bộ nhớ lớn hơn và tiếp giáp khó tìm hơn.

+0

Xin chào, tôi đã thay đổi Danh sách cho kích thước được xác định trước byte [], với kích thước là 10.000.000 và thời gian cho chức năng hoàn thành hoàn toàn ngẫu nhiên. Nhanh nhất là 462ms, Trung bình là 1192ms và chậm nhất là 2509ms- cao gấp đôi mức trung bình. – mezamorphic

1

Bạn đang gặp các giới hạn máy khá cơ bản ở đây. Bạn có rất nhiều lõi nhưng vẫn chỉ có một bus bộ nhớ. Vì vậy, nếu chủ đề của bạn làm rất nhiều dữ liệu xáo trộn sau đó họ có khả năng nhận được throttled bởi băng thông của xe buýt duy nhất. Đây là luật của Amdahl tại nơi làm việc.

Có một tối ưu hóa có thể, nó phụ thuộc vào loại hệ điều hành mà máy này chạy. Đây là loại phần cứng máy chủ nhưng nếu bạn có phiên bản Windows không phải máy chủ thì trình thu gom rác sẽ chạy ở chế độ máy trạm. Sau đó, bạn có thể sử dụng phần tử <gcServer> trong tệp .config của ứng dụng để yêu cầu phiên bản máy chủ của trình thu thập. Nó sử dụng nhiều đống để các chủ đề sẽ không chiến đấu cho khóa heap GC thường xuyên khi chúng cấp phát bộ nhớ. Ymmv.

0

Hãy chắc chắn rằng cấu hình thời gian chạy có gcserver = true

+0

Điều tra điều đó - nó làm cho quá trình trung bình nhanh hơn nhưng không làm giảm sự thay đổi theo thời gian. – mezamorphic

+0

Tôi sẽ quan tâm để xem kết quả của việc sử dụng parallel.for trong mã của bạn để xem các cuộc gọi không đồng bộ tác động làm cho – Shay

4

Có là không đủ để tiếp tục, nhưng đây là một số khu vực để bắt đầu tìm kiếm:

  • Các biến là kết quả của tình trạng GC nội . GC tự động quản lý kích thước của các hồ khác nhau. Nếu bạn bắt đầu với các kích thước nhóm khác nhau, bạn sẽ nhận được hành vi GC khác nhau trong khi chạy.
  • Mẫu Moire trong quá trình lên lịch chuỗi. Tùy thuộc vào các biến thể ngẫu nhiên trong trình tự chuỗi, bạn có thể có nhiều kiểu tranh chấp thuận lợi hơn hoặc ít hơn. Nếu có bất kỳ chu kỳ nào, điều đó có thể dẫn đến hiệu ứng khuếch đại tương tự như nhiễu giao thoa.
  • Chia sẻ sai. Nếu bạn có hai luồng mà cả hai đều nhấn địa chỉ bộ nhớ đủ gần để được colocated trong bộ nhớ cache của bộ xử lý, bạn sẽ thấy hiệu suất giảm đáng kể vì bộ vi xử lý phải mất rất nhiều thời gian đồng bộ hóa lại bộ đệm của chúng. Tùy thuộc vào cách bạn tổ chức dữ liệu của bạn và phân bổ các luồng để xử lý nó, bạn có thể nhận các mẫu trong chia sẻ sai dựa trên các biến thể lúc bắt đầu.
  • Quy trình khác trong hệ thống đang chiếm thời gian xử lý. Bạn có thể muốn sử dụng thước đo thời gian của chế độ người dùng thay vì thời gian tường. (Có một người truy cập vào đó trong lớp Process ở đâu đó).
  • Máy đang chạy gần với giới hạn bộ nhớ vật lý đầy đủ. Trao đổi vào đĩa xảy ra với một mẫu ngẫu nhiên nhiều hơn hoặc ít hơn.
+1

# 3 thường được gọi là [chia sẻ sai] (http://en.wikipedia.org/wiki/False_sharing). –

+0

@RonWarholic Cảm ơn. Tôi biết có một thuật ngữ cho nó, chỉ không thể nhớ được. –

0

Tại thời điểm này, có vẻ như đoán bất kỳ điều gì đơn giản chỉ là phỏng đoán. Thực sự những gì bạn cần là nhiều thông tin hơn.

tôi sẽ treo lên một hồ sơ hoặc thiết lập một số bộ đếm hiệu suất Windows:

http://support.microsoft.com/kb/300504

Bạn sẽ có thể thêm một số bộ đếm hiệu suất tập trung vào quá trình này. Bạn có thể xem có bao nhiêu chủ đề đang được tách ra, sử dụng bộ nhớ, v.v. Tôi sẽ đưa ra một số gợi ý khác ở đây và đo lường kịch bản mà bạn đang tìm kiếm. Nếu bạn kết xuất dữ liệu hiệu suất truy cập vào tệp csv, bạn thậm chí có thể lập biểu đồ kết quả khá nhanh chóng để có được một số dữ liệu tốt để thực sự nhai. Nếu bạn có thể tìm thấy chỉ số nào đang thay đổi với kịch bản 1.2 và 7s, bạn có thể bắt đầu thực hiện một số phỏng đoán được giáo dục về những gì đang diễn ra và tiếp tục trau dồi.

0

Cuộc gọi đồng bộ tới tài nguyên được chia sẻ, như Bảng điều khiển hoặc Tệp Hệ thống, sẽ làm suy giảm đáng kể hiệu suất, nhưng do ngoại hình của sự vật, mã này chỉ là tối đa CPU và chênh lệch thời gian phải do các quá trình khác yêu cầu thời gian CPU.

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