Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/llfio.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2021-09-08 17:58:28 +0300
committerNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2021-09-08 17:58:28 +0300
commitafbac282eda46b9d6cc6b8ab9a959fcdbe1ef606 (patch)
treed076bad1000c286dc65ad727c9cda7bbebf46ab9
parentbcc600db9feb6aa50e0880422a071d0e39ae74aa (diff)
current_process_memory_usage: Add system memory stats.
-rw-r--r--include/llfio/revision.hpp6
-rw-r--r--include/llfio/v2.0/detail/impl/posix/utils.ipp340
-rw-r--r--include/llfio/v2.0/detail/impl/windows/import.hpp28
-rw-r--r--include/llfio/v2.0/detail/impl/windows/utils.ipp61
-rw-r--r--include/llfio/v2.0/utils.hpp24
-rw-r--r--test/tests/utils.cpp93
6 files changed, 339 insertions, 213 deletions
diff --git a/include/llfio/revision.hpp b/include/llfio/revision.hpp
index 08851c80..d7f4cf22 100644
--- a/include/llfio/revision.hpp
+++ b/include/llfio/revision.hpp
@@ -1,4 +1,4 @@
// Note the second line of this file must ALWAYS be the git SHA, third line ALWAYS the git SHA update time
-#define LLFIO_PREVIOUS_COMMIT_REF 8cec4ff8fcd601b774c0ed882fe869e73d23d136
-#define LLFIO_PREVIOUS_COMMIT_DATE "2021-08-30 14:53:35 +00:00"
-#define LLFIO_PREVIOUS_COMMIT_UNIQUE 8cec4ff8
+#define LLFIO_PREVIOUS_COMMIT_REF bcc600db9feb6aa50e0880422a071d0e39ae74aa
+#define LLFIO_PREVIOUS_COMMIT_DATE "2021-08-30 15:08:05 +00:00"
+#define LLFIO_PREVIOUS_COMMIT_UNIQUE bcc600db
diff --git a/include/llfio/v2.0/detail/impl/posix/utils.ipp b/include/llfio/v2.0/detail/impl/posix/utils.ipp
index 15fe1a5a..ccd634e1 100644
--- a/include/llfio/v2.0/detail/impl/posix/utils.ipp
+++ b/include/llfio/v2.0/detail/impl/posix/utils.ipp
@@ -341,156 +341,187 @@ namespace utils
private_paged_in = ??? MISSING
*/
- if(!(want & process_memory_usage::want::private_committed) || (want & process_memory_usage::want::private_committed_inaccurate))
+ process_memory_usage ret;
+ if(!!(want & process_memory_usage::want::this_process))
{
- process_memory_usage ret;
- if((want & process_memory_usage::want::total_address_space_in_use) || (want & process_memory_usage::want::total_address_space_paged_in) ||
- (want & process_memory_usage::want::private_paged_in))
- {
- std::vector<char> buffer(256);
- OUTCOME_TRY(fill_buffer(buffer, "/proc/self/statm"));
- if(buffer.size() > 1)
- {
- size_t file_and_shared_pages_paged_in = 0;
- sscanf(buffer.data(), "%zu %zu %zu", &ret.total_address_space_in_use, &ret.total_address_space_paged_in, &file_and_shared_pages_paged_in);
- ret.private_paged_in = ret.total_address_space_paged_in - file_and_shared_pages_paged_in;
- ret.total_address_space_in_use *= page_size();
- ret.total_address_space_paged_in *= page_size();
- ret.private_paged_in *= page_size();
- //std::cout << string_view(buffer.data(), buffer.size()) << std::endl;
- }
- }
- if(want & process_memory_usage::want::private_committed)
+ if(!(want & process_memory_usage::want::private_committed) || (want & process_memory_usage::want::private_committed_inaccurate))
{
- std::vector<char> smaps_rollup(256), maps(65536);
- auto r = fill_buffer(smaps_rollup, "/proc/self/smaps_rollup");
- if(!r)
+ if((want & process_memory_usage::want::total_address_space_in_use) || (want & process_memory_usage::want::total_address_space_paged_in) ||
+ (want & process_memory_usage::want::private_paged_in))
{
- if(r.error() == errc::no_such_file_or_directory)
+ std::vector<char> buffer(256);
+ OUTCOME_TRY(fill_buffer(buffer, "/proc/self/statm"));
+ if(buffer.size() > 1)
{
- // Linux kernel is too old
- return errc::operation_not_supported;
+ size_t file_and_shared_pages_paged_in = 0;
+ sscanf(buffer.data(), "%zu %zu %zu", &ret.total_address_space_in_use, &ret.total_address_space_paged_in, &file_and_shared_pages_paged_in);
+ ret.private_paged_in = ret.total_address_space_paged_in - file_and_shared_pages_paged_in;
+ ret.total_address_space_in_use *= page_size();
+ ret.total_address_space_paged_in *= page_size();
+ ret.private_paged_in *= page_size();
+ // std::cout << string_view(buffer.data(), buffer.size()) << std::endl;
}
- return std::move(r).error();
}
- OUTCOME_TRY(fill_buffer(maps, "/proc/self/maps"));
- uint64_t lazyfree = 0;
+ if(want & process_memory_usage::want::private_committed)
{
- string_view i(smaps_rollup.data(), smaps_rollup.size());
- OUTCOME_TRY(lazyfree, parse(i, "\nLazyFree:"));
+ std::vector<char> smaps_rollup(256), maps(65536);
+ auto r = fill_buffer(smaps_rollup, "/proc/self/smaps_rollup");
+ if(!r)
+ {
+ if(r.error() == errc::no_such_file_or_directory)
+ {
+ // Linux kernel is too old
+ return errc::operation_not_supported;
+ }
+ return std::move(r).error();
+ }
+ OUTCOME_TRY(fill_buffer(maps, "/proc/self/maps"));
+ uint64_t lazyfree = 0;
+ {
+ string_view i(smaps_rollup.data(), smaps_rollup.size());
+ OUTCOME_TRY(lazyfree, parse(i, "\nLazyFree:"));
+ }
+ string_view i(maps.data(), maps.size());
+ size_t anonymous = 0;
+ for(size_t idx = 0;;)
+ {
+ idx = i.find("\n", idx);
+ if(idx == i.npos)
+ {
+ break;
+ }
+ idx++;
+ size_t start = 0, end = 0, inode = 1;
+ char read = 0, write = 0, executable = 0, private_ = 0;
+ sscanf(i.data() + idx, "%zx-%zx %c%c%c%c %*u %*u:%*u %zd", &start, &end, &read, &write, &executable, &private_, &inode);
+ if(inode == 0 && read == 'r' && write == 'w' && executable == '-' && private_ == 'p')
+ {
+ anonymous += end - start;
+ // std::cout << (end - start) << " " << i.substr(idx, 40) << std::endl;
+ }
+ }
+ if(lazyfree != (uint64_t) -1)
+ {
+ anonymous -= (size_t) lazyfree;
+ }
+ ret.private_committed = anonymous;
}
- string_view i(maps.data(), maps.size());
- size_t anonymous = 0;
- for(size_t idx = 0;;)
+ }
+ else
+ {
+ std::vector<char> buffer(1024 * 1024);
+ OUTCOME_TRY(fill_buffer(buffer, "/proc/self/smaps"));
+ const string_view totalview(buffer.data(), buffer.size());
+ // std::cerr << totalview << std::endl;
+ std::vector<string_view> anon_entries, non_anon_entries;
+ anon_entries.reserve(32);
+ non_anon_entries.reserve(32);
+ auto find_item = [&](size_t idx) -> string_view {
+ auto x = totalview.rfind("\nSize:", idx);
+ if(x == string_view::npos)
+ {
+ return {};
+ }
+ x = totalview.rfind("\n", x - 1);
+ if(x == string_view::npos)
+ {
+ x = 0;
+ }
+ else
+ {
+ x++;
+ }
+ return totalview.substr(x, idx - x);
+ };
+ for(string_view item = find_item(totalview.size()); item != string_view(); item = find_item(item.data() - totalview.data()))
{
- idx = i.find("\n", idx);
- if(idx == i.npos)
+ // std::cout << "***" << item << "***";
+ // hexaddr-hexaddr flags offset dev:id inode [path]
+ size_t inode = 1;
+ sscanf(item.data(), "%*x-%*x %*c%*c%*c%*c %*x %*c%*c:%*c%*c %zu", &inode);
+ auto vmflagsidx = item.rfind("\nVmFlags:");
+ if(vmflagsidx == string_view::npos)
{
- break;
+ return errc::illegal_byte_sequence;
+ }
+ // Is there " ac" after vmflagsidx?
+ if(string_view::npos != item.find(" ac", vmflagsidx) && inode == 0)
+ {
+ // std::cerr << "Adding anon entry at offset " << itemtopidx << std::endl;
+ anon_entries.push_back(item);
}
- idx++;
- size_t start = 0, end = 0, inode = 1;
- char read = 0, write = 0, executable = 0, private_ = 0;
- sscanf(i.data() + idx, "%zx-%zx %c%c%c%c %*u %*u:%*u %zd", &start, &end, &read, &write, &executable, &private_, &inode);
- if(inode == 0 && read == 'r' && write == 'w' && executable == '-' && private_ == 'p')
+ else
{
- anonymous += end - start;
- // std::cout << (end - start) << " " << i.substr(idx, 40) << std::endl;
+ // std::cerr << "Adding non-anon entry at offset " << itemtopidx << std::endl;
+ non_anon_entries.push_back(item);
}
}
- if(lazyfree != (uint64_t) -1)
+ // std::cerr << "Anon entries:";
+ for(auto &i : anon_entries)
{
- anonymous -= (size_t) lazyfree;
+ OUTCOME_TRY(auto &&size, parse(i, "\nSize:"));
+ OUTCOME_TRY(auto &&rss, parse(i, "\nRss:"));
+ OUTCOME_TRY(auto &&anonymous, parse(i, "\nAnonymous:"));
+ OUTCOME_TRY(auto &&lazyfree, parse(i, "\nLazyFree:"));
+ if(size != (uint64_t) -1 && rss != (uint64_t) -1 && anonymous != (uint64_t) -1)
+ {
+ ret.total_address_space_in_use += size;
+ ret.total_address_space_paged_in += rss;
+ ret.private_committed += anonymous;
+ if(lazyfree != (uint64_t) -1)
+ {
+ ret.total_address_space_paged_in -= lazyfree;
+ ret.private_committed -= lazyfree;
+ }
+ ret.private_paged_in += rss;
+ }
+ // std::cerr << i << "\nSize = " << size << " Rss = " << rss << std::endl;
}
- ret.private_committed = anonymous;
- }
- return ret;
- }
- std::vector<char> buffer(1024 * 1024);
- OUTCOME_TRY(fill_buffer(buffer, "/proc/self/smaps"));
- const string_view totalview(buffer.data(), buffer.size());
- // std::cerr << totalview << std::endl;
- std::vector<string_view> anon_entries, non_anon_entries;
- anon_entries.reserve(32);
- non_anon_entries.reserve(32);
- auto find_item = [&](size_t idx) -> string_view {
- auto x = totalview.rfind("\nSize:", idx);
- if(x == string_view::npos)
- {
- return {};
- }
- x = totalview.rfind("\n", x - 1);
- if(x == string_view::npos)
- {
- x = 0;
- }
- else
- {
- x++;
- }
- return totalview.substr(x, idx - x);
- };
- for(string_view item = find_item(totalview.size()); item != string_view(); item = find_item(item.data() - totalview.data()))
- {
- // std::cout << "***" << item << "***";
- // hexaddr-hexaddr flags offset dev:id inode [path]
- size_t inode = 1;
- sscanf(item.data(), "%*x-%*x %*c%*c%*c%*c %*x %*c%*c:%*c%*c %zu", &inode);
- auto vmflagsidx = item.rfind("\nVmFlags:");
- if(vmflagsidx == string_view::npos)
- {
- return errc::illegal_byte_sequence;
- }
- // Is there " ac" after vmflagsidx?
- if(string_view::npos != item.find(" ac", vmflagsidx) && inode == 0)
- {
- // std::cerr << "Adding anon entry at offset " << itemtopidx << std::endl;
- anon_entries.push_back(item);
- }
- else
- {
- // std::cerr << "Adding non-anon entry at offset " << itemtopidx << std::endl;
- non_anon_entries.push_back(item);
- }
- }
- process_memory_usage ret;
- // std::cerr << "Anon entries:";
- for(auto &i : anon_entries)
- {
- OUTCOME_TRY(auto &&size, parse(i, "\nSize:"));
- OUTCOME_TRY(auto &&rss, parse(i, "\nRss:"));
- OUTCOME_TRY(auto &&anonymous, parse(i, "\nAnonymous:"));
- OUTCOME_TRY(auto &&lazyfree, parse(i, "\nLazyFree:"));
- if(size != (uint64_t) -1 && rss != (uint64_t) -1 && anonymous != (uint64_t) -1)
- {
- ret.total_address_space_in_use += size;
- ret.total_address_space_paged_in += rss;
- ret.private_committed += anonymous;
- if(lazyfree != (uint64_t) -1)
+ // std::cerr << "\n\nNon-anon entries:";
+ for(auto &i : non_anon_entries)
{
- ret.total_address_space_paged_in -= lazyfree;
- ret.private_committed -= lazyfree;
+ OUTCOME_TRY(auto &&size, parse(i, "\nSize:"));
+ OUTCOME_TRY(auto &&rss, parse(i, "\nRss:"));
+ OUTCOME_TRY(auto &&lazyfree, parse(i, "\nLazyFree:"));
+ if(size != (uint64_t) -1 && rss != (uint64_t) -1)
+ {
+ ret.total_address_space_in_use += size;
+ ret.total_address_space_paged_in += rss;
+ if(lazyfree != (uint64_t) -1)
+ {
+ ret.total_address_space_in_use -= lazyfree;
+ }
+ }
+ // std::cerr << i << "\nSize = " << size << " Rss = " << rss << std::endl;
}
- ret.private_paged_in += rss;
}
- // std::cerr << i << "\nSize = " << size << " Rss = " << rss << std::endl;
}
- // std::cerr << "\n\nNon-anon entries:";
- for(auto &i : non_anon_entries)
+ if(!!(want & process_memory_usage::want::this_system))
{
- OUTCOME_TRY(auto &&size, parse(i, "\nSize:"));
- OUTCOME_TRY(auto &&rss, parse(i, "\nRss:"));
- OUTCOME_TRY(auto &&lazyfree, parse(i, "\nLazyFree:"));
- if(size != (uint64_t) -1 && rss != (uint64_t) -1)
+ std::vector<char> buffer(1024);
+ OUTCOME_TRY(fill_buffer(buffer, "/proc/meminfo"));
+ if(buffer.size() > 1)
{
- ret.total_address_space_in_use += size;
- ret.total_address_space_paged_in += rss;
- if(lazyfree != (uint64_t) -1)
+ string_view i(buffer.data(), buffer.size());
+ OUTCOME_TRY(ret.system_physical_memory_total, parse(i, "MemTotal:"));
+ OUTCOME_TRY(ret.system_physical_memory_available, parse(i, "\nMemAvailable:"));
+ if((uint64_t) -1 == ret.system_physical_memory_available)
{
- ret.total_address_space_in_use -= lazyfree;
+ // MemAvailable is >= Linux 3.14, so let's approximate what it would be
+ OUTCOME_TRY(auto &&memfree, parse(i, "\nMemFree:"));
+ OUTCOME_TRY(auto &&cached, parse(i, "\nCached:"));
+ OUTCOME_TRY(auto &&swapcached, parse(i, "\nSwapCached:"));
+ ret.system_physical_memory_available = memfree + cached + swapcached;
}
+ OUTCOME_TRY(ret.system_commit_charge_maximum, parse(i, "\nCommitLimit:"));
+ OUTCOME_TRY(ret.system_commit_charge_available, parse(i, "\nCommitted_AS:"));
+ OUTCOME_TRY(auto &&lazyfree, parse(i, "\nLazyFree:"));
+ if(lazyfree == (uint64_t) -1)
+ {
+ lazyfree = 0;
+ }
+ ret.system_commit_charge_available = ret.system_commit_charge_maximum - ret.system_commit_charge_available + lazyfree;
}
- // std::cerr << i << "\nSize = " << size << " Rss = " << rss << std::endl;
}
return ret;
}
@@ -502,29 +533,48 @@ namespace utils
(void) want;
kern_return_t error;
mach_msg_type_number_t outCount;
- task_vm_info_data_t vmInfo;
- // task_kernelmemory_info_data_t kmInfo;
+ process_memory_usage ret;
+ if(!!(wanted & process_memory_usage::want::this_process))
+ {
+ task_vm_info_data_t vmInfo;
+ // task_kernelmemory_info_data_t kmInfo;
- outCount = TASK_VM_INFO_COUNT;
- error = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &outCount);
- if(error != KERN_SUCCESS)
+ outCount = TASK_VM_INFO_COUNT;
+ error = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &outCount);
+ if(error != KERN_SUCCESS)
+ {
+ return errc::invalid_argument;
+ }
+ // outCount = TASK_KERNELMEMORY_INFO_COUNT;
+ // error = task_info(mach_task_self(), TASK_KERNELMEMORY_INFO, (task_info_t)&kmInfo, &outCount);
+ // if (error != KERN_SUCCESS) {
+ // return errc::invalid_argument;
+ //}
+ // std::cout << vmInfo.virtual_size << "\n" << vmInfo.region_count << "\n" << vmInfo.resident_size << "\n" << vmInfo.device << "\n" << vmInfo.internal <<
+ // "\n" << vmInfo.external << "\n" << vmInfo.reusable << "\n" << vmInfo.purgeable_volatile_pmap<< "\n" << vmInfo.purgeable_volatile_resident << "\n" <<
+ // vmInfo.purgeable_volatile_virtual << "\n" << vmInfo.compressed << "\n" << vmInfo.phys_footprint << std::endl; std::cout << "\n" << kmInfo.total_palloc
+ // <<
+ // "\n" << kmInfo.total_pfree << "\n" << kmInfo.total_salloc << "\n" << kmInfo.total_sfree << std::endl;
+ ret.total_address_space_in_use = vmInfo.virtual_size;
+ ret.total_address_space_paged_in = vmInfo.resident_size;
+ ret.private_committed = vmInfo.internal + vmInfo.compressed;
+ ret.private_paged_in = vmInfo.phys_footprint;
+ }
+ if(!!(wanted & process_memory_usage::want::this_system))
{
- return errc::invalid_argument;
+ vm_statistics_data_t vmStat;
+ outCount = HOST_VM_INFO_COUNT;
+ error = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t) &vmStat, &outCount);
+ if(error != KERN_SUCCESS)
+ {
+ return errc::invalid_argument;
+ }
+ ret.system_physical_memory_total = ((uint64_t) vmStat.free_count + vmStat.active_count + vmStat.inactive_count + vmStat.wire_count) * page_size();
+ ret.system_physical_memory_available = ((uint64_t) vmStat.free_count + vmStat.inactive_count) * page_size();
+ // Not sure how to retrieve these on Mac OS
+ // ret.system_commit_charge_maximum = (uint64_t) pi.CommitLimit * page_size();
+ // ret.system_commit_charge_available = (uint64_t) pi.CommitTotal * page_size();
}
- // outCount = TASK_KERNELMEMORY_INFO_COUNT;
- // error = task_info(mach_task_self(), TASK_KERNELMEMORY_INFO, (task_info_t)&kmInfo, &outCount);
- // if (error != KERN_SUCCESS) {
- // return errc::invalid_argument;
- //}
- // std::cout << vmInfo.virtual_size << "\n" << vmInfo.region_count << "\n" << vmInfo.resident_size << "\n" << vmInfo.device << "\n" << vmInfo.internal <<
- // "\n" << vmInfo.external << "\n" << vmInfo.reusable << "\n" << vmInfo.purgeable_volatile_pmap<< "\n" << vmInfo.purgeable_volatile_resident << "\n" <<
- // vmInfo.purgeable_volatile_virtual << "\n" << vmInfo.compressed << "\n" << vmInfo.phys_footprint << std::endl; std::cout << "\n" << kmInfo.total_palloc <<
- // "\n" << kmInfo.total_pfree << "\n" << kmInfo.total_salloc << "\n" << kmInfo.total_sfree << std::endl;
- process_memory_usage ret;
- ret.total_address_space_in_use = vmInfo.virtual_size;
- ret.total_address_space_paged_in = vmInfo.resident_size;
- ret.private_committed = vmInfo.internal + vmInfo.compressed;
- ret.private_paged_in = vmInfo.phys_footprint;
return ret;
#else
#error Unknown platform
diff --git a/include/llfio/v2.0/detail/impl/windows/import.hpp b/include/llfio/v2.0/detail/impl/windows/import.hpp
index 71001ce6..dd4b0ac2 100644
--- a/include/llfio/v2.0/detail/impl/windows/import.hpp
+++ b/include/llfio/v2.0/detail/impl/windows/import.hpp
@@ -539,6 +539,26 @@ namespace windows_nt_kernel
using DiscardVirtualMemory_t = BOOL(NTAPI *)(_In_ PVOID VirtualAddress, _In_ SIZE_T Size);
+ typedef struct _PERFORMANCE_INFORMATION
+ {
+ DWORD cb;
+ SIZE_T CommitTotal;
+ SIZE_T CommitLimit;
+ SIZE_T CommitPeak;
+ SIZE_T PhysicalTotal;
+ SIZE_T PhysicalAvailable;
+ SIZE_T SystemCache;
+ SIZE_T KernelTotal;
+ SIZE_T KernelPaged;
+ SIZE_T KernelNonpaged;
+ SIZE_T PageSize;
+ DWORD HandleCount;
+ DWORD ProcessCount;
+ DWORD ThreadCount;
+ } PERFORMANCE_INFORMATION, *PPERFORMANCE_INFORMATION, PERFORMACE_INFORMATION, *PPERFORMACE_INFORMATION;
+
+ using GetPerformanceInfo_t = BOOL(NTAPI*)(PPERFORMANCE_INFORMATION pPerformanceInformation, DWORD cb);
+
using RtlCaptureStackBackTrace_t = USHORT(NTAPI *)(_In_ ULONG FramesToSkip, _In_ ULONG FramesToCapture, _Out_ PVOID *BackTrace,
_Out_opt_ PULONG BackTraceHash);
@@ -965,6 +985,7 @@ namespace windows_nt_kernel
static AdjustTokenPrivileges_t AdjustTokenPrivileges;
static PrefetchVirtualMemory_t PrefetchVirtualMemory_;
static DiscardVirtualMemory_t DiscardVirtualMemory_;
+ static GetPerformanceInfo_t GetPerformanceInfo;
static SymInitialize_t SymInitialize;
static SymGetLineFromAddr64_t SymGetLineFromAddr64;
static RtlCaptureStackBackTrace_t RtlCaptureStackBackTrace;
@@ -1300,6 +1321,13 @@ namespace windows_nt_kernel
{
DiscardVirtualMemory_ = reinterpret_cast<DiscardVirtualMemory_t>(GetProcAddress(kernel32, "DiscardVirtualMemory"));
}
+ if(GetPerformanceInfo == nullptr)
+ {
+ if((GetPerformanceInfo = reinterpret_cast<GetPerformanceInfo_t>(GetProcAddress(kernel32, "K32GetPerformanceInfo"))) == nullptr)
+ {
+ abort();
+ }
+ }
#ifdef LLFIO_OP_STACKBACKTRACEDEPTH
if(dbghelp)
{
diff --git a/include/llfio/v2.0/detail/impl/windows/utils.ipp b/include/llfio/v2.0/detail/impl/windows/utils.ipp
index e12db462..4557e567 100644
--- a/include/llfio/v2.0/detail/impl/windows/utils.ipp
+++ b/include/llfio/v2.0/detail/impl/windows/utils.ipp
@@ -207,38 +207,55 @@ namespace utils
return success();
}
- result<process_memory_usage> current_process_memory_usage(process_memory_usage::want /*unused*/) noexcept
+ result<process_memory_usage> current_process_memory_usage(process_memory_usage::want wanted) noexcept
{
// Amazingly Win32 doesn't expose private working set, so to avoid having
// to iterate all the pages in the process and calculate, use a hidden
// NT kernel call
windows_nt_kernel::init();
using namespace windows_nt_kernel;
- ULONG written = 0;
- _VM_COUNTERS_EX2 vmc;
- memset(&vmc, 0, sizeof(vmc));
- NTSTATUS ntstat = NtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &vmc, sizeof(vmc), &written);
- if(ntstat < 0)
- {
- return ntkernel_error(ntstat);
- }
process_memory_usage ret;
- /* Notes:
+ if(!!(wanted & process_memory_usage::want::this_process))
+ {
+ ULONG written = 0;
+ _VM_COUNTERS_EX2 vmc;
+ memset(&vmc, 0, sizeof(vmc));
+ NTSTATUS ntstat = NtQueryInformationProcess(GetCurrentProcess(), ProcessVmCounters, &vmc, sizeof(vmc), &written);
+ if(ntstat < 0)
+ {
+ return ntkernel_error(ntstat);
+ }
+ /* Notes:
- Apparently PrivateUsage is the commit charge on Windows. It always equals PagefileUsage.
- It is the total amount of private anonymous pages committed.
- SharedCommitUsage is amount of non-binary Shared memory committed.
- Therefore total non-binary commit = PrivateUsage + SharedCommitUsage
+ Apparently PrivateUsage is the commit charge on Windows. It always equals PagefileUsage.
+ It is the total amount of private anonymous pages committed.
+ SharedCommitUsage is amount of non-binary Shared memory committed.
+ Therefore total non-binary commit = PrivateUsage + SharedCommitUsage
- WorkingSetSize is the total amount of program binaries, non-binary shared memory, and anonymous pages faulted in.
- PrivateWorkingSetSize is the amount of private anonymous pages faulted into the process.
- Therefore remainder is all shared working set faulted into the process.
- */
- ret.total_address_space_in_use = vmc.VirtualSize;
- ret.total_address_space_paged_in = vmc.WorkingSetSize;
+ WorkingSetSize is the total amount of program binaries, non-binary shared memory, and anonymous pages faulted in.
+ PrivateWorkingSetSize is the amount of private anonymous pages faulted into the process.
+ Therefore remainder is all shared working set faulted into the process.
+ */
+ ret.total_address_space_in_use = vmc.VirtualSize;
+ ret.total_address_space_paged_in = vmc.WorkingSetSize;
- ret.private_committed = vmc.PrivateUsage;
- ret.private_paged_in = vmc.PrivateWorkingSetSize;
+ ret.private_committed = vmc.PrivateUsage;
+ ret.private_paged_in = vmc.PrivateWorkingSetSize;
+ }
+ if(!!(wanted & process_memory_usage::want::this_system))
+ {
+ PERFORMANCE_INFORMATION pi;
+ memset(&pi, 0, sizeof(pi));
+ pi.cb = sizeof(pi);
+ if(!GetPerformanceInfo(&pi, sizeof(pi)))
+ {
+ return win32_error();
+ }
+ ret.system_physical_memory_total = (uint64_t) pi.PhysicalTotal * pi.PageSize;
+ ret.system_physical_memory_available = (uint64_t) pi.PhysicalAvailable * pi.PageSize;
+ ret.system_commit_charge_maximum = (uint64_t) pi.CommitLimit * pi.PageSize;
+ ret.system_commit_charge_available = (uint64_t)(pi.CommitLimit - pi.CommitTotal) * pi.PageSize;
+ }
return ret;
}
diff --git a/include/llfio/v2.0/utils.hpp b/include/llfio/v2.0/utils.hpp
index 147dfc7b..4b8501da 100644
--- a/include/llfio/v2.0/utils.hpp
+++ b/include/llfio/v2.0/utils.hpp
@@ -205,11 +205,31 @@ namespace utils
total_address_space_paged_in = 1U << 1U,
private_committed = 1U << 2U,
private_paged_in = 1U << 3U,
+
private_committed_inaccurate = 1U << 8U,
- all = (unsigned) -1 //
+ system_physical_memory_total = 1U << 16U,
+ system_physical_memory_available = 1U << 17U,
+ system_commit_charge_maximum = 1U << 18U,
+ system_commit_charge_available = 1U << 19U,
+
+ this_process = 0x0000ffff, //
+ this_system = 0xffff0000, //
+ all = 0xffffffff //
} QUICKCPPLIB_BITFIELD_END(want)
+ //! The total physical memory in this system.
+ uint64_t system_physical_memory_total{0};
+ //! The physical memory in this system not containing dirty pages i.e. is currently used for file system caching, or unused.
+ uint64_t system_physical_memory_available{0};
+
+ //! The maximum amount of memory which can be committed by all processes. This is typically physical RAM plus swap files. Note that swap files can be added
+ //! and removed over time.
+ uint64_t system_commit_charge_maximum{0};
+ //! The amount of commit charge remaining before the maximum. Subtract this from `system_commit_charge_maximum` to determine the amount of commit charge
+ //! consumed by all processes in the system.
+ uint64_t system_commit_charge_available{0};
+
//! The total virtual address space in use.
size_t total_address_space_in_use{0};
//! The total memory currently paged into the process. Always `<= total_address_space_in_use`. Also known as "working set", or "resident set size including
@@ -248,7 +268,7 @@ namespace utils
We therefore supply as `private_committed` the same value as `private_paged_in`.
*/
LLFIO_HEADERS_ONLY_FUNC_SPEC result<process_memory_usage>
- current_process_memory_usage(process_memory_usage::want want = process_memory_usage::want::all) noexcept;
+ current_process_memory_usage(process_memory_usage::want want = process_memory_usage::want::this_process) noexcept;
/*! \brief CPU usage statistics for a process.
*/
diff --git a/test/tests/utils.cpp b/test/tests/utils.cpp
index 82967e87..13ab969f 100644
--- a/test/tests/utils.cpp
+++ b/test/tests/utils.cpp
@@ -51,10 +51,9 @@ static inline void TestCurrentProcessCPUUsage()
#ifndef __APPLE__ // On Mac CI at least, idle is approx 2x user which ought to not occur on a two CPU VM
BOOST_CHECK(diff.system_ns_in_idle_mode <= 1100000000ULL * thread_count);
#endif
- std::cout << "With " << thread_count << " threads busy the process spent " << diff.process_ns_in_user_mode
- << " ns in user mode and " << diff.process_ns_in_kernel_mode << " ns in kernel mode. The system spent " << diff.system_ns_in_user_mode
- << " ns in user mode, " << diff.system_ns_in_kernel_mode << " ns in kernel mode, and " << diff.system_ns_in_idle_mode << " in idle mode."
- << std::endl;
+ std::cout << "With " << thread_count << " threads busy the process spent " << diff.process_ns_in_user_mode << " ns in user mode and "
+ << diff.process_ns_in_kernel_mode << " ns in kernel mode. The system spent " << diff.system_ns_in_user_mode << " ns in user mode, "
+ << diff.system_ns_in_kernel_mode << " ns in kernel mode, and " << diff.system_ns_in_idle_mode << " in idle mode." << std::endl;
done = true;
for(auto &t : threads)
{
@@ -72,11 +71,12 @@ static inline void TestCurrentProcessMemoryUsage()
namespace llfio = LLFIO_V2_NAMESPACE;
static const llfio::utils::process_memory_usage *last_pmu;
auto print = [](llfio::utils::process_memory_usage &pmu) -> std::ostream &(*) (std::ostream &) {
- pmu = llfio::utils::current_process_memory_usage().value();
+ pmu = llfio::utils::current_process_memory_usage(llfio::utils::process_memory_usage::want::all).value();
last_pmu = &pmu;
return [](std::ostream &s) -> std::ostream & {
return s << " " << (last_pmu->total_address_space_in_use / 1024.0 / 1024.0) << "," << (last_pmu->total_address_space_paged_in / 1024.0 / 1024.0)
- << "," << (last_pmu->private_committed / 1024.0 / 1024.0) << "," << (last_pmu->private_paged_in / 1024.0 / 1024.0) << std::endl;
+ << "," << (last_pmu->private_committed / 1024.0 / 1024.0) << "," << (last_pmu->private_paged_in / 1024.0 / 1024.0) << ","
+ << ((last_pmu->system_commit_charge_maximum - last_pmu->system_commit_charge_available) / 1024.0 / 1024.0) << std::endl;
};
};
auto fakefault = [](llfio::map_handle &maph) {
@@ -108,7 +108,7 @@ static inline void TestCurrentProcessMemoryUsage()
std::cout << "For page allocation:\n";
{
llfio::utils::process_memory_usage before_anything, after_reserve, after_commit, after_fault, after_decommit, after_zero, after_do_not_store;
- std::cout << " Total address space, Total address space paged in, Private bytes committed, Private bytes paged in\n\n";
+ std::cout << " Total address space, Total address space paged in, Private bytes committed, Private bytes paged in, System commit charge\n\n";
std::cout << " Before anything:\n" << print(before_anything) << std::endl;
{
// Should raise total_address_space_in_use by 1Gb
@@ -148,35 +148,41 @@ static inline void TestCurrentProcessMemoryUsage()
std::cout << " After committing and faulting and do not storing 1Gb:\n" << print(after_do_not_store) << std::endl;
}
auto within = [](const llfio::utils::process_memory_usage &a, const llfio::utils::process_memory_usage &b, int total_address_space_in_use,
- int total_address_space_paged_in, int private_committed, int private_paged_in) {
+ int total_address_space_paged_in, int private_committed, int private_paged_in, int system_committed) {
auto check = [](size_t a, size_t b, int bound) {
- auto diff = abs((b / 1024.0 / 1024.0) - (a / 1024.0 / 1024.0));
- return diff > bound - 10 && diff < bound + 10;
+ if(bound == INT_MAX)
+ {
+ return true;
+ }
+ auto diff = (b / 1024.0 / 1024.0) - (a / 1024.0 / 1024.0);
+ return diff > bound - 50 && diff < bound + 50;
};
return check(a.total_address_space_in_use, b.total_address_space_in_use, total_address_space_in_use) //
&& check(a.total_address_space_paged_in, b.total_address_space_paged_in, total_address_space_paged_in) //
&& check(a.private_committed, b.private_committed, private_committed) //
- && check(a.private_paged_in, b.private_paged_in, private_paged_in);
+ && check(a.private_paged_in, b.private_paged_in, private_paged_in) //
+ && check(b.system_commit_charge_available, a.system_commit_charge_available, system_committed);
};
#ifdef __APPLE__
// Mac OS has no way of differentiating between committed and paged in pages :(
- BOOST_CHECK(within(before_anything, after_reserve, 1024, 0, 0, 0));
- BOOST_CHECK(within(before_anything, after_commit, 1024, 0, 0, 0));
- BOOST_CHECK(within(before_anything, after_fault, 1024, 1024, 1024, 1024));
- BOOST_CHECK(within(before_anything, after_decommit, 1024, 0, 0, 0));
- BOOST_CHECK(within(before_anything, after_zero, 1024, 1024, 0, 0));
- BOOST_CHECK(within(before_anything, after_do_not_store, 1024, 1024, 1024, 1024)); // do_not_store() doesn't decrease RSS
+ BOOST_CHECK(within(before_anything, after_reserve, 1024, 0, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_commit, 1024, 0, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_fault, 1024, 1024, 1024, 1024, 0));
+ BOOST_CHECK(within(before_anything, after_decommit, 1024, 0, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_zero, 1024, 1024, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_do_not_store, 1024, 1024, 1024, 1024, 0)); // do_not_store() doesn't decrease RSS
#else
- BOOST_CHECK(within(before_anything, after_reserve, 1024, 0, 0, 0));
- BOOST_CHECK(within(before_anything, after_commit, 1024, 0, 1024, 0));
- BOOST_CHECK(within(before_anything, after_fault, 1024, 1024, 1024, 1024));
- BOOST_CHECK(within(before_anything, after_decommit, 1024, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_reserve, 1024, 0, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_commit, 1024, 0, 1024, 0, 1024));
+ BOOST_CHECK(within(before_anything, after_fault, 1024, 1024, 1024, 1024, 1024));
+ BOOST_CHECK(within(before_anything, after_decommit, 1024, 0, 0, 0, 0));
#ifdef _WIN32
- BOOST_CHECK(within(before_anything, after_zero, 1024, 0, 1024, 0));
- BOOST_CHECK(within(before_anything, after_do_not_store, 1024, 0, 1024, 0)); // do_not_store() decreases RSS but not commit on Windows
+ BOOST_CHECK(within(before_anything, after_zero, 1024, 0, 1024, 0, 1024));
+ BOOST_CHECK(within(before_anything, after_do_not_store, 1024, 0, 1024, 0, 1024)); // do_not_store() decreases RSS but not commit on Windows
#else
(void) after_zero; // may not evict faulted set on POSIX
- BOOST_CHECK(within(before_anything, after_do_not_store, 1024, 1024, 0, 1024)); // do_not_store() decreases commit but does not RSS on POSIX
+ BOOST_CHECK(within(before_anything, after_do_not_store, 1024, 1024, 0, 1024,
+ INT_MAX)); // do_not_store() decreases commit but does not RSS on POSIX BUT not the system commit if Linux < 4.12
#endif
#endif
}
@@ -189,7 +195,7 @@ static inline void TestCurrentProcessMemoryUsage()
{
auto sectionh = llfio::section_handle::section(1024 * 1024 * 1024).value();
llfio::utils::process_memory_usage before_anything, after_reserve, after_commit, after_fault, after_decommit, after_zero, after_do_not_store;
- std::cout << " Total address space, Total address space paged in, Private bytes committed, Private bytes paged in\n\n";
+ std::cout << " Total address space, Total address space paged in, Private bytes committed, Private bytes paged in, System commit charge\n\n";
std::cout << " Before anything:\n" << print(before_anything) << std::endl;
{
@@ -236,32 +242,37 @@ static inline void TestCurrentProcessMemoryUsage()
}
#endif
auto within = [](const llfio::utils::process_memory_usage &a, const llfio::utils::process_memory_usage &b, int total_address_space_in_use,
- int total_address_space_paged_in, int private_committed, int private_paged_in) {
+ int total_address_space_paged_in, int private_committed, int private_paged_in, int system_committed) {
auto check = [](size_t a, size_t b, int bound) {
- auto diff = abs((b / 1024.0 / 1024.0) - (a / 1024.0 / 1024.0));
- return diff > bound - 10 && diff < bound + 10;
+ if(bound == INT_MAX)
+ {
+ return true;
+ }
+ auto diff = (b / 1024.0 / 1024.0) - (a / 1024.0 / 1024.0);
+ return diff > bound - 50 && diff < bound + 50;
};
return check(a.total_address_space_in_use, b.total_address_space_in_use, total_address_space_in_use) //
&& check(a.total_address_space_paged_in, b.total_address_space_paged_in, total_address_space_paged_in) //
&& check(a.private_committed, b.private_committed, private_committed) //
- && check(a.private_paged_in, b.private_paged_in, private_paged_in);
+ && check(a.private_paged_in, b.private_paged_in, private_paged_in) //
+ && check(b.system_commit_charge_available, a.system_commit_charge_available, system_committed);
};
#ifdef __APPLE__
// Mac OS has no way of differentiating between committed and paged in pages :(
- BOOST_CHECK(within(before_anything, after_reserve, 1024, 0, 0, 0));
- BOOST_CHECK(within(before_anything, after_commit, 1024, 0, 0, 0));
- BOOST_CHECK(within(before_anything, after_fault, 1024, 1024, 0, 0));
- BOOST_CHECK(within(before_anything, after_decommit, 1024, 0, 0, 0));
- BOOST_CHECK(within(before_anything, after_zero, 1024, 1024, 0, 0)); // doesn't implement zero()
- BOOST_CHECK(within(before_anything, after_do_not_store, 1024, 1024, 0, 0)); // do_not_store() doesn't decrease RSS
+ BOOST_CHECK(within(before_anything, after_reserve, 1024, 0, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_commit, 1024, 0, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_fault, 1024, 1024, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_decommit, 1024, 0, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_zero, 1024, 1024, 0, 0, 0)); // doesn't implement zero()
+ BOOST_CHECK(within(before_anything, after_do_not_store, 1024, 1024, 0, 0, 0)); // do_not_store() doesn't decrease RSS
#else
- BOOST_CHECK(within(before_anything, after_reserve, 1024, 0, 0, 0));
- BOOST_CHECK(within(before_anything, after_commit, 1024, 0, 0, 0));
- BOOST_CHECK(within(before_anything, after_fault, 1024, 1024, 0, 0));
+ BOOST_CHECK(within(before_anything, after_reserve, 1024, 0, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_commit, 1024, 0, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_fault, 1024, 1024, 0, 0, 0));
#ifndef _WIN32
- BOOST_CHECK(within(before_anything, after_decommit, 1024, 0, 0, 0));
- BOOST_CHECK(within(before_anything, after_zero, 1024, 0, 0, 0));
- BOOST_CHECK(within(before_anything, after_do_not_store, 1024, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_decommit, 1024, 0, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_zero, 1024, 0, 0, 0, 0));
+ BOOST_CHECK(within(before_anything, after_do_not_store, 1024, 0, 0, 0, INT_MAX)); // system commit varies if Linux > 4.12
#else
(void) after_decommit;
(void) after_zero;