diff --git a/xpcom/base/SystemMemoryReporter.cpp b/xpcom/base/SystemMemoryReporter.cpp index 38a2c4990ee..41516bbd162 100644 --- a/xpcom/base/SystemMemoryReporter.cpp +++ b/xpcom/base/SystemMemoryReporter.cpp @@ -46,6 +46,26 @@ namespace SystemMemoryReporter { #error "This won't work if we're not on Linux." #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 EndsWithLiteral(const nsCString& aHaystack, const char* aNeedle) { @@ -180,6 +200,10 @@ public: rv = CollectKgslReports(aHandleReport, aData); NS_ENSURE_SUCCESS(rv, rv); + // Report ION memory usage. + rv = CollectIonReports(aHandleReport, aData); + NS_ENSURE_SUCCESS(rv, rv); + return rv; } @@ -680,6 +704,106 @@ private: 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 + // ---------------------------------------------------- + // + // + // 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 ReadSizeFromFile(const char* aFilename) { @@ -866,20 +990,6 @@ private: 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 CollectKgslReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)