diff options
-rw-r--r-- | base/process_util.h | 20 | ||||
-rw-r--r-- | base/process_util_linux.cc | 36 | ||||
-rw-r--r-- | chrome/browser/chromeos/status/memory_menu_button.cc | 68 | ||||
-rw-r--r-- | chrome/browser/chromeos/status/memory_menu_button.h | 32 |
4 files changed, 109 insertions, 47 deletions
diff --git a/base/process_util.h b/base/process_util.h index acaa2d7..b98e266 100644 --- a/base/process_util.h +++ b/base/process_util.h @@ -657,11 +657,23 @@ class BASE_EXPORT ProcessMetrics { }; #if defined(OS_LINUX) +// Data from /proc/meminfo about system-wide memory consumption. +// Values are in KB. +struct SystemMemoryInfoKB { + SystemMemoryInfoKB() : total(0), free(0), buffers(0), cached(0), + active_anon(0), inactive_anon(0), shmem(0) {} + int total; + int free; + int buffers; + int cached; + int active_anon; + int inactive_anon; + int shmem; +}; // Retrieves data from /proc/meminfo about system-wide memory consumption. -// Values are in KB. Returns true on success. -BASE_EXPORT bool GetSystemMemoryInfo(int* total_kb, int* free_kb, - int* buffers_kb, int* cache_kb, - int* shmem_kb); +// Fills in the provided |meminfo| structure. Returns true on success. +// Exposed for memory debugging widget. +BASE_EXPORT bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo); #endif // Returns the memory committed by the system in KBytes. diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc index 3ea383f..1f71f4d 100644 --- a/base/process_util_linux.cc +++ b/base/process_util_linux.cc @@ -558,12 +558,13 @@ namespace { const size_t kMemTotalIndex = 1; const size_t kMemFreeIndex = 4; const size_t kMemBuffersIndex = 7; -const size_t kMemCacheIndex = 10; +const size_t kMemCachedIndex = 10; +const size_t kMemActiveAnonIndex = 22; +const size_t kMemInactiveAnonIndex = 25; } // namespace -bool GetSystemMemoryInfo(int* mem_total, int* mem_free, int* mem_buffers, - int* mem_cache, int* shmem) { +bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { // Synchronously reading files in /proc is safe. base::ThreadRestrictions::ScopedAllowIO allow_io; @@ -577,7 +578,7 @@ bool GetSystemMemoryInfo(int* mem_total, int* mem_free, int* mem_buffers, std::vector<std::string> meminfo_fields; SplitStringAlongWhitespace(meminfo_data, &meminfo_fields); - if (meminfo_fields.size() < kMemCacheIndex) { + if (meminfo_fields.size() < kMemCachedIndex) { LOG(WARNING) << "Failed to parse /proc/meminfo. Only found " << meminfo_fields.size() << " fields."; return false; @@ -586,20 +587,25 @@ bool GetSystemMemoryInfo(int* mem_total, int* mem_free, int* mem_buffers, DCHECK_EQ(meminfo_fields[kMemTotalIndex-1], "MemTotal:"); DCHECK_EQ(meminfo_fields[kMemFreeIndex-1], "MemFree:"); DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:"); - DCHECK_EQ(meminfo_fields[kMemCacheIndex-1], "Cached:"); - - base::StringToInt(meminfo_fields[kMemTotalIndex], mem_total); - base::StringToInt(meminfo_fields[kMemFreeIndex], mem_free); - base::StringToInt(meminfo_fields[kMemBuffersIndex], mem_buffers); - base::StringToInt(meminfo_fields[kMemCacheIndex], mem_cache); + DCHECK_EQ(meminfo_fields[kMemCachedIndex-1], "Cached:"); + DCHECK_EQ(meminfo_fields[kMemActiveAnonIndex-1], "Active(anon):"); + DCHECK_EQ(meminfo_fields[kMemInactiveAnonIndex-1], "Inactive(anon):"); + + base::StringToInt(meminfo_fields[kMemTotalIndex], &meminfo->total); + base::StringToInt(meminfo_fields[kMemFreeIndex], &meminfo->free); + base::StringToInt(meminfo_fields[kMemBuffersIndex], &meminfo->buffers); + base::StringToInt(meminfo_fields[kMemCachedIndex], &meminfo->cached); + base::StringToInt(meminfo_fields[kMemActiveAnonIndex], &meminfo->active_anon); + base::StringToInt(meminfo_fields[kMemInactiveAnonIndex], + &meminfo->inactive_anon); #if defined(OS_CHROMEOS) // Chrome OS has a tweaked kernel that allows us to query Shmem, which is // usually video memory otherwise invisible to the OS. Unfortunately, the // meminfo format varies on different hardware so we have to search for the // string. It always appears after "Cached:". - for (size_t i = kMemCacheIndex+2; i < meminfo_fields.size(); i += 3) { + for (size_t i = kMemCachedIndex+2; i < meminfo_fields.size(); i += 3) { if (meminfo_fields[i] == "Shmem:") { - base::StringToInt(meminfo_fields[i+1], shmem); + base::StringToInt(meminfo_fields[i+1], &meminfo->shmem); break; } } @@ -608,10 +614,10 @@ bool GetSystemMemoryInfo(int* mem_total, int* mem_free, int* mem_buffers, } size_t GetSystemCommitCharge() { - int total, free, buffers, cache, shmem; - if (!GetSystemMemoryInfo(&total, &free, &buffers, &cache, &shmem)) + SystemMemoryInfoKB meminfo; + if (!GetSystemMemoryInfo(&meminfo)) return 0; - return total - free - buffers - cache; + return meminfo.total - meminfo.free - meminfo.buffers - meminfo.cached; } namespace { diff --git a/chrome/browser/chromeos/status/memory_menu_button.cc b/chrome/browser/chromeos/status/memory_menu_button.cc index 606ebc1..634c985 100644 --- a/chrome/browser/chromeos/status/memory_menu_button.cc +++ b/chrome/browser/chromeos/status/memory_menu_button.cc @@ -8,6 +8,8 @@ #include "base/stringprintf.h" #include "chrome/browser/chromeos/status/status_area_host.h" #include "chrome/browser/memory_purger.h" +#include "content/browser/renderer_host/render_process_host.h" +#include "content/common/notification_service.h" #include "grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" #include "views/widget/widget.h" @@ -33,11 +35,12 @@ const int kUpdateIntervalSeconds = 5; MemoryMenuButton::MemoryMenuButton(StatusAreaHost* host) : StatusAreaButton(host, this), - mem_total_(0), - shmem_(0), - mem_free_(0), - mem_buffers_(0), - mem_cache_(0) { + meminfo_(new base::SystemMemoryInfoKB()), + renderer_kills_(0) { + // Track renderer kills, as the kernel OOM killer will start to kill our + // renderers as we run out of memory. + registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, + NotificationService::AllSources()); UpdateTextAndSetNextTimer(); } @@ -52,17 +55,20 @@ void MemoryMenuButton::UpdateTextAndSetNextTimer() { } void MemoryMenuButton::UpdateText() { - base::GetSystemMemoryInfo(&mem_total_, &mem_free_, &mem_buffers_, &mem_cache_, - &shmem_); - std::wstring label = base::StringPrintf(L"%d MB", mem_free_ / 1024); + base::GetSystemMemoryInfo(meminfo_.get()); + // "Anonymous" memory, meaning not mapped to a file (which has a name), + // represents memory that has been dynamically allocated to a process. + // It thus approximates heap memory usage across all processes. + int anon_kb = meminfo_->active_anon + meminfo_->inactive_anon; + std::wstring label = base::StringPrintf(L"%d MB (%d)", + anon_kb / 1024, + renderer_kills_); SetText(label); std::wstring tooltip = base::StringPrintf( - L"%d MB total\n%d MB free\n%d MB buffers\n%d MB cache\n%d MB shmem", - mem_total_ / 1024, - mem_free_ / 1024, - mem_buffers_ / 1024, - mem_cache_ / 1024, - shmem_ / 1024); + L"%d MB allocated (anonymous)\n" + L"%d renderer kill(s)", + anon_kb / 1024, + renderer_kills_); SetTooltipText(tooltip); SchedulePaint(); } @@ -71,15 +77,15 @@ void MemoryMenuButton::UpdateText() { std::wstring MemoryMenuButton::GetLabel(int id) const { switch (id) { case MEM_TOTAL_ITEM: - return StringPrintf(L"%d MB total", mem_total_ / 1024); + return StringPrintf(L"%d MB total", meminfo_->total / 1024); case MEM_FREE_ITEM: - return StringPrintf(L"%d MB free", mem_free_ / 1024); + return StringPrintf(L"%d MB free", meminfo_->free / 1024); case MEM_BUFFERS_ITEM: - return StringPrintf(L"%d MB buffers", mem_buffers_ / 1024); + return StringPrintf(L"%d MB buffers", meminfo_->buffers / 1024); case MEM_CACHE_ITEM: - return StringPrintf(L"%d MB cache", mem_cache_ / 1024); + return StringPrintf(L"%d MB cache", meminfo_->cached / 1024); case SHMEM_ITEM: - return StringPrintf(L"%d MB shmem", shmem_ / 1024); + return StringPrintf(L"%d MB shmem", meminfo_->shmem / 1024); case PURGE_MEMORY_ITEM: return L"Purge memory"; default: @@ -146,4 +152,28 @@ void MemoryMenuButton::EnsureMenu() { menu_->AppendDelegateMenuItem(PURGE_MEMORY_ITEM); } +///////////////////////////////////////////////////////////////////////////// +// NotificationObserver overrides. + +void MemoryMenuButton::Observe(int type, + const NotificationSource& source, + const NotificationDetails& details) { + switch (type) { + case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { + RenderProcessHost::RendererClosedDetails* process_details = + Details<RenderProcessHost::RendererClosedDetails>(details).ptr(); + if (process_details->status == + base::TERMINATION_STATUS_PROCESS_WAS_KILLED) { + renderer_kills_++; + // A kill is a very interesting event, so repaint immediately. + UpdateText(); + } + break; + } + default: + NOTREACHED() << L"Received unexpected notification"; + break; + } +} + } // namespace chromeos diff --git a/chrome/browser/chromeos/status/memory_menu_button.h b/chrome/browser/chromeos/status/memory_menu_button.h index feddcac..d404c39 100644 --- a/chrome/browser/chromeos/status/memory_menu_button.h +++ b/chrome/browser/chromeos/status/memory_menu_button.h @@ -9,9 +9,15 @@ #include "base/memory/scoped_ptr.h" #include "base/timer.h" #include "chrome/browser/chromeos/status/status_area_button.h" +#include "content/common/notification_observer.h" +#include "content/common/notification_registrar.h" #include "views/controls/menu/menu_delegate.h" #include "views/controls/menu/view_menu_delegate.h" +namespace base { +struct SystemMemoryInfoKB; +} + namespace views { class MenuItemView; } @@ -23,7 +29,8 @@ class StatusAreaHost; // Memory debugging display that lives in the status area. class MemoryMenuButton : public StatusAreaButton, public views::MenuDelegate, - public views::ViewMenuDelegate { + public views::ViewMenuDelegate, + public NotificationObserver { public: explicit MemoryMenuButton(StatusAreaHost* host); virtual ~MemoryMenuButton(); @@ -33,6 +40,14 @@ class MemoryMenuButton : public StatusAreaButton, virtual bool IsCommandEnabled(int id) const OVERRIDE; virtual void ExecuteCommand(int id) OVERRIDE; + // views::ViewMenuDelegate implementation. + virtual void RunMenu(views::View* source, const gfx::Point& pt) OVERRIDE; + + // NotificationObserver overrides. + virtual void Observe(int type, + const NotificationSource& source, + const NotificationDetails& details) OVERRIDE; + // Updates the text on the menu button. void UpdateText(); @@ -40,9 +55,6 @@ class MemoryMenuButton : public StatusAreaButton, virtual int horizontal_padding() OVERRIDE; private: - // views::ViewMenuDelegate implementation. - virtual void RunMenu(views::View* source, const gfx::Point& pt); - // Create and initialize menu if not already present. void EnsureMenu(); @@ -55,11 +67,13 @@ class MemoryMenuButton : public StatusAreaButton, // constructor. scoped_ptr<views::MenuItemView> menu_; - int mem_total_; - int shmem_; // video driver memory, hidden from OS - int mem_free_; - int mem_buffers_; - int mem_cache_; + // Raw data from /proc/meminfo + scoped_ptr<base::SystemMemoryInfoKB> meminfo_; + + NotificationRegistrar registrar_; + + // Number of renderer kills we have observed. + int renderer_kills_; DISALLOW_COPY_AND_ASSIGN(MemoryMenuButton); }; |