Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 9 additions & 15 deletions include/bitcoin/database/memory/utilities.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ BCD_API size_t page_size() NOEXCEPT;
/// The bytes of physical memory, zero if failed.
BCD_API uint64_t system_memory() NOEXCEPT;

/// Head buckets from expected elements and installed memory, scaled linearly
/// between the contested and uncontested load factors (in tenths). Hashmaps
/// only; zero expected is not derived.
BCD_API uint32_t derive_buckets(uint64_t expected, uint32_t low,
uint32_t high) NOEXCEPT;

/// The bytes of unused physical memory, zero if failed. Scarcity precedes
/// pressure: clean file cache is reclaimable, so the pressure level does not
/// raise while free memory exhausts.
Expand All @@ -51,10 +57,12 @@ BCD_API size_t system_pressure() NOEXCEPT;
/// if failed or the platform provides no source.
BCD_API uint64_t system_compressed() NOEXCEPT;

// TODO: move all below to release.hpp, remove compound ternaries, delint.

/// Head-release page-run helpers (pure, unit tested). Pages are tracked as
/// bits in 64-bit words (low order bit is the lowest page of the word). A
/// release candidate page is clean (not dirty), cold (not recently written)
/// and not already released; candidacy is limited to full pages below the
/// and not already released. Candidacy is limited to full pages below the
/// logical page count.
/// ---------------------------------------------------------------------------

Expand Down Expand Up @@ -134,20 +142,6 @@ inline std::pair<size_t, size_t> bit_run(const uint64_t* words, size_t pages,
return { start, end };
}

/// C++26: std::atomic<size_t>::fetch_max
template <typename Integral, if_integral_integer<Integral> = true>
Integral fetch_max(std::atomic<Integral>& atomic, Integral value) NOEXCEPT
{
constexpr auto relaxed = std::memory_order_relaxed;

auto atom = atomic.load(relaxed);
while (value > atom && !atomic.compare_exchange_weak(atom, value, relaxed))
{
}

return atom;
}

} // namespace database
} // namespace libbitcoin

Expand Down
51 changes: 40 additions & 11 deletions src/memory/utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,16 @@
namespace libbitcoin {
namespace database {

using namespace system;

#if defined(HAVE_MSC)

size_t page_size() NOEXCEPT
{
using namespace system;
SYSTEM_INFO info{};
::GetSystemInfo(&info);

BC_ASSERT(!system::is_limited<size_t>(info.dwPageSize));
BC_ASSERT(!is_limited<size_t>(info.dwPageSize));
return info.dwPageSize;
}

Expand Down Expand Up @@ -94,12 +95,11 @@ uint64_t system_compressed() NOEXCEPT
return zero;
}

#else
#else // HAVE_MSC

size_t page_size() NOEXCEPT
{
errno = 0;
using namespace system;
const auto size = sysconf(_SC_PAGESIZE);
if (is_zero(errno) && !is_negative(size))
{
Expand All @@ -113,7 +113,6 @@ size_t page_size() NOEXCEPT
uint64_t system_memory() NOEXCEPT
{
errno = 0;
using namespace system;
const int64_t pages = sysconf(_SC_PHYS_PAGES);
if (is_zero(errno) && !is_negative(pages))
{
Expand All @@ -128,7 +127,6 @@ uint64_t system_memory() NOEXCEPT
uint64_t system_free() NOEXCEPT
{
#if defined(HAVE_APPLE)
using namespace system;
auto count = HOST_VM_INFO64_COUNT;
vm_statistics64_data_t statistics{};
if (::host_statistics64(::mach_host_self(), HOST_VM_INFO64,
Expand All @@ -138,7 +136,6 @@ uint64_t system_free() NOEXCEPT
}
#else
errno = 0;
using namespace system;
const int64_t pages = sysconf(_SC_AVPHYS_PAGES);
if (is_zero(errno) && !is_negative(pages))
{
Expand All @@ -157,7 +154,6 @@ uint64_t system_available() NOEXCEPT
#if defined(HAVE_APPLE)
// Free plus purgeable plus file-backed (external) pages are available to
// allocation without compression or swap.
using namespace system;
auto count = HOST_VM_INFO64_COUNT;
vm_statistics64_data_t statistics{};
if (::host_statistics64(::mach_host_self(), HOST_VM_INFO64,
Expand All @@ -180,7 +176,7 @@ uint64_t system_available() NOEXCEPT
&kilobytes) == 1)
{
std::fclose(file);
return system::ceilinged_multiply<uint64_t>(kilobytes, 1024u);
return ceilinged_multiply<uint64_t>(kilobytes, 1024u);
}
}

Expand All @@ -200,7 +196,7 @@ size_t system_pressure() NOEXCEPT
if (is_zero(::sysctlbyname("kern.memorystatus_vm_pressure_level", &level,
&size, nullptr, 0)))
{
return system::possible_narrow_sign_cast<size_t>(level);
return possible_narrow_sign_cast<size_t>(level);
}
#elif defined(HAVE_LINUX)
// PSI (requires CONFIG_PSI): fraction of recent wall time that tasks
Expand Down Expand Up @@ -235,7 +231,6 @@ size_t system_pressure() NOEXCEPT
uint64_t system_compressed() NOEXCEPT
{
#if defined(HAVE_APPLE)
using namespace system;
auto count = HOST_VM_INFO64_COUNT;
vm_statistics64_data_t statistics{};
if (::host_statistics64(::mach_host_self(), HOST_VM_INFO64,
Expand All @@ -251,7 +246,41 @@ uint64_t system_compressed() NOEXCEPT
return zero;
}

#endif // HAVE_MSC

constexpr auto gigabyte = power2<uint64_t>(30u);
constexpr auto megabyte = power2<uint64_t>(20u);
constexpr auto uncontested = power2<uint64_t>(35u);

#if defined(HAVE_APPLE)
constexpr auto contested = 10u * gigabyte;
#else
constexpr auto contested = 8u * gigabyte;
#endif

uint32_t derive_buckets(uint64_t expected, uint32_t low,
uint32_t high) NOEXCEPT
{
if (is_zero(expected) || is_zero(low) || is_zero(high))
return {};

const auto scaled = ceilinged_multiply<uint64_t>(expected, 10);
const auto floored = scaled / low;
const auto ceiled = scaled / high;
const auto memory = system_memory();

if (memory <= contested)
return possible_narrow_cast<uint32_t>(floored);

if (memory >= uncontested)
return possible_narrow_cast<uint32_t>(ceiled);

// Megabytes, as the byte product overflows the word.
const auto over = (memory - contested) / megabyte;
const auto rise = floored_subtract(ceiled, floored);
constexpr auto span = (uncontested - contested) / megabyte;
return limit<uint32_t>(floored + (ceilinged_multiply(rise, over) / span));
}

} // namespace database
} // namespace libbitcoin
Loading