summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-19 04:50:04 +0000
committerviettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-19 04:50:04 +0000
commit3740cb9b54f6a5d28c3501b650b7c179101568eb (patch)
tree848c46b9b75018e0fc60edf715e068bf5cc87c24
parent0ec9512a65f8d7f15dbddd902363994660d85ffb (diff)
downloadchromium_src-3740cb9b54f6a5d28c3501b650b7c179101568eb.zip
chromium_src-3740cb9b54f6a5d28c3501b650b7c179101568eb.tar.gz
chromium_src-3740cb9b54f6a5d28c3501b650b7c179101568eb.tar.bz2
Revert 35025 - Revert 34994, maybe it regressed startup perf Fix cpu/memory measurements on OS X.
Right now, this only works for the current process; support for child processes will be added in a later CL. BUG=13156,25454 TEST=Hook up task manager (connect menu item to commandDispatch:, give it the right tag). Stats for the browser process should now be right, and %cpu should be 0 (for now) for all other processes. Review URL: http://codereview.chromium.org/500118 TBR=thakis@chromium.org Review URL: http://codereview.chromium.org/504068 TBR=thakis@chromium.org Review URL: http://codereview.chromium.org/505056 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35043 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/process_util.h32
-rw-r--r--base/process_util_mac.mm125
-rw-r--r--base/process_util_posix.cc67
-rw-r--r--base/trace_event.cc7
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_database_unittest.cc5
-rw-r--r--chrome/browser/task_manager.cc13
-rw-r--r--chrome/common/mach_ipc_mac.h5
-rw-r--r--chrome/common/mach_ipc_mac.mm8
-rw-r--r--chrome/test/chrome_process_util.h7
-rw-r--r--webkit/glue/webkitclient_impl.cc7
10 files changed, 212 insertions, 64 deletions
diff --git a/base/process_util.h b/base/process_util.h
index 1122de7..2bb5396 100644
--- a/base/process_util.h
+++ b/base/process_util.h
@@ -317,6 +317,11 @@ class NamedProcessIterator {
// priv: Pages mapped only by this process
// shared: PSS or 0 if the kernel doesn't support this
// shareable: 0
+//
+// On OS X: TODO(thakis): Revise.
+// priv: Memory.
+// shared: 0
+// shareable: 0
struct WorkingSetKBytes {
WorkingSetKBytes() : priv(0), shareable(0), shared(0) {}
size_t priv;
@@ -359,7 +364,23 @@ class ProcessMetrics {
public:
// Creates a ProcessMetrics for the specified process.
// The caller owns the returned object.
+#if !defined(OS_MACOSX)
static ProcessMetrics* CreateProcessMetrics(ProcessHandle process);
+#else
+ class PortProvider {
+ public:
+ // Should return the mach task for |process| if possible, or else 0. Only
+ // processes that this returns tasks for will have metrics on OS X (except
+ // for the current process, which always gets metrics).
+ virtual mach_port_t TaskForPid(ProcessHandle process) const = 0;
+ };
+
+ // The port provider needs to outlive the ProcessMetrics object returned by
+ // this function. If NULL is passed as provider, the returned object
+ // only returns valid metrics if |process| is the current process.
+ static ProcessMetrics* CreateProcessMetrics(ProcessHandle process,
+ PortProvider* port_provider);
+#endif
~ProcessMetrics();
@@ -407,7 +428,11 @@ class ProcessMetrics {
bool GetIOCounters(IoCounters* io_counters) const;
private:
+#if !defined(OS_MACOSX)
explicit ProcessMetrics(ProcessHandle process);
+#else
+ ProcessMetrics(ProcessHandle process, PortProvider* port_provider);
+#endif
ProcessHandle process_;
@@ -423,6 +448,13 @@ class ProcessMetrics {
int last_cpu_;
#endif
+#if defined(OS_MACOSX)
+ // Queries the port provider if it's set.
+ mach_port_t TaskForPid(ProcessHandle process) const;
+
+ PortProvider* port_provider_;
+#endif
+
DISALLOW_EVIL_CONSTRUCTORS(ProcessMetrics);
};
diff --git a/base/process_util_mac.mm b/base/process_util_mac.mm
index 91944e8..dd4dc37 100644
--- a/base/process_util_mac.mm
+++ b/base/process_util_mac.mm
@@ -182,23 +182,46 @@ bool NamedProcessIterator::IncludeEntry() {
// ------------------------------------------------------------------------
// NOTE: about ProcessMetrics
//
-// Mac doesn't have /proc, and getting a mach task from a pid for another
-// process requires permissions, so there doesn't really seem to be a way
-// to do these (and spinning up ps to fetch each stats seems dangerous to
-// put in a base api for anyone to call.
+// Getting a mach task from a pid for another process requires permissions in
+// general, so there doesn't really seem to be a way to do these (and spinning
+// up ps to fetch each stats seems dangerous to put in a base api for anyone to
+// call). Child processes ipc their port, so return something if available,
+// otherwise return 0.
//
bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
return false;
}
+
+static bool GetTaskInfo(mach_port_t task, task_basic_info_64* task_info_data) {
+ if (!task)
+ return false;
+ mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
+ kern_return_t kr = task_info(task,
+ TASK_BASIC_INFO_64,
+ reinterpret_cast<task_info_t>(task_info_data),
+ &count);
+ // Most likely cause for failure: |task| is a zombie.
+ return kr == KERN_SUCCESS;
+}
+
size_t ProcessMetrics::GetPagefileUsage() const {
- return 0;
+ task_basic_info_64 task_info_data;
+ if (!GetTaskInfo(TaskForPid(process_), &task_info_data))
+ return 0;
+ return task_info_data.virtual_size;
}
+
size_t ProcessMetrics::GetPeakPagefileUsage() const {
return 0;
}
+
size_t ProcessMetrics::GetWorkingSetSize() const {
- return 0;
+ task_basic_info_64 task_info_data;
+ if (!GetTaskInfo(TaskForPid(process_), &task_info_data))
+ return 0;
+ return task_info_data.resident_size;
}
+
size_t ProcessMetrics::GetPeakWorkingSetSize() const {
return 0;
}
@@ -211,7 +234,95 @@ void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const {
}
bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
- return false;
+ size_t priv = GetWorkingSetSize();
+ if (!priv)
+ return false;
+ ws_usage->priv = priv / 1024;
+ ws_usage->shareable = 0;
+ ws_usage->shared = 0;
+ return true;
+}
+
+#define TIME_VALUE_TO_TIMEVAL(a, r) do { \
+ (r)->tv_sec = (a)->seconds; \
+ (r)->tv_usec = (a)->microseconds; \
+} while (0)
+
+int ProcessMetrics::GetCPUUsage() {
+ mach_port_t task = TaskForPid(process_);
+ if (!task)
+ return 0;
+
+ kern_return_t kr;
+
+ // TODO(thakis): Libtop doesn't use thread info. How can they get away
+ // without it?
+ task_thread_times_info thread_info_data;
+ mach_msg_type_number_t thread_info_count = TASK_THREAD_TIMES_INFO_COUNT;
+ kr = task_info(task,
+ TASK_THREAD_TIMES_INFO,
+ reinterpret_cast<task_info_t>(&thread_info_data),
+ &thread_info_count);
+ if (kr != KERN_SUCCESS) {
+ // Most likely cause: |task| is a zombie.
+ return 0;
+ }
+
+ task_basic_info_64 task_info_data;
+ if (!GetTaskInfo(task, &task_info_data))
+ return 0;
+
+ /* Set total_time. */
+ // thread info contains live time...
+ struct timeval user_timeval, system_timeval, task_timeval;
+ TIME_VALUE_TO_TIMEVAL(&thread_info_data.user_time, &user_timeval);
+ TIME_VALUE_TO_TIMEVAL(&thread_info_data.system_time, &system_timeval);
+ timeradd(&user_timeval, &system_timeval, &task_timeval);
+
+ // ... task info contains terminated time.
+ TIME_VALUE_TO_TIMEVAL(&task_info_data.user_time, &user_timeval);
+ TIME_VALUE_TO_TIMEVAL(&task_info_data.system_time, &system_timeval);
+ timeradd(&user_timeval, &task_timeval, &task_timeval);
+ timeradd(&system_timeval, &task_timeval, &task_timeval);
+
+ struct timeval now;
+ int retval = gettimeofday(&now, NULL);
+ if (retval)
+ return 0;
+
+ int64 time = TimeValToMicroseconds(now);
+ int64 task_time = TimeValToMicroseconds(task_timeval);
+
+ if ((last_system_time_ == 0) || (last_time_ == 0)) {
+ // First call, just set the last values.
+ last_system_time_ = task_time;
+ last_time_ = time;
+ return 0;
+ }
+
+ int64 system_time_delta = task_time - last_system_time_;
+ int64 time_delta = time - last_time_;
+ DCHECK(time_delta != 0);
+ if (time_delta == 0)
+ return 0;
+
+ // We add time_delta / 2 so the result is rounded.
+ int cpu = static_cast<int>((system_time_delta * 100 + time_delta / 2) /
+ (time_delta));
+
+ last_system_time_ = task_time;
+ last_time_ = time;
+
+ return cpu;
+}
+
+mach_port_t ProcessMetrics::TaskForPid(ProcessHandle process) const {
+ mach_port_t task = 0;
+ if (port_provider_)
+ task = port_provider_->TaskForPid(process_);
+ if (!task && process_ == getpid())
+ task = mach_task_self();
+ return task;
}
// ------------------------------------------------------------------------
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc
index 4392c7b..16469db 100644
--- a/base/process_util_posix.cc
+++ b/base/process_util_posix.cc
@@ -360,20 +360,36 @@ bool LaunchApp(const CommandLine& cl,
return LaunchApp(cl.argv(), no_files, wait, process_handle);
}
-ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process),
- last_time_(0),
- last_system_time_(0)
+#if !defined(OS_MACOSX)
+ProcessMetrics::ProcessMetrics(ProcessHandle process)
+#else
+ProcessMetrics::ProcessMetrics(ProcessHandle process,
+ ProcessMetrics::PortProvider* port_provider)
+#endif
+ : process_(process),
+ last_time_(0),
+ last_system_time_(0)
#if defined(OS_LINUX)
- , last_cpu_(0)
+ , last_cpu_(0)
+#elif defined (OS_MACOSX)
+ , port_provider_(port_provider)
#endif
{
processor_count_ = base::SysInfo::NumberOfProcessors();
}
// static
+#if !defined(OS_MACOSX)
ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
return new ProcessMetrics(process);
}
+#else
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(
+ ProcessHandle process,
+ ProcessMetrics::PortProvider* port_provider) {
+ return new ProcessMetrics(process, port_provider);
+}
+#endif
ProcessMetrics::~ProcessMetrics() { }
@@ -494,49 +510,6 @@ int64 TimeValToMicroseconds(const struct timeval& tv) {
return tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec;
}
-#if defined(OS_MACOSX)
-// TODO(port): this function only returns the *current* CPU's usage;
-// we want to return this->process_'s CPU usage.
-int ProcessMetrics::GetCPUUsage() {
- struct timeval now;
- struct rusage usage;
-
- int retval = gettimeofday(&now, NULL);
- if (retval)
- return 0;
- retval = getrusage(RUSAGE_SELF, &usage);
- if (retval)
- return 0;
-
- int64 system_time = (TimeValToMicroseconds(usage.ru_stime) +
- TimeValToMicroseconds(usage.ru_utime)) /
- processor_count_;
- int64 time = TimeValToMicroseconds(now);
-
- if ((last_system_time_ == 0) || (last_time_ == 0)) {
- // First call, just set the last values.
- last_system_time_ = system_time;
- last_time_ = time;
- return 0;
- }
-
- int64 system_time_delta = system_time - last_system_time_;
- int64 time_delta = time - last_time_;
- DCHECK(time_delta != 0);
- if (time_delta == 0)
- return 0;
-
- // We add time_delta / 2 so the result is rounded.
- int cpu = static_cast<int>((system_time_delta * 100 + time_delta / 2) /
- time_delta);
-
- last_system_time_ = system_time;
- last_time_ = time;
-
- return cpu;
-}
-#endif
-
// Executes the application specified by |cl| and wait for it to exit. Stores
// the output (stdout) in |output|. If |do_search_path| is set, it searches the
// path for the application; in that case, |envp| must be null, and it will use
diff --git a/base/trace_event.cc b/base/trace_event.cc
index 13c0c2c..ff834ea 100644
--- a/base/trace_event.cc
+++ b/base/trace_event.cc
@@ -29,7 +29,14 @@ static const FilePath::CharType* kLogFileName =
TraceLog::TraceLog() : enabled_(false), log_file_(NULL) {
base::ProcessHandle proc = base::GetCurrentProcessHandle();
+#if !defined(OS_MACOSX)
process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(proc));
+#else
+ // The default port provider is sufficient to get data for the current
+ // process.
+ process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(proc,
+ NULL));
+#endif
}
TraceLog::~TraceLog() {
diff --git a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
index 3d244c0..30f9de4 100644
--- a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc
@@ -1078,7 +1078,12 @@ void PeformUpdate(const std::wstring& initial_db,
Time before_time = Time::Now();
base::ProcessHandle handle = base::Process::Current().handle();
scoped_ptr<base::ProcessMetrics> metric(
+#if !defined(OS_MACOSX)
base::ProcessMetrics::CreateProcessMetrics(handle));
+#else
+ // Getting stats only for the current process is enough, so NULL is fine.
+ base::ProcessMetrics::CreateProcessMetrics(handle, NULL));
+#endif
CHECK(metric->GetIOCounters(&before));
std::vector<SBListChunkRanges> lists;
diff --git a/chrome/browser/task_manager.cc b/chrome/browser/task_manager.cc
index 43952a5..edd7b37 100644
--- a/chrome/browser/task_manager.cc
+++ b/chrome/browser/task_manager.cc
@@ -533,7 +533,14 @@ void TaskManagerModel::AddResource(TaskManager::Resource* resource) {
// Create the ProcessMetrics for this process if needed (not in map).
if (metrics_map_.find(process) == metrics_map_.end()) {
base::ProcessMetrics* pm =
+#if !defined(OS_MACOSX)
base::ProcessMetrics::CreateProcessMetrics(process);
+#else
+ // TODO(thakis): Write a port provider that knows the task ports of
+ // child processes.
+ base::ProcessMetrics::CreateProcessMetrics(process, NULL);
+#endif
+
metrics_map_[process] = pm;
}
@@ -770,12 +777,12 @@ void TaskManagerModel::OnJobRemoved(URLRequestJob* job) {
}
void TaskManagerModel::OnJobDone(URLRequestJob* job,
- const URLRequestStatus& status) {
+ const URLRequestStatus& status) {
}
void TaskManagerModel::OnJobRedirect(URLRequestJob* job,
- const GURL& location,
- int status_code) {
+ const GURL& location,
+ int status_code) {
}
void TaskManagerModel::OnBytesRead(URLRequestJob* job, int byte_count) {
diff --git a/chrome/common/mach_ipc_mac.h b/chrome/common/mach_ipc_mac.h
index 8c345dd..42b9c65 100644
--- a/chrome/common/mach_ipc_mac.h
+++ b/chrome/common/mach_ipc_mac.h
@@ -167,8 +167,9 @@ class MachMessage {
bool AddDescriptor(const MachMsgPortDescriptor &desc);
int GetDescriptorCount() const {
- return storage_->body.msgh_descriptor_count;
- }
+ return storage_->body.msgh_descriptor_count;
+ }
+
MachMsgPortDescriptor *GetDescriptor(int n);
// Convenience method which gets the mach port described by the descriptor
diff --git a/chrome/common/mach_ipc_mac.mm b/chrome/common/mach_ipc_mac.mm
index 3c95ef6..7693d9a 100644
--- a/chrome/common/mach_ipc_mac.mm
+++ b/chrome/common/mach_ipc_mac.mm
@@ -213,10 +213,10 @@ ReceivePort::ReceivePort() {
if (init_result_ != KERN_SUCCESS)
return;
- init_result_ = mach_port_insert_right(current_task,
- port_,
- port_,
- MACH_MSG_TYPE_MAKE_SEND);
+ init_result_ = mach_port_insert_right(current_task,
+ port_,
+ port_,
+ MACH_MSG_TYPE_MAKE_SEND);
}
//==============================================================================
diff --git a/chrome/test/chrome_process_util.h b/chrome/test/chrome_process_util.h
index 19a5446..4fb1513 100644
--- a/chrome/test/chrome_process_util.h
+++ b/chrome/test/chrome_process_util.h
@@ -57,7 +57,12 @@ class ChromeTestProcessMetrics {
private:
explicit ChromeTestProcessMetrics(base::ProcessHandle process) {
- process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(process));
+ process_metrics_.reset(
+#if !defined(OS_MACOSX)
+ base::ProcessMetrics::CreateProcessMetrics(process));
+#else
+ base::ProcessMetrics::CreateProcessMetrics(process, NULL));
+#endif
process_handle_ = process;
}
diff --git a/webkit/glue/webkitclient_impl.cc b/webkit/glue/webkitclient_impl.cc
index 340a28c..c7673cf 100644
--- a/webkit/glue/webkitclient_impl.cc
+++ b/webkit/glue/webkitclient_impl.cc
@@ -318,7 +318,14 @@ WebKit::WebString WebKitClientImpl::signedPublicKeyAndChallengeString(
size_t WebKitClientImpl::memoryUsageMB() {
using base::ProcessMetrics;
static ProcessMetrics* process_metrics =
+#if !defined(OS_MACOSX)
ProcessMetrics::CreateProcessMetrics(base::GetCurrentProcessHandle());
+#else
+ // The default port provider is sufficient to get data for the current
+ // process.
+ ProcessMetrics::CreateProcessMetrics(base::GetCurrentProcessHandle(),
+ NULL);
+#endif
DCHECK(process_metrics);
return process_metrics->GetPagefileUsage() >> 20;
}