encapsulate and instrument

This commit is contained in:
Valentin Balaschenko
2025-11-11 15:19:50 +00:00
parent ac5554e9f5
commit 3fdd42af63
3 changed files with 139 additions and 7 deletions

View File

@@ -0,0 +1,42 @@
#ifndef XRPL_BASICS_MALLOCTRIM_H_INCLUDED
#define XRPL_BASICS_MALLOCTRIM_H_INCLUDED
#include <xrpl/beast/utility/Journal.h>
#include <optional>
#include <string>
namespace ripple {
struct MallocTrimReport
{
bool supported{false};
int trimResult{-1};
long rssBeforeKB{-1};
long rssAfterKB{-1};
long
deltaKB() const
{
return rssAfterKB - rssBeforeKB;
}
};
/** Attempt to return freed memory to the operating system.
*
* This function is only effective on Linux with glibc. On other platforms,
* it returns a report indicating the operation is unsupported.
*
* @param tag Optional identifier for logging/debugging purposes
* @param journal Journal for logging diagnostic information
* @return Report containing before/after memory metrics
*
* @note This is intended for use after cache sweeps or other operations
* that free significant amounts of memory.
*/
MallocTrimReport
mallocTrim(std::optional<std::string> const& tag, beast::Journal journal);
} // namespace ripple
#endif

View File

@@ -2,12 +2,9 @@
#define XRPL_BASICS_TAGGEDCACHE_IPP_INCLUDED
#include <xrpl/basics/IntrusivePointer.ipp>
#include <xrpl/basics/MallocTrim.h>
#include <xrpl/basics/TaggedCache.h>
#ifdef __GLIBC__
#include <malloc.h>
#endif
namespace ripple {
template <
@@ -331,9 +328,7 @@ TaggedCache<
.count()
<< "ms";
#ifdef __GLIBC__
(void)malloc_trim(0);
#endif
mallocTrim(std::optional<std::string>(m_name), m_journal);
}
template <

View File

@@ -0,0 +1,95 @@
#include <xrpl/basics/Log.h>
#include <xrpl/basics/MallocTrim.h>
#include <boost/predef.h>
#include <cstdio>
#include <fstream>
#if defined(__GLIBC__) && BOOST_OS_LINUX
#include <malloc.h>
#include <unistd.h>
#endif
namespace ripple {
namespace detail {
#if defined(__GLIBC__) && BOOST_OS_LINUX
std::string
readFile(std::string const& path)
{
std::ifstream ifs(path);
if (!ifs.is_open())
return {};
return std::string(
std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
}
long
parseVmRSSkB(std::string const& status)
{
// "VmRSS: 123456 kB"
auto pos = status.find("VmRSS:");
if (pos == std::string::npos)
return -1;
pos += 6; // past "VmRSS:"
while (pos < status.size() && status[pos] == ' ')
++pos;
long value = -1;
std::sscanf(status.c_str() + pos, "%ld", &value);
return value; // in kB
}
#endif // __GLIBC__ && BOOST_OS_LINUX
} // namespace detail
MallocTrimReport
mallocTrim(
[[maybe_unused]] std::optional<std::string> const& tag,
beast::Journal journal)
{
MallocTrimReport report;
#if !(defined(__GLIBC__) && BOOST_OS_LINUX)
JLOG(journal.debug()) << "malloc_trim not supported on this platform";
return report;
#else
report.supported = true;
if (journal.debug())
{
std::string const tagStr = tag.value_or("default");
pid_t const pid = ::getpid();
std::string const statusPath =
"/proc/" + std::to_string(pid) + "/status";
auto const statusBefore = detail::readFile(statusPath);
report.rssBeforeKB = detail::parseVmRSSkB(statusBefore);
report.trimResult = ::malloc_trim(0);
auto const statusAfter = detail::readFile(statusPath);
report.rssAfterKB = detail::parseVmRSSkB(statusAfter);
JLOG(journal.debug())
<< "malloc_trim tag=" << tagStr << " result=" << report.trimResult
<< " rss_before=" << report.rssBeforeKB << "kB"
<< " rss_after=" << report.rssAfterKB << "kB"
<< " delta=" << report.deltaKB() << "kB";
}
else
{
report.trimResult = ::malloc_trim(0);
}
return report;
#endif
}
} // namespace ripple