2009-06-16 33 views
8

Tôi có triển khai một lớp X, có hai con trỏ tới hai mẩu thông tin. Tôi đã viết một triển khai mới, lớp Y, chỉ có một con trỏ đến một cấu trúc chứa hai mẩu thông tin với nhau như các thành viên lân cận. Các phương thức của X và Y thường chỉ cần thao tác một phần thông tin, nhưng cung cấp phương thức get() trả về một con trỏ tới phần thứ hai (trong trường hợp này lớp X chỉ trả về con trỏ của nó cho phần đó và lớp Y trả về địa chỉ của thành viên thứ hai của cấu trúc). Trong sử dụng bình thường, các cuộc gọi đến các phương thức của X và Y sẽ xảy ra xen kẽ bởi các cuộc gọi để nhận() và thực hiện công việc trên mảnh thứ hai được trả về. Tôi hy vọng rằng trong các tình huống thực tế cần phải có một cải tiến hiệu suất, bây giờ hai thông tin nằm cạnh nhau trong bộ nhớ trong việc thực hiện lớp Y (vì chúng là các thành viên liền kề của một cấu trúc), nhưng tôi 'không thấy bất kỳ sự khác biệt nào trong các tiêu chuẩn tôi đã viết (xen kẽ các cuộc gọi đến các phương thức của X và Y bằng cách thực hiện công việc trên các phần thứ hai của chúng trong các vòng lớn). Tôi nghi ngờ điều này là bởi vì tất cả mọi thứ phù hợp trong bộ nhớ cache trong cả hai trường hợp trong các bài kiểm tra của tôi. Tôi không muốn thử điều này trong ứng dụng thực sự của tôi bởi vì ngữ nghĩa của X và Y khác nhau theo những cách tinh tế khác không liên quan đến việc tối ưu hóa này và chuyển ứng dụng đang sử dụng sẽ là một số công việc. làm việc ngay từ đầu.C++, cách cải thiện điểm chuẩn trong vùng nhớ đệm?

Cách tốt nhất để quan sát sự khác biệt về hiệu suất do vị trí bộ nhớ cache tốt hơn là gì? Nếu tôi làm một loạt các công việc giả trên một mảng bằng với kích thước của bộ nhớ cache giữa các cuộc gọi là đủ? Hoặc tôi muốn làm việc trên một mảng hơi ít hơn kích thước bộ nhớ cache, để làm việc trên trường hợp của tôi trong lớp học của tôi sẽ gây ra những thứ để rơi vào và ra khỏi bộ nhớ cache? Tôi không chắc chắn làm thế nào để mã một cái gì đó là mạnh mẽ chống lại tối ưu hóa trình biên dịch và kích thước bộ nhớ cache khác nhau.

Trả lời

0

Nếu tôi hiểu rõ tình huống của bạn một cách chính xác (và vui lòng sửa tôi nếu không), thì đó là sáu hoặc một nửa.

Trong lớp X, bạn cần một tra cứu con trỏ cho một phần thông tin. Trong lớp Y, bạn cần một tra cứu cho lần đầu tiên, và hai (lấy giá trị đầu tiên và sau đó bù trừ) cho lần thứ hai. Đó là hy sinh "địa phương" cho một truy cập bộ nhớ khác. Trình biên dịch vẫn còn, thật không may, rất tốt tại lãng phí thời gian xe buýt tìm kiếm các từ trong RAM.

Nếu có thể, bạn sẽ nhận được kết quả tốt nhất bằng cách giữ hai mẩu thông tin đích trực tiếp trong lớp đang được đề cập (tức là mỗi thành viên là lớp riêng), thay vì sử dụng các con trỏ đó cho sự không cần thiết. Không thấy bất kỳ mã nào, đó là tất cả những gì tôi có thể nói.

Ở bất kỳ mức nào, bạn sẽ nhận được hiệu suất cao hơn nhiều so với việc tối ưu hóa hai biến trong định nghĩa lớp học. Ngoài ra, một ý tưởng tuyệt vời là sử dụng công cụ lược tả để xem (khách quan), nơi nút cổ chai của bạn (gprof là phổ biến trên các hệ thống * nix). Có lý do khác biệt nào mà bạn đang tìm cách tăng bộ đệm ẩn cục bộ cụ thể không?

+0

'Tại sao' không thực sự là vấn đề ở đây - câu hỏi khá rõ ràng đối với địa điểm bộ nhớ cache điểm chuẩn. Tôi không nghĩ 'tại sao' lại thực sự thêm bất cứ điều gì vào cuộc thảo luận, và tốt nhất là cho rằng Joseph biết mình đang làm gì. – Justicle

+0

"Tại sao" luôn quan trọng, ít nhất là IMHO. "Tôi hy vọng rằng trong các tình huống thực tế đời sống cần phải có một cải tiến hiệu suất" mà nói với tôi Joseph đang tìm cách để tăng tốc độ. "Tôi không muốn thử điều này trong ứng dụng thực của tôi", điều này cho thấy mục tiêu cuối cùng của anh là hiệu suất tốt hơn và anh cố gắng thực hiện nó thông qua địa phương được cải thiện - đó là lý do tôi đề nghị các khóa học khác để cải thiện hiệu suất. Tuy nhiên, @ Joseph, nếu tôi đã đi sai hướng ở đây, xin vui lòng bỏ qua. ;-) [Và trong trường hợp đó, cachegrind là những gì bạn muốn] –

+0

Tôi đang viết một lớp con trỏ thông minh về cơ bản là thuật toán ít hơn. Tôi đã tối ưu hóa nó với g-prof xuống đến điểm mà mọi thứ như một chi nhánh tồn tại (một if) hoặc một số nguyên phân bổ có thể xác định xem lớp của tôi có đánh bại việc thực thi cũ hay không. Đây là một trong số ít các trường hợp tối ưu hóa vi mô chắc chắn áp dụng;) –

8

Nếu bạn sử dụng Linux, sau đó sử dụng Cachegrind kết hợp với KCacheGrind có thể cung cấp thông tin chi tiết hơn về cách bộ nhớ cache của bạn hoạt động như thế nào.

2

Bạn có thể thiết kế một điểm chuẩn cụ thể để phá vỡ bộ nhớ cache. Ví dụ, phân bổ các khối dữ liệu được chỉ định sao cho tất cả chúng được bảo đảm trên các dòng bộ nhớ cache khác nhau (giả sử, bằng cách sử dụng một bộ cấp phát bộ nhớ tùy chỉnh để phân bổ ít nhất một vài trăm byte). Sau đó lặp đi lặp lại nhiều lần đối với một số đối tượng quá lớn để phù hợp với mọi thứ trong bộ đệm L2 (rất phụ thuộc vào nền tảng, vì nó phụ thuộc vào số lượng dòng trong bộ đệm, nhưng 1 triệu sẽ bao gồm hầu hết các kiến ​​trúc và chỉ yêu cầu vài trăm meg RAM toàn bộ).

Điều này sẽ cho bạn giới hạn trên về mức tăng hiệu suất được thực hiện bởi thay đổi từ X thành Y. Nhưng nó làm giảm hiệu suất của X xuống dưới bất kỳ mức sử dụng thực tế nào. Và để chứng minh trường hợp của bạn, bạn cần một ước tính giới hạn thấp hơn, không phải là ước tính giới hạn trên. Vì vậy, tôi không chắc chắn bạn sẽ đạt được nhiều, trừ khi bạn phát hiện ra rằng ngay cả trường hợp xấu nhất này vẫn không có sự khác biệt đáng kể và bạn không cần phải bận tâm với việc tối ưu hóa. Ngay cả khi bạn không nhằm mục đích cho hiệu suất xấu nhất lý thuyết của X, bất kỳ điểm chuẩn được thiết kế để vượt quá bộ nhớ cache chỉ cần chọn một điểm tùy ý của hiệu suất xấu của X, và tìm kiếm để xem liệu Y có tốt hơn không. Không. Nó không xa gian lận các điểm chuẩn để làm cho Y nhìn tốt. Nó thực sự không quan trọng làm thế nào mã của bạn thực hiện trong tiêu chuẩn tinh ranh, ngoại trừ có thể cho các mục đích tiếp thị nằm văn học.

Cách tốt nhất để quan sát sự khác biệt trong thế giới thực trong hoạt động là đo lường một khách hàng thực tế trong lớp học của bạn. Bạn nói rằng "ngữ nghĩa của X và Y khác biệt theo những cách tinh tế khác không liên quan đến tối ưu hóa này", trong trường hợp này tôi chỉ có thể khuyên bạn nên viết một lớp Z khác với X chỉ liên quan đến tối ưu hóa này và sử dụng trong ứng dụng của bạn như là so sánh.

Khi thử nghiệm của bạn cố gắng thể hiện mức sử dụng thực tế tồi tệ nhất, thì nếu bạn không thấy bất kỳ sự khác biệt nào về hiệu suất, có thể không có hiệu suất nào. Tất cả những gì đã nói, nếu nó có ý nghĩa hợp lý (nghĩa là nó không làm cho mã trở nên đáng kinh ngạc hơn), thì tôi sẽ ủng hộ giảm thiểu số lượng phân bổ đống trong C++ đơn giản như một quy tắc của ngón tay cái. Nó không có xu hướng làm cho tốc độ hoặc sử dụng bộ nhớ tổng số tồi tệ hơn, và nó có xu hướng đơn giản hóa việc xử lý tài nguyên của bạn. Một quy tắc của ngón tay cái không biện minh cho một viết lại mã làm việc, tất nhiên.

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