github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/memory_accounting.cc (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <sys/mman.h> 16 17 #include <map> 18 19 #include "gtest/gtest.h" 20 #include "absl/strings/match.h" 21 #include "absl/strings/numbers.h" 22 #include "absl/strings/str_format.h" 23 #include "absl/strings/str_split.h" 24 #include "test/util/fs_util.h" 25 #include "test/util/posix_error.h" 26 #include "test/util/test_util.h" 27 28 namespace gvisor { 29 namespace testing { 30 namespace { 31 32 using ::absl::StrFormat; 33 34 // AnonUsageFromMeminfo scrapes the current anonymous memory usage from 35 // /proc/meminfo and returns it in bytes. 36 PosixErrorOr<uint64_t> AnonUsageFromMeminfo() { 37 ASSIGN_OR_RETURN_ERRNO(auto meminfo, GetContents("/proc/meminfo")); 38 std::vector<std::string> lines(absl::StrSplit(meminfo, '\n')); 39 40 // Try to find AnonPages line, the format is AnonPages:\\s+(\\d+) kB\n. 41 for (const auto& line : lines) { 42 if (!absl::StartsWith(line, "AnonPages:")) { 43 continue; 44 } 45 46 std::vector<std::string> parts( 47 absl::StrSplit(line, ' ', absl::SkipEmpty())); 48 if (parts.size() == 3) { 49 // The size is the second field, let's try to parse it as a number. 50 ASSIGN_OR_RETURN_ERRNO(auto anon_kb, Atoi<uint64_t>(parts[1])); 51 return anon_kb * 1024; 52 } 53 54 return PosixError(EINVAL, "AnonPages field in /proc/meminfo was malformed"); 55 } 56 57 return PosixError(EINVAL, "AnonPages field not found in /proc/meminfo"); 58 } 59 60 TEST(MemoryAccounting, AnonAccountingPreservedOnSaveRestore) { 61 // This test isn't meaningful on Linux. /proc/meminfo reports system-wide 62 // memory usage, which can change arbitrarily in Linux from other activity on 63 // the machine. In gvisor, this test is the only thing running on the 64 // "machine", so values in /proc/meminfo accurately reflect the memory used by 65 // the test. 66 SKIP_IF(!IsRunningOnGvisor()); 67 68 uint64_t anon_initial = ASSERT_NO_ERRNO_AND_VALUE(AnonUsageFromMeminfo()); 69 70 // Cause some anonymous memory usage. 71 uint64_t map_bytes = Megabytes(512); 72 char* mem = 73 static_cast<char*>(mmap(nullptr, map_bytes, PROT_READ | PROT_WRITE, 74 MAP_POPULATE | MAP_ANON | MAP_PRIVATE, -1, 0)); 75 ASSERT_NE(mem, MAP_FAILED) 76 << "Map failed, errno: " << errno << " (" << strerror(errno) << ")."; 77 78 // Write something to each page to prevent them from being decommited on 79 // S/R. Zero pages are dropped on save. 80 for (uint64_t i = 0; i < map_bytes; i += kPageSize) { 81 mem[i] = 'a'; 82 } 83 84 uint64_t anon_after_alloc = ASSERT_NO_ERRNO_AND_VALUE(AnonUsageFromMeminfo()); 85 EXPECT_THAT(anon_after_alloc, 86 EquivalentWithin(anon_initial + map_bytes, 0.04)); 87 88 // We have many implicit S/R cycles from scraping /proc/meminfo throughout the 89 // test, but throw an explicit S/R in here as well. 90 MaybeSave(); 91 92 // Usage should remain the same across S/R. 93 uint64_t anon_after_sr = ASSERT_NO_ERRNO_AND_VALUE(AnonUsageFromMeminfo()); 94 EXPECT_THAT(anon_after_sr, EquivalentWithin(anon_after_alloc, 0.04)); 95 } 96 97 } // namespace 98 } // namespace testing 99 } // namespace gvisor