m1_sensors_mac.mm 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/power_metrics/m1_sensors_mac.h"
  5. #import <Foundation/Foundation.h>
  6. #import <IOKit/hid/IOHIDDeviceKeys.h>
  7. #import <IOKit/hidsystem/IOHIDServiceClient.h>
  8. #include <utility>
  9. #include "base/mac/foundation_util.h"
  10. #include "base/memory/ptr_util.h"
  11. #include "components/power_metrics/m1_sensors_internal_types_mac.h"
  12. extern "C" {
  13. extern IOHIDEventSystemClientRef IOHIDEventSystemClientCreate(CFAllocatorRef);
  14. extern int IOHIDEventSystemClientSetMatching(IOHIDEventSystemClientRef client,
  15. CFDictionaryRef match);
  16. extern CFTypeRef IOHIDServiceClientCopyEvent(IOHIDServiceClientRef,
  17. int64_t,
  18. int32_t,
  19. int64_t);
  20. extern double IOHIDEventGetFloatValue(CFTypeRef, int32_t);
  21. }
  22. namespace power_metrics {
  23. namespace {
  24. absl::optional<double> GetEventFloatValue(IOHIDServiceClientRef service,
  25. int64_t event_type) {
  26. base::ScopedCFTypeRef<CFTypeRef> event(
  27. IOHIDServiceClientCopyEvent(service, event_type, 0, 0));
  28. if (!event)
  29. return absl::nullopt;
  30. return IOHIDEventGetFloatValue(event, IOHIDEventFieldBase(event_type));
  31. }
  32. } // namespace
  33. M1SensorsReader::TemperaturesCelsius::TemperaturesCelsius() = default;
  34. M1SensorsReader::TemperaturesCelsius::TemperaturesCelsius(
  35. const TemperaturesCelsius&) noexcept = default;
  36. M1SensorsReader::TemperaturesCelsius::~TemperaturesCelsius() = default;
  37. M1SensorsReader::~M1SensorsReader() = default;
  38. // static
  39. std::unique_ptr<M1SensorsReader> M1SensorsReader::Create() {
  40. base::ScopedCFTypeRef<IOHIDEventSystemClientRef> system(
  41. IOHIDEventSystemClientCreate(kCFAllocatorDefault));
  42. if (system == nil)
  43. return nullptr;
  44. NSDictionary* filter = @{
  45. @kIOHIDPrimaryUsagePageKey : [NSNumber numberWithInt:kHIDPage_AppleVendor],
  46. @kIOHIDPrimaryUsageKey :
  47. [NSNumber numberWithInt:kHIDUsage_AppleVendor_TemperatureSensor],
  48. };
  49. IOHIDEventSystemClientSetMatching(system, base::mac::NSToCFCast(filter));
  50. return base::WrapUnique(new M1SensorsReader(std::move(system)));
  51. }
  52. M1SensorsReader::TemperaturesCelsius M1SensorsReader::ReadTemperatures() {
  53. base::ScopedCFTypeRef<CFArrayRef> services(
  54. IOHIDEventSystemClientCopyServices(system_.get()));
  55. // There are multiple temperature sensors on P-Cores and E-Cores. Count and
  56. // sum values to compute average later.
  57. int num_p_core_temp = 0;
  58. int num_e_core_temp = 0;
  59. double sum_p_core_temp = 0;
  60. double sum_e_core_temp = 0;
  61. for (id service_obj in base::mac::CFToNSCast(services.get())) {
  62. IOHIDServiceClientRef service = (IOHIDServiceClientRef)service_obj;
  63. base::ScopedCFTypeRef<CFStringRef> product_cf(
  64. base::mac::CFCast<CFStringRef>(
  65. IOHIDServiceClientCopyProperty(service, CFSTR(kIOHIDProductKey))));
  66. if (product_cf == nil)
  67. continue;
  68. if ([base::mac::CFToNSCast(product_cf.get())
  69. hasPrefix:@"pACC MTR Temp Sensor"]) {
  70. absl::optional<double> temp =
  71. GetEventFloatValue(service, kIOHIDEventTypeTemperature);
  72. if (temp.has_value()) {
  73. num_p_core_temp += 1;
  74. sum_p_core_temp += temp.value();
  75. }
  76. }
  77. if ([base::mac::CFToNSCast(product_cf.get())
  78. hasPrefix:@"eACC MTR Temp Sensor"]) {
  79. absl::optional<double> temp =
  80. GetEventFloatValue(service, kIOHIDEventTypeTemperature);
  81. if (temp.has_value()) {
  82. num_e_core_temp += 1;
  83. sum_e_core_temp += temp.value();
  84. }
  85. }
  86. }
  87. TemperaturesCelsius temperatures;
  88. if (num_p_core_temp > 0)
  89. temperatures.p_cores = sum_p_core_temp / num_p_core_temp;
  90. if (num_e_core_temp > 0)
  91. temperatures.e_cores = sum_e_core_temp / num_e_core_temp;
  92. return temperatures;
  93. }
  94. M1SensorsReader::M1SensorsReader(
  95. base::ScopedCFTypeRef<IOHIDEventSystemClientRef> system)
  96. : system_(std::move(system)) {}
  97. } // namespace power_metrics