aggregate_metrics_processor.cc 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // Copyright 2017 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 "services/resource_coordinator/memory_instrumentation/aggregate_metrics_processor.h"
  5. #include <set>
  6. #include <string>
  7. #include <vector>
  8. #include "base/android/library_loader/anchor_functions.h"
  9. #include "base/android/library_loader/anchor_functions_buildflags.h"
  10. #include "base/bits.h"
  11. #include "base/command_line.h"
  12. #include "base/files/file.h"
  13. #include "base/format_macros.h"
  14. #include "base/logging.h"
  15. #include "base/memory/page_size.h"
  16. #include "base/strings/stringprintf.h"
  17. #include "base/trace_event/trace_event.h"
  18. #include "services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h"
  19. #if BUILDFLAG(SUPPORTS_CODE_ORDERING)
  20. namespace {
  21. void LogNativeCodeResidentPages(const std::set<size_t>& accessed_pages_set) {
  22. // |SUPPORTS_CODE_ORDERING| can only be enabled on Android.
  23. const auto kResidentPagesPath = base::FilePath(
  24. "/data/local/tmp/chrome/native-library-resident-pages.txt");
  25. auto file = base::File(kResidentPagesPath, base::File::FLAG_CREATE_ALWAYS |
  26. base::File::FLAG_WRITE);
  27. if (!file.IsValid()) {
  28. DLOG(ERROR) << "Could not open " << kResidentPagesPath;
  29. return;
  30. }
  31. for (size_t page : accessed_pages_set) {
  32. std::string page_str = base::StringPrintf("%" PRIuS "\n", page);
  33. if (file.WriteAtCurrentPos(page_str.c_str(),
  34. static_cast<int>(page_str.size())) < 0) {
  35. DLOG(WARNING) << "Error while dumping Resident pages";
  36. return;
  37. }
  38. }
  39. }
  40. } // namespace
  41. namespace memory_instrumentation {
  42. mojom::AggregatedMetricsPtr ComputeGlobalNativeCodeResidentMemoryKb(
  43. const std::map<base::ProcessId, mojom::RawOSMemDump*>& pid_to_pmd) {
  44. std::vector<uint8_t> common_map;
  45. auto metrics = mojom::AggregatedMetricsPtr(mojom::AggregatedMetrics::New());
  46. for (const auto& pmd : pid_to_pmd) {
  47. if (!pmd.second || pmd.second->native_library_pages_bitmap.empty()) {
  48. DLOG(WARNING) << "No process pagemap entry for " << pmd.first;
  49. return metrics;
  50. }
  51. if (common_map.size() < pmd.second->native_library_pages_bitmap.size()) {
  52. common_map.resize(pmd.second->native_library_pages_bitmap.size());
  53. }
  54. for (size_t i = 0; i < pmd.second->native_library_pages_bitmap.size();
  55. ++i) {
  56. common_map[i] |= pmd.second->native_library_pages_bitmap[i];
  57. }
  58. }
  59. // |accessed_pages_set| will be ~40kB on 32 bit mode and ~80kB on 64 bit mode.
  60. std::set<size_t> accessed_pages_set;
  61. for (size_t i = 0; i < common_map.size(); i++) {
  62. for (int j = 0; j < 8; j++) {
  63. if (common_map[i] & (1 << j))
  64. accessed_pages_set.insert(i * 8 + j);
  65. }
  66. }
  67. if (base::CommandLine::ForCurrentProcess()->HasSwitch(
  68. "log-native-library-residency")) {
  69. LogNativeCodeResidentPages(accessed_pages_set);
  70. }
  71. const size_t kPageSize = base::GetPageSize();
  72. const size_t kb_per_page = kPageSize / 1024;
  73. int32_t native_library_resident_not_ordered_kb =
  74. GlobalMemoryDump::AggregatedMetrics::kInvalid;
  75. int32_t native_library_not_resident_ordered_kb =
  76. GlobalMemoryDump::AggregatedMetrics::kInvalid;
  77. int32_t native_library_resident_kb =
  78. static_cast<int32_t>(accessed_pages_set.size() * kb_per_page);
  79. // Reporting the resident code data only requires |AreAnchorsSane()|, not
  80. // |IsOrderingSane()| which is a stronger guarantee.
  81. if (base::android::IsOrderingSane()) {
  82. // Start and end markers are not necessarily aligned with page boundaries.
  83. size_t start_of_text_page_index = base::android::kStartOfText / kPageSize;
  84. // Range is [start_of_ordered_section_page_offset,
  85. // end_of_ordered_section_page_offset)
  86. size_t start_of_ordered_section_page_offset =
  87. base::android::kStartOfOrderedText / kPageSize -
  88. start_of_text_page_index;
  89. size_t end_of_ordered_section_page_offset =
  90. base::bits::AlignUp(base::android::kEndOfOrderedText, kPageSize) /
  91. kPageSize -
  92. start_of_text_page_index;
  93. size_t resident_pages_in_ordered_section = 0;
  94. size_t resident_pages_outside_ordered_section = 0;
  95. for (size_t page : accessed_pages_set) {
  96. if (page >= start_of_ordered_section_page_offset &&
  97. page < end_of_ordered_section_page_offset) {
  98. resident_pages_in_ordered_section++;
  99. } else {
  100. resident_pages_outside_ordered_section++;
  101. }
  102. }
  103. size_t ordered_section_pages = end_of_ordered_section_page_offset -
  104. start_of_ordered_section_page_offset;
  105. size_t not_resident_ordered_pages =
  106. ordered_section_pages - resident_pages_in_ordered_section;
  107. native_library_resident_not_ordered_kb = static_cast<int32_t>(
  108. resident_pages_outside_ordered_section * kb_per_page);
  109. native_library_not_resident_ordered_kb =
  110. static_cast<int32_t>(not_resident_ordered_pages * kb_per_page);
  111. }
  112. // TODO(crbug.com/956464) replace adding |NativeCodeResidentMemory| to trace
  113. // this way by adding it through |tracing_observer| in Finalize().
  114. TRACE_EVENT_INSTANT1(base::trace_event::MemoryDumpManager::kTraceCategory,
  115. "ReportGlobalNativeCodeResidentMemoryKb",
  116. TRACE_EVENT_SCOPE_GLOBAL, "NativeCodeResidentMemory",
  117. native_library_resident_kb);
  118. metrics->native_library_resident_kb = native_library_resident_kb;
  119. metrics->native_library_resident_not_ordered_kb =
  120. native_library_resident_not_ordered_kb;
  121. metrics->native_library_not_resident_ordered_kb =
  122. native_library_not_resident_ordered_kb;
  123. // 0 is not a valid value, as at the very least the current page (the one
  124. // containing code for the collection function) should be resident.
  125. if (!native_library_resident_kb) {
  126. metrics->native_library_resident_kb =
  127. GlobalMemoryDump::AggregatedMetrics::kInvalid;
  128. }
  129. return metrics;
  130. }
  131. } // namespace memory_instrumentation
  132. #else
  133. namespace memory_instrumentation {
  134. mojom::AggregatedMetricsPtr ComputeGlobalNativeCodeResidentMemoryKb(
  135. const std::map<base::ProcessId, mojom::RawOSMemDump*>& pid_to_pmd) {
  136. return mojom::AggregatedMetricsPtr(mojom::AggregatedMetrics::New());
  137. }
  138. } // namespace memory_instrumentation
  139. #endif // #if BUILDFLAG(SUPPORTS_CODE_ORDERING)