#include "base/threading/platform_thread_metrics.h"
#include <windows.h>
#include <memory>
#include <optional>
#include <utility>
#include "base/memory/ptr_util.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "base/win/scoped_handle.h"
#include "build/build_config.h"
namespace base {
namespace {
std::optional<TimeDelta> GetImpreciseCumulativeCPUUsage(
const win::ScopedHandle& handle) {
FILETIME creation_time;
FILETIME exit_time;
FILETIME kernel_time;
FILETIME user_time;
if (!::GetThreadTimes(handle.get(), &creation_time, &exit_time, &kernel_time,
&user_time)) {
return std::nullopt;
}
return TimeDelta::FromFileTime(kernel_time) +
TimeDelta::FromFileTime(user_time);
}
}
std::unique_ptr<PlatformThreadMetrics> PlatformThreadMetrics::CreateFromHandle(
PlatformThreadHandle handle) {
HANDLE new_handle = INVALID_HANDLE_VALUE;
if (!::DuplicateHandle(::GetCurrentProcess(),
handle.platform_handle(),
::GetCurrentProcess(),
&new_handle, THREAD_QUERY_LIMITED_INFORMATION,
FALSE, 0)) {
return nullptr;
}
return WrapUnique(new PlatformThreadMetrics(win::ScopedHandle(new_handle)));
}
std::unique_ptr<PlatformThreadMetrics> PlatformThreadMetrics::CreateFromId(
PlatformThreadId tid) {
if (tid == kInvalidThreadId) {
return nullptr;
}
win::ScopedHandle handle(::OpenThread(THREAD_QUERY_LIMITED_INFORMATION,
FALSE, tid.raw()));
if (!handle.is_valid()) {
return nullptr;
}
return WrapUnique(new PlatformThreadMetrics(std::move(handle)));
}
PlatformThreadMetrics::PlatformThreadMetrics(win::ScopedHandle&& handle)
: handle_(std::move(handle)) {}
std::optional<TimeDelta> PlatformThreadMetrics::GetCumulativeCPUUsage() {
TRACE_EVENT("base", "Thread::GetCumulativeCPUUsage");
#if defined(ARCH_CPU_ARM64)
return GetImpreciseCumulativeCPUUsage(handle_);
#else
if (!time_internal::HasConstantRateTSC()) {
return GetImpreciseCumulativeCPUUsage(handle_);
}
const double tsc_ticks_per_second = time_internal::TSCTicksPerSecond();
if (tsc_ticks_per_second == 0) {
return GetImpreciseCumulativeCPUUsage(handle_);
}
ULONG64 cycle_time = 0;
if (!::QueryThreadCycleTime(handle_.get(), &cycle_time)) {
return std::nullopt;
}
return Seconds(cycle_time / tsc_ticks_per_second);
#endif
}
}