stack_buffer.cc 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. // Copyright 2019 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/profiler/stack_buffer.h"
  5. #include "base/bits.h"
  6. #if BUILDFLAG(IS_CHROMEOS)
  7. #include <sys/mman.h>
  8. #include <ostream>
  9. #include "base/check.h"
  10. #include "base/check_op.h"
  11. #include "base/memory/page_size.h"
  12. #endif // #if BUILDFLAG(IS_CHROMEOS)
  13. namespace base {
  14. constexpr size_t StackBuffer::kPlatformStackAlignment;
  15. #if BUILDFLAG(IS_CHROMEOS)
  16. void StackBuffer::MarkUpperBufferContentsAsUnneeded(size_t retained_bytes) {
  17. // Round up to the next multiple of the page size. madvise needs the
  18. // starting address to be page aligned. Since buffer_.get() is
  19. // already page aligned, we just need to round up the retained bytes.
  20. size_t actual_retained_bytes = bits::AlignUp(retained_bytes, GetPageSize());
  21. // Avoid passing a negative discard_size to madvise(). Doing so would randomly
  22. // discard large amounts of memory causing weird crashes.
  23. CHECK_LE(actual_retained_bytes, size_);
  24. uint8_t* start_of_discard =
  25. reinterpret_cast<uint8_t*>(buffer_.get()) + actual_retained_bytes;
  26. size_t discard_size = size_ - actual_retained_bytes;
  27. int result = madvise(start_of_discard, discard_size, MADV_DONTNEED);
  28. DPCHECK(result == 0) << "madvise failed: ";
  29. }
  30. #endif // #if BUILDFLAG(IS_CHROMEOS)
  31. StackBuffer::StackBuffer(size_t buffer_size)
  32. #if BUILDFLAG(IS_CHROMEOS)
  33. // On ChromeOS, we have 8MB of stack space per thread; however, we normally
  34. // only use a small fraction of that. To avoid blowing our memory budget,
  35. // we use madvise(MADV_DONTNEED) to let the kernel discard the memory in the
  36. // 8MB buffer except when we are actively using it. For madvise() to work,
  37. // we need |buffer_| to be aligned to a page boundary.
  38. //
  39. // We also need the |size_| to be a multiple of the page size so that we
  40. // don't pass partial pages to madvise(). This isn't documented but the
  41. // program will consistently crash otherwise.
  42. : size_(bits::AlignUp(buffer_size, GetPageSize())),
  43. buffer_(static_cast<uintptr_t*>(AlignedAlloc(size_, GetPageSize()))) {
  44. // Our (very large) buffer may already have data written to it & thus have
  45. // backing pages. Tell the kernel we don't need the current contents.
  46. MarkUpperBufferContentsAsUnneeded(0);
  47. }
  48. #else // #if BUILDFLAG(IS_CHROMEOS)
  49. : size_(buffer_size),
  50. buffer_(static_cast<uintptr_t*>(
  51. AlignedAlloc(size_, kPlatformStackAlignment))) {
  52. static_assert(bits::IsPowerOfTwo(kPlatformStackAlignment));
  53. }
  54. #endif // !#if BUILDFLAG(IS_CHROMEOS)
  55. StackBuffer::~StackBuffer() = default;
  56. } // namespace base