summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-01 23:36:00 +0000
committerjamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-08-01 23:36:00 +0000
commitf31deb497a7543d9815131cf054ad7b0067f2508 (patch)
tree21e1b06cc163c6e1e1d09fb3ef2eeacaed9080f4
parent58f5ca425866f9b119929fb291fba420cd462542 (diff)
downloadchromium_src-f31deb497a7543d9815131cf054ad7b0067f2508.zip
chromium_src-f31deb497a7543d9815131cf054ad7b0067f2508.tar.gz
chromium_src-f31deb497a7543d9815131cf054ad7b0067f2508.tar.bz2
CrOS - Add memory consumption status bar widget behind flag
Pass --memory-widget on CrOS to get a real-time display, updated every 5 seconds, of the system's free memory. Tooltip and menu itself detail the data from /proc/meminfo. Also made base::GetSystemMemoryInfo() available on Linux systems to provide detailed data. BUG=chromium-os:18446 TEST=manual Review URL: http://codereview.chromium.org/7518010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@94999 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/process_util.h9
-rw-r--r--base/process_util_linux.cc36
-rw-r--r--chrome/browser/chromeos/status/memory_menu_button.cc166
-rw-r--r--chrome/browser/chromeos/status/memory_menu_button.h69
-rw-r--r--chrome/browser/chromeos/status/status_area_view.cc11
-rw-r--r--chrome/browser/chromeos/status/status_area_view.h2
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/common/chrome_switches.cc3
-rw-r--r--chrome/common/chrome_switches.h1
9 files changed, 289 insertions, 10 deletions
diff --git a/base/process_util.h b/base/process_util.h
index 3d9b7d1..5f88c62 100644
--- a/base/process_util.h
+++ b/base/process_util.h
@@ -653,7 +653,14 @@ class BASE_API ProcessMetrics {
DISALLOW_COPY_AND_ASSIGN(ProcessMetrics);
};
-// Returns the memory commited by the system in KBytes.
+#if defined(OS_LINUX)
+// Retrieves data from /proc/meminfo about system-wide memory consumption.
+// Values are in KB. Returns true on success.
+BASE_API bool GetSystemMemoryInfo(int* total_kb, int* free_kb, int* buffers_kb,
+ int* cache_kb, int* shmem_kb);
+#endif
+
+// Returns the memory committed by the system in KBytes.
// Returns 0 if it can't compute the commit charge.
BASE_API size_t GetSystemCommitCharge();
diff --git a/base/process_util_linux.cc b/base/process_util_linux.cc
index aabd201..3ea383f 100644
--- a/base/process_util_linux.cc
+++ b/base/process_util_linux.cc
@@ -562,7 +562,8 @@ const size_t kMemCacheIndex = 10;
} // namespace
-size_t GetSystemCommitCharge() {
+bool GetSystemMemoryInfo(int* mem_total, int* mem_free, int* mem_buffers,
+ int* mem_cache, int* shmem) {
// Synchronously reading files in /proc is safe.
base::ThreadRestrictions::ScopedAllowIO allow_io;
@@ -571,7 +572,7 @@ size_t GetSystemCommitCharge() {
std::string meminfo_data;
if (!file_util::ReadFileToString(meminfo_file, &meminfo_data)) {
LOG(WARNING) << "Failed to open /proc/meminfo.";
- return 0;
+ return false;
}
std::vector<std::string> meminfo_fields;
SplitStringAlongWhitespace(meminfo_data, &meminfo_fields);
@@ -579,7 +580,7 @@ size_t GetSystemCommitCharge() {
if (meminfo_fields.size() < kMemCacheIndex) {
LOG(WARNING) << "Failed to parse /proc/meminfo. Only found " <<
meminfo_fields.size() << " fields.";
- return 0;
+ return false;
}
DCHECK_EQ(meminfo_fields[kMemTotalIndex-1], "MemTotal:");
@@ -587,13 +588,30 @@ size_t GetSystemCommitCharge() {
DCHECK_EQ(meminfo_fields[kMemBuffersIndex-1], "Buffers:");
DCHECK_EQ(meminfo_fields[kMemCacheIndex-1], "Cached:");
- int mem_total, mem_free, mem_buffers, mem_cache;
- 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);
+ 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);
+#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) {
+ if (meminfo_fields[i] == "Shmem:") {
+ base::StringToInt(meminfo_fields[i+1], shmem);
+ break;
+ }
+ }
+#endif
+ return true;
+}
- return mem_total - mem_free - mem_buffers - mem_cache;
+size_t GetSystemCommitCharge() {
+ int total, free, buffers, cache, shmem;
+ if (!GetSystemMemoryInfo(&total, &free, &buffers, &cache, &shmem))
+ return 0;
+ return total - free - buffers - cache;
}
namespace {
diff --git a/chrome/browser/chromeos/status/memory_menu_button.cc b/chrome/browser/chromeos/status/memory_menu_button.cc
new file mode 100644
index 0000000..e19b50f
--- /dev/null
+++ b/chrome/browser/chromeos/status/memory_menu_button.cc
@@ -0,0 +1,166 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/status/memory_menu_button.h"
+
+#include "base/process_util.h" // GetSystemMemoryInfo
+#include "base/stringprintf.h"
+#include "chrome/browser/chromeos/status/status_area_host.h"
+#include "grit/generated_resources.h"
+#include "third_party/tcmalloc/chromium/src/google/heap-profiler.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "views/widget/widget.h"
+
+namespace {
+
+// views::MenuItemView item ids
+enum {
+ MEM_TOTAL_ITEM,
+ MEM_FREE_ITEM,
+ MEM_BUFFERS_ITEM,
+ MEM_CACHE_ITEM,
+ SHMEM_ITEM,
+ HEAP_PROFILE_START_ITEM,
+ HEAP_PROFILE_STOP_ITEM,
+};
+
+} // namespace
+
+namespace chromeos {
+
+// Delay between updates, in seconds.
+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) {
+ UpdateTextAndSetNextTimer();
+}
+
+MemoryMenuButton::~MemoryMenuButton() {
+}
+
+void MemoryMenuButton::UpdateTextAndSetNextTimer() {
+ UpdateText();
+
+ timer_.Start(base::TimeDelta::FromSeconds(kUpdateIntervalSeconds), this,
+ &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);
+ 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);
+ SetTooltipText(tooltip);
+ SchedulePaint();
+}
+
+// MemoryMenuButton, views::MenuDelegate implementation:
+std::wstring MemoryMenuButton::GetLabel(int id) const {
+ switch (id) {
+ case MEM_TOTAL_ITEM:
+ return StringPrintf(L"%d MB total", mem_total_ / 1024);
+ case MEM_FREE_ITEM:
+ return StringPrintf(L"%d MB free", mem_free_ / 1024);
+ case MEM_BUFFERS_ITEM:
+ return StringPrintf(L"%d MB buffers", mem_buffers_ / 1024);
+ case MEM_CACHE_ITEM:
+ return StringPrintf(L"%d MB cache", mem_cache_ / 1024);
+ case SHMEM_ITEM:
+ return StringPrintf(L"%d MB shmem", shmem_ / 1024);
+ case HEAP_PROFILE_START_ITEM:
+ return std::wstring(L"Start heap profile");
+ case HEAP_PROFILE_STOP_ITEM:
+ return std::wstring(L"Stop heap profile");
+ default:
+ return std::wstring();
+ }
+}
+
+bool MemoryMenuButton::IsCommandEnabled(int id) const {
+ switch (id) {
+ case MEM_TOTAL_ITEM:
+ case MEM_FREE_ITEM:
+ case MEM_BUFFERS_ITEM:
+ case MEM_CACHE_ITEM:
+ case SHMEM_ITEM:
+ return false;
+ case HEAP_PROFILE_START_ITEM:
+ return !IsHeapProfilerRunning();
+ case HEAP_PROFILE_STOP_ITEM:
+ return IsHeapProfilerRunning();
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+void MemoryMenuButton::ExecuteCommand(int id) {
+ switch (id) {
+ case HEAP_PROFILE_START_ITEM:
+ HeapProfilerStart("/tmp/heap");
+ break;
+ case HEAP_PROFILE_STOP_ITEM:
+ HeapProfilerDump("Heap profile stopped");
+ HeapProfilerStop();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+int MemoryMenuButton::horizontal_padding() {
+ return 3;
+}
+
+// MemoryMenuButton, views::ViewMenuDelegate implementation:
+
+void MemoryMenuButton::RunMenu(views::View* source, const gfx::Point& pt) {
+ // View passed in must be a views::MenuButton, i.e. the MemoryMenuButton.
+ DCHECK_EQ(source, this);
+
+ EnsureMenu();
+
+ gfx::Point screen_location;
+ views::View::ConvertPointToScreen(source, &screen_location);
+ gfx::Rect bounds(screen_location, source->size());
+ menu_->RunMenuAt(
+ source->GetWidget()->GetTopLevelWidget(),
+ this,
+ bounds,
+ views::MenuItemView::TOPRIGHT,
+ true);
+}
+
+// MemoryMenuButton, views::View implementation:
+
+void MemoryMenuButton::EnsureMenu() {
+ // Just rebuild the menu each time to ensure the labels are up-to-date.
+ menu_.reset(new views::MenuItemView(this));
+ // Text for these items will be set by GetLabel().
+ menu_->AppendDelegateMenuItem(MEM_TOTAL_ITEM);
+ menu_->AppendDelegateMenuItem(MEM_FREE_ITEM);
+ menu_->AppendDelegateMenuItem(MEM_BUFFERS_ITEM);
+ menu_->AppendDelegateMenuItem(MEM_CACHE_ITEM);
+ menu_->AppendDelegateMenuItem(SHMEM_ITEM);
+ menu_->AppendSeparator();
+ // TODO(jamescook): Add items to run memory_purger, dump tcmalloc stats.
+ menu_->AppendDelegateMenuItem(HEAP_PROFILE_START_ITEM);
+ menu_->AppendDelegateMenuItem(HEAP_PROFILE_STOP_ITEM);
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/status/memory_menu_button.h b/chrome/browser/chromeos/status/memory_menu_button.h
new file mode 100644
index 0000000..c399df7
--- /dev/null
+++ b/chrome/browser/chromeos/status/memory_menu_button.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_STATUS_MEMORY_MENU_BUTTON_H_
+#define CHROME_BROWSER_CHROMEOS_STATUS_MEMORY_MENU_BUTTON_H_
+#pragma once
+
+#include "base/memory/scoped_ptr.h"
+#include "base/timer.h"
+#include "chrome/browser/chromeos/status/status_area_button.h"
+#include "views/controls/menu/menu_delegate.h"
+#include "views/controls/menu/view_menu_delegate.h"
+
+namespace views {
+class MenuItemView;
+}
+
+namespace chromeos {
+
+class StatusAreaHost;
+
+// Memory debugging display that lives in the status area.
+class MemoryMenuButton : public StatusAreaButton,
+ public views::MenuDelegate,
+ public views::ViewMenuDelegate {
+ public:
+ explicit MemoryMenuButton(StatusAreaHost* host);
+ virtual ~MemoryMenuButton();
+
+ // views::MenuDelegate implementation
+ virtual std::wstring GetLabel(int id) const OVERRIDE;
+ virtual bool IsCommandEnabled(int id) const OVERRIDE;
+ virtual void ExecuteCommand(int id) OVERRIDE;
+
+ // Updates the text on the menu button.
+ void UpdateText();
+
+ protected:
+ virtual int horizontal_padding();
+
+ private:
+ // views::ViewMenuDelegate implementation.
+ virtual void RunMenu(views::View* source, const gfx::Point& pt);
+
+ // Create and initialize menu if not already present.
+ void EnsureMenu();
+
+ // Updates text and schedules the timer to fire at the next minute interval.
+ void UpdateTextAndSetNextTimer();
+
+ base::OneShotTimer<MemoryMenuButton> timer_;
+
+ // NOTE: we use a scoped_ptr here as menu calls into 'this' from the
+ // 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_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryMenuButton);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_STATUS_MEMORY_MENU_BUTTON_H_
diff --git a/chrome/browser/chromeos/status/status_area_view.cc b/chrome/browser/chromeos/status/status_area_view.cc
index 161edfb..b87ca3c 100644
--- a/chrome/browser/chromeos/status/status_area_view.cc
+++ b/chrome/browser/chromeos/status/status_area_view.cc
@@ -6,12 +6,15 @@
#include <algorithm>
+#include "base/command_line.h"
#include "chrome/browser/chromeos/status/caps_lock_menu_button.h"
#include "chrome/browser/chromeos/status/clock_menu_button.h"
#include "chrome/browser/chromeos/status/input_method_menu_button.h"
+#include "chrome/browser/chromeos/status/memory_menu_button.h"
#include "chrome/browser/chromeos/status/network_menu_button.h"
#include "chrome/browser/chromeos/status/power_menu_button.h"
#include "chrome/browser/chromeos/status/status_area_host.h"
+#include "chrome/common/chrome_switches.h"
#include "grit/theme_resources.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas.h"
@@ -32,11 +35,17 @@ StatusAreaView::StatusAreaView(StatusAreaHost* host)
caps_lock_view_(NULL),
clock_view_(NULL),
input_method_view_(NULL),
+ memory_view_(NULL),
network_view_(NULL),
power_view_(NULL) {
}
void StatusAreaView::Init() {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kMemoryWidget)) {
+ memory_view_ = new MemoryMenuButton(host_);
+ AddChildView(memory_view_);
+ }
+
caps_lock_view_ = new CapsLockMenuButton(host_);
caps_lock_view_->set_border(views::Border::CreateEmptyBorder(0, 1, 0, 0));
AddChildView(caps_lock_view_);
@@ -102,6 +111,8 @@ void StatusAreaView::ChildPreferredSizeChanged(View* child) {
}
void StatusAreaView::MakeButtonsActive(bool active) {
+ if (memory_view_)
+ memory_view_->set_active(active);
clock_view()->set_active(active);
input_method_view()->set_active(active);
network_view()->set_active(active);
diff --git a/chrome/browser/chromeos/status/status_area_view.h b/chrome/browser/chromeos/status/status_area_view.h
index dc8c801..ec43087 100644
--- a/chrome/browser/chromeos/status/status_area_view.h
+++ b/chrome/browser/chromeos/status/status_area_view.h
@@ -15,6 +15,7 @@ namespace chromeos {
class CapsLockMenuButton;
class ClockMenuButton;
class InputMethodMenuButton;
+class MemoryMenuButton;
class NetworkMenuButton;
class PowerMenuButton;
class StatusAreaHost;
@@ -47,6 +48,7 @@ class StatusAreaView : public AccessiblePaneView {
CapsLockMenuButton* caps_lock_view_;
ClockMenuButton* clock_view_;
InputMethodMenuButton* input_method_view_;
+ MemoryMenuButton* memory_view_;
NetworkMenuButton* network_view_;
PowerMenuButton* power_view_;
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 94a7158..66b2e19 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -710,6 +710,8 @@
'browser/chromeos/status/input_method_menu.h',
'browser/chromeos/status/input_method_menu_button.cc',
'browser/chromeos/status/input_method_menu_button.h',
+ 'browser/chromeos/status/memory_menu_button.cc',
+ 'browser/chromeos/status/memory_menu_button.h',
'browser/chromeos/status/network_dropdown_button.cc',
'browser/chromeos/status/network_dropdown_button.h',
'browser/chromeos/status/network_menu.cc',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 1db0e04..e100d59 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1061,6 +1061,9 @@ const char kLoginScreen[] = "login-screen";
// Allows control over the initial login screen size. Pass width,height.
const char kLoginScreenSize[] = "login-screen-size";
+// Shows a memory consumption status area widget for OOM debugging.
+const char kMemoryWidget[] = "memory-widget";
+
// Attempts to load libcros and validate it, then exits. A nonzero return code
// means the library could not be loaded correctly.
const char kTestLoadLibcros[] = "test-load-libcros";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 6b0c375..5cc034c 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -292,6 +292,7 @@ extern const char kLoginManager[];
// purposes.
extern const char kLoginScreen[];
extern const char kLoginScreenSize[];
+extern const char kMemoryWidget[];
extern const char kTestLoadLibcros[];
extern const char kLoginProfile[];
extern const char kLoginUser[];