Mục đích của việc căn chỉnh bộ nhớ


195

Phải thừa nhận rằng tôi không nhận được nó. Giả sử bạn có bộ nhớ với từ bộ nhớ có độ dài 1 byte. Tại sao bạn không thể truy cập biến dài 4 byte trong một lần truy cập bộ nhớ trên một địa chỉ không được phân bổ (nghĩa là không chia hết cho 4), như trường hợp có địa chỉ được căn chỉnh?


17
Sau khi thực hiện thêm một số Google tôi đã tìm thấy liên kết tuyệt vời này , điều đó giải thích vấn đề thực sự tốt.
hòm

Kiểm tra bài viết nhỏ này cho những người bắt đầu học bài này: blog.virtualmethodstudio.com/2017/03/memory-alocation-run-fools
darkgaze

3
@ark link bị hỏng
John Jiang

2
@JohnJiang Tôi nghĩ rằng tôi đã tìm thấy liên kết mới ở đây: developer.ibm.com/technology/systems/articles/pa-dalign
ejohnso49

Câu trả lời:


62

Đó là một hạn chế của nhiều bộ xử lý cơ bản. Nó thường có thể được xử lý bằng cách thực hiện 4 lần tìm nạp byte không hiệu quả thay vì tìm nạp một từ hiệu quả, nhưng nhiều nhà xác định ngôn ngữ đã quyết định sẽ dễ dàng hơn khi đặt ngoài vòng pháp luật và buộc mọi thứ phải được căn chỉnh.

Có nhiều thông tin hơn trong liên kết này mà OP phát hiện ra.


310

Hệ thống con bộ nhớ trên bộ xử lý hiện đại bị hạn chế truy cập bộ nhớ ở mức độ chi tiết và căn chỉnh kích thước từ của nó; đây là trường hợp vì một số lý do.

Tốc độ

Bộ xử lý hiện đại có nhiều cấp bộ nhớ đệm mà dữ liệu phải được kéo qua; hỗ trợ các lần đọc byte đơn sẽ làm cho thông lượng của hệ thống con bộ nhớ bị ràng buộc chặt chẽ với thông lượng của đơn vị thực thi (còn gọi là giới hạn cpu); tất cả đều gợi nhớ đến cách chế độ PIO bị DMA vượt qua vì nhiều lý do tương tự trong các ổ đĩa cứng.

CPU luôn đọc ở kích thước từ của nó (4 byte trên bộ xử lý 32 bit), vì vậy khi bạn thực hiện truy cập địa chỉ không được phân bổ - trên bộ xử lý hỗ trợ nó - bộ xử lý sẽ đọc nhiều từ. CPU sẽ đọc từng từ của bộ nhớ mà địa chỉ yêu cầu của bạn đứng. Điều này gây ra sự khuếch đại lên tới 2 lần số lượng giao dịch bộ nhớ cần thiết để truy cập dữ liệu được yêu cầu.

Bởi vì điều này, có thể rất dễ dàng để đọc chậm hơn hai byte so với bốn. Ví dụ: giả sử bạn có cấu trúc trong bộ nhớ trông như thế này:

struct mystruct {
    char c;  // one byte
    int i;   // four bytes
    short s; // two bytes
}

Trên bộ xử lý 32 bit, rất có thể nó sẽ được căn chỉnh như hiển thị ở đây:

Bố cục cấu trúc

Bộ xử lý có thể đọc từng thành viên này trong một giao dịch.

Giả sử bạn đã có một phiên bản đóng gói của struct, có thể từ mạng nơi nó được đóng gói cho hiệu quả truyền dẫn; nó có thể trông giống như thế này:

Cấu trúc đóng gói

Đọc byte đầu tiên sẽ giống nhau.

Khi bạn yêu cầu bộ xử lý cung cấp cho bạn 16 bit từ 0x0005, nó sẽ phải đọc một từ từ 0x0004 và dịch chuyển sang trái 1 byte để đặt nó vào thanh ghi 16 bit; một số công việc phụ, nhưng hầu hết có thể xử lý việc đó trong một chu kỳ.

Khi bạn yêu cầu 32 bit từ 0x0001, bạn sẽ nhận được khuếch đại 2X. Bộ xử lý sẽ đọc từ 0x0000 vào thanh ghi kết quả và dịch chuyển sang trái 1 byte, sau đó đọc lại từ 0x0004 sang thanh ghi tạm thời, chuyển sang phải 3 byte, sau đó chuyển sang ORthanh ghi kết quả.

Phạm vi

Đối với bất kỳ không gian địa chỉ đã cho nào, nếu kiến ​​trúc có thể giả sử rằng 2 LSB luôn bằng 0 (ví dụ: máy 32 bit) thì nó có thể truy cập bộ nhớ gấp 4 lần (2 bit được lưu có thể biểu thị 4 trạng thái riêng biệt) hoặc cùng một lượng của bộ nhớ với 2 bit cho một cái gì đó như cờ. Việc loại bỏ 2 LSB khỏi một địa chỉ sẽ cho bạn căn chỉnh 4 byte; cũng được gọi là một sải chân của 4 byte. Mỗi khi một địa chỉ được tăng lên, nó sẽ tăng bit 2 một cách hiệu quả, chứ không phải bit 0, tức là, 2 bit cuối cùng sẽ luôn tiếp tục 00.

Điều này thậm chí có thể ảnh hưởng đến thiết kế vật lý của hệ thống. Nếu bus địa chỉ cần ít hơn 2 bit, có thể có ít hơn 2 chân trên CPU và 2 dấu vết ít hơn trên bảng mạch.

Nguyên tử

CPU có thể hoạt động trên một từ bộ nhớ được căn chỉnh nguyên tử, có nghĩa là không có lệnh nào khác có thể làm gián đoạn hoạt động đó. Điều này rất quan trọng đối với hoạt động chính xác của nhiều cấu trúc dữ liệu không khóa và các mô hình tương tranh khác .

Phần kết luận

Hệ thống bộ nhớ của bộ xử lý khá phức tạp và liên quan nhiều hơn so với mô tả ở đây; một cuộc thảo luận về cách một bộ xử lý x86 thực sự giải quyết bộ nhớ có thể giúp ích (nhiều bộ xử lý hoạt động tương tự nhau).

Có nhiều lợi ích hơn khi tuân thủ sự liên kết bộ nhớ mà bạn có thể đọc tại bài viết này của IBM .

Sử dụng chính của máy tính là để chuyển đổi dữ liệu. Các kiến ​​trúc và công nghệ bộ nhớ hiện đại đã được tối ưu hóa trong nhiều thập kỷ để tạo điều kiện nhận được nhiều dữ liệu hơn, vào, ra và giữa các đơn vị thực thi nhanh hơn và nhanh hơn theo cách rất đáng tin cậy.

Tiền thưởng: Bộ nhớ cache

Một căn chỉnh khác cho hiệu năng mà tôi đã đề cập trước đây là căn chỉnh trên các dòng bộ đệm (ví dụ, trên một số CPU) 64B.

Để biết thêm thông tin về mức độ hiệu suất có thể đạt được bằng cách tận dụng bộ nhớ cache, hãy xem Thư viện hiệu ứng bộ đệm của bộ xử lý ; từ câu hỏi này về kích thước dòng bộ đệm

Hiểu về các dòng bộ đệm có thể quan trọng đối với một số loại tối ưu hóa chương trình. Ví dụ: căn chỉnh dữ liệu có thể xác định liệu một thao tác có chạm vào một hoặc hai dòng bộ đệm hay không. Như chúng ta đã thấy trong ví dụ trên, điều này có thể dễ dàng có nghĩa là trong trường hợp sai, hoạt động sẽ chậm hơn hai lần.


các chuỗi sau xyz có các kích thước khác nhau, do quy tắc của mỗi thành viên phải bắt đầu bằng địa chỉ là bội số của kích thước của nó và strcut phải được kết thúc bằng địa chỉ là bội số của kích thước lớn nhất của thành viên cấu trúc. cấu trúc x {ngắn s; // 2 byte và 2 đệm tyte int i; // 4 byte char c; // 1 byte và 3 byte đệm dài l; }; cấu trúc y {int i; // 4 byte char c; // 1 byte và 1 byte đệm ngắn s; // 2 byte}; cấu trúc z {int i; // 4 byte ngắn s; // 2 byte char c; // 1 byte và 1 byte đệm};
Gavin

1
Nếu tôi hiểu chính xác, lý do TẠI SAO một máy tính không thể đọc được một từ không được phân bổ trong một bước là vì các phần phụ sử dụng 30 bit chứ không phải 32 bit ??
GetFree

1
@chux Đúng vậy, tuyệt đối không bao giờ giữ. 8088 là một nghiên cứu thú vị về sự đánh đổi giữa tốc độ và chi phí, về cơ bản, nó là một chiếc 8086 16 bit (có đầy đủ bus ngoài 16 bit) nhưng chỉ bằng một nửa các tuyến xe buýt để tiết kiệm chi phí sản xuất. Do đó, 8088 cần gấp đôi chu kỳ đồng hồ để truy cập bộ nhớ so với 8086 vì nó phải thực hiện hai lần đọc để có được từ 16 bit đầy đủ. Phần thú vị, 8086 có thể thực hiện một từ 16 bit được căn chỉnh trong một chu kỳ, các lần đọc không được phân bổ mất 2. Thực tế là 8088 có một nửa bus bị che khuất sự chậm chạp này.
joshperry

2
@joshperry: Hiệu chỉnh nhẹ: 8086 có thể thực hiện đọc 16 bit được căn chỉnh từ trong bốn chu kỳ, trong khi các lần đọc không được sắp xếp mất tám . Do giao diện bộ nhớ chậm, thời gian thực hiện trên các máy dựa trên 8088 thường bị chi phối bởi các lệnh tìm nạp. Một lệnh như "MOV AX, BX" thường nhanh hơn một chu kỳ so với "XCHG AX, BX", nhưng trừ khi nó được đi trước hoặc theo sau bởi một lệnh có quá trình thực thi mất hơn bốn chu kỳ cho mỗi byte mã, sẽ mất bốn chu kỳ lâu hơn hành hình. Trên 8086, việc tìm nạp mã đôi khi có thể theo kịp sự thực thi, nhưng trên 8088 trừ khi người ta sử dụng ...
supercat

1
Rất đúng, @martin. Tôi đã sử dụng các byte đệm để tập trung vào nội dung thảo luận, nhưng có lẽ sẽ tốt hơn nếu đưa chúng vào.
joshperry

22

bạn có thể với một số bộ xử lý ( nehalem có thể làm điều này ), nhưng trước đây tất cả quyền truy cập bộ nhớ được căn chỉnh trên dòng 64 bit (hoặc 32 bit), vì bus rộng 64 bit, bạn phải tìm nạp 64 bit mỗi lần và dễ dàng hơn để tìm nạp chúng trong các "khối" 64 bit được căn chỉnh.

Vì vậy, nếu bạn muốn có được một byte đơn, bạn đã tìm nạp đoạn 64 bit và sau đó che đi các bit bạn không muốn. Dễ dàng và nhanh chóng nếu byte của bạn ở cuối bên phải, nhưng nếu nó ở giữa đoạn 64 bit đó, bạn sẽ phải che đi các bit không mong muốn và sau đó chuyển dữ liệu sang đúng vị trí. Tệ hơn, nếu bạn muốn một biến 2 byte, nhưng nó được chia thành 2 khối, thì điều đó đòi hỏi gấp đôi số lần truy cập bộ nhớ cần thiết.

Vì vậy, như mọi người nghĩ rằng bộ nhớ là rẻ, họ chỉ làm cho trình biên dịch căn chỉnh dữ liệu trên các kích thước khối của bộ xử lý để mã của bạn chạy nhanh hơn và hiệu quả hơn với chi phí bộ nhớ bị lãng phí.


5

Về cơ bản, lý do là vì bus bộ nhớ có một số chiều dài cụ thể nhỏ hơn nhiều so với kích thước bộ nhớ.

Vì vậy, CPU đọc ra khỏi bộ đệm L1 trên chip, thường là 32KB những ngày này. Nhưng bus bộ nhớ kết nối bộ đệm L1 với CPU sẽ có chiều rộng nhỏ hơn rất nhiều của kích thước dòng bộ đệm. Điều này sẽ theo thứ tự 128 bit .

Vì thế:

262,144 bits - size of memory
    128 bits - size of bus

Truy cập không đúng lúc đôi khi sẽ chồng lấp hai dòng bộ đệm và điều này sẽ yêu cầu đọc bộ đệm hoàn toàn mới để có được dữ liệu. Nó thậm chí có thể bỏ lỡ tất cả các cách để DRAM.

Hơn nữa, một số phần của CPU sẽ phải đứng trên đầu của nó để đặt một đối tượng duy nhất ra khỏi hai dòng bộ đệm khác nhau mà mỗi dòng có một phần dữ liệu. Trên một dòng, nó sẽ ở các bit thứ tự rất cao, mặt khác, các bit thứ tự rất thấp.

Sẽ có phần cứng chuyên dụng được tích hợp hoàn toàn vào đường ống xử lý việc di chuyển các đối tượng được căn chỉnh lên các bit cần thiết của bus dữ liệu CPU, nhưng phần cứng như vậy có thể thiếu đối với các đối tượng bị sai lệch, bởi vì có lẽ sẽ hợp lý hơn khi sử dụng các bóng bán dẫn đó để tăng tốc độ tối ưu chính xác các chương trình.

Trong mọi trường hợp, bộ nhớ thứ hai đôi khi cần thiết sẽ làm chậm đường ống cho dù phần cứng có mục đích đặc biệt bao nhiêu (giả định và dại dột) dành riêng để vá các hoạt động bộ nhớ bị sai lệch.


5

@joshperry đã đưa ra một câu trả lời tuyệt vời cho câu hỏi này. Ngoài câu trả lời của anh ấy, tôi có một số con số hiển thị bằng đồ họa các hiệu ứng đã được mô tả, đặc biệt là khuếch đại 2X. Đây là một liên kết đến bảng tính Google cho thấy hiệu ứng của các sắp xếp từ khác nhau trông như thế nào. Ngoài ra, đây là một liên kết đến một ý chính Github với mã cho bài kiểm tra. Mã kiểm tra được điều chỉnh từ bài báo được viết bởi Jonathan Rentzsch mà @joshperry tham chiếu. Các thử nghiệm đã được chạy trên Macbook Pro với bộ xử lý Intel Core i7 64 bit lõi tứ 2,8 GHz và RAM 16 GB.

nhập mô tả hình ảnh ở đây


4
Làm xyphối hợp có nghĩa là gì?
shuva

1
I7 thế hệ nào? (Cảm ơn bạn đã đăng liên kết tới mã!)
Nick Desaulniers

2

Nếu một hệ thống có bộ nhớ có địa chỉ byte có bus bộ nhớ rộng 32 bit, điều đó có nghĩa là có bốn hệ thống bộ nhớ rộng byte hiệu quả, tất cả đều có dây để đọc hoặc ghi cùng một địa chỉ. Việc đọc 32 bit được căn chỉnh sẽ yêu cầu thông tin được lưu trữ trong cùng một địa chỉ trong cả bốn hệ thống bộ nhớ, vì vậy tất cả các hệ thống có thể cung cấp dữ liệu cùng một lúc. Việc đọc 32 bit không được phân bổ sẽ yêu cầu một số hệ thống bộ nhớ trả về dữ liệu từ một địa chỉ và một số để trả lại dữ liệu từ địa chỉ cao hơn tiếp theo. Mặc dù có một số hệ thống bộ nhớ được tối ưu hóa để có thể thực hiện các yêu cầu đó (ngoài địa chỉ của chúng, chúng thực sự có tín hiệu "cộng một" khiến chúng sử dụng địa chỉ cao hơn một chỉ định) như một tính năng làm tăng thêm chi phí đáng kể và sự phức tạp đối với một hệ thống bộ nhớ;


2

Nếu bạn có bus dữ liệu 32 bit, các dòng địa chỉ bus địa chỉ được kết nối với bộ nhớ sẽ bắt đầu từ A 2 , do đó chỉ có thể truy cập các địa chỉ được căn chỉnh 32 bit trong một chu kỳ bus.

Vì vậy, nếu một từ kéo dài một ranh giới căn chỉnh địa chỉ - tức là A 0 cho dữ liệu 16,32 bit hoặc A 1 cho dữ liệu 32 bit không bằng 0, hai chu kỳ bus được yêu cầu để có được dữ liệu.

Một số kiến ​​trúc / bộ hướng dẫn không hỗ trợ truy cập không được phân bổ và sẽ tạo ra ngoại lệ đối với các lần thử đó, vì vậy trình biên dịch tạo mã truy cập không được phân bổ không chỉ yêu cầu các chu kỳ bus bổ sung, mà còn hướng dẫn bổ sung, làm cho nó thậm chí kém hiệu quả hơn.


0

Trên PowerPC, bạn có thể tải một số nguyên từ một địa chỉ lẻ mà không gặp vấn đề gì.

Sparc và I86 và (tôi nghĩ) Itatnium tăng ngoại lệ phần cứng khi bạn thử điều này.

Một tải 32 bit so với bốn tải 8 bit sẽ không tạo ra nhiều khác biệt trên hầu hết các bộ xử lý hiện đại. Liệu dữ liệu đã có trong bộ nhớ cache hay chưa sẽ có ảnh hưởng lớn hơn nhiều.


Trên Sparc, đây là "Lỗi xe buýt", do đó chương "Lỗi xe buýt, đi tàu" trong "Lập trình chuyên gia C: Bí mật sâu sắc" của Peter Van der Linden
jjg
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.