Move code to read macOS resource coalition stats to //components/power_metrics.
This allows reuse by the code that records histograms in Chrome and the "power_sampler" tool in //tools/mac/power. Bug: 1254332 Change-Id: I6c0d9fcdee9d556b061868a90344843b4e80d587 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3265524 Commit-Queue: François Doray <fdoray@chromium.org> Reviewed-by: Jochen Eisinger <jochen@chromium.org> Reviewed-by: Etienne Pierre-Doray <etiennep@chromium.org> Cr-Commit-Position: refs/heads/main@{#945055}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
c5705a1ef9
commit
dbfac69059
chrome
browser
test
components/power_metrics
@ -5609,7 +5609,6 @@ static_library("browser") {
|
||||
"obsolete_system/obsolete_system_mac.cc",
|
||||
"password_manager/password_manager_util_mac.h",
|
||||
"password_manager/password_manager_util_mac.mm",
|
||||
"performance_monitor/resource_coalition_internal_types_mac.h",
|
||||
"performance_monitor/resource_coalition_mac.h",
|
||||
"performance_monitor/resource_coalition_mac.mm",
|
||||
"platform_util_mac.mm",
|
||||
@ -5637,6 +5636,7 @@ static_library("browser") {
|
||||
"//chrome/services/mac_notifications/public/mojom",
|
||||
"//components/crash/core/app",
|
||||
"//components/metal_util",
|
||||
"//components/power_metrics",
|
||||
"//components/remote_cocoa/browser:browser",
|
||||
"//sandbox/mac:seatbelt",
|
||||
"//sandbox/policy",
|
||||
|
@ -14,16 +14,46 @@
|
||||
#include "base/process/process_handle.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/performance_monitor/resource_coalition_internal_types_mac.h"
|
||||
|
||||
extern "C" int coalition_info_resource_usage(
|
||||
uint64_t cid,
|
||||
struct coalition_resource_usage* cru,
|
||||
size_t sz);
|
||||
#include "components/power_metrics/resource_coalition_mac.h"
|
||||
|
||||
namespace performance_monitor {
|
||||
namespace {
|
||||
|
||||
static_assert(
|
||||
THREAD_QOS_DEFAULT ==
|
||||
static_cast<int>(
|
||||
performance_monitor::ResourceCoalition::QoSLevels::kDefault),
|
||||
"QoSLevels indexes should match the OS defined ones.");
|
||||
static_assert(
|
||||
THREAD_QOS_MAINTENANCE ==
|
||||
static_cast<int>(
|
||||
performance_monitor::ResourceCoalition::QoSLevels::kMaintenance),
|
||||
"QoSLevels indexes should match the OS defined ones.");
|
||||
static_assert(
|
||||
THREAD_QOS_BACKGROUND ==
|
||||
static_cast<int>(
|
||||
performance_monitor::ResourceCoalition::QoSLevels::kBackground),
|
||||
"QoSLevels indexes should match the OS defined ones.");
|
||||
static_assert(
|
||||
THREAD_QOS_UTILITY ==
|
||||
static_cast<int>(
|
||||
performance_monitor::ResourceCoalition::QoSLevels::kUtility),
|
||||
"QoSLevels indexes should match the OS defined ones.");
|
||||
static_assert(
|
||||
THREAD_QOS_LEGACY ==
|
||||
static_cast<int>(
|
||||
performance_monitor::ResourceCoalition::QoSLevels::kLegacy),
|
||||
"QoSLevels indexes should match the OS defined ones.");
|
||||
static_assert(
|
||||
THREAD_QOS_USER_INITIATED ==
|
||||
static_cast<int>(
|
||||
performance_monitor::ResourceCoalition::QoSLevels::kUserInitiated),
|
||||
"QoSLevels indexes should match the OS defined ones.");
|
||||
static_assert(THREAD_QOS_USER_INTERACTIVE ==
|
||||
static_cast<int>(performance_monitor::ResourceCoalition::
|
||||
QoSLevels::kUserInteractive),
|
||||
"QoSLevels indexes should match the OS defined ones.");
|
||||
|
||||
const char kCoalitionAvailabilityHistogram[] =
|
||||
"PerformanceMonitor.ResourceCoalition.Availability";
|
||||
|
||||
@ -40,19 +70,6 @@ enum class CoalitionAvailability {
|
||||
kMaxValue = kNotAloneInCoalition
|
||||
};
|
||||
|
||||
// Returns the coalition ID that a given process belongs to, or nullopt if this
|
||||
// information isn't available.
|
||||
absl::optional<uint64_t> GetProcessCoalitionId(const base::ProcessId pid) {
|
||||
proc_pidcoalitioninfo coalition_info = {};
|
||||
int res = proc_pidinfo(pid, PROC_PIDCOALITIONINFO, 0, &coalition_info,
|
||||
sizeof(coalition_info));
|
||||
|
||||
if (res != sizeof(coalition_info))
|
||||
return absl::nullopt;
|
||||
|
||||
return coalition_info.coalition_id[COALITION_TYPE_RESOURCE];
|
||||
}
|
||||
|
||||
// Returns the coalition ID that the current process belongs to. If this isn't
|
||||
// available or deemed not usable (e.g. if the process is not alone in its
|
||||
// coalition) this will return nullopt and |availability_details| will receive
|
||||
@ -61,7 +78,7 @@ absl::optional<uint64_t> GetProcessCoalitionId(const base::ProcessId pid) {
|
||||
absl::optional<uint64_t> GetCurrentCoalitionId(
|
||||
CoalitionAvailability* availability_details) {
|
||||
DCHECK(availability_details);
|
||||
auto cid = GetProcessCoalitionId(base::GetCurrentProcId());
|
||||
auto cid = power_metrics::GetProcessCoalitionId(base::GetCurrentProcId());
|
||||
|
||||
if (!cid.has_value()) {
|
||||
*availability_details = CoalitionAvailability::kCoalitionIDNotAvailable;
|
||||
@ -69,15 +86,13 @@ absl::optional<uint64_t> GetCurrentCoalitionId(
|
||||
}
|
||||
|
||||
// Check if resource usage metrics can be retrieved for this coalition ID.
|
||||
coalition_resource_usage cru = {};
|
||||
uint64_t res = coalition_info_resource_usage(cid.value(), &cru, sizeof(cru));
|
||||
if (res != 0) {
|
||||
if (!power_metrics::GetCoalitionResourceUsage(cid.value())) {
|
||||
*availability_details =
|
||||
CoalitionAvailability::kCoalitionResourceUsageNotAvailable;
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
auto parent_cid = GetProcessCoalitionId(
|
||||
auto parent_cid = power_metrics::GetProcessCoalitionId(
|
||||
base::GetParentProcessId(base::GetCurrentProcessHandle()));
|
||||
|
||||
if (!parent_cid.has_value()) {
|
||||
@ -97,20 +112,6 @@ absl::optional<uint64_t> GetCurrentCoalitionId(
|
||||
return cid;
|
||||
}
|
||||
|
||||
// Returns the resource usage coalition data for the given coalition ID.
|
||||
// This assumes that resource coalition data are always available for a given
|
||||
// coalition ID (i.e. the coalition has a lifetime that exceeds the usage of the
|
||||
// ID).
|
||||
std::unique_ptr<coalition_resource_usage> GetResourceUsageData(
|
||||
int64_t coalition_id) {
|
||||
auto cru = std::make_unique<coalition_resource_usage>();
|
||||
uint64_t res = coalition_info_resource_usage(
|
||||
coalition_id, cru.get(), sizeof(coalition_resource_usage));
|
||||
DCHECK_EQ(0U, res);
|
||||
|
||||
return cru;
|
||||
}
|
||||
|
||||
NSDictionary* MaybeGetDictionaryFromPath(const base::FilePath& path) {
|
||||
// The folder where the energy coefficient plist files are stored.
|
||||
NSString* plist_path_string = base::SysUTF8ToNSString(path.value().c_str());
|
||||
@ -147,11 +148,13 @@ ResourceCoalition::~ResourceCoalition() = default;
|
||||
|
||||
absl::optional<ResourceCoalition::DataRate> ResourceCoalition::GetDataRate() {
|
||||
DCHECK(IsAvailable());
|
||||
DCHECK_EQ(GetProcessCoalitionId(base::GetCurrentProcId()).value(),
|
||||
coalition_id_.value());
|
||||
DCHECK_EQ(
|
||||
power_metrics::GetProcessCoalitionId(base::GetCurrentProcId()).value(),
|
||||
coalition_id_.value());
|
||||
DCHECK(last_data_sample_);
|
||||
return GetDataRateImpl(GetResourceUsageData(coalition_id_.value()),
|
||||
base::TimeTicks::Now());
|
||||
return GetDataRateImpl(
|
||||
power_metrics::GetCoalitionResourceUsage(coalition_id_.value()),
|
||||
base::TimeTicks::Now());
|
||||
}
|
||||
|
||||
absl::optional<ResourceCoalition::DataRate>
|
||||
@ -166,7 +169,8 @@ ResourceCoalition::GetDataRateFromFakeDataForTesting(
|
||||
}
|
||||
|
||||
void ResourceCoalition::SetCoalitionIDToCurrentProcessIdForTesting() {
|
||||
SetCoalitionId(GetProcessCoalitionId(base::GetCurrentProcId()));
|
||||
SetCoalitionId(
|
||||
power_metrics::GetProcessCoalitionId(base::GetCurrentProcId()));
|
||||
}
|
||||
|
||||
// static
|
||||
@ -340,7 +344,8 @@ void ResourceCoalition::EnsureEnergyImpactCoefficientsIfAvailable() {
|
||||
void ResourceCoalition::SetCoalitionId(absl::optional<uint64_t> coalition_id) {
|
||||
coalition_id_ = coalition_id;
|
||||
if (coalition_id_.has_value()) {
|
||||
last_data_sample_ = GetResourceUsageData(coalition_id_.value());
|
||||
last_data_sample_ =
|
||||
power_metrics::GetCoalitionResourceUsage(coalition_id_.value());
|
||||
last_data_sample_timestamp_ = base::TimeTicks::Now();
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,8 @@
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/test/metrics/histogram_tester.h"
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/performance_monitor/resource_coalition_internal_types_mac.h"
|
||||
#include "chrome/common/chrome_paths.h"
|
||||
#include "components/power_metrics/resource_coalition_internal_types_mac.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace performance_monitor {
|
||||
|
@ -5582,6 +5582,7 @@ test("unit_tests") {
|
||||
"//chrome/services/mac_notifications/public/mojom",
|
||||
"//chrome/utility/safe_browsing/mac",
|
||||
"//chrome/utility/safe_browsing/mac:dmg_common",
|
||||
"//components/power_metrics",
|
||||
"//ui/events/devices:test_support",
|
||||
]
|
||||
}
|
||||
|
15
components/power_metrics/BUILD.gn
Normal file
15
components/power_metrics/BUILD.gn
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
if (is_mac) {
|
||||
static_library("power_metrics") {
|
||||
sources = [
|
||||
"resource_coalition_internal_types_mac.h",
|
||||
"resource_coalition_mac.h",
|
||||
"resource_coalition_mac.mm",
|
||||
]
|
||||
|
||||
deps = [ "//base" ]
|
||||
}
|
||||
}
|
12
components/power_metrics/DIR_METADATA
Normal file
12
components/power_metrics/DIR_METADATA
Normal file
@ -0,0 +1,12 @@
|
||||
# Metadata information for this directory.
|
||||
#
|
||||
# For more information on DIR_METADATA files, see:
|
||||
# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/README.md
|
||||
#
|
||||
# For the schema of this file, see Metadata message:
|
||||
# https://source.chromium.org/chromium/infra/infra/+/main:go/src/infra/tools/dirmd/proto/dir_metadata.proto
|
||||
|
||||
monorail {
|
||||
component: "Internals>Power"
|
||||
}
|
||||
team_email: "chrome-catan-battery@google.com"
|
2
components/power_metrics/OWNERS
Normal file
2
components/power_metrics/OWNERS
Normal file
@ -0,0 +1,2 @@
|
||||
etiennep@chromium.org
|
||||
fdoray@chromium.org
|
@ -2,17 +2,14 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file defines some data types used to retrieve the coalition data from
|
||||
// the OS. It's only meant to be included in resource_coalition_mac.h and its
|
||||
// test files.
|
||||
// This file defines data types used to retrieve coalition metrics from the OS.
|
||||
|
||||
#ifndef CHROME_BROWSER_PERFORMANCE_MONITOR_RESOURCE_COALITION_INTERNAL_TYPES_MAC_H_
|
||||
#define CHROME_BROWSER_PERFORMANCE_MONITOR_RESOURCE_COALITION_INTERNAL_TYPES_MAC_H_
|
||||
#ifndef COMPONENTS_POWER_METRICS_RESOURCE_COALITION_INTERNAL_TYPES_MAC_H_
|
||||
#define COMPONENTS_POWER_METRICS_RESOURCE_COALITION_INTERNAL_TYPES_MAC_H_
|
||||
|
||||
#include "chrome/browser/performance_monitor/resource_coalition_mac.h"
|
||||
#include <stdint.h>
|
||||
|
||||
// Comes from osfmk/mach/coalition.h
|
||||
|
||||
#define COALITION_TYPE_RESOURCE (0)
|
||||
#define COALITION_TYPE_JETSAM (1)
|
||||
#define COALITION_TYPE_MAX (1)
|
||||
@ -36,45 +33,7 @@
|
||||
static_assert(COALITION_NUM_THREAD_QOS_TYPES == THREAD_QOS_LAST,
|
||||
"Unexpected number of QoS levels.");
|
||||
|
||||
static_assert(
|
||||
THREAD_QOS_DEFAULT ==
|
||||
static_cast<int>(
|
||||
performance_monitor::ResourceCoalition::QoSLevels::kDefault),
|
||||
"QoSLevels indexes should match the OS defined ones.");
|
||||
static_assert(
|
||||
THREAD_QOS_MAINTENANCE ==
|
||||
static_cast<int>(
|
||||
performance_monitor::ResourceCoalition::QoSLevels::kMaintenance),
|
||||
"QoSLevels indexes should match the OS defined ones.");
|
||||
static_assert(
|
||||
THREAD_QOS_BACKGROUND ==
|
||||
static_cast<int>(
|
||||
performance_monitor::ResourceCoalition::QoSLevels::kBackground),
|
||||
"QoSLevels indexes should match the OS defined ones.");
|
||||
static_assert(
|
||||
THREAD_QOS_UTILITY ==
|
||||
static_cast<int>(
|
||||
performance_monitor::ResourceCoalition::QoSLevels::kUtility),
|
||||
"QoSLevels indexes should match the OS defined ones.");
|
||||
static_assert(
|
||||
THREAD_QOS_LEGACY ==
|
||||
static_cast<int>(
|
||||
performance_monitor::ResourceCoalition::QoSLevels::kLegacy),
|
||||
"QoSLevels indexes should match the OS defined ones.");
|
||||
static_assert(
|
||||
THREAD_QOS_USER_INITIATED ==
|
||||
static_cast<int>(
|
||||
performance_monitor::ResourceCoalition::QoSLevels::kUserInitiated),
|
||||
"QoSLevels indexes should match the OS defined ones.");
|
||||
static_assert(THREAD_QOS_USER_INTERACTIVE ==
|
||||
static_cast<int>(performance_monitor::ResourceCoalition::
|
||||
QoSLevels::kUserInteractive),
|
||||
"QoSLevels indexes should match the OS defined ones.");
|
||||
|
||||
// Comes from bsd/sys/coalition.h
|
||||
//
|
||||
// TODO(crbug.com/1229686): Report some data derived from the tasks_started and
|
||||
// tasks_exited counters.
|
||||
struct coalition_resource_usage {
|
||||
uint64_t tasks_started;
|
||||
uint64_t tasks_exited;
|
||||
@ -117,4 +76,4 @@ struct proc_pidcoalitioninfo {
|
||||
// Comes from bsd/sys/proc_info.h
|
||||
#define PROC_PIDCOALITIONINFO 20
|
||||
|
||||
#endif // CHROME_BROWSER_PERFORMANCE_MONITOR_RESOURCE_COALITION_INTERNAL_TYPES_MAC_H_
|
||||
#endif // COMPONENTS_POWER_METRICS_RESOURCE_COALITION_INTERNAL_TYPES_MAC_H_
|
34
components/power_metrics/resource_coalition_mac.h
Normal file
34
components/power_metrics/resource_coalition_mac.h
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Resource Coalition is an (undocumented) mechanism available in macOS that
|
||||
// allows retrieving accrued resource usage metrics for a group of processes,
|
||||
// including processes that have died. Typically, a coalition includes a root
|
||||
// process and its descendants. The source can help understand the mechanism:
|
||||
// https://github.com/apple/darwin-xnu/blob/main/osfmk/kern/coalition.c
|
||||
|
||||
#ifndef COMPONENTS_POWER_METRICS_RESOURCE_COALITION_MAC_H_
|
||||
#define COMPONENTS_POWER_METRICS_RESOURCE_COALITION_MAC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
|
||||
#include "base/process/process_handle.h"
|
||||
#include "components/power_metrics/resource_coalition_internal_types_mac.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
|
||||
namespace power_metrics {
|
||||
|
||||
// Returns the coalition id for the process identified by |pid| or nullopt if
|
||||
// not available.
|
||||
absl::optional<uint64_t> GetProcessCoalitionId(base::ProcessId pid);
|
||||
|
||||
// Returns resource usage data for the coalition identified by |coalition_id|,
|
||||
// or nullptr if not available.
|
||||
std::unique_ptr<coalition_resource_usage> GetCoalitionResourceUsage(
|
||||
int64_t coalition_id);
|
||||
|
||||
} // namespace power_metrics
|
||||
|
||||
#endif // COMPONENTS_PPOWER_METRICS_RESOURCE_COALITION_MAC_H_
|
39
components/power_metrics/resource_coalition_mac.mm
Normal file
39
components/power_metrics/resource_coalition_mac.mm
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "components/power_metrics/resource_coalition_mac.h"
|
||||
|
||||
#include <libproc.h>
|
||||
|
||||
#include "base/check_op.h"
|
||||
|
||||
extern "C" int coalition_info_resource_usage(
|
||||
uint64_t cid,
|
||||
struct coalition_resource_usage* cru,
|
||||
size_t sz);
|
||||
|
||||
namespace power_metrics {
|
||||
|
||||
absl::optional<uint64_t> GetProcessCoalitionId(base::ProcessId pid) {
|
||||
proc_pidcoalitioninfo coalition_info = {};
|
||||
int res = proc_pidinfo(pid, PROC_PIDCOALITIONINFO, 0, &coalition_info,
|
||||
sizeof(coalition_info));
|
||||
|
||||
if (res != sizeof(coalition_info))
|
||||
return absl::nullopt;
|
||||
|
||||
return coalition_info.coalition_id[COALITION_TYPE_RESOURCE];
|
||||
}
|
||||
|
||||
std::unique_ptr<coalition_resource_usage> GetCoalitionResourceUsage(
|
||||
int64_t coalition_id) {
|
||||
auto cru = std::make_unique<coalition_resource_usage>();
|
||||
uint64_t res = coalition_info_resource_usage(
|
||||
coalition_id, cru.get(), sizeof(coalition_resource_usage));
|
||||
if (res == 0U)
|
||||
return cru;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // power_metrics
|
Reference in New Issue
Block a user