diff options
author | bruvzg <7645683+bruvzg@users.noreply.github.com> | 2023-04-03 11:46:29 +0300 |
---|---|---|
committer | bruvzg <7645683+bruvzg@users.noreply.github.com> | 2023-04-24 14:08:55 +0300 |
commit | 628f3b2f7975600dee2ee31fc85ed23d2f34c8ab (patch) | |
tree | dc20debec3326ff820d5014b9e26f9f62d83b4aa /drivers/unix/os_unix.cpp | |
parent | f178cad04a39bc40e759ef50675606b12bb07fff (diff) | |
download | redot-engine-628f3b2f7975600dee2ee31fc85ed23d2f34c8ab.tar.gz |
[OS] Implement and expose to scripting APIs `get_memory_info` method instead of old `get_free_static_memory`.
Diffstat (limited to 'drivers/unix/os_unix.cpp')
-rw-r--r-- | drivers/unix/os_unix.cpp | 205 |
1 files changed, 204 insertions, 1 deletions
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 178f01b185..967699c5f3 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -41,9 +41,12 @@ #include "drivers/unix/thread_posix.h" #include "servers/rendering_server.h" -#ifdef __APPLE__ +#if defined(__APPLE__) #include <mach-o/dyld.h> +#include <mach/host_info.h> +#include <mach/mach_host.h> #include <mach/mach_time.h> +#include <sys/sysctl.h> #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) @@ -51,6 +54,19 @@ #include <sys/sysctl.h> #endif +#if defined(__FreeBSD__) +#include <kvm.h> +#endif + +#if defined(__OpenBSD__) +#include <sys/swap.h> +#include <uvm/uvmexp.h> +#endif + +#if defined(__NetBSD__) +#include <uvm/uvm_extern.h> +#endif + #include <dlfcn.h> #include <errno.h> #include <poll.h> @@ -59,6 +75,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/resource.h> #include <sys/time.h> #include <sys/wait.h> #include <time.h> @@ -274,6 +291,192 @@ uint64_t OS_Unix::get_ticks_usec() const { return longtime; } +Dictionary OS_Unix::get_memory_info() const { + Dictionary meminfo; + + meminfo["physical"] = -1; + meminfo["free"] = -1; + meminfo["available"] = -1; + meminfo["stack"] = -1; + +#if defined(__APPLE__) + int pagesize = 0; + size_t len = sizeof(pagesize); + if (sysctlbyname("vm.pagesize", &pagesize, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get vm.pagesize, error code: %d - %s", errno, strerror(errno))); + } + + int64_t phy_mem = 0; + len = sizeof(phy_mem); + if (sysctlbyname("hw.memsize", &phy_mem, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get hw.memsize, error code: %d - %s", errno, strerror(errno))); + } + + mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; + vm_statistics64_data_t vmstat; + if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&vmstat, &count) != KERN_SUCCESS) { + ERR_PRINT(vformat("Could not get host vm statistics.")); + } + struct xsw_usage swap_used; + len = sizeof(swap_used); + if (sysctlbyname("vm.swapusage", &swap_used, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get vm.swapusage, error code: %d - %s", errno, strerror(errno))); + } + + if (phy_mem != 0) { + meminfo["physical"] = phy_mem; + } + if (vmstat.free_count * (int64_t)pagesize != 0) { + meminfo["free"] = vmstat.free_count * (int64_t)pagesize; + } + if (swap_used.xsu_avail + vmstat.free_count * (int64_t)pagesize != 0) { + meminfo["available"] = swap_used.xsu_avail + vmstat.free_count * (int64_t)pagesize; + } +#elif defined(__FreeBSD__) + int pagesize = 0; + size_t len = sizeof(pagesize); + if (sysctlbyname("vm.stats.vm.v_page_size", &pagesize, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get vm.stats.vm.v_page_size, error code: %d - %s", errno, strerror(errno))); + } + + uint64_t mtotal = 0; + len = sizeof(mtotal); + if (sysctlbyname("vm.stats.vm.v_page_count", &mtotal, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get vm.stats.vm.v_page_count, error code: %d - %s", errno, strerror(errno))); + } + uint64_t mfree = 0; + len = sizeof(mfree); + if (sysctlbyname("vm.stats.vm.v_free_count", &mfree, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get vm.stats.vm.v_free_count, error code: %d - %s", errno, strerror(errno))); + } + + uint64_t stotal = 0; + uint64_t sused = 0; + char errmsg[_POSIX2_LINE_MAX] = {}; + kvm_t *kd = kvm_openfiles(nullptr, "/dev/null", nullptr, 0, errmsg); + if (kd == nullptr) { + ERR_PRINT(vformat("kvm_openfiles failed, error: %s", errmsg)); + } else { + struct kvm_swap swap_info[32]; + int count = kvm_getswapinfo(kd, swap_info, 32, 0); + for (int i = 0; i < count; i++) { + stotal += swap_info[i].ksw_total; + sused += swap_info[i].ksw_used; + } + kvm_close(kd); + } + + if (mtotal * pagesize != 0) { + meminfo["physical"] = mtotal * pagesize; + } + if (mfree * pagesize != 0) { + meminfo["free"] = mfree * pagesize; + } + if ((mfree + stotal - sused) * pagesize != 0) { + meminfo["available"] = (mfree + stotal - sused) * pagesize; + } +#elif defined(__OpenBSD__) + int pagesize = sysconf(_SC_PAGESIZE); + + const int mib[] = { CTL_VM, VM_UVMEXP }; + uvmexp uvmexp_info; + size_t len = sizeof(uvmexp_info); + if (sysctl(mib, 2, &uvmexp_info, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get CTL_VM, VM_UVMEXP, error code: %d - %s", errno, strerror(errno))); + } + + uint64_t stotal = 0; + uint64_t sused = 0; + int count = swapctl(SWAP_NSWAP, 0, 0); + if (count > 0) { + swapent swap_info[count]; + count = swapctl(SWAP_STATS, swap_info, count); + + for (int i = 0; i < count; i++) { + if (swap_info[i].se_flags & SWF_ENABLE) { + sused += swap_info[i].se_inuse; + stotal += swap_info[i].se_nblks; + } + } + } + + if (uvmexp_info.npages * pagesize != 0) { + meminfo["physical"] = uvmexp_info.npages * pagesize; + } + if (uvmexp_info.free * pagesize != 0) { + meminfo["free"] = uvmexp_info.free * pagesize; + } + if ((uvmexp_info.free * pagesize) + (stotal - sused) * DEV_BSIZE != 0) { + meminfo["available"] = (uvmexp_info.free * pagesize) + (stotal - sused) * DEV_BSIZE; + } +#elif defined(__NetBSD__) + int pagesize = sysconf(_SC_PAGESIZE); + + const int mib[] = { CTL_VM, VM_UVMEXP2 }; + uvmexp_sysctl uvmexp_info; + size_t len = sizeof(uvmexp_info); + if (sysctl(mib, 2, &uvmexp_info, &len, nullptr, 0) < 0) { + ERR_PRINT(vformat("Could not get CTL_VM, VM_UVMEXP2, error code: %d - %s", errno, strerror(errno))); + } + + if (uvmexp_info.npages * pagesize != 0) { + meminfo["physical"] = uvmexp_info.npages * pagesize; + } + if (uvmexp_info.free * pagesize != 0) { + meminfo["free"] = uvmexp_info.free * pagesize; + } + if ((uvmexp_info.free + uvmexp_info.swpages - uvmexp_info.swpginuse) * pagesize != 0) { + meminfo["available"] = (uvmexp_info.free + uvmexp_info.swpages - uvmexp_info.swpginuse) * pagesize; + } +#else + Error err; + Ref<FileAccess> f = FileAccess::open("/proc/meminfo", FileAccess::READ, &err); + uint64_t mtotal = 0; + uint64_t mfree = 0; + uint64_t sfree = 0; + while (f.is_valid() && !f->eof_reached()) { + String s = f->get_line().strip_edges(); + if (s.begins_with("MemTotal:")) { + Vector<String> stok = s.replace("MemTotal:", "").strip_edges().split(" "); + if (stok.size() == 2) { + mtotal = stok[0].to_int() * 1024; + } + } + if (s.begins_with("MemFree:")) { + Vector<String> stok = s.replace("MemFree:", "").strip_edges().split(" "); + if (stok.size() == 2) { + mfree = stok[0].to_int() * 1024; + } + } + if (s.begins_with("SwapFree:")) { + Vector<String> stok = s.replace("SwapFree:", "").strip_edges().split(" "); + if (stok.size() == 2) { + sfree = stok[0].to_int() * 1024; + } + } + } + + if (mtotal != 0) { + meminfo["physical"] = mtotal; + } + if (mfree != 0) { + meminfo["free"] = mfree; + } + if (mfree + sfree != 0) { + meminfo["available"] = mfree + sfree; + } +#endif + + rlimit stackinfo = {}; + getrlimit(RLIMIT_STACK, &stackinfo); + + if (stackinfo.rlim_cur != 0) { + meminfo["stack"] = (int64_t)stackinfo.rlim_cur; + } + + return meminfo; +} + Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) { #ifdef __EMSCRIPTEN__ // Don't compile this code at all to avoid undefined references. |