1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#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);
}
} // namespace
// static
std::unique_ptr<PlatformThreadMetrics> PlatformThreadMetrics::CreateFromHandle(
PlatformThreadHandle handle) {
// Duplicate the handle to get one that can be owned by PlatformThreadMetrics.
HANDLE new_handle = INVALID_HANDLE_VALUE;
if (!::DuplicateHandle(/*hSourceProcessHandle=*/::GetCurrentProcess(),
/*hSourceHandle=*/handle.platform_handle(),
/*hTargetProcessHandle=*/::GetCurrentProcess(),
&new_handle, THREAD_QUERY_LIMITED_INFORMATION,
/*bInheritHandle=*/FALSE, /*dwOptions=*/0)) {
return nullptr;
}
return WrapUnique(new PlatformThreadMetrics(win::ScopedHandle(new_handle)));
}
// static
std::unique_ptr<PlatformThreadMetrics> PlatformThreadMetrics::CreateFromId(
PlatformThreadId tid) {
if (tid == kInvalidThreadId) {
return nullptr;
}
win::ScopedHandle handle(::OpenThread(THREAD_QUERY_LIMITED_INFORMATION,
/*bInheritHandle=*/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)
// Precise CPU usage is not available on Arm CPUs because they don't support
// constant rate TSC.
return GetImpreciseCumulativeCPUUsage(handle_);
#else // !defined(ARCH_CPU_ARM64)
if (!time_internal::HasConstantRateTSC()) {
return GetImpreciseCumulativeCPUUsage(handle_);
}
const double tsc_ticks_per_second = time_internal::TSCTicksPerSecond();
if (tsc_ticks_per_second == 0) {
// TSC is only initialized once TSCTicksPerSecond() is called twice 50 ms
// apart on the same thread to get a baseline. In unit tests, it is frequent
// for the initialization not to be complete. In production, it can also
// theoretically happen.
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 // !defined(ARCH_CPU_ARM64)
}
} // namespace base
|