From 4282fe06c7f121c93cb64e52f8d6772095438398 Mon Sep 17 00:00:00 2001 From: zhaoyanbai Date: Sat, 15 Aug 2026 08:43:58 +0800 Subject: [PATCH] =?utf8?q?=E6=B7=BB=E5=8A=A0=E9=80=9A=E8=BF=87TSC=E7=BB=9F?= =?utf8?q?=E8=AE=A1=E8=BF=9B=E7=A8=8B=E7=B2=BE=E7=A1=AE=E8=BF=90=E8=A1=8C?= =?utf8?q?=E6=97=B6=E9=97=B4=E7=9A=84=E8=83=BD=E5=8A=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- include/system.h | 5 ++++ include/task.h | 9 ++++--- kernel/ap.c | 65 +++++++++++++++++++++++++++++++++++++++++++++--- kernel/fork.c | 4 +-- kernel/hpet.c | 35 ++++++++++++++++++++++++++ kernel/sched.c | 23 ++++++++++++++--- kernel/system.c | 41 ++++++++++++++++++++++++++++++ 7 files changed, 169 insertions(+), 13 deletions(-) diff --git a/include/system.h b/include/system.h index 40b9828..e8231d8 100644 --- a/include/system.h +++ b/include/system.h @@ -68,6 +68,11 @@ void kfree(void* addr); #define disableIRQ() cli() #define enableIRQ() sti() +extern uint64_t tsc_khz; // TSC频率(KHZ:次/毫秒) +uint64_t rdtsc(); + +void udiv64(uint64_t dividend, uint64_t divisor, uint64_t* quotient, uint64_t* remainder); + #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define INT_STACK_SIZE PAGE_SIZE diff --git a/include/task.h b/include/task.h index e143b60..731239d 100644 --- a/include/task.h +++ b/include/task.h @@ -88,9 +88,11 @@ typedef union task_union { int ticks_left; // 时间片剩余 // 仅用于统计 - uint32_t st_ticks; - uint32_t sched_cnt; // 被调度换上CPU的次数 - uint32_t sched_keep_cnt; // 时间片到了,但是没有被换出,又重新执行的次数 + uint64_t st_ticks; + uint64_t st_last_exec_tsc; // 上次被调度上CPU执行的TSC时间 + uint64_t st_runtime_tsc; // 总的运行时间TSC时间 + uint32_t sched_cnt; // 被调度换上CPU的次数 + uint32_t sched_keep_cnt; // 时间片到了,但是没有被换出,又重新执行的次数 uint64_t magic; // 栈溢出标志 }; @@ -123,6 +125,7 @@ void task_set_ready(task_t* t); void task_set_wait(); // 只有当前进程可以调用 void task_init_lists(task_t* t); +void task_init_stats(task_t* t); #endif // ASM diff --git a/kernel/ap.c b/kernel/ap.c index 288c2bd..4a10353 100644 --- a/kernel/ap.c +++ b/kernel/ap.c @@ -309,10 +309,66 @@ const char* task_state(unsigned int state) { return s[state]; } + +static char* format_runtime_tsc(uint64_t tsc) { + uint64_t runtime_tsc = tsc; + uint64_t _ms = 0; + uint64_t _us = 0; + uint64_t _ns = 0; + uint64_t _remainder = 0; + udiv64(runtime_tsc, tsc_khz, &_ms, &_remainder); + udiv64(_remainder * 1000, tsc_khz, &_us, &_remainder); + udiv64(_remainder * 1000, tsc_khz, &_ns, NULL); + + uint64_t total_seconds = 0; + uint64_t days = 0; + uint64_t hours = 0; + uint64_t minutes = 0; + uint64_t seconds = 0; + + // total_seconds = ms / 1000; + // ms = ms % 1000 + udiv64(_ms, 1000, &total_seconds, &_ms); + + // days = total_seconds / (60 * 60 * 24); + udiv64(total_seconds, 60 * 60 * 24, &days, &total_seconds); + udiv64(total_seconds, 60 * 60, &hours, &total_seconds); + udiv64(total_seconds, 60, &minutes, &seconds); + + static char buffer[64]; + char tmp[16]; + + buffer[0] = 0; + + if (days > 0) { + sprintf(tmp, "%lud", days); + strcat(buffer, tmp); + } + if (hours > 0) { + sprintf(tmp, "%uh", (uint32_t)hours); + strcat(buffer, tmp); + } + if (minutes > 0) { + sprintf(tmp, "%um", (uint32_t)minutes); + strcat(buffer, tmp); + } + if (seconds > 0) { + sprintf(tmp, "%us", (uint32_t)seconds); + strcat(buffer, tmp); + } + + uint32_t _ms32 = (uint32_t)_ms; + uint32_t _us32 = (uint32_t)_us; + _us32 /= 100; // 保留1位小数 + sprintf(tmp, ".%03u.%u", _ms32, _us32); + strcat(buffer, tmp); + + return (char*)buffer; +} void print_all_tasks() { extern task_t* monitor_tasks[]; - ap_printl(MPL_TASK_TITLE, " NAME STATE LT/PI REASON TICKS SCHED KEEP"); + ap_printl(MPL_TASK_TITLE, " NAME STATE LT/PI REASON TICKS RUNTIME"); for (int i = 0; i < 10; i++) { task_t* p = monitor_tasks[i]; @@ -321,7 +377,9 @@ void print_all_tasks() { continue; } - ap_printl(MPL_TASK_0 + p->pid, "%08x %-6s:%u %s %02d/%02u %-10s %-9u %-9u %-9u", + char* runtime_str = format_runtime_tsc(p->st_runtime_tsc); + + ap_printl(MPL_TASK_0 + p->pid, "%08x %-6s:%u %s %02d/%02u %-10s %-9lu %16s", p, // p->name, // p->pid, // @@ -330,8 +388,7 @@ void print_all_tasks() { p->priority, // p->reason, // p->st_ticks, // - p->sched_cnt, // - p->sched_keep_cnt // + runtime_str // ); } } diff --git a/kernel/fork.c b/kernel/fork.c index dd36f00..b51ab47 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -32,6 +32,7 @@ int do_fork(pt_regs_t* regs, unsigned long flags) { tsk->state = TASK_INITING; task_init_lists(tsk); + task_init_stats(tsk); unsigned long iflags; irq_save(iflags); @@ -85,9 +86,6 @@ int do_fork(pt_regs_t* regs, unsigned long flags) { tsk->priority = current->priority; tsk->ticks_left = TASK_TICKS_PER_QUANTUM; - tsk->st_ticks = 0; - tsk->sched_cnt = 0; - tsk->sched_keep_cnt = 0; // for switch_to tsk->eip = child_regs->eip; diff --git a/kernel/hpet.c b/kernel/hpet.c index 665bf94..7a0d2e0 100644 --- a/kernel/hpet.c +++ b/kernel/hpet.c @@ -194,6 +194,38 @@ bool hpet_calibration_end(uint32_t timn) { return false; } +void hpet_calibrate_tsc(uint32_t hz) { + const uint32_t timn = 0; + + hpet_disable(); + + hpet_prepare_calibration(timn, hz); + + hpet_enable(); + + uint64_t tsc_t0 = rdtsc(); + + while (!hpet_calibration_end(timn)) { + asm("pause"); + } + + uint64_t tsc_t1 = rdtsc(); + + assert(tsc_t1 > tsc_t0); + + uint64_t tsc_delta = tsc_t1 - tsc_t0; + + // HPET精确等待T秒,T = 1/hz,则T秒内TSC的计数为tsc_delta + // tsc_dela = tsc频率(次/秒) * T秒 + // 所以 tcs频率(HZ:次/秒)= tsc_delta / T秒 = tsc_delta * hz + // 所以 tcs频率(KHZ:次/毫秒) = tsc_delta * hz / 1000 + // + // tsc_khz = tsc_delta * hz / 1000; + udiv64(tsc_delta * hz, 1000, &tsc_khz, NULL); + + printk("TSC frequency: %u KHz\n", tsc_khz); +} + void hpet_init() { assert(hpet_use_phys_addr_index < sizeof(hpet_phys_addrs) / sizeof(hpet_phys_addrs[0])); hpet_phys_addr = hpet_phys_addrs[hpet_use_phys_addr_index]; @@ -219,4 +251,7 @@ void hpet_init() { printk("HPET Configuration: 0x%08x%08x\n", (uint32_t)(config >> 32), (uint32_t)config); printk("HPET enabled: %s\n", (config & (1ULL << 0)) ? "Y" : "N"); printk("HPET legacy replacement: %s\n", (config & (1ULL << 1)) ? "Y" : "N"); + + // 用HPET等待 1秒*1000/10=100ms 的时间来校准TSC频率 + hpet_calibrate_tsc(10); } diff --git a/kernel/sched.c b/kernel/sched.c index ddbb8aa..4720a5a 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -56,14 +56,13 @@ void init_root_task() { root_task.reason = "root"; root_task.priority = TASK_PRIORITY_MAX; root_task.ticks_left = 1; - root_task.st_ticks = 0; root_task.vma_list = NULL; - root_task.sched_cnt = 0; - root_task.sched_keep_cnt = 0; root_task.magic = TASK_MAGIC; strcpy(root_task.name, "root"); task_init_lists(&root_task); + task_init_stats(&root_task); + root_task.st_last_exec_tsc = rdtsc(); list_add(&root_task.list, &all_tasks); @@ -316,7 +315,16 @@ void schedule() { clear_need_schedule(); if (prev != next) { + uint64_t tsc = rdtsc(); + + prev->st_runtime_tsc += tsc - prev->st_last_exec_tsc; + prev->st_last_exec_tsc = 0; + + assert(next->st_last_exec_tsc == 0); + next->st_last_exec_tsc = tsc; + next->sched_cnt++; + context_switch(prev, next); } else { next->sched_keep_cnt++; @@ -373,6 +381,15 @@ void task_init_lists(task_t* t) { INIT_LIST_HEAD(&t->waitq_list); } +void task_init_stats(task_t* t) { + assert(t != NULL); + t->st_ticks = 0; + t->st_last_exec_tsc = 0; + t->st_runtime_tsc = 0; + t->sched_cnt = 0; + t->sched_keep_cnt = 0; +} + /// static volatile bool _need_schedule = false; diff --git a/kernel/system.c b/kernel/system.c index 45ee423..04c5fba 100644 --- a/kernel/system.c +++ b/kernel/system.c @@ -234,6 +234,47 @@ void io_mfence() { asm volatile("mfence" ::: "memory"); } +uint64_t tsc_khz = 0; // TSC频率(KHZ:次/毫秒) + +uint64_t rdtsc() { + uint32_t lo, hi; + + asm volatile("rdtsc;" : "=a"(lo), "=d"(hi)::"memory"); + + uint64_t tsc = ((uint64_t)hi << 32) | lo; + + return tsc; +} + +void udiv64(uint64_t dividend, uint64_t divisor, uint64_t* quotient, uint64_t* remainder) { + uint64_t _quotient = 0; + uint64_t _remainder = 0; + + // 整体算法类似10进的除法,只不过换成二进制的数来算 + // 10进制需要猜能乘几,而二进制不用猜,只有0和1,所以直接比较大小即可 + for (int i = 63; i >= 0; i--) { + // 以下两行可以看成类似10进制除法的被除数从高往低试除数时,被除数被逐渐试的高位数 + _remainder <<= 1; + _remainder |= (dividend >> i) & 1; + + // 如果这部分高位数能比被除数大,则商的对应位为1,否则为0 + if (_remainder >= divisor) { + _remainder -= divisor; + _quotient |= (1ULL << i); + } else { + // 商为0的比特位其实什么都不用做 + } + } + + if (quotient) { + *quotient = _quotient; + } + + if (remainder) { + *remainder = _remainder; + } +} + paddr_t get_rcba_paddr() { uint32_t rcba = pci_get_rcba(); -- 2.55.0