SH-2218 FIX -- v2.8.x Viewers crash consistently when I actively use other applications
* Mac memory stats now extracted from proper system calls. Reviewed by Nat Linden.master
parent
6d9158dcad
commit
d712dde69e
|
|
@ -68,9 +68,11 @@ using namespace llsd;
|
|||
# include <sys/utsname.h>
|
||||
# include <stdint.h>
|
||||
# include <Carbon/Carbon.h>
|
||||
# include <sys/wait.h>
|
||||
# include <string.h>
|
||||
# include <stdexcept>
|
||||
# include <mach/host_info.h>
|
||||
# include <mach/mach_host.h>
|
||||
# include <mach/task.h>
|
||||
# include <mach/task_info.h>
|
||||
#elif LL_LINUX
|
||||
# include <errno.h>
|
||||
# include <sys/utsname.h>
|
||||
|
|
@ -990,194 +992,88 @@ LLSD LLMemoryInfo::loadStatsMap()
|
|||
stats.add("PrivateUsage KB", pmem.PrivateUsage/1024);
|
||||
|
||||
#elif LL_DARWIN
|
||||
uint64_t phys = 0;
|
||||
|
||||
size_t len = sizeof(phys);
|
||||
|
||||
if (sysctlbyname("hw.memsize", &phys, &len, NULL, 0) == 0)
|
||||
const vm_size_t pagekb(vm_page_size / 1024);
|
||||
|
||||
//
|
||||
// Collect the vm_stat's
|
||||
//
|
||||
|
||||
{
|
||||
stats.add("Total Physical KB", 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) // popen() couldn't run vm_stat
|
||||
{
|
||||
// Save errno right away.
|
||||
int popen_errno(errno);
|
||||
LL_WARNS("LLMemoryInfo") << "Unable to collect vm_stat memory information: ";
|
||||
char buffer[256];
|
||||
if (0 == strerror_r(popen_errno, buffer, sizeof(buffer)))
|
||||
vm_statistics_data_t vmstat;
|
||||
mach_msg_type_number_t vmstatCount = HOST_VM_INFO_COUNT;
|
||||
|
||||
if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t) &vmstat, &vmstatCount) != KERN_SUCCESS)
|
||||
{
|
||||
LL_CONT << buffer;
|
||||
LL_WARNS("LLMemoryInfo") << "Unable to collect memory information" << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_CONT << "errno " << popen_errno;
|
||||
stats.add("Pages free KB", pagekb * vmstat.free_count);
|
||||
stats.add("Pages active KB", pagekb * vmstat.active_count);
|
||||
stats.add("Pages inactive KB", pagekb * vmstat.inactive_count);
|
||||
stats.add("Pages wired KB", pagekb * vmstat.wire_count);
|
||||
|
||||
stats.add("Pages zero fill", vmstat.zero_fill_count);
|
||||
stats.add("Page reactivations", vmstat.reactivations);
|
||||
stats.add("Page-ins", vmstat.pageins);
|
||||
stats.add("Page-outs", vmstat.pageouts);
|
||||
|
||||
stats.add("Faults", vmstat.faults);
|
||||
stats.add("Faults copy-on-write", vmstat.cow_faults);
|
||||
|
||||
stats.add("Cache lookups", vmstat.lookups);
|
||||
stats.add("Cache hits", vmstat.hits);
|
||||
|
||||
stats.add("Page purgeable count", vmstat.purgeable_count);
|
||||
stats.add("Page purges", vmstat.purges);
|
||||
|
||||
stats.add("Page speculative reads", vmstat.speculative_count);
|
||||
}
|
||||
LL_CONT << LL_ENDL;
|
||||
}
|
||||
else // popen() launched vm_stat
|
||||
|
||||
//
|
||||
// Collect the misc task info
|
||||
//
|
||||
|
||||
{
|
||||
// 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)
|
||||
|
||||
// Intentionally don't pass the boost::no_except flag. These
|
||||
// boost::regex objects are constructed with string literals, so they
|
||||
// should be valid every time. If they become invalid, we WANT an
|
||||
// exception, hopefully even before the dev checks in.
|
||||
boost::regex pagesize_rx("\\(page size of ([0-9]+) bytes\\)");
|
||||
boost::regex stat_rx("(.+): +([0-9]+)\\.");
|
||||
boost::regex cache_rx("Object cache: ([0-9]+) hits of ([0-9]+) lookups "
|
||||
"\\(([0-9]+)% hit rate\\)");
|
||||
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))
|
||||
task_events_info_data_t taskinfo;
|
||||
unsigned taskinfoSize = sizeof(taskinfo);
|
||||
|
||||
if (task_info(mach_task_self(), TASK_EVENTS_INFO, (task_info_t) &taskinfo, &taskinfoSize) != KERN_SUCCESS)
|
||||
{
|
||||
size_t linelen(strlen(line));
|
||||
// Truncate any trailing newline
|
||||
if (line[linelen - 1] == '\n')
|
||||
{
|
||||
line[--linelen] = '\0';
|
||||
}
|
||||
LL_DEBUGS("LLMemoryInfo") << line << LL_ENDL;
|
||||
if (regex_search_no_exc(line, matched, pagesize_rx))
|
||||
{
|
||||
// "Mach Virtual Memory Statistics: (page size of 4096 bytes)"
|
||||
std::string pagesize_str(matched[1].first, matched[1].second);
|
||||
try
|
||||
{
|
||||
// Reasonable to assume that pagesize will always be a
|
||||
// multiple of 1Kb?
|
||||
pagesizekb = boost::lexical_cast<LLSD::Integer>(pagesize_str)/1024;
|
||||
}
|
||||
catch (const boost::bad_lexical_cast&)
|
||||
{
|
||||
LL_WARNS("LLMemoryInfo") << "couldn't parse '" << pagesize_str
|
||||
<< "' in vm_stat line: " << line << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
stats.add("page size", pagesizekb);
|
||||
}
|
||||
else if (regex_match_no_exc(line, matched, stat_rx))
|
||||
{
|
||||
// e.g. "Pages free: 462078."
|
||||
// Strip double-quotes off certain statistic names
|
||||
const char *key_begin(matched[1].first), *key_end(matched[1].second);
|
||||
if (key_begin[0] == '"' && key_end[-1] == '"')
|
||||
{
|
||||
++key_begin;
|
||||
--key_end;
|
||||
}
|
||||
LLSD::String key(key_begin, key_end);
|
||||
LLSD::String value_str(matched[2].first, matched[2].second);
|
||||
LLSD::Integer value(0);
|
||||
try
|
||||
{
|
||||
value = boost::lexical_cast<LLSD::Integer>(value_str);
|
||||
}
|
||||
catch (const boost::bad_lexical_cast&)
|
||||
{
|
||||
LL_WARNS("LLMemoryInfo") << "couldn't parse '" << value_str
|
||||
<< "' in vm_stat line: " << line << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
// Store this statistic.
|
||||
stats.add(key, value);
|
||||
// Is this in units of pages? If so, convert to Kb.
|
||||
static const LLSD::String pages("Pages ");
|
||||
if (key.substr(0, pages.length()) == pages)
|
||||
{
|
||||
// Synthesize a new key with kb in place of Pages
|
||||
LLSD::String kbkey("kb ");
|
||||
kbkey.append(key.substr(pages.length()));
|
||||
stats.add(kbkey, value * pagesizekb);
|
||||
}
|
||||
}
|
||||
else if (regex_match_no_exc(line, matched, cache_rx))
|
||||
{
|
||||
// e.g. "Object cache: 841598 hits of 7629869 lookups (11% hit rate)"
|
||||
static const char* cache_keys[] = { "cache hits", "cache lookups", "cache hit%" };
|
||||
std::vector<LLSD::Integer> cache_values;
|
||||
for (size_t i = 0; i < (sizeof(cache_keys)/sizeof(cache_keys[0])); ++i)
|
||||
{
|
||||
LLSD::String value_str(matched[i+1].first, matched[i+1].second);
|
||||
LLSD::Integer value(0);
|
||||
try
|
||||
{
|
||||
value = boost::lexical_cast<LLSD::Integer>(value_str);
|
||||
}
|
||||
catch (boost::bad_lexical_cast&)
|
||||
{
|
||||
LL_WARNS("LLMemoryInfo") << "couldn't parse '" << value_str
|
||||
<< "' in vm_stat line: " << line << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
stats.add(cache_keys[i], value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("LLMemoryInfo") << "unrecognized vm_stat line: " << line << LL_ENDL;
|
||||
}
|
||||
LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL;
|
||||
}
|
||||
int status(pclose(pout));
|
||||
if (status == -1) // pclose() couldn't retrieve rc
|
||||
else
|
||||
{
|
||||
// Save errno right away.
|
||||
int pclose_errno(errno);
|
||||
// The ECHILD error happens so frequently that unless filtered,
|
||||
// the warning below spams the log file. This is too bad, because
|
||||
// sometimes the logic above fails to produce any output derived
|
||||
// from vm_stat, but we've been unable to observe any specific
|
||||
// error indicating the problem.
|
||||
if (pclose_errno != ECHILD)
|
||||
{
|
||||
LL_WARNS("LLMemoryInfo") << "Unable to obtain vm_stat termination code: ";
|
||||
char buffer[256];
|
||||
if (0 == strerror_r(pclose_errno, buffer, sizeof(buffer)))
|
||||
{
|
||||
LL_CONT << buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_CONT << "errno " << pclose_errno;
|
||||
}
|
||||
LL_CONT << LL_ENDL;
|
||||
}
|
||||
stats.add("Task page-ins", taskinfo.pageins);
|
||||
stats.add("Task copy-on-write faults", taskinfo.cow_faults);
|
||||
stats.add("Task messages sent", taskinfo.messages_sent);
|
||||
stats.add("Task messages received", taskinfo.messages_received);
|
||||
stats.add("Task mach system call count", taskinfo.syscalls_mach);
|
||||
stats.add("Task unix system call count", taskinfo.syscalls_unix);
|
||||
stats.add("Task context switch count", taskinfo.csw);
|
||||
}
|
||||
else // pclose() retrieved rc; analyze
|
||||
}
|
||||
|
||||
//
|
||||
// Collect the basic task info
|
||||
//
|
||||
|
||||
{
|
||||
task_basic_info_64_data_t taskinfo;
|
||||
unsigned taskinfoSize = sizeof(taskinfo);
|
||||
|
||||
if (task_info(mach_task_self(), TASK_BASIC_INFO_64, (task_info_t) &taskinfo, &taskinfoSize) != KERN_SUCCESS)
|
||||
{
|
||||
if (WIFEXITED(status))
|
||||
{
|
||||
int rc(WEXITSTATUS(status));
|
||||
if (rc != 0)
|
||||
{
|
||||
LL_WARNS("LLMemoryInfo") << "vm_stat terminated with rc " << rc << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else if (WIFSIGNALED(status))
|
||||
{
|
||||
LL_WARNS("LLMemoryInfo") << "vm_stat terminated by signal " << WTERMSIG(status)
|
||||
<< LL_ENDL;
|
||||
}
|
||||
LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
stats.add("Basic suspend count", taskinfo.suspend_count);
|
||||
stats.add("Basic virtual memory KB", taskinfo.virtual_size / 1024);
|
||||
stats.add("Basic resident memory KB", taskinfo.resident_size / 1024);
|
||||
stats.add("Basic new thread policy", taskinfo.policy);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue