resource_coalition_mac.mm 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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/resource_coalition_mac.h"
  5. #include <libproc.h>
  6. #include "base/check_op.h"
  7. #include "components/power_metrics/energy_impact_mac.h"
  8. #include "components/power_metrics/mach_time_mac.h"
  9. extern "C" int coalition_info_resource_usage(
  10. uint64_t cid,
  11. struct coalition_resource_usage* cru,
  12. size_t sz);
  13. namespace power_metrics {
  14. absl::optional<uint64_t> GetProcessCoalitionId(base::ProcessId pid) {
  15. proc_pidcoalitioninfo coalition_info = {};
  16. int res = proc_pidinfo(pid, PROC_PIDCOALITIONINFO, 0, &coalition_info,
  17. sizeof(coalition_info));
  18. if (res != sizeof(coalition_info))
  19. return absl::nullopt;
  20. return coalition_info.coalition_id[COALITION_TYPE_RESOURCE];
  21. }
  22. std::unique_ptr<coalition_resource_usage> GetCoalitionResourceUsage(
  23. int64_t coalition_id) {
  24. auto cru = std::make_unique<coalition_resource_usage>();
  25. uint64_t res = coalition_info_resource_usage(
  26. coalition_id, cru.get(), sizeof(coalition_resource_usage));
  27. if (res == 0U)
  28. return cru;
  29. return nullptr;
  30. }
  31. coalition_resource_usage GetCoalitionResourceUsageDifference(
  32. const coalition_resource_usage& left,
  33. const coalition_resource_usage& right) {
  34. DCHECK_GE(left.tasks_started, right.tasks_started);
  35. DCHECK_GE(left.tasks_exited, right.tasks_exited);
  36. DCHECK_GE(left.time_nonempty, right.time_nonempty);
  37. DCHECK_GE(left.cpu_time, right.cpu_time);
  38. DCHECK_GE(left.interrupt_wakeups, right.interrupt_wakeups);
  39. DCHECK_GE(left.platform_idle_wakeups, right.platform_idle_wakeups);
  40. DCHECK_GE(left.bytesread, right.bytesread);
  41. DCHECK_GE(left.byteswritten, right.byteswritten);
  42. DCHECK_GE(left.gpu_time, right.gpu_time);
  43. DCHECK_GE(left.cpu_time_billed_to_me, right.cpu_time_billed_to_me);
  44. DCHECK_GE(left.cpu_time_billed_to_others, right.cpu_time_billed_to_others);
  45. DCHECK_GE(left.energy, right.energy);
  46. DCHECK_GE(left.logical_immediate_writes, right.logical_immediate_writes);
  47. DCHECK_GE(left.logical_deferred_writes, right.logical_deferred_writes);
  48. DCHECK_GE(left.logical_invalidated_writes, right.logical_invalidated_writes);
  49. DCHECK_GE(left.logical_metadata_writes, right.logical_metadata_writes);
  50. DCHECK_GE(left.logical_immediate_writes_to_external,
  51. right.logical_immediate_writes_to_external);
  52. DCHECK_GE(left.logical_deferred_writes_to_external,
  53. right.logical_deferred_writes_to_external);
  54. DCHECK_GE(left.logical_invalidated_writes_to_external,
  55. right.logical_invalidated_writes_to_external);
  56. DCHECK_GE(left.logical_metadata_writes_to_external,
  57. right.logical_metadata_writes_to_external);
  58. DCHECK_GE(left.energy_billed_to_me, right.energy_billed_to_me);
  59. DCHECK_GE(left.energy_billed_to_others, right.energy_billed_to_others);
  60. DCHECK_GE(left.cpu_ptime, right.cpu_ptime);
  61. DCHECK_GE(left.cpu_instructions, right.cpu_instructions);
  62. DCHECK_GE(left.cpu_cycles, right.cpu_cycles);
  63. DCHECK_GE(left.fs_metadata_writes, right.fs_metadata_writes);
  64. DCHECK_GE(left.pm_writes, right.pm_writes);
  65. coalition_resource_usage ret;
  66. ret.tasks_started = left.tasks_started - right.tasks_started;
  67. ret.tasks_exited = left.tasks_exited - right.tasks_exited;
  68. ret.time_nonempty = left.time_nonempty - right.time_nonempty;
  69. ret.cpu_time = left.cpu_time - right.cpu_time;
  70. ret.interrupt_wakeups = left.interrupt_wakeups - right.interrupt_wakeups;
  71. ret.platform_idle_wakeups =
  72. left.platform_idle_wakeups - right.platform_idle_wakeups;
  73. ret.bytesread = left.bytesread - right.bytesread;
  74. ret.byteswritten = left.byteswritten - right.byteswritten;
  75. ret.gpu_time = left.gpu_time - right.gpu_time;
  76. ret.cpu_time_billed_to_me =
  77. left.cpu_time_billed_to_me - right.cpu_time_billed_to_me;
  78. ret.cpu_time_billed_to_others =
  79. left.cpu_time_billed_to_others - right.cpu_time_billed_to_others;
  80. ret.energy = left.energy - right.energy;
  81. ret.logical_immediate_writes =
  82. left.logical_immediate_writes - right.logical_immediate_writes;
  83. ret.logical_deferred_writes =
  84. left.logical_deferred_writes - right.logical_deferred_writes;
  85. ret.logical_invalidated_writes =
  86. left.logical_invalidated_writes - right.logical_invalidated_writes;
  87. ret.logical_metadata_writes =
  88. left.logical_metadata_writes - right.logical_metadata_writes;
  89. ret.logical_immediate_writes_to_external =
  90. left.logical_immediate_writes_to_external -
  91. right.logical_immediate_writes_to_external;
  92. ret.logical_deferred_writes_to_external =
  93. left.logical_deferred_writes_to_external -
  94. right.logical_deferred_writes_to_external;
  95. ret.logical_invalidated_writes_to_external =
  96. left.logical_invalidated_writes_to_external -
  97. right.logical_invalidated_writes_to_external;
  98. ret.logical_metadata_writes_to_external =
  99. left.logical_metadata_writes_to_external -
  100. right.logical_metadata_writes_to_external;
  101. ret.energy_billed_to_me =
  102. left.energy_billed_to_me - right.energy_billed_to_me;
  103. ret.energy_billed_to_others =
  104. left.energy_billed_to_others - right.energy_billed_to_others;
  105. ret.cpu_ptime = left.cpu_ptime - right.cpu_ptime;
  106. DCHECK_EQ(left.cpu_time_eqos_len,
  107. static_cast<uint64_t>(COALITION_NUM_THREAD_QOS_TYPES));
  108. DCHECK_EQ(right.cpu_time_eqos_len,
  109. static_cast<uint64_t>(COALITION_NUM_THREAD_QOS_TYPES));
  110. ret.cpu_time_eqos_len = left.cpu_time_eqos_len;
  111. for (int i = 0; i < COALITION_NUM_THREAD_QOS_TYPES; ++i) {
  112. DCHECK_GE(left.cpu_time_eqos[i], right.cpu_time_eqos[i]);
  113. ret.cpu_time_eqos[i] = left.cpu_time_eqos[i] - right.cpu_time_eqos[i];
  114. }
  115. ret.cpu_instructions = left.cpu_instructions - right.cpu_instructions;
  116. ret.cpu_cycles = left.cpu_cycles - right.cpu_cycles;
  117. ret.fs_metadata_writes = left.fs_metadata_writes - right.fs_metadata_writes;
  118. ret.pm_writes = left.pm_writes - right.pm_writes;
  119. return ret;
  120. }
  121. absl::optional<CoalitionResourceUsageRate> GetCoalitionResourceUsageRate(
  122. const coalition_resource_usage& begin,
  123. const coalition_resource_usage& end,
  124. base::TimeDelta interval_duration,
  125. mach_timebase_info_data_t timebase,
  126. absl::optional<EnergyImpactCoefficients> energy_impact_coefficients) {
  127. // Validate that |end| >= |begin|.
  128. bool end_greater_or_equal_begin =
  129. std::tie(end.cpu_time, end.interrupt_wakeups, end.platform_idle_wakeups,
  130. end.bytesread, end.byteswritten, end.gpu_time, end.energy) >=
  131. std::tie(begin.cpu_time, begin.interrupt_wakeups,
  132. begin.platform_idle_wakeups, begin.bytesread, begin.byteswritten,
  133. begin.gpu_time, begin.energy);
  134. for (int i = 0; i < COALITION_NUM_THREAD_QOS_TYPES; ++i) {
  135. if (end.cpu_time_eqos[i] < begin.cpu_time_eqos[i])
  136. end_greater_or_equal_begin = false;
  137. }
  138. if (!end_greater_or_equal_begin)
  139. return absl::nullopt;
  140. auto get_rate_per_second = [&interval_duration](uint64_t begin,
  141. uint64_t end) -> double {
  142. DCHECK_GE(end, begin);
  143. uint64_t diff = end - begin;
  144. return diff / interval_duration.InSecondsF();
  145. };
  146. auto get_time_rate_per_second = [&interval_duration, &timebase](
  147. uint64_t begin, uint64_t end) -> double {
  148. DCHECK_GE(end, begin);
  149. // Compute the delta in s, being careful to avoid truncation due to integral
  150. // division.
  151. double delta_sample_s =
  152. power_metrics::MachTimeToNs(end - begin, timebase) /
  153. static_cast<double>(base::Time::kNanosecondsPerSecond);
  154. return delta_sample_s / interval_duration.InSecondsF();
  155. };
  156. CoalitionResourceUsageRate result;
  157. result.cpu_time_per_second =
  158. get_time_rate_per_second(begin.cpu_time, end.cpu_time);
  159. result.interrupt_wakeups_per_second =
  160. get_rate_per_second(begin.interrupt_wakeups, end.interrupt_wakeups);
  161. result.platform_idle_wakeups_per_second = get_rate_per_second(
  162. begin.platform_idle_wakeups, end.platform_idle_wakeups);
  163. result.bytesread_per_second =
  164. get_rate_per_second(begin.bytesread, end.bytesread);
  165. result.byteswritten_per_second =
  166. get_rate_per_second(begin.byteswritten, end.byteswritten);
  167. result.gpu_time_per_second =
  168. get_time_rate_per_second(begin.gpu_time, end.gpu_time);
  169. result.power_nw = get_rate_per_second(begin.energy, end.energy);
  170. for (int i = 0; i < COALITION_NUM_THREAD_QOS_TYPES; ++i) {
  171. result.qos_time_per_second[i] =
  172. get_time_rate_per_second(begin.cpu_time_eqos[i], end.cpu_time_eqos[i]);
  173. }
  174. if (energy_impact_coefficients.has_value()) {
  175. result.energy_impact_per_second =
  176. (ComputeEnergyImpactForResourceUsage(
  177. end, energy_impact_coefficients.value(), timebase) -
  178. ComputeEnergyImpactForResourceUsage(
  179. begin, energy_impact_coefficients.value(), timebase)) /
  180. interval_duration.InSecondsF();
  181. }
  182. return result;
  183. }
  184. } // power_metrics