Làm thế nào để dự đoán chi nhánh hoạt động, nếu bạn vẫn phải kiểm tra các điều kiện?


30

Tôi đã đọc câu trả lời phổ biến về Dự đoán chi nhánh từ https://stackoverflow.com/q/11227809/555690 và có một điều khiến tôi bối rối:

  • Nếu bạn đoán đúng, nó tiếp tục.
  • Nếu bạn đoán sai, thuyền trưởng sẽ dừng lại, sao lưu và la mắng bạn để lật công tắc. Sau đó, nó có thể khởi động lại con đường khác.

Nếu bạn đoán đúng mọi lúc, tàu sẽ không bao giờ phải dừng lại.

Nếu bạn đoán sai quá thường xuyên, tàu sẽ mất rất nhiều thời gian để dừng lại, sao lưu và khởi động lại.

Nhưng đây là những gì tôi không nhận được: để biết liệu dự đoán của bạn là đúng hay sai, dù sao bạn cũng phải kiểm tra điều kiện . Vì vậy, làm thế nào để dự đoán chi nhánh thậm chí hoạt động, nếu một trong hai cách bạn vẫn đang làm kiểm tra điều kiện tương tự?

Điều tôi đang cố gắng nói là, không phải dự đoán chi nhánh giống hệt như không có dự đoán chi nhánh nào cả vì dù sao bạn cũng đang thực hiện kiểm tra có điều kiện? (rõ ràng là tôi sai, nhưng tôi không hiểu)


1
Bài viết wiki này làm một công việc khá tốt giải thích nó.
thúc

8
Một CPU hiện đại được sắp xếp theo đường ống và có thể làm một số việc cùng một lúc. Do đó, nó có thể bắt đầu thực hiện dự đoán của mình trong khi nó vẫn nhận ra nếu nó đoán đúng. Nếu đoán đúng, đường ống tiếp tục chạy. Khi đoán sai, đường ống được đưa ra và thực hiện khởi động lại từ điểm "câu trả lời đúng".
markspace

2
Đọc liên quan: đường ống . Tôi cũng khuyên bạn nên đọc lại câu trả lời được chấp nhận cho câu hỏi SO đó, vì nó trả lời câu hỏi của bạn ở đây.

Câu trả lời:


19

Tất nhiên điều kiện được kiểm tra mỗi lần. Nhưng tại thời điểm nó được kiểm tra, nó đã đi sâu vào đường ống CPU. Đồng thời, các hướng dẫn khác cũng đã được đưa vào đường ống và đang ở các giai đoạn thực hiện khác nhau.

Thông thường, một điều kiện ngay lập tức được theo sau bởi một lệnh rẽ nhánh có điều kiện, một trong hai nhánh nếu điều kiện ước lượng thành TRUE hoặc rơi vào nếu điều kiện ước lượng thành FALSE. Điều này có nghĩa là có hai luồng hướng dẫn khác nhau có thể được tải vào đường ống sau lệnh điều kiện và lệnh rẽ nhánh, tùy thuộc vào điều kiện đánh giá thành TRUE hay FALSE. Thật không may, ngay sau khi tải lệnh điều kiện và lệnh rẽ nhánh, CPU vẫn chưa biết điều kiện sẽ đánh giá là gì, nhưng nó vẫn phải tiếp tục tải công cụ vào đường ống. Vì vậy, nó chọn một trong hai bộ hướng dẫn dựa trên dự đoán về điều kiện sẽ đánh giá.

Sau này, khi hướng dẫn điều kiện đi lên đường ống, đây là lúc để đánh giá. Vào thời điểm đó, CPU tìm hiểu xem dự đoán của nó là đúng hay sai.

Nếu dự đoán là đúng, thì chi nhánh đã đi đến đúng nơi và các hướng dẫn đúng đã được tải vào đường ống. Nếu hóa ra dự đoán là sai, thì tất cả các hướng dẫn được nạp vào đường ống sau khi lệnh rẽ nhánh có điều kiện đều sai, chúng cần phải được loại bỏ và tìm nạp lại các lệnh phải bắt đầu lại từ đúng nơi.

Sửa đổi

Đáp lại bình luận của StarWeaver, để đưa ra ý tưởng về những gì CPU phải làm để thực hiện một lệnh:

Hãy xem xét một cái gì đó đơn giản như MOV AX,[SI+10]con người chúng ta ngây thơ nghĩ là "tải AX với từ tại SI cộng 10". Roughly, CPU phải:

  1. phát nội dung của PC ("thanh ghi bộ đếm chương trình") đến bus địa chỉ;
  2. đọc opcode hướng dẫn từ bus dữ liệu;
  3. PC tăng;
  4. giải mã opcode để biết phải làm gì với nó;
  5. phát nội dung của PC đến bus địa chỉ;
  6. đọc toán hạng lệnh (trong trường hợp này là 10) từ bus dữ liệu;
  7. PC tăng;
  8. đưa toán hạng và SI vào bộ cộng;
  9. phát ra kết quả của bộ cộng vào bus địa chỉ;
  10. đọc AX từ bus dữ liệu.

Đây là một con số khổng lồ 10 bước. Một số bước này sẽ được tối ưu hóa ngay cả trong các CPU không có đường ống, ví dụ CPU sẽ luôn tăng PC song song với bước tiếp theo, đây là một điều dễ thực hiện vì PC là một thanh ghi rất, rất đặc biệt không bao giờ được sử dụng cho bất kỳ công việc nào khác, vì vậy không có khả năng tranh chấp giữa các phần khác nhau của CPU để truy cập vào thanh ghi cụ thể này. Tuy nhiên, chúng tôi vẫn còn 8 bước cho một hướng dẫn đơn giản như vậy và lưu ý rằng tôi đã giả sử một mức độ tinh vi nào đó thay cho CPU, ví dụ tôi cho rằng sẽ không cần thêm một bước nữa cho adder để thực sự bổ sung trước khi kết quả có thể được đọc từ nó,

Bây giờ, hãy xem xét rằng tồn tại các chế độ địa chỉ phức tạp hơn, như MOV AX, [DX+SI*4+10], và thậm chí các hướng dẫn phức tạp hơn nhiều, giống như MUL AX, operandthực sự thực hiện các vòng lặp bên trong CPU để tính kết quả của chúng.

Vì vậy, quan điểm của tôi ở đây là phép ẩn dụ "cấp độ nguyên tử" không phù hợp với mức độ chỉ dẫn của CPU. Nó có thể phù hợp với cấp bước đường ống, nếu bạn không muốn đi quá xa đến mức cổng logic thực tế.


2
Huh, tôi tự hỏi nếu một phần của vấn đề mà mọi người (bao gồm cả tôi) hiểu về điều này là nó rất khó (đối với tôi dù thế nào) để tưởng tượng một cpu chỉ có một phần kiến ​​thức về một hướng dẫn duy nhất; hoặc để có một nửa các hướng dẫn hoàn thành "đi qua lò nướng bánh pizza" ít nhất đối với tôi, nó cảm thấy giống như một sự thay đổi quy mô thành nguyên tử khi tôi thường làm việc với những thứ giữa bộ dụng cụ cương cứng và mức độ máy tiện kim loại.
StarWeaver

1
@StarWeaver Tôi thích bình luận của bạn, vì vậy tôi đã sửa đổi câu trả lời của mình để giải quyết nó.
Mike Nakis

1
Wow, khám phá tốt đẹp. Tôi có xu hướng quên đi bao nhiêu việc chỉ chuyển các từ vào các vị trí hữu ích hơn. Mặc dù vậy, tôi vẫn đang hình dung một cpu như một bộ lò nướng pizza chạy bằng dây đai: 3.
StarWeaver

Điều đáng ghi nhớ là câu hỏi Stack Overflow được liên kết bởi OP - câu hỏi có 1,3 triệu lượt xem có thể đã giới thiệu hơn 1 triệu lập trình viên về một thực tế lạ lẫm trước đây rằng "dự đoán nhánh" thậm chí còn tồn tại - thể hiện một ví dụ trong Java . Đối với những người như tôi, những người đã quen làm việc ở mức độ trừu tượng mà các ngôn ngữ như Java cung cấp cho chúng ta, thậm chí MOV AX,[SI+10]là xa lạ, không "đơn giản"; hầu hết các lập trình viên ngày nay chưa bao giờ viết lắp ráp. Chúng tôi không "ngây thơ nghĩ" nó có nghĩa là bất cứ điều gì.
Đánh dấu

@MarkAmery tốt, được thôi, tôi nghĩ khá rõ ràng rằng "con người chúng ta" ý tôi là "con người chúng ta dám viết lắp ráp". Vấn đề đang được đưa ra là ngay cả các lập trình viên ngôn ngữ lắp ráp cũng không nghĩ đến đường ống mọi lúc, hoặc thậm chí là cả.
Mike Nakis

28

Hãy nghĩ về nó giống như một chuyến đi đường mà không có GPS. Bạn đến một ngã tư và nghĩ rằng bạn cần rẽ, nhưng không hoàn toàn chắc chắn. Vì vậy, bạn rẽ, nhưng yêu cầu hành khách của bạn kiểm tra bản đồ. Có thể bạn ba dặm xuống đường vào thời điểm bạn kết thúc tranh cãi về nơi bạn đang đứng. Nếu bạn đã đúng, bạn ba dặm xa hơn bạn sẽ có được nếu bạn đã dừng lại và tranh luận trước khi quay. Nếu bạn sai, bạn phải quay lại.

Đường ống CPU hoạt động theo cùng một cách. Vào thời điểm họ có thể kiểm tra tình trạng, họ đã xuống đường. Sự khác biệt là, họ không cần phải lái xe ba dặm trở lại, họ chỉ mất khởi đầu. Điều đó có nghĩa là không có hại trong việc cố gắng.


2
Giải thích này là gọn gàng.
sharptooth

2

Theo hiểu biết của tôi, dự đoán chi nhánh là hữu ích nhất khi điều kiện bạn cần kiểm tra đòi hỏi kết quả của một thứ đắt tiền hoặc vẫn đang được tiến hành, và nếu không bạn sẽ vặn ngón tay cái chờ giá trị để đánh giá điều kiện.

Với những thứ như thực hiện không theo thứ tự, bạn có thể sử dụng dự đoán nhánh để bắt đầu điền vào các điểm trống trong đường ống mà CPU nếu không sẽ không thể sử dụng. Trong một tình huống không có, vì một số lý do, bất kỳ chu kỳ nhàn rỗi nào trong đường ống, thì có, không có lợi ích trong dự đoán chi nhánh.

Nhưng mấu chốt ở đây là, CPU đang bắt đầu công việc cho một trong những nhánh được dự đoán bởi vì nó chưa thể tự đánh giá điều kiện.


1

Hình thức ngắn:

Một số CPU có thể bắt đầu làm việc theo một hướng dẫn mới trước khi hoàn thành cái cũ. Đây là những CPU sử dụng dự đoán nhánh.

Một ví dụ mã giả:

int globalVariable;
int Read(int* readThis, int* readThat)
{
    if ((globalVariable*globalVariable % 17) < 5)
       return *readThis;
    else
       return *readThat;
}

Đoạn mã trên kiểm tra một điều kiện và dựa trên kết quả mà nó cần để trả về giá trị được lưu trữ tại vị trí bộ nhớ addThishoặc giá trị được lưu trữ tại readThat. Nếu dự đoán nhánh dự đoán điều kiện sẽ xảy ra true, CPU sẽ đọc giá trị được lưu trữ tại vị trí bộ nhớ addThistrong khi thực hiện phép tính cần thiết để đánh giá ifcâu lệnh. Đây là một ví dụ đơn giản.


1

Có, điều kiện được kiểm tra một trong hai cách. Nhưng lợi thế của dự đoán chi nhánh là bạn có thể thực hiện công việc thay vì chờ kết quả kiểm tra điều kiện.

Hãy nói rằng bạn phải viết một bài luận và nó có thể là về chủ đề A hoặc chủ đề B. Bạn biết từ các bài tiểu luận trước đó rằng giáo viên của bạn thích chủ đề A tốt hơn B và chọn nó thường xuyên hơn. Thay vì chờ đợi quyết định của anh ấy, bạn có thể bắt đầu viết bài luận về chủ đề đầu tiên. Bây giờ có hai kết quả có thể xảy ra:

  1. Bạn đã bắt đầu bài luận về chủ đề sai và phải bỏ những gì bạn đã viết cho đến nay. Bạn phải bắt đầu viết về chủ đề khác và đó là nỗ lực cùng thời gian như thể bạn đã chờ đợi.
  2. Bạn đoán đúng và bạn đã hoàn thành công việc.

Các CPU hiện đại hầu hết thời gian không hoạt động vì chúng đang chờ phản hồi IO hoặc kết quả của các tính toán khác. Thời gian này có thể được sử dụng để làm một số công việc trong tương lai.

Ngay cả khi bạn phải loại bỏ những gì bạn đang làm trong thời gian nhàn rỗi này - rất có thể sẽ hiệu quả hơn nếu bạn có khả năng đoán đường dẫn mà chương trình sẽ chọn. Và CPU hiện đại có khả năng này.

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.