xrpld
Loading...
Searching...
No Matches
libxrpl/basics/MallocTrim.cpp
1#include <xrpl/basics/MallocTrim.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/beast/utility/Journal.h>
5
6#include <boost/predef.h>
7
8#include <string_view>
9
10#if defined(__GLIBC__) && BOOST_OS_LINUX
11#include <sys/resource.h>
12
13#include <malloc.h>
14#include <unistd.h>
15
16#include <chrono>
17#include <cstddef>
18#include <cstdint>
19#include <fstream>
20#include <ios>
21#include <sstream>
22#include <string>
23
24// Require RUSAGE_THREAD for thread-scoped page fault tracking
25#ifndef RUSAGE_THREAD
26#error "MallocTrim rusage instrumentation requires RUSAGE_THREAD on Linux/glibc"
27#endif
28
29namespace {
30
31bool
32getRusageThread(struct rusage& ru)
33{
34 return ::getrusage(RUSAGE_THREAD, &ru) == 0; // LCOV_EXCL_LINE
35}
36
37} // namespace
38#endif
39
40namespace xrpl {
41
42namespace detail {
43
44// cSpell:ignore statm
45
46#if defined(__GLIBC__) && BOOST_OS_LINUX
47
48inline int
49mallocTrimWithPad(std::size_t padBytes)
50{
51 return ::malloc_trim(padBytes);
52}
53
54long
55parseStatmRSSkB(std::string const& statm)
56{
57 // /proc/self/statm format: size resident shared text lib data dt
58 // We want the second field (resident) which is in pages
59 std::istringstream iss(statm);
60 long size = 0, resident = 0;
61 if (!(iss >> size >> resident))
62 return -1;
63
64 // Convert pages to KB
65 long const pageSize = ::sysconf(_SC_PAGESIZE);
66 if (pageSize <= 0)
67 return -1;
68
69 return (resident * pageSize) / 1024;
70}
71
72#endif // __GLIBC__ && BOOST_OS_LINUX
73
74} // namespace detail
75
78{
79 // LCOV_EXCL_START
80
81 MallocTrimReport report;
82
83#if !(defined(__GLIBC__) && BOOST_OS_LINUX)
84 JLOG(journal.debug()) << "malloc_trim not supported on this platform (tag=" << tag << ")";
85#else
86 // Keep glibc malloc_trim padding at 0 (default): 12h Mainnet tests across 0/256KB/1MB/16MB
87 // showed no clear, consistent benefit from custom padding—0 provided the best overall balance
88 // of RSS reduction and trim-latency stability without adding a tuning surface.
89 static constexpr std::size_t kTrimPad = 0;
90
91 report.supported = true;
92
93 if (journal.debug())
94 {
95 auto readFile = [](std::string const& path) -> std::string {
96 std::ifstream ifs(path, std::ios::in | std::ios::binary);
97 if (!ifs.is_open())
98 return {};
99
100 // /proc files are often not seekable; read as a stream.
102 oss << ifs.rdbuf();
103 return oss.str();
104 };
105
106 std::string const tagStr{tag};
107 std::string const statmPath = "/proc/self/statm";
108
109 auto const statmBefore = readFile(statmPath);
110 long const rssBeforeKB = detail::parseStatmRSSkB(statmBefore);
111
112 struct rusage ru0{};
113 bool const haveRu0 = getRusageThread(ru0);
114
115 auto const t0 = std::chrono::steady_clock::now();
116
117 report.trimResult = detail::mallocTrimWithPad(kTrimPad);
118
119 auto const t1 = std::chrono::steady_clock::now();
120
121 struct rusage ru1{};
122 bool const haveRu1 = getRusageThread(ru1);
123
124 auto const statmAfter = readFile(statmPath);
125 long const rssAfterKB = detail::parseStatmRSSkB(statmAfter);
126
127 // Populate report fields
128 report.rssBeforeKB = rssBeforeKB;
129 report.rssAfterKB = rssAfterKB;
131
132 if (haveRu0 && haveRu1)
133 {
134 report.minfltDelta = ru1.ru_minflt - ru0.ru_minflt;
135 report.majfltDelta = ru1.ru_majflt - ru0.ru_majflt;
136 }
137
138 std::int64_t const deltaKB = (rssBeforeKB < 0 || rssAfterKB < 0)
139 ? 0
140 : (static_cast<std::int64_t>(rssAfterKB) - static_cast<std::int64_t>(rssBeforeKB));
141
142 JLOG(journal.debug()) << "malloc_trim tag=" << tagStr << " result=" << report.trimResult
143 << " pad=" << kTrimPad << " bytes"
144 << " rss_before=" << rssBeforeKB << "kB"
145 << " rss_after=" << rssAfterKB << "kB"
146 << " delta=" << deltaKB << "kB"
147 << " duration_us=" << report.durationUs.count()
148 << " minflt_delta=" << report.minfltDelta
149 << " majflt_delta=" << report.majfltDelta;
150 }
151 else
152 {
153 report.trimResult = detail::mallocTrimWithPad(kTrimPad);
154 }
155
156#endif
157
158 return report;
159
160 // LCOV_EXCL_STOP
161}
162
163} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
Stream debug() const
Definition Journal.h:297
T duration_cast(T... args)
T is_open(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
MallocTrimReport mallocTrim(std::string_view tag, beast::Journal journal)
Attempt to return freed memory to the operating system.
T rdbuf(T... args)
T size(T... args)
T str(T... args)
std::int64_t majfltDelta
Definition MallocTrim.h:35
std::int64_t minfltDelta
Definition MallocTrim.h:34
std::chrono::microseconds durationUs
Definition MallocTrim.h:33
std::int64_t rssAfterKB
Definition MallocTrim.h:32
std::int64_t rssBeforeKB
Definition MallocTrim.h:31