Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (537.12 KB, 10 trang )
<span class="text_page_counter">Trang 1</span><div class="page_container" data-page="1">
TRƯỜNG ĐẠI HỌC BÁCH KHOA HÀ NỘI
Ngày nay, máy tính và các đồ dùng điện tử đều đang phát triển cơng nghệ với tốcđộ chóng mặt. Các vật dụng đó gắn liền với cuộc sống của chúng ta.
Với mỗi một chiếc máy tính của chúng ta bây giờ thì hầu như rất dễ sử dụng, thânthiện với người dùng. Chúng ta có thể học cách sử dụng chúng một cách dễ dàng. Điềunày nhờ những hệ điều hành thân thiện với người dùng mà chúng ta đã quá quen nhưwindow hoặc Mac OS.
Để tìm hiểu cách một hệ điều hành như thế nào, phục vụ cho muc đích hiểu thêmvề mơn học Hệ Điều Hành của TS Phạm Văn Tiến giảng dạy, em đã làm đề tài tìm hiểunày qua Pintos. Phần mà em muốn tìm hiểu là phần advanced scheduler.
2
</div><span class="text_page_counter">Trang 3</span><div class="page_container" data-page="3"><b>1. Tìm hiểu đề tài1.1. Yêu cầu</b>
Triển khai bộ lập lịch hàng đợi phản hồi đa cấp( Multi-level feedbackqueue scheduler) tương tự như bộ lập lịch 4.4BSD để giảm thời gian phảnhồi trung bình để chạy các cơng việc trên hệ thống của bạn.
Giống như bộ lập lịch ưu tiên( Priority scheduler), bộ lập lịch nâng caochọn luồng để chạy dựa trên các ưu tiên. Tuy nhiên, bộ lập lịch nâng caokhơng thực hiện qun góp ưu tiên. Do đó, chúng tơi khun bạn nên cóbộ lập lịch ưu tiên làm việc, ngoại trừ có thể là quyên góp ưu tiên, trướckhi bạn bắt đầu làm việc trên bộ lập lịch nâng cao.
<b>1.2. Bộ lập lịch 4.4BSD</b>
Mục tiêu của bộ lập lịch có mục đích chung là cân bằng các nhu cầu lậplịch trình khác nhau của các luồng. Các luồng thực hiện nhiều I / O yêucầu thời gian phản hồi nhanh để giữ cho các thiết bị đầu vào và đầu ra bậnrộn, nhưng cần ít thời gian CPU. Mặt khác, các luồng bị ràng buộc tínhtốn cần nhận được nhiều thời gian CPU để hoàn thành công việc củachúng, nhưng không yêu cầu thời gian phản hồi nhanh. Các luồng khácnằm ở đâu đó ở giữa, với các chu kỳ I / O được ngắt quãng bởi các giaiđoạn tính tốn và do đó có các yêu cầu thay đổi theo thời gian. Một bộ lậplịch được thiết kế tốt thường có thể chứa các luồng với tất cả các yêu cầunày cùng một lúc.
Đối với dự án 1, bạn phải thực hiện bộ lập lịch được mô tả trong phụ lụcnày. Bộ lập lịch của chúng tôi giống với bộ lập lịch được mô tả trong[McKusick], đây là một ví dụ về bộ lập lịch hàng đợi phản hồi đa cấp.Loại bộ lập lịch này duy trì một số hàng đợi các luồng sẵn sàng chạy,trong đó mỗi hàng đợi chứa các luồng với mức độ ưu tiên khác nhau. Tạibất kỳ thời điểm nào, bộ lập lịch chọn một chuỗi từ hàng đợi không trốngcó mức độ ưu tiên cao nhất. Nếu hàng đợi ưu tiên cao nhất chứa nhiềuluồng, thì chúng sẽ chạy theo thứ tự "round robin".
</div><span class="text_page_counter">Trang 4</span><div class="page_container" data-page="4">Nhiều khía cạnh của bộ lập lịch yêu cầu dữ liệu được cập nhật sau một sốlần tích tắc hẹn giờ nhất định. Trong mọi trường hợp, các bản cập nhậtnày sẽ xảy ra trước khi bất kỳ luồng hạt nhân thông thường nào có cơ hộichạy, do đó khơng có khả năng luồng hạt nhân có thể thấy giá trịtimer_ticks() mới tăng mà là giá trị dữ liệu bộ lập lịch cũ.
<b>1.3. Bộ định thời multi-level feedback queue</b>
Bộ định thời multilevel feedback queue gồm có nhiều hàng đợi khácnhau, mỗi hàng đợi sẽ chứa các tiểu trình có độ ưu tiên khác nhau. Bộđịnh thời này sẽ ln chọn tiểu trình từ hàng đợi khơng trống có độ ưutiên cao nhất. Nếu hàng đợi có độ ưu tiên cao nhất có nhiều tiểu trình,mỗi tiểu trình sẽ được định thời bằng giải thuật “round robin". Các phầncủa bộ định thời này đòi hỏi dữliệu phải được cập nhật sau một khoảngthời gian nhất định (là bội số của timer ticks).
<b>1.4. Các thông số cần chú ý1.4.1. Niceness</b>
Mỗi tiểu trình có một giá trị số nguyên gọi là nice, giá trị này xácđịnh mức độ “mới” của tiểu trình so với các tiểu trình khác. Giá trịnice bằng 0 khơng ảnh hưởng tới độ ưu tiên của tiểu trình. Giá trị nicedương (tối đa 20) sẽ làm giảm độ ưu tiên của tiểu trình và sẽ khiến nótừ bỏ giờ CPU mà nó nhận được. Ngược lại, giá trị nice âm (tối thiểulà -20) sẽ giúp tiểu trình có xu hướng nhận được CPU từ các tiểu trìnhkhác.
Giá trị nice của tiểu trình đầu tiên là 0. Các tiểu trình khác sẽ có giátrị nice được kế thừa từ tiểu trình cha của nó. Các hàm liên quan đếnnice sau đây cần được cài đặt (nguyên mẫu hàm của chúng được địnhnghĩa sẵn trong tập tin threads/thread.c):
• int thread_get_nice (void): Trả về giá trị nice của tiểu trìnhhiện tại.
• void thread_set_nice (int new_nice): Thiết lập giá trị nice mớicho tiểu trình hiện tại, đồng thời tính lại độ ưu tiên của tiểu trình dựatrên giá trị nice mới. Nếu tiểu trình đang chạy khơng có độ ưu tiên caonhất, nó cần từ bỏ việc sử dụng CPU.
4
</div><span class="text_page_counter">Trang 5</span><div class="page_container" data-page="5"><b>1.4.2. Priority</b>
Bộ định thời cần cài đặt có 64 độ ưu tiên, cũng đồng thời có 64hàng đợi được đánh số từ 0 (PRI_MIN) đến 63 (PRI_MAX). Độ ưutiên 0 là nhỏ nhất, 63 là cao nhất.
Độ ưu tiên của tiểu trình được xác định tại thời điểm khởi tạo.Sau đó, nó sẽ được xác định lại sau mỗi 4 chu kỳ xung clock. Độưu tiên mới được xác định bằng công thức:
priority = PRI_MAX − (recent_cpu/4) − (nice × 2)
Trong đó, recent_cpu là thời gian CPU ước tính mà tiểu trình đãsử dụng gần đây, còn nice là giá trị nice của tiểu trình. Kết quả củabiểu thức trên trên sẽ được làm trịn xuống số ngun gần nhất. Cácgiá trị ¼ và 2 trong biểu thức trên được xác định thông qua thựcnghiệm. Kết quả độ ưu tiên tính được phải luôn nằm trong phạm vitừ PRI_MIN đến PRI_MAX.
Công thức trên được thiết kế để các tiểu trình đã nhận đượcCPU gần đây sẽ có độ ưu tiên thấp hơn ở lần lập lịch kế tiếp. Đâychính là chìa khóa để ngăn chặn tình trạng bỏ đói (starvation): mộttiểu trình chưa được nhận CPU gần đây sẽ có recent_cpu bằng 0, sẽluôn đảm bảo sẽ được nhận CPU sớm.
<b>1.4.3. Recent CPU</b>
Giá trị recent_cpu được sử dụng để đo lường lượng giờ CPUmỗi tiểu trình đã nhận được gần đây. Để ước tính giá trị này, hàmexponentially weighted moving average được sử dụng, hàm nàycó dạng tổng quát:
x(0) = f(0)
x(t) = a × x(t − 1) + f(t)a = k/(k + 1)
Trong biểu thức này, x(t) là moving average tại thời điểm t ≥ 0,f(t) là hàm trung bình và k điều khiển tỷ lệ.
</div><span class="text_page_counter">Trang 6</span><div class="page_container" data-page="6">Giá trị khởi tạo của recent_cpu là 0 khi tiểu trình đầu tiên đượctạo. Nếu là các tiểu trình khác, giá trị này sẽ là giá trị recent_cpucủa tiểu trình cha. Mỗi lần một ngắt timer diễn ra, recent_cpu sẽtăng lên 1 đối với tiểu trình đang thực thi. Thêm vào đó, mỗi giây,giá trị recent_cpu của mỗi tiểu trình được xác định( bất kể tiểutrình đó đang chạy, ready hay blocked) qua cơng thức sau:
recent_cpu = (2 × load_avg)/(2 × load_avg + 1) × recent_cpu +nice
Trong công thức này, load_avg là moving average của số tiểutrình sẵn sàng được chạy.
Giá trị recent_cpu có thể âm nếu tiểu trình có nice âm, khi đókhơng được làm trịn recent_cpu về 0.
Khi thực hiện biểu thức này, cần tính giá trị (2 × load_avg)/(2×load_avg + 1) trước, sau đó nhân với recent_cpu. Thực hiện khácthứ tự có thể dẫn đến lỗi tràn bộ nhớ.
Cần phải cài đặt hàm thread_get_recent_cpu() trongthreads/thread.c:
• int thread_get_recent_cpu(void): Trả về giá trị recent_cpu củatiểu trình hiện tại (tính theo phần trăm), được làm tròn đến sốnguyên gần nhất.
<b>1.4.4. Load Average</b>
Giá trị load_avg, thường được gọi là thời gian tải trung bình,dùng để ước tính số tiểu trình trung bình được thực thi trong vịngmột phút trước đó. Giống như recent_cpu, giá trị này cũng làexponentially weighted moving average.
Tuy nhiên, khác với độ ưu tiên và recent_cpu, load_avg đượcxác định trên phạm vi tồn hệ thống, khơng phải đặc trưng theotừng tiểu trình. Tại thời điểm hệ thống bắt đầu hoạt động, giá trịnày được khởi tạo bằng 0. Mỗi một giây trôi qua, nó được cập nhậtlại theo cơng thức sau:
load_avg = (59/60) × load_avg + (1/60) × ready_threads6
</div><span class="text_page_counter">Trang 7</span><div class="page_container" data-page="7">Trong cơng thức này, ready_threads là tổng số tiểu trình đangchạy hoặc đang ở trạng thái sẵn sàng (ready) tại thời điểm cập nhật.Giá trị này được trả về thông qua hàm thread_get_load_avg(),hàm này đã được định nghĩa trong threads/thread.c nhưng chưađược cài đặt:
• int thread_get_load_avg(void): Trả về thời gian tải trung bìnhcủa hệ thống (tính theo phần trăm), làm tròn tới số nguyên gầnnhất.
<b>2. Triển khai đề tài2.1. Thao tác với file</b>
- Các file sẽ thao tác trong đề tài này: threads/thread.c, threads/thread.h,Devices/timer.c
Như ta đã thấy, các công để tính tốn các thơng số trên đều ở dưới dạng sốthực mà không phải ở dạng số nguyên. Tuy nhiên mã nguồn Pintos lại khơnghỗ trợ các phép tốn với số thực có dấu chấm động. Vì vậy, cần tạo một tậptin “ fixed_point.h” nằm trong thư mục pitos/src/threads/. Tập tin này có cấutrúc và các hàm cần thiết để tính tốn số thực.
Dưới đây tóm tắt cách thực hiện các phép toán số học dấu phẩy động trongC. Trong bảng, x và y là các số dấu phẩy động, n là một số nguyên, các sốdấu phẩy động ở định dạng p.q có dấu trong đó p + q = 31, và f là 1 << q:Convert n to fixed point: n * f
Convert x to integer (rounding toward zero): x / f
Convert x to integer (rounding to nearest): (x + f / 2) / f if x >= 0,(x - f / 2) / f if x <= 0.
Add x and y: x + ySubtract y from x: x - yAdd x and n: x + n * fSubtract n from x: x - n * f
Multiply x by y: ((int64_t) x) * y / f
</div><span class="text_page_counter">Trang 8</span><div class="page_container" data-page="8">Multiply x by n: x * n
Divide x by y: ((int64_t) x) * f / yDivide x by n: x / n
void mlfqs_recent_cpu_update (struct thread* t,void * aux)Cập nhật mức ưu tiên mỗi 4 timer ticker
void mlfqs_thread_priority_update (struct thread* t, void * aux)Cập nhật CPU gần đây và Load Average mỗi giây:
void mlfqs_rc_and_la_update (void)Cập nhật các hàm so sánh- threadlock_cmp_priority- cmp_priority
Cập nhật các hàm xử lý lock- thread_release_lock
8
</div><span class="text_page_counter">Trang 9</span><div class="page_container" data-page="9">Cập nhật theo công thức và thuật tốn
Chỉnh sửa timer_interrupt để phục vụ tính tốn load_avg và recent_cpu:if (ticks % TIMER_FREQ == 0)
nếu đúng thì trả về recent_cpu và load_avg mỗi giâyif (ticks % 4 == 0)
Nếu đúng thì trả về priority mỗi 4 timer ticks
<b>3. Kết quả sau khi chạy thử</b>
</div><span class="text_page_counter">Trang 10</span><div class="page_container" data-page="10">4. Link Github và các link khácGithub:
- Pintos: src/threads/thread.c File Reference (jhu-cs318.github.io)
10
</div>