[M120 Migration][VD] Enable direct rendering for TVPlus
[platform/framework/web/chromium-efl.git] / components / power_metrics / energy_impact_mac.mm
1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/power_metrics/energy_impact_mac.h"
6
7 #include <Foundation/Foundation.h>
8 #import <IOKit/IOKitLib.h>
9
10 #include "base/apple/foundation_util.h"
11 #include "base/apple/scoped_cftyperef.h"
12 #include "base/mac/scoped_ioobject.h"
13 #include "base/strings/sys_string_conversions.h"
14 #include "base/time/time.h"
15 #include "components/power_metrics/mach_time_mac.h"
16 #include "components/power_metrics/resource_coalition_mac.h"
17
18 namespace power_metrics {
19
20 namespace {
21
22 NSDictionary* MaybeGetDictionaryFromPath(const base::FilePath& path) {
23   // The folder where the energy coefficient plist files are stored.
24   return [NSDictionary
25       dictionaryWithContentsOfURL:base::apple::FilePathToNSURL(path)
26                             error:nil];
27 }
28
29 double GetNamedCoefficientOrZero(NSDictionary* dict, NSString* key) {
30   NSNumber* num = base::apple::ObjCCast<NSNumber>(dict[key]);
31   return num.floatValue;
32 }
33
34 }  // namespace
35
36 absl::optional<EnergyImpactCoefficients>
37 ReadCoefficientsForCurrentMachineOrDefault() {
38   absl::optional<std::string> board_id = internal::GetBoardIdForThisMachine();
39   if (!board_id.has_value())
40     return absl::nullopt;
41
42   return internal::ReadCoefficientsForBoardIdOrDefault(
43       base::FilePath(FILE_PATH_LITERAL("/usr/share/pmenergy")),
44       board_id.value());
45 }
46
47 double ComputeEnergyImpactForResourceUsage(
48     const coalition_resource_usage& data_sample,
49     const EnergyImpactCoefficients& coefficients,
50     const mach_timebase_info_data_t& mach_timebase) {
51   // TODO(https://crbug.com/1249536): The below coefficients are not used
52   // for now. Their units are unknown, and in the case of the network-related
53   // coefficients, it's not clear how to sample the data.
54   //
55   // coefficients.kdiskio_bytesread;
56   // coefficients.kdiskio_byteswritten;
57   // coefficients.knetwork_recv_bytes;
58   // coefficients.knetwork_recv_packets;
59   // coefficients.knetwork_sent_bytes;
60   // coefficients.knetwork_sent_packets;
61
62   // The cumulative CPU usage in |data_sample| is in units of ns, and
63   // |cpu_time_equivalent_ns| is computed in CPU ns up to the end of this
64   // function, where it's converted to units of EnergyImpact.
65   double cpu_time_equivalent_ns = 0.0;
66
67   // The kcpu_wakeups coefficient on disk is in seconds, but our
68   // intermediate result is in ns, so convert to ns on the fly.
69   cpu_time_equivalent_ns += coefficients.kcpu_wakeups *
70                             base::Time::kNanosecondsPerSecond *
71                             data_sample.platform_idle_wakeups;
72
73   // Presumably the kgpu_time coefficient has suitable units for the
74   // conversion of GPU time energy to CPU time energy. There is a fairly
75   // wide spread on this constant seen in /usr/share/pmenergy. On
76   // macOS 11.5.2 the spread is from 0 through 5.9.
77   cpu_time_equivalent_ns += coefficients.kgpu_time *
78                             MachTimeToNs(data_sample.gpu_time, mach_timebase);
79
80   cpu_time_equivalent_ns +=
81       coefficients.kqos_background *
82       MachTimeToNs(data_sample.cpu_time_eqos[THREAD_QOS_BACKGROUND],
83                    mach_timebase);
84   cpu_time_equivalent_ns +=
85       coefficients.kqos_default *
86       MachTimeToNs(data_sample.cpu_time_eqos[THREAD_QOS_DEFAULT],
87                    mach_timebase);
88   cpu_time_equivalent_ns +=
89       coefficients.kqos_legacy *
90       MachTimeToNs(data_sample.cpu_time_eqos[THREAD_QOS_LEGACY], mach_timebase);
91   cpu_time_equivalent_ns +=
92       coefficients.kqos_user_initiated *
93       MachTimeToNs(data_sample.cpu_time_eqos[THREAD_QOS_USER_INITIATED],
94                    mach_timebase);
95   cpu_time_equivalent_ns +=
96       coefficients.kqos_user_interactive *
97       MachTimeToNs(data_sample.cpu_time_eqos[THREAD_QOS_USER_INTERACTIVE],
98                    mach_timebase);
99   cpu_time_equivalent_ns +=
100       coefficients.kqos_utility *
101       MachTimeToNs(data_sample.cpu_time_eqos[THREAD_QOS_UTILITY],
102                    mach_timebase);
103
104   // The conversion ratio for CPU time/EnergyImpact is ns/10ms
105   constexpr double kNsToEI = 1E-7;
106   return cpu_time_equivalent_ns * kNsToEI;
107 }
108
109 namespace internal {
110
111 absl::optional<EnergyImpactCoefficients> ReadCoefficientsFromPath(
112     const base::FilePath& plist_file) {
113   @autoreleasepool {
114     NSDictionary* dict = MaybeGetDictionaryFromPath(plist_file);
115     if (!dict) {
116       return absl::nullopt;
117     }
118
119     NSDictionary* energy_constants = dict[@"energy_constants"];
120     if (!energy_constants) {
121       return absl::nullopt;
122     }
123
124     EnergyImpactCoefficients coefficients{};
125     coefficients.kcpu_time =
126         GetNamedCoefficientOrZero(energy_constants, @"kcpu_time");
127     coefficients.kcpu_wakeups =
128         GetNamedCoefficientOrZero(energy_constants, @"kcpu_wakeups");
129
130     coefficients.kqos_default =
131         GetNamedCoefficientOrZero(energy_constants, @"kqos_default");
132     coefficients.kqos_background =
133         GetNamedCoefficientOrZero(energy_constants, @"kqos_background");
134     coefficients.kqos_utility =
135         GetNamedCoefficientOrZero(energy_constants, @"kqos_utility");
136     coefficients.kqos_legacy =
137         GetNamedCoefficientOrZero(energy_constants, @"kqos_legacy");
138     coefficients.kqos_user_initiated =
139         GetNamedCoefficientOrZero(energy_constants, @"kqos_user_initiated");
140     coefficients.kqos_user_interactive =
141         GetNamedCoefficientOrZero(energy_constants, @"kqos_user_interactive");
142
143     coefficients.kdiskio_bytesread =
144         GetNamedCoefficientOrZero(energy_constants, @"kdiskio_bytesread");
145     coefficients.kdiskio_byteswritten =
146         GetNamedCoefficientOrZero(energy_constants, @"kdiskio_byteswritten");
147
148     coefficients.kgpu_time =
149         GetNamedCoefficientOrZero(energy_constants, @"kgpu_time");
150
151     coefficients.knetwork_recv_bytes =
152         GetNamedCoefficientOrZero(energy_constants, @"knetwork_recv_bytes");
153     coefficients.knetwork_recv_packets =
154         GetNamedCoefficientOrZero(energy_constants, @"knetwork_recv_packets");
155     coefficients.knetwork_sent_bytes =
156         GetNamedCoefficientOrZero(energy_constants, @"knetwork_sent_bytes");
157     coefficients.knetwork_sent_packets =
158         GetNamedCoefficientOrZero(energy_constants, @"knetwork_sent_packets");
159
160     return coefficients;
161   }
162 }
163
164 absl::optional<EnergyImpactCoefficients> ReadCoefficientsForBoardIdOrDefault(
165     const base::FilePath& directory,
166     const std::string& board_id) {
167   auto coefficients = ReadCoefficientsFromPath(
168       directory.Append(board_id).AddExtension(FILE_PATH_LITERAL("plist")));
169   if (coefficients.has_value())
170     return coefficients;
171
172   return ReadCoefficientsFromPath(
173       directory.Append(FILE_PATH_LITERAL("default.plist")));
174 }
175
176 absl::optional<std::string> GetBoardIdForThisMachine() {
177   base::mac::ScopedIOObject<io_service_t> platform_expert(
178       IOServiceGetMatchingService(kIOMasterPortDefault,
179                                   IOServiceMatching("IOPlatformExpertDevice")));
180   if (!platform_expert)
181     return absl::nullopt;
182
183   // This is what libpmenergy is observed to do in order to retrieve the correct
184   // coefficients file for the local computer.
185   base::apple::ScopedCFTypeRef<CFDataRef> board_id_data(
186       base::apple::CFCast<CFDataRef>(IORegistryEntryCreateCFProperty(
187           platform_expert, CFSTR("board-id"), kCFAllocatorDefault, 0)));
188
189   if (!board_id_data)
190     return absl::nullopt;
191
192   return reinterpret_cast<const char*>(CFDataGetBytePtr(board_id_data));
193 }
194
195 }  // namespace internal
196
197 }  // namespace power_metrics