VirtualBox

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

Last change on this file since 103164 was 103164, checked in by vboxsync, 8 months ago

FE/Qt: bugref:10501. Moving some cloud machine related functions to the common code area.

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