library_prefetcher.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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 "base/android/library_loader/library_prefetcher.h"
  5. #include <stddef.h>
  6. #include <sys/mman.h>
  7. #include <sys/resource.h>
  8. #include <sys/wait.h>
  9. #include <unistd.h>
  10. #include <algorithm>
  11. #include <atomic>
  12. #include <cstdlib>
  13. #include <memory>
  14. #include <utility>
  15. #include <vector>
  16. #include "base/android/library_loader/anchor_functions.h"
  17. #include "base/android/orderfile/orderfile_buildflags.h"
  18. #include "base/bits.h"
  19. #include "base/files/file.h"
  20. #include "base/format_macros.h"
  21. #include "base/logging.h"
  22. #include "base/posix/eintr_wrapper.h"
  23. #include "base/process/process_metrics.h"
  24. #include "base/strings/string_util.h"
  25. #include "base/strings/stringprintf.h"
  26. #include "build/build_config.h"
  27. #if BUILDFLAG(ORDERFILE_INSTRUMENTATION)
  28. #include "base/android/orderfile/orderfile_instrumentation.h"
  29. #endif
  30. #if BUILDFLAG(SUPPORTS_CODE_ORDERING)
  31. namespace base {
  32. namespace android {
  33. namespace {
  34. // Valid for all Android architectures.
  35. constexpr size_t kPageSize = 4096;
  36. // Populates the per-page residency between |start| and |end| in |residency|. If
  37. // successful, |residency| has the size of |end| - |start| in pages.
  38. // Returns true for success.
  39. bool Mincore(size_t start, size_t end, std::vector<unsigned char>* residency) {
  40. if (start % kPageSize || end % kPageSize)
  41. return false;
  42. size_t size = end - start;
  43. size_t size_in_pages = size / kPageSize;
  44. if (residency->size() != size_in_pages)
  45. residency->resize(size_in_pages);
  46. int err = HANDLE_EINTR(
  47. mincore(reinterpret_cast<void*>(start), size, &(*residency)[0]));
  48. PLOG_IF(ERROR, err) << "mincore() failed";
  49. return !err;
  50. }
  51. // Returns the start and end of .text, aligned to the lower and upper page
  52. // boundaries, respectively.
  53. std::pair<size_t, size_t> GetTextRange() {
  54. // |kStartOfText| may not be at the beginning of a page, since .plt can be
  55. // before it, yet in the same mapping for instance.
  56. size_t start_page = kStartOfText - kStartOfText % kPageSize;
  57. // Set the end to the page on which the beginning of the last symbol is. The
  58. // actual symbol may spill into the next page by a few bytes, but this is
  59. // outside of the executable code range anyway.
  60. size_t end_page = base::bits::AlignUp(kEndOfText, kPageSize);
  61. return {start_page, end_page};
  62. }
  63. // Returns the start and end pages of the unordered section of .text, aligned to
  64. // lower and upper page boundaries, respectively.
  65. std::pair<size_t, size_t> GetOrderedTextRange() {
  66. size_t start_page = kStartOfOrderedText - kStartOfOrderedText % kPageSize;
  67. // kEndOfUnorderedText is not considered ordered, but the byte immediately
  68. // before is considered ordered and so can not be contained in the start page.
  69. size_t end_page = base::bits::AlignUp(kEndOfOrderedText, kPageSize);
  70. return {start_page, end_page};
  71. }
  72. // Calls madvise(advice) on the specified range. Does nothing if the range is
  73. // empty.
  74. void MadviseOnRange(const std::pair<size_t, size_t>& range, int advice) {
  75. if (range.first >= range.second) {
  76. return;
  77. }
  78. size_t size = range.second - range.first;
  79. int err = madvise(reinterpret_cast<void*>(range.first), size, advice);
  80. if (err) {
  81. PLOG(ERROR) << "madvise() failed";
  82. }
  83. }
  84. // Timestamp in ns since Unix Epoch, and residency, as returned by mincore().
  85. struct TimestampAndResidency {
  86. uint64_t timestamp_nanos;
  87. std::vector<unsigned char> residency;
  88. TimestampAndResidency(uint64_t timestamp_nanos,
  89. std::vector<unsigned char>&& residency)
  90. : timestamp_nanos(timestamp_nanos), residency(residency) {}
  91. };
  92. // Returns true for success.
  93. bool CollectResidency(size_t start,
  94. size_t end,
  95. std::vector<TimestampAndResidency>* data) {
  96. // Not using base::TimeTicks() to not call too many base:: symbol that would
  97. // pollute the reached symbols dumps.
  98. struct timespec ts;
  99. if (HANDLE_EINTR(clock_gettime(CLOCK_MONOTONIC, &ts))) {
  100. PLOG(ERROR) << "Cannot get the time.";
  101. return false;
  102. }
  103. uint64_t now = static_cast<uint64_t>(ts.tv_sec) * 1000 * 1000 * 1000 +
  104. static_cast<uint64_t>(ts.tv_nsec);
  105. std::vector<unsigned char> residency;
  106. if (!Mincore(start, end, &residency))
  107. return false;
  108. data->emplace_back(now, std::move(residency));
  109. return true;
  110. }
  111. void DumpResidency(size_t start,
  112. size_t end,
  113. std::unique_ptr<std::vector<TimestampAndResidency>> data) {
  114. LOG(WARNING) << "Dumping native library residency";
  115. auto path = base::FilePath(
  116. base::StringPrintf("/data/local/tmp/chrome/residency-%d.txt", getpid()));
  117. auto file =
  118. base::File(path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
  119. if (!file.IsValid()) {
  120. PLOG(ERROR) << "Cannot open file to dump the residency data "
  121. << path.value();
  122. return;
  123. }
  124. // First line: start-end of text range.
  125. CHECK(AreAnchorsSane());
  126. CHECK_LE(start, kStartOfText);
  127. CHECK_LE(kEndOfText, end);
  128. auto start_end = base::StringPrintf("%" PRIuS " %" PRIuS "\n",
  129. kStartOfText - start, kEndOfText - start);
  130. file.WriteAtCurrentPos(start_end.c_str(), static_cast<int>(start_end.size()));
  131. for (const auto& data_point : *data) {
  132. auto timestamp =
  133. base::StringPrintf("%" PRIu64 " ", data_point.timestamp_nanos);
  134. file.WriteAtCurrentPos(timestamp.c_str(),
  135. static_cast<int>(timestamp.size()));
  136. std::vector<char> dump;
  137. dump.reserve(data_point.residency.size() + 1);
  138. for (auto c : data_point.residency)
  139. dump.push_back(c ? '1' : '0');
  140. dump[dump.size() - 1] = '\n';
  141. file.WriteAtCurrentPos(&dump[0], checked_cast<int>(dump.size()));
  142. }
  143. }
  144. #if !BUILDFLAG(ORDERFILE_INSTRUMENTATION)
  145. // Reads a byte per page between |start| and |end| to force it into the page
  146. // cache.
  147. // Heap allocations, syscalls and library functions are not allowed in this
  148. // function.
  149. // Returns true for success.
  150. #if defined(ADDRESS_SANITIZER)
  151. // Disable AddressSanitizer instrumentation for this function. It is touching
  152. // memory that hasn't been allocated by the app, though the addresses are
  153. // valid. Furthermore, this takes place in a child process. See crbug.com/653372
  154. // for the context.
  155. __attribute__((no_sanitize_address))
  156. #endif
  157. void Prefetch(size_t start, size_t end) {
  158. unsigned char* start_ptr = reinterpret_cast<unsigned char*>(start);
  159. unsigned char* end_ptr = reinterpret_cast<unsigned char*>(end);
  160. [[maybe_unused]] unsigned char dummy = 0;
  161. for (unsigned char* ptr = start_ptr; ptr < end_ptr; ptr += kPageSize) {
  162. // Volatile is required to prevent the compiler from eliminating this
  163. // loop.
  164. dummy ^= *static_cast<volatile unsigned char*>(ptr);
  165. }
  166. }
  167. // These values were used in the past for recording
  168. // "LibraryLoader.PrefetchDetailedStatus".
  169. enum class PrefetchStatus {
  170. kSuccess = 0,
  171. kWrongOrdering = 1,
  172. kForkFailed = 2,
  173. kChildProcessCrashed = 3,
  174. kChildProcessKilled = 4,
  175. kMaxValue = kChildProcessKilled
  176. };
  177. PrefetchStatus ForkAndPrefetch(bool ordered_only) {
  178. if (!IsOrderingSane()) {
  179. LOG(WARNING) << "Incorrect code ordering";
  180. return PrefetchStatus::kWrongOrdering;
  181. }
  182. // Looking for ranges is done before the fork, to avoid syscalls and/or memory
  183. // allocations in the forked process. The child process inherits the lock
  184. // state of its parent thread. It cannot rely on being able to acquire any
  185. // lock (unless special care is taken in a pre-fork handler), including being
  186. // able to call malloc().
  187. //
  188. // Always prefetch the ordered section first, as it's reached early during
  189. // startup, and not necessarily located at the beginning of .text.
  190. std::vector<std::pair<size_t, size_t>> ranges = {GetOrderedTextRange()};
  191. if (!ordered_only)
  192. ranges.push_back(GetTextRange());
  193. pid_t pid = fork();
  194. if (pid == 0) {
  195. // Android defines the background priority to this value since at least 2009
  196. // (see Process.java).
  197. constexpr int kBackgroundPriority = 10;
  198. setpriority(PRIO_PROCESS, 0, kBackgroundPriority);
  199. // _exit() doesn't call the atexit() handlers.
  200. for (const auto& range : ranges) {
  201. Prefetch(range.first, range.second);
  202. }
  203. _exit(EXIT_SUCCESS);
  204. } else {
  205. if (pid < 0) {
  206. return PrefetchStatus::kForkFailed;
  207. }
  208. int status;
  209. const pid_t result = HANDLE_EINTR(waitpid(pid, &status, 0));
  210. if (result == pid) {
  211. if (WIFEXITED(status))
  212. return PrefetchStatus::kSuccess;
  213. if (WIFSIGNALED(status)) {
  214. int signal = WTERMSIG(status);
  215. switch (signal) {
  216. case SIGSEGV:
  217. case SIGBUS:
  218. return PrefetchStatus::kChildProcessCrashed;
  219. case SIGKILL:
  220. case SIGTERM:
  221. default:
  222. return PrefetchStatus::kChildProcessKilled;
  223. }
  224. }
  225. }
  226. // Should not happen. Per man waitpid(2), errors are:
  227. // - EINTR: handled.
  228. // - ECHILD if the process doesn't have an unwaited-for child with this PID.
  229. // - EINVAL.
  230. return PrefetchStatus::kChildProcessKilled;
  231. }
  232. }
  233. #endif // !BUILDFLAG(ORDERFILE_INSTRUMENTATION)
  234. } // namespace
  235. // static
  236. void NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary(bool ordered_only) {
  237. #if BUILDFLAG(ORDERFILE_INSTRUMENTATION)
  238. // Avoid forking with orderfile instrumentation because the child process
  239. // would create a dump as well.
  240. return;
  241. #else
  242. PrefetchStatus status = ForkAndPrefetch(ordered_only);
  243. if (status != PrefetchStatus::kSuccess) {
  244. LOG(WARNING) << "Cannot prefetch the library. status = "
  245. << static_cast<int>(status);
  246. }
  247. #endif // BUILDFLAG(ORDERFILE_INSTRUMENTATION)
  248. }
  249. // static
  250. int NativeLibraryPrefetcher::PercentageOfResidentCode(size_t start,
  251. size_t end) {
  252. size_t total_pages = 0;
  253. size_t resident_pages = 0;
  254. std::vector<unsigned char> residency;
  255. bool ok = Mincore(start, end, &residency);
  256. if (!ok)
  257. return -1;
  258. total_pages += residency.size();
  259. resident_pages +=
  260. static_cast<size_t>(std::count_if(residency.begin(), residency.end(),
  261. [](unsigned char x) { return x & 1; }));
  262. if (total_pages == 0)
  263. return -1;
  264. return static_cast<int>((100 * resident_pages) / total_pages);
  265. }
  266. // static
  267. int NativeLibraryPrefetcher::PercentageOfResidentNativeLibraryCode() {
  268. if (!AreAnchorsSane()) {
  269. LOG(WARNING) << "Incorrect code ordering";
  270. return -1;
  271. }
  272. const auto& range = GetTextRange();
  273. return PercentageOfResidentCode(range.first, range.second);
  274. }
  275. // static
  276. void NativeLibraryPrefetcher::PeriodicallyCollectResidency() {
  277. CHECK_EQ(static_cast<long>(kPageSize), sysconf(_SC_PAGESIZE));
  278. LOG(WARNING) << "Spawning thread to periodically collect residency";
  279. const auto& range = GetTextRange();
  280. auto data = std::make_unique<std::vector<TimestampAndResidency>>();
  281. // Collect residency for about minute (the actual time spent collecting
  282. // residency can vary, so this is only approximate).
  283. for (int i = 0; i < 120; ++i) {
  284. if (!CollectResidency(range.first, range.second, data.get()))
  285. return;
  286. usleep(5e5);
  287. }
  288. DumpResidency(range.first, range.second, std::move(data));
  289. }
  290. // static
  291. void NativeLibraryPrefetcher::MadviseForOrderfile() {
  292. if (!IsOrderingSane()) {
  293. LOG(WARNING) << "Code not ordered, madvise optimization skipped";
  294. return;
  295. }
  296. // First MADV_RANDOM on all of text, then turn the ordered text range back to
  297. // normal. The ordered range may be placed anywhere within .text.
  298. MadviseOnRange(GetTextRange(), MADV_RANDOM);
  299. MadviseOnRange(GetOrderedTextRange(), MADV_NORMAL);
  300. }
  301. // static
  302. void NativeLibraryPrefetcher::MadviseForResidencyCollection() {
  303. if (!AreAnchorsSane()) {
  304. LOG(WARNING) << "Code not ordered, cannot madvise";
  305. return;
  306. }
  307. LOG(WARNING) << "Performing madvise for residency collection";
  308. MadviseOnRange(GetTextRange(), MADV_RANDOM);
  309. }
  310. } // namespace android
  311. } // namespace base
  312. #endif // BUILDFLAG(SUPPORTS_CODE_ORDERING)