1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/profiler/stack_buffer.h"
6
7 #include "base/memory/aligned_memory.h"
8 #include "build/build_config.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10
11 #if BUILDFLAG(IS_CHROMEOS)
12 #include "base/bits.h"
13 #include "base/memory/page_size.h"
14 #endif // #if BUILDFLAG(IS_CHROMEOS)
15
16 namespace base {
17
TEST(StackBufferTest,BufferAllocated)18 TEST(StackBufferTest, BufferAllocated) {
19 const unsigned int kBufferSize = 32 * 1024;
20 StackBuffer stack_buffer(kBufferSize);
21 EXPECT_EQ(stack_buffer.size(), kBufferSize);
22 // Without volatile, the compiler could simply optimize away the entire for
23 // loop below.
24 volatile uintptr_t* buffer = stack_buffer.buffer();
25 ASSERT_NE(nullptr, buffer);
26 EXPECT_TRUE(IsAligned(const_cast<uintptr_t*>(buffer),
27 StackBuffer::kPlatformStackAlignment));
28
29 // Memory pointed to by buffer should be writable.
30 for (unsigned int i = 0; i < (kBufferSize / sizeof(buffer[0])); i++) {
31 buffer[i] = i;
32 EXPECT_EQ(buffer[i], i);
33 }
34 }
35
36 #if BUILDFLAG(IS_CHROMEOS)
TEST(StackBufferTest,MarkBufferContentsAsUnneeded)37 TEST(StackBufferTest, MarkBufferContentsAsUnneeded) {
38 const unsigned int kBufferSize = 32 * GetPageSize();
39 StackBuffer stack_buffer(kBufferSize);
40 volatile uintptr_t* buffer = stack_buffer.buffer();
41 ASSERT_NE(nullptr, buffer);
42
43 // Force the kernel to allocate backing store for the buffer.
44 for (unsigned int i = 0; i < (kBufferSize / sizeof(uintptr_t)); i++) {
45 buffer[i] = i;
46 EXPECT_EQ(buffer[i], i);
47 }
48
49 // Tell kernel to discard (most of) the memory.
50 constexpr size_t kUndiscardedElements = 100;
51 stack_buffer.MarkUpperBufferContentsAsUnneeded(kUndiscardedElements *
52 sizeof(buffer[0]));
53
54 // The first 100 elements shouldn't have been discarded.
55 for (size_t i = 0; i < kUndiscardedElements; i++) {
56 EXPECT_EQ(buffer[i], i);
57 }
58
59 // Pages past the discard point should be zero-filled now.
60 const size_t kExpectedDiscardStartPoint =
61 bits::AlignUp(kUndiscardedElements * sizeof(buffer[0]), GetPageSize()) /
62 sizeof(buffer[0]);
63 for (size_t i = kExpectedDiscardStartPoint;
64 i < kBufferSize / sizeof(buffer[0]); i++) {
65 EXPECT_EQ(buffer[i], 0U);
66 }
67
68 // Writing to the memory (both discarded and undiscarded parts) shouldn't
69 // cause segmentation faults and should remember the value we write.
70 for (unsigned int i = 0; i < (kBufferSize / sizeof(buffer[0])); i++) {
71 buffer[i] = i + 7;
72 EXPECT_EQ(buffer[i], i + 7);
73 }
74 }
75 #endif // #if BUILDFLAG(IS_CHROMEOS)
76
77 } // namespace base
78