VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/activity/UIMonitorCommon.cpp

Last change on this file was 106061, checked in by vboxsync, 3 weeks ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.7 KB
Line 
1/* $Id: UIMonitorCommon.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIMonitorCommon class implementation.
4 */
5
6/*
7 * Copyright (C) 2016-2024 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/* Qt includes: */
29#include <QPainter>
30#include <QPainterPath>
31#include <QPainterPathStroker>
32#include <QXmlStreamReader>
33
34
35/* GUI includes: */
36#include "UIMonitorCommon.h"
37
38/* COM includes: */
39#include "CForm.h"
40#include "CFormValue.h"
41#include "CRangedIntegerFormValue.h"
42#include "CMachineDebugger.h"
43#include "CPerformanceCollector.h"
44#include <VBox/com/VirtualBox.h>
45
46
47/*********************************************************************************************************************************
48* UIProgressTaskReadCloudMachineMetricList implementation. *
49*********************************************************************************************************************************/
50
51UIProgressTaskReadCloudMachineMetricList::UIProgressTaskReadCloudMachineMetricList(QObject *pParent, CCloudMachine comCloudMachine)
52 :UIProgressTask(pParent)
53 , m_comCloudMachine(comCloudMachine)
54{
55}
56
57CProgress UIProgressTaskReadCloudMachineMetricList::createProgress()
58{
59 if (!m_comCloudMachine.isOk())
60 return CProgress();
61 return m_comCloudMachine.ListMetricNames(m_metricNamesArray);
62}
63
64void UIProgressTaskReadCloudMachineMetricList::handleProgressFinished(CProgress &comProgress)
65{
66 if (!comProgress.isOk())
67 return;
68 emit sigMetricListReceived(m_metricNamesArray.GetValues());
69}
70
71
72/*********************************************************************************************************************************
73* UIProgressTaskReadCloudMachineMetricData implementation. *
74*********************************************************************************************************************************/
75
76UIProgressTaskReadCloudMachineMetricData::UIProgressTaskReadCloudMachineMetricData(QObject *pParent,
77 CCloudMachine comCloudMachine,
78 KMetricType enmMetricType,
79 ULONG uDataPointsCount)
80 :UIProgressTask(pParent)
81 , m_comCloudMachine(comCloudMachine)
82 , m_enmMetricType(enmMetricType)
83 , m_uDataPointsCount(uDataPointsCount)
84{
85}
86
87CProgress UIProgressTaskReadCloudMachineMetricData::createProgress()
88{
89 if (!m_comCloudMachine.isOk())
90 return CProgress();
91
92 CStringArray aUnit;
93 return m_comCloudMachine.EnumerateMetricData(m_enmMetricType, m_uDataPointsCount, m_metricData, m_timeStamps, aUnit);
94}
95
96
97void UIProgressTaskReadCloudMachineMetricData::handleProgressFinished(CProgress &comProgress)
98{
99 if (!comProgress.isOk())
100 return;
101 if (m_metricData.isOk() && m_timeStamps.isOk())
102 emit sigMetricDataReceived(m_enmMetricType, m_metricData.GetValues(), m_timeStamps.GetValues());
103}
104
105/* static */
106void UIMonitorCommon::getNetworkLoad(CMachineDebugger &debugger, quint64 &uOutNetworkReceived, quint64 &uOutNetworkTransmitted)
107{
108 uOutNetworkReceived = 0;
109 uOutNetworkTransmitted = 0;
110 QVector<UIDebuggerMetricData> xmlData = getAndParseStatsFromDebugger(debugger, "/Public/NetAdapter/*/Bytes*");
111 foreach (const UIDebuggerMetricData &data, xmlData)
112 {
113 if (data.m_strName.endsWith("BytesReceived"))
114 uOutNetworkReceived += data.m_counter;
115 else if (data.m_strName.endsWith("BytesTransmitted"))
116 uOutNetworkTransmitted += data.m_counter;
117 else
118 AssertMsgFailed(("name=%s\n", data.m_strName.toLocal8Bit().data()));
119 }
120}
121
122/* static */
123void UIMonitorCommon::getDiskLoad(CMachineDebugger &debugger, quint64 &uOutDiskWritten, quint64 &uOutDiskRead)
124{
125 uOutDiskWritten = 0;
126 uOutDiskRead = 0;
127 QVector<UIDebuggerMetricData> xmlData = getAndParseStatsFromDebugger(debugger, "/Public/Storage/*/Port*/Bytes*");
128 foreach (const UIDebuggerMetricData &data, xmlData)
129 {
130 if (data.m_strName.endsWith("BytesWritten"))
131 uOutDiskWritten += data.m_counter;
132 else if (data.m_strName.endsWith("BytesRead"))
133 uOutDiskRead += data.m_counter;
134 else
135 AssertMsgFailed(("name=%s\n", data.m_strName.toLocal8Bit().data()));
136 }
137}
138
139/* static */
140void UIMonitorCommon::getVMMExitCount(CMachineDebugger &debugger, quint64 &uOutVMMExitCount)
141{
142 uOutVMMExitCount = 0;
143 QVector<UIDebuggerMetricData> xmlData = getAndParseStatsFromDebugger(debugger, "/PROF/CPU*/EM/RecordedExits");
144 foreach (const UIDebuggerMetricData &data, xmlData)
145 {
146 if (data.m_strName.endsWith("RecordedExits"))
147 uOutVMMExitCount += data.m_counter;
148 else
149 AssertMsgFailed(("name=%s\n", data.m_strName.toLocal8Bit().data()));
150 }
151}
152
153
154/* static */
155QVector<UIDebuggerMetricData> UIMonitorCommon::getAndParseStatsFromDebugger(CMachineDebugger &debugger, const QString &strQuery)
156{
157 QVector<UIDebuggerMetricData> xmlData;
158 if (strQuery.isEmpty())
159 return xmlData;
160 QString strStats = debugger.GetStats(strQuery, false);
161 QXmlStreamReader xmlReader;
162 xmlReader.addData(strStats);
163 if (xmlReader.readNextStartElement())
164 {
165 while (xmlReader.readNextStartElement())
166 {
167 if (xmlReader.name() == QLatin1String("Counter"))
168 {
169 QXmlStreamAttributes attributes = xmlReader.attributes();
170 quint64 iCounter = attributes.value("c").toULongLong();
171 xmlData.push_back(UIDebuggerMetricData(attributes.value("name").toString(), iCounter));
172 }
173 else if (xmlReader.name() == QLatin1String("U64"))
174 {
175 QXmlStreamAttributes attributes = xmlReader.attributes();
176 quint64 iCounter = attributes.value("val").toULongLong();
177 xmlData.push_back(UIDebuggerMetricData(attributes.value("name").toString(), iCounter));
178 }
179 xmlReader.skipCurrentElement();
180 }
181 }
182 return xmlData;
183}
184
185/* static */
186void UIMonitorCommon::getRAMLoad(CPerformanceCollector &comPerformanceCollector, QVector<QString> &nameList,
187 QVector<CUnknown>& objectList, quint64 &iOutTotalRAM, quint64 &iOutFreeRAM)
188{
189 iOutTotalRAM = 0;
190 iOutFreeRAM = 0;
191 QVector<QString> aReturnNames;
192 QVector<CUnknown> aReturnObjects;
193 QVector<QString> aReturnUnits;
194 QVector<ULONG> aReturnScales;
195 QVector<ULONG> aReturnSequenceNumbers;
196 QVector<ULONG> aReturnDataIndices;
197 QVector<ULONG> aReturnDataLengths;
198 /* Make a query to CPerformanceCollector to fetch some metrics (e.g RAM usage): */
199 QVector<LONG> returnData = comPerformanceCollector.QueryMetricsData(nameList,
200 objectList,
201 aReturnNames,
202 aReturnObjects,
203 aReturnUnits,
204 aReturnScales,
205 aReturnSequenceNumbers,
206 aReturnDataIndices,
207 aReturnDataLengths);
208 /* Parse the result we get from CPerformanceCollector to get respective values: */
209 for (int i = 0; i < aReturnNames.size(); ++i)
210 {
211 if (aReturnDataLengths[i] == 0)
212 continue;
213 /* Read the last of the return data disregarding the rest since we are caching the data in GUI side: */
214 float fData = returnData[aReturnDataIndices[i] + aReturnDataLengths[i] - 1] / (float)aReturnScales[i];
215 if (aReturnNames[i].contains("RAM", Qt::CaseInsensitive) && !aReturnNames[i].contains(":"))
216 {
217 if (aReturnNames[i].contains("Total", Qt::CaseInsensitive))
218 iOutTotalRAM = (quint64)fData;
219 if (aReturnNames[i].contains("Free", Qt::CaseInsensitive))
220 iOutFreeRAM = (quint64)fData;
221 }
222 }
223}
224
225/* static */
226QPainterPath UIMonitorCommon::doughnutSlice(const QRectF &outerRectangle, const QRectF &innerRectangle, float fStartAngle, float fSweepAngle)
227{
228 QPainterPath subPath1;
229 subPath1.moveTo(outerRectangle.center());
230 subPath1.arcTo(outerRectangle, fStartAngle,
231 -1.f * fSweepAngle);
232 subPath1.closeSubpath();
233
234 QPainterPath subPath2;
235 subPath2.moveTo(innerRectangle.center());
236 subPath2.arcTo(innerRectangle, fStartAngle,
237 -1.f * fSweepAngle);
238 subPath2.closeSubpath();
239
240 return subPath1.subtracted(subPath2);
241}
242
243/* static */
244QPainterPath UIMonitorCommon::wholeArc(const QRectF &rectangle)
245{
246 QPainterPath arc;
247 arc.addEllipse(rectangle);
248 return arc;
249}
250
251/* static */
252void UIMonitorCommon::drawCombinedDoughnutChart(quint64 data1, const QColor &data1Color,
253 quint64 data2, const QColor &data2Color,
254 QPainter &painter, quint64 iMaximum,
255 const QRectF &chartRect, const QRectF &innerRect, int iOverlayAlpha)
256{
257 (void)data2;
258 (void)data2Color;
259 (void)iOverlayAlpha;
260 /* Draw two arcs. one for the inner the other for the outer circle: */
261 painter.setPen(QPen(QColor(100, 100, 100, iOverlayAlpha), 1));
262 painter.drawArc(chartRect, 0, 3600 * 16);
263 painter.drawArc(innerRect, 0, 3600 * 16);
264
265 /* Draw a translucent white background: */
266 QPainterPath background = wholeArc(chartRect).subtracted(wholeArc(innerRect));
267 painter.setPen(Qt::NoPen);
268 painter.setBrush(QColor(255, 255, 255, iOverlayAlpha));
269 painter.drawPath(background);
270
271 /* Draw a doughnut slice for the first data series: */
272 float fAngle = 360.f * data1 / (float)iMaximum;
273 painter.setBrush(data1Color);
274 painter.drawPath(doughnutSlice(chartRect, innerRect, 90, fAngle));
275
276 float fAngle2 = 360.f * data2 / (float)iMaximum;
277 painter.setBrush(data2Color);
278 painter.drawPath(doughnutSlice(chartRect, innerRect, 90 - fAngle, fAngle2));
279}
280
281/* static */
282QRectF UIMonitorCommon::getScaledRect(const QRectF &outerFrame, float fScaleX, float fScaleY)
283{
284 if (!outerFrame.isValid())
285 return QRectF();
286 QPointF center = outerFrame.center();
287 float iWidth = fScaleX * outerFrame.width();
288 float iHeight = fScaleY * outerFrame.height();
289 return QRectF(QPointF(center.x() - 0.5 * iWidth, center.y() - 0.5 * iHeight),
290 QSizeF(iWidth, iHeight));
291}
292
293/* static */
294void UIMonitorCommon::drawDoughnutChart(QPainter &painter, quint64 iMaximum, quint64 data,
295 const QRectF &chartRect, const QRectF &innerRect, int iOverlayAlpha, const QColor &color)
296{
297 /* Draw a whole non-filled circle: */
298 painter.setPen(QPen(QColor(100, 100, 100, iOverlayAlpha), 1));
299 painter.drawArc(chartRect, 0, 3600 * 16);
300 painter.drawArc(innerRect, 0, 3600 * 16);
301
302 /* Draw a white filled circle and the arc for data: */
303 QPainterPath background = UIMonitorCommon::wholeArc(chartRect).subtracted(UIMonitorCommon::wholeArc(innerRect));
304 painter.setPen(Qt::NoPen);
305 painter.setBrush(QColor(255, 255, 255, iOverlayAlpha));
306 painter.drawPath(background);
307
308 /* Draw the doughnut slice for the data: */
309 float fAngle = 360.f * data / (float)iMaximum;
310 painter.setBrush(color);
311 painter.drawPath(UIMonitorCommon::doughnutSlice(chartRect, innerRect, 90, fAngle));
312}
313
314/* static */
315quint64 UIMonitorCommon::determineTotalRAMAmount(CCloudMachine &comCloudMachine)
316{
317 quint64 iTotalRAM = 0;
318 CForm comForm = comCloudMachine.GetDetailsForm();
319 /* Ignore cloud machine errors: */
320 if (comCloudMachine.isOk())
321 {
322 /* Common anchor for all fields: */
323 const QString strAnchorType = "cloud";
324
325 /* For each form value: */
326 const QVector<CFormValue> values = comForm.GetValues();
327 foreach (const CFormValue &comIteratedValue, values)
328 {
329 /* Ignore invisible values: */
330 if (!comIteratedValue.GetVisible())
331 continue;
332
333 /* Acquire label: */
334 const QString strLabel = comIteratedValue.GetLabel();
335 if (strLabel != "RAM")
336 continue;
337
338 AssertReturn((comIteratedValue.GetType() == KFormValueType_RangedInteger), 0);
339
340 CRangedIntegerFormValue comValue(comIteratedValue);
341 iTotalRAM = comValue.GetInteger();
342 QString strRAMUnit = comValue.GetSuffix();
343 if (strRAMUnit.compare("gb", Qt::CaseInsensitive) == 0)
344 iTotalRAM *= _1G / _1K;
345 else if (strRAMUnit.compare("mb", Qt::CaseInsensitive) == 0)
346 iTotalRAM *= _1M / _1K;
347 if (!comValue.isOk())
348 iTotalRAM = 0;
349 }
350 }
351 return iTotalRAM;
352}
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