0

[power_sampler] Add sampling of M1 temperature sensors.

Bug: 1254332
Change-Id: Ie55c0792d0afff7dabe2939f3111a3ab23bbf76a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3323152
Reviewed-by: Etienne Pierre-Doray <etiennep@chromium.org>
Reviewed-by: Jayson Adams <shrike@chromium.org>
Commit-Queue: Francois Pierre Doray <fdoray@chromium.org>
Cr-Commit-Position: refs/heads/main@{#956644}
This commit is contained in:
Francois Doray
2022-01-07 20:25:09 +00:00
committed by Chromium LUCI CQ
parent 5d5d48d6be
commit 30385a7022
10 changed files with 417 additions and 0 deletions

@ -9,6 +9,9 @@ if (is_mac) {
"energy_impact_mac.mm",
"iopm_power_source_sampling_event_source.cc",
"iopm_power_source_sampling_event_source.h",
"m1_sensors_internal_types_mac.h",
"m1_sensors_mac.h",
"m1_sensors_mac.mm",
"mach_time_mac.h",
"mach_time_mac.mm",
"resource_coalition_internal_types_mac.h",

@ -0,0 +1,26 @@
// 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.
#ifndef COMPONENTS_POWER_METRICS_M1_SENSORS_INTERNAL_TYPES_MAC_H_
#define COMPONENTS_POWER_METRICS_M1_SENSORS_INTERNAL_TYPES_MAC_H_
#include <stdint.h>
// From:
// https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-421.6/IOHIDFamily/IOHIDEventTypes.h.auto.html
#define IOHIDEventFieldBase(type) (type << 16)
constexpr int64_t kIOHIDEventTypeTemperature = 15;
// From:
// https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-421.6/IOHIDFamily/AppleHIDUsageTables.h
// Usage pages
constexpr int kHIDPage_AppleVendor = 0xff00;
// Usage keys for `kHIDPage_AppleVendor`
constexpr int kHIDUsage_AppleVendor_TemperatureSensor = 0x0005;
#endif // COMPONENTS_POWER_METRICS_M1_SENSORS_INTERNAL_TYPES_MAC_H_

@ -0,0 +1,48 @@
// 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.
// The Apple M1 chip has sensors to monitor its power consumption and
// temperature. This file defines a class to retrieve data from these sensors.
#ifndef COMPONENTS_POWER_METRICS_M1_SENSORS_MAC_H_
#define COMPONENTS_POWER_METRICS_M1_SENSORS_MAC_H_
#include <memory>
#include <IOKit/hidsystem/IOHIDEventSystemClient.h>
#include "base/mac/scoped_cftyperef.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace power_metrics {
class M1SensorsReader {
public:
struct TemperaturesCelsius {
TemperaturesCelsius();
TemperaturesCelsius(const TemperaturesCelsius&) noexcept;
~TemperaturesCelsius();
absl::optional<double> p_cores;
absl::optional<double> e_cores;
};
virtual ~M1SensorsReader();
// Creates an M1SensorsReader. Returns nullptr on failure.
static std::unique_ptr<M1SensorsReader> Create();
// Reads temperature sensors. Virtual for testing.
virtual TemperaturesCelsius ReadTemperatures();
protected:
M1SensorsReader(base::ScopedCFTypeRef<IOHIDEventSystemClientRef> system);
private:
base::ScopedCFTypeRef<IOHIDEventSystemClientRef> system_;
};
} // namespace power_metrics
#endif // COMPONENTS_POWER_METRICS_M1_SENSORS_MAC_H_

@ -0,0 +1,123 @@
// 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/m1_sensors_mac.h"
#import <Foundation/Foundation.h>
#import <IOKit/hid/IOHIDDeviceKeys.h>
#import <IOKit/hidsystem/IOHIDServiceClient.h>
#include <utility>
#include "base/mac/foundation_util.h"
#include "base/memory/ptr_util.h"
#include "components/power_metrics/m1_sensors_internal_types_mac.h"
extern "C" {
extern IOHIDEventSystemClientRef IOHIDEventSystemClientCreate(CFAllocatorRef);
extern int IOHIDEventSystemClientSetMatching(IOHIDEventSystemClientRef client,
CFDictionaryRef match);
extern CFTypeRef IOHIDServiceClientCopyEvent(IOHIDServiceClientRef,
int64_t,
int32_t,
int64_t);
extern double IOHIDEventGetFloatValue(CFTypeRef, int32_t);
}
namespace power_metrics {
namespace {
absl::optional<double> GetEventFloatValue(IOHIDServiceClientRef service,
int64_t event_type) {
base::ScopedCFTypeRef<CFTypeRef> event(
IOHIDServiceClientCopyEvent(service, event_type, 0, 0));
if (!event)
return absl::nullopt;
return IOHIDEventGetFloatValue(event, IOHIDEventFieldBase(event_type));
}
} // namespace
M1SensorsReader::TemperaturesCelsius::TemperaturesCelsius() = default;
M1SensorsReader::TemperaturesCelsius::TemperaturesCelsius(
const TemperaturesCelsius&) noexcept = default;
M1SensorsReader::TemperaturesCelsius::~TemperaturesCelsius() = default;
M1SensorsReader::~M1SensorsReader() = default;
// static
std::unique_ptr<M1SensorsReader> M1SensorsReader::Create() {
base::ScopedCFTypeRef<IOHIDEventSystemClientRef> system(
IOHIDEventSystemClientCreate(kCFAllocatorDefault));
if (system == nil)
return nullptr;
NSDictionary* filter = @{
@kIOHIDPrimaryUsagePageKey : [NSNumber numberWithInt:kHIDPage_AppleVendor],
@kIOHIDPrimaryUsageKey :
[NSNumber numberWithInt:kHIDUsage_AppleVendor_TemperatureSensor],
};
IOHIDEventSystemClientSetMatching(system, base::mac::NSToCFCast(filter));
return base::WrapUnique(new M1SensorsReader(std::move(system)));
}
M1SensorsReader::TemperaturesCelsius M1SensorsReader::ReadTemperatures() {
base::ScopedCFTypeRef<CFArrayRef> services(
IOHIDEventSystemClientCopyServices(system_.get()));
// There are multiple temperature sensors on P-Cores and E-Cores. Count and
// sum values to compute average later.
int num_p_core_temp = 0;
int num_e_core_temp = 0;
double sum_p_core_temp = 0;
double sum_e_core_temp = 0;
for (id service_obj in base::mac::CFToNSCast(services.get())) {
IOHIDServiceClientRef service = (IOHIDServiceClientRef)service_obj;
base::ScopedCFTypeRef<CFStringRef> product_cf(
base::mac::CFCast<CFStringRef>(
IOHIDServiceClientCopyProperty(service, CFSTR(kIOHIDProductKey))));
if (product_cf == nil)
continue;
if ([base::mac::CFToNSCast(product_cf.get())
hasPrefix:@"pACC MTR Temp Sensor"]) {
absl::optional<double> temp =
GetEventFloatValue(service, kIOHIDEventTypeTemperature);
if (temp.has_value()) {
num_p_core_temp += 1;
sum_p_core_temp += temp.value();
}
}
if ([base::mac::CFToNSCast(product_cf.get())
hasPrefix:@"eACC MTR Temp Sensor"]) {
absl::optional<double> temp =
GetEventFloatValue(service, kIOHIDEventTypeTemperature);
if (temp.has_value()) {
num_e_core_temp += 1;
sum_e_core_temp += temp.value();
}
}
}
TemperaturesCelsius temperatures;
if (num_p_core_temp > 0)
temperatures.p_cores = sum_p_core_temp / num_p_core_temp;
if (num_e_core_temp > 0)
temperatures.e_cores = sum_e_core_temp / num_e_core_temp;
return temperatures;
}
M1SensorsReader::M1SensorsReader(
base::ScopedCFTypeRef<IOHIDEventSystemClientRef> system)
: system_(std::move(system)) {}
} // namespace power_metrics