8#include "kmemoryinfo.h"
10#include <QLoggingCategory>
13Q_DECLARE_LOGGING_CATEGORY(LOG_KMEMORYINFO)
14Q_LOGGING_CATEGORY(LOG_KMEMORYINFO,
"kf.coreaddons.kmemoryinfo", QtWarningMsg)
17#if defined(Q_OS_WINDOWS)
20#elif defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)
23 #include <QByteArrayView>
24#elif defined(Q_OS_MACOS)
25 #include <mach/mach.h>
26 #include <sys/sysctl.h>
27#elif defined(Q_OS_FREEBSD)
30 #include <sys/sysctl.h>
31#elif defined(Q_OS_OPENBSD)
32 #include <sys/mount.h>
33 #include <sys/param.h>
35 #include <sys/syscall.h>
36 #include <sys/sysctl.h>
52 quint64 m_totalPhysical = 0;
53 quint64 m_availablePhysical = 0;
54 quint64 m_freePhysical = 0;
55 quint64 m_totalSwapFile = 0;
56 quint64 m_freeSwapFile = 0;
58 quint64 m_buffers = 0;
62 : d(new KMemoryInfoPrivate)
67KMemoryInfo::~KMemoryInfo()
88 return (d->m_availablePhysical == other.d->m_availablePhysical
89 && d->m_freePhysical == other.d->m_freePhysical
90 && d->m_freeSwapFile == other.d->m_freeSwapFile
91 && d->m_cached == other.d->m_cached
92 && d->m_buffers == other.d->m_buffers
93 && d->m_totalSwapFile == other.d->m_totalSwapFile
94 && d->m_totalPhysical == other.d->m_totalPhysical);
105 return d->m_totalPhysical == 0;
110 return d->m_totalPhysical;
115 return d->m_freePhysical;
120 return d->m_availablePhysical;
135 return d->m_totalSwapFile;
140 return d->m_freeSwapFile;
143#if defined(Q_OS_WINDOWS)
149 quint64 totalPageFilePages = 0;
150 quint64 freePageFilePages = 0;
153BOOL __stdcall pageInfo(LPVOID pContext, PENUM_PAGE_FILE_INFORMATION pPageFileInfo, LPCWSTR lpFilename)
156 if (
auto sw =
static_cast<SwapInfo *
>(pContext)) {
157 sw->totalPageFilePages += pPageFileInfo->TotalSize;
158 sw->freePageFilePages += (pPageFileInfo->TotalSize - pPageFileInfo->TotalInUse);
164bool KMemoryInfo::update()
166 MEMORYSTATUSEX statex;
167 statex.dwLength =
sizeof(statex);
168 if (!GlobalMemoryStatusEx(&statex)) {
172 PERFORMANCE_INFORMATION pi;
173 DWORD pisz =
sizeof(pi);
174 if (!GetPerformanceInfo(&pi, pisz)) {
179 if (!EnumPageFiles(pageInfo, &si)) {
183 d->m_totalPhysical = statex.ullTotalPhys;
184 d->m_availablePhysical = statex.ullAvailPhys;
185 d->m_freePhysical = statex.ullAvailPhys;
186 d->m_totalSwapFile = si.totalPageFilePages * pi.PageSize;
187 d->m_freeSwapFile = si.freePageFilePages * pi.PageSize;
188 d->m_cached = pi.SystemCache * pi.PageSize;
194#elif defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)
201bool extractBytes(quint64 &value,
const QByteArray &buffer,
const ByteArrayView &beginPattern, qsizetype &from)
203 ByteArrayView endPattern(
"kB");
204 auto beginIdx = buffer.
indexOf(beginPattern, from);
206 auto start = beginIdx + beginPattern.size();
209 from = endIdx + endPattern.size();
216 qCWarning(LOG_KMEMORYINFO) <<
"KMemoryInfo: extractBytes: wrong order when extracting" << beginPattern;
218 return extractBytes(value, buffer, beginPattern, from);
223bool KMemoryInfo::update()
225 QFile file(QStringLiteral(
"/proc/meminfo"));
229 auto meminfo = file.readAll();
232 qsizetype miFrom = 0;
233 quint64 totalPhys = 0;
234 if (!extractBytes(totalPhys, meminfo,
"MemTotal:", miFrom)) {
237 quint64 freePhys = 0;
238 if (!extractBytes(freePhys, meminfo,
"MemFree:", miFrom)) {
241 quint64 availPhys = 0;
242 if (!extractBytes(availPhys, meminfo,
"MemAvailable:", miFrom)) {
246 if (!extractBytes(
buffers, meminfo,
"Buffers:", miFrom)) {
250 if (!extractBytes(
cached, meminfo,
"Cached:", miFrom)) {
253 quint64 swapTotal = 0;
254 if (!extractBytes(swapTotal, meminfo,
"SwapTotal:", miFrom)) {
257 quint64 swapFree = 0;
258 if (!extractBytes(swapFree, meminfo,
"SwapFree:", miFrom)) {
261 quint64 sharedMem = 0;
262 if (!extractBytes(sharedMem, meminfo,
"Shmem:", miFrom)) {
265 quint64 sReclaimable = 0;
266 if (!extractBytes(sReclaimable, meminfo,
"SReclaimable:", miFrom)) {
271 d->m_totalPhysical = totalPhys;
273 d->m_availablePhysical = availPhys ? std::min(availPhys, totalPhys) : freePhys;
274 d->m_freePhysical = freePhys;
275 d->m_totalSwapFile = swapTotal;
276 d->m_freeSwapFile = swapFree;
277 d->m_cached =
cached + sReclaimable - sharedMem;
283#elif defined(Q_OS_MACOS)
289bool sysctlread(
const char *name, T &var)
291 auto sz =
sizeof(var);
292 return (sysctlbyname(name, &var, &sz, NULL, 0) == 0);
295bool KMemoryInfo::update()
306 sz =
sizeof(memSize);
307 if (sysctl(mib, 2, &memSize, &sz, NULL, 0) != KERN_SUCCESS) {
312 mib[1] = HW_PAGESIZE;
314 if (sysctl(mib, 2, &pageSize, &sz, NULL, 0) != KERN_SUCCESS) {
319 mib[1] = VM_SWAPUSAGE;
320 sz =
sizeof(swapUsage);
321 if (sysctl(mib, 2, &swapUsage, &sz, NULL, 0) != KERN_SUCCESS) {
325 quint64 zfs_arcstats_size = 0;
326 if (!sysctlread(
"kstat.zfs.misc.arcstats.size", zfs_arcstats_size)) {
327 zfs_arcstats_size = 0;
330 mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
331 vm_statistics64_data_t vmstat;
332 if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&vmstat, &count) != KERN_SUCCESS) {
336 d->m_totalPhysical = memSize;
337 d->m_availablePhysical = memSize - (vmstat.internal_page_count + vmstat.compressor_page_count + vmstat.wire_count) * pageSize;
338 d->m_freePhysical = vmstat.free_count *
pageSize;
339 d->m_totalSwapFile = swapUsage.xsu_total;
340 d->m_freeSwapFile = swapUsage.xsu_avail;
341 d->m_cached = vmstat.external_page_count *
pageSize + zfs_arcstats_size;
347#elif defined(Q_OS_FREEBSD)
353bool sysctlread(
const char *name, T &var)
355 auto sz =
sizeof(var);
356 return (sysctlbyname(name, &var, &sz, NULL, 0) == 0);
359bool KMemoryInfo::update()
369 sz =
sizeof(memSize);
370 if (sysctl(mib, 2, &memSize, &sz, NULL, 0) != 0) {
375 mib[1] = HW_PAGESIZE;
377 if (sysctl(mib, 2, &pageSize, &sz, NULL, 0) != 0) {
381 quint32 v_pageSize = 0;
382 if (sysctlread(
"vm.stats.vm.v_page_size", v_pageSize)) {
385 quint64 zfs_arcstats_size = 0;
386 if (!sysctlread(
"kstat.zfs.misc.arcstats.size", zfs_arcstats_size)) {
387 zfs_arcstats_size = 0;
389 quint32 v_cache_count = 0;
390 if (!sysctlread(
"vm.stats.vm.v_cache_count", v_cache_count)) {
393 quint32 v_inactive_count = 0;
394 if (!sysctlread(
"vm.stats.vm.v_inactive_count", v_inactive_count)) {
397 quint32 v_free_count = 0;
398 if (!sysctlread(
"vm.stats.vm.v_free_count", v_free_count)) {
401 quint64 vfs_bufspace = 0;
402 if (!sysctlread(
"vfs.bufspace", vfs_bufspace)) {
406 quint64 swap_tot = 0;
407 quint64 swap_free = 0;
408 if (
auto kd = kvm_open(
"/dev/null",
"/dev/null",
"/dev/null", O_RDONLY,
"kvm_open")) {
409 struct kvm_swap swap;
412 auto nswap = kvm_getswapinfo(kd, &swap, 1, 0);
414 swap_tot = swap.ksw_total;
415 swap_free = swap.ksw_used;
417 swap_free = (swap_tot - swap_free) * pageSize;
422 d->m_totalPhysical = memSize;
423 d->m_availablePhysical =
pageSize * (v_cache_count + v_free_count + v_inactive_count) + vfs_bufspace + zfs_arcstats_size;
424 d->m_freePhysical =
pageSize * v_free_count;
425 d->m_totalSwapFile = swap_tot;
426 d->m_freeSwapFile = swap_free;
427 d->m_cached =
pageSize * v_cache_count + zfs_arcstats_size;
428 d->m_buffers = vfs_bufspace;
433#elif defined(Q_OS_OPENBSD)
438static int swap_usage(
int *used,
int *total)
440 struct swapent *swdev;
441 int nswap, rnswap, i;
443 nswap = swapctl(SWAP_NSWAP,
nullptr, 0);
447 swdev =
static_cast<struct swapent *
>(calloc(nswap,
sizeof(*swdev)));
451 rnswap = swapctl(SWAP_STATS, swdev, nswap);
458 for (i = 0; i < nswap; i++) {
459 if (swdev[i].se_flags & SWF_ENABLE) {
460 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
461 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
468bool KMemoryInfo::update()
473 const long phys_pages = sysconf(_SC_PHYS_PAGES);
474 const long pagesize = sysconf(_SC_PAGESIZE);
475 if (phys_pages != -1 && pagesize != -1)
476 d->m_totalPhysical = ((uint64_t)phys_pages * (uint64_t)pagesize / 1024);
480 if (swap_usage(&swap_free, &swap_tot)) {
481 d->m_totalSwapFile = swap_tot;
482 d->m_freeSwapFile = swap_free;
485 int uvmexp_mib[] = {CTL_VM, VM_UVMEXP};
486 struct uvmexp uvmexp;
487 size_t size =
sizeof(uvmexp);
488 if (sysctl(uvmexp_mib, 2, &uvmexp, &size, NULL, 0) == -1) {
489 bzero(&uvmexp,
sizeof(uvmexp));
492 d->m_freePhysical = uvmexp.free * pagesize / 1024;
494 int bcstats_mib[] = {CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT};
495 struct bcachestats bcstats;
496 size =
sizeof(bcstats);
497 if (sysctl(bcstats_mib, 3, &bcstats, &size, NULL, 0) == -1) {
498 bzero(&bcstats,
sizeof(bcstats));
501 d->m_cached = bcstats.numbufpages * pagesize / 1024;
510bool KMemoryInfo::update()
512 qCWarning(LOG_KMEMORYINFO) <<
"KMemoryInfo: unsupported platform!";
The KMemoryInfo class provides an interface to get memory information (RAM/SWAP).
bool operator==(const KMemoryInfo &other) const
operator ==
quint64 freeSwapFile() const
freeSwapFile
quint64 freePhysical() const
freePhysical
quint64 cached() const
cached
KMemoryInfo & operator=(const KMemoryInfo &other)
operator = Makes a copy of the other memoryinfo and returns a reference to the copy.
quint64 totalSwapFile() const
totalSwapFile
quint64 buffers() const
buffers
bool isNull() const
isNull
bool operator!=(const KMemoryInfo &other) const
operator !=
quint64 availablePhysical() const
availablePhysical
KMemoryInfo()
KMemoryInfo Constructs a class with a snapshot of the state of the memory.
quint64 totalPhysical() const
totalPhysical
Q_SCRIPTABLE Q_NOREPLY void start()
KREPORT_EXPORT QPageSize::PageSizeId pageSize(const QString &key)
qsizetype indexOf(QByteArrayView bv, qsizetype from) const const
QByteArray mid(qsizetype pos, qsizetype len) const const
qulonglong toULongLong(bool *ok, int base) const const