VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/darwin/PerformanceDarwin.cpp@ 98110

Last change on this file since 98110 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.1 KB
Line 
1/* $Id: PerformanceDarwin.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * VBox Darwin-specific Performance Classes implementation.
4 */
5
6/*
7 * Copyright (C) 2008-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include <mach/mach_error.h>
29#include <mach/mach_host.h>
30#include <mach/mach_init.h>
31#include <mach/mach_time.h>
32#include <mach/vm_statistics.h>
33#include <sys/sysctl.h>
34#include <sys/errno.h>
35#include <iprt/errcore.h>
36#include <iprt/log.h>
37#include <iprt/mp.h>
38#include <iprt/param.h>
39#include <iprt/system.h>
40#include "Performance.h"
41
42/* The following declarations are missing in 10.4.x SDK */
43/** @todo Replace them with libproc.h and sys/proc_info.h when 10.4 is no longer supported */
44extern "C" int proc_pidinfo(int pid, int flavor, uint64_t arg, void *buffer, int buffersize);
45struct proc_taskinfo {
46 uint64_t pti_virtual_size; /* virtual memory size (bytes) */
47 uint64_t pti_resident_size; /* resident memory size (bytes) */
48 uint64_t pti_total_user; /* total time */
49 uint64_t pti_total_system;
50 uint64_t pti_threads_user; /* existing threads only */
51 uint64_t pti_threads_system;
52 int32_t pti_policy; /* default policy for new threads */
53 int32_t pti_faults; /* number of page faults */
54 int32_t pti_pageins; /* number of actual pageins */
55 int32_t pti_cow_faults; /* number of copy-on-write faults */
56 int32_t pti_messages_sent; /* number of messages sent */
57 int32_t pti_messages_received; /* number of messages received */
58 int32_t pti_syscalls_mach; /* number of mach system calls */
59 int32_t pti_syscalls_unix; /* number of unix system calls */
60 int32_t pti_csw; /* number of context switches */
61 int32_t pti_threadnum; /* number of threads in the task */
62 int32_t pti_numrunning; /* number of running threads */
63 int32_t pti_priority; /* task priority*/
64};
65#define PROC_PIDTASKINFO 4
66
67namespace pm {
68
69class CollectorDarwin : public CollectorHAL
70{
71public:
72 CollectorDarwin();
73 virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle);
74 virtual int getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available);
75 virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total);
76 virtual int getProcessMemoryUsage(RTPROCESS process, ULONG *used);
77private:
78 ULONG totalRAM;
79 uint32_t nCpus;
80};
81
82CollectorHAL *createHAL()
83{
84 return new CollectorDarwin();
85}
86
87CollectorDarwin::CollectorDarwin()
88{
89 uint64_t cb;
90 int rc = RTSystemQueryTotalRam(&cb);
91 if (RT_FAILURE(rc))
92 totalRAM = 0;
93 else
94 totalRAM = (ULONG)(cb / 1024);
95 nCpus = RTMpGetOnlineCount();
96 Assert(nCpus);
97 if (nCpus == 0)
98 {
99 /* It is rather unsual to have no CPUs, but the show must go on. */
100 nCpus = 1;
101 }
102}
103
104int CollectorDarwin::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle)
105{
106 kern_return_t krc;
107 mach_msg_type_number_t count;
108 host_cpu_load_info_data_t info;
109
110 count = HOST_CPU_LOAD_INFO_COUNT;
111
112 krc = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&info, &count);
113 if (krc != KERN_SUCCESS)
114 {
115 Log(("host_statistics() -> %s", mach_error_string(krc)));
116 return RTErrConvertFromDarwinKern(krc);
117 }
118
119 *user = (uint64_t)info.cpu_ticks[CPU_STATE_USER]
120 + info.cpu_ticks[CPU_STATE_NICE];
121 *kernel = (uint64_t)info.cpu_ticks[CPU_STATE_SYSTEM];
122 *idle = (uint64_t)info.cpu_ticks[CPU_STATE_IDLE];
123 return VINF_SUCCESS;
124}
125
126int CollectorDarwin::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available)
127{
128 AssertReturn(totalRAM, VERR_INTERNAL_ERROR);
129 uint64_t cb;
130 int rc = RTSystemQueryAvailableRam(&cb);
131 if (RT_SUCCESS(rc))
132 {
133 *total = totalRAM;
134 cb /= 1024;
135 *available = cb < ~(ULONG)0 ? (ULONG)cb : ~(ULONG)0;
136 *used = *total - *available;
137 }
138 return rc;
139}
140
141static int getProcessInfo(RTPROCESS process, struct proc_taskinfo *tinfo)
142{
143 Log7(("getProcessInfo() getting info for %d", process));
144 int cbRet = proc_pidinfo((pid_t)process, PROC_PIDTASKINFO, 0, tinfo, sizeof(*tinfo));
145 if (cbRet <= 0)
146 {
147 int iErrNo = errno;
148 Log(("proc_pidinfo() -> %s", strerror(iErrNo)));
149 return RTErrConvertFromDarwin(iErrNo);
150 }
151 if ((unsigned int)cbRet < sizeof(*tinfo))
152 {
153 Log(("proc_pidinfo() -> too few bytes %d", cbRet));
154 return VERR_INTERNAL_ERROR;
155 }
156 return VINF_SUCCESS;
157}
158
159int CollectorDarwin::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total)
160{
161 struct proc_taskinfo tinfo;
162
163 int rc = getProcessInfo(process, &tinfo);
164 if (RT_SUCCESS(rc))
165 {
166 /*
167 * Adjust user and kernel values so 100% is when ALL cores are fully
168 * utilized (see @bugref{6345}).
169 */
170 *user = tinfo.pti_total_user / nCpus;
171 *kernel = tinfo.pti_total_system / nCpus;
172 *total = mach_absolute_time();
173 }
174 return rc;
175}
176
177int CollectorDarwin::getProcessMemoryUsage(RTPROCESS process, ULONG *used)
178{
179 struct proc_taskinfo tinfo;
180
181 int rc = getProcessInfo(process, &tinfo);
182 if (RT_SUCCESS(rc))
183 {
184 uint64_t cKbResident = tinfo.pti_resident_size / 1024;
185 *used = cKbResident < ~(ULONG)0 ? (ULONG)cKbResident : ~(ULONG)0;
186 }
187 return rc;
188}
189
190}
191
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette