#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
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; // 栈溢出标志
};
void task_set_wait(); // 只有当前进程可以调用
void task_init_lists(task_t* t);
+void task_init_stats(task_t* t);
#endif // ASM
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];
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, //
p->priority, //
p->reason, //
p->st_ticks, //
- p->sched_cnt, //
- p->sched_keep_cnt //
+ runtime_str //
);
}
}
tsk->state = TASK_INITING;
task_init_lists(tsk);
+ task_init_stats(tsk);
unsigned long iflags;
irq_save(iflags);
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;
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];
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);
}
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);
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++;
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;
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();