v8_isolate_memory_dump_provider_unittest.cc 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // Copyright 2015 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 "gin/v8_isolate_memory_dump_provider.h"
  5. #include <memory>
  6. #include "base/task/thread_pool/thread_pool_instance.h"
  7. #include "base/threading/thread_task_runner_handle.h"
  8. #include "base/trace_event/process_memory_dump.h"
  9. #include "base/trace_event/trace_event.h"
  10. #include "build/build_config.h"
  11. #include "gin/public/isolate_holder.h"
  12. #include "gin/test/v8_test.h"
  13. #include "v8/include/v8-initialization.h"
  14. namespace gin {
  15. class V8MemoryDumpProviderTest : public V8Test {
  16. void SetUp() override {
  17. // Sets the track objects flag for dumping object statistics. Set this
  18. // before initializing V8, because flags should not be modified after
  19. // initialization. Also, setting the flag as early as possible ensures more
  20. // precise numbers.
  21. v8::V8::SetFlagsFromString("--track-gc-object-stats");
  22. V8Test::SetUp();
  23. }
  24. };
  25. class V8MemoryDumpProviderWorkerTest : public V8MemoryDumpProviderTest {
  26. protected:
  27. std::unique_ptr<IsolateHolder> CreateIsolateHolder() const override {
  28. return std::make_unique<gin::IsolateHolder>(
  29. base::ThreadTaskRunnerHandle::Get(),
  30. gin::IsolateHolder::IsolateType::kBlinkWorkerThread);
  31. }
  32. };
  33. // Checks if the dump provider runs without crashing and dumps root objects.
  34. TEST_F(V8MemoryDumpProviderTest, DumpStatistics) {
  35. base::trace_event::MemoryDumpArgs dump_args = {
  36. base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
  37. std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
  38. new base::trace_event::ProcessMemoryDump(dump_args));
  39. instance_->isolate_memory_dump_provider_for_testing()->OnMemoryDump(
  40. dump_args, process_memory_dump.get());
  41. const base::trace_event::ProcessMemoryDump::AllocatorDumpsMap&
  42. allocator_dumps = process_memory_dump->allocator_dumps();
  43. bool did_dump_isolate_stats = false;
  44. bool did_dump_space_stats = false;
  45. bool did_dump_objects_stats = false;
  46. for (const auto& name_dump : allocator_dumps) {
  47. const std::string& name = name_dump.first;
  48. if (name.find("v8/main") != std::string::npos) {
  49. did_dump_isolate_stats = true;
  50. }
  51. if (name.find("v8/main/heap") != std::string::npos) {
  52. did_dump_space_stats = true;
  53. }
  54. if (name.find("v8/main/heap_objects") != std::string::npos) {
  55. did_dump_objects_stats = true;
  56. }
  57. }
  58. ASSERT_TRUE(did_dump_isolate_stats);
  59. ASSERT_TRUE(did_dump_space_stats);
  60. ASSERT_TRUE(did_dump_objects_stats);
  61. }
  62. TEST_F(V8MemoryDumpProviderTest, DumpGlobalHandlesSize) {
  63. base::trace_event::MemoryDumpArgs dump_args = {
  64. base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND};
  65. std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
  66. new base::trace_event::ProcessMemoryDump(dump_args));
  67. instance_->isolate_memory_dump_provider_for_testing()->OnMemoryDump(
  68. dump_args, process_memory_dump.get());
  69. const base::trace_event::ProcessMemoryDump::AllocatorDumpsMap&
  70. allocator_dumps = process_memory_dump->allocator_dumps();
  71. bool did_dump_global_handles = false;
  72. for (const auto& name_dump : allocator_dumps) {
  73. const std::string& name = name_dump.first;
  74. if (name.find("v8/main/global_handles") != std::string::npos) {
  75. did_dump_global_handles = true;
  76. }
  77. }
  78. ASSERT_TRUE(did_dump_global_handles);
  79. }
  80. TEST_F(V8MemoryDumpProviderTest, DumpContextStatistics) {
  81. base::trace_event::MemoryDumpArgs dump_args = {
  82. base::trace_event::MemoryDumpLevelOfDetail::LIGHT};
  83. std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
  84. new base::trace_event::ProcessMemoryDump(dump_args));
  85. instance_->isolate_memory_dump_provider_for_testing()->OnMemoryDump(
  86. dump_args, process_memory_dump.get());
  87. const base::trace_event::ProcessMemoryDump::AllocatorDumpsMap&
  88. allocator_dumps = process_memory_dump->allocator_dumps();
  89. bool did_dump_detached_contexts = false;
  90. bool did_dump_native_contexts = false;
  91. for (const auto& name_dump : allocator_dumps) {
  92. const std::string& name = name_dump.first;
  93. if (name.find("main/contexts/detached_context") != std::string::npos) {
  94. did_dump_detached_contexts = true;
  95. }
  96. if (name.find("main/contexts/native_context") != std::string::npos) {
  97. did_dump_native_contexts = true;
  98. }
  99. }
  100. ASSERT_TRUE(did_dump_detached_contexts);
  101. ASSERT_TRUE(did_dump_native_contexts);
  102. }
  103. TEST_F(V8MemoryDumpProviderWorkerTest, DumpContextStatistics) {
  104. base::trace_event::MemoryDumpArgs dump_args = {
  105. base::trace_event::MemoryDumpLevelOfDetail::LIGHT};
  106. std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
  107. new base::trace_event::ProcessMemoryDump(dump_args));
  108. instance_->isolate_memory_dump_provider_for_testing()->OnMemoryDump(
  109. dump_args, process_memory_dump.get());
  110. const base::trace_event::ProcessMemoryDump::AllocatorDumpsMap&
  111. allocator_dumps = process_memory_dump->allocator_dumps();
  112. bool did_dump_detached_contexts = false;
  113. bool did_dump_native_contexts = false;
  114. for (const auto& name_dump : allocator_dumps) {
  115. const std::string& name = name_dump.first;
  116. if (name.find("workers/contexts/detached_context/isolate_0x") !=
  117. std::string::npos) {
  118. did_dump_detached_contexts = true;
  119. }
  120. if (name.find("workers/contexts/native_context/isolate_0x") !=
  121. std::string::npos) {
  122. did_dump_native_contexts = true;
  123. }
  124. }
  125. ASSERT_TRUE(did_dump_detached_contexts);
  126. ASSERT_TRUE(did_dump_native_contexts);
  127. }
  128. TEST_F(V8MemoryDumpProviderTest, DumpCodeStatistics) {
  129. // Code stats are disabled unless this category is enabled.
  130. base::trace_event::TraceLog::GetInstance()->SetEnabled(
  131. base::trace_event::TraceConfig(
  132. TRACE_DISABLED_BY_DEFAULT("memory-infra.v8.code_stats"), ""),
  133. base::trace_event::TraceLog::RECORDING_MODE);
  134. base::trace_event::MemoryDumpArgs dump_args = {
  135. base::trace_event::MemoryDumpLevelOfDetail::LIGHT};
  136. std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
  137. new base::trace_event::ProcessMemoryDump(dump_args));
  138. instance_->isolate_memory_dump_provider_for_testing()->OnMemoryDump(
  139. dump_args, process_memory_dump.get());
  140. const base::trace_event::ProcessMemoryDump::AllocatorDumpsMap&
  141. allocator_dumps = process_memory_dump->allocator_dumps();
  142. bool did_dump_bytecode_size = false;
  143. bool did_dump_code_size = false;
  144. bool did_dump_external_scripts_size = false;
  145. bool did_dump_cpu_profiler_metadata_size = false;
  146. for (const auto& name_dump : allocator_dumps) {
  147. const std::string& name = name_dump.first;
  148. if (name.find("code_stats") != std::string::npos) {
  149. for (const base::trace_event::MemoryAllocatorDump::Entry& entry :
  150. name_dump.second->entries()) {
  151. if (entry.name == "bytecode_and_metadata_size") {
  152. did_dump_bytecode_size = true;
  153. } else if (entry.name == "code_and_metadata_size") {
  154. did_dump_code_size = true;
  155. } else if (entry.name == "external_script_source_size") {
  156. did_dump_external_scripts_size = true;
  157. } else if (entry.name == "cpu_profiler_metadata_size") {
  158. did_dump_cpu_profiler_metadata_size = true;
  159. }
  160. }
  161. }
  162. }
  163. base::trace_event::TraceLog::GetInstance()->SetDisabled();
  164. ASSERT_TRUE(did_dump_bytecode_size);
  165. ASSERT_TRUE(did_dump_code_size);
  166. ASSERT_TRUE(did_dump_external_scripts_size);
  167. ASSERT_TRUE(did_dump_cpu_profiler_metadata_size);
  168. }
  169. // Tests that a deterministic memory dump request performs a GC.
  170. // TODO(crbug.com/1318974): Fix the flakiness on Linux.
  171. // TODO(crbug.com/1342599): Fix the falkiness on linux-chromeos-dbg.
  172. #if BUILDFLAG(IS_LINUX) || (BUILDFLAG(IS_CHROMEOS) && !defined(NDEBUG))
  173. #define MAYBE_Deterministic DISABLED_Deterministic
  174. #else
  175. #define MAYBE_Deterministic Deterministic
  176. #endif
  177. TEST_F(V8MemoryDumpProviderTest, MAYBE_Deterministic) {
  178. base::trace_event::MemoryDumpArgs dump_args = {
  179. base::trace_event::MemoryDumpLevelOfDetail::LIGHT,
  180. base::trace_event::MemoryDumpDeterminism::FORCE_GC};
  181. std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
  182. new base::trace_event::ProcessMemoryDump(dump_args));
  183. // Allocate an object that has only a weak reference.
  184. v8::Global<v8::Object> weak_ref;
  185. {
  186. v8::HandleScope scope(instance_->isolate());
  187. v8::Local<v8::Object> object = v8::Object::New(instance_->isolate());
  188. weak_ref.Reset(instance_->isolate(), object);
  189. weak_ref.SetWeak();
  190. }
  191. // Deterministic memory dump should trigger GC.
  192. instance_->isolate_memory_dump_provider_for_testing()->OnMemoryDump(
  193. dump_args, process_memory_dump.get());
  194. // GC reclaimed the object.
  195. ASSERT_TRUE(weak_ref.IsEmpty());
  196. }
  197. } // namespace gin