Tôi biết bạn đã không yêu cầu (và có thể không cần một bài giảng về cách xử lý thích hợp của bộ nhớ cache, nhưng tôi nghĩ tôi sẽ đóng góp hai xu của mình. Lưu ý rằng tất cả điều này chỉ áp dụng trong mã nóng. Hãy nhớ rằng tối ưu hóa sớm là gốc rễ của tất cả các điều ác.
Như đã được chỉ ra trong các ý kiến, cách tốt nhất là có các thùng chứa dữ liệu thực tế. ngay cả khi bạn phải sao chép một số dữ liệu và/hoặc trả một mức giá để thay đổi kích thước/di chuyển/chống phân mảnh cấu trúc dữ liệu của bạn. một mảng dữ liệu) chỉ trả hết nếu bạn truy cập chúng một cách tuyến tính và tuần tự phần lớn thời gian.
Nhưng chiến lược này có thể không phải lúc nào cũng có thể sử dụng được. Thay cho dữ liệu tuyến tính thực tế, bạn có thể sử dụng các chiến lược khác như sử dụng các trình phân bổ pool và lặp lại qua các nhóm, thay vì trên vectơ giữ các con trỏ. Điều này tất nhiên có những nhược điểm riêng của nó và có thể phức tạp hơn một chút.
Tôi chắc chắn bạn đã biết điều này, nhưng nó lại nhắc đến một trong những kỹ thuật hiệu quả nhất để tận dụng tối đa bộ nhớ cache của bạn là có dữ liệu nhỏ hơn! Trong đoạn mã trên, nếu bạn có thể lấy đi với int16_t
thay vì int32_t
, bạn chắc chắn nên làm như vậy.Bạn nên đóng gói nhiều số bool
s và cờ và enums vào các trường bit, sử dụng các chỉ mục thay vì các con trỏ (đặc biệt trên các hệ thống 64 bit,) sử dụng các giá trị băm cố định trong cấu trúc dữ liệu của bạn thay vì chuỗi, v.v. Bây giờ, về câu hỏi chính của bạn là liệu bộ xử lý có thể theo dõi các con trỏ ngẫu nhiên xung quanh và đưa dữ liệu vào bộ nhớ cache trước khi chúng cần thiết hay không. Ở một mức độ rất hạn chế, điều này xảy ra. Có lẽ bạn biết, CPU hiện đại sử dụng rất nhiều thủ thuật để tăng tốc độ của chúng (tức là tăng tốc độ rút lui lệnh của chúng.) Các thủ thuật như có bộ đệm cửa hàng, thực thi ngoài đơn đặt hàng, đường ống superscalar, nhiều đơn vị chức năng thuộc mọi loại, chi nhánh dự đoán, vv Hầu hết thời gian, các thủ thuật này chỉ giúp CPU tiếp tục thực hiện các hướng dẫn, ngay cả khi các hướng dẫn hiện tại đã bị ngừng hoặc mất quá nhiều thời gian để hoàn tất. Đối với tải bộ nhớ (đó là điều chậm nhất để làm, iff dữ liệu không có trong bộ nhớ cache,) điều này có nghĩa là CPU sẽ nhận được hướng dẫn càng sớm càng tốt, tính toán địa chỉ, và yêu cầu dữ liệu từ bộ điều khiển bộ nhớ. Tuy nhiên, bộ điều khiển bộ nhớ có thể chỉ có một số lượng rất hạn chế các yêu cầu xuất sắc (thường là hai ngày này, nhưng tôi không chắc chắn.) Điều này có nghĩa là ngay cả khi CPU thực hiện các công cụ rất tinh vi để nhìn vào các vị trí bộ nhớ khác (ví dụ: các phần tử của vector posPointers
của bạn) và suy ra rằng đây là địa chỉ của dữ liệu mới mà mã của bạn cần, nó không thể đi xa phía trước vì bộ điều khiển bộ nhớ chỉ có thể có quá nhiều yêu cầu đang chờ xử lý.
Trong mọi trường hợp, AFAIK, tôi không nghĩ rằng CPU thực sự làm điều đó. Lưu ý rằng đây là một trường hợp khó, vì địa chỉ của các vị trí bộ nhớ được phân phối ngẫu nhiên của bạn nằm trong bộ nhớ (ngược với việc đăng ký hoặc tính toán được từ nội dung của thanh ghi.) Và nếu các CPU đã làm, nó sẽ không có rất nhiều hiệu ứng anyways vì giới hạn giao diện bộ nhớ.
Kỹ thuật tìm nạp trước bạn đã đề cập có vẻ hợp lệ đối với tôi và tôi đã thấy nó được sử dụng, nhưng nó chỉ mang lại hiệu quả đáng chú ý nếu CPU của bạn có việc cần làm trong khi chờ dữ liệu trong tương lai đến. Việc tăng thêm ba số nguyên mất ít thời gian hơn nhiều so với việc tải 12 byte từ bộ nhớ (tải một dòng bộ nhớ cache, thực sự) và vì vậy nó không có ý nghĩa nhiều đối với thời gian thực thi. Nhưng nếu bạn có thứ gì đó đáng giá và nặng hơn để phủ lên đầu bộ nhớ tìm nạp trước (ví dụ: tính toán một hàm phức tạp không yêu cầu dữ liệu từ bộ nhớ!) Thì bạn có thể tăng tốc rất tốt. Bạn thấy đấy, thời gian để đi qua vòng lặp trên về cơ bản là tổng thời gian của tất cả các bộ nhớ cache bị mất; và bạn đang nhận được gia số tọa độ và sổ kế toán vòng lặp miễn phí. Vì vậy, bạn sẽ giành được nhiều hơn nếu các công cụ miễn phí có giá trị hơn!
Mã như thế này không có khả năng hoạt động tốt, bộ nhớ cache rất không thân thiện và không tự động vector hóa. Sửa lỗi đơn giản là 'std :: vector', tạo một bản sao. –
Tạo bản sao đó sẽ chỉ là bộ nhớ cache không hiệu quả. Bạn vẫn cần phải thu thập các đối tượng từ khắp nơi trên bộ nhớ. Và nếu kết quả cần được lưu trữ trở lại, làm cho một bản sao thậm chí sẽ tồi tệ hơn. – MSalters