2012-02-20 10 views
5

Có vô số các biến được căn chỉnh trên các ranh giới từ nhanh hơn các phép tính tải chưa được ký trên bộ xử lý x86/64 (Intel/AMD 64 bit) không?Tải từ được căn chỉnh nhanh hơn các tải chưa được căn chỉnh trên bộ vi xử lý x64?

Một đồng nghiệp của tôi cho rằng tải không được căn chỉnh chậm và cần tránh. Ông trích dẫn việc đệm các hạng mục vào các ranh giới từ trong các cấu trúc như là một bằng chứng cho thấy các tải không được sắp xếp là chậm. Ví dụ:

struct A { 
    char a; 
    uint64_t b; 
}; 

Cấu trúc A thường có kích thước 16 byte.

Mặt khác, trạng thái documentation of the Snappy compressor cho biết Snappy giả định rằng "tải và cửa hàng 32 và 64 bit không được ký hiệu là giá rẻ". Theo mã nguồn, điều này đúng với bộ vi xử lý Intel 32 và 64 bit.

Vì vậy: Sự thật ở đây là gì? Nếu và bởi bao nhiêu là tải unaligned chậm hơn? Trong hoàn cảnh nào?

+0

Việc đóng gói cấu trúc mặc định là 8, vì vậy Một thành viên b :: được trong thực tế liên kết. Các thành viên không được sắp xếp có thể nằm trong dòng bộ nhớ cache và điều đó luôn đắt đỏ. –

Trả lời

3

tải Phù hợp là cửa hàng được nhanh hơn, hai trích đoạn từ Intel Optimization Manual sạch điểm này ra:

3,6 tối ưu hóa bộ nhớ truy cập

dữ liệu Align, chú ý đến cách bố trí dữ liệu và sắp xếp ngăn xếp

...

Sự cố liên kết và chuyển tiếp nằm trong số các nguồn phổ biến nhất của sự chậm trễ lớn trên các hệ thống sors dựa trên vi kiến ​​trúc Intel NetBurst.

3.6.4 Alignment

Alignment dữ liệu mối quan tâm tất cả các loại biến:

• Tự động phân bổ biến

• Thành viên của một cấu trúc dữ liệu

• Toàn cầu o r biến địa phương

• Các thông số thông qua trên stack

dữ liệu Không thẳng hàng truy cập có thể phải chịu hình phạt hiệu suất đáng kể. Đây là đặc biệt đúng đối với các chia tách dòng bộ nhớ cache.

Tiếp theo đó là một phần trong 3.6.4, có một quy tắc tốt đẹp cho các nhà phát triển trình biên dịch:

hội/Compiler Mã hóa Quy tắc 45. Nghiêm (H tác động, H tổng quát) Căn dữ liệu trên kích thước toán hạng tự nhiên ranh giới địa chỉ. Nếu dữ liệu sẽ được truy cập với véc tơ lệnh tải và lưu trữ, căn chỉnh dữ liệu trên ranh giới 16 byte.

theo sau là danh sách các quy tắc căn chỉnh và đá quý khác trong 3.6.6

tài khoản/Nguồn Mã hóa Rule 6. (H va chạm, M tính tổng quát) dữ liệu Pad cấu trúc được định nghĩa trong mã nguồn để mỗi phần tử dữ liệu được liên kết đến một toán hạng tự nhiên ranh giới địa chỉ kích cỡ.

Cả hai quy tắc được đánh dấu là cao tác động, có nghĩa là họ rất có thể thay đổi hiệu suất, cùng với các trích đoạn, phần còn lại của mục 3.6 được làm đầy với các lý do khác để tự nhiên sắp xếp dữ liệu của bạn. Nó cũng có giá trị bất kỳ nhà phát triển thời gian để đọc các hướng dẫn sử dụng, nếu chỉ để hiểu phần cứng anh/cô ấy đang làm việc trên.

+0

Nếu bạn có thể đảm bảo rằng tải/cửa hàng không được sắp xếp của bạn không vượt qua ranh giới dòng bộ nhớ cache, sẽ không bị phạt trên Intel hiện đại. (Trên AMD hiện đại, có thể là ranh giới 32 byte hoặc 16 byte). Thông thường, cách dễ nhất để tránh chia tách dòng bộ nhớ cache là liên kết tự nhiên, tuy nhiên, nếu bạn có cấu trúc liên kết 64 byte, thì có trường không được căn chỉnh bên trong nó là tốt. –

5

Một chàng trai ngẫu nhiên trên Internet Tôi đã tìm thấy nói rằng đối với 486 nói rằng một truy cập 32 bit phù hợp có một chu kỳ. Một truy cập 32-bit không được ký kết kéo dài quads nhưng nằm trong cùng một dòng bộ nhớ cache có bốn chu kỳ. Một số không đồng nhất vv mở rộng nhiều dòng bộ nhớ cache có thể mất thêm từ sáu đến mười hai chu kỳ.

Cho rằng truy cập chưa được ký yêu cầu phải truy cập vào nhiều bộ nhớ, khá nhiều theo định nghĩa, tôi hoàn toàn không ngạc nhiên bởi điều này. Tôi muốn tưởng tượng rằng hiệu suất bộ nhớ đệm tốt hơn trên các bộ vi xử lý hiện đại làm cho chi phí ít hơn một chút xấu, nhưng nó vẫn là một cái gì đó để tránh.

(Ngẫu nhiên, nếu mã của bạn có bất kỳ giả định nào về tính di động ... ia32 và hậu duệ là khá nhiều kiến ​​trúc hiện đại duy nhất hỗ trợ truy cập chưa được căn chỉnh. truy cập vào các phần mềm, hoặc chỉ tải giá trị sai, tùy thuộc vào hệ điều hành)

cập nhật: Dưới đây là những người thực sự đã đi và measured it. Trên phần cứng của mình, ông cho rằng truy cập không được sắp xếp bằng một nửa nhanh như đã căn chỉnh. Hãy thử tự mình ...

+0

+1 cho nguồn và liên kết ở cuối –

+0

Một số biến thể ARM gây ra ngoại lệ đối với các truy cập chưa được ký, nhưng các biến thể khác sẽ phân tách chúng thành các phần nhỏ hơn. Trên Cortex M3, một từ (32) tải/lưu trữ trên một nửa (16) ranh giới sẽ được phân tách thành hai phần nửa từ; một tải từ/lưu trữ trên một ranh giới byte sẽ được phân tách thành ba: truy cập hai byte và truy cập từ. Lưu ý rằng không phải tất cả các hướng dẫn đều cho phép truy cập chưa được ký. – supercat

+1

Trên Intel x86 gần đây (Nehalem và mới hơn), các tải và cửa hàng không được chỉ định chỉ có một hình phạt khi bạn vượt qua một dòng bộ nhớ cache (hoặc tệ hơn, một dòng trang). Xem http://agner.org/optimize/ để biết hướng dẫn vi mô với các chi tiết. Nó có thể đáng giá thêm một phần mở đầu cho các vòng lặp, để làm không có giá trị cho đến khi bạn đạt đến một địa chỉ liên kết, do đó vòng lặp chính chạy trên dữ liệu được căn chỉnh, nếu bạn đang xử lý từng byte. –

1

Để sửa lỗi đọc không đúng, bộ xử lý cần thực hiện hai lần đọc được căn chỉnh và sửa kết quả. Đây là chậm hơn so với việc phải đọc một và không sửa chữa.

Mã Snappy có các lý do đặc biệt để khai thác quyền truy cập chưa được ký. Nó sẽ hoạt động trên x86_64; nó sẽ không hoạt động trên các kiến ​​trúc mà truy cập không được ký hiệu không phải là một tùy chọn và nó sẽ hoạt động chậm khi việc sửa lỗi truy cập chưa được ký là một cuộc gọi hệ thống hoặc một hoạt động đắt tiền tương tự. (Trên DEC Alpha, có một cơ chế xấp xỉ tương đương với lời gọi hệ thống để sửa lỗi truy cập chưa được ký và bạn phải bật nó cho chương trình của mình.)

Sử dụng quyền truy cập chưa được ký là quyết định được thông báo rằng tác giả của Snappy đã thực hiện . Nó không làm cho nó hợp lý cho tất cả mọi người để thi đua nó. Các nhà văn biên dịch sẽ được trích dẫn cho hiệu suất kém của mã của họ nếu họ sử dụng nó theo mặc định, ví dụ.

1

Không thể sử dụng tải/cửa hàng không được gán, nhưng lý do không phải là hiệu suất. Lý do là ngôn ngữ C cấm chúng (cả thông qua quy tắc căn chỉnh và quy tắc bí danh) và chúng không hoạt động trên nhiều hệ thống mà không có mã mô phỏng cực kỳ chậm - mã cũng có thể phá vỡ mô hình bộ nhớ C11 cần thiết cho hành vi thích hợp của mã đa luồng, trừ khi nó được thực hiện trên một mức độ hoàn toàn byte-by-byte.

Đối với x86 và x86_64, đối với hầu hết các hoạt động (ngoại trừ một số chỉ lệnh SSE), tải và lưu trữ không được chỉ định, nhưng điều đó không có nghĩa là chúng truy cập nhanh. Nó chỉ có nghĩa là CPU thực hiện mô phỏng cho bạn, và nó có hiệu quả hơn bạn có thể làm được.Ví dụ, một vòng lặp memcpy-type đang thực hiện đọc và ghi kích thước từ không đúng thiết kế sẽ chậm hơn so với cùng một cách memcpy thực hiện truy cập được liên kết, nhưng nó cũng sẽ nhanh hơn việc viết vòng lặp bản sao từng byte của riêng bạn.

+0

Giả sử một người muốn sao chép 64Kbyte dữ liệu trong đó nguồn và đích được căn chỉnh khác nhau. Những gì bạn sẽ xem xét là sự cân bằng giữa (1) bản sao như byte; (2) sắp xếp một trong hai nguồn hoặc đích, và sao chép như longwords với một liên kết và một con trỏ không có dấu; (3) sắp xếp một trong hai nguồn hoặc đích, và thao tác đó như các từ và phần còn lại là byte hoặc nửa; (4) thao tác cả nguồn và đích dưới dạng từ, sử dụng bit dịch chuyển khi cần để kết hợp nguồn và đích. Hãy nhớ rằng những gì nhanh trên CPU của ngày hôm nay có thể chậm vào ngày mai. – supercat

+0

Trừ khi bạn là người triển khai hệ thống, tôi sẽ sử dụng 'memcpy' của hệ thống. Nó có khả năng được sử dụng bất cứ điều gì được biết là nhanh nhất, và có lẽ quan trọng hơn bạn không phải lo lắng rằng trình biên dịch sẽ tìm ra bạn đã phá vỡ các quy tắc bí danh và do đó phá vỡ mã của bạn. –

+0

@R: Điểm công bằng về memcpy trong trường hợp người ta sẽ chỉ sao chép dữ liệu. Điều gì sẽ xảy ra nếu một người sẽ làm điều gì đó phức tạp hơn một chút, ví dụ: tương đương với - giả sử byte-- 'while (n--) * dest ++^= * srC++;' Nếu cả hai đều có sự liên kết giống hệt nhau, rõ ràng việc sử dụng các từ cho hầu hết các thao tác sẽ cho phép tăng tốc lớn, nhưng điều gì sẽ là mô hình hợp lý để mã hóa một điều như vậy? – supercat

0

Truy cập 32 bit và 64 bit không được điều chỉnh là KHÔNG rẻ.

Tôi đã kiểm tra để xác minh điều này. Kết quả của tôi trên Core i5 M460 (64 bit) như sau: loại số nguyên nhanh nhất là 32 bit. Liên kết 64 bit hơi chậm nhưng gần như giống nhau. Liên kết 16 bit và căn chỉnh 8 bit đều chậm hơn đáng kể so với cả liên kết 32 bit và 64 bit. 16 bit chậm hơn so với liên kết 8 bit. Dạng truy cập chậm nhất là truy cập 32 bit không liên kết chậm hơn 3,5 lần so với truy cập 32 bit liên kết (nhanh nhất) và truy cập 32 bit không được ký hiệu thậm chí còn chậm hơn 40% so với truy cập 64 bit chưa được ký.

Kết quả: https://github.com/mkschreder/align-test/blob/master/results-i5-64bit.jpg?raw=true đang Nguồn: https://github.com/mkschreder/align-test