VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/linux/PerformanceLinux.cpp@ 43547

Last change on this file since 43547 was 43512, checked in by vboxsync, 13 years ago

Main/Metrics: build fix for lin32

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.2 KB
Line 
1/* $Id: PerformanceLinux.cpp 43512 2012-10-02 14:46:50Z vboxsync $ */
2
3/** @file
4 *
5 * VBox Linux-specific Performance Classes implementation.
6 */
7
8/*
9 * Copyright (C) 2008-2011 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#include <stdio.h>
21#include <iprt/alloc.h>
22#include <iprt/err.h>
23#include <iprt/param.h>
24#include <iprt/string.h>
25
26#include <map>
27#include <vector>
28
29#include "Logging.h"
30#include "Performance.h"
31
32namespace pm {
33
34class CollectorLinux : public CollectorHAL
35{
36public:
37 virtual int preCollect(const CollectorHints& hints, uint64_t /* iTick */);
38 virtual int getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available);
39 virtual int getProcessMemoryUsage(RTPROCESS process, ULONG *used);
40
41 virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle);
42 virtual int getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx);
43 virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total);
44private:
45 virtual int _getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle);
46 int getRawProcessStats(RTPROCESS process, uint64_t *cpuUser, uint64_t *cpuKernel, ULONG *memPagesUsed);
47
48 struct VMProcessStats
49 {
50 uint64_t cpuUser;
51 uint64_t cpuKernel;
52 ULONG pagesUsed;
53 };
54
55 typedef std::map<RTPROCESS, VMProcessStats> VMProcessMap;
56
57 VMProcessMap mProcessStats;
58 uint64_t mUser, mKernel, mIdle;
59};
60
61CollectorHAL *createHAL()
62{
63 return new CollectorLinux();
64}
65
66// Collector HAL for Linux
67
68int CollectorLinux::preCollect(const CollectorHints& hints, uint64_t /* iTick */)
69{
70 std::vector<RTPROCESS> processes;
71 hints.getProcesses(processes);
72
73 std::vector<RTPROCESS>::iterator it;
74 for (it = processes.begin(); it != processes.end(); it++)
75 {
76 VMProcessStats vmStats;
77 int rc = getRawProcessStats(*it, &vmStats.cpuUser, &vmStats.cpuKernel, &vmStats.pagesUsed);
78 /* On failure, do NOT stop. Just skip the entry. Having the stats for
79 * one (probably broken) process frozen/zero is a minor issue compared
80 * to not updating many process stats and the host cpu stats. */
81 if (RT_SUCCESS(rc))
82 mProcessStats[*it] = vmStats;
83 }
84 if (hints.isHostCpuLoadCollected() || mProcessStats.size())
85 {
86 _getRawHostCpuLoad(&mUser, &mKernel, &mIdle);
87 }
88 return VINF_SUCCESS;
89}
90
91int CollectorLinux::_getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle)
92{
93 int rc = VINF_SUCCESS;
94 ULONG u32user, u32nice, u32kernel, u32idle;
95 FILE *f = fopen("/proc/stat", "r");
96
97 if (f)
98 {
99 if (fscanf(f, "cpu %u %u %u %u", &u32user, &u32nice, &u32kernel, &u32idle) == 4)
100 {
101 *user = (uint64_t)u32user + u32nice;
102 *kernel = u32kernel;
103 *idle = u32idle;
104 }
105 else
106 rc = VERR_FILE_IO_ERROR;
107 fclose(f);
108 }
109 else
110 rc = VERR_ACCESS_DENIED;
111
112 return rc;
113}
114
115int CollectorLinux::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle)
116{
117 *user = mUser;
118 *kernel = mKernel;
119 *idle = mIdle;
120 return VINF_SUCCESS;
121}
122
123int CollectorLinux::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total)
124{
125 VMProcessMap::const_iterator it = mProcessStats.find(process);
126
127 if (it == mProcessStats.end())
128 {
129 Log (("No stats pre-collected for process %x\n", process));
130 return VERR_INTERNAL_ERROR;
131 }
132 *user = it->second.cpuUser;
133 *kernel = it->second.cpuKernel;
134 *total = mUser + mKernel + mIdle;
135 return VINF_SUCCESS;
136}
137
138int CollectorLinux::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available)
139{
140 int rc = VINF_SUCCESS;
141 ULONG buffers, cached;
142 FILE *f = fopen("/proc/meminfo", "r");
143
144 if (f)
145 {
146 int processed = fscanf(f, "MemTotal: %u kB\n", total);
147 processed += fscanf(f, "MemFree: %u kB\n", available);
148 processed += fscanf(f, "Buffers: %u kB\n", &buffers);
149 processed += fscanf(f, "Cached: %u kB\n", &cached);
150 if (processed == 4)
151 {
152 *available += buffers + cached;
153 *used = *total - *available;
154 }
155 else
156 rc = VERR_FILE_IO_ERROR;
157 fclose(f);
158 }
159 else
160 rc = VERR_ACCESS_DENIED;
161
162 return rc;
163}
164
165int CollectorLinux::getProcessMemoryUsage(RTPROCESS process, ULONG *used)
166{
167 VMProcessMap::const_iterator it = mProcessStats.find(process);
168
169 if (it == mProcessStats.end())
170 {
171 Log (("No stats pre-collected for process %x\n", process));
172 return VERR_INTERNAL_ERROR;
173 }
174 *used = it->second.pagesUsed * (PAGE_SIZE / 1024);
175 return VINF_SUCCESS;
176}
177
178int CollectorLinux::getRawProcessStats(RTPROCESS process, uint64_t *cpuUser, uint64_t *cpuKernel, ULONG *memPagesUsed)
179{
180 int rc = VINF_SUCCESS;
181 char *pszName;
182 pid_t pid2;
183 char c;
184 int iTmp;
185 long long unsigned int u64Tmp;
186 unsigned uTmp;
187 unsigned long ulTmp;
188 signed long ilTmp;
189 ULONG u32user, u32kernel;
190 char buf[80]; /* @todo: this should be tied to max allowed proc name. */
191
192 RTStrAPrintf(&pszName, "/proc/%d/stat", process);
193 //printf("Opening %s...\n", pszName);
194 FILE *f = fopen(pszName, "r");
195 RTMemFree(pszName);
196
197 if (f)
198 {
199 if (fscanf(f, "%d %79s %c %d %d %d %d %d %u %lu %lu %lu %lu %u %u "
200 "%ld %ld %ld %ld %ld %ld %llu %lu %u",
201 &pid2, buf, &c, &iTmp, &iTmp, &iTmp, &iTmp, &iTmp, &uTmp,
202 &ulTmp, &ulTmp, &ulTmp, &ulTmp, &u32user, &u32kernel,
203 &ilTmp, &ilTmp, &ilTmp, &ilTmp, &ilTmp, &ilTmp, &u64Tmp,
204 &ulTmp, memPagesUsed) == 24)
205 {
206 Assert((pid_t)process == pid2);
207 *cpuUser = u32user;
208 *cpuKernel = u32kernel;
209 }
210 else
211 rc = VERR_FILE_IO_ERROR;
212 fclose(f);
213 }
214 else
215 rc = VERR_ACCESS_DENIED;
216
217 return rc;
218}
219
220int CollectorLinux::getRawHostNetworkLoad(const char *name, uint64_t *rx, uint64_t *tx)
221{
222 int rc = VINF_SUCCESS;
223 char szIfName[/*IFNAMSIZ*/ 16 + 36];
224 long long unsigned int u64Rx, u64Tx;
225
226 RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/rx_bytes", name);
227 FILE *f = fopen(szIfName, "r");
228 if (f)
229 {
230 if (fscanf(f, "%llu", &u64Rx) == 1)
231 *rx = u64Rx;
232 else
233 rc = VERR_FILE_IO_ERROR;
234 fclose(f);
235 RTStrPrintf(szIfName, sizeof(szIfName), "/sys/class/net/%s/statistics/tx_bytes", name);
236 f = fopen(szIfName, "r");
237 if (f)
238 {
239 if (fscanf(f, "%llu", &u64Tx) == 1)
240 *tx = u64Tx;
241 else
242 rc = VERR_FILE_IO_ERROR;
243 fclose(f);
244 }
245 else
246 rc = VERR_ACCESS_DENIED;
247 }
248 else
249 rc = VERR_ACCESS_DENIED;
250
251 return rc;
252}
253
254}
255
Note: See TracBrowser for help on using the repository browser.

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