VirtualBox

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

Last change on this file since 103131 was 103131, checked in by vboxsync, 12 months ago

FE/Qt: bugref:10501. Moving cloud machine metric data related progress tasks to common area.

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