v8_isolate_memory_dump_provider_unittest.cc 8.3 KB

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