Việc đo đạc và sử dụng thời gian là một thành phần cốt lõi của bất kỳ hệ điều hành nào. Bài viết này sẽ phân tích các cơ chế cơ bản về cách thời gian được quản lý trong một hệ thống (như Linux) và những lưu ý quan trọng khi thực hiện đo lường.
1. Nguồn gốc Thời gian Phần cứng (Clock)
Thời gian trong hệ thống bắt nguồn từ một thiết bị phần cứng bên ngoài gọi là “clock”.
- Nguồn cấp: Nguồn của clock thường được cấp từ một cục pin riêng gọi là CMOS. Điều này cho phép clock vẫn tiếp tục chạy (và duy trì thời gian) ngay cả khi máy tính đã được tắt nguồn hoàn toàn.
- Tần số: Clock có xung nhịp (tần số) cố định, thường là các mốc chẵn như 10MHz, 100MHz, hoặc 1000MHz.
- Thanh ghi (Register): Nó sở hữu một thanh ghi (ví dụ: 32 bit) dùng để lưu một giá trị đếm. Khi bộ đếm xung nhịp đạt đến giá trị này, nó sẽ kích hoạt (raise) một ngắt (interrupt).
2. Cơ chế Timer Interrupt và Biến HZ
Giá trị trong thanh ghi của clock có thể được cấu hình thông qua một biến hệ thống, trong Linux gọi là HZ.
Biến HZ định nghĩa số lần mà “timer hardware interrupt” (ngắt hẹn giờ phần cứng) sẽ xảy ra trong một giây.
- Ví dụ: Giả sử hệ thống định nghĩa
HZ = 1000, nghĩa là hệ thống mong muốn nhận được 1000 ngắt mỗi giây. - Nếu clock phần cứng có xung nhịp là 100MHz.
- Để đạt được 1000 ngắt/giây, giá trị cần nạp vào thanh ghi của clock sẽ là:
100,000,000 \(Hz) / 1000 (HZ) = 100,000
- Khi đó, cứ mỗi khi clock đếm đủ 100.000 xung nhịp, nó sẽ tạo ra một ngắt “timer hardware interrupt”.
3. Vai trò của jiffies trong Kernel
Trình xử lý ngắt hẹn giờ (Timer interrupt handler) có hai nhiệm vụ chính:
- Quản lý Scheduler: Mỗi lần timer interrupt xảy ra, nó sẽ gọi scheduler (bộ lập lịch). Đây là cơ chế cho phép scheduler tiến hành việc lập lịch, quyết định xem có cần chuyển đổi (switch) tác vụ (task) đang chạy hay không.
- Cập nhật
jiffies: Quan trọng hơn, nó cập nhật giá trị của biến toàn cụcjiffies. Biếnjiffieslà một bộ đếm, lưu trữ “thời gian” của kernel tính từ lúc khởi động, được đo bằng số lần timer interrupt đã xảy ra.
Toàn bộ việc đo đạc thời gian tương đối dưới kernel đều dựa trên biến jiffies này. Ví dụ, khi một chương trình gọi sleep(1) (ngủ 1 giây) và HZ là 1000, về bản chất, hệ thống sẽ “đánh thức” chương trình đó dậy sau khi biến jiffies đã tăng thêm 1000 đơn vị.
4. Các Lưu ý quan trọng khi Đo lường Thời gian
Khi sử dụng chính bộ timer của hệ thống để đo đạc thời gian thực thi của một đoạn mã, có hai vấn đề chính cần phải lưu ý:
A. Ảnh hưởng của Bộ lập lịch (Scheduler)
Trong quá trình đoạn mã đang chạy để được đo đạc, scheduler hoàn toàn có thể tạm dừng (pre-empt) đoạn mã đó, chuyển CPU cho một chương trình khác chạy. Sau một thời gian, scheduler mới quay lại thực thi tiếp đoạn mã.
- Hậu quả: Thời gian đo được sẽ bị sai lệch (tăng lên) so với thời gian thực tế. Ví dụ, thời gian thực thi thật của đoạn mã là 10 giây, nhưng do bị ngắt quãng, kết quả đo được có thể là 15 hoặc 20 giây.
- Giải pháp: Có thể xem xét việc vô hiệu hóa scheduler (disable pre-emption) trong đoạn mã cần đo, hoặc phổ biến hơn là tiến hành đo đạc nhiều lần và lấy kết quả trung bình.
B. Sai số do Vô hiệu hóa Ngắt (Disable Interrupt)
Trong một số đoạn mã quan trọng (critical section) của kernel, việc vô hiệu hóa ngắt (disable interrupt) là cần thiết.
- Hậu quả: Nếu việc vô hiệu hóa ngắt xảy ra, các ngắt “timer interrupt” sẽ không được xử lý. Điều này ngăn cản việc cập nhật giá trị cho biến
jiffies, khiến cho các giá trị thời gian đọc được trong lúc này có thể bị “lỗi thời” (out-of-date). - Cơ chế phục hồi: Tuy nhiên, phần cứng (clock) vẫn tiếp tục đếm và có một thanh ghi riêng để “counter” (đếm) số lần timer interrupt đã được raise lên nhưng chưa được xử lý. Ngay sau khi ngắt được cho phép trở lại (enable interrupt), trình xử lý ngắt sẽ chạy và cập nhật bù (update) giá trị mới nhất cho
jiffiesdựa trên số đếm của phần cứng.
