PerformanceDarwin.cpp revision 88e68b19b8e610f11783a271c548281b976e706a
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync/* $Id$ */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync/** @file
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync *
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync * VBox Darwin-specific Performance Classes implementation.
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync */
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync/*
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync * Copyright (C) 2008 Sun Microsystems, Inc.
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync *
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync * available from http://www.virtualbox.org. This file is free software;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync * you can redistribute it and/or modify it under the terms of the GNU
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync * General Public License (GPL) as published by the Free Software
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync *
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync * additional information or have any questions.
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync#include <iprt/stdint.h>
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync#include <mach/mach_error.h>
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync#include <mach/mach_host.h>
3d0f3ca0cd1069534be3ea175f883f1f53b69bdbvboxsync#include <mach/mach_init.h>
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync#include <mach/mach_time.h>
ba6206b9b2f863489c4b95178af0dbda929f6cc1vboxsync#include <mach/vm_statistics.h>
ba6206b9b2f863489c4b95178af0dbda929f6cc1vboxsync#include <sys/sysctl.h>
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync#include <sys/errno.h>
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync#include <iprt/err.h>
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync#include <iprt/log.h>
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync#include <iprt/param.h>
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync#include "Performance.h"
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync/* The following declarations are missing in 10.4.x SDK */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync/* @todo Replace them with libproc.h and sys/proc_info.h when 10.4 is no longer supported */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsyncextern "C" int proc_pidinfo(int pid, int flavor, uint64_t arg, void *buffer, int buffersize);
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsyncstruct proc_taskinfo {
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync uint64_t pti_virtual_size; /* virtual memory size (bytes) */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync uint64_t pti_resident_size; /* resident memory size (bytes) */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync uint64_t pti_total_user; /* total time */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync uint64_t pti_total_system;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync uint64_t pti_threads_user; /* existing threads only */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync uint64_t pti_threads_system;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int32_t pti_policy; /* default policy for new threads */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int32_t pti_faults; /* number of page faults */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int32_t pti_pageins; /* number of actual pageins */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int32_t pti_cow_faults; /* number of copy-on-write faults */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int32_t pti_messages_sent; /* number of messages sent */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int32_t pti_messages_received; /* number of messages received */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int32_t pti_syscalls_mach; /* number of mach system calls */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int32_t pti_syscalls_unix; /* number of unix system calls */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int32_t pti_csw; /* number of context switches */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int32_t pti_threadnum; /* number of threads in the task */
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int32_t pti_numrunning; /* number of running threads */
082180a39ac3c7041b0e7f70e77c735a55baec15vboxsync int32_t pti_priority; /* task priority*/
082180a39ac3c7041b0e7f70e77c735a55baec15vboxsync};
082180a39ac3c7041b0e7f70e77c735a55baec15vboxsync#define PROC_PIDTASKINFO 4
db328d9a0c557c268222858740db4860d4f22a95vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsyncnamespace pm {
db328d9a0c557c268222858740db4860d4f22a95vboxsync
db328d9a0c557c268222858740db4860d4f22a95vboxsyncclass CollectorDarwin : public CollectorHAL
db328d9a0c557c268222858740db4860d4f22a95vboxsync{
db328d9a0c557c268222858740db4860d4f22a95vboxsyncpublic:
db328d9a0c557c268222858740db4860d4f22a95vboxsync virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle);
db328d9a0c557c268222858740db4860d4f22a95vboxsync virtual int getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available);
db328d9a0c557c268222858740db4860d4f22a95vboxsync virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total);
db328d9a0c557c268222858740db4860d4f22a95vboxsync virtual int getProcessMemoryUsage(RTPROCESS process, ULONG *used);
db328d9a0c557c268222858740db4860d4f22a95vboxsync};
db328d9a0c557c268222858740db4860d4f22a95vboxsync
db328d9a0c557c268222858740db4860d4f22a95vboxsyncMetricFactoryDarwin::MetricFactoryDarwin()
db328d9a0c557c268222858740db4860d4f22a95vboxsync{
db328d9a0c557c268222858740db4860d4f22a95vboxsync mHAL = new CollectorDarwin();
db328d9a0c557c268222858740db4860d4f22a95vboxsync Assert(mHAL);
db328d9a0c557c268222858740db4860d4f22a95vboxsync}
db328d9a0c557c268222858740db4860d4f22a95vboxsync
db328d9a0c557c268222858740db4860d4f22a95vboxsyncint CollectorDarwin::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle)
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync{
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync kern_return_t krc;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync mach_msg_type_number_t count;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync host_cpu_load_info_data_t info;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync count = HOST_CPU_LOAD_INFO_COUNT;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync krc = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&info, &count);
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync if (krc != KERN_SUCCESS)
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync {
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync Log(("host_statistics() -> %s", mach_error_string(krc)));
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync return RTErrConvertFromDarwinKern(krc);
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync }
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync *user = (uint64_t)info.cpu_ticks[CPU_STATE_USER]
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync + info.cpu_ticks[CPU_STATE_NICE];
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync *kernel = (uint64_t)info.cpu_ticks[CPU_STATE_SYSTEM];
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync *idle = (uint64_t)info.cpu_ticks[CPU_STATE_IDLE];
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync return VINF_SUCCESS;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync}
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsyncint CollectorDarwin::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available)
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync{
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync kern_return_t krc;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync mach_msg_type_number_t count;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync vm_statistics_data_t info;
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync count = HOST_VM_INFO_COUNT;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync krc = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&info, &count);
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync if (krc != KERN_SUCCESS)
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync {
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync Log(("host_statistics() -> %s", mach_error_string(krc)));
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync return RTErrConvertFromDarwinKern(krc);
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync }
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync uint64_t hostMemory;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int mib[2];
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync size_t size;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync mib[0] = CTL_HW;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync mib[1] = HW_MEMSIZE;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync size = sizeof(hostMemory);
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync if (sysctl(mib, 2, &hostMemory, &size, NULL, 0) == -1) {
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync int error = errno;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync Log(("sysctl() -> %s", strerror(error)));
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync return RTErrConvertFromErrno(error);
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync }
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync *total = (ULONG)(hostMemory / 1024);
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync *available = info.free_count * (PAGE_SIZE / 1024);
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync *used = *total - *available;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync return VINF_SUCCESS;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync}
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsyncstatic int getProcessInfo(RTPROCESS process, struct proc_taskinfo *tinfo)
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync{
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int nb = proc_pidinfo(process, PROC_PIDTASKINFO, 0, tinfo, sizeof(*tinfo));
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync if (nb <= 0)
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync {
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int rc = errno;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync Log(("proc_pidinfo() -> %s", strerror(rc)));
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync return RTErrConvertFromDarwin(rc);
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync }
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync else if (nb < sizeof(*tinfo))
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync {
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync Log(("proc_pidinfo() -> too few bytes %d", nb));
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync return VERR_INTERNAL_ERROR;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync }
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync return VINF_SUCCESS;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync}
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsyncint CollectorDarwin::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total)
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync{
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync struct proc_taskinfo tinfo;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int rc = getProcessInfo(process, &tinfo);
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync if (RT_SUCCESS(rc))
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync {
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync *user = tinfo.pti_total_user;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync *kernel = tinfo.pti_total_system;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync *total = mach_absolute_time();
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync }
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync return rc;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync}
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsyncint CollectorDarwin::getProcessMemoryUsage(RTPROCESS process, ULONG *used)
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync{
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync struct proc_taskinfo tinfo;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync int rc = getProcessInfo(process, &tinfo);
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync if (RT_SUCCESS(rc))
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync {
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync *used = tinfo.pti_resident_size / 1024;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync }
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync return rc;
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync}
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync}
7b57f6ec6175ce1ee53e1ea49c24ff06f3723379vboxsync