diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2011-06-29 20:35:44 -0400 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2011-06-29 20:35:44 -0400 |
commit | 7f8ec9f142f34057fc10436f94ce420183cf75b8 (patch) | |
tree | a3ee1c7dd40212a8bdeaba3324137ca9b0f7df22 /indra | |
parent | 1262f710b548100e4522866341febba3d7cf535d (diff) |
CHOP-753: Introduce LLSD access to LLMemoryInfo ** BROKEN **
This is known not to compile on Mac yet; checking in to concurrently work on
Linux-specific code.
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llcommon/llsys.cpp | 211 | ||||
-rw-r--r-- | indra/llcommon/llsys.h | 28 |
2 files changed, 239 insertions, 0 deletions
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index f0f98f5bf6..40914dca3f 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -43,8 +43,15 @@ #include "llerrorcontrol.h" #include "llevents.h" #include "lltimer.h" +#include "llsdserialize.h" +#include "llsdutil.h" #include <boost/bind.hpp> #include <boost/circular_buffer.hpp> +#include <boost/regex.hpp> +#include <boost/foreach.hpp> +#include <boost/lexical_cast.hpp> + +using namespace llsd; #if LL_WINDOWS # define WIN32_LEAN_AND_MEAN @@ -633,6 +640,7 @@ void LLCPUInfo::stream(std::ostream& s) const LLMemoryInfo::LLMemoryInfo() { + refresh(); } #if LL_WINDOWS @@ -873,6 +881,209 @@ void LLMemoryInfo::stream(std::ostream& s) const #endif } +LLSD LLMemoryInfo::getStatsMap() const +{ + LLSD map; + + BOOST_FOREACH(LLSD pair, inArray(mData)) + { + // Have to be clear that we want the key asString() to specify map + // indexing rather than array subscripting. + map[pair[0].asString()] = pair[1]; + } + + return map; +} + +LLSD LLMemoryInfo::getStatsArray() const +{ + return mData; +} + +LLMemoryInfo& LLMemoryInfo::refresh() +{ + // This implementation is derived from stream() code (as of 2011-06-29). + // Hopefully we'll reimplement stream() to use mData before long... + mData = LLSD::emptyArray(); + +#if LL_WINDOWS + MEMORYSTATUSEX state; + state.dwLength = sizeof(state); + GlobalMemoryStatusEx(&state); + + mData.append(LLSDArray("Percent Memory use")(LLSD::Integer(state.dwMemoryLoad))); + mData.append(LLSDArray("Total Physical KB") (LLSD::Integer(state.ullTotalPhys/1024))); + mData.append(LLSDArray("Avail Physical KB") (LLSD::Integer(state.ullAvailPhys/1024))); + mData.append(LLSDArray("Total page KB") (LLSD::Integer(state.ullTotalPageFile/1024))); + mData.append(LLSDArray("Avail page KB") (LLSD::Integer(state.ullAvailPageFile/1024))); + mData.append(LLSDArray("Total Virtual KB") (LLSD::Integer(state.ullTotalVirtual/1024))); + mData.append(LLSDArray("Avail Virtual KB") (LLSD::Integer(state.ullAvailVirtual/1024))); + +#elif LL_DARWIN + uint64_t phys = 0; + + size_t len = sizeof(phys); + + if (sysctlbyname("hw.memsize", &phys, &len, NULL, 0) == 0) + { + mData.append(LLSDArray("Total Physical KB")(LLSD::Integer(phys/1024))); + } + else + { + LL_WARNS("LLMemoryInfo") << "Unable to collect hw.memsize memory information" << LL_ENDL; + } + + FILE* pout = popen("vm_stat 2>&1", "r"); + if (! pout) + { + LL_WARNS("LLMemoryInfo") << "Unable to collect vm_stat memory information" << LL_ENDL; + } + else + { + // Mach Virtual Memory Statistics: (page size of 4096 bytes) + // Pages free: 462078. + // Pages active: 142010. + // Pages inactive: 220007. + // Pages wired down: 159552. + // "Translation faults": 220825184. + // Pages copy-on-write: 2104153. + // Pages zero filled: 167034876. + // Pages reactivated: 65153. + // Pageins: 2097212. + // Pageouts: 41759. + // Object cache: 841598 hits of 7629869 lookups (11% hit rate) + + boost::regex pagesize_rx("\\(page size of ([0-9]+) bytes\\)"); + boost::regex stat_rx("(.+): +([0-9]+)\\."); + boost::regex pages_rx("Pages "); + boost::cmatch matched; + LLSD::Integer pagesizekb(4096/1024); + + // Here 'pout' is vm_stat's stdout. Search it for relevant data. + char line[100]; + line[sizeof(line)-1] = '\0'; + while (fgets(line, sizeof(line)-1, pout)) + { + size_t linelen(strlen(line)); + // Truncate any trailing newline + if (line[linelen - 1] == '\n') + { + line[--linelen] = '\0'; + } + if (boost::regex_search(&line[0], line+linelen, matched, pagesize_rx)) + { + // "Mach Virtual Memory Statistics: (page size of 4096 bytes)" + std::string pagesize_str(matched[1].first, matched[1].second); + // Reasonable to assume that pagesize will always be a + // multiple of 1Kb? + pagesizekb = boost::lexical_cast<LLSD::Integer>(pagesize_str)/1024; + } + else if (boost::regex_match(&line[0], line+linelen, matched, stat_rx)) + { + // e.g. "Pages free: 462078." + // Strip double-quotes off certain statistic names + if (matched[1].first[0] == '"' && matched[1].second[-1] == '"') + { + ++matched[1].first; + --matched[1].second; + } + LLSD::String key(matched[1].first, matched[1].second); + LLSD::String value_str(matched[2].first, matched[2].second); + LLSD::Integer value(boost::lexical_cast<LLSD::Integer>(value_str)); + // Store this statistic. + mData.append(LLSDArray(key)(value)); + // Is this in units of pages? If so, convert to Kb. + // boost::regex_match() doc sez: "If you want to match a + // prefix of the character string then use regex_search with + // the flag match_continuous set." + boost::smatch smatched; + if (boost::regex_search(key, smatched, pages_rx, boost::match_continuous)) + { + // Synthesize a new key with kB in place of Pages + LLSD::String kbkey("kB "); + kbkey.append(smatched[0].second, key.end()); + mData.append(LLSDArray(kbkey)(value * pagesizekb)); + } + } + else + { + LL_WARNS("LLMemoryInfo") << "unrecognized vm_stat line: " << line << LL_ENDL; + } + } + fclose(pout); + } + +#elif LL_SOLARIS + U64 phys = 0; + + phys = (U64)(sysconf(_SC_PHYS_PAGES)) * (U64)(sysconf(_SC_PAGESIZE)/1024); + + mData.append(LLSDArray("Total Physical KB")(phys)); + +#elif LL_LINUX + std::ifstream meminfo(MEMINFO_FILE); + if (meminfo.is_open()) + { + // MemTotal: 4108424 kB + // MemFree: 1244064 kB + // Buffers: 85164 kB + // Cached: 1990264 kB + // SwapCached: 0 kB + // Active: 1176648 kB + // Inactive: 1427532 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 + + boost::regex stat_rx("(.+): +([0-9]+)( kB)?"); + boost::smatch matched; + + std::string line; + while (std::getline(meminfo, line)) + { + if (boost::regex_match(line, line+linelen, matched, stat_rx)) + { + // e.g. "MemTotal: 4108424 kB" + LLSD::String key(matched[1].first, matched[1].second); + LLSD::String value_str(matched[2].first, matched[2].second); + LLSD::Integer value(boost::lexical_cast<LLSD::Integer>(value_str)); + // Store this statistic. + mData.append(LLSDArray(key)(value)); + } + else + { + LL_WARNS("LLMemoryInfo") << "unrecognized " << MEMINFO_FILE << " line: " + << line << LL_ENDL; + } + } + } + else + { + s << "Unable to collect memory information" << std::endl; + } + +#else + s << "Unknown system; unable to collect memory information" << std::endl; + +#endif + + // should become LL_DEBUGS when we're happy + LL_INFOS("LLMemoryInfo") << "Populated mData:\n"; + LLSDSerialize::toPrettyXML(mData, LL_CONT); + LL_ENDL; + + return *this; +} + std::ostream& operator<<(std::ostream& s, const LLOSInfo& info) { info.stream(s); diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h index 41a4f25000..5b44757e08 100644 --- a/indra/llcommon/llsys.h +++ b/indra/llcommon/llsys.h @@ -36,6 +36,7 @@ // llinfos << info << llendl; // +#include "llsd.h" #include <iosfwd> #include <string> @@ -117,6 +118,33 @@ public: //get the available memory infomation in KiloBytes. static void getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb); + + // Retrieve a map of memory statistics. The keys of the map are platform- + // dependent. The values are in kilobytes. + LLSD getStatsMap() const; + + // Retrieve memory statistics: an array of pair arrays [name, value]. This + // is the same data as presented in getStatsMap(), but it preserves the + // order in which we retrieved it from the OS in case that's useful. The + // set of statistics names is platform-dependent. The values are in + // kilobytes to try to avoid integer overflow. + LLSD getStatsArray() const; + + // Re-fetch memory data (as reported by stream() and getStats*()) from the + // system. Normally this is fetched at construction time. Return (*this) + // to permit usage of the form: + // @code + // LLMemoryInfo info; + // ... + // info.refresh().getStatsArray(); + // @endcode + LLMemoryInfo& refresh(); + +private: + // Internally, we store memory stats as for getStatsArray(). It's + // straightforward to convert that to getStatsMap() form, less so to + // reconstruct the original order when converting the other way. + LLSD mData; }; |