diff options
author | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-19 04:50:04 +0000 |
---|---|---|
committer | viettrungluu@chromium.org <viettrungluu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-12-19 04:50:04 +0000 |
commit | 3740cb9b54f6a5d28c3501b650b7c179101568eb (patch) | |
tree | 848c46b9b75018e0fc60edf715e068bf5cc87c24 /base | |
parent | 0ec9512a65f8d7f15dbddd902363994660d85ffb (diff) | |
download | chromium_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
Diffstat (limited to 'base')
-rw-r--r-- | base/process_util.h | 32 | ||||
-rw-r--r-- | base/process_util_mac.mm | 125 | ||||
-rw-r--r-- | base/process_util_posix.cc | 67 | ||||
-rw-r--r-- | base/trace_event.cc | 7 |
4 files changed, 177 insertions, 54 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() { |