Bug 1038888 - Extend system memory reporter to report ion memory. r=njn

--HG--
extra : rebase_source : 39dbc0a696d67c1a239876ec8ca412527fc2712e
This commit is contained in:
Eric Rahm 2014-07-23 16:36:27 -07:00
parent 1679b15cf6
commit 2304c179f5

View File

@ -46,6 +46,26 @@ namespace SystemMemoryReporter {
#error "This won't work if we're not on Linux." #error "This won't work if we're not on Linux."
#endif #endif
/**
* RAII helper that will close an open DIR handle.
*/
struct MOZ_STACK_CLASS AutoDir
{
AutoDir(DIR* aDir) : mDir(aDir) {}
~AutoDir() { if (mDir) closedir(mDir); };
DIR* mDir;
};
/**
* RAII helper that will close an open FILE handle.
*/
struct MOZ_STACK_CLASS AutoFile
{
AutoFile(FILE* aFile) : mFile(aFile) {}
~AutoFile() { if (mFile) fclose(mFile); }
FILE* mFile;
};
static bool static bool
EndsWithLiteral(const nsCString& aHaystack, const char* aNeedle) EndsWithLiteral(const nsCString& aHaystack, const char* aNeedle)
{ {
@ -180,6 +200,10 @@ public:
rv = CollectKgslReports(aHandleReport, aData); rv = CollectKgslReports(aHandleReport, aData);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Report ION memory usage.
rv = CollectIonReports(aHandleReport, aData);
NS_ENSURE_SUCCESS(rv, rv);
return rv; return rv;
} }
@ -680,6 +704,106 @@ private:
return NS_OK; return NS_OK;
} }
nsresult
CollectIonReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData)
{
// ION is a replacement for PMEM (and other similar allocators).
//
// More details from http://lwn.net/Articles/480055/
// "Like its PMEM-like predecessors, ION manages one or more memory pools,
// some of which are set aside at boot time to combat fragmentation or to
// serve special hardware needs. GPUs, display controllers, and cameras
// are some of the hardware blocks that may have special memory
// requirements."
//
// The file format starts as follows:
// client pid size
// ----------------------------------------------------
// adsprpc-smd 1 4096
// fd900000.qcom,mdss_mdp 1 1658880
// ----------------------------------------------------
// orphaned allocations (info is from last known client):
// Homescreen 24100 294912 0 1
// b2g 23987 1658880 0 1
// mdss_fb0 401 1658880 0 1
// b2g 23987 4096 0 1
// Built-in Keyboa 24205 61440 0 1
// ----------------------------------------------------
// <other stuff>
//
// For our purposes we only care about the first portion of the file noted
// above which contains memory alloations (both sections). The term
// "orphaned" is misleading, it appears that every allocation not by the
// first process is considered orphaned on FxOS devices.
// The first three fields of each entry interest us:
// 1) client - Essentially the process name. We limit client names to 63
// characters, in theory they should never be greater than 15
// due to thread name length limitations.
// 2) pid - The ID of the allocating process, read as a uint32_t.
// 3) size - The size of the allocation in bytes, read as as a uint64_t.
const char* const kFormatString = "%63s %" SCNu32 " %" SCNu64;
const size_t kNumFields = 3;
const size_t kStringSize = 64;
const char* const kIonIommuPath = "/sys/kernel/debug/ion/iommu";
FILE* iommu = fopen(kIonIommuPath, "r");
if (!iommu) {
if (NS_WARN_IF(errno != ENOENT)) {
return NS_ERROR_FAILURE;
}
// If ENOENT, system doesn't use ION.
return NS_OK;
}
AutoFile iommuGuard(iommu);
const size_t kBufferLen = 256;
char buffer[kBufferLen];
char client[kStringSize];
uint32_t pid;
uint64_t size;
// Ignore the header line.
fgets(buffer, kBufferLen, iommu);
// Ignore the separator line.
fgets(buffer, kBufferLen, iommu);
const char* const kSep = "----";
const size_t kSepLen = 4;
// Read non-orphaned entries.
while (fgets(buffer, kBufferLen, iommu) &&
strncmp(kSep, buffer, kSepLen) != 0) {
if (sscanf(buffer, kFormatString, client, &pid, &size) == kNumFields) {
nsPrintfCString entryPath("ion-memory/%s (pid=%d)", client, pid);
REPORT(entryPath,
size,
NS_LITERAL_CSTRING("An ION kernel memory allocation."));
}
}
// Ignore the orphaned header.
fgets(buffer, kBufferLen, iommu);
// Read orphaned entries.
while (fgets(buffer, kBufferLen, iommu) &&
strncmp(kSep, buffer, kSepLen) != 0) {
if (sscanf(buffer, kFormatString, client, &pid, &size) == kNumFields) {
nsPrintfCString entryPath("ion-memory/%s (pid=%d)", client, pid);
REPORT(entryPath,
size,
NS_LITERAL_CSTRING("An ION kernel memory allocation."));
}
}
// Ignore the rest of the file.
return NS_OK;
}
uint64_t uint64_t
ReadSizeFromFile(const char* aFilename) ReadSizeFromFile(const char* aFilename)
{ {
@ -866,20 +990,6 @@ private:
return NS_OK; return NS_OK;
} }
struct AutoDir
{
AutoDir(DIR* aDir) : mDir(aDir) {}
~AutoDir() { closedir(mDir); };
DIR* mDir;
};
struct AutoFile
{
AutoFile(FILE* aFile) : mFile(aFile) {}
~AutoFile() { fclose(mFile); }
FILE* mFile;
};
nsresult nsresult
CollectKgslReports(nsIHandleReportCallback* aHandleReport, CollectKgslReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData) nsISupports* aData)