Giới thiệu
AMD đã cho ra mắt bộ xử lý đầu tiên dựa trên công nghệ này là chip máy chủ Opteron, dựa trên nhân có mật danh là Barcelona năm 2007 .
Không may là các kỹ sư của AMD không thể cung cấp đủ số lượng sản phẩm cần thiết. Có vẻ như chướng ngại chính trên con đường dẫn đến việc tăng tốc độ làm việc là việc bốn nhân chạy với tốc độ cao cùng một lúc sẽ tiêu tốn quá nhiều năng lượng so với mức cho phép của nền tảng TDP. Nhưng qua mỗi lần cải tiến với công nghệ ngày càng phát triển, lượng điện tiêu thụ sẽ ngày càng giảm và hiệu suất làm việc cũng ngày càng cao.
Quý 4 năm 2007, AMD hứa sẽ tăng tốc độ của Opteron lên 2.4-2.5GHz và sẽ sản xuất bộ xử lý công nghệ K10 cho máy tính để bàn.
- Phenom FX (mật danh Agena FX) – 4 nhân, cache 2MB L3, tốc độ tối thiểu: 2.2-2.4GHz, ổ cắm AM2+ Socket, F+;
- Phenom X4 (mật danh Agena) – 4 nhân, cache 2MB L3, tốc độ tối thiểu: 2.2-2.4GHz, ổ cắm AM2+.
Còn đầu năm 2008, AMD hứa sẽ giới thiệu một số những thay đổi “nhỏ” đối với các bộ vi xử lý kiểu mới như:
- Phenom X2 (mật danh Kuma) – 2 nhân, cạce 2MB L3, tốc độ tối thiểu 2.2-2.6GHz, ổ cắm AM2+;
- Athlon X2 (mật danh Rana) – 2 nhân, không có cache L3, tốc độ tối thiểu 2.2GHz, ổ cắm AM2+;
- Sempron (mật danh Spica) – 1 nhân, tốc độ tối thiểu: 2.2-2.4GHz, ổ cắm AM2+.
Nhưng đó là chuyện của tương lai.Còn bây giờ hãy thử xem công nghệ vi cấu trúc của AMD có điểm gì khác biệt so với các công nghệ trước đó. Bài báo này sẽ cố gắng xem xét công nghệ mới này từ mọi khía cạnh và xem chúng có ích lợi gì đối với chúng ta.
Tìm nạp dòng lệnh – Instructions Fetch
Bộ xử lý bắt đầu quá trình mã hoá bằng việc tìm nạp dòng lệnh từ cache lệnh L1 và giải mã chúng.Độ dài của lệnh x86 thường không ổn định nên rất khó xác định giới hạn của chúng trước khi quá trình giải mã bắt đầu. Để đảm bảo rằng việc xác định độ dài lệnh không ảnh hưởng đến tốc độ giải mã, các bộ xử lý K8/K10 sẽ giải mã dòng lệnh trong khi chúng đang được nhập vào cache L1. Thông tin về quá trình giải mã được chứa trong những vùng đặc biệt bên trong cache L1 (3bit thông tin trước khi giải mã cho một byte lệnh). Bằng cách giải mã trước (predecoding) trong khi đang tải lệnh vào cache, phạm vi những lệnh có thể được xác định trong quá trình giải mã, cho phép đảm bảo tốc độ giải mã ổn định không phụ thuộc vào dạng thức và độ dài của lệnh.
Các bộ xử lý tải các khối dòng lệnh từ cache và lấy ra các dòng lệnh mà nó cần gửi cho giải mã. Một chiếc CPU sử dụng công nghệ vi cấu trúc K10 sẽ tìm nạp lệnh từ cache L1 theo các khối 32-byte, còn các bộ xử lý K8 và Core 2 thì nạp lệnh trong các khối 16-byte. Khi đó, tốc độ nạp lệnh đủ nhanh để bộ xử lý K8 và Core 2 có thể gửi được ba dòng lệnh với tốc độ giải mã trung bình là 5 byte mỗi xung nhịp. Tuy nhiên, một số dòng lệnh x86 có thể dài 16 byte và theo một số thuật toán, độ dài của một số dòng lệnh cạnh đó có thể lớn hơn 5 byte. Do đó, không thể giải mã ba dòng lệnh trong một xung nhịp. (Hình 1).
Hình1: Một số dòng lệnh dài liền nhau làm hạn chế tốc độ giải mã trong quá trình tìm nạp dòng lệnh trong khối 16 byte
Cụ thể, SSE2 – một dòng lệnh đơn giản với những phép toán dạng thanh ghi-thanh ghi (ví dụ, movapd xmm0, xmm1 ) – dài 4 byte. Tuy nhiên, nếu dòng lệnh tạo lập bộ nhớ xác định bằng cách sử dụng thanh ghi cơ sở và Offset trống nhưmovapd xmm0, [eax+16] , thì độ dài của nó tăng lên 6 đến 9 byte tùy thuộc vào khoảng Offset . Nếu có các thanh ghi bổ sung trong chế độ 64 bit, vẫn có một REX-prefix một byte thêm vào mã dòng lệnh. Khi đó, độ dài của dòng lệnh SSE2 trong chế độ 64 bit có thể tăng lên thành 7-10 byte. Các lệnh SSE1 thì ngắn hơn 1 byte nếu như đó là lệnh vector (nói cách khác là làm việc với 4 trị số 32 bit). Nhưng nếu nó là một dòng lệnh SSE1 vô hướng (chỉ có một toán hạng), chiều dài của nó cũng có thể tăng đến 7-10 byte trong cùng điều kiện.
Trong trường hợp này, việc tìm nạp các khối 16 byte không phải là giới hạn của bộ xử lý K8, bởi nó không thể giải mã dòng lệnh vector quá 2 lần mỗi xung nhịp. Tuy nhiên, đối với dòng lệnh K10, một xung nhịp 16 byte là giới hạn cuối cùng, vì thế việc tăng kích thước khối lên 32 byte là việc rất cần thiết.
Hơn nữa, các bộ xử lý Core 2 tìm nạp các khối lệnh 16- byte giống như bộ xử lý K8, đó là lý do tại sao chúng có thể giải mã 4 dòng lệnh trong mỗi xung nhịp nếu như độ dài trung bình của dòng lệnh không vượt quá 4 byte. Nếu không, bộ phận giải mã sẽ không thể xử lý 4, thậm chí là 3 dòng lệnh mỗi xung nhịp. Tuy nhiên, các bộ xử lý Core 2 lại có một bộ nhớ đệm trong 64 byte đặc biệt chứa các khối 16 byte được xử lý cuối cùng. Các dòng lệnh được tìm nạp từ bộ nhớ đệm này với tốc độ 32 byte mỗi xung nhịp. Bộ nhớ đệm này cũng giúp thời gian cache ngắn hơn, vượt giới hạn tốc độ thông thường và có thể tiết kiệm đến 1 xung nhịp mỗi lần. Mặc dù mỗi chu kì không thể chứa quá 18 dòng lệnh, 4 nhánh điều kiện và không chứa được một dòng lệnh RET nào cả. .
Dự đoán rẽ nhánh – Brach Prediction
Nếu như chuỗi lệnh móc xích tới nhiều nhánh, CPU sẽ cố dự đoán xa hơn hướng của chương trình để tránh việc đứt đoạn trong quá trình giải mã và chọn lựa giải mã nhánh chắc chắn nhất. Trong trường hợp này, các thuật toán dự đoán nhánh sẽ được sử dụng để tìm nạp khối lệnh tiếp theo. Các bộ xử lý K8 sử dụng thuật toán thích ứng bậc hai để dự đoán nhánh. Thuật toán này xem xét quá trình dự đoán không chỉ trong dòng lệnh hiện thời, mà cả 8 dòng lệnh trước đó. Nhược điểm chính của các thuật toán dự đoán nhánh K8 là chúng không có khả năng dự đoán nhánh gián tiếp có địa chỉ không cố định.
Nhánh gián tiếp là các nhánh sử dụng một con trỏ (Pointer) được tính toán động trong suốt quá trình xử lý mã chương trình. Các nhánh động này thường được thêm vào các lệnh Case trong chương trình dịch và được sử dụng trong suốt quá trình để gọi hàm địa chỉ vàhàm ảo trong việc lập trình hướng tới đối tượng. Các bộ xử lý K8 thường cố sử dụng địa chỉ nhánh cuối cùng để tìm nạp một nhóm mã. Nếu như địa chỉ đó đã thay đổi thì Pipe giải mã sẽ hoàn toàn trống rỗng. Còn nếu địa chỉ nhánh thường xuyên thay đổi thì hệ điều hành sẽ liên tục mắc lỗi. Việc dự đoán địa chỉ không cố định đối với nhánh gián tiếp được sử dụng lần đầu tiên trong bộ xử lý Pentium M. Do trong CPU K8 không có những thuật toán như vậy nên những CPU này cũng hoạt động kém hiệu quả hơn trong các mã định hướng đối tượng.
Như chúng ta đã dự đoán, K10 có những thuật toán dự đoán nhánh được cải tiến như sau:
- Nó có những thuật toán dành cho địa chỉ nhánh không cố định. Thuật toán này sử dụng một bảng gồm 512 yếu tố.
- Thanh ghi sự kiện tăng từ 8 lên 12 bit. Nó có nhiệm vụ xác định tính kế tiếp cho những lệnh rẽ nhánh trước đó .
- Kích cỡ Ngăn xếp (Stack) địa chỉ trả về tăng từ 12 lên 24 vị trí. Stack này dùng để nhanh chóng thu nhận các địa chỉ trả về để việc tìm nạp diễn ra liên tục và không cần phải đợi lệnh RET nhận địa chỉ trả về Stack nữa.
Các cải tiến trên có thể giúp K10 xử lý chương trình viết bằng mã định hướng đối tượng bậc cao nhanh chóng hơn. Nhưng rất khó để tính toán một cách khách quan hiệu quả của việc dự đoán nhánh 10K. Theo một số dữ liệu, hiệu quả của chúng có thể thấp hơn bộ xử lý của Intel trong một số trường hợp.
Giải mã – Decoding
Các khối lệnh nhận được từ cache lệnh được sao chép vào bộ nhớ đệm tạm thời Predecode/Pick , nơi các dòng lệnh được chọn ra từ các khối, định dạng, và chuyển vào các bộ phận ( Pipe ) giải mã tương ứng. Các lệnh đơn giản có thể được giải mã chỉ bằng một hoặc hai vi lệnh ( Micro-Operation hay được ghi Micro-Ops ) sẽ được gửi đến một bộ phận giải mã đơn giản có tên DirectPath . Còn các dòng lệnh phức tạp hơn, yêu cầu từ 3 phép toán trở lên, sẽ được gửi vào bộ phận giải mã vi chương trình được gọi là VectorPath .
Bộ phận giải mã
Cứ mỗi xung nhịp, có tối đa 3 Macro-Operation (MOP) được ra khỏi bộ phận giải mã. Trong mỗi xung nhịp, bộ phận giải mã DirectPath có thể xử lý 3 lệnh 1-MOP đơn giản hoặc một lệnh 2-MOP và một lệnh 1-MOP, hoặc 1.5 lệnh 2-MOP (ba lệnh 2 MOP trong hai xung nhịp). Nhưng việc giải mã các lệnh phức tạp phải cần đến hơn 3 MOP, đó chính là lý do tại sao phải cần đến vài xung nhịp mới giải mã đầy đủ được chúng. Để tránh xung đột khi rời Pipe giải mã , K8 và K10 những lệnh đơn giản và phức tạp có thể được gửi liên tục để giải mã .
Các MOP gồm hai vi lệnh ( Micro-Ops ) : một phép tính số nguyên hay một phép tính số học dấu phẩy động và một yêu cầu địa chỉ bộ nhớ. Các vi lệnh được lấy ra từ các MOP bằng một bộ phận phân phát ( Scheduler ) , sau đó chúng được gửi để thực hiện một cách độc lập .
Các MOP rời khỏi bộ giải mã trong một xung nhịp lại được kết hợp vào các nhóm ba, đôi khi là hai, hoặc thậm chí chỉ có 1 MOP bởi các lệnh DirectPath và VectorPath hay các khoảng thời gian trễ khác nhau trong việc chọn lệnh để giải mã. Một nhóm không hoàn thiện như vậy cần phải bổ sung thêm các MOP rỗng để đủ 3 MOP, sau đó sẽ được chuyển đi xử lý.
Các lệnh vector SSE, SSE2 và SSE3 trong bộ xử lý K8 được chia làm các cặp MOP chuyên xử lý riêng rẽ nửa trên và nửa dưới 64 bit trong thanh ghi SSE 128 bit bằng thiết bị 64 bit. Điều này làm thời gian hoàn thành quá trình giải mã tăng lên gấp đôi, và giảm số dòng lệnh chờ xuống 1 nửa.
Nhờ FPU 128 bit trong các bộ xử lý K10, không cần phải chia các lệnh vector SSE thành 2 MOP nữa. Phần lớn các dòng lệnh SSE mà K8 sử dụng để giải mã như DirectPath Double đều đã được giải mã trong K10 như DirectPath Single trong 1 MOP. Hơn nữa, một số lệnh SSE thường được giải mã bằng bộ phận giải mã VectorPath của K8, giờ đã có thể giải mã trong K10 với bộ giải mã đơn giản DirectPath và ít MOP hơn: chỉ có 1 hoặc 2 MOP tuỳ theo phép toán.
Việc giải mã lệnh stack cũng đã được đơn giản hoá. Phần lớn các lệnh stack thường được dùng trong hàm CALL-RET và PUSH-POP giờ đây đều có thể được xử lý bởi một bộ phận giải mã đơn giản với 1 MOP. Không chỉ có vậy, phương pháp Sideband Stack Optimizer đặc biệt đã chuyển hoá các lệnh này thành một chuỗi các vi lệnh mà có thể thực hiện song sông với nhau .
Sideband Stack Optimizer
Các bộ phận giải mã trong các bộ xử lý K10 kiểu mới có một khối đặc biệt có tên Sideband Stack Optimizer. Nguyên tắc hoạt động của nó cũng tương tự như Stack Pointer Tracker trong bộ xử lý Core. Vậy tại sao chúng ta cần đến nó? Hệ thống x86 sử dụng lệnh CALL, RET, PUSH và POP để lập hàm, xoá hàm, chuyển tham số và giữ lại những nội dung liên quan tới những thanh ghi. Tất cả những lệnh này sử dụng thanh ghi ESP để gián tiếp xác định giá trị Stack-Pointer hiện thời. Khi bạn sử dụng một hàm trong bộ xử lý K8, bạn có thể thực hiện quá trình xử lý lệnh bằng cách thiết lập quá trình giải mã như một chuỗi các phép tính đơn giản.
Lệnh
|
Phép tính tương ứng
|
// hàm (x, y, z);
push X push Y push Z call func |
sub esp, 4; mov [esp], X
sub esp, 4; mov [esp], Y sub esp, 4; mov [esp], Z sub esp, 4; mov [esp], eip; jmp func |
push esi
push edi mov eax, [esp+16] …….. pop edi, pop esi ret |
sub esp, 4; mov [esp], esi
sub esp, 4; mov [esp], edi mov eax, [esp+16] ………….. mov edi, [esp]; add esp, 4 mov esi, [esp]; add esp, 4 jmp [esp]; add esp, 4 |
add esp, 12
|
add esp, 12
|
Trong ví dụ trên, khi sử dụng một hàm nào đó, các lệnh sẽ không ngừng thay đổi thanh ghi ESP, vì vậy mỗi lệnh tiếp theo chỉ đơn giản là dựa trên kết quả của lệnh trước đó. Các lệnh trong chuỗi này không thể được sử dụng lại, đó là lý do tại sao hàm mở đầu bằng mov eax, [esp+16] không thể bắt đầu trừ khi lệnh PUSH trước đó đã được thực hiện. Sideband Stack Optimize sẽ lần theo sự thay đổi trạng thái Stack ( Ngăn xếp ) và biến đổi chuỗi lệnh thành một chuỗi độc lập bằng cách điều chỉnh khoảng trống Stack đối với mỗi lệnh và đặt các phép tính MOP đồng bộ (phần cuối cùng của quá trình đồng bộ hoá stack) trước các lệnh làm việc trực tiếp với thanh ghi stack. Bằng cách này, các lệnh làm việc trực tiếp với Stack có thể được sử dụng lại vô giới hạn.
Lệnh
|
Phép tính tương ứng
|
|
// hàm (x, y, z);
push X push Y push Z call func |
mov [esp-4], X
mov [esp-8], Y mov [esp-12], Z mov [esp-16], eip; jmp func |
|
push esi
push edi mov eax, [esp+16] |
mov [esp-20], esi
mov [esp-24], edi sub esp, 24 mov eax, [esp+16] ………….. mov esi, [esp] mov edi, [esp+4] jmp [esp+8] |
sync-MOP |
add esp, 12
|
add esp, 12
add esp, 12 |
sync-MOP
|
Lệnh mov eax, [esp+16] bắt đầu bằng việc tính toán hàm trong ví dụ trên phụ thuộc vào phép tính MOP đồng bộ. Giờ đây các phép tính này có thể được thực hiện đồng thời sau các lệnh trước đó. Như vậy, việc giải quyết các tham số và tiết kiệm thanh ghi diễn ra nhanh hơn và hàm số có thể bắt đầu tải các tham số trên rồi xử lý chúng trước cả khi tất cả đã được chuyển đổi thành công và việc tiết kiệm thanh ghi đã hoàn tất.
Vì vậy, với việc giải mã phép tính nhanh hơn, Sideband Stack Optimizer, stack địa chỉ trả về lớn hơn và việc dự đoán thành công nhánh động khiến cho K10 hoạt động tốt hơn nhiều trong việc xử lý mã nhiều hàm số.
Bộ phận giải mã trong K10 sẽ không thể giải mã 4 lệnh trong mỗi xung nhịp giống như trong bộ xử lý Core 2 trong điều kiện thuận lợi, nhưng đây không phải là vấn đề lớn trong việc xử lý chương trình. Tốc độ xử lý lệnh trung bình hiếm khi đạt đến con số ba trong mỗi xung nhịp, vì thế bộ phận giải mã của K10 cũng đủ hiệu quả cho các thiết bị điện toán bởi chúng không thiếu bất kỳ lệnh nào, và vì thế có thể hoạt động liên tục.
Bộ phận điều khiển lệnh – Instruction Control Unit (ICU)
Bộ ba MOP đã được giải mã sẽ đến Bộ phận điều khiển lệnh (ICU) để chuyển đến bộ nhớ đệm sắp xếp lại (ROB- ReOrder Buffer ). Bộ nhớ đệm này bao gồm 24 dòng, mỗi dòng có 3 MOP. Mỗi bộ ba MOP được viết trong một dòng. Vì vậy, ROB cho phép bộ phận quản lý lệnh nắm được trạng thái của tối đa 72 MOP cho đến khi chúng ngừng hoạt động.
Từ bộ nhớ đệm ROB này, những MOP được gửi nhanh đến Bộ phận cấp phát ( Scheduler ) của những Bộ phận xử lí số nguyên và dấu phẩy động sắp hàng theo đúng thứ tự như vậy. Đến lúc này, MOP sẽ ngưng hoạt động trong bộ phận giải mã. Các bộ ba MOP sẽ được lưu trữ trong ROB cho đến khi tất cả các phép tính cũ hơn đều đã được xử lý và chấm dứt hoạt động. Khi ngừng hoạt động, những trị số cuối cùng sẽ được ghi lại trong những thanh ghi cấu trúc và bộ nhớ. Còn thứ tự chương trình, cách sắp xếp phép tính trong ROB, vẫn được giữ nguyên khi các phép tính đã chấm dứt, dữ liệu của chúng bị xoá khỏi ROB nhưng các trị số cuối cùng vẫn được giữ lại. Việc đảm bảo rằng kết quả của tất cả các phép tính sau này được hoàn thành trước thời hạn có thể bị xoá trong một số trường hợp ngoại lệ hoặc ngắt.
Bộ phận xử lý số nguyên – Interger Execution Unit
Bộ phận xử lý số nguyên của các bộ xử lý K8 và K10 gồm ba Pipe số nguyên đối xứng. Mỗi Pipe này có bộ phận Scheduler riêng với một hàng đợi 8-MOP, một bộ đơn vị số học và logic (ALU – Arithmetic and Logical Unit ), một đơn vị tạo địa chỉ (AGU – Address Generation Unit ) và một đơn vị dự đoán rẽ nhánh. Ngoài ra, còn có một đơn vị nhân nối với Pipe 0, còn Pipe 2 thì được nối với đơn vị xử lý các phép tính mới: LZCNT và POPCNT mà chúng ta sẽ tìm hiểu kỹ hơn trong phần sau của bài báo này.
Bộ phậnxử lý số nguyên
Lựa chọn hàng đợi cho mỗi MOP tuỳ thuộc vào vị trí cố định của lệnh trong bộ ba. Mỗi Macro-Operation trong bộ ba lại được gửi đến Bộ đệm sắp xếp lại (ROB) để xử lý trong đó . Một mặt, nó giúp đơn giản hoá việc quản lý lệnh, nhưng mặt khác, nó có thể dẫn đến việc hàng đợi bị mất cân bằng nếu như một chuỗi phép tính độc lập được xếp đặt không thích hợp trong mã chương trình (trong thực tế điều này hiếm khi xảy ra và cũng ít ảnh hưởng đến hiệu quả làm việc). Bộ phận giải mã sẽ sắp đặt phép nhân và mở rộng các phép tính Bit mở rộng trong nhóm bộ ba tương ứng để chúng được chuyển đến Pipe thích hợp.
Như đã đề cập từ trước, các MOP sẽ được tách làm các phép tính số nguyên và phép tính địa chỉ bộ nhớ trong hàng đợi Scheduler của Pipe số nguyên. Dựa vào từng dữ liệu, Scheduler có thể chuyển một phép tính số nguyên sang ALU và một phép tính địa chỉ sang AGU từ mỗi hàng đưọi . Có tối đa hai yêu cầu bộ nhớ đồng thời. Vì vậy, nhiều nhất là ba phép tính số nguyên và 2 phép tính bộ nhớ (64 bit được đọc/viết) được xử lý trong mỗi xung nhịp. Còn các Micro-Operation từ nhiều MOP khác nhau có thể được xử lý không theo thứ tự mà tuỳ thuộc vào dữ liệu sẵn sàng. Ngay khi phép tính vi lệnh ( Micro-Ops ) số học và MOP đã được xử lý, MOP sẽ rời khỏi hàng đợi lập Scheduler nhường chỗ cho các phép tính khác.
Các bộ xử lý K8 sẽ chọn phép tính Micro-Ops đòi hỏi địa chỉ bộ nhớ theo mức độ chương trình. Các yêu cầu bộ nhớ xuất hiện sau trong mã chương trình không thể được xử lý trước những phép tính trước đó. Vì thế, nếu như các phép tính trước chưa được thực hiện, tất cả những phép tính địa chỉ sau đó cũng không thể tiến hành ngay cả khi các toán hạng đã sẵn sàng.
Ví dụ:
add ebx, ecx
mov eax, [ebx+10h] – Phép tính nhanh địa chỉ
mov ecx, [eax+ebx] – địa chỉ phụ thuộc vào kết quả của lệnh trước đó
mov edx, [ebx+24h] – lệnh này sẽ không được gửi đi thực hiện cho đến khi tất cả địa chỉ của các lệnh trước đó đã được tính toán xong.
mov eax, [ebx+10h] – Phép tính nhanh địa chỉ
mov ecx, [eax+ebx] – địa chỉ phụ thuộc vào kết quả của lệnh trước đó
mov edx, [ebx+24h] – lệnh này sẽ không được gửi đi thực hiện cho đến khi tất cả địa chỉ của các lệnh trước đó đã được tính toán xong.
Việc này có thể ảnh hưởng đến tốc độ xử lý của K8 do bị “thắt nút cổ chai” . Do đó, mặc dù bộ xử lý K8 có thể tiến hành hai lệnh mỗi xung nhịp, trong một số mã nhất định, nó có thể thực hiện đòi hỏi bộ nhớ kém hiệu quả hơn bộ xử lý Core 2, chỉ đọc được một lệnh mỗi xung nhịp, nhưng lại áp dụng quy tắc xử lý lệnh không theo thứ tự và có thể đọc hoặc ghi trước các lệnh trước đó.
Các CPU sử dụng công nghệ vi cấu trúc K10 sẽ không gặp phải tình trạng này nữa. Giờ đây các bộ xử lý K10 không chỉ có khả năng đọc lệnh không theo thứ tự, mà còn có thể viết lệnh trước khi đọc nếu như CPU chắc chắn rằng không có xung đột địa chỉ xảy ra giữa việc viết lệnh và đọc lệnh. Bằng cách viết lệnh trước khi đọc, bộ xử lý có thể tăng đáng kể tốc độ xử lý một số loại mã, ví dụ như bắt đầu quá trình đọc bằng một dữ liệu đọc từ bộ nhớ, và kết thúc bằng việc viết kết quả tính toán vào bộ nhớ.
L1:
mov eax, [esi] // đang tải dữ liệu
…..// đang xử lí dữ liệu
mov [edi] , eax // đang lưu trữ kết quả
cmp
jnz L1
mov eax, [esi] // đang tải dữ liệu
…..// đang xử lí dữ liệu
mov [edi] , eax // đang lưu trữ kết quả
cmp
jnz L1
Trong những trường hợp như thế này, bộ xử lý không thể đọc dữ liệu trước khi viết hay bắt đầu quá trình xử lý tiếp theo trước khi kết quả của quá trình hiện tại vẫn chưa được ghi hết vào bộ nhớ. Loại CPU hỗ trợ việc sắp xếp lại dữ liệu đọc có thể bắt đầu tải dữ liệu mới cho vòng xử lý tiếp theo mà không phải đợi lần xử lý này kết thúc.
Không may là bộ xử lý K10 lại không thể bắt đầu quá trình tải trước dữ liệu khi chưa hoàn thành việc viết dữ liệu nếu như vẫn chưa biết được địa chỉ như bộ xử lý Core 2. Mặc dù việc này có thể gây ra một số lỗi, nhưng việc này rất hiếm khi xảy ra trong mã chương trình thực tế (chỉ khoảng 5%). Dó là lý do tại sao việc tải trước dữ liệu rất thích hợp cho việc tăng tốc độ làm việc của bô xử lý.
Ngoài ra, một cải tiến khác của đơn vị số nguyên K10 là sự tối ưu hoá thuật toán chia số nguyên. Hiện tại, tốc độ của các phép tính chia số nguyên tuỳ thuộc vào bit lớn nhất của số chia và số bị chia. Ví dụ, nếu số bị chia bằng 0, phép chia sẽ thực hiện mất khoảng 1 nửa thời gian. Thực ra, phép chia số nguyên là một phép tính rất ít dùng bởi chúng thực hiện khá chậm, nên mã lập trình thường tránh sử dụng chúng. Phép chia thường được thay thế bằng phép nhân nghịch đảo, đó là lý do tại sao việc tối ưu hoá này thường không ảnh hưởng nhiều tới tốc độ xử lý chung của ứng dụng.
Nói chung, đơn vị số nguyên của K10 cũng không phải là hoàn hảo. Sau khi thêm vào quá trình xử lý đòi hỏi bộ nhớ không theo thứ tự, chúng sẽ không gặp phải những vẫnđề như trên nữa. Mặc dù K10 không có hàng chờ lớn như Core 2, nó lại có khả năng đọc file thanh ghi cũng như lập biểu vô giới hạn, điều mà Core 2 không thể thực hiện được với tốc độ tối đa.
Bộ phận dấu phẩy động – Floating Point Unit
Bộ phận Scheduler đơn vị dấu phẩy động (FPU) của các bộ xử lý K8 và K10 được tách riêng khỏi bộ phận Scheduler đơn vị số nguyên và có thiết kế khác đi một chút. Bộ nhớ đệm của Scheduler có thể cung cấp tối đa 12 nhóm, mỗi nhóm gồm 3 MOP (theo lý thuyết là 36 phép tính dấu phẩy động). Khác với Bộ phận số nguyên có các Pipe đối xứng, FPU gồm có ba phần khác nhau: FADD cho phép cộng dấu phảy động , FMUL cho phép nhân dấu phảy động và FMISC (còn được gọi là FSTORE) cho các phép tính lưu trong bộ nhớ và phép tính bổ trợ. Do đó, bộ nhớ đệm Scheduler không cố định rõ các MOP vào từng nhóm trong một khác nhau ( theo hình dưới )
Đơn vị dấu phẩy động
Mỗi xung nhịp, K8 và K10 có thể gửi một phép tính đến đơn vị dấu phẩy động để xử lý. Bộ xử lý K8 sử dụng đơn vị dấu phẩy động 80 bit. Tại phần giải mã, các lệnh vector SSE 128 bit sẽ được tách làm hai MOP xử lý hai nửa 64 bit của một toán hạng 128 bit. Các MOP này sẽ được xử lý lần lượt tại các xung nhịp khác nhau. Điều này không chỉ làm chậm tiến độ xử lý lệnh vector, mà còn làm giảm kích thước của bộ nhớ đệm Scheduler FPU xuống một nửa, và do đó giảm hiệu quả việc xử lý lệnh không theo thứ tự.
Chiếu rộng của đơn vị bộ nhớ đệm trong bộ xử lý K10 được tăng lên tới 128 bit. K10 có thể xử lý các toán hạng vector 128 bit trong một phép tính đơn, giúp tăng gấp đôi (theo lý thuyết) tốc độ xử lý lệnh vector SSE so với K8. Hơn nữa, do lượng MOP hiện giờ đã giảm xuống một nửa, độ dài của hàng đợi Scheduler sẽ tăng lên, giúp tăng hiệu quả của việc xử lý không theo thứ tự ( OOO : Out-Of- Order ) được sâu hơn .
Bộ xử lý K8 thực hiện tải những lệnh SSE bằng cách sử dụng Bộ phận FSTORE. Một mặt, nó không cho phép xử lý cùng lúc bất kỳ lệnh nào khác cần sử dụng Bộ phận này. Mặt khác, nó chỉ cho phép một lần tải lệnh cùng lúc. K8 chỉ có thể đọc song song hai lệnh cùng lúc nếu một trong số các lệnh đó kết hợp một phép tính bộ nhớ và một phép tính dữ liệu (còn gọi là lệnh Load-Execute), ví dụ như ADDPS xmm1, [esi].
Theo dự kiến, các bộ xử lý K10 sẽ cải thiện quá trình tải những lệnh SSE.
Đầu tiên, các lệnh tải dữ liệu sẽ không sử dụng tài nguyên trong FPU nữa. Bằng cách này, cổng FSTORE sẽ trống và có thể dùng để thực hiện các lệnh khác. Hai lệnh đã tải hiện tại đã có thể xử lý trong một xung nhịp.
Thứ hai, nếu như dữ liệu trong bộ nhớ được xết trong khối 16 byte, thì việc tài dữ liệu tự do (MOVU**) cũng hiệu quả như việc tải dữ liệu đã sắp xếp (MOVA**). Vì vậy, việc sử dụng MOVA** không còn là lợi thế đối với các bộ xử lý K10 nữa.
Thứ ba, các bộ xử lý K10 giờ đã có thể tiến hành tải dữ liệu tự do ngay cả đối với lệnh Load-Execute. Nếu vẫn chưa rõ dữ liệu trong bộ nhớ đã được xếp vào từng khối chưa, người lập trình thường sử dụng lệnh MOVU** để đọc dữ liệu vào thanh ghi để xử lý thêm. Bằng cách tải dữ liệu tự do cùng với lệnh Load-Execute, họ có thể giảm đáng kể số lệnh đã tải trong mã chương trình, và do đó, tăng tốc độ xử lý. Tính năng này sẽ rất có ích cho các lập trình viên. Thực ra, Intel cho rằng một yêu cầu từ lệnh Load-Execute chuyển đến một địa chỉ chưa được sắp xếp vào khối 16 byte là trường hợp ngoại lệ. Để giữ vững tính tương thích, các dữ liệu tự do và lệnh Load-Execute nên được gắn dấu hiệu đặc biệt trong mã chương trình được thiết kế và xếp vào các tính năng xử lý mới.
Thứ 4, hai bus dữ liệu từ cache L1 của bộ xử lý K10 đã được tăng lên thành 128 bit. Do đó, CPU có thể đọc hai khối dữ liệu 128 bit trong mỗi xung nhịp. Đây là điều rất đặc biệt bởi 2 lệnh lại cần 4 toán hạng mới có thể được xử lý song song cùng một lúc (hai toán hạng mỗi lệnh), và trong một số thuật toán xử lý dữ liệu, thường thì hai trong số bốn toán hạng sẽ được đọc từ RAM. Trái lại, hai bus viết dữ liệu trong bộ xử lý K10 vẫn rộng 64 bit lại được chia làm hai gói 64 bit khi ghi vào bộ nhớ. Vì vậy, trong mỗi xung nhịp, CPU chỉ có thể viết hoặc đọc 128 bit, hay đọc 128 bit và viết 64 bit. Tuy nhiên, do số dữ liệu đọc thường gấp ít nhất hai lần dữ liệu viết, nên giới hạn này không ảnh hưởng đến hiệu quả của bộ xử lý đối với dữ liệu 128 bit.
Thứ 5, việc copy dữ liệu 128 bit, thanh ghi-thanh ghi MOV*** giờ đây đã có thể thực hiện được trong bất cứ đơn vị nào trong ba đơn vị FPU chứ không chỉ trong FADD và FMUL nữa. Do vậy nó cũng giải phóng các đơn vị FADD và FMUL cho các phép tính khác.
Như chúng ta thấy, FPU của bộ xử lý K10 đã trở nên linh hoạt hơn rất nhiều. Nó được bổ sung thêm một số tính năng chưa có ở các bộ xử lý Intel như tải dữ liệu tự do, bao gồm lệnh Load-Execute và đọc hai gói dữ liệu 128 bit trong mỗi xung nhịp. Khác với Core 2, bộ phận lập biểu số nguyên và dấu phẩy động lại sử dụng các hàng chờ riêng. Các hàng chờ riêng rẽ này giúp loại bỏ xung đột có thể xảy ra trong cùng một cổng xử lý. Tuy vậy, K10 vẫn chia sẻ đơn vị FSTORE cho các phép tính SSE cùng một số lệnh chuyển tiếp dữ liệu, đôi khi có thể gây ảnh hưởng đến tốc độ xử lý.
Tóm lại, FPU K10 FPU hứa hẹn sẽ rất hữu hiệu và cải tiến hơn nhiều so với FPU của Core 2 (ví dụ như việc đọc hai gói dữ liệu 128 bit và việc tải dữ liệu tự do chẳng hạn).
Hệ thống bộ nhớ bên trong
Đơn vị tài/lưu trữ – Load/Store Unit
Khi các địa chỉ cần tìm đã được tính toán xong trong AGU của bộ xử lý K8, tất cả các phép tính đã được tải và lưu trữ sẽ được chuyển đến LSU (Đơn vị tải/lưu trữ – Load/Store Unit ). LSU chứa hai hàng chờ: LS1 và LS2. Đầu tiên, các phép tính này sẽ được chuyển vào hàng LS1 với 12 đơn vị. Với tốc độ hai phép tính mỗi xung nhịp, hàng chờ LS1 cần có bộ nhớ cache L1 được sắp xếp bởi mã lập trình. Trong trường hợp không có trong cache ( Cache –Miss ) , các phép tính sẽ được xếp vào hàng chờ LS2 32 đơn vị. Đây là lúc cần đến bộ nhớ cache L2 và RAM.
LSU của bô xử lý K10 đã được cải tiến. Giờ đây hàng chờ LS1 chỉ nhận các phép tính đã tải, trong khi các phép tính lưu trữ sẽ được chuyển đến hàng chờ LS2. Các phép tính đã tải từ LS1 có thể được xử lý không theo thứ tự dựa vào các địa chỉ của các phép tính lưu trữ trong LS2. Như đã nói trong phần trước, K10 sẽ xử lý các phép tính lưu trữ 128 bit giống như đối với 2 phép tính 64 bit, và đó là lý do tại sao chúng chiếm hai chỗ trong hàng chờ LS2.
Cache L1
Cache L1 trong K8 và K10 được tách riêng: 64KB lệnh (L1I) và dữ liệu (L1D). Mỗi cache được liên kết hai chiều và có độ dài 64 byte. Việc này có thể dẫn đến xung đột thường xuyên giữa các đường có cùng đích đến, làm tăng số cache thiếu và ảnh hưởng xấu đến tốc độ xử lý. Nhưng tình trạng này có thể được khắc phục bằng cache L1 có kích thước lớn hơn. Ngoài ra, một ưu điểm khác của L1D đó là có có hai cổng, do vậy có thể xử lý hai lệnh đọc hoặc/và viết hai lệnh trong mỗi xung nhịp.
Điều không may là cache L1 của bộ xử lý K10 vẫn có kích thước và số liên kết như cũ. Cải tiến đáng chú ý duy nhất là độ dài của Bus đọc có tăng lên. Như đã nói trong phần trước, giờ đây CPU có thể đọc 128 bit mỗi xung nhịp, giúp chúng hoạt động hiệu quả hơn nhiều trong việc xử lý dữ liệu SSE trong bộ nhớ cục bộ.
Cache L2
Mỗi nhân trong bộ xử lý 2 nhân K8 và 4 nhân K10 đều có cache L2 riêng của mình . Cache L2 trong K10 vẫn như cũ: 512KB mỗi nhân với 16 liên kết. Các cache L2 riêng đều có ưu và nhược điểm riêng so với cache L2 chia sẻ trong CPU Core 2. Chắc chắn ưu điểm lớn nhất là việc xung đột và cạnh tranh cache khi nhiều nhân cùng được tải cùng một lúc sẽ không còn nữa. Còn nhược điểm là sẽ có ít cache hơn cho mỗi nhân khi chỉ có một ứng dụng hoạt động.
Cache L2 đều là riêng: các dữ liệu lưu trong cache L1 và L2 đều không nhân đôi. Cache L1 và L2 trao đổi dữ liệu qua hai Bus theo hai hướng: một để nhận và một để chuyển dữ liệu. Trong bộ xử lý K8, mỗi Bus rộng 64 bit (8 byte). Cấu trúc này giúp tốc độ chuyển dữ liệu đến cache L2 ít nhất là 8 byte/xung nhịp. Nói cách khác, cần 8 xung nhịp để chuyển 64 bit, do vậy thời gian chuyển dữ liệu đến nhân sẽ bị chậm lại rõ rệt, đặc biệt là khi hai dòng trong cache L2 được chuyển đến cùng một lúc.
Mặc dù chưa được xác định cụ thể, nhưng Bus gửi và nhận trong bộ xử lý K10 sẽ trở nên rộng gấp đôi, khoảng 128 bit mỗi Bus. Điều này giúp giảm thời gian trễ khi hai hay nhiều dòng cùng được gửi đến một lúc.
Bus chuyển dữ liệu giữa cache L1 và L2 trong bộ xử lý K8
Bus chuyển dữ liệu giữa cache L1 và L2 trong bộ xử lý K10
Cache L3
Để khắc phục nhược điểm của cache L2 có kích cỡ nhỏ, các cache L3 2MB trong tất cả các nhân của K10 lại có thể chia sẻ được với 32 đường liên kết.Cache L3 có cả khả năng thích ứng và riêng biệt: nó lưu trữ dữ liệu từ cache L2 của tất cả các nhân và cả dữ liệu chung của nhiều nhân. Khi nhân yêu cầu đọc một dòng lệnh, nếu như chỉ có một nhân đang sử dụng dòng lệnh đó, nó sẽ được chuyển từ không gian trống trong L3. Còn nếu dòng lệnh này đang được một nhân khác sử dụng, nó sẽ vẫn nằm trong cache. Tuy nhiên, để xếp chỗ cho dòng lệnh đến từ cache 2, một dòng lệnh khác trước đó sẽ rời đi.
Cache L3 sẽ giúp tăng tốc độ luân chuyển dữ liệu giữa các nhân. Như đã tìm hiểu, các bộ xử lý Athlon 64 tạm thời chỉ chuyển đổi dữ liệu giữa các nhân thông qua Bus bộ nhớ. Do đó, việc chuyển đến dữ liệu chia sẻ diễn ra chậm hơn nhiều. Theo như AMD, bộ xử lý 4 nhân K10 có thể trao đổi dữ liệu qua cache L3. Khi yêu cầu từ một trong số các nhân được chuyển đến, nhân chuyển đổi dữ liệu sẽ copy dữ liệu vào cache L3, nơi nhân yêu cầu có thể đọc chúng. Thời gian chuyển dữ liệu trong cache của nhân còn lại sẽ được rút ngắn rất nhiều.
Quá trình chuyển dữ liệu giữa các nhân trong bộ xử lý K10
Cache L3 sẽ hoạt động hiệu quả hơn so với cache L2. Tuy nhiên, AMD cho rằng hiệu quả trội hơn này còn tuỳ thuộc vào khối lượng công việc. Nếu khối lượng công việc không quá lớn, khả năng làm việc của L3 sẽ lớn hơn rõ rệt, còn nếu khối lượng công việc rất nặng nề, độ rộng băng thông sẽ tăng lên. Chúng ta sẽ còn phải chờ để kiểm chứng điều đó .
TLB
Bên cạnh bộ nhớ Cache cho lệnh và cho dữ liệu , bộ vi xử lí có nhiều kiểu của Cache : đó là Bộ đệm TLB ( Translation – Lookaside Buffer ) . Những bộ đệm này được dùng để lưu trữ sự kết nối giữa địa chỉ trang vật lí với địa chỉ trang ảo từ những Bảng trang địa chỉ .
Số lượng của danh mục TLB xác định có bao nhiêu trang bộ nhớ có thể làm việc mà không mất công chuyển sang Bảng trang khác . Điều này hay bị phê phán trong những ứng dụng mà xử lí dữ liệu bộ nhớ ngẫu nhiên , khi chúng yêu cầu dữ liệu liên tục trong những trang khác nhau , bộ vi xử lí K10 có những bộ đệm dịch nhiều hơn và có kích thước cũng lớn hơn . Để thuận tiên theo dõi , sửa máy tính đưa ra bảng dưới đây
Bảng 1 : Khả năng TLB của bộ vi xử lí K8 và K10
ITLB : Bộ đệm TLB cho lệnh
DTLB : Bộ đệm TLB cho dữ liệu
Như bảng trên cho thấy nhiều bộ đệm dịch những trang 2MB . Nó xuất hiện để hỗ trợ cho việc những trang có dung lượng lớn hơn 1GB mà có thể được dùng hữu ích cho những máy chủ xử lí khối lượng dữ liệu lớn . Với sự hỗ trợ thích hợp từ phía hệ điều hành mà những ứng dụng dùng những trang 2MB và 1GB sẽ chạy nhanh hơn .
Bộ phận điều khiển bộ nhớ – Memory Controller
Khi dữ liệu được yêu cầu không tìm thấy trong bất kì bộ nhớ Cache nào , thì yêu cầu đó được chuyển tới Bộ phận điều khiển bộ nhớ tích hợp bên trong Die ( Vùng Silcon chứa Chip ) của bộ vi xử lí . Vị trí của Bộ phận điều khiển bộ nhớ nằm trên Die của bộ vi xử lí làm giảm thời gian trễ với bộ nhớ , nhưng bên cạnh đó nó lại làm cho bộ vi xử lí không linh hoạt với những kiểu bộ nhớ khác nhau , nó lại làm tăng kích thước của Die và sự phức tạp trong thiết kế .
Bộ phận điều khiển bộ nhớ được tích hợp bên trong CPU là một điều thuận lợi với những bộ vi xử lí K8 và nó được cải tiến một cách đáng kể với những bộ vi xử lí K10 .
Đầu tiên , bây giờ nó có thể truyền dữ liệu không phải bằng một kênh có độ rộng 128-bit và nó dùng hai kênh độc lập 64-bit . Như vậy hai hoặc nhiều nhân của bộ vi xử lí có thể làm việc hiệu quả hơn với bộ nhớ trong cùng một thời gian .
Thứ hai , thuật toán sắp xếp lại và cấp phát trong Bộ phận điều khiển bộ nhớ được tối ưu hoá . Những nhóm điều khiển bộ nhớ Đọc và Ghi vì thế mà Bus nhớ có thể được tận dụng một cách tối đa . Những việc Đọc thuận lợi hơn so với việc Ghi . Dữ liệu cần ghi được lưu trữ trong bộ đệm mà không rõ kích thước ( nó sẽ nằm giữa từ 16 và 30 dòng , mõi dòng 64-byte ) . Với việc điều khiển những dòng yêu cầu trong những nhóm chúng ta có thể tránh việc chuyển Bus nhớ từ trạng thái Đọc thành Ghi liên tục để tiết kiệm thời gian . Nó cho phép tăng hiệu suất một cách đáng kể khi thay đổi yêu cầu trạng thái Đọc và Ghi .
Thứ ba , Bộ phận điều khiển bộ nhớ có thể phân tích chuỗi yêu cầu và thực hiện công việc lấy trước dữ liệu . ( Prefetch ) .
Lấy trước dữ liệu – Prefetch
Prefetch rõ ràng đem lại lợi ích cho những bộ vi xử lí K8 . Tích hợp bộ phận điều khiển bộ nhớ cho phép thời gian trễ thấp điều đó làm cho những bộ vi xử lí của AMD thực hiện thành công với hệ thống nhớ trong một thời gian dài . Tuy nhiên , những bộ vi xử lí K8 không đạt được hiệu suất làm việc như mong đợi với bộ nhớ DDR2 , trong khi đó Core 2 lại có cơ cấu tạo nên sức mạnh với Prefetch . Những bộ vi xử lí K8 có 02 Prefetch : một để cho mã và một để cho dữ liệu . Prefetch cho dữ liệu lấy dữ liệu vào trong bộ nhớ Cache L2 bằng phương thức đơn giản đó là liên tục .
K10 đã cải tiến cơ cấu Prefetch
Đầu tiên , những bộ vi xử lí K10 lấy trước dữ liệu trực tiếp vào trong Cache L1 , mà cho phép tránh thời gian trễ của Cache L2 khi dữ liệu được yêu cầu . Mặc dù nó làm tăng khả năng làm cho Cache L1 lưu trữ những dữ liệu không cần thiết , nhưng bản chất của nó là giảm thời gian trễ của Cache , AMD tuyên bố có thể đo được điều này để phân định .
Thứ hai , chúng thực hiện việc thay đổi khả năng lấy trước dữ liệu theo những điều kiện phù hợp với những khối dữ liệu động . Prefetch đã trở nên vô cùng linh hoạt : nó có thể lấy những bộ nhớ yêu cầu tại bất kì địa chỉ mà không cần theo cách sử dụng những địa chỉ liền kề . Hơn nữa Prefetch có thể được tuỳ biến theo yêu cầu của phần mềm .
Thứ ba , việc tách riêng Prefetch đã tăng thêm điều kiện tiếp xúc trực tiếp với bộ phận điều khiển bộ nhớ . Bộ phận điều khiển bộ nhớ phân tích những yêu cầu kế tiếp nhau từ mã lệnh của chương trình và tải dữ liệu vào bộ đệm Ghi tận dụng Bus nhớ để tối ưu hoá công việc .
Chúng ta đã xem qua những cải tiến của hệ thống phụ của bộ nhớ , và cũng có thể nói trên phương diện lí thuyết là có khả năng cạnh tranh được với hệ thống phụ bộ nhớ trong những bộ vi xử lí của Intel trong nhiều ứng dụng nhưng vẫn còn một số tính năng mà K10 không có như :
Tải để tích trữ những địa chỉ đã được sử dụng của những phép Ghi dữ liệu , liên kết dữ liệu của Cache L1 nhỏ hơn , tốc độ truyền dữ liệu giữa L1 và L2 thấp hơn , bộ nhớ Cache L2 nhỏ hơn và Prefetch đơn giản hơn .
Mặc dù cũng có sự cải tiến nhưng Prefetch của Core 2 có nhiều sức mạnh hơn Prefetch của K10 . Ví dụ K10 không có Prefetch những địa chỉ lệnh do đó mà cần phải giữ lại dấu vết của những lệnh riêng biệt , hoặc không có Prefetch từ L2 tới L1 nên việc giấu thời gian trễ của L2 là vẫn chưa đủ . Những yếu tốc đó có thể tạo nên những sự khác biệt trong nhiều ứng dụng khác nhau .
Những lệnh mới
Bộ vi xử lí K10 có một số lệnh mới để mở rộng những chức năng của nó
· Mở rộng những phép tính về Bit trong những thanh ghi kết quả chung
LZCNT – Count Leading Zeros – đếm số Bit 0 đầu tiên trong phép toán
POPCNT – Bit Population Count – đếm số Bit có giá trị bằng 1 trong phép toán
· Xử lí những thanh ghi SSE thành những lệnh của SSE4a
EXTRQ – lấy ra số của những Bit xác định trong phần 64-bit thấp của thanh ghi SSE
INSERTTQ – chèn số của những Bit xác định trong phần 64-bit thấp của thanh ghi SSE
MOVNTSS , MOVNTSD – lưu trữ ( không boa gồm bộ nhớ Cache ) những giá trị phạm vi dấu phảy động .
Những lệnh SSE4a mở rộng không phải là một phần của những lệnh SSE4.1 và SSE4.2 của Intel .
Ảo hoá
AMD tiếp tục cải tiến công nghệ ảo của họ mà những máy chủ có thể chạy vài hệ điều hành cùng một lúc trên một máy tính . Một trong những cải tiến công nghệ ảo một cách sâu sắc đó là sử dụng Nested Paging . Trong hệ thống này những trang máy ảo được lồng nhau trong toàn bộ Bảng trang của Hypervisor ( Theo dõi những máy ảo – là một nền tảng ảo cho phép nhiều hệ điều hành chạy trên một PC ) . Nếu không có liên kết tới trang trong TLB , CPU thực hiện biến đổi tất cả Bảng tự động , không như kiểu Shadow Paging yêu cầu nhiều tài nguyên để quản lí việc chuyển Bảng của những máy ảo
Hình 7a : Kiểu Shadow Paging khi chuyển giữa những hệ thống máy ảo thì Hypervisor phải chuyển giữa những Bảng trang đã được xoá sạch TLB trong cùng một thời gian
Hình 7b : Kiểu Nested Paging khi chuyển giữa những hệ thống máy ảo Hypervisor khong cần phải xoá sạch TLB tại cùng một thời điểm .
Một số dữ liệu cho rằng dùng Nested Paging làm tăng hiệu suất ứng dụng trên hệ thống ảo tới 40% khi so sánh với hiệu suất được dùng kiểu Shadow Paging .
Quản lí tần số và năng lượng
Những bộ vi xử lí K10 mới sẽ có hệ thống quản lí tần số và năng lượng mới . Mỗi lõi bây giờ sẽ làm việc độc lập với lõi khác , tần số làm việc của mỗi lõi thay đổi phụ thuộc vào mức độ Load của nó và không ảnh hưởng bởi những lõi khác .
Tuy nhiên không thấy nói rõ rằng bộ nhớ Cache L3 lúc đó thay đổi như thế nào . Điện áp của các lõi là như nhau và được xác định theo lõi mà có mức tải cao nhất . Bộ phận điều khiển bộ nhớ quản lí điện áp của mình độc lập với lõi và có thể thấp hơn điện áp của lõi khi mà có mức tải ( Load ) thấp .