Vì vậy công việc hoán đổi các câu lệnh của ngôn ngữ máy, sao cho tận dụng được những ưu điểm của bộ xử lý là cần thiết nhằm tăng tốc độ thực hiện của chương trình.. Định thời mã thực hiệ
Trang 1GIẢI THUẬT ĐỊNH THỜI MÃ CHO KIẾN TRÚC PIPELINE
Chuyên ngành: Khoa học máy tính
LUẬN VĂN THẠC SĨ
TP HỒ CHÍ MINH, tháng 12 năm 2008
Trang 2Bộ xử lý của máy tính là bộ não của máy tính, chúng ta muốn máy tính làm những công việc nào đó mà chúng ta cần thì chúng ta phải ra lệnh cho máy tính. Việc ra lệnh cho máy tính thực hiện theo các yêu cầu của chúng ta thông qua việc lập trình. Bộ xử lý của các máy tính chỉ hiểu được các lệnh máy, hay còn được gọi
là ngôn ngữ máy, do đó những lập trình viên muốn lập trình trên các bộ xử lý này sẽ gặp rất nhiều khó khăn vì ngôn ngữ máy không gần với những ngôn ngữ tự nhiên.
Để bộ xử lý của máy tính có thể hiểu được những chương trình được viết ở ngôn ngữ lập trình cấp cao (là những ngôn ngữ gần với ngôn ngữ tự nhiên) cần phải có một chương trình chuyển đổi ngôn ngữ cấp cao thành ngôn ngữ máy, đó là trình biên dịch.
Trình biên dịch là phần mềm quan trọng, nó dùng để chuyển một ngôn ngữ lập trình cấp cao thành một ngôn ngữ lập trình cấp thấp hơn, giúp cho lập trình viên viết chương trình trên các ngôn ngữ gần với các ngôn ngữ trong cuộc sống đời thường mà máy tính vẫn có thể hiểu được. Trình biên dịch thực hiện công việc đọc một chương trình nguồn ở dạng ngôn ngữ cấp cao và dịch nó sang chương trình đích là ngôn ngữ máy tương ứng với bộ xử lý của máy tính được sử dụng.
Trình biên dịch tốt là trình biên dịch sinh ra mã đối tượng tốt. Nếu trình biên dịch sinh ra mã đối tượng tốt thì chương trình sẽ thực thi nhanh hơn. Sinh mã đối tượng nằm ở giai đoạn cuối của trình biên dịch. Vấn đề sinh mã tối ưu trong trình biên dịch là không thể thực hiện được về mặt lý thuyết tổng quát, song trong thực tế
ta có thể lựa chọn các kỹ thuật cụ thể để tạo ra được các mã đối tượng tốt mà không cần phải là mã tối ưu. Trong quá trình sinh mã đối tượng, để tạo ra được mã đối tượng tốt người ta phải thực hiện nhiều công đoạn và một trong những công đoạn
đó là định thời mã đối tượng
Trang 3mã đối tượng phù hợp với kiến trúc bộ xử lý đó. Vì vậy công việc hoán đổi các câu lệnh của ngôn ngữ máy, sao cho tận dụng được những ưu điểm của bộ xử lý là cần thiết nhằm tăng tốc độ thực hiện của chương trình. Trong những máy tính hiện đại ngày nay, các bộ xử lý thường được sử dụng kiến trúc Pipeline tuyến tính.
Việc xây dựng một trình biên dịch để tận dụng ưu điểm của kiến trúc Pipeline tuyến tính nhằm tăng tốc độ thực thi của chương trình là cần thiết. Bộ xử lý Pipeline tuyến tính là một dãy các bước xử lý, các bước này kết nối tuyến tính để thực hiện một chức năng cố định trên một dòng dữ liệu theo từng bước một. Để trình biên dịch sinh ra mã tốt thì trong quá trình sinh mã đối tượng ta cần thực hiện công việc định thời mã đối tượng, sao cho giảm thiểu được càng nhiều interlock càng tốt (nghĩa là giảm thiểu các bước trì hoãn. Các bước trì hoãn của câu lệnh sinh
ra vì phải đợi các kết quả của các câu lệnh trước đó).
Để định thời mã, người ta thường chia quá trình định thời mã cho một chương trình thành hai giai đoạn. Giai đoạn một là phân rã chương trình thành những khối cơ bản và giai đoạn hai là thực hiện định thời lệnh trên khối cơ bản đó. Khối cơ bản là một dãy những câu lệnh liên tiếp, dãy các câu lệnh này có những dòng điều khiển đi vào tại vị trí bắt đầu và những dòng điều khiển đi ra tại vị trí kết thúc, những dòng điều khiển này không bị gián đoạn hoặc có thể chấp nhận rẽ nhánh tại vị trí cuối.
Đề tài này đã đưa ra giải thuật List_cycle_scheduling thực hiện việc định thời mã cho một khối cơ bản. Giải thuật List_cycle_scheduling được cài đặt trong Trimaran3.7. Kết quả thử nghiệm của giải thuật List_cycle_scheduling cho ra kết quả là: Tổng số chu kỳ thực hiện của chương trình hiện thực bằng giải thuật List_cycle_scheduling so với các giải thuật do Trimaran cài đặt (như giải thuật Cycle_scheduling, Oper_scheduling, List_bt_scheduling) là gần bằng nhau và Thời
Trang 4Nội dung đề tài gồm năm chương.
Chương 1: Một vài khái niệm cơ bản. Chương này nêu các khái niệm có liên quan đến nội dung của những giải thuật nêu ra trong đề tài.
Chương 2: Một vài giải thuật định thời cục bộ. Chương này nêu ra một vài giải thuật định thời mã làm cơ sở để đưa ra giải thuật List_cycle_scheduling.
Chương 3: Giải thuật List_cycle_scheduling. Trong chương này đưa ra giải thuật List_cycle_scheduling, ví dụ minh họa cho giải thuật này và phân tích độ phức tạp của giải thuật.
Chương 4: Kết quả thử nghiệm của giài thuật List_cycle_scheduling. Trong chương này giới thiệu công cụ để hiện thực cho giải thuật này là Trimaran. Đưa ra các mẫu dữ liệu dùng để thử nghiệm cho giải thuật, Tổng số chu kỳ thực hiện trên các mẫu này và Thời gian thực thi của các giải thuật khi áp dụng cho các mẫu dữ liệu. So sánh kết quả của giải thuật List_cycle_scheduling với các giải thuật khác. Chương 5: Kết luận. Tổng kết các kết quả đạt được của đề tài và định hướng phát triển của đề tài
Trang 5Giới thiệu 1
Chương 1. Một vài khái niệm cơ bản 4
1) Kiến trúc pipeline 4
2) Sự phụ thuộc giữa các câu lệnh 9
3) DDAG (The Dependency Directed Acyclic Graph) 10
4) Khối cơ bản (Basic block) 12
Chương 2. Một vài giải thuật định thời cục bộ 14
1) Giải thuật DLS (DelayedLoad Scheduling algorithm) 14
2) Giải thuật CSP (Code Scheduling for Pipelined processors): 21
3) Giải thuật ICS (Integrated Code Scheduling) 25
4) Giải thuật List_scheduling: 30
5) Giải thuật Cycle_scheduling: 33
6) Giải thuật Oper_scheduling: 37
7) Giải thuật List_BT_scheduling: 41
Chương 3. Giải thuật List_cycle_scheduling 47
1) Đặt vấn đề 47
2) Nội dung giải thuật 49
3) Ví dụ 53
4) Phân tích độ phức tạp của giải thuật 59
Trang 62) Hiện thực giải thuật List_cycle_scheduling 63
3) Tổng số chu kỳ thực hiện 64
4) Thời gian thực thi 65
5) Kết luận kết quả thử nghiệm 69
Chương 5. Kết luận 70
Trang 7Hiện nay, các bộ xử lý của máy tính thường sử dụng kiến trúc Pipeline nên việc xây dựng một trình biên dịch để tận dụng ưu điểm của kiến trúc Pipeline nhằm tăng tốc độ thực thi của chương trình là cần thiết. Định thời mã đối tượng là công việc quan trọng và cần thiết trong giai đoạn sinh mã đối tượng của trình biên dịch. Định thời mã thực hiện công việc định thời điểm thực thi của câu lệnh và hoán đổi các câu lệnh của ngôn ngữ máy, sao cho ý nghĩa của chương trình không thay đổi
và làm tăng tốc độ thực hiện của chương trình. Định thời mã đối tượng có hai loại là: Định thời toàn cục và Định thời cục bộ. Đề tài này đã tìm hiểu một vài giải thuật định thời cục bộ và đưa ra giải thuật List_cycle_scheduling thực hiện việc định thời cục bộ cho một khối cơ bản
Trang 8Một vài khái niệm cơ bản
Trong chương này nêu ra một vài khái niệm sẽ được sử dụng khi trình bày các giải thuật định thời lệnh cho kiến trúc Pipeline. Mục đích của việc định thời lệnh là thay đổi trật tự của những câu lệnh và xác định thời điểm bắt đầu thực hiện câu lệnh, sao cho chúng có thể thực thi nhanh nhất nếu có thể và phù hợp với kiến trúc máy đích. Chương này trình bày các khái niệm như sau: Kiến trúc Pipeline, Sự phụ thuộc giữa các câu lệnh, Khối lệnh cơ bản, và đồ thị DDAG.
1) Kiến trúc Pipeline:
Bộ xử lý Pipeline tuyến tính (Linear Pipeline Processors) là một dãy các bước xử lý, các bước này kết nối tuyến tính để thực hiện một chức năng cố định trên một dòng dữ liệu theo từng bước một. Trong những máy tính hiện đại ngày nay thì Pipeline tuyến tính được cài đặt cho việc thực thi lệnh, tính toán số học, và hoạt động truy cập bộ nhớ [KH93].
Một bộ xử lý Pipeline tuyến tính được xây dựng với k bước xử lý. Dữ liệu ở
bên ngoài đi vào Pipeline tại bước đầu tiên S 1 . Kết quả xử lý được đưa từ bước S i
đến bước Si+1, với i=1, 2, …, k1. Kết quả cuối cùng được đưa ra khỏi Pipeline tại bước cuối cùng S k .
Một dòng những câu lệnh có thể thực thi trên Pipeline theo kiểu Overlap (các lệnh gối lên nhau). Ví dụ như những Pipeline lệnh cho những bộ xử lý CISC và RISC.
Việc thực thi lệnh là một dãy các hoạt động, bao gồm: bước đọc lệnh (fetch stage: F), bước giải mã lệnh (decode stage: D), bước chiếm giữ tài nguyên (issue
Trang 9stage: I), bước thực thi lệnh (execute stage: E), bước ghi kết quả (writeback stage: W)
· Bước đọc lệnh : là đọc lệnh từ bộ nhớ
· Bước giải mã lệnh: giải mã lệnh để thực hiện và nhận diện những tài nguyên cần thiết. Những tài nguyên này bao gồm: các thanh ghi, các bus, và những đơn vị chức năng
· Bước chiếm giữ tài nguyên: Giữ trước những tài nguyên (thanh ghi,
bộ nhớ,…). Pipeline điều khiển những Interlock thì được duy trì tại bước này. Những dữ liệu vào từ bên ngoài thì cũng được đọc từ những thanh ghi trong khoảng thời gian này
· Bước thực thi lệnh: Thực thi lệnh có một hoặc nhiều Bước thực thi
Trang 10thực thi xong thì mới thực thi được. Tương tự, câu lệnh 4 được thực thi từ xung clock 4 đến xung clock 15, nó bị interclock từ xung clock 5 đến xung clock 7 (bởi
vì nó đợi câu lệnh 3 thực hiện bước chiếm giữ tài nguyên) và nó bị interlock từ xung clock 9 đến xung clock 10 (bởi vì nó phải đợi kết quả thực thi từ câu lệnh 3). Câu lệnh 5 được thực hiện từ xung clock 8 đến xung clock 16 và nó bị interlock từ xung clock 9 đến xung clock 10; bởi vì nó phải đợi cho câu lệnh 4 thực hiện bước chiếm giữ tài nguyên thì nó mới thực hiện tiếp được. Câu lệnh 6 thực hiện từ xung clock 11 đến xung clock 17. Câu lệnh 7 được thực hiện từ xung clock 12 đến xung clock 20 và bị interlock từ xung clock 14 đến xung clock 15; Bởi vì nó phải đợi kết quả thực thi từ câu lệnh 5 và câu lệnh 6. Câu lệnh 8 được thực hiện từ xung clock
13 đến xung clock 23, nó bị interlock từ xung clock 14 đến xung clock 15 (bởi vì nó đợi câu lệnh 7 thực hiện bước chiếm giữ tài nguyên) và nó bị interlock từ xung clock 17 đến xung clock 18 (bởi vì nó đợi kết quả thực thi của câu lệnh 7). Kết quả
được chỉ ra ở Hình 1.1.3.
(1) Load R1, Y (2) Load R2, Z (3) Add R3, R1, R2 (4) Store X, R3 (5) Load R4, B (6) Load R5, C (7) Mul R6, R4, R5 (8) Store A, R6 (Hình 1.1.2:Đoạn lệnh chưa định thời)
Vậy ta phải tốn 23 xung clocks để thực hiện đoạn lệnh trên; Nhưng ta lại bị interclock đến 9 xung clock. Vậy vấn đề đặt ra là ta có thể nào tối thiểu được số interclock khi thực thi chương trình mà không làm thay đổi tính đúng đắn của nó
Trang 111 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 (1) F D I E E E W
(2) F D I E E E W
(Hình 1.1.3:Đoạn lệnh ở hình 1.1.2 được thực hiện trên kiến trúc Pipeline)
Ta thấy interclock của câu lệnh 3 và 4 là do nó phải đợi kết quả thực thi từ câu lệnh 1 và 2. Như vậy ta phải tìm những câu lệnh còn lại của chương trình, sao cho không phụ thuộc vào kết quả của câu lệnh 3 và 4; Sau đó di chuyển các câu lệnh này lên các vị trí của câu lệnh 3 và 4, còn các câu lệnh 3 và 4 ta di chuyển về phía dưới. Ta dễ dàng thấy rằng câu lệnh 5 và 6 không phụ thuộc vào kết quả thực thi của câu lệnh 3 và 4; Do đó ta hoán đổi vị trí của câu lệnh 5 và 6 cho câu lệnh 3
và 4. Ta có kết quả như sau:
(1) Load R1, Y (2) Load R2, Z (5) Load R4, B (6) Load R5, C (3) Add R3, R1, R2 (4) Store X, R3 (7) Mul R6, R4, R5 (8) Store A, R6
Trang 12vị trí của câu lệnh 4 với câu lệnh 7. Khi đó ta có được đoạn chương trình đã được
định thời như Hình 1.1.4.
(1) Load R1, Y (2) Load R2, Z (5) Load R4, B (6) Load R5, C (3) Add R3, R1, R2 (7) Mul R6, R4, R5 (4) Store X, R3 (8) Store A, R6 (Hình 1.1.4:Đoạn lệnh ở hình 1.1.2 đã được định thời)
Tương tự như trên, đoạn trình ở hình 1.1.4 được thực thi trên kiến trúc Pipeline như sau (Hình 1.1.5):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
(Hình 1.1.5: Đoạn lệnh ở hình 1.1.4 được thực hiện trên kiến trúc Pipeline)
Trang 13đó với đoạn lệnh chưa được định thời ta phải tốn 23 xung clocks để thực hiện. Như vậy đoạn chương trình sau khi định thời, khi ta thực thi đã tiết kiệm được 6 xung clocks. Do đó việc định thời lại các câu lệnh để thực thi trong bộ xử lý Pipeline là cần thiết nhằm tận dụng kiến trúc Pipeline để tăng tốc độ thực hiện của một chương trình.
Ta thấy rằng để thực hiệc việc định thời lệnh trên kiến trúc Pipeline, ta phải chỉ ra được sự phụ thuộc giữa các câu lệnh và công việc định thời lại được thực hiện trên các câu lệnh ở mức mã máy tại thời gian biên dịch. Vì vậy bài toán định thời lệnh trên kiến trúc Pipeline là bài toán NPcomplete [HG83].
2) Sự phụ thuộc giữa các câu lệnh:
Khi ta thực hiện định thời các câu lệnh trong chương trình thì ta phải biết được những phụ thuộc giữa các câu lệnh trong chương trình đó. Các câu lệnh trong chương trình có những phụ thuộc cơ bản sau [KKF95]:
· Sự phụ thuộc dữ liệu (Data dependence): Khi một câu lệnh a tạo ra một tập
các dữ liệu và những dữ liệu này được dùng cho câu lệnh b thì câu lệnh b sẽ không thực hiện được cho đến khi dữ liệu được tạo ra bởi câu lệnh a. Sự phụ thuộc này gọi là sự phụ thuộc dữ liệu.
Trang 14Chúng ta xây dựng mỗi nút của DDAG là một câu lệnh và những cạnh của
đồ thị chỉ ra sự phụ thuộc dữ liệu giữa các câu lệnh. Một cạnh bắt đầu từ nút a vào một nút b, nghĩa là: câu lệnh a phải được thực thi trước câu lệnh b để bảo đảm tính đúng đắn của toàn bộ chương trình.
Ví dụ: ta có chương trình nguồn được viết dưới dạng ngôn ngữ cấp cao, như
r1=2 r3=r1+4 r1=r51
Sự phụ thuộc dữ liệu
Sự phụ thuộc tài nguyên của thanh ghi
bt:r1==r4
r3=r2 r2=1 r3=3
bt sai
bt đúng
Trang 15sau: h= a*b +(c+d)*(a+e);
Viết lại đoạn chương trình trên bằng ngôn ngữ tựa ngôn ngữ máy:
(1) Load PR1, a (2) Load PR2, b (3) Mul PR3, PR1, PR2 (4) Load PR4, c
(5) Load PR5, d (6) Add PR6, PR4, PR5 (7) Load PR7, e
(8) Add PR8, PR1, PR7 (9) Mul PR9, PR6, PR8 (10) Add PR10, PR3, PR9 (11) Store h, PR10
(Hình 1.3.1)
Ta thấy câu lệnh 3 muốn thực thi được thì câu lệnh 1 và 2 phải thực thi xong.
Do đó ta biểu diễn ràng buộc này như sau:
Tương tự, câu lệnh 6 thực thi được khi ta thực thi xong câu lệnh 4 và 5. Câu lệnh 8 thực thi được khi ta thực thi xong câu lệnh 1 và 7. Câu lệnh 9 thực thi được khi ta thực thi xong câu lệnh 6 và 8. Câu lệnh 10 thực thi được khi ta thực thi xong
2
1
3
Trang 1611 (Hình 1.3.2: Đồ thị DDAG)
Trang 17Ngoài ra trong chương trình còn có những ràng buộc điều khiển. Để xác định được những ràng buộc này, ta phân hoạch chương trình thành các khối cơ bản và các ràng buộc điều khiển đuợc thể hiện bằng các cạnh nối các khối cơ bản với nhau. Khối cơ bản là một dãy những câu lệnh liên tiếp. Dãy các câu lệnh này có những dòng điều khiển đi vào tại vị trí bắt đầu và những dòng điều khiển đi ra tại vị trí kết thúc. Những dòng điều khiển này không bị gián đoạn hoặc có thể chấp nhận
Exp S1
S2 S3
S4
S1 IfFalse (Exp) goto L1
B1
B4
Trang 18Một vài giải thuật định thời cục bộ
Chương này trình bày các giải thuật định thời cục bộ làm kiến thức nền tảng cho việc hình thành giải thuật List_cycle_scheduling. Để thực hiện định thời chương trình, chúng ta phân rã chương trình thành những khối cơ bản và thực hiện định thời trên những khối cơ bản đó. Định thời cục bộ (local scheduling) là ta thực hiện định thời lệnh trên khối cơ bản. Nội dung của chương này trình bày các giải thuật định thời cục bộ sử dụng cho kiến trúc Pipeline, bao gồm: Giải thuật DLS, Giải thuật CSP, Giải thuật ICS, Giải thuật List_scheduling, Giải thuật Cycle_scheduling, Giải thuật Oper_scheduling, và Giải thuật List_bt_scheduling.
1) Giải thuật DLS (DelayedLoad Scheduling algorithm)
Giải thuật DLS dùng để định thời lệnh và phân phối thanh ghi [TC91], nhưng điểm nổi bậc nhất của giải thuật là phân phối thanh ghi và chỉ ra đoạn chương trình khi định thời cần tối thiểu bao nhiêu thanh ghi mà không gây ra Spilling. Giải thuật này sử dụng cây biểu thức để định thời lệnh.
Nội dung của giải thuật DLS:
Bước 1: Xây dựng cây biểu thức.
Bước 2: Tính minReg cho mỗi nút trong cây biểu thức. MinReg là một số
nguyên xác định số thanh ghi tối thiểu cần cho việc định thời lệnh mà không gây ra Spilling. MinReg tại nút a được tính như sau:
If ( a là nút lá)
a.minReg=1;
Else{
Trang 19}
Bước 4: Thực hiện thứ tự các câu lệnh đã được sắp xếp theo Bước 3
Trang 20Ngõ vào: opSched, loadSched, và Regs. Regs là số thanh ghi dùng để định thời lệnh.
Trang 22hai nút *2 và *1, nút *2 có minReg bằng 3 và nút *1 có minReg bằng 2, do đó nút + 3
có minReg bằng minReg của nút lớn nhất; Nghĩa là bằng minReg của nút *2 và bằng 3.
Bước 3: Thứ tự thực hiện của các lệnh load và các phép toán Kết quả duyệt cây biểu thức ta được:
((d c+ 1) (e a + 2) *2) (a b *1) + 3
Do đó thứ tự thực hiện của các câu lệnh load là: d, c, e, a, a, b; Và thứ tự thực hiện của các phép toán là: + 1, + 2, *2, *1, + 3
Bước 4: Định thời lệnh. Giả sử số thanh ghi dùng để định thời là 4.
Vì số thanh ghi sử dụng là 4, nên giải thuật DLS lấy bốn lệnh load đầu tiên là:
Load r1,d Load r2,c Load r3,e Load r4,a
Vì hết thanh ghi để phân phối cho các lệnh load còn lại nên giải thuật DLS lấy một phép toán trong danh sách phép toán (đó là phép toán +1) là: Add r2,r1,r2. Sau khi thực hiện câu lệnh này thì thanh ghi r1 được giải phóng, do đó giải thuật thực hiện việc lấy câu lệnh load tiếp theo là: Load r1,a.Quá trình thực hiện tương tự cho đến khi các câu lệnh load trong danh sách lệnh load được lấy hết.
Ta có các lệnh được lấy là:
Add r4,r3,r4 Load r3,b
Tiếp theo ta lấy các phép toán còn lại trong danh sách phép toán (là *2, *1,
+3), ta được các câu lệnh sau:
Trang 23Mul r4,r2,r4 Mul r3,r1,r3 Add r3,r4,r3
Vậy ta có danh sách các câu lệnh đã được định thời như cột bên phải trong
hình 2.1.2. Cột bên trái của hình 2.1.2 chứa các câu lệnh chưa được định thời
Khi đó ta tính được tổng số chu kỳ thực hiện của đoạn chương trình định thời bằng giải thuật DLS (với Delay=1) là 20 xung clocks. Trong khi đó, nếu ta không định thời lệnh thì tổng số chu kỳ thực hiện của đoạn chương trình là 25 xung clocks. Vậy giải thuật DLS đã cải thiện được tốc độ thực hiện của chương trình.
Các lệnh chưa định thời DLS(Delay=1)
(1) Load R1, a (2) Load R2, b (3) Mul R1, R1, R2 (4) Load R3, c (5) Load R4, d (6) Add R3, R3, R4 (7) Load R4, e (8) Add R4, R1, R4 (9) Mul R3, R3, R4 (10) Add R3, R3, R2 (11) Store h, R3
Load r1,d Load r2,c Load r3,e Load r4,a Add r2,r1,r2 Load r1,a Add r4,r3,r4 Load r3,b Mul r4,r2,r4 Mul r3,r1,r3 Add r3,r4,r3 store r3,h
25 xung clocks 20 xung clocks
(Hình 2.1.2: Định thời theo giải thuật DLS)
Giả sử số chu kỳ thực hiện của các lệnh là: (đơn vị tính là xung clock)
Trang 24v Nhược điểm của giải thuật DLS:
· Giải thuật DLS dùng cây biểu thức để định thời nên quá trình định thời lệnh chỉ thực hiện được khi ta xây dựng được cây biểu thức. Nghĩa là giải thuật chỉ định thời trên những khối lệnh cơ bản phát sinh
đó gây ra Interlock trong Pipeline. Giả sử lệnh load có số chu kỳ thực hiện là 4 xung clock, như vậy Pipeline phải interlock 3 xung clock mới thực hiện được phép toán đứng kề sau nó
Trang 252) Giải thuật CSP (Code Scheduling for Pipelined processors):
Giải thuật CSP dùng để thực hiện định thời lệnh [GM86], và giải thuật giả sử
là số thanh ghi mà hệ thống máy cấp cho giải thuật luôn đủ, do đó giải thuật không quan tâm đến việc phân phối thanh ghi. Giải thuật thực hiện việc định thời lệnh sao cho tối thiểu càng nhiều Interlock càng tốt. Giải thuật dùng đồ thị DDAG để định thời lệnh
Trang 2611 (Hình 2.2.2:D DAG trọng số)
Trang 27số của nút 5 là 12, trọng số của nút 4 là 12, trọng số của nút 2 là 10. Trọng số của nút 1 bằng tổng số chu kỳ thực thi của câu lệnh 1 với giá trị lớn nhất của trọng số của nút 3 và nút 8, do đó nút 1 có trọng số bằng 12. Vậy DDAG trọng số có được
Ta tiếp tục lấy câu lệnh 7, 1 ra khỏi tập dự tuyển và thêm vào danh sách lệnh
và xoá các nút 7, 1 khỏi DDAG; Khi đó nút 8 có bậc vào là 0, nên ta thêm nút 8 vào tập dự tuyển. Do đó tập dự tuyển lúc này là {2, 6, 8}.
Lấy câu lệnh 2 ra khỏi tập dự tuyển và thêm vào danh sách lệnh và xoá các nút 2 khỏi DDAG; Khi đó nút 3 có bậc vào là 0, nên ta thêm nút 3 vào tập dự tuyển.
Do đó tập dự tuyển lúc này là {6, 8, 3}.
Lấy câu lệnh 6, 8 ra khỏi tập dự tuyển và thêm vào danh sách lệnh và xoá các nút 6, 8 khỏi DDAG; Khi đó nút 9 có bậc vào là 0, nên ta thêm nút 9 vào tập dự tuyển. Do đó tập dự tuyển lúc này là {3, 9}.
Lấy câu lệnh 3, 9 ra khỏi tập dự tuyển và thêm vào danh sách lệnh và xoá các nút 3, 9 khỏi DDAG; Khi đó nút 10 có bậc vào là 0, nên ta thêm nút 10 vào tập dự tuyển. Do đó tập dự tuyển lúc này là {10}.
Lấy câu lệnh 10 ra khỏi tập dự tuyển và thêm vào danh sách lệnh và xoá các nút 10 khỏi DDAG; Khi đó nút 11 có bậc vào là 0, nên ta thêm nút 11 vào tập dự
Trang 28Lấy câu lệnh 11 ra khỏi tập dự tuyển và thêm vào danh sách lệnh và xoá các nút 11 khỏi DDAG; Khi đó DDAG rỗng và tập dự tuyển lúc này là rỗng. Kết thúc giải thuật ta có được danh sách các lệnh đã được định thời: 4, 5, 7, 1, 2, 6, 8, 3, 9,
Các câu lệnh chưa định thời CSP (1) Load R1, a
(2) Load R2, b (3) Mul R1, R1, R2 (4) Load R3, c (5) Load R4, d (6) Add R3, R3, R4 (7) Load R4, e (8) Add R4, R1, R4 (9) Mul R3, R3, R4 (10) Add R3, R3, R2 (11) Store h, R3
(4) Load r2,c (5) Load r3,d (7) Load r4,e (1) Load r1,a (2) Load r5,b (6) Add r2,r2,r3 (8) Add r4,r1,r4 (3) Mul r1,r1,r5 (9) Mul r2,r2,r4 (10) Add r1,r1,r2 (11) store r1,h
25 xung clock 15 xung clock
(Hình 2.2.3:Định thời dùng giải thuật CSP )
Trang 29v Nhược điểm của giải thuật CSP: Giải thuật này chỉ quan tâm đến việc định thời lệnh mà không chú ý đến việc phân phối thanh ghi. Nếu trong ví dụ trên,
số thanh ghi mà ta có thể dùng được là nhỏ hơn 5 thì giải thuật CSP sẽ không đáp ứng được. Vì vậy giải thuật CSP đã lạm dụng việc sử dụng quá nhiều thanh ghi và không chú ý đến việc phân phối các thanh ghi.
3) Giải thuật ICS (Integrated Code Scheduling)
Khi định thời mã lệnh chúng ta phải quan tâm đến hai vấn đề là: Định thời lệnh và Phân phối thanh ghi. Để định thời lệnh ta dùng kỹ thuật CSP (Code scheduling for Pipelined processors), còn để phân phối thanh ghi ta dùng kỹ thuật CSR (Code scheduling to minimize Registers usage), và ta đã thể hiện kỹ thuật này thông qua giải thuật DLS. Kỹ thuật CSR theo dõi những thanh ghi có thể sử dụng được trong quá trình định thời, mỗi lần thực hiện một câu lệnh có thể tạo ra một thanh ghi hoạt động mới (new live register) và chấm dứt hoạt động của một vài thanh ghi (the lifetime of some registers). Giải thuật ICS [GWC88] sẽ theo dõi số thanh ghi có thể sử dụng được; Khi có đủ số thanh ghi thì dùng CSP để rút gọn interlock; Còn khi không đủ số thanh ghi có thể sử dụng được thì chuyển sang CSR để điều khiển việc dùng các thanh ghi
v AVLREG:
Việc chuyển qua lại giữa CSP và CSR được điều khiển bởi AVLREG là
số thanh ghi có thể dùng được. CSP chịu trách nhiệm định thời lệnh để có tổng
số chu kỳ thực hiện nhỏ nhất. Khi AVLREG giảm xuống đến ngưỡng nào đó thì CSR sẽ được gọi. Sau khi AVLREG phục hồi đến một giá trị chấp nhận được thì CSP được phục hồi việc định thời. AVLREG được tính bằng tổng số thanh ghi trừ cho số thanh ghi hoạt động. Chúng ta tăng AVLREG khi có câu lệnh giải phóng những thanh ghi và giảm AVLREG khi có câu lệnh tạo ra những thanh ghi hoạt động.
v Tập Leader và Tập ready
Một leader của một DDAG là một đỉnh mà không có đỉnh tổ tiên (hay
Trang 30đỉnh có bậc vào bằng 0). Một câu lệnh sẽ không được thực hiện cho đến khi nó trở thành một leader. Những câu lệnh sau khi thực hiện thì những đỉnh của nó trên DDAG sẽ bị xóa và một vài đỉnh khác sẽ trở thành những leader mới. Tất cả những leader được chứa trong tập leader. Những câu lệnh trong tập leader mà không có interlock với những câu lệnh đã thực hiện trước đó thì được chuyển từ tập leader sang tập ready. Tất cả các câu lệnh trong tập ready thì sẵn sàng thực hiện.
v Nội dung của giải thuật ICS:
Ngõ vào:Danh sách tập lệnh (chưa được định thời), số thanh ghi có
thể sử dụng được và số chu kỳ thực thi của từng câu lệnh. Ngõ ra: Danh sách tập lệnh staList đã được định thời.
Bước 1: Xây dựng DDAG trọng số. Trọng số của mỗi nút trên DDAG được
tính bằng chi phí tích lũy của mỗi nút trong DDAG bằng cách ước lượng số chu kỳ thực thi của mỗi lệnh.
Bước 2: Ứng với mỗi nút a của DDAG, tính refCount(a) là bậc ra của nút a. Bước 3: Tạo ra Tập leader (là những nút của DDAG phụ thuộc có bậc vào
Lấy câu lệnh s với trọng số lớn nhất ra khỏi Tập leader;
Trang 31Else {chuyển sang CSR}
If ( Nếu có những nút trong tập ready có thể giải phóng
thanh ghi) Lấy câu lệnh s sao cho giải phóng số thanh ghi nhiều nhất (Nếu có nhiều hơn một nút như vậy ta chọn nút có trọng số lớn nhất);
Else
If(Nếu có những nút trong tập leader có thể giải phóng thanh ghi)
Lấy câu lệnh s sao cho giải phóng số thanh ghi nhiều nhất (Nếu có nhiều hơn một nút như vậy ta chọn nút ít gây ra interlocks nhất);
Else
Tìm một đường dẫn có giá trị cục bộ và lấy câu lệnh s từ tập leader trong đường dẫn này (Nếu không có những đường dẫn có giá trị cục
bộ thì lựa chọn bất kỳ nút nào trong tập ready hoặc trong tập leader nếu như tập ready rỗng); EndIf
Trang 32Ta chọn các câu lệnh 4, 5, 7, 1 từ tập ready (vì nó có trọng số lớn nhất) và thêm vào danh sách lệnh, Xoá các nút này khỏi DDAG. Các nút 6, 8 có bậc vào là 0 nên
ta thêm các nút này vào tập leader.
Do đó tập leader = {6, 8}, tập ready = {2} và AVLREG=0. Nên ta chuyển sang
kỹ thuật CSR, lúc này ta không thể lấy câu lệnh 2 được vì đã dùng hết số thanh ghi cho phép. Vì vậy ta phải lấy câu lệnh 6 từ tập leader. Câu lệnh 6 giải phóng một thanh ghi, do đó AVLREG=1 và giải thuật chuyển sang kỹ thuật CSP. Khi đó câu lệnh 2 trong tập ready được lấy, và nút 3 có bậc vào bằng 0, nên ta thêm câu lệnh 3 vào tập leader, và câu lệnh 8 trong tập leader không gây ra interlock nên ta chuyển
Trang 33Do đó tập leader = {3}, tập ready = {8} và AVLREG=0. Lấy câu lệnh 8 từ tập ready và thêm vào danh sách định thời. Xoá nút 8, khi đó nút 9 có bậc vào bằng 0 nên ta thêm nút 9 vào tập leader.
Do đó tập leader = {3, 9}, tập ready = rỗng và AVLREG=0. Lấy câu lệnh 3, 9 từ tập leader và thêm vào danh sách định thời. Xoá nút 3, 9. Khi đó nút 10 có bậc vào bằng 0 nên ta thêm nút 10 vào tập leader.
Do đó tập leader = {10}, tập ready = rỗng và AVLREG=2. Lấy câu lệnh 10 từ tập leader và thêm vào danh sách định thời. Xoá nút 10. Khi đó nút 11 có bậc vào bằng 0 nên ta thêm nút 11 vào tập leader.
Các câu lệnh chưa định thời ICS (1) Load R1, a
(2) Load R2, b (3) Mul R1, R1, R2 (4) Load R3, c (5) Load R4, d (6) Add R3, R3, R4 (7) Load R4, e (8) Add R4, R1, R4 (9) Mul R3, R3, R4 (10) Add R3, R3, R2 (11) Store h, R3
(4) Load r2,c (5) Load r3,d (7) Load r4,e (1) Load r1,a (6) Add r2,r2,r3 (2) Load r3,b (8) Add r4,r1,r4 (3) Mul r1,r1,r3 (9) Mul r2,r2,r4 (10) Add r1,r1,r2 (11) stor r1,h
25 xung clocks 18 xung clocks
(Hình 2.3.1:Định thời dùng giải thuật ICS )
Do đó tập leader = {11}, tập ready = rỗng và AVLREG=3. Lấy câu lệnh 11 từ
Trang 34tập leader và thêm vào danh sách định thời. Xoá nút 11.
Do đó tập leader = rỗng, tập ready = rỗng và AVLREG=4. Kết thúc giải thuật và
các câu lệnh được định thời ở cột bên phải của hình 2.3.1. Tổng số chu kỳ thực thi
của giải thuật là 18 xung clocks. Đoạn lệnh chưa định thời có tổng số chu kỳ thực thi là 25 xung clocks. Nên giải thuật thực thi đoạn lệnh nhanh hơn khi chưa định thời là 7 xung clocks.
4) Giải thuật List Scheduling
Trong phần này trình bày giải thuật List_scheduling [Trimaran]. Giải thuật định thời dựa vào bậc vào của mỗi nút trên đồ thị DDAG. Những nút có bậc vào bằng 0 thì được đưa vào danh sách ready_list và trong quá trình định thời ta lấy một nút cm_op ra khỏi danh sách ready_list để định thời. Nếu không phân phối được tài nguyên cho nút cm_op thì tăng chu kỳ bắt đầu định thời của cm_op lên 1 đơn vị, sau đó quay lại kiểm tra phân phối tài nguyên cho nút cm_op cho đến khi phân phối được tài nguyên cho nút cm_op. Sau khi định thời cm_op ta giảm bậc vào cho những nút ra của cm_op đi 1 đơn vị, và những nút ra có bậc vào bằng 0 thì được đưa vào danh sách ready_list.
Trang 36· Giảm bậc vào của nút dest_op đi 1.
Bậc vào của nút Dest_op bằng 0.
Trang 37v Độ phức tạp của giải thuật:
Gọi n là số nút của đồ thị DDAG.
Câu lệnh (1) có độ phức tạp là O(n). Các câu lệnh (2), (3), (4) có độ phức tạp là O(1).
Các câu lệnh (5.1), (5.2), (5.3), (5.5) có độ phức tạp là O(1). Các câu lệnh (5.4.1), (5.4.2) có độ phức tạp O(1), còn câu lệnh (5.4.3) có độ phức tạp là O(n). Do
đó câu lệnh (5.4) có độ phức tạp là O(n 2 ).
Vậy câu lệnh (5) có độ phức tạp là O(n 3 ), do đó độ phức tạp của giải thuật List scheduling là O(n 3 ).
5) Giải thuật Cycle Scheduling
Trong phần này trình bày giải thuật Cycle_scheduling [Trimaran]. Giải thuật này định thời lệnh dựa vào trọng số của nút trên đồ thị DDAG. Trọng số của nút là thời điểm sớm nhất có thể định thời cho nút đó. Trọng số của nút x được tính bằng trọng
số của nút y cộng với trọng số cạnh yx; Với y là nút gốc của nút x và trọng số cạnh
yx là số chu kỳ thực hiện của lệnh tương ứng với nút y. Giải thuật tính trọng số cho các nút chưa được định thời và những nút cha của nó đã được định thời, sau đó chọn
ra những nút có trọng số nhỏ nhất để đưa vào danh sách ready_slist. Lấy nút cm_op
ra khỏi danh sách ready_slist để định thời. Nếu phân phối được tài nguyên cho cm_op thì định thời cho nó và tính lại trọng số cho tất cả những nút chưa định thời, tìm những nút chưa định thời có trọng số nhỏ nhất để đưa vào danh sách ready_slist. Nếu không phân phối được tài nguyên cho nút cm_op thì tăng trọng số nút cm_op lên 1 đơn vị và thực hiện định thời lại cm_op.