0

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:
Francois Doray
2021-11-24 19:13:10 +00:00
committed by Chromium LUCI CQ
parent c5705a1ef9
commit dbfac69059
10 changed files with 159 additions and 92 deletions

@ -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" ]
}
}

@ -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"

@ -0,0 +1,2 @@
etiennep@chromium.org
fdoray@chromium.org

@ -0,0 +1,79 @@
// 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.
// This file defines data types used to retrieve coalition metrics from the OS.
#ifndef COMPONENTS_POWER_METRICS_RESOURCE_COALITION_INTERNAL_TYPES_MAC_H_
#define COMPONENTS_POWER_METRICS_RESOURCE_COALITION_INTERNAL_TYPES_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)
#define COALITION_NUM_TYPES (COALITION_TYPE_MAX + 1)
#define COALITION_NUM_THREAD_QOS_TYPES 7
// Comes from osfmk/mach/thread_policy.h
#define THREAD_QOS_UNSPECIFIED 0
#define THREAD_QOS_DEFAULT THREAD_QOS_UNSPECIFIED /* Temporary rename */
#define THREAD_QOS_MAINTENANCE 1
#define THREAD_QOS_BACKGROUND 2
#define THREAD_QOS_UTILITY 3
#define THREAD_QOS_LEGACY 4 /* i.e. default workq threads */
#define THREAD_QOS_USER_INITIATED 5
#define THREAD_QOS_USER_INTERACTIVE 6
#define THREAD_QOS_LAST 7
static_assert(COALITION_NUM_THREAD_QOS_TYPES == THREAD_QOS_LAST,
"Unexpected number of QoS levels.");
// Comes from bsd/sys/coalition.h
struct coalition_resource_usage {
uint64_t tasks_started;
uint64_t tasks_exited;
uint64_t time_nonempty;
uint64_t cpu_time;
uint64_t interrupt_wakeups;
uint64_t platform_idle_wakeups;
uint64_t bytesread;
uint64_t byteswritten;
uint64_t gpu_time;
uint64_t cpu_time_billed_to_me;
uint64_t cpu_time_billed_to_others;
uint64_t energy;
uint64_t logical_immediate_writes;
uint64_t logical_deferred_writes;
uint64_t logical_invalidated_writes;
uint64_t logical_metadata_writes;
uint64_t logical_immediate_writes_to_external;
uint64_t logical_deferred_writes_to_external;
uint64_t logical_invalidated_writes_to_external;
uint64_t logical_metadata_writes_to_external;
uint64_t energy_billed_to_me;
uint64_t energy_billed_to_others;
uint64_t cpu_ptime;
uint64_t cpu_time_eqos_len; /* Stores the number of thread QoS types */
uint64_t cpu_time_eqos[COALITION_NUM_THREAD_QOS_TYPES];
uint64_t cpu_instructions;
uint64_t cpu_cycles;
uint64_t fs_metadata_writes;
uint64_t pm_writes;
};
struct proc_pidcoalitioninfo {
uint64_t coalition_id[COALITION_NUM_TYPES];
uint64_t reserved1;
uint64_t reserved2;
uint64_t reserved3;
};
// Comes from bsd/sys/proc_info.h
#define PROC_PIDCOALITIONINFO 20
#endif // COMPONENTS_POWER_METRICS_RESOURCE_COALITION_INTERNAL_TYPES_MAC_H_

@ -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_

@ -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