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