v8_metrics.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. // Copyright 2020 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 "third_party/blink/renderer/bindings/core/v8/v8_metrics.h"
  5. #include <cstdint>
  6. #include "base/metrics/histogram_macros.h"
  7. #include "base/time/time.h"
  8. #include "services/metrics/public/cpp/metrics_utils.h"
  9. #include "services/metrics/public/cpp/ukm_builders.h"
  10. #include "third_party/blink/renderer/bindings/core/v8/local_window_proxy.h"
  11. #include "third_party/blink/renderer/core/dom/document.h"
  12. #include "third_party/blink/renderer/core/frame/frame.h"
  13. #include "third_party/blink/renderer/core/frame/local_dom_window.h"
  14. #include "third_party/blink/renderer/core/frame/local_frame.h"
  15. #include "third_party/blink/renderer/core/page/page.h"
  16. #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
  17. #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
  18. namespace blink {
  19. void V8MetricsRecorder::AddMainThreadEvent(
  20. const v8::metrics::WasmModuleDecoded& event,
  21. v8::metrics::Recorder::ContextId context_id) {
  22. auto ukm = GetUkmRecorderAndSourceId(context_id);
  23. if (!ukm)
  24. return;
  25. ukm::builders::V8_Wasm_ModuleDecoded(ukm->source_id)
  26. .SetStreamed(event.streamed ? 1 : 0)
  27. .SetSuccess(event.success ? 1 : 0)
  28. .SetModuleSize(
  29. ukm::GetExponentialBucketMinForBytes(event.module_size_in_bytes))
  30. .SetFunctionCount(event.function_count)
  31. .SetWallClockDuration(event.wall_clock_duration_in_us)
  32. .Record(ukm->recorder);
  33. }
  34. void V8MetricsRecorder::AddMainThreadEvent(
  35. const v8::metrics::WasmModuleCompiled& event,
  36. v8::metrics::Recorder::ContextId context_id) {
  37. auto ukm = GetUkmRecorderAndSourceId(context_id);
  38. if (!ukm)
  39. return;
  40. ukm::builders::V8_Wasm_ModuleCompiled(ukm->source_id)
  41. .SetAsync(event.async ? 1 : 0)
  42. .SetCached(event.cached ? 1 : 0)
  43. .SetDeserialized(event.deserialized ? 1 : 0)
  44. .SetLazy(event.lazy ? 1 : 0)
  45. .SetStreamed(event.streamed ? 1 : 0)
  46. .SetSuccess(event.success ? 1 : 0)
  47. .SetCodeSize(
  48. ukm::GetExponentialBucketMinForBytes(event.code_size_in_bytes))
  49. .SetLiftoffBailoutCount(event.liftoff_bailout_count)
  50. .SetWallClockDuration(event.wall_clock_duration_in_us)
  51. .Record(ukm->recorder);
  52. }
  53. void V8MetricsRecorder::AddMainThreadEvent(
  54. const v8::metrics::WasmModuleInstantiated& event,
  55. v8::metrics::Recorder::ContextId context_id) {
  56. auto ukm = GetUkmRecorderAndSourceId(context_id);
  57. if (!ukm)
  58. return;
  59. ukm::builders::V8_Wasm_ModuleInstantiated(ukm->source_id)
  60. .SetSuccess(event.success ? 1 : 0)
  61. .SetImportedFunctionCount(event.imported_function_count)
  62. .SetWallClockDuration(event.wall_clock_duration_in_us)
  63. .Record(ukm->recorder);
  64. }
  65. namespace {
  66. // Helper function to convert a byte count to a KB count, capping at
  67. // INT_MAX if the number is larger than that.
  68. constexpr int32_t CappedSizeInKB(int64_t size_in_bytes) {
  69. return base::saturated_cast<int32_t>(size_in_bytes / 1024);
  70. }
  71. // Helper function to convert a B/us count to a KB/ms count, capping at
  72. // INT_MAX if the number is larger than that.
  73. constexpr int32_t CappedEfficacyInKBPerMs(double efficacy_in_bytes_per_us) {
  74. return base::saturated_cast<int32_t>(efficacy_in_bytes_per_us * 1000 / 1024);
  75. }
  76. // Returns true if |event| contains valid cpp histogram values.
  77. bool CheckCppEvents(const v8::metrics::GarbageCollectionFullCycle& event) {
  78. if (event.total_cpp.mark_wall_clock_duration_in_us == -1) {
  79. // If a cpp field in |event| is uninitialized, all cpp fields should be
  80. // uninitialized.
  81. DCHECK_EQ(-1, event.total_cpp.mark_wall_clock_duration_in_us);
  82. DCHECK_EQ(-1, event.total_cpp.weak_wall_clock_duration_in_us);
  83. DCHECK_EQ(-1, event.total_cpp.compact_wall_clock_duration_in_us);
  84. DCHECK_EQ(-1, event.total_cpp.sweep_wall_clock_duration_in_us);
  85. DCHECK_EQ(-1, event.main_thread_cpp.mark_wall_clock_duration_in_us);
  86. DCHECK_EQ(-1, event.main_thread_cpp.weak_wall_clock_duration_in_us);
  87. DCHECK_EQ(-1, event.main_thread_cpp.compact_wall_clock_duration_in_us);
  88. DCHECK_EQ(-1, event.main_thread_cpp.sweep_wall_clock_duration_in_us);
  89. DCHECK_EQ(-1, event.main_thread_atomic_cpp.mark_wall_clock_duration_in_us);
  90. DCHECK_EQ(-1, event.main_thread_atomic_cpp.weak_wall_clock_duration_in_us);
  91. DCHECK_EQ(-1,
  92. event.main_thread_atomic_cpp.compact_wall_clock_duration_in_us);
  93. DCHECK_EQ(-1, event.main_thread_atomic_cpp.sweep_wall_clock_duration_in_us);
  94. DCHECK_EQ(-1, event.objects_cpp.bytes_before);
  95. DCHECK_EQ(-1, event.objects_cpp.bytes_after);
  96. DCHECK_EQ(-1, event.objects_cpp.bytes_freed);
  97. DCHECK_EQ(-1, event.memory_cpp.bytes_freed);
  98. DCHECK_EQ(-1.0, event.efficiency_cpp_in_bytes_per_us);
  99. DCHECK_EQ(-1.0, event.main_thread_efficiency_cpp_in_bytes_per_us);
  100. DCHECK_EQ(-1.0, event.collection_rate_cpp_in_percent);
  101. return false;
  102. }
  103. // Check that all used values have been initialized.
  104. DCHECK_LE(0, event.total_cpp.mark_wall_clock_duration_in_us);
  105. DCHECK_LE(0, event.total_cpp.weak_wall_clock_duration_in_us);
  106. DCHECK_LE(0, event.total_cpp.compact_wall_clock_duration_in_us);
  107. DCHECK_LE(0, event.total_cpp.sweep_wall_clock_duration_in_us);
  108. DCHECK_LE(0, event.main_thread_cpp.mark_wall_clock_duration_in_us);
  109. DCHECK_LE(0, event.main_thread_cpp.weak_wall_clock_duration_in_us);
  110. DCHECK_LE(0, event.main_thread_cpp.compact_wall_clock_duration_in_us);
  111. DCHECK_LE(0, event.main_thread_cpp.sweep_wall_clock_duration_in_us);
  112. DCHECK_LE(0, event.main_thread_atomic_cpp.mark_wall_clock_duration_in_us);
  113. DCHECK_LE(0, event.main_thread_atomic_cpp.weak_wall_clock_duration_in_us);
  114. DCHECK_LE(0, event.main_thread_atomic_cpp.compact_wall_clock_duration_in_us);
  115. DCHECK_LE(0, event.main_thread_atomic_cpp.sweep_wall_clock_duration_in_us);
  116. DCHECK_LE(0, event.objects_cpp.bytes_before);
  117. DCHECK_LE(0, event.objects_cpp.bytes_after);
  118. DCHECK_LE(0, event.objects_cpp.bytes_freed);
  119. DCHECK_LE(0, event.memory_cpp.bytes_freed);
  120. DCHECK_LE(0, event.efficiency_cpp_in_bytes_per_us);
  121. DCHECK_LE(0, event.main_thread_efficiency_cpp_in_bytes_per_us);
  122. DCHECK_LE(0, event.collection_rate_cpp_in_percent);
  123. return true;
  124. }
  125. void CheckUnifiedEvents(const v8::metrics::GarbageCollectionFullCycle& event) {
  126. // Check that all used values have been initialized.
  127. DCHECK_LE(0, event.total.total_wall_clock_duration_in_us);
  128. DCHECK_LE(0, event.total.mark_wall_clock_duration_in_us);
  129. DCHECK_LE(0, event.total.weak_wall_clock_duration_in_us);
  130. DCHECK_LE(0, event.total.compact_wall_clock_duration_in_us);
  131. DCHECK_LE(0, event.total.sweep_wall_clock_duration_in_us);
  132. DCHECK_LE(0, event.main_thread.total_wall_clock_duration_in_us);
  133. DCHECK_LE(0, event.main_thread.mark_wall_clock_duration_in_us);
  134. DCHECK_LE(0, event.main_thread.weak_wall_clock_duration_in_us);
  135. DCHECK_LE(0, event.main_thread.compact_wall_clock_duration_in_us);
  136. DCHECK_LE(0, event.main_thread.sweep_wall_clock_duration_in_us);
  137. DCHECK_LE(0, event.main_thread_atomic.total_wall_clock_duration_in_us);
  138. DCHECK_LE(0, event.main_thread_atomic.mark_wall_clock_duration_in_us);
  139. DCHECK_LE(0, event.main_thread_atomic.weak_wall_clock_duration_in_us);
  140. DCHECK_LE(0, event.main_thread_atomic.compact_wall_clock_duration_in_us);
  141. DCHECK_LE(0, event.main_thread_atomic.sweep_wall_clock_duration_in_us);
  142. // Incremental marking and sweeping may be uninitialized; the other values
  143. // must be uninitialized.
  144. DCHECK_EQ(-1, event.main_thread_incremental.total_wall_clock_duration_in_us);
  145. DCHECK_LE(-1, event.main_thread_incremental.mark_wall_clock_duration_in_us);
  146. DCHECK_EQ(-1, event.main_thread_incremental.weak_wall_clock_duration_in_us);
  147. DCHECK_EQ(-1,
  148. event.main_thread_incremental.compact_wall_clock_duration_in_us);
  149. DCHECK_LE(-1, event.main_thread_incremental.sweep_wall_clock_duration_in_us);
  150. // TODO(chromium:1154636): Also check for the following when they are
  151. // populated:
  152. #if 0
  153. DCHECK_LE(0, event.objects.bytes_before);
  154. DCHECK_LE(0, event.objects.bytes_after);
  155. DCHECK_LE(0, event.objects.bytes_freed);
  156. DCHECK_LE(0, event.memory.bytes_freed);
  157. DCHECK_LE(0, event.efficiency_in_bytes_per_us);
  158. DCHECK_LE(0, event.main_thread_efficiency_in_bytes_per_us);
  159. DCHECK_LE(0, event.collection_rate_in_percent);
  160. #endif
  161. }
  162. } // namespace
  163. void V8MetricsRecorder::AddMainThreadEvent(
  164. const v8::metrics::GarbageCollectionFullCycle& event,
  165. ContextId context_id) {
  166. #define UMA_HISTOGRAM_TIMES_ALL_GC_PHASES(prefix, suffix, statistics) \
  167. UMA_HISTOGRAM_TIMES( \
  168. prefix suffix, \
  169. base::Microseconds(statistics.total_wall_clock_duration_in_us)); \
  170. UMA_HISTOGRAM_TIMES( \
  171. prefix ".Mark" suffix, \
  172. base::Microseconds(statistics.mark_wall_clock_duration_in_us)); \
  173. UMA_HISTOGRAM_TIMES( \
  174. prefix ".Compact" suffix, \
  175. base::Microseconds(statistics.compact_wall_clock_duration_in_us)); \
  176. UMA_HISTOGRAM_TIMES( \
  177. prefix ".Sweep" suffix, \
  178. base::Microseconds(statistics.sweep_wall_clock_duration_in_us)); \
  179. UMA_HISTOGRAM_TIMES( \
  180. prefix ".Weak" suffix, \
  181. base::Microseconds(statistics.weak_wall_clock_duration_in_us));
  182. DCHECK_LE(0, event.reason);
  183. UMA_HISTOGRAM_ENUMERATION("V8.GC.Cycle.Reason.Full", event.reason,
  184. v8::internal::kGarbageCollectionReasonMaxValue);
  185. static constexpr size_t kMinSize = 1;
  186. static constexpr size_t kMaxSize = 4 * 1024 * 1024;
  187. static constexpr size_t kNumBuckets = 50;
  188. CheckUnifiedEvents(event);
  189. // Report throughput metrics:
  190. UMA_HISTOGRAM_TIMES_ALL_GC_PHASES("V8.GC.Cycle.Full", "", event.total);
  191. UMA_HISTOGRAM_TIMES_ALL_GC_PHASES("V8.GC.Cycle.MainThread.Full", "",
  192. event.main_thread);
  193. // Report atomic pause metrics:
  194. UMA_HISTOGRAM_TIMES_ALL_GC_PHASES("V8.GC.Cycle.MainThread.Full.Atomic", "",
  195. event.main_thread_atomic);
  196. // Report incremental marking/sweeping metrics:
  197. if (event.main_thread_incremental.mark_wall_clock_duration_in_us >= 0) {
  198. UMA_HISTOGRAM_TIMES(
  199. "V8.GC.Cycle.MainThread.Full.Incremental.Mark",
  200. base::Microseconds(
  201. event.main_thread_incremental.mark_wall_clock_duration_in_us));
  202. }
  203. if (event.main_thread_incremental.sweep_wall_clock_duration_in_us >= 0) {
  204. UMA_HISTOGRAM_TIMES(
  205. "V8.GC.Cycle.MainThread.Full.Incremental.Sweep",
  206. base::Microseconds(
  207. event.main_thread_incremental.sweep_wall_clock_duration_in_us));
  208. }
  209. // TODO(chromium:1154636): emit the following when they are populated:
  210. // - event.objects
  211. // - event.memory
  212. // Report efficacy metrics:
  213. DEFINE_THREAD_SAFE_STATIC_LOCAL(
  214. CustomCountHistogram, efficacy_histogram,
  215. ("V8.GC.Cycle.Efficiency.Full", kMinSize, kMaxSize, kNumBuckets));
  216. efficacy_histogram.Count(
  217. CappedEfficacyInKBPerMs(event.efficiency_in_bytes_per_us));
  218. DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram,
  219. efficacy_main_thread_histogram,
  220. ("V8.GC.Cycle.Efficiency.MainThread.Full",
  221. kMinSize, kMaxSize, kNumBuckets));
  222. efficacy_main_thread_histogram.Count(
  223. CappedEfficacyInKBPerMs(event.main_thread_efficiency_in_bytes_per_us));
  224. DEFINE_THREAD_SAFE_STATIC_LOCAL(
  225. CustomCountHistogram, collection_rate_histogram,
  226. ("V8.GC.Cycle.CollectionRate.Full", 1, 100, 20));
  227. collection_rate_histogram.Count(base::saturated_cast<base::Histogram::Sample>(
  228. 100 * event.collection_rate_in_percent));
  229. if (CheckCppEvents(event)) {
  230. // Report throughput metrics:
  231. UMA_HISTOGRAM_TIMES_ALL_GC_PHASES("V8.GC.Cycle.Full", ".Cpp",
  232. event.total_cpp);
  233. UMA_HISTOGRAM_TIMES_ALL_GC_PHASES("V8.GC.Cycle.MainThread.Full", ".Cpp",
  234. event.main_thread_cpp);
  235. // Report atomic pause metrics:
  236. UMA_HISTOGRAM_TIMES_ALL_GC_PHASES("V8.GC.Cycle.MainThread.Full.Atomic",
  237. ".Cpp", event.main_thread_atomic_cpp);
  238. // Report incremental marking/sweeping metrics:
  239. if (event.main_thread_incremental_cpp.mark_wall_clock_duration_in_us >= 0) {
  240. UMA_HISTOGRAM_TIMES(
  241. "V8.GC.Cycle.MainThread.Full.Incremental.Mark.Cpp",
  242. base::Microseconds(event.main_thread_incremental_cpp
  243. .mark_wall_clock_duration_in_us));
  244. }
  245. if (event.main_thread_incremental_cpp.sweep_wall_clock_duration_in_us >=
  246. 0) {
  247. UMA_HISTOGRAM_TIMES(
  248. "V8.GC.Cycle.MainThread.Full.Incremental.Sweep.Cpp",
  249. base::Microseconds(event.main_thread_incremental_cpp
  250. .sweep_wall_clock_duration_in_us));
  251. }
  252. // Report size metrics:
  253. DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram,
  254. object_size_before_histogram,
  255. ("V8.GC.Cycle.Objects.Before.Full.Cpp",
  256. kMinSize, kMaxSize, kNumBuckets));
  257. object_size_before_histogram.Count(
  258. CappedSizeInKB(event.objects_cpp.bytes_before));
  259. DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram,
  260. object_size_after_histogram,
  261. ("V8.GC.Cycle.Objects.After.Full.Cpp",
  262. kMinSize, kMaxSize, kNumBuckets));
  263. object_size_after_histogram.Count(
  264. CappedSizeInKB(event.objects_cpp.bytes_after));
  265. DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram,
  266. object_size_freed_histogram,
  267. ("V8.GC.Cycle.Objects.Freed.Full.Cpp",
  268. kMinSize, kMaxSize, kNumBuckets));
  269. object_size_freed_histogram.Count(
  270. CappedSizeInKB(event.objects_cpp.bytes_freed));
  271. DEFINE_THREAD_SAFE_STATIC_LOCAL(
  272. CustomCountHistogram, memory_size_freed_histogram,
  273. ("V8.GC.Cycle.Memory.Freed.Full.Cpp", kMinSize, kMaxSize, kNumBuckets));
  274. memory_size_freed_histogram.Count(
  275. CappedSizeInKB(event.memory_cpp.bytes_freed));
  276. // Report efficacy metrics:
  277. DEFINE_THREAD_SAFE_STATIC_LOCAL(
  278. CustomCountHistogram, efficacy_histogram,
  279. ("V8.GC.Cycle.Efficiency.Full.Cpp", kMinSize, kMaxSize, kNumBuckets));
  280. efficacy_histogram.Count(
  281. CappedEfficacyInKBPerMs(event.efficiency_cpp_in_bytes_per_us));
  282. DEFINE_THREAD_SAFE_STATIC_LOCAL(
  283. CustomCountHistogram, efficacy_main_thread_cpp_histogram,
  284. ("V8.GC.Cycle.Efficiency.MainThread.Full.Cpp", kMinSize, kMaxSize,
  285. kNumBuckets));
  286. efficacy_main_thread_cpp_histogram.Count(CappedEfficacyInKBPerMs(
  287. event.main_thread_efficiency_cpp_in_bytes_per_us));
  288. DEFINE_THREAD_SAFE_STATIC_LOCAL(
  289. CustomCountHistogram, collection_rate_histogram,
  290. ("V8.GC.Cycle.CollectionRate.Full.Cpp", 1, 100, 20));
  291. collection_rate_histogram.Count(
  292. base::saturated_cast<base::Histogram::Sample>(
  293. 100 * event.collection_rate_cpp_in_percent));
  294. }
  295. #undef UMA_HISTOGRAM_TIMES_ALL_GC_PHASES
  296. }
  297. void V8MetricsRecorder::AddMainThreadEvent(
  298. const v8::metrics::GarbageCollectionFullMainThreadIncrementalMark& event,
  299. ContextId context_id) {
  300. if (event.wall_clock_duration_in_us >= 0) {
  301. UMA_HISTOGRAM_TIMES("V8.GC.Event.MainThread.Full.Incremental.Mark",
  302. base::Microseconds(event.wall_clock_duration_in_us));
  303. }
  304. if (event.cpp_wall_clock_duration_in_us >= 0) {
  305. // This is only a latency event.
  306. UMA_HISTOGRAM_TIMES(
  307. "V8.GC.Event.MainThread.Full.Incremental.Mark.Cpp",
  308. base::Microseconds(event.cpp_wall_clock_duration_in_us));
  309. }
  310. }
  311. void V8MetricsRecorder::AddMainThreadEvent(
  312. const v8::metrics::GarbageCollectionFullMainThreadIncrementalSweep& event,
  313. ContextId context_id) {
  314. if (event.wall_clock_duration_in_us >= 0) {
  315. UMA_HISTOGRAM_TIMES("V8.GC.Event.MainThread.Full.Incremental.Sweep",
  316. base::Microseconds(event.wall_clock_duration_in_us));
  317. }
  318. if (event.cpp_wall_clock_duration_in_us >= 0) {
  319. // This is only a latency event.
  320. UMA_HISTOGRAM_TIMES(
  321. "V8.GC.Event.MainThread.Full.Incremental.Sweep.Cpp",
  322. base::Microseconds(event.cpp_wall_clock_duration_in_us));
  323. }
  324. }
  325. void V8MetricsRecorder::AddMainThreadEvent(
  326. const v8::metrics::GarbageCollectionFullMainThreadBatchedIncrementalMark&
  327. event,
  328. ContextId context_id) {
  329. AddMainThreadBatchedEvents(event, context_id);
  330. }
  331. void V8MetricsRecorder::AddMainThreadEvent(
  332. const v8::metrics::GarbageCollectionFullMainThreadBatchedIncrementalSweep&
  333. event,
  334. ContextId context_id) {
  335. AddMainThreadBatchedEvents(event, context_id);
  336. }
  337. void V8MetricsRecorder::AddMainThreadEvent(
  338. const v8::metrics::GarbageCollectionYoungCycle& event,
  339. ContextId context_id) {
  340. // Check that all used values have been initialized.
  341. DCHECK_LE(0, event.reason);
  342. DCHECK_LE(0, event.total_wall_clock_duration_in_us);
  343. DCHECK_LE(0, event.main_thread_wall_clock_duration_in_us);
  344. DCHECK_LE(0, event.collection_rate_in_percent);
  345. DCHECK_LE(0, event.efficiency_in_bytes_per_us);
  346. DCHECK_LE(0, event.main_thread_efficiency_in_bytes_per_us);
  347. UMA_HISTOGRAM_ENUMERATION("V8.GC.Cycle.Reason.Young", event.reason,
  348. v8::internal::kGarbageCollectionReasonMaxValue);
  349. UMA_HISTOGRAM_TIMES(
  350. "V8.GC.Cycle.Young",
  351. base::Microseconds(event.total_wall_clock_duration_in_us));
  352. UMA_HISTOGRAM_TIMES(
  353. "V8.GC.Cycle.MainThread.Young",
  354. base::Microseconds(event.main_thread_wall_clock_duration_in_us));
  355. static constexpr size_t kMinSize = 1;
  356. static constexpr size_t kMaxSize = 4 * 1024 * 1024;
  357. static constexpr size_t kNumBuckets = 50;
  358. DEFINE_THREAD_SAFE_STATIC_LOCAL(
  359. CustomCountHistogram, efficacy_histogram,
  360. ("V8.GC.Cycle.Efficiency.Young", kMinSize, kMaxSize, kNumBuckets));
  361. efficacy_histogram.Count(
  362. CappedEfficacyInKBPerMs(event.efficiency_in_bytes_per_us));
  363. DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram,
  364. efficacy_main_thread_histogram,
  365. ("V8.GC.Cycle.Efficiency.MainThread.Young",
  366. kMinSize, kMaxSize, kNumBuckets));
  367. efficacy_main_thread_histogram.Count(
  368. CappedEfficacyInKBPerMs(event.main_thread_efficiency_in_bytes_per_us));
  369. DEFINE_THREAD_SAFE_STATIC_LOCAL(
  370. CustomCountHistogram, collection_rate_histogram,
  371. ("V8.GC.Cycle.CollectionRate.Young", 1, 100, 20));
  372. collection_rate_histogram.Count(base::saturated_cast<base::Histogram::Sample>(
  373. 100 * event.collection_rate_in_percent));
  374. }
  375. void V8MetricsRecorder::NotifyIsolateDisposal() {
  376. v8::metrics::Recorder::NotifyIsolateDisposal();
  377. isolate_ = nullptr;
  378. }
  379. absl::optional<V8MetricsRecorder::UkmRecorderAndSourceId>
  380. V8MetricsRecorder::GetUkmRecorderAndSourceId(
  381. v8::metrics::Recorder::ContextId context_id) {
  382. if (!isolate_)
  383. return absl::optional<UkmRecorderAndSourceId>();
  384. v8::HandleScope handle_scope(isolate_);
  385. v8::MaybeLocal<v8::Context> maybe_context =
  386. v8::metrics::Recorder::GetContext(isolate_, context_id);
  387. if (maybe_context.IsEmpty())
  388. return absl::optional<UkmRecorderAndSourceId>();
  389. ExecutionContext* context =
  390. ExecutionContext::From(maybe_context.ToLocalChecked());
  391. if (!context)
  392. return absl::optional<UkmRecorderAndSourceId>();
  393. ukm::UkmRecorder* ukm_recorder = context->UkmRecorder();
  394. if (!ukm_recorder)
  395. return absl::optional<UkmRecorderAndSourceId>();
  396. return absl::optional<UkmRecorderAndSourceId>(absl::in_place, ukm_recorder,
  397. context->UkmSourceID());
  398. }
  399. } // namespace blink