diff --git a/libraries/libmesosphere/source/kern_k_dump_object.cpp b/libraries/libmesosphere/source/kern_k_dump_object.cpp index 628d3e869..6582a8143 100644 --- a/libraries/libmesosphere/source/kern_k_dump_object.cpp +++ b/libraries/libmesosphere/source/kern_k_dump_object.cpp @@ -252,6 +252,13 @@ namespace ams::kern::KDumpObject { } } + ALWAYS_INLINE s64 GetTickOrdered() { + __asm__ __volatile__("" ::: "memory"); + const s64 tick = KHardwareTimer::GetTick(); + __asm__ __volatile__("" ::: "memory"); + return tick; + } + } void DumpThread() { @@ -648,7 +655,73 @@ namespace ams::kern::KDumpObject { } void DumpKernelCpuUtilization() { - /* TODO */ + MESOSPHERE_RELEASE_LOG("Dump Kernel Cpu Utilization\n"); + + constexpr size_t MaxLogDepth = 64; + { + /* Create tracking arrays. */ + KAutoObject *objects[MaxLogDepth]; + u32 cpu_time[MaxLogDepth]; + + s64 start_tick; + size_t i, n; + KDpcManager::Sync(); + { + /* Lock the thread list. */ + KThread::ListAccessor accessor; + + /* Begin tracking. */ + start_tick = GetTickOrdered(); + + /* Iterate, finding kernel threads. */ + const auto end = accessor.end(); + i = 0; + for (auto it = accessor.begin(); it != end; ++it) { + KThread *thread = static_cast(std::addressof(*it)); + if (KProcess *process = thread->GetOwnerProcess(); process == nullptr) { + if (AMS_LIKELY(i < MaxLogDepth)) { + if (AMS_LIKELY(thread->Open())) { + cpu_time[i] = thread->GetCpuTime(); + objects[i] = thread; + ++i; + } + } + } + } + + /* Keep track of how many kernel threads we found. */ + n = i; + } + + /* Wait one second. */ + const s64 timeout = KHardwareTimer::GetTick() + ams::svc::Tick(TimeSpan::FromSeconds(1)); + GetCurrentThread().Sleep(timeout); + KDpcManager::Sync(); + + /* Update our metrics. */ + for (i = 0; i < n; ++i) { + KThread *thread = static_cast(objects[i]); + cpu_time[i] = thread->GetCpuTime() - cpu_time[i]; + } + + /* End tracking. */ + const s64 end_tick = GetTickOrdered(); + + /* Log thread utilization. */ + for (i = 0; i < n; ++i) { + KThread *thread = static_cast(objects[i]); + const s64 t = static_cast(cpu_time[i]) * 1000 / (end_tick - start_tick); + + MESOSPHERE_RELEASE_LOG("tid=%3lu (kernel) %3lu.%lu%% pri=%2d af=%lx\n", thread->GetId(), t / 10, t % 10, thread->GetPriority(), thread->GetAffinityMask().GetAffinityMask()); + } + + /* Close all objects. */ + for (i = 0; i < n; ++i) { + objects[i]->Close(); + } + } + + MESOSPHERE_RELEASE_LOG("\n"); } void DumpCpuUtilization() {