diff options
| author | Jonathan "Geenz" Goodman <geenz@lindenlab.com> | 2026-08-14 17:10:28 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-14 17:10:28 -0400 |
| commit | 05a5a15c99bd1174736da66c58b7080c75a8acb8 (patch) | |
| tree | e73b7b75809ab21a1933b7cb9f78f4fc5271b061 /indra/llcommon/llsys.cpp | |
| parent | a3c380acd9256102730574afb261aa6266f9a2a5 (diff) | |
| parent | 0007f7f99fc37b45ad7f3ad6df4238893c50a5be (diff) | |
Merge pull request #6132 from secondlife/geenz/linux-to-develop
Geenz/linux (and 26.3) to develop
Diffstat (limited to 'indra/llcommon/llsys.cpp')
| -rw-r--r-- | indra/llcommon/llsys.cpp | 214 |
1 files changed, 92 insertions, 122 deletions
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 051f24fcb5..bc38b72004 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2026, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -43,6 +43,7 @@ #include "llerrorcontrol.h" #include "llevents.h" #include "llformat.h" +#include "llmemory.h" #include "llregex.h" #include "lltimer.h" #include "llsdserialize.h" @@ -506,57 +507,46 @@ const S32 LLOSInfo::getOSBitness() const return mOSBitness; } -//static -U32 LLOSInfo::getProcessVirtualSizeKB() -{ - U32 virtual_size = 0; -#if LL_LINUX -# define STATUS_SIZE 2048 - LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); - if (status_filep) - { - S32 numRead = 0; - char buff[STATUS_SIZE]; /* Flawfinder: ignore */ +namespace { - size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); - buff[nbytes] = '\0'; + U32 readFromProcStat( std::string entryName ) + { + U32 val{}; +#if LL_LINUX + constexpr U32 STATUS_SIZE = 2048; - // All these guys return numbers in KB - char *memp = strstr(buff, "VmSize:"); - if (memp) + LLFILE* status_filep = LLFile::fopen("/proc/self/status", LLFILE_MODE("rb")); + if (status_filep) { - numRead += sscanf(memp, "%*s %u", &virtual_size); + char buff[STATUS_SIZE]; /* Flawfinder: ignore */ + + size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); + buff[nbytes] = '\0'; + + // All these guys return numbers in KB + char *memp = strstr(buff, entryName.c_str()); + if (memp) + { + (void) sscanf(memp, "%*s %u", &val); + } + fclose(status_filep); } - fclose(status_filep); - } #endif - return virtual_size; + return val; + } + } //static -U32 LLOSInfo::getProcessResidentSizeKB() +U32 LLOSInfo::getProcessVirtualSizeKB() { - U32 resident_size = 0; -#if LL_LINUX - LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); - if (status_filep != NULL) - { - S32 numRead = 0; - char buff[STATUS_SIZE]; /* Flawfinder: ignore */ - - size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); - buff[nbytes] = '\0'; + return readFromProcStat( "VmSize:" ); +} - // All these guys return numbers in KB - char *memp = strstr(buff, "VmRSS:"); - if (memp) - { - numRead += sscanf(memp, "%*s %u", &resident_size); - } - fclose(status_filep); - } -#endif - return resident_size; +//static +U32 LLOSInfo::getProcessResidentSizeKB() +{ + return readFromProcStat( "VmRSS:" ); } //static @@ -756,7 +746,7 @@ public: void add(const LLSD::String& name, const T& value, typename std::enable_if_t<std::is_integral_v<T> >* = 0) { - mStats[name] = LLSD::Integer(value); + mStats[name] = LLSD::Integer(llmin<T>(value, S32_MAX)); } // Store every floating-point type as LLSD::Real. @@ -837,15 +827,13 @@ U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const } //static -void LLMemoryInfo::getAvailableMemoryKB(U32Kilobytes& avail_mem_kb) +void LLMemoryInfo::updateAvailableMemory() { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; #if LL_WINDOWS - // Sigh, this shouldn't be a static method, then we wouldn't have to - // reload this data separately from refresh() - LLSD statsMap(loadStatsMap()); - - avail_mem_kb = (U32Kilobytes)statsMap["Avail Physical KB"].asInteger(); + // On windows loadStatsMap will fill sAvailPhysicalMemInKB, + // sAvailCommitMemInMB, sAllocatedMemInKB and sAllocatedPageSizeInKB + loadStatsMap(); #elif LL_DARWIN // use host_statistics64 to get memory info @@ -857,70 +845,21 @@ void LLMemoryInfo::getAvailableMemoryKB(U32Kilobytes& avail_mem_kb) kern_return_t result = host_statistics64(host, HOST_VM_INFO64, reinterpret_cast<host_info_t>(&vmstat), &count); if (result == KERN_SUCCESS) { - avail_mem_kb = U64Bytes((vmstat.free_count + vmstat.inactive_count) * page_size); + LLMemory::sAvailPhysicalMemInKB = U64Bytes((vmstat.free_count + vmstat.inactive_count) * page_size); } else { - avail_mem_kb = (U32Kilobytes)-1; + LLMemory::sAvailPhysicalMemInKB = (U32Kilobytes)-1; } #elif LL_LINUX - // mStatsMap is derived from MEMINFO_FILE: - // $ cat /proc/meminfo - // MemTotal: 4108424 kB - // MemFree: 1244064 kB - // Buffers: 85164 kB - // Cached: 1990264 kB - // SwapCached: 0 kB - // Active: 1176648 kB - // Inactive: 1427532 kB - // Active(anon): 529152 kB - // Inactive(anon): 15924 kB - // Active(file): 647496 kB - // Inactive(file): 1411608 kB - // Unevictable: 16 kB - // Mlocked: 16 kB - // HighTotal: 3266316 kB - // HighFree: 721308 kB - // LowTotal: 842108 kB - // LowFree: 522756 kB - // SwapTotal: 6384632 kB - // SwapFree: 6384632 kB - // Dirty: 28 kB - // Writeback: 0 kB - // AnonPages: 528820 kB - // Mapped: 89472 kB - // Shmem: 16324 kB - // Slab: 159624 kB - // SReclaimable: 145168 kB - // SUnreclaim: 14456 kB - // KernelStack: 2560 kB - // PageTables: 5560 kB - // NFS_Unstable: 0 kB - // Bounce: 0 kB - // WritebackTmp: 0 kB - // CommitLimit: 8438844 kB - // Committed_AS: 1271596 kB - // VmallocTotal: 122880 kB - // VmallocUsed: 65252 kB - // VmallocChunk: 52356 kB - // HardwareCorrupted: 0 kB - // HugePages_Total: 0 - // HugePages_Free: 0 - // HugePages_Rsvd: 0 - // HugePages_Surp: 0 - // Hugepagesize: 2048 kB - // DirectMap4k: 434168 kB - // DirectMap2M: 477184 kB - // (could also run 'free', but easier to read a file than run a program) - LLSD statsMap(loadStatsMap()); - - avail_mem_kb = (U32Kilobytes)statsMap["MemFree"].asInteger(); + U64 phys = U64(getpagesize()) * U64(get_avphys_pages()); + LLMemory::sAvailPhysicalMemInKB = U64Bytes(phys); #else //do not know how to collect available memory info for other systems. //leave it blank here for now. - avail_mem_kb = (U32Kilobytes)-1 ; + LLMemory::sAvailPhysicalMemInKB = (U32Kilobytes)-1 ; #endif } @@ -991,15 +930,24 @@ LLSD LLMemoryInfo::loadStatsMap() state.dwLength = sizeof(state); GlobalMemoryStatusEx(&state); - DWORDLONG div = 1024; + static constexpr DWORDLONG div = 1024; - stats.add("Percent Memory use", state.dwMemoryLoad/div); + stats.add("Percent Memory use", state.dwMemoryLoad); stats.add("Total Physical KB", state.ullTotalPhys/div); stats.add("Avail Physical KB", state.ullAvailPhys/div); + + // Despite the confusing naming "PageFile" , these values + // actually represent the committed memory limit for + // the system or the current process, whichever is smaller. stats.add("Total page KB", state.ullTotalPageFile/div); stats.add("Avail page KB", state.ullAvailPageFile/div); - stats.add("Total Virtual KB", state.ullTotalVirtual/div); - stats.add("Avail Virtual KB", state.ullAvailVirtual/div); + + static constexpr DWORDLONG mb_div = 1024 * 1024; + stats.add("Total Virtual MB", state.ullTotalVirtual/mb_div); // ~134 million MB + stats.add("Avail Virtual MB", state.ullAvailVirtual/mb_div); + + LLMemory::sAvailPhysicalMemInKB = U32Kilobytes::convert(U64Bytes(state.ullAvailPhys)); + LLMemory::sAvailCommitMemInMB = U32Megabytes::convert(U64Bytes(state.ullAvailPageFile)); // SL-12122 - Call to GetPerformanceInfo() was removed here. Took // on order of 10 ms, causing unacceptable frame time spike every @@ -1015,18 +963,38 @@ LLSD LLMemoryInfo::loadStatsMap() // specifically accepts PROCESS_MEMORY_COUNTERS*, and since this is a // classic-C API, PROCESS_MEMORY_COUNTERS_EX isn't a subclass. Cast the // pointer. - GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*) &pmem, sizeof(pmem)); + if (GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmem, sizeof(pmem))) + { + LLMemory::sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(pmem.WorkingSetSize)); + LLMemory::sAllocatedPageSizeInKB = U32Kilobytes::convert(U64Bytes(pmem.PagefileUsage)); - stats.add("Page Fault Count", pmem.PageFaultCount); - stats.add("PeakWorkingSetSize KB", pmem.PeakWorkingSetSize/div); - stats.add("WorkingSetSize KB", pmem.WorkingSetSize/div); - stats.add("QutaPeakPagedPoolUsage KB", pmem.QuotaPeakPagedPoolUsage/div); - stats.add("QuotaPagedPoolUsage KB", pmem.QuotaPagedPoolUsage/div); - stats.add("QuotaPeakNonPagedPoolUsage KB", pmem.QuotaPeakNonPagedPoolUsage/div); - stats.add("QuotaNonPagedPoolUsage KB", pmem.QuotaNonPagedPoolUsage/div); - stats.add("PagefileUsage KB", pmem.PagefileUsage/div); - stats.add("PeakPagefileUsage KB", pmem.PeakPagefileUsage/div); - stats.add("PrivateUsage KB", pmem.PrivateUsage/div); + stats.add("Page Fault Count", pmem.PageFaultCount); + stats.add("PeakWorkingSetSize KB", pmem.PeakWorkingSetSize / div); + stats.add("WorkingSetSize KB", pmem.WorkingSetSize / div); + stats.add("QuotaPeakPagedPoolUsage KB", pmem.QuotaPeakPagedPoolUsage / div); + stats.add("QuotaPagedPoolUsage KB", pmem.QuotaPagedPoolUsage / div); + stats.add("QuotaPeakNonPagedPoolUsage KB", pmem.QuotaPeakNonPagedPoolUsage / div); + stats.add("QuotaNonPagedPoolUsage KB", pmem.QuotaNonPagedPoolUsage / div); + stats.add("PagefileUsage KB", pmem.PagefileUsage / div); + stats.add("PeakPagefileUsage KB", pmem.PeakPagefileUsage / div); + stats.add("PrivateUsage KB", pmem.PrivateUsage / div); + } + else + { + LLMemory::sAllocatedMemInKB = U32Kilobytes(0); + LLMemory::sAllocatedPageSizeInKB = U32Kilobytes(0); + + stats.add("Page Fault Count", 0); + stats.add("PeakWorkingSetSize KB", 0); + stats.add("WorkingSetSize KB", 0); + stats.add("QuotaPeakPagedPoolUsage KB", 0); + stats.add("QuotaPagedPoolUsage KB", 0); + stats.add("QuotaPeakNonPagedPoolUsage KB", 0); + stats.add("QuotaNonPagedPoolUsage KB", 0); + stats.add("PagefileUsage KB", 0); + stats.add("PeakPagefileUsage KB", 0); + stats.add("PrivateUsage KB", 0); + } #elif LL_DARWIN @@ -1115,7 +1083,7 @@ LLSD LLMemoryInfo::loadStatsMap() } #elif LL_LINUX - std::ifstream meminfo(MEMINFO_FILE); + llifstream meminfo(MEMINFO_FILE); if (meminfo.is_open()) { // MemTotal: 4108424 kB @@ -1155,9 +1123,10 @@ LLSD LLMemoryInfo::loadStatsMap() LLSD::String key(matched[1].first, matched[1].second); LLSD::String value_str(matched[2].first, matched[2].second); LLSD::Integer value(0); + S64 intval = 0; try { - value = boost::lexical_cast<LLSD::Integer>(value_str); + intval = llclamp(boost::lexical_cast<S64>(value_str), S32_MIN, S32_MAX); } catch (const boost::bad_lexical_cast&) { @@ -1166,6 +1135,7 @@ LLSD LLMemoryInfo::loadStatsMap() << line << LL_ENDL; continue; } + value = LLSD::Integer(intval); // Store this statistic. stats.add(key, value); } @@ -1366,7 +1336,7 @@ bool gunzip_file(const std::string& srcfile, const std::string& dstfile) src = gzopen(srcfile.c_str(), "rb"); #endif if (! src) goto err; - dst = LLFile::fopen(tmpfile, "wb"); /* Flawfinder: ignore */ + dst = LLFile::fopen(tmpfile, LLFILE_MODE("wb")); /* Flawfinder: ignore */ if (! dst) goto err; do { @@ -1407,7 +1377,7 @@ bool gzip_file(const std::string& srcfile, const std::string& dstfile) #endif if (! dst) goto err; - src = LLFile::fopen(srcfile, "rb"); /* Flawfinder: ignore */ + src = LLFile::fopen(srcfile, LLFILE_MODE("rb")); /* Flawfinder: ignore */ if (! src) goto err; while ((bytes = (S32)fread(buffer, sizeof(U8), COMPRESS_BUFFER_SIZE, src)) > 0) |
