From 299c919d1d2cf3879af5778f448bea2bc873e366 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 25 Apr 2023 05:12:58 +0300 Subject: [PATCH] Add UserTime and KernelTime tracker --- Kernel.cpp | 46 ++++++++++++++--------------- KernelThread.cpp | 62 +++++++++++++++++++++++++++++++++------- SystemCalls/Syscalls.cpp | 28 +++++++++++------- Tasking/Scheduler.cpp | 38 ++++++++++-------------- Tasking/Task.cpp | 46 +++++++---------------------- include/task.hpp | 21 ++++---------- 6 files changed, 122 insertions(+), 119 deletions(-) diff --git a/Kernel.cpp b/Kernel.cpp index 14b7da6..8723980 100644 --- a/Kernel.cpp +++ b/Kernel.cpp @@ -81,6 +81,7 @@ LockClass mExtTrkLock; * - [?] Somewhere in the kernel, the memory is wrongly freed or memcpy/memset. * - [ ] GlobalDescriptorTable::SetKernelStack() is not working properly. * - [ ] Sometimes while the kernel is inside BeforeShutdown(), we end up in a deadlock. + * - [ ] CPU usage is not working properly. * * CREDITS AND REFERENCES: * - General: @@ -200,8 +201,6 @@ Time::time *TimeManager = nullptr; VirtualFileSystem::Virtual *vfs = nullptr; VirtualFileSystem::Virtual *bootanim_vfs = nullptr; -Time::Clock BootClock; - KernelConfig Config = { .AllocatorType = Memory::MemoryAllocatorType::XallocV1, .SchedulerType = 1, @@ -254,18 +253,23 @@ EXTERNC void KPrint(const char *Format, ...) EXTERNC NIF void Main(BootInfo *Info) { - BootClock = Time::ReadClock(); memcpy(&bInfo, Info, sizeof(BootInfo)); debug("BootInfo structure is at %p", bInfo); Display = new Video::Display(bInfo.Framebuffer[0]); KPrint("%s - %s [\e058C19%s\eFFFFFF]", KERNEL_NAME, KERNEL_VERSION, GIT_COMMIT_SHORT); - /**************************************************************************************/ KPrint("CPU: \e058C19%s \e8822AA%s \e8888FF%s", CPU::Hypervisor(), CPU::Vendor(), CPU::Name()); + if (DebuggerIsAttached) + KPrint("\eFFA500Kernel debugger detected."); + + /**************************************************************************************/ KPrint("Initializing GDT and IDT"); Interrupts::Initialize(0); + KPrint("Loading Kernel Symbols"); + KernelSymbolTable = new SymbolResolver::Symbols((uintptr_t)Info->Kernel.FileBase); + KPrint("Reading Kernel Parameters"); ParseConfig((char *)bInfo.Kernel.CommandLine, &Config); @@ -286,15 +290,23 @@ EXTERNC NIF void Main(BootInfo *Info) KPrint("Initializing CPU Features"); CPU::InitializeFeatures(0); - if (DebuggerIsAttached) - KPrint("\eFFA500Kernel debugger detected."); - - KPrint("Loading Kernel Symbols"); - KernelSymbolTable = new SymbolResolver::Symbols((uintptr_t)Info->Kernel.FileBase); - KPrint("Initializing Power Manager"); PowerManager = new Power::Power; +#if defined(a64) + PowerManager->InitDSDT(); +#elif defined(a32) + // FIXME: Add ACPI support for i386 +#elif defined(aa64) +#endif + + KPrint("Enabling Interrupts on Bootstrap Processor"); + Interrupts::Enable(0); + + KPrint("Initializing Timers"); + TimeManager = new Time::time; + TimeManager->FindTimers(PowerManager->GetACPI()); + KPrint("Initializing PCI Manager"); PCIManager = new PCI::PCI; @@ -308,20 +320,6 @@ EXTERNC NIF void Main(BootInfo *Info) PCI::Descriptors::GetProgIFName(Device->Class, Device->Subclass, Device->ProgIF)); } - KPrint("Enabling Interrupts on Bootstrap Processor"); - Interrupts::Enable(0); - -#if defined(a64) - PowerManager->InitDSDT(); -#elif defined(a32) - // FIXME: Add ACPI support for i386 -#elif defined(aa64) -#endif - - KPrint("Initializing Timers"); - TimeManager = new Time::time; - TimeManager->FindTimers(PowerManager->GetACPI()); - KPrint("Initializing Bootstrap Processor Timer"); Interrupts::InitializeTimer(0); diff --git a/KernelThread.cpp b/KernelThread.cpp index 665eb2e..360c84a 100644 --- a/KernelThread.cpp +++ b/KernelThread.cpp @@ -92,16 +92,53 @@ const char *SuccessSourceStrings[] = { "SchedulerSearchProcessThread", }; -void TaskMgr() +void TaskMgr_Dummy100Usage() { + while (1) + ; +} + +void TaskMgr_Dummy0Usage() +{ + while (1) + TaskManager->Sleep(1000000); +} + +uint64_t GetUsage(uint64_t OldSystemTime, Tasking::TaskInfo *Info) +{ + /* https://github.com/reactos/reactos/blob/560671a784c1e0e0aa7590df5e0598c1e2f41f5a/base/applications/taskmgr/perfdata.c#L347 */ + if (Info->OldKernelTime || Info->OldUserTime) + { + uint64_t SystemTime = TimeManager->GetCounter() - OldSystemTime; + uint64_t CurrentTime = Info->KernelTime + Info->UserTime; + uint64_t OldTime = Info->OldKernelTime + Info->OldUserTime; + uint64_t CpuUsage = (CurrentTime - OldTime) / SystemTime; + CpuUsage = CpuUsage * 100; + + // debug("CurrentTime: %ld OldTime: %ld Time Diff: %ld Usage: %ld%%", + // CurrentTime, OldTime, SystemTime, CpuUsage); + + Info->OldKernelTime = Info->KernelTime; + Info->OldUserTime = Info->UserTime; + return CpuUsage; + } + Info->OldKernelTime = Info->KernelTime; + Info->OldUserTime = Info->UserTime; + return 0; +} + +void TaskMgr() +{ + TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)TaskMgr_Dummy100Usage)->Rename("Dummy 100% Usage"); + TaskManager->CreateThread(TaskManager->GetCurrentProcess(), (Tasking::IP)TaskMgr_Dummy0Usage)->Rename("Dummy 0% Usage"); + while (1) { - CPU::Interrupts(CPU::Disable); static int sanity = 0; Video::ScreenBuffer *sb = Display->GetBuffer(0); - for (short i = 0; i < 340; i++) + for (short i = 0; i < 500; i++) { - for (short j = 0; j < 200; j++) + for (short j = 0; j < 500; j++) { uint32_t *Pixel = (uint32_t *)((uintptr_t)sb->Buffer + (j * sb->Width + i) * (bInfo.Framebuffer[0].BitsPerPixel / 8)); *Pixel = 0x222222; @@ -112,19 +149,23 @@ void TaskMgr() Display->GetBufferCursor(0, &tmpX, &tmpY); Display->SetBufferCursor(0, 0, 0); printf("\eF02C21Task Manager\n"); + static uint64_t OldSystemTime = 0; foreach (auto Proc in TaskManager->GetProcessList()) { int Status = Proc->Status; - printf("\e%s-> \eAABBCC%s \e00AAAA%s\n", - Statuses[Status], Proc->Name, StatusesSign[Status]); + uint64_t ProcessCpuUsage = GetUsage(OldSystemTime, &Proc->Info); + printf("\e%s-> \eAABBCC%s \e00AAAA%s %ld%% (KT: %ld UT: %ld)\n", + Statuses[Status], Proc->Name, StatusesSign[Status], ProcessCpuUsage, Proc->Info.KernelTime, Proc->Info.UserTime); foreach (auto Thd in Proc->Threads) { Status = Thd->Status; - printf(" \e%s-> \eAABBCC%s \e00AAAA%s\n\eAABBCC", - Statuses[Status], Thd->Name, StatusesSign[Status]); + uint64_t ThreadCpuUsage = GetUsage(OldSystemTime, &Thd->Info); + printf(" \e%s-> \eAABBCC%s \e00AAAA%s %ld%% (KT: %ld UT: %ld)\n\eAABBCC", + Statuses[Status], Thd->Name, StatusesSign[Status], ThreadCpuUsage, Thd->Info.KernelTime, Thd->Info.UserTime); } } + OldSystemTime = TimeManager->GetCounter(); #if defined(a64) register uintptr_t CurrentStackAddress asm("rsp"); #elif defined(a32) @@ -138,7 +179,8 @@ void TaskMgr() Display->SetBufferCursor(0, tmpX, tmpY); if (!Config.BootAnimation) Display->SetBuffer(0); - CPU::Interrupts(CPU::Enable); + + TaskManager->Sleep(100); } } #endif @@ -315,7 +357,7 @@ void KernelMainThread() #ifdef DEBUG /* TODO: This should not be enabled because it may cause a deadlock. Not sure where or how. */ // Tasking::PCB *tskMgr = TaskManager->CreateProcess(TaskManager->GetCurrentProcess(), "Debug Task Manager", Tasking::TaskTrustLevel::Kernel); - // TaskManager->CreateThread(tskMgr, (Tasking::IP)TaskMgr)->SetPriority(Tasking::High); + // TaskManager->CreateThread(tskMgr, (Tasking::IP)TaskMgr)->SetPriority(Tasking::Low); TreeFS(vfs->GetRootNode(), 0); #endif diff --git a/SystemCalls/Syscalls.cpp b/SystemCalls/Syscalls.cpp index 7c8bcc0..af6a797 100644 --- a/SystemCalls/Syscalls.cpp +++ b/SystemCalls/Syscalls.cpp @@ -28,13 +28,26 @@ extern "C" uintptr_t SystemCallsHandler(SyscallsFrame *Frame) CPU::Interrupts(CPU::Enable); SmartLock(SyscallsLock); /* TODO: This should be replaced or moved somewhere else. */ -#if defined(a64) - switch (TaskManager->GetCurrentThread()->Info.Compatibility) + Tasking::TaskInfo *Ptinfo = &TaskManager->GetCurrentProcess()->Info; + Tasking::TaskInfo *Ttinfo = &TaskManager->GetCurrentThread()->Info; + uint64_t TempTimeCalc = TimeManager->GetCounter(); + + switch (Ttinfo->Compatibility) { case Tasking::TaskCompatibility::Native: - return HandleNativeSyscalls(Frame); + { + uintptr_t ret = HandleNativeSyscalls(Frame); + Ptinfo->KernelTime += TimeManager->GetCounter() - TempTimeCalc; + Ttinfo->KernelTime += TimeManager->GetCounter() - TempTimeCalc; + return ret; + } case Tasking::TaskCompatibility::Linux: - return HandleLinuxSyscalls(Frame); + { + uintptr_t ret = HandleLinuxSyscalls(Frame); + Ptinfo->KernelTime += TimeManager->GetCounter() - TempTimeCalc; + Ttinfo->KernelTime += TimeManager->GetCounter() - TempTimeCalc; + return ret; + } case Tasking::TaskCompatibility::Windows: { error("Windows compatibility not implemented yet."); @@ -47,10 +60,5 @@ extern "C" uintptr_t SystemCallsHandler(SyscallsFrame *Frame) break; } } -#elif defined(a32) - fixme("System call %lld", Frame->eax); -#elif defined(aa64) - fixme("System call"); -#endif - return -1; + assert(false); /* Should never reach here. */ } diff --git a/Tasking/Scheduler.cpp b/Tasking/Scheduler.cpp index 3059f2d..7d41026 100644 --- a/Tasking/Scheduler.cpp +++ b/Tasking/Scheduler.cpp @@ -476,8 +476,9 @@ namespace Tasking warn("Scheduler stopped."); return; } + bool ProcessNotChanged = false; CPU::x64::writecr3({.raw = (uint64_t)KernelPageTable}); /* Restore kernel page table for safety reasons. */ - uint64_t SchedTmpTicks = CPU::Counter(); + uint64_t SchedTmpTicks = TimeManager->GetCounter(); this->LastTaskTicks.store(SchedTmpTicks - this->SchedulerTicks.load()); CPUData *CurrentCPU = GetCurrentCPU(); schedbg("Scheduler called on CPU %d.", CurrentCPU->ID); @@ -511,6 +512,7 @@ namespace Tasking if (unlikely(InvalidPCB(CurrentCPU->CurrentProcess.load()) || InvalidTCB(CurrentCPU->CurrentThread.load()))) { schedbg("Invalid process or thread. Finding a new one."); + ProcessNotChanged = true; if (this->FindNewProcess(CurrentCPU)) goto Success; else @@ -539,6 +541,7 @@ namespace Tasking #ifdef ON_SCREEN_SCHEDULER_TASK_MANAGER SuccessSource = 1; #endif + ProcessNotChanged = true; goto Success; } schedbg("Passed GetNextAvailableThread"); @@ -567,22 +570,24 @@ namespace Tasking } } - /* [this]->RealEnd */ warn("Unwanted reach!"); TaskingScheduler_OneShot(100); - goto RealEnd; + goto End; - /* Idle-->Success */ Idle: + ProcessNotChanged = true; CurrentCPU->CurrentProcess = IdleProcess; CurrentCPU->CurrentThread = IdleThread; - /* Success-->End */ Success: schedbg("Process \"%s\"(%d) Thread \"%s\"(%d) is now running on CPU %d", CurrentCPU->CurrentProcess->Name, CurrentCPU->CurrentProcess->ID, CurrentCPU->CurrentThread->Name, CurrentCPU->CurrentThread->ID, CurrentCPU->ID); + if (!ProcessNotChanged) + UpdateUsage(&CurrentCPU->CurrentProcess->Info, &CurrentCPU->CurrentProcess->Security, CurrentCPU->ID); + UpdateUsage(&CurrentCPU->CurrentThread->Info, &CurrentCPU->CurrentThread->Security, CurrentCPU->ID); + CurrentCPU->CurrentProcess->Status = TaskStatus::Running; CurrentCPU->CurrentThread->Status = TaskStatus::Running; @@ -621,21 +626,9 @@ namespace Tasking break; } - /* End-->RealEnd */ - // End: - /* TODO: This is not accurate. */ - if (CurrentCPU->CurrentProcess->Security.TrustLevel == TaskTrustLevel::User) - UpdateUserTime(&CurrentCPU->CurrentProcess->Info); - else - UpdateKernelTime(&CurrentCPU->CurrentProcess->Info); - - if (CurrentCPU->CurrentThread->Security.TrustLevel == TaskTrustLevel::User) - UpdateUserTime(&CurrentCPU->CurrentThread->Info); - else - UpdateKernelTime(&CurrentCPU->CurrentThread->Info); - - UpdateUsage(&CurrentCPU->CurrentProcess->Info, CurrentCPU->ID); - UpdateUsage(&CurrentCPU->CurrentThread->Info, CurrentCPU->ID); + if (!ProcessNotChanged) + (&CurrentCPU->CurrentProcess->Info)->LastUpdateTime = TimeManager->GetCounter(); + (&CurrentCPU->CurrentThread->Info)->LastUpdateTime = TimeManager->GetCounter(); TaskingScheduler_OneShot(CurrentCPU->CurrentThread->Info.Priority); if (CurrentCPU->CurrentThread->Security.IsDebugEnabled && CurrentCPU->CurrentThread->Security.IsKernelDebugEnabled) @@ -666,9 +659,8 @@ namespace Tasking Frame->rip, Frame->rflags, Frame->InterruptNumber, Frame->ErrorCode); schedbg("================================================================"); - /* RealEnd->[Function Exit] */ - RealEnd: - this->SchedulerTicks.store(CPU::Counter() - SchedTmpTicks); + End: + this->SchedulerTicks.store(TimeManager->GetCounter() - SchedTmpTicks); __sync; /* TODO: Is this really needed? */ } diff --git a/Tasking/Task.cpp b/Tasking/Task.cpp index 35d5284..aefda10 100644 --- a/Tasking/Task.cpp +++ b/Tasking/Task.cpp @@ -172,40 +172,16 @@ namespace Tasking } } - SafeFunction NIF void Task::UpdateUserTime(TaskInfo *Info) + SafeFunction NIF void Task::UpdateUsage(TaskInfo *Info, TaskSecurity *Security, int Core) { - // TODO - Info->UserTime++; - } + uint64_t CurrentTime = TimeManager->GetCounter(); + uint64_t TimePassed = CurrentTime - Info->LastUpdateTime; + // Info->LastUpdateTime = CurrentTime; - SafeFunction NIF void Task::UpdateKernelTime(TaskInfo *Info) - { - // TODO - Info->KernelTime++; - } - - SafeFunction NIF void Task::UpdateUsage(TaskInfo *Info, int Core) - { - if (Info->Affinity[Core] == true) - { - // TODO: Not working(?) - uint64_t CounterNow = CPU::Counter(); - - Info->OldUserTime = Info->CurrentUserTime; - Info->OldKernelTime = Info->CurrentKernelTime; - - Info->CurrentUserTime = Info->UserTime; - Info->CurrentKernelTime = Info->KernelTime; - - Info->Usage[Core] = (Info->CurrentUserTime - Info->OldUserTime) + (Info->CurrentKernelTime - Info->OldKernelTime); - Info->Usage[Core] = (Info->Usage[Core] * 100) / (CounterNow - Info->SpawnTime); - - Info->OldUserTime = Info->CurrentUserTime; - Info->OldKernelTime = Info->CurrentKernelTime; - - Info->CurrentUserTime = Info->UserTime; - Info->CurrentKernelTime = Info->KernelTime; - } + if (Security->TrustLevel == TaskTrustLevel::User) + Info->UserTime += TimePassed; + else + Info->KernelTime += TimePassed; } void ThreadDoExit() @@ -635,7 +611,7 @@ namespace Tasking } Thread->Info = {}; - Thread->Info.SpawnTime = CPU::Counter(); + Thread->Info.SpawnTime = TimeManager->GetCounter(); Thread->Info.Year = 0; Thread->Info.Month = 0; Thread->Info.Day = 0; @@ -644,7 +620,6 @@ namespace Tasking Thread->Info.Second = 0; for (int i = 0; i < MAX_CPU; i++) { - Thread->Info.Usage[i] = 0; Thread->Info.Affinity[i] = true; } Thread->Info.Priority = TaskPriority::Normal; @@ -741,7 +716,7 @@ namespace Tasking } Process->Info = {}; - Process->Info.SpawnTime = CPU::Counter(); + Process->Info.SpawnTime = TimeManager->GetCounter(); Process->Info.Year = 0; Process->Info.Month = 0; Process->Info.Day = 0; @@ -750,7 +725,6 @@ namespace Tasking Process->Info.Second = 0; for (int i = 0; i < MAX_CPU; i++) { - Process->Info.Usage[i] = 0; Process->Info.Affinity[i] = true; } Process->Info.Priority = TaskPriority::Normal; diff --git a/include/task.hpp b/include/task.hpp index 0c9573d..95e828b 100644 --- a/include/task.hpp +++ b/include/task.hpp @@ -95,13 +95,12 @@ namespace Tasking struct TaskInfo { + uint64_t OldUserTime = 0; + uint64_t OldKernelTime = 0; + uint64_t SleepUntil = 0; - uint64_t SpawnTime = 0; - uint64_t OldUserTime = 0, CurrentUserTime = 0; - uint64_t OldKernelTime = 0, CurrentKernelTime = 0; - uint64_t KernelTime = 0, UserTime = 0; + uint64_t KernelTime = 0, UserTime = 0, SpawnTime = 0, LastUpdateTime = 0; uint64_t Year, Month, Day, Hour, Minute, Second; - uint64_t Usage[256]; // MAX_CPU bool Affinity[256]; // MAX_CPU TaskPriority Priority; TaskArchitecture Architecture; @@ -252,9 +251,7 @@ namespace Tasking void RemoveThread(TCB *tcb); void RemoveProcess(PCB *pcb); - void UpdateUserTime(TaskInfo *Info); - void UpdateKernelTime(TaskInfo *Info); - void UpdateUsage(TaskInfo *Info, int Core); + void UpdateUsage(TaskInfo *Info, TaskSecurity *Security, int Core); bool FindNewProcess(void *CPUDataPointer); bool GetNextAvailableThread(void *CPUDataPointer); @@ -287,14 +284,6 @@ namespace Tasking void RevertProcessCreation(PCB *Process); void RevertThreadCreation(TCB *Thread); - long GetUsage(int Core) - { - if (IdleProcess) - return 100 - IdleProcess->Info.Usage[Core]; - else - return 0; - } - void KillThread(TCB *tcb, int Code) { tcb->Status = TaskStatus::Terminated;