summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel d'Andrada <daniel.dandrada@luxoft.com>2018-12-03 11:25:34 +0100
committerRobert Griebl <robert.griebl@pelagicore.com>2018-12-07 15:04:24 +0000
commit05a3bb55ce78d785a77bc8c8aaab2fd82b0bc0b5 (patch)
treeea33f8f0b2288af890d666ad74509b8fba33b181
parentadb57812ee1cf89f3311f8a27ef97abf5d424bde (diff)
downloadqtapplicationmanager-05a3bb55ce78d785a77bc8c8aaab2fd82b0bc0b5.tar.gz
Introduce MonitorModel & friends
A better, more flexible, API for monitor-lib. Fixes: AUTOSUITE-692 Fixes: AUTOSUITE-250 Fixes: AUTOSUITE-686 Change-Id: Ib672e6a19beca4e83a51bcdca530c50be1bf00b7 Reviewed-by: Robert Griebl <robert.griebl@pelagicore.com>
-rw-r--r--doc/migration-guide-5.12.qdoc75
-rw-r--r--examples/applicationmanager/applicationmanager.pro3
-rw-r--r--examples/applicationmanager/frame-timer/am-config.yaml (renamed from examples/applicationmanager/monitor/am-config.yaml)5
-rw-r--r--examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.qml (renamed from examples/applicationmanager/monitor/apps/tld.monitor.app/app.qml)48
-rw-r--r--examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.svg64
-rw-r--r--examples/applicationmanager/frame-timer/apps/frame-timer.fish/info.yaml9
-rw-r--r--examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/info.yaml9
-rw-r--r--examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.qml (renamed from examples/applicationmanager/monitor/system-ui/Switch.qml)29
-rw-r--r--examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.svg64
-rw-r--r--examples/applicationmanager/frame-timer/doc/images/frame-timer-example.pngbin0 -> 39709 bytes
-rw-r--r--examples/applicationmanager/frame-timer/doc/src/frame-timer-example.qdoc54
-rw-r--r--examples/applicationmanager/frame-timer/frame-timer.pro (renamed from examples/applicationmanager/monitor/monitor.pro)17
-rw-r--r--examples/applicationmanager/frame-timer/system-ui/main.qml268
-rw-r--r--examples/applicationmanager/monitor/apps/tld.monitor.app/dummyicon0
-rw-r--r--examples/applicationmanager/monitor/apps/tld.monitor.app/info.yaml9
-rw-r--r--examples/applicationmanager/monitor/doc/images/monitor.pngbin31783 -> 0 bytes
-rw-r--r--examples/applicationmanager/monitor/doc/src/monitor.qdoc108
-rw-r--r--examples/applicationmanager/monitor/monitor.qmlproject17
-rw-r--r--examples/applicationmanager/monitor/system-ui/MonitorChart.qml97
-rw-r--r--examples/applicationmanager/monitor/system-ui/MonitorText.qml58
-rw-r--r--examples/applicationmanager/monitor/system-ui/Tile.qml58
-rw-r--r--examples/applicationmanager/monitor/system-ui/main.qml260
-rw-r--r--examples/applicationmanager/process-status/am-config.yaml8
-rw-r--r--examples/applicationmanager/process-status/apps/process-status.cpu-hog/icon.pngbin0 -> 1027 bytes
-rw-r--r--examples/applicationmanager/process-status/apps/process-status.cpu-hog/info.yaml9
-rw-r--r--examples/applicationmanager/process-status/apps/process-status.cpu-hog/main.qml89
-rw-r--r--examples/applicationmanager/process-status/apps/process-status.mem-hog/icon.pngbin0 -> 1105 bytes
-rw-r--r--examples/applicationmanager/process-status/apps/process-status.mem-hog/info.yaml9
-rw-r--r--examples/applicationmanager/process-status/apps/process-status.mem-hog/main.qml (renamed from examples/applicationmanager/monitor/system-ui/WindowContainer.qml)44
-rw-r--r--examples/applicationmanager/process-status/apps/process-status.slim/icon.pngbin0 -> 1133 bytes
-rw-r--r--examples/applicationmanager/process-status/apps/process-status.slim/info.yaml9
-rw-r--r--examples/applicationmanager/process-status/apps/process-status.slim/main.qml (renamed from examples/applicationmanager/monitor/apps/tld.monitor.app/ApplicationWindow.qml)40
-rw-r--r--examples/applicationmanager/process-status/doc/images/process-status-example.pngbin0 -> 43067 bytes
-rw-r--r--examples/applicationmanager/process-status/doc/src/process-status-example.qdoc53
-rw-r--r--examples/applicationmanager/process-status/process-status.pro17
-rw-r--r--examples/applicationmanager/process-status/system-ui/ApplicationDisplay.qml107
-rw-r--r--examples/applicationmanager/process-status/system-ui/CpuGraph.qml96
-rw-r--r--examples/applicationmanager/process-status/system-ui/MemoryText.qml50
-rw-r--r--examples/applicationmanager/process-status/system-ui/Stats.qml83
-rw-r--r--examples/applicationmanager/process-status/system-ui/main.qml81
-rw-r--r--src/main-lib/main.cpp22
-rw-r--r--src/monitor-lib/cpustatus.cpp148
-rw-r--r--src/monitor-lib/cpustatus.h79
-rw-r--r--src/monitor-lib/frametimer.cpp290
-rw-r--r--src/monitor-lib/frametimer.h65
-rw-r--r--src/monitor-lib/gpustatus.cpp160
-rw-r--r--src/monitor-lib/gpustatus.h78
-rw-r--r--src/monitor-lib/iostatus.cpp188
-rw-r--r--src/monitor-lib/iostatus.h (renamed from src/monitor-lib/systemmonitor_p.h)117
-rw-r--r--src/monitor-lib/memorystatus.cpp156
-rw-r--r--src/monitor-lib/memorystatus.h80
-rw-r--r--src/monitor-lib/monitor-lib.pro25
-rw-r--r--src/monitor-lib/monitormodel.cpp473
-rw-r--r--src/monitor-lib/monitormodel.h132
-rw-r--r--src/monitor-lib/processmonitor.cpp552
-rw-r--r--src/monitor-lib/processmonitor_p.cpp747
-rw-r--r--src/monitor-lib/processmonitor_p.h240
-rw-r--r--src/monitor-lib/processreader.cpp374
-rw-r--r--src/monitor-lib/processreader.h98
-rw-r--r--src/monitor-lib/processstatus.cpp329
-rw-r--r--src/monitor-lib/processstatus.h (renamed from src/monitor-lib/processmonitor.h)91
-rw-r--r--src/monitor-lib/systemmonitor.cpp968
-rw-r--r--src/monitor-lib/systemmonitor.h145
-rw-r--r--src/src.pro2
-rw-r--r--src/tools/launcher-qml/launcher-qml.cpp16
-rw-r--r--src/tools/launcher-qml/launcher-qml.pro1
-rw-r--r--tests/manual/monitormodel/PropertyField.qml (renamed from tests/manual/systemmonitor/PropertyField.qml)0
-rw-r--r--tests/manual/monitormodel/README (renamed from tests/manual/systemmonitor/README)2
-rw-r--r--tests/manual/monitormodel/SystemMonitorChart.qml (renamed from tests/manual/systemmonitor/SystemMonitorChart.qml)0
-rw-r--r--tests/manual/monitormodel/main.qml (renamed from tests/manual/systemmonitor/main.qml)107
-rw-r--r--tests/processmonitor/processmonitor.pro11
-rw-r--r--tests/processmonitor/tst_processmonitor.cpp153
-rw-r--r--tests/processreader/advanced.smaps (renamed from tests/processmonitor/advanced.smaps)0
-rw-r--r--tests/processreader/basic.smaps (renamed from tests/processmonitor/basic.smaps)0
-rw-r--r--tests/processreader/invalid.smaps (renamed from tests/processmonitor/invalid.smaps)0
-rw-r--r--tests/processreader/processreader.pro (renamed from tests/systemmonitor/systemmonitor.pro)4
-rw-r--r--tests/processreader/tst_processreader.cpp142
-rw-r--r--tests/systemmonitor/tst_systemmonitor.cpp142
-rw-r--r--tests/tests.pro3
79 files changed, 4215 insertions, 3872 deletions
diff --git a/doc/migration-guide-5.12.qdoc b/doc/migration-guide-5.12.qdoc
index ac42e770..499167df 100644
--- a/doc/migration-guide-5.12.qdoc
+++ b/doc/migration-guide-5.12.qdoc
@@ -244,40 +244,77 @@ QtObject {
\section1 SystemMonitor
-SystemMonitor is no longer a singleton. That way it's simpler to bind expressions to its properties and
-you have control over the lifecycle of that object, so that you only create an instance of it when you
-actually need it. It's also simpler to test code that uses a regular QML object instead of a singleton,
-as you can apply patterns such as dependency injection.
+The SystemMonitor singleton no longer exists. The functionality that it provided has been split into several new
+components, namely: MonitorModel, CpuStatus, GpuStatus, MemoryStatus, FrameTimer and IoStatus.
\oldcode
Item {
id: root
...
- Label {
- text: "CPU Cores: " + SystemMonitor.cpuCores
- }
- ...
Component.onCompleted: {
- SystemMonitor.reportingInterval = 1000;
- SystemMonitor.count = 12;
- SystemMonitor.idleLoadThreshold = 0.05;
+ SystemMonitor.reportingInterval = 1500;
+ SystemMonitor.count = 20;
}
Binding { target: SystemMonitor; property: "cpuLoadReportingEnabled"; value: root.visible }
+
+ // Draw a graph of CPU usage
+ ListView {
+ model: SystemMonitor
+ ...
+ }
}
\newcode
Item {
id: root
...
- Label {
- text: "CPU Cores: " + systemMonitor.cpuCores
+ // Draw a graph of CPU usage
+ ListView {
+ model: MonitorModel {
+ interval: 1500
+ running: root.visible
+ maximumCount: 20
+ CpuStatus {}
+ }
+ ...
}
+}
+\endcode
+
+\section1 ProcessMonitor
+
+The ProcessMonitor component no longer exists. The functionality that it provided has been split into a
+couple of new components, namely: ProcessStatus, MonitorModel and FrameTimer.
+
+\oldcode
+Item {
+ id: root
+ ...
+ // Draw a graph of CPU usage
+ ListView {
+ model: ProcessMonitor {
+ count: 20
+ cpuReportingEnabled: root.visible
+ reportingInterval: 1500
+ applicationId: "foo.app"
+ }
+ ...
+ }
+}
+\newcode
+Item {
+ id: root
...
- SystemMonitor {
- id: systemMonitor
- reportingInterval: 1000
- count: 12
- idleLoadThreshold: 0.05
- cpuLoadReportingEnabled: root.visible
+ // Draw a graph of CPU usage
+ ListView {
+ model: MonitorModel {
+ maximumCount: 20
+ running: root.visible
+ interval: 1500
+ ProcessStatus {
+ applicationId: "foo.app"
+ }
+ }
+ ...
}
}
\endcode
diff --git a/examples/applicationmanager/applicationmanager.pro b/examples/applicationmanager/applicationmanager.pro
index 6b7b8034..8231c457 100644
--- a/examples/applicationmanager/applicationmanager.pro
+++ b/examples/applicationmanager/applicationmanager.pro
@@ -2,10 +2,11 @@ TEMPLATE = subdirs
SUBDIRS = \
animated-windows \
+ frame-timer \
hello-world \
minidesk \
- monitor \
multi-views \
+ process-status \
startup-plugin \
intents \
diff --git a/examples/applicationmanager/monitor/am-config.yaml b/examples/applicationmanager/frame-timer/am-config.yaml
index dc5216c5..5db21e36 100644
--- a/examples/applicationmanager/monitor/am-config.yaml
+++ b/examples/applicationmanager/frame-timer/am-config.yaml
@@ -1,13 +1,8 @@
formatVersion: 1
formatType: am-configuration
---
-
applications:
builtinAppsManifestDir: "${CONFIG_PWD}/apps"
ui:
mainQml: "${CONFIG_PWD}/system-ui/main.qml"
-
-# development setup:
-flags:
- noUiWatchdog: yes
diff --git a/examples/applicationmanager/monitor/apps/tld.monitor.app/app.qml b/examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.qml
index a199d467..d6ae4bc3 100644
--- a/examples/applicationmanager/monitor/apps/tld.monitor.app/app.qml
+++ b/examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.qml
@@ -50,34 +50,36 @@
**
****************************************************************************/
-import QtQuick 2.6
+import QtQuick 2.4
import QtApplicationManager.Application 1.0
-ApplicationWindow {
- title: "Primary Window"
- windowType: "primary"
+ApplicationManagerWindow {
+ id: root
+ color: mouseArea.pressed ? "red" : "darkblue"
- ApplicationWindow {
- title: "Secondary Window"
- windowType: "secondary"
- visible: true
- idle: 500
- }
+ Rectangle {
+ id: rectangle
+ anchors.centerIn: parent
+ width: 180; height: 180; radius: width/4
+ color: "aqua"
+
+ Image {
+ source: ApplicationInterface.icon
+ anchors.centerIn: parent
+ }
- Timer {
- property int count: 0
- running: true
- repeat: true
- onTriggered: {
- if (count < 100) {
- var arr = [];
- var idx = 200000;
- while (idx > 0)
- arr[idx] = idx--;
- count++;
- } else {
- repeat = false;
+ Timer {
+ running: true
+ repeat: true
+ interval: 1000 / 25 // 25 frames per second
+ onTriggered: {
+ rectangle.rotation = (rectangle.rotation + 5) % 360;
}
}
}
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ }
}
diff --git a/examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.svg b/examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.svg
new file mode 100644
index 00000000..69a95ea7
--- /dev/null
+++ b/examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.svg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ id="svg8"
+ version="1.1"
+ viewBox="0 0 51.879999 51.880002"
+ height="51.880001mm"
+ width="51.880001mm">
+ <title
+ id="title4518">U+144A5 ANATOLIAN HIEROGLYPH A138</title>
+ <defs
+ id="defs2" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>U+144A5 ANATOLIAN HIEROGLYPH A138 from Noto Sans font</dc:title>
+ <cc:license
+ rdf:resource="http://scripts.sil.org/OFL" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://scripts.sil.org/OFL">
+ <cc:permits
+ rdf:resource="http://scripts.sil.org/pub/OFL/Reproduction" />
+ <cc:permits
+ rdf:resource="http://scripts.sil.org/pub/OFL/Distribution" />
+ <cc:permits
+ rdf:resource="http://scripts.sil.org/pub/OFL/Embedding" />
+ <cc:permits
+ rdf:resource="http://scripts.sil.org/pub/OFL/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://scripts.sil.org/pub/OFL/Notice" />
+ <cc:requires
+ rdf:resource="http://scripts.sil.org/pub/OFL/Attribution" />
+ <cc:requires
+ rdf:resource="http://scripts.sil.org/pub/OFL/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://scripts.sil.org/pub/OFL/DerivativeRenaming" />
+ <cc:requires
+ rdf:resource="http://scripts.sil.org/pub/OFL/BundlingWhenSelling" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ transform="translate(-47.560265,-26.871213)"
+ id="layer1">
+ <g
+ id="text4538"
+ style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;image-rendering:auto">
+ <path
+ id="path814"
+ style="font-size:42.33333206px;stroke-width:0.26458332"
+ d="m 71.320099,66.590713 q -2.032,0 -3.852334,-0.804334 -1.777999,-0.762 -3.217333,-2.032 -1.439333,-1.227666 -2.413,-2.667 -3.090333,-0.973666 -6.095999,-3.090333 -3.005667,-2.116666 -6.180667,-4.699 V 52.32438 q 3.175,-2.582334 6.180667,-4.699 3.005666,-2.116667 6.095999,-3.090333 0.973667,-1.439334 2.413,-2.667 1.439334,-1.27 3.217333,-2.032 1.820334,-0.804334 3.852334,-0.804334 0.677333,0 1.058333,0.169334 0.423333,0.127 0.423333,0.592666 0,0.592667 -0.465666,1.058334 -0.465667,0.423333 -1.143,0.846666 -0.677334,0.423334 -1.312334,0.973667 -0.635,0.508 -0.973666,1.312333 l 1.820333,0.254 q 1.439333,-1.27 3.259667,-2.074333 1.862666,-0.846667 3.937,-0.846667 0.677333,0 1.058333,0.169334 0.423333,0.127 0.423333,0.592666 0,0.677334 -0.635,1.227667 -0.592666,0.550333 -1.397,1.100667 -0.804333,0.508 -1.439333,1.227666 0.465667,0.127 0.889,0.296334 0.423333,0.127 0.846667,0.254 1.269999,-0.846667 2.751666,-1.439334 1.524,-0.592666 3.090333,-0.592666 0.677334,0 1.058334,0.169333 0.423333,0.169333 0.423333,0.592667 0,0.889 -0.931333,1.439333 -0.931334,0.550333 -1.862667,1.312333 1.143,0.296333 2.201333,0.508 1.100667,0.211667 2.116667,0.211667 1.354667,0 2.582333,-0.635 1.227667,-0.677334 2.243667,-1.481667 1.058333,-0.846666 1.778,-1.397 0.296333,-0.211666 0.846666,-0.719666 0.550334,-0.550334 1.143,-1.016 0.592667,-0.465667 0.973667,-0.465667 0.635,0 0.973667,0.719667 0.381,0.677333 0.381,1.227666 0,0.973667 -0.550334,2.074333 -0.550333,1.100667 -1.312333,2.201334 -0.719667,1.058333 -1.27,2.032 -0.550333,0.931333 -0.550333,1.608666 v 0.550334 q 0,0.677333 0.550333,1.651 0.550333,0.931333 1.27,2.032 0.762,1.058333 1.312333,2.158999 0.550334,1.100667 0.550334,2.074334 0,0.592666 -0.381,1.27 -0.338667,0.677333 -0.973667,0.677333 -0.381,0 -0.973667,-0.465667 -0.592666,-0.465666 -1.143,-0.973666 -0.550333,-0.550334 -0.846666,-0.762 -0.719667,-0.550334 -1.778,-1.354667 -1.016,-0.846667 -2.243667,-1.481667 -1.227666,-0.677333 -2.582333,-0.677333 -1.016,0 -2.116667,0.211667 -1.058333,0.169333 -2.201333,0.508 0.931333,0.762 1.862667,1.312333 0.931333,0.550333 0.931333,1.439333 0,0.465667 -0.423333,0.635 -0.381,0.127 -1.058334,0.127 -1.566333,0 -3.090333,-0.592666 -1.481667,-0.635 -2.751666,-1.439334 -0.423334,0.127 -0.846667,0.296334 -0.423333,0.127 -0.889,0.254 0.635,0.677333 1.439333,1.227666 0.804334,0.550334 1.397,1.100667 0.635,0.550333 0.635,1.227667 0,0.423333 -0.423333,0.592666 -0.381,0.169334 -1.058333,0.169334 -2.074334,0 -3.937,-0.846667 -1.820334,-0.804333 -3.259667,-2.074333 l -1.820333,0.254 q 0.338666,0.804333 0.973666,1.312333 0.635,0.550333 1.312334,0.973667 0.677333,0.423333 1.143,0.846666 0.465666,0.465667 0.465666,1.058334 0,0.423333 -0.423333,0.592666 -0.381,0.169334 -1.058333,0.169334 z m -7.493,-22.563666 q 0.550333,-0.08467 1.143,-0.127 0.592667,-0.08467 1.185333,-0.08467 0.423334,0 0.804334,0 0.380999,0 0.804333,0.04233 0.508,-1.439333 1.524,-2.159 1.016,-0.762 1.947333,-1.566333 -0.127,-0.04233 -0.381,-0.04233 -1.735667,0 -3.640667,1.100666 -1.904999,1.100667 -3.386666,2.836334 z m 11.006666,1.227666 q 0.592667,-0.846666 1.439334,-1.524 0.846666,-0.719666 1.566333,-1.312333 -0.127,-0.04233 -0.381,-0.04233 -1.227667,0 -2.624667,0.635 -1.397,0.592666 -2.624666,1.566333 0.677333,0.169333 1.312333,0.338667 0.677333,0.169333 1.312333,0.338666 z m 21.209,16.298333 q 0.127,-0.254 0.127,-0.508 0,-0.804333 -0.592667,-1.820333 -0.550333,-1.058334 -1.354667,-2.159 -0.762,-1.143 -1.354666,-2.159 -0.550334,-1.058333 -0.550334,-1.820333 v -0.550334 q 0,-0.762 0.550334,-1.778 0.592666,-1.058333 1.354666,-2.159 0.804334,-1.143 1.354667,-2.159 0.592667,-1.058333 0.592667,-1.862666 0,-0.254 -0.127,-0.508 -1.100667,1.100667 -2.497667,2.370666 -1.397,1.227667 -3.090333,2.201334 -1.651,0.931333 -3.513667,1.016 v 6.307666 q 1.862667,0.127 3.513667,1.058334 1.693333,0.931333 3.090333,2.201333 1.397,1.27 2.497667,2.328333 z m -29.844999,-1.016 q 3.174999,0 5.799666,-0.635 2.667,-0.635 4.953,-1.481667 2.328333,-0.846666 4.445,-1.523999 2.159,-0.719667 4.275666,-0.889 v -6.392334 q -2.116666,-0.169333 -4.275666,-0.846666 -2.116667,-0.719667 -4.445,-1.566334 -2.286,-0.846666 -4.953,-1.481666 -2.624667,-0.635 -5.799666,-0.635 -2.878667,0 -5.418667,1.100667 -2.54,1.100666 -4.953,2.878666 -2.413,1.778 -4.868333,3.767667 2.413,1.989666 4.826,3.767666 2.413,1.735667 4.953,2.836333 2.582333,1.100667 5.461,1.100667 z M 80.972098,47.286713 q 0.592667,-0.592667 1.227667,-1.058333 0.635,-0.465667 1.227667,-0.973667 -0.127,-0.04233 -0.381,-0.04233 -0.973667,0 -2.032,0.381 -1.058334,0.381 -2.116667,1.016 0.550333,0.169333 1.058333,0.338666 0.508,0.169334 1.016,0.338667 z m -17.017999,9.440333 q 0.08467,-0.804333 0.635,-1.439333 0.550333,-0.635 0.550333,-1.354667 0,-0.550333 -0.423333,-0.973666 -0.423333,-0.423334 -0.846667,-0.931334 -0.381,-0.508 -0.381,-1.354666 0,-0.846667 0.423334,-1.481667 0.465666,-0.677333 0.550333,-1.439333 l 1.227667,0.127 q -0.08467,0.592666 -0.508,1.312333 -0.423334,0.719667 -0.423334,1.354667 0,0.635 0.381,1.143 0.423334,0.465666 0.846667,1.016 0.423333,0.508 0.423333,1.227666 0,0.550334 -0.296333,0.973667 -0.296333,0.423333 -0.592667,0.846667 -0.296333,0.423333 -0.296333,0.889 z m 8.466666,0 q 0.08467,-0.804333 0.635,-1.439333 0.550334,-0.635 0.550334,-1.354667 0,-0.550333 -0.423334,-0.973666 -0.423333,-0.423334 -0.846666,-0.931334 -0.381,-0.508 -0.381,-1.354666 0,-0.846667 0.423333,-1.481667 0.465667,-0.677333 0.550333,-1.439333 l 1.227667,0.127 q -0.08467,0.592666 -0.508,1.312333 -0.423333,0.719667 -0.423333,1.354667 0,0.635 0.381,1.143 0.423333,0.465666 0.846666,1.016 0.423334,0.508 0.423334,1.227666 0,0.550334 -0.296334,0.973667 -0.296333,0.423333 -0.592666,0.846667 -0.296334,0.423333 -0.296334,0.889 z m -4.233333,0 q 0.08467,-0.804333 0.635,-1.439333 0.550333,-0.635 0.550333,-1.354667 0,-0.550333 -0.423333,-0.973666 -0.423333,-0.423334 -0.846667,-0.931334 -0.381,-0.508 -0.381,-1.354666 0,-0.846667 0.423334,-1.481667 0.465666,-0.677333 0.550333,-1.439333 l 1.227667,0.127 q -0.08467,0.592666 -0.508,1.312333 -0.423334,0.719667 -0.423334,1.354667 0,0.635 0.381,1.143 0.423334,0.465666 0.846667,1.016 0.423333,0.508 0.423333,1.227666 0,0.550334 -0.296333,0.973667 -0.296333,0.423333 -0.592667,0.846667 -0.296333,0.423333 -0.296333,0.889 z m -10.879666,-3.429 q -0.804334,0 -1.354667,-0.508 -0.508,-0.550333 -0.508,-1.354666 0,-0.762 0.508,-1.312334 0.550333,-0.592666 1.354667,-0.592666 0.762,0 1.312333,0.592666 0.592667,0.550334 0.592667,1.312334 0,0.804333 -0.592667,1.354666 -0.550333,0.508 -1.312333,0.508 z m 25.738666,7.112 q 0.254,0 0.381,-0.04233 -0.592667,-0.508 -1.227667,-0.973667 -0.635,-0.465667 -1.227667,-1.058333 -0.508,0.169333 -1.016,0.338666 -0.508,0.127 -1.058333,0.338667 1.058333,0.635 2.116667,1.016 1.058333,0.381 2.032,0.381 z m -5.588,2.836333 q 0.254,0 0.381,-0.04233 -0.719667,-0.592667 -1.566333,-1.312333 -0.846667,-0.719667 -1.439334,-1.524 -0.635,0.211666 -1.312333,0.381 -0.635,0.127 -1.312333,0.296333 1.227666,0.973667 2.624666,1.608667 1.397,0.592666 2.624667,0.592666 z m -6.604,2.286 q 0.254,0 0.381,-0.04233 -0.931333,-0.804333 -1.947333,-1.566333 -1.016,-0.719667 -1.524,-2.159 -0.423334,0.04233 -0.804333,0.04233 -0.381,0 -0.804334,0 -0.592666,0 -1.185333,-0.04233 -0.592667,-0.08467 -1.143,-0.169334 1.481667,1.693334 3.386666,2.794 1.905,1.143 3.640667,1.143 z" />
+ </g>
+ </g>
+</svg>
diff --git a/examples/applicationmanager/frame-timer/apps/frame-timer.fish/info.yaml b/examples/applicationmanager/frame-timer/apps/frame-timer.fish/info.yaml
new file mode 100644
index 00000000..2178b68e
--- /dev/null
+++ b/examples/applicationmanager/frame-timer/apps/frame-timer.fish/info.yaml
@@ -0,0 +1,9 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'frame-timer.fish'
+icon: 'fish.svg'
+code: 'fish.qml'
+runtime: 'qml'
+name:
+ en: 'Fish'
diff --git a/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/info.yaml b/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/info.yaml
new file mode 100644
index 00000000..a50f99ad
--- /dev/null
+++ b/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/info.yaml
@@ -0,0 +1,9 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'frame-timer.rabbit'
+icon: 'rabbit.svg'
+code: 'rabbit.qml'
+runtime: 'qml'
+name:
+ en: 'Rabbit'
diff --git a/examples/applicationmanager/monitor/system-ui/Switch.qml b/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.qml
index 6ed638fb..4e38ce61 100644
--- a/examples/applicationmanager/monitor/system-ui/Switch.qml
+++ b/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.qml
@@ -50,23 +50,30 @@
**
****************************************************************************/
-import QtQuick 2.6
+import QtQuick 2.4
+import QtApplicationManager.Application 1.0
-Rectangle {
- signal toggle()
+ApplicationManagerWindow {
+ id: root
+ color: mouseArea.pressed ? "red" : "forestgreen"
- width: 180; height: 30; radius: 4
- color: 'white'
-
- MonitorText {
+ Rectangle {
anchors.centerIn: parent
- text: 'Switch Process'
- font.bold: true
- color: 'black'
+ width: 180; height: 180; radius: width/4
+ color: "palegreen"
+
+ Image {
+ source: ApplicationInterface.icon
+ anchors.centerIn: parent
+ }
+
+ RotationAnimation on rotation {
+ from: 0; to: 360; loops: Animation.Infinite; duration: 4000
+ }
}
MouseArea {
+ id: mouseArea
anchors.fill: parent
- onClicked: toggle();
}
}
diff --git a/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.svg b/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.svg
new file mode 100644
index 00000000..639841df
--- /dev/null
+++ b/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.svg
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ width="51.880001mm"
+ height="51.880001mm"
+ viewBox="0 0 51.879999 51.879998"
+ version="1.1"
+ id="svg4565">
+ <title
+ id="title815">U+1448C ANATOLIAN HIEROGLYPH A115A from Noto Sans font</title>
+ <defs
+ id="defs4559" />
+ <metadata
+ id="metadata4562">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>U+1448C ANATOLIAN HIEROGLYPH A115A from Noto Sans font</dc:title>
+ <cc:license
+ rdf:resource="http://scripts.sil.org/OFL" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://scripts.sil.org/OFL">
+ <cc:permits
+ rdf:resource="http://scripts.sil.org/pub/OFL/Reproduction" />
+ <cc:permits
+ rdf:resource="http://scripts.sil.org/pub/OFL/Distribution" />
+ <cc:permits
+ rdf:resource="http://scripts.sil.org/pub/OFL/Embedding" />
+ <cc:permits
+ rdf:resource="http://scripts.sil.org/pub/OFL/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://scripts.sil.org/pub/OFL/Notice" />
+ <cc:requires
+ rdf:resource="http://scripts.sil.org/pub/OFL/Attribution" />
+ <cc:requires
+ rdf:resource="http://scripts.sil.org/pub/OFL/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://scripts.sil.org/pub/OFL/DerivativeRenaming" />
+ <cc:requires
+ rdf:resource="http://scripts.sil.org/pub/OFL/BundlingWhenSelling" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ transform="matrix(1.1970749,0,0,1.1970749,-89.370004,-96.553259)">
+ <g
+ id="text5112"
+ style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332">
+ <path
+ id="path815"
+ style="font-size:42.33333206px;stroke-width:0.26458332"
+ d="m 109.57681,120.95381 q -1.43934,0 -1.905,-0.508 -0.46567,-0.508 -0.46567,-1.18533 0,-0.254 0.254,-0.67733 0.29633,-0.46567 0.55033,-0.93134 0.29634,-0.508 0.29634,-0.889 0,-0.59266 -0.93134,-0.59266 -0.635,0 -1.56633,0.16933 -0.889,0.127 -1.69333,0.127 -1.10067,0 -1.905,-0.97367 -0.762,-0.97366 -1.10067,-2.49766 -1.05833,0.42333 -3.217334,0.84666 -2.159,0.42334 -4.487334,0.42334 -0.635,0 -1.524,-0.127 -0.846666,-0.16934 -1.523999,-0.16934 -0.931334,0 -1.439334,0.635 -0.465666,0.59267 -0.804333,1.524 -0.296333,0.889 -0.677333,1.82034 -0.381,0.93133 -1.100667,1.56633 -0.677333,0.59267 -1.947333,0.59267 h -2.794 q -0.931334,0 -1.566334,-0.59267 -0.592666,-0.635 -0.592666,-1.18533 0,-0.93134 0.677333,-1.48167 0.677333,-0.59267 1.566333,-1.016 0.931334,-0.46567 1.608667,-0.97367 0.169333,-1.31233 0.719667,-3.048 0.592666,-1.778 2.370666,-3.25966 0.550334,-0.46567 1.016,-0.55034 0.465667,-0.127 0.465667,-0.93133 0,-0.16933 -0.127,-0.42333 -0.08467,-0.254 -0.296333,-0.254 -0.762,0 -1.481667,0.42333 -0.677333,0.381 -1.439333,0.80433 -0.719667,0.381 -1.524,0.381 -0.931334,0 -1.820334,-0.59266 -0.846666,-0.59267 -1.396999,-1.48167 -0.550334,-0.889 -0.550334,-1.778 0,-1.82033 1.143,-3.25967 1.143,-1.481662 2.667,-2.582329 -0.338667,-1.058333 -0.550333,-2.582333 -0.169334,-1.524 -0.296334,-3.048 -0.08467,-1.524 -0.08467,-2.582333 0,-1.481667 0.254,-2.963333 0.254,-1.481667 0.889,-2.455334 0.635,-0.973666 1.735666,-0.973666 0.931334,0 1.439334,0.846666 0.550333,0.846667 0.762,1.989667 0.211666,1.100667 0.211666,1.905 0,1.947333 -0.465666,3.81 -0.465667,1.862666 -0.465667,3.81 0,0.889 0.169333,1.27 0.169334,0.381 0.677334,0.381 1.016,0 1.651,-1.016 0.635,-1.058334 1.524,-2.751667 0.338666,-0.635 0.931333,-1.862667 0.635,-1.27 1.524,-2.624666 0.889,-1.354667 2.074333,-2.286 1.227667,-0.931333 2.751667,-0.931333 0.592666,0 1.143,0.762 0.550333,0.719666 0.550333,1.862666 0,1.27 -0.804333,2.667 -0.804334,1.397 -1.989667,2.794 -1.185333,1.397 -2.370667,2.709333 -1.185333,1.312334 -1.989666,2.413 -0.804334,1.100669 -0.804334,1.947329 0,0.55034 0.381,0.80434 0.423334,0.21166 0.846667,0.21166 4.318,0 7.366005,-0.0847 3.09033,-0.127 5.207,-0.46567 0.71967,-0.42333 1.60867,-0.71967 0.93133,-0.29633 2.11666,-0.29633 1.778,0 2.921,1.35467 1.18534,1.31233 1.18534,3.429 0,1.35466 -0.42334,1.905 -0.42333,0.508 -1.05833,0.635 -0.59267,0.0847 -1.18533,0.127 -0.59267,0.0423 -1.016,0.381 -0.42334,0.33866 -0.42334,1.397 0,0.889 0.635,1.397 0.635,0.508 1.22767,0.762 1.73567,0.80433 2.11667,1.35466 0.42333,0.508 0.42333,1.22767 0,1.05833 -0.42333,2.159 -0.42334,1.05833 -1.05834,1.98967 -0.635,0.889 -1.31233,1.43933 -0.635,0.55033 -1.05833,0.55033 z m 0.0847,-1.397 q 0.29634,0 0.84667,-0.71966 0.55033,-0.762 0.97367,-1.778 0.46566,-1.016 0.46566,-1.905 0,-0.71967 -0.381,-1.05834 -0.33866,-0.33866 -1.31233,-0.762 -1.05833,-0.508 -1.778,-1.43933 -0.71967,-0.93133 -0.71967,-2.07433 0,-1.18534 0.381,-1.69334 0.42334,-0.55033 1.016,-0.71966 0.635,-0.21167 1.22767,-0.29634 0.635,-0.0847 1.016,-0.33866 0.42333,-0.29634 0.42333,-1.016 0,-1.524 -0.84666,-2.58234 -0.80434,-1.05833 -2.11667,-1.05833 -1.10067,0 -1.73567,0.29633 -0.59266,0.254 -1.35466,0.67734 -1.48167,0.254 -3.64067,0.381 -2.11667,0.127 -4.572001,0.16933 -2.455333,0.0423 -4.953,0.0423 -1.143,0 -1.778,-0.508 -0.592666,-0.508 -0.592666,-1.82033 0,-1.05833 0.804333,-2.243665 0.804333,-1.227667 1.989666,-2.54 1.185334,-1.312334 2.328334,-2.624667 1.185333,-1.354667 1.989666,-2.624667 0.804334,-1.27 0.804334,-2.370666 0,-0.338667 -0.127,-0.889 -0.127,-0.550333 -0.762,-0.550333 -0.804334,0 -1.651,0.804333 -0.846667,0.804333 -1.693334,2.074333 -0.846666,1.227667 -1.608666,2.582333 -0.719667,1.312334 -1.312333,2.413 -0.592667,1.058334 -0.973667,1.862667 -0.381,0.762 -1.016,1.185333 -0.592667,0.423334 -1.820333,0.423334 -0.973667,0 -1.439334,-0.635 -0.423333,-0.677334 -0.423333,-1.524 0,-1.989667 0.381,-3.894667 0.423333,-1.947333 0.423333,-3.894667 0,-0.719666 -0.08467,-1.650999 -0.04233,-0.931334 -0.296334,-1.608667 -0.211666,-0.677333 -0.677333,-0.677333 -0.677333,0 -1.058333,0.889 -0.338667,0.846666 -0.508,2.032 -0.127,1.142999 -0.127,2.031999 0,1.143 0.04233,2.667 0.04233,1.524 0.169333,3.005667 0.127,1.481667 0.423334,2.497667 0.127,0.254 0.127,0.465666 0,0.169334 -0.127,0.296334 -0.08467,0.08467 -0.211667,0.211666 -0.677333,0.550333 -1.439333,1.227669 -0.762,0.67733 -1.312334,1.56633 -0.508,0.889 -0.508,2.20133 0,0.80434 0.677334,1.73567 0.677333,0.93133 1.735666,0.93133 0.804334,0 1.524,-0.381 0.719667,-0.42333 1.439334,-0.80433 0.762,-0.42333 1.651,-0.42333 0.719666,0 1.185333,0.508 0.465667,0.508 0.465667,1.22766 0,0.97367 -0.381,1.397 -0.338667,0.42334 -0.889,0.67734 -0.508,0.254 -1.058334,0.80433 -1.185333,1.18533 -1.651,2.49767 -0.423333,1.31233 -0.592666,2.667 -0.08467,0.635 -0.592667,1.016 -0.508,0.381 -1.185333,0.71966 -0.677334,0.29634 -1.27,0.67734 -0.550334,0.381 -0.804334,1.05833 0.211667,0.21167 0.423334,0.33867 0.254,0.127 1.058333,0.127 h 2.54 q 0.677333,0 1.058333,-0.59267 0.423334,-0.635 0.762,-1.56633 0.338667,-0.93134 0.762,-1.86267 0.423334,-0.93133 1.100667,-1.524 0.677333,-0.635 1.778,-0.635 0.592667,0 1.397,0.21167 0.804333,0.21166 1.481666,0.21166 2.413,0 4.572,-0.42333 2.159,-0.46567 3.217335,-0.889 -0.0423,-0.21167 -0.0423,-0.42333 0,-0.254 0,-0.46567 l 1.18534,0.254 q 0,1.86267 0.55033,2.96333 0.55033,1.10067 1.905,1.10067 0.33867,0 1.10067,-0.0847 0.762,-0.0847 1.48166,-0.127 0.71967,-0.0847 0.93134,-0.0847 0.762,0 1.05833,0.42333 0.33867,0.381 0.33867,0.84667 0,1.05833 -0.508,1.69333 -0.46567,0.635 -0.46567,0.84667 0,0.59266 0.29633,0.71966 0.33867,0.127 0.889,0.127 z m -24.722664,-17.272 q -0.465667,0 -0.846667,-0.33866 -0.338666,-0.381 -0.338666,-0.84667 0,-0.508 0.338666,-0.84667 0.381,-0.380996 0.846667,-0.380996 0.508,0 0.846667,0.380996 0.381,0.33867 0.381,0.84667 0,0.46567 -0.381,0.84667 -0.338667,0.33866 -0.846667,0.33866 z" />
+ </g>
+ </g>
+</svg>
diff --git a/examples/applicationmanager/frame-timer/doc/images/frame-timer-example.png b/examples/applicationmanager/frame-timer/doc/images/frame-timer-example.png
new file mode 100644
index 00000000..6654660f
--- /dev/null
+++ b/examples/applicationmanager/frame-timer/doc/images/frame-timer-example.png
Binary files differ
diff --git a/examples/applicationmanager/frame-timer/doc/src/frame-timer-example.qdoc b/examples/applicationmanager/frame-timer/doc/src/frame-timer-example.qdoc
new file mode 100644
index 00000000..a6f90b72
--- /dev/null
+++ b/examples/applicationmanager/frame-timer/doc/src/frame-timer-example.qdoc
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:FDL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\example applicationmanager/frame-timer
+\title Displaying Frame-Rate of System-UI and Applications Example
+\image frame-timer-example.png The "FrameTimer" example with two applications running.
+\brief How to use FrameTimer to display frame-rate information.
+\ingroup applicationmanager-examples
+
+This example shows you how to use the \l FrameTimer component to display frame-rate information
+of both System-UI and application windows.
+
+The System-UI is comprised of a column of application icons on the left side and a graph on the top
+right side, displaying the average frame-rate of the System-UI itself (actually of System-UI's top-level
+Window, to be more precise). If there are no applications running, System-UI's frame rate will mostly
+stay at 1 frame per second. That's because a Qt QML application window is only redrawn when needed. If
+nothing changed on it, it won't redraw (zero frames per second then). The only reason that System-UI
+stays around 1 FPS when there are no apps running is because of the FPS graph itself, which is updated
+once every second and thus causes a redraw of the System-UI (an
+\l{https://en.wikipedia.org/wiki/Observer_effect_(information_technology)}{Observer effect}).
+
+The Fish application animates (and therefore redraws) at a rate of 25 frames per second. So running it will
+instantly raise the frame-rate of System-UI to 25 FPS (frames per second) as well.
+
+The Rabbit application animates at native speed (ie, as fast as the system can or is configured to do, which
+is usually 60 FPS). So running it will raise System-UI's FPS further, to 60 FPS.
+
+*/
diff --git a/examples/applicationmanager/monitor/monitor.pro b/examples/applicationmanager/frame-timer/frame-timer.pro
index c77dbd4f..e35a8a9d 100644
--- a/examples/applicationmanager/monitor/monitor.pro
+++ b/examples/applicationmanager/frame-timer/frame-timer.pro
@@ -3,14 +3,15 @@ CONFIG += am-systemui
OTHER_FILES += \
am-config.yaml \
- monitor.qmlproject \
- doc/src/*.qdoc \
- doc/images/*.png \
system-ui/*.qml \
- apps/tld.monitor.app/*.yaml \
- apps/tld.monitor.app/*.qml
+ apps/frame-timer.fish/*.yaml \
+ apps/frame-timer.fish/*.qml \
+ apps/frame-timer.fish/*.svg \
+ apps/frame-timer.rabbit/*.yaml \
+ apps/frame-timer.rabbit/*.qml \
+ apps/frame-timer.rabbit/*.svg \
-target.path = $$[QT_INSTALL_EXAMPLES]/applicationmanager/monitor
+target.path = $$[QT_INSTALL_EXAMPLES]/applicationmanager/frame-timer
INSTALLS += target
AM_COPY_DIRECTORIES += apps system-ui
@@ -19,8 +20,8 @@ AM_COPY_FILES += am-config.yaml
prefix_build:tpath = $$target.path
else:tpath = $$_PRO_FILE_PWD_
-AM_DEFAULT_ARGS = -c $$tpath/am-config.yaml --start-session-dbus --verbose
+AM_DEFAULT_ARGS = -c $$tpath/am-config.yaml --start-session-dbus --verbose -r
example_sources.path = $$target.path
-example_sources.files = $$AM_COPY_FILES $$AM_COPY_DIRECTORIES doc
+example_sources.files = $$AM_COPY_FILES $$AM_COPY_DIRECTORIES
INSTALLS += example_sources
diff --git a/examples/applicationmanager/frame-timer/system-ui/main.qml b/examples/applicationmanager/frame-timer/system-ui/main.qml
new file mode 100644
index 00000000..2c13f84c
--- /dev/null
+++ b/examples/applicationmanager/frame-timer/system-ui/main.qml
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+
+import QtQuick 2.11
+import QtQuick.Layouts 1.11
+import QtQuick.Window 2.11
+import QtApplicationManager 1.0
+import QtApplicationManager.SystemUI 1.0
+
+Window {
+ id: sysuiWindow
+
+ width: 1024
+ height: 640
+
+ Rectangle {
+ anchors.fill: parent
+ color: "linen"
+
+
+ // A graph displaying the FPS of the System UI itself
+ Rectangle {
+ id: fpsGraph
+ anchors.top: parent.top
+ anchors.right: parent.right
+ width: 500
+ height: 200
+ color: "grey"
+ ListView {
+ id: listView
+ anchors.fill: parent
+ orientation: ListView.Horizontal
+ spacing: (fpsGraph.width / model.count) * 0.2
+ clip: true
+ interactive: false
+
+ model: MonitorModel {
+ id: monitorModel
+ running: true
+ // Just put a FrameTimer inside a MonitorModel and you can use it as a data source
+ // There's no need to set its running property as the MonitorModel will take care of asking
+ // it to update itself when appropriate.
+ FrameTimer { window: sysuiWindow }
+ }
+
+ delegate: Rectangle {
+ width: (fpsGraph.width / monitorModel.count) * 0.8
+ height: (model.averageFps / 100) * fpsGraph.height
+ y: fpsGraph.height - height
+ color: "blue"
+ }
+ }
+
+ Text {
+ anchors.top: parent.top
+ text: "100"
+ font.pixelSize: 15
+ }
+
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ text: "50"
+ font.pixelSize: 15
+ }
+
+ Text {
+ anchors.bottom: parent.bottom
+ text: "0"
+ font.pixelSize: 15
+ }
+ }
+
+
+ // Application icons.
+ // Click on an icon to start its application and click on it again to stop it.
+ ColumnLayout {
+ anchors.left: parent.left
+ anchors.top: parent.top
+ anchors.margins: 10
+ spacing: 15
+ Repeater {
+ model: ApplicationManager
+ ColumnLayout {
+ Layout.alignment: Qt.AlignHCenter
+ Rectangle {
+ Layout.alignment: Qt.AlignHCenter
+ width: 100; height: 100; radius: width/4
+ color: model.isRunning ? "darkgrey" : "lightgrey"
+ Image {
+ anchors.fill: parent
+ source: icon
+ sourceSize.width: 100
+ sourceSize.height: 100
+ }
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (model.isRunning)
+ application.stop();
+ else
+ application.start();
+ }
+ }
+ }
+ Text {
+ Layout.alignment: Qt.AlignHCenter
+ text: model.name + " application"
+ horizontalAlignment: Text.AlignHCenter
+ }
+ }
+ }
+ }
+
+ // Application windows.
+ // Each WindowObject is put in a WindowItem decorated with a border and a title bar.
+ Repeater {
+ model: ListModel { id: windowsModel }
+
+ delegate: Rectangle {
+ id: winChrome
+
+ width: 400; height: 320
+ z: model.index
+ color: "tan"
+
+ // Title bar text
+ Text {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: model.window.application.name("en") + " application window"
+ }
+
+ // Raises the window when the title bar is clicked and moves it around when dragged.
+ MouseArea {
+ anchors.fill: parent
+ drag.target: parent
+ onPressed: windowsModel.move(model.index, windowsModel.count-1, 1);
+ }
+
+ // Close button
+ Rectangle {
+ width: 25; height: 25
+ color: "chocolate"
+ Text {
+ anchors.fill: parent
+ fontSizeMode: Text.Fit; minimumPixelSize: 10; font.pixelSize: 25
+ horizontalAlignment: Text.AlignHCenter; verticalAlignment: Text.AlignVCenter
+ text: "x"
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: model.window.close()
+ }
+ }
+
+ // The window itself
+ WindowItem {
+ id: windowItem
+ anchors.fill: parent
+ anchors.margins: 3
+ anchors.topMargin: 25
+ window: model.window
+
+ Rectangle {
+ anchors.fill: fpsOverlay
+ color: "black"
+ opacity: 0.3
+ }
+
+ // And its FPS overlay
+ Column {
+ id: fpsOverlay
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.margins: 4
+ Text {
+ text: "averageFps: " + Number(frameTimer.averageFps).toLocaleString(Qt.locale("en_US"), 'f', 1)
+ font.pixelSize: 16; color: "white"
+ }
+ Text {
+ text: "maximumFps: " + Number(frameTimer.maximumFps).toLocaleString(Qt.locale("en_US"), 'f', 1)
+ font.pixelSize: 16; color: "white"
+ }
+ Text {
+ text: "minimumFps: " + Number(frameTimer.minimumFps).toLocaleString(Qt.locale("en_US"), 'f', 1)
+ font.pixelSize: 16; color: "white"
+ }
+ Text {
+ text: "jitterFps: " + Number(frameTimer.jitterFps).toLocaleString(Qt.locale("en_US"), 'f', 1)
+ font.pixelSize: 16; color: "white"
+ }
+ }
+ }
+
+ // FrameTimer will calculate the frame rate numbers for the given window
+ FrameTimer {
+ id: frameTimer
+ // no sense in trying to update the FrameTimer while the window has no surface (or has just an empty one)
+ running: window && window.contentState === WindowObject.SurfaceWithContent
+ window: model.window
+ }
+
+ Component.onCompleted: {
+ winChrome.x = 300 + model.index * 50;
+ winChrome.y = 10 + model.index * 30;
+ }
+
+ readonly property bool shouldBeRemoved: model.window && model.window.contentState === WindowObject.NoSurface
+ onShouldBeRemovedChanged: if (shouldBeRemoved) windowsModel.remove(model.index, 1)
+ }
+ }
+
+ // Populates the windowsModel
+ Connections {
+ target: WindowManager
+ onWindowAdded: windowsModel.append({"window":window})
+ }
+ }
+}
diff --git a/examples/applicationmanager/monitor/apps/tld.monitor.app/dummyicon b/examples/applicationmanager/monitor/apps/tld.monitor.app/dummyicon
deleted file mode 100644
index e69de29b..00000000
--- a/examples/applicationmanager/monitor/apps/tld.monitor.app/dummyicon
+++ /dev/null
diff --git a/examples/applicationmanager/monitor/apps/tld.monitor.app/info.yaml b/examples/applicationmanager/monitor/apps/tld.monitor.app/info.yaml
deleted file mode 100644
index cd0a58c8..00000000
--- a/examples/applicationmanager/monitor/apps/tld.monitor.app/info.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-formatVersion: 1
-formatType: am-application
----
-id: 'tld.monitor.app'
-icon: 'dummyicon'
-code: 'app.qml'
-runtime: 'qml'
-name:
- en: 'Application'
diff --git a/examples/applicationmanager/monitor/doc/images/monitor.png b/examples/applicationmanager/monitor/doc/images/monitor.png
deleted file mode 100644
index d3b3cddd..00000000
--- a/examples/applicationmanager/monitor/doc/images/monitor.png
+++ /dev/null
Binary files differ
diff --git a/examples/applicationmanager/monitor/doc/src/monitor.qdoc b/examples/applicationmanager/monitor/doc/src/monitor.qdoc
deleted file mode 100644
index 5fc0faa3..00000000
--- a/examples/applicationmanager/monitor/doc/src/monitor.qdoc
+++ /dev/null
@@ -1,108 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Pelagicore Application Manager.
-**
-** $QT_BEGIN_LICENSE:FDL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite licenses may use
-** this file in accordance with the commercial license agreement provided
-** with the Software or, alternatively, in accordance with the terms
-** contained in a written agreement between you and The Qt Company. For
-** licensing terms and conditions see https://www.qt.io/terms-conditions.
-** For further information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-/*!
-
-\example applicationmanager/monitor
-\title Performance Monitoring Example
-\image monitor.png Screenshot
-\brief A resource and performance monitor.
-\ingroup applicationmanager-examples
-
-\section1 Introduction
-
-This example shows the basic usage of system and process monitoring APIs offered by the
-application-manager:
- \list
- \li SystemMonitor
- \li ProcessMonitor
- \endlist
-
-The example monitors performance (frame rate), as well as rescource usage (memory and CPU).
-
-\section2 Invocation
-The example can be started from within the "monitor" folder with:
-\badcode
-path/to/bin/appman -c am-config.yaml
-\endcode
-
-\note The application-manager attempts to register a \c freedesktop.org compliant notification
-server. DBus errors might occur if it conflicts with the server running on the host desktop
-environment. In this case, a private session bus needs to be started by adding the
-\c --start-session-dbus option.
-
-\section1 Walkthrough
-
-We will start from the bottom, because this is the essential part.
-
-\section2 SystemMonitor and ProcessMonitor Usage
-
-\quotefromfile applicationmanager/monitor/system-ui/main.qml
-\skipto ProcessMonitor
-\printuntil ApplicationManager.application(0).start()
-\printline }
-The ProcessMonitor will monitor the process that is associated with
-its \l {ProcessMonitor::applicationId}{applicationId} property. An empty applicationId string means
-that the System-UI process is monitored. By clicking the "Switch Process" button, the monitored
-process can be changed to the \c tld.monitor.app application. Measurements will be performed each
-second (1000 ms) and 12 reading points will be kept in the model (ProcessMonitor is a model).
-The model is used below to display the bar charts.
-
-Memory and frame rate reporting need to be enabled, since we are interested in both. For frame rate
-measurements the list of \c monitoredWindows has to be filled with windows that we are interested
-in. For the System-UI this is the single root window itself and for the tld.monitor.app process it
-is the currently selected window. Hence the list will always include just one element. The memory
-and frame rate changed signal handlers will update the current values of the corresponding views.
-
-The Connections type is used to implement signal handlers for the property changes of the
-SystemMonitor. The current values of the corresponding views are updated, as well.
-
-For the SystemMonitor, like above, measurements will be performed each second (1000 ms) and
-12 reading points will be kept in the model (the SystemMonitor is a model, as well).
-
-The very last line will start the only application that is provided by this example. Note that, if
-the application-manager is running in single-process mode, the application will run within the
-System-UI process and consequently the ProcessMonitor will not report anything and the associated
-ProcessMonitor::processId will be set to 0.
-
-\section2 The User Interface
-
-\quotefromfile applicationmanager/monitor/system-ui/main.qml
-\skipto import Qt
-\printto ProcessMonitor
-\dots
-
-We won't go into much detail, because it's rather conventional QML code. The MonitorChart is a
-ListView that uses either an instance of a ProcessMonitor or the SystemMonitor singleton as its
-model. The reading values are represented as bars. Their height is determined by the
-corresponding model role, e.g. for the PSS memory consumption it is \c memoryPss.total.
-
-When the tld.monitor.app process is monitored, its two windows will be shown (primary and
-secondary). The window that is monitored in terms of frame rate can be selected and is highlighted
-with a white border.
-
-*/
diff --git a/examples/applicationmanager/monitor/monitor.qmlproject b/examples/applicationmanager/monitor/monitor.qmlproject
deleted file mode 100644
index 5ce6345e..00000000
--- a/examples/applicationmanager/monitor/monitor.qmlproject
+++ /dev/null
@@ -1,17 +0,0 @@
-import QmlProject 1.1
-
-Project {
- mainFile: "system-ui/main.qml"
-
- QmlFiles {
- directory: "."
- }
- ImageFiles {
- directory: "apps"
- }
- Files {
- directory: "."
- filter: "*.yaml"
- }
-}
-
diff --git a/examples/applicationmanager/monitor/system-ui/MonitorChart.qml b/examples/applicationmanager/monitor/system-ui/MonitorChart.qml
deleted file mode 100644
index 0d49e346..00000000
--- a/examples/applicationmanager/monitor/system-ui/MonitorChart.qml
+++ /dev/null
@@ -1,97 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Pelagicore Application Manager.
-**
-** $QT_BEGIN_LICENSE:BSD-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite licenses may use
-** this file in accordance with the commercial license agreement provided
-** with the Software or, alternatively, in accordance with the terms
-** contained in a written agreement between you and The Qt Company. For
-** licensing terms and conditions see https://www.qt.io/terms-conditions.
-** For further information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: BSD-3-Clause
-**
-****************************************************************************/
-
-import QtQuick 2.6
-
-Rectangle {
- property alias title: title.text
- property alias reading: reading.text
- property alias model: listview.model
- property alias delegate: listview.delegate
-
- width: 185
- height: 250
- color: "black"
- border { width: 1; color: "white" }
-
- Rectangle {
- width: parent.width
- height: 30
- color: "black"
- border { width: 1; color: "white" }
-
- MonitorText {
- id: title
- anchors.left: parent.left
- anchors.leftMargin: 10
- anchors.verticalCenter: parent.verticalCenter
- }
-
- MonitorText {
- id: reading
- anchors.right: parent.right
- anchors.rightMargin: 10
- anchors.verticalCenter: parent.verticalCenter
- }
- }
-
- ListView {
- id: listview
- anchors.fill: parent
- anchors.margins: 10
- anchors.topMargin: 40
- orientation: ListView.Horizontal
- layoutDirection: Qt.RightToLeft
- spacing: 3
- clip: true
- }
-}
diff --git a/examples/applicationmanager/monitor/system-ui/MonitorText.qml b/examples/applicationmanager/monitor/system-ui/MonitorText.qml
deleted file mode 100644
index 263a22ec..00000000
--- a/examples/applicationmanager/monitor/system-ui/MonitorText.qml
+++ /dev/null
@@ -1,58 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Pelagicore Application Manager.
-**
-** $QT_BEGIN_LICENSE:BSD-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite licenses may use
-** this file in accordance with the commercial license agreement provided
-** with the Software or, alternatively, in accordance with the terms
-** contained in a written agreement between you and The Qt Company. For
-** licensing terms and conditions see https://www.qt.io/terms-conditions.
-** For further information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: BSD-3-Clause
-**
-****************************************************************************/
-
-import QtQuick 2.6
-
-Text {
- font.pixelSize: 14
- color: "white"
-}
diff --git a/examples/applicationmanager/monitor/system-ui/Tile.qml b/examples/applicationmanager/monitor/system-ui/Tile.qml
deleted file mode 100644
index d3a06b18..00000000
--- a/examples/applicationmanager/monitor/system-ui/Tile.qml
+++ /dev/null
@@ -1,58 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Pelagicore Application Manager.
-**
-** $QT_BEGIN_LICENSE:BSD-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite licenses may use
-** this file in accordance with the commercial license agreement provided
-** with the Software or, alternatively, in accordance with the terms
-** contained in a written agreement between you and The Qt Company. For
-** licensing terms and conditions see https://www.qt.io/terms-conditions.
-** For further information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: BSD-3-Clause
-**
-****************************************************************************/
-
-import QtQuick 2.6
-
-Item {
- width: 225
- height: 300
-}
diff --git a/examples/applicationmanager/monitor/system-ui/main.qml b/examples/applicationmanager/monitor/system-ui/main.qml
deleted file mode 100644
index 8d3a1327..00000000
--- a/examples/applicationmanager/monitor/system-ui/main.qml
+++ /dev/null
@@ -1,260 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Pelagicore Application Manager.
-**
-** $QT_BEGIN_LICENSE:BSD-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite licenses may use
-** this file in accordance with the commercial license agreement provided
-** with the Software or, alternatively, in accordance with the terms
-** contained in a written agreement between you and The Qt Company. For
-** licensing terms and conditions see https://www.qt.io/terms-conditions.
-** For further information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: BSD-3-Clause
-**
-****************************************************************************/
-
-import QtQuick 2.6
-import QtQuick.Window 2.0
-import QtApplicationManager.SystemUI 1.0
-
-Window {
- id: root
-
- property alias primaryWindow: primaryContainer.window
- property alias secondaryWindow: secondaryContainer.window
-
- width: 720
- height: 600
- color: "black"
-
- SystemMonitor {
- id: systemMonitor
- reportingInterval: 1000
- count: 12
- idleLoadThreshold: 0.05
- cpuLoadReportingEnabled: true
- gpuLoadReportingEnabled: true
- memoryReportingEnabled: true
- }
-
- Column {
- x: 10
- padding: 20
-
- Tile {
- Column {
- spacing: 10
- MonitorText { text: "System"; font.pixelSize: 26 }
- MonitorText { text: "CPU Cores: " + systemMonitor.cpuCores }
- MonitorText { text: "Total Memory: " + (systemMonitor.totalMemory / 1e9).toFixed(1) + " GB" }
- MonitorText { text: "Used Memory: " + (systemMonitor.memoryUsed / 1e9).toFixed(1) + " GB" }
- MonitorText { text: "Idle Threshold: " + systemMonitor.idleLoadThreshold * 100 + " %" }
- MonitorText { text: "Idle: " + systemMonitor.idle }
- MonitorText { text: "GPU Load: " + systemMonitor.gpuLoad * 100 + " %" }
- }
- }
-
- Tile {
- MonitorChart {
- title: "CPU Load"
- model: systemMonitor
- reading: (systemMonitor.cpuLoad * 100).toFixed(1) + " %"
- delegate: Rectangle {
- width: 11
- height: parent.height
- gradient: Gradient {
- GradientStop { position: 0.5; color: "#FF0000" }
- GradientStop { position: 1.0; color: "#00FF00" }
- }
- Rectangle {
- width: parent.width
- height: parent.height - cpuLoad * parent.height
- color: "black"
- }
- }
- }
- }
- }
-
- Rectangle {
- x: 246; y: 25
- width: 1; height: root.height - 50
- color: "white"
- }
-
- Grid {
- columns: 2
- padding: 20
- x: 260
-
- Tile {
- Column {
- spacing: 20
-
- MonitorText {
- text: processMon.applicationId === "" ? "System-UI" : processMon.applicationId
- font.pixelSize: 26
- }
- MonitorText { text: "Process ID: " + processMon.processId }
-
- Switch {
- onToggle: {
- processMon.applicationId = processMon.applicationId === ""
- ? ApplicationManager.application(0).id : ""
- if (processMon.applicationId !== "") {
- if (ApplicationManager.singleProcess)
- console.warn("There is no dedicated application process in single-process mode");
-
- if (primaryWindow && secondaryWindow) {
- processMon.monitoredWindows = primaryContainer.active ? [primaryWindow] : [secondaryWindow]
- } else {
- processMon.monitoredWindows = []
- console.warn("No application window available. Please check your QtWayland configuration.");
- }
- } else {
- processMon.monitoredWindows = [root]
- }
- }
- }
- }
- }
-
- Tile {
- Column {
- visible: processMon.applicationId !== ""
- spacing: 20
- Item {
- width: 200; height: 65
- MonitorText { anchors.bottom: parent.bottom; text: "Application Windows:" }
- }
-
- WindowContainer {
- id: primaryContainer
- active: true
- window: root.primaryWindow
- onActivated: {
- processMon.monitoredWindows = [primaryWindow];
- secondaryContainer.active = false;
- }
- }
-
- WindowContainer {
- id: secondaryContainer
- window: root.secondaryWindow
- onActivated: {
- processMon.monitoredWindows = [secondaryWindow];
- primaryContainer.active = false;
- }
- }
- }
- }
-
- Tile {
- MonitorChart {
- id: processPss
- title: "Memory PSS"
- model: processMon
- delegate: Rectangle {
- width: 11
- height: memoryPss.total / 5e6
- anchors.bottom: parent.bottom
- color: "lightsteelblue"
- }
- }
- }
-
- Tile {
- MonitorChart {
- id: frameChart
- title: "Frame rate"
- model: processMon
- delegate: Rectangle {
- width: 11
- height: frameRate[0] ? frameRate[0].average * 3 : 0
- anchors.bottom: parent.bottom
- color.r: frameRate[0] ? (frameRate[0].average >= 60 ? 0 : 1 - frameRate[0].average / 60) : 0
- color.g: frameRate[0] ? (frameRate[0].average >= 60 ? 1 : frameRate[0].average / 60) : 0
- color.b: 0
-
- }
- }
- }
- }
-
- Connections {
- target: WindowManager
- onWindowAdded: {
- if (window.windowProperty("windowType") === "primary") {
- primaryWindow = window
- } else {
- secondaryWindow = window
- }
- }
-
- onWindowAboutToBeRemoved: {
- if (primaryWindow === window) {
- primaryWindow = null;
- } else if (secondaryWindow === window) {
- secondaryWindow = null;
- }
- }
- }
-
- ProcessMonitor {
- id: processMon
- applicationId: ""
- reportingInterval: 1000
- count: 12
-
- memoryReportingEnabled: true
- frameRateReportingEnabled: true
- monitoredWindows: [root]
-
- onMemoryReportingChanged: processPss.reading = (memoryPss.total / 1e6).toFixed(0) + " MB";
- onFrameRateReportingChanged: {
- if (frameRate[0])
- frameChart.reading = frameRate[0].average.toFixed(0) + " fps";
- }
- }
-
- Component.onCompleted: {
- ApplicationManager.application(0).start();
- }
-}
diff --git a/examples/applicationmanager/process-status/am-config.yaml b/examples/applicationmanager/process-status/am-config.yaml
new file mode 100644
index 00000000..5db21e36
--- /dev/null
+++ b/examples/applicationmanager/process-status/am-config.yaml
@@ -0,0 +1,8 @@
+formatVersion: 1
+formatType: am-configuration
+---
+applications:
+ builtinAppsManifestDir: "${CONFIG_PWD}/apps"
+
+ui:
+ mainQml: "${CONFIG_PWD}/system-ui/main.qml"
diff --git a/examples/applicationmanager/process-status/apps/process-status.cpu-hog/icon.png b/examples/applicationmanager/process-status/apps/process-status.cpu-hog/icon.png
new file mode 100644
index 00000000..04ca44dd
--- /dev/null
+++ b/examples/applicationmanager/process-status/apps/process-status.cpu-hog/icon.png
Binary files differ
diff --git a/examples/applicationmanager/process-status/apps/process-status.cpu-hog/info.yaml b/examples/applicationmanager/process-status/apps/process-status.cpu-hog/info.yaml
new file mode 100644
index 00000000..89807bd3
--- /dev/null
+++ b/examples/applicationmanager/process-status/apps/process-status.cpu-hog/info.yaml
@@ -0,0 +1,9 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'process-status.cpu-hog'
+icon: 'icon.png'
+code: 'main.qml'
+runtime: 'qml'
+name:
+ en: 'CPU Hog'
diff --git a/examples/applicationmanager/process-status/apps/process-status.cpu-hog/main.qml b/examples/applicationmanager/process-status/apps/process-status.cpu-hog/main.qml
new file mode 100644
index 00000000..f38964cc
--- /dev/null
+++ b/examples/applicationmanager/process-status/apps/process-status.cpu-hog/main.qml
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:BSD-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: BSD-3-Clause
+**
+****************************************************************************/
+
+import QtQuick 2.4
+import QtApplicationManager.Application 1.0
+
+ApplicationManagerWindow {
+ color: "red"
+
+ Text {
+ anchors.fill: parent
+ text: "This application consumes a lot of CPU time."
+ font.pixelSize: 15
+ color: "white"
+ }
+
+ Rectangle {
+ id: rectangle
+ width: Math.min(parent.width, parent.height) / 2
+ height: width
+ anchors.centerIn: parent
+ color: "grey"
+ Timer {
+ interval: 10
+ repeat: true
+ running: true
+ onTriggered: {
+ rectangle.rotation += 1;
+ doBusyWork();
+ }
+ function doBusyWork() {
+ var i = 1;
+ var n = 1;
+ for (i = 1; i < 100000; i++) {
+ n = n + n * n / 1.5;
+ }
+ }
+ }
+ }
+}
diff --git a/examples/applicationmanager/process-status/apps/process-status.mem-hog/icon.png b/examples/applicationmanager/process-status/apps/process-status.mem-hog/icon.png
new file mode 100644
index 00000000..b149340c
--- /dev/null
+++ b/examples/applicationmanager/process-status/apps/process-status.mem-hog/icon.png
Binary files differ
diff --git a/examples/applicationmanager/process-status/apps/process-status.mem-hog/info.yaml b/examples/applicationmanager/process-status/apps/process-status.mem-hog/info.yaml
new file mode 100644
index 00000000..a437b108
--- /dev/null
+++ b/examples/applicationmanager/process-status/apps/process-status.mem-hog/info.yaml
@@ -0,0 +1,9 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'process-status.mem-hog'
+icon: 'icon.png'
+code: 'main.qml'
+runtime: 'qml'
+name:
+ en: 'Memory Hog'
diff --git a/examples/applicationmanager/monitor/system-ui/WindowContainer.qml b/examples/applicationmanager/process-status/apps/process-status.mem-hog/main.qml
index 66215eb9..ba62b988 100644
--- a/examples/applicationmanager/monitor/system-ui/WindowContainer.qml
+++ b/examples/applicationmanager/process-status/apps/process-status.mem-hog/main.qml
@@ -50,29 +50,37 @@
**
****************************************************************************/
-import QtQuick 2.6
-import QtApplicationManager.SystemUI 1.0
+import QtQuick 2.4
+import QtApplicationManager.Application 1.0
-Rectangle {
- property bool active: false
- property alias window: windowItem.window
- signal activated()
+ApplicationManagerWindow {
+ id: root
+ color: "green"
- width: 180; height: 65
-
- color: active ? "white" : "transparent"
-
- WindowItem {
- id: windowItem
- anchors.margins: 2
+ Text {
anchors.fill: parent
+ text: "This application consumes a lot of memory."
+ font.pixelSize: 15
+ color: "white"
}
- MouseArea {
- anchors.fill: parent
- onClicked: {
- active = true;
- activated();
+ Rectangle {
+ id: rectangle
+ width: Math.min(parent.width, parent.height) / 2
+ height: width
+ anchors.centerIn: parent
+ color: "grey"
+ Timer {
+ interval: 10
+ repeat: true
+ running: true
+ onTriggered: {
+ rectangle.rotation += 1;
+ root.contentItem.grabToImage(function(result) {
+ foo.push(result);
+ });
+ }
+ property var foo: []
}
}
}
diff --git a/examples/applicationmanager/process-status/apps/process-status.slim/icon.png b/examples/applicationmanager/process-status/apps/process-status.slim/icon.png
new file mode 100644
index 00000000..be6ffc57
--- /dev/null
+++ b/examples/applicationmanager/process-status/apps/process-status.slim/icon.png
Binary files differ
diff --git a/examples/applicationmanager/process-status/apps/process-status.slim/info.yaml b/examples/applicationmanager/process-status/apps/process-status.slim/info.yaml
new file mode 100644
index 00000000..3c148ed4
--- /dev/null
+++ b/examples/applicationmanager/process-status/apps/process-status.slim/info.yaml
@@ -0,0 +1,9 @@
+formatVersion: 1
+formatType: am-application
+---
+id: 'process-status.slim'
+icon: 'icon.png'
+code: 'main.qml'
+runtime: 'qml'
+name:
+ en: 'Slim'
diff --git a/examples/applicationmanager/monitor/apps/tld.monitor.app/ApplicationWindow.qml b/examples/applicationmanager/process-status/apps/process-status.slim/main.qml
index bcafcc7a..5967789b 100644
--- a/examples/applicationmanager/monitor/apps/tld.monitor.app/ApplicationWindow.qml
+++ b/examples/applicationmanager/process-status/apps/process-status.slim/main.qml
@@ -50,31 +50,33 @@
**
****************************************************************************/
-import QtQuick 2.4
+import QtQuick 2.11
import QtApplicationManager.Application 1.0
ApplicationManagerWindow {
- id: root
+ color: "blue"
- property alias title: title.text
- property alias idle: pause.duration
- property string windowType
-
- color: "darkgreen"
-
- Text{
- id: title
+ Text {
+ anchors.fill: parent
+ text: "This a slim application that just animates."
+ font.pixelSize: 15
color: "white"
- anchors.centerIn: parent
}
- SequentialAnimation on color {
- loops: Animation.Infinite
- ColorAnimation { to: "darkolivegreen"; duration: 500 }
- PauseAnimation { id: pause; duration: 0 }
- ColorAnimation { to: "darkgreen"; duration: 500 }
- PauseAnimation { duration: pause.duration }
- }
+ Rectangle {
+ id: rectangle
+ width: Math.min(parent.width, parent.height) / 2
+ height: width
+ anchors.centerIn: parent
+ color: "grey"
+ RotationAnimation {
+ target: rectangle
+ from: 0
+ to: 360
+ duration: 1000
+ running: true
+ loops: Animation.Infinite
+ }
- onWindowTypeChanged: root.setWindowProperty("windowType", windowType)
+ }
}
diff --git a/examples/applicationmanager/process-status/doc/images/process-status-example.png b/examples/applicationmanager/process-status/doc/images/process-status-example.png
new file mode 100644
index 00000000..6c7df5e4
--- /dev/null
+++ b/examples/applicationmanager/process-status/doc/images/process-status-example.png
Binary files differ
diff --git a/examples/applicationmanager/process-status/doc/src/process-status-example.qdoc b/examples/applicationmanager/process-status/doc/src/process-status-example.qdoc
new file mode 100644
index 00000000..0cad1578
--- /dev/null
+++ b/examples/applicationmanager/process-status/doc/src/process-status-example.qdoc
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:FDL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\example applicationmanager/process-status
+\title Displaying Information About Application Processes
+\image process-status-example.png
+\brief How to use ProcessStatus to display application process information.
+\ingroup applicationmanager-examples
+
+This example shows you how to use the \l ProcessStatus component to display information
+about an application's process.
+
+This example is based on the simpler \l {"Hello World!" System-UI Example} {Hello World} one. You might
+want to start from there if you haven't seen it already.
+
+On the left side the built-in applications are listed in a column, where each application has a row containing
+its icon and name next to a tabbed view that shows information about the application's process (in case the
+application is actually running).
+
+On the right side of the System-UI the windows of the running applications are stacked in a column, in order of
+appearance (oldest window at the top and youngest at the bottom).
+
+There are three applications available, a red one called "CPU Hog" which consumes a lot of CPU, a green one
+called "Memory Hog" that continually increases its memory consumption (so don't leave it running for too long
+as it will eat up all available RAM eventually) and a blue one called "Slim", which behaves normally.
+
+*/
diff --git a/examples/applicationmanager/process-status/process-status.pro b/examples/applicationmanager/process-status/process-status.pro
new file mode 100644
index 00000000..e2a794d0
--- /dev/null
+++ b/examples/applicationmanager/process-status/process-status.pro
@@ -0,0 +1,17 @@
+TEMPLATE = app
+CONFIG += am-systemui
+
+target.path = $$[QT_INSTALL_EXAMPLES]/applicationmanager/process-status
+INSTALLS += target
+
+AM_COPY_DIRECTORIES += apps system-ui
+AM_COPY_FILES += am-config.yaml
+
+prefix_build:tpath = $$target.path
+else:tpath = $$_PRO_FILE_PWD_
+
+AM_DEFAULT_ARGS = -c $$tpath/am-config.yaml --start-session-dbus --verbose -r
+
+example_sources.path = $$target.path
+example_sources.files = $$AM_COPY_FILES $$AM_COPY_DIRECTORIES
+INSTALLS += example_sources
diff --git a/examples/applicationmanager/process-status/system-ui/ApplicationDisplay.qml b/examples/applicationmanager/process-status/system-ui/ApplicationDisplay.qml
new file mode 100644
index 00000000..652cffd4
--- /dev/null
+++ b/examples/applicationmanager/process-status/system-ui/ApplicationDisplay.qml
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.4
+import QtApplicationManager.SystemUI 1.0
+import QtQuick.Controls 2.4
+import QtQuick.Layouts 1.11
+
+Frame {
+ id: root
+ property string name
+ property var application
+
+ width: 450
+
+ RowLayout {
+ width: parent.width
+
+ Column {
+ id: iconAndText
+
+ Image {
+ source: root.application.icon
+ MouseArea {
+ anchors.fill: parent
+ onClicked: root.application.runState === Am.Running ? application.stop() : application.start()
+ }
+ }
+ Label {
+ font.pixelSize: 18
+ text: root.name
+ }
+
+ }
+
+ Frame {
+ opacity: root.application.runState === Am.Running ? 1 : 0
+ Layout.fillWidth: true
+
+ ColumnLayout {
+ width: parent.width
+ TabBar {
+ id: tabBar
+ Layout.fillWidth: true
+ TabButton {
+ text: "Stats"
+ font.pixelSize: 15
+ }
+ TabButton {
+ text: "CPU Graph"
+ font.pixelSize: 15
+ }
+ }
+
+ StackLayout {
+ Layout.fillWidth: true
+ currentIndex: tabBar.currentIndex
+ Stats {
+ application: root.application
+ }
+ CpuGraph {
+ application: root.application
+ }
+ }
+ }
+ }
+
+ }
+}
diff --git a/examples/applicationmanager/process-status/system-ui/CpuGraph.qml b/examples/applicationmanager/process-status/system-ui/CpuGraph.qml
new file mode 100644
index 00000000..109e902b
--- /dev/null
+++ b/examples/applicationmanager/process-status/system-ui/CpuGraph.qml
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.11
+import QtQuick.Controls 2.4
+import QtApplicationManager 1.0
+import QtApplicationManager.SystemUI 1.0
+
+/*
+ This file shows how to use ProcessStatus inside a MonitorModel to draw a graph
+ */
+Pane {
+ id: root
+
+ property var application
+
+ ListView {
+ id: listView
+ anchors.fill: parent
+ orientation: ListView.Horizontal
+ spacing: (root.width / model.count) * 0.2
+ clip: true
+ interactive: false
+
+ model: MonitorModel {
+ id: monitorModel
+ running: root.visible && root.application.runState === Am.Running
+ ProcessStatus {
+ applicationId: root.application.id
+ }
+ }
+
+ delegate: Rectangle {
+ width: (root.width / monitorModel.count) * 0.8
+ height: model.cpuLoad * root.height
+ y: root.height - height
+ color: root.palette.highlight
+ }
+ }
+
+ Label {
+ anchors.top: parent.top
+ text: "100%"
+ font.pixelSize: 15
+ }
+
+ Label {
+ anchors.verticalCenter: parent.verticalCenter
+ text: "50%"
+ font.pixelSize: 15
+ }
+
+ Label {
+ anchors.bottom: parent.bottom
+ text: "0%"
+ font.pixelSize: 15
+ }
+}
diff --git a/examples/applicationmanager/process-status/system-ui/MemoryText.qml b/examples/applicationmanager/process-status/system-ui/MemoryText.qml
new file mode 100644
index 00000000..fc745d55
--- /dev/null
+++ b/examples/applicationmanager/process-status/system-ui/MemoryText.qml
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.4
+import QtQuick.Controls 2.4
+
+Label {
+ property var value
+ property string name
+ text: name + ": " + (value / 1e6).toFixed(0) + " MB"
+ font.pixelSize: 15
+}
diff --git a/examples/applicationmanager/process-status/system-ui/Stats.qml b/examples/applicationmanager/process-status/system-ui/Stats.qml
new file mode 100644
index 00000000..69e4d3ea
--- /dev/null
+++ b/examples/applicationmanager/process-status/system-ui/Stats.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.4
+import QtQuick.Controls 2.4
+import QtApplicationManager.SystemUI 1.0
+
+/*
+ This file shows how to use ProcessStatus alongside a Timer (instead of putting it inside a MonitorModel)
+ when all that is needed is the latest information on a given application process.
+ */
+Grid {
+ spacing: 10
+ columns: 2
+ rows: 5
+
+ property var application
+
+ property var status: ProcessStatus {
+ id: processStatus
+ applicationId: root.application.id
+ }
+ property var timer: Timer {
+ id: updateTimer
+ interval: 500
+ repeat: true
+ running: root.visible && root.application.runState === Am.Running
+ onTriggered: processStatus.update()
+ }
+
+
+ Label { text: "processId: " + processStatus.processId; font.pixelSize: 15 }
+ Label {
+ property string loadPercent: Number(processStatus.cpuLoad * 100).toLocaleString(Qt.locale("en_US"), 'f', 1)
+ text: "cpuLoad: " + loadPercent + "%"
+ font.pixelSize: 15
+ }
+ MemoryText { name: "PSS.total"; value: processStatus.memoryPss.total }
+ MemoryText { name: "PSS.text"; value: processStatus.memoryPss.text }
+ MemoryText { name: "PSS.heap"; value: processStatus.memoryPss.heap }
+ MemoryText { name: "RSS.total"; value: processStatus.memoryRss.total }
+ MemoryText { name: "RSS.text"; value: processStatus.memoryRss.text }
+ MemoryText { name: "RSS.heap"; value: processStatus.memoryRss.heap }
+ MemoryText { name: "Virtual.total"; value: processStatus.memoryVirtual.total }
+}
diff --git a/examples/applicationmanager/process-status/system-ui/main.qml b/examples/applicationmanager/process-status/system-ui/main.qml
new file mode 100644
index 00000000..5bc7cf68
--- /dev/null
+++ b/examples/applicationmanager/process-status/system-ui/main.qml
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+import QtQuick 2.4
+import QtQuick.Controls 2.4
+import QtApplicationManager.SystemUI 1.0
+
+Pane {
+ width: 900
+ height: appsColumn.y + appsColumn.height
+
+ // Show name, icon and ProcessStatus data for each application
+ Column {
+ id: appsColumn
+ anchors.left: parent.left
+ anchors.top: parent.top
+ anchors.margins: 2
+ spacing: 10
+ Repeater {
+ model: ApplicationManager
+ ApplicationDisplay {
+ name: model.name
+ application: model.application
+ }
+ }
+ }
+
+ // Show windows of running applications
+ Column {
+ id: windowsColumn
+ anchors.left: appsColumn.right
+ anchors.right: parent.right
+ anchors.margins: 10
+ Repeater {
+ model: WindowManager
+ WindowItem {
+ width: windowsColumn.width
+ height: 200
+ window: model.window
+ }
+ }
+ }
+}
diff --git a/src/main-lib/main.cpp b/src/main-lib/main.cpp
index 2323ecd0..1c81d28a 100644
--- a/src/main-lib/main.cpp
+++ b/src/main-lib/main.cpp
@@ -133,11 +133,18 @@
#include "crashhandler.h"
#include "qmllogger.h"
#include "startuptimer.h"
-#include "systemmonitor.h"
-#include "processmonitor.h"
#include "applicationipcmanager.h"
#include "unixsignalhandler.h"
+// monitor-lib
+#include "cpustatus.h"
+#include "frametimer.h"
+#include "gpustatus.h"
+#include "iostatus.h"
+#include "memorystatus.h"
+#include "monitormodel.h"
+#include "processstatus.h"
+
#include "../plugin-interfaces/startupinterface.h"
@@ -616,8 +623,15 @@ void Main::setupQmlEngine(const QStringList &importPaths, const QString &quickCo
#if !defined(AM_HEADLESS)
qmlRegisterType<QmlInProcessApplicationManagerWindow>("QtApplicationManager.Application", 1, 0, "ApplicationManagerWindow");
#endif
- qmlRegisterType<ProcessMonitor>("QtApplicationManager.SystemUI", 1, 0, "ProcessMonitor");
- qmlRegisterType<SystemMonitor>("QtApplicationManager.SystemUI", 1, 0, "SystemMonitor");
+
+ // monitor-lib
+ qmlRegisterType<CpuStatus>("QtApplicationManager", 1, 0, "CpuStatus");
+ qmlRegisterType<FrameTimer>("QtApplicationManager", 1, 0, "FrameTimer");
+ qmlRegisterType<GpuStatus>("QtApplicationManager", 1, 0, "GpuStatus");
+ qmlRegisterType<IoStatus>("QtApplicationManager", 1, 0, "IoStatus");
+ qmlRegisterType<MemoryStatus>("QtApplicationManager", 1, 0, "MemoryStatus");
+ qmlRegisterType<MonitorModel>("QtApplicationManager", 1, 0, "MonitorModel");
+ qmlRegisterType<ProcessStatus>("QtApplicationManager.SystemUI", 1, 0, "ProcessStatus");
StartupTimer::instance()->checkpoint("after QML registrations");
diff --git a/src/monitor-lib/cpustatus.cpp b/src/monitor-lib/cpustatus.cpp
new file mode 100644
index 00000000..5bf2729c
--- /dev/null
+++ b/src/monitor-lib/cpustatus.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "cpustatus.h"
+
+#include <QThread>
+
+/*!
+ \qmltype CpuStatus
+ \inqmlmodule QtApplicationManager
+ \ingroup common-instantiatable
+ \brief Provides information on the CPU status.
+
+ As the name implies, CpuStatus provides information on the status of the CPU. Its property values
+ are updated whenever the method update() is called.
+
+ You can use this component as a MonitorModel data source if you want to plot its
+ previous values over time.
+
+ \qml
+ import QtQuick 2.11
+ import QtApplicationManager 1.0
+ ...
+ MonitorModel {
+ CpuStatus {}
+ }
+ \endqml
+
+ You can also use it alongside a Timer for instance, when you're only interested in its current value.
+
+ \qml
+ import QtQuick 2.11
+ import QtApplicationManager 1.0
+ ...
+ CpuStatus { id: cpuStatus }
+ Timer {
+ interval: 500
+ running: true
+ repeat: true
+ onTriggered: cpuStatus.update()
+ }
+ Text {
+ property string loadPercent: Number(cpuStatus.cpuLoad * 100).toLocaleString(Qt.locale("en_US"), 'f', 1)
+ text: "cpuLoad: " + loadPercent + "%"
+ }
+ \endqml
+*/
+
+QT_USE_NAMESPACE_AM
+
+CpuStatus::CpuStatus(QObject *parent)
+ : QObject(parent)
+ , m_cpuReader(new CpuReader)
+ , m_cpuLoad(0)
+{
+}
+
+/*!
+ \qmlproperty real CpuStatus::cpuLoad
+ \readonly
+
+ The CPU utilization when update() was last called, as a value ranging from 0 (inclusive, completely
+ idle) to 1 (inclusive, fully busy).
+
+ \sa CpuStatus::update
+*/
+qreal CpuStatus::cpuLoad() const
+{
+ return m_cpuLoad;
+}
+
+/*!
+ \qmlproperty int CpuStatus::cpuCores
+ \readonly
+
+ The number of physical CPU cores that are installed on the system.
+*/
+int CpuStatus::cpuCores() const
+{
+ return QThread::idealThreadCount();
+}
+
+/*!
+ \qmlmethod CpuStatus::update
+
+ Updates the cpuLoad property.
+
+ \sa CpuStatus::cpuLoad
+*/
+void CpuStatus::update()
+{
+ qreal newLoad = m_cpuReader->readLoadValue();
+ if (newLoad != m_cpuLoad) {
+ m_cpuLoad = newLoad;
+ emit cpuLoadChanged();
+ }
+}
+
+/*!
+ \qmlproperty list<string> CpuStatus::roleNames
+ \readonly
+
+ Names of the roles provided by CpuStatus when used as a MonitorModel data source.
+
+ \sa MonitorModel
+*/
+QStringList CpuStatus::roleNames() const
+{
+ return { qSL("cpuLoad") };
+}
diff --git a/src/monitor-lib/cpustatus.h b/src/monitor-lib/cpustatus.h
new file mode 100644
index 00000000..e87a016d
--- /dev/null
+++ b/src/monitor-lib/cpustatus.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtAppManCommon/global.h>
+
+#include <QtAppManManager/systemreader.h>
+
+#include <QObject>
+#include <QScopedPointer>
+
+QT_BEGIN_NAMESPACE_AM
+
+class CpuStatus : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal cpuLoad READ cpuLoad NOTIFY cpuLoadChanged)
+ Q_PROPERTY(int cpuCores READ cpuCores CONSTANT)
+
+ Q_PROPERTY(QStringList roleNames READ roleNames CONSTANT)
+
+public:
+ CpuStatus(QObject *parent = nullptr);
+
+ qreal cpuLoad() const;
+ int cpuCores() const;
+
+ QStringList roleNames() const;
+
+ Q_INVOKABLE void update();
+
+signals:
+ void cpuLoadChanged();
+
+private:
+ QScopedPointer<CpuReader> m_cpuReader;
+ qreal m_cpuLoad;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/monitor-lib/frametimer.cpp b/src/monitor-lib/frametimer.cpp
index ef483736..534c3033 100644
--- a/src/monitor-lib/frametimer.cpp
+++ b/src/monitor-lib/frametimer.cpp
@@ -41,12 +41,75 @@
#include "frametimer.h"
+#include <QQuickWindow>
+#include <qqmlinfo.h>
+
+#include "waylandwindow.h"
+#include "inprocesswindow.h"
+
+/*!
+ \qmltype FrameTimer
+ \inqmlmodule QtApplicationManager
+ \ingroup common-instantiatable
+ \brief Provides frame-rate information about a given window.
+
+ FrameTimer is used to get frame-rate information for a given window. The window can be either
+ a toplevel Window (from the QtQuick.Window module) or a WindowObject
+ (from the QtApplicationManager.SystemUI module).
+
+ The following snippet shows how to use FrameTimer to display the frame-rate of a Window:
+
+ \qml
+ import QtQuick 2.11
+ import QtApplicationManager 1.0
+
+ Window {
+ id: toplevelWindow
+ ...
+ FrameTimer {
+ id: frameTimer
+ running: topLevelWindow.visible
+ window: toplevelWindow
+ }
+ Text {
+ text: "FPS: " + Number(frameTimer.averageFps).toLocaleString(Qt.locale("en_US"), 'f', 1)
+ }
+ }
+ \endqml
+
+ You can also use this component as a MonitorModel data source if you want to plot its
+ previous values over time:
+
+ \qml
+ import QtQuick 2.11
+ import QtApplicationManager 1.0
+
+ Window {
+ id: toplevelWindow
+ ...
+ MonitorModel {
+ running: true
+ FrameTimer {
+ window: toplevelWindow
+ }
+ }
+ }
+ \endqml
+
+ Please note that when using FrameTimer as a MonitorModel data source there's no need to set it
+ to \l{FrameTimer::running}{running} as MonitorModel will already call update() as needed.
+*/
+
QT_BEGIN_NAMESPACE_AM
const qreal FrameTimer::MicrosInSec = qreal(1000 * 1000);
-FrameTimer::FrameTimer()
-{ }
+FrameTimer::FrameTimer(QObject *parent)
+ : QObject(parent)
+{
+ m_updateTimer.setInterval(1000);
+ connect(&m_updateTimer, &QTimer::timeout, this, &FrameTimer::update);
+}
void FrameTimer::newFrame()
{
@@ -67,24 +130,239 @@ void FrameTimer::reset()
m_min = std::numeric_limits<int>::max();
}
+/*!
+ \qmlproperty real FrameTimer::averageFps
+ \readonly
+
+ The average frame rate of the given \l window, in frames per second, since update()
+ was last called (either manually or automatically in case \l{FrameTimer::running}{running} is set to true).
+
+ \sa window running update()
+*/
qreal FrameTimer::averageFps() const
{
- return m_sum ? MicrosInSec * m_count / m_sum : qreal(0);
+ return m_averageFps;
}
+/*!
+ \qmlproperty real FrameTimer::minimumFps
+ \readonly
+
+ The minimum frame rate of the given \l window, in frames per second, since update()
+ was last called (either manually or automatically in case \l{FrameTimer::running}{running} is set to true).
+
+ \sa window running update()
+*/
qreal FrameTimer::minimumFps() const
{
- return m_max ? MicrosInSec / m_max : qreal(0);
+ return m_minimumFps;
}
+/*!
+ \qmlproperty real FrameTimer::maximumFps
+ \readonly
+
+ The maximum frame rate of the given \l window, in frames per second, since update()
+ was last called (either manually or automatically in case \l{FrameTimer::running}{running} is set to true).
+
+ \sa window running update()
+*/
qreal FrameTimer::maximumFps() const
{
- return m_min ? MicrosInSec / m_min : qreal(0);
+ return m_maximumFps;
}
+/*!
+ \qmlproperty real FrameTimer::jitterFps
+ \readonly
+
+ The frame rate jitter of the given \l window, in frames per second, since update()
+ was last called (either manually or automatically in case \l{FrameTimer::running}{running} is set to true).
+
+ \sa window running update()
+*/
qreal FrameTimer::jitterFps() const
{
- return m_count ? m_jitter / m_count : qreal(0);
+ return m_jitterFps;
+}
+
+/*!
+ \qmlproperty Object FrameTimer::window
+
+ The window to be monitored, from which frame-rate information will be gathered.
+ It can be either a toplevel Window (from the QtQuick.Window module) or a WindowObject
+ (from the QtApplicationManager.SystemUI module).
+
+ \sa WindowObject
+*/
+QObject *FrameTimer::window() const
+{
+ return m_window;
+}
+
+void FrameTimer::setWindow(QObject *value)
+{
+ if (m_window == value)
+ return;
+
+#if defined(AM_MULTI_PROCESS)
+ disconnectFromWaylandSurface();
+#endif
+
+ if (m_window)
+ disconnect(m_window, nullptr, this, nullptr);
+
+ m_window = value;
+
+ if (m_window) {
+ if (!connectToQuickWindow() && !connectToAppManWindow())
+ qmlWarning(this) << "The given window is neither a QQuickWindow nor a WindowObject.";
+ }
+
+ emit windowChanged();
+}
+
+bool FrameTimer::connectToQuickWindow()
+{
+ QQuickWindow *quickWindow = qobject_cast<QQuickWindow*>(m_window);
+ if (!quickWindow)
+ return false;
+
+ connect(quickWindow, &QQuickWindow::frameSwapped, this, &FrameTimer::newFrame, Qt::UniqueConnection);
+ return true;
+}
+
+bool FrameTimer::connectToAppManWindow()
+{
+ Window *appManWindow = qobject_cast<Window*>(m_window);
+ if (!appManWindow)
+ return false;
+
+ if (qobject_cast<InProcessWindow*>(appManWindow)) {
+ qmlWarning(this) << "It makes no sense to measure the FPS of a WindowObject in single-process mode."
+ " FrameTimer won't operate with the given window.";
+ return true;
+ }
+
+#if defined(AM_MULTI_PROCESS)
+ WaylandWindow *waylandWindow = qobject_cast<WaylandWindow*>(m_window);
+ Q_ASSERT(waylandWindow);
+
+ connect(waylandWindow, &WaylandWindow::waylandSurfaceChanged,
+ this, &FrameTimer::connectToWaylandSurface, Qt::UniqueConnection);
+
+ connectToWaylandSurface();
+#endif
+
+ return true;
+}
+
+#if defined(AM_MULTI_PROCESS)
+void FrameTimer::connectToWaylandSurface()
+{
+ WaylandWindow *waylandWindow = qobject_cast<WaylandWindow*>(m_window);
+ Q_ASSERT(waylandWindow);
+
+ disconnectFromWaylandSurface();
+
+ m_waylandSurface = waylandWindow->waylandSurface();
+ if (m_waylandSurface)
+ connect(m_waylandSurface, &QWaylandQuickSurface::redraw, this, &FrameTimer::newFrame, Qt::UniqueConnection);
+}
+
+void FrameTimer::disconnectFromWaylandSurface()
+{
+ if (!m_waylandSurface)
+ return;
+
+ disconnect(m_waylandSurface, nullptr, this, nullptr);
+
+ m_waylandSurface = nullptr;
+}
+#endif
+
+/*!
+ \qmlproperty list<string> FrameTimer::roleNames
+ \readonly
+
+ Names of the roles provided by FrameTimer when used as a MonitorModel data source.
+
+ \sa MonitorModel
+*/
+QStringList FrameTimer::roleNames() const
+{
+ return { qSL("averageFps"), qSL("minimumFps"), qSL("maximumFps"), qSL("jitterFps") };
+}
+
+/*!
+ \qmlmethod FrameTimer::update
+
+ Updates the properties averageFps, minimumFps, maximumFps and jitterFps. Then resets internal
+ counters so that new numbers can be taken for the new time period starting from the moment
+ this method is called.
+
+ Note that you normally don't have to call this method directly, as FrameTimer does it automatically
+ every \l interval milliseconds while \l{FrameTimer::running}{running} is set to true.
+
+ \sa running
+*/
+void FrameTimer::update()
+{
+ m_averageFps = m_sum ? MicrosInSec * m_count / m_sum : qreal(0);
+ m_minimumFps = m_max ? MicrosInSec / m_max : qreal(0);
+ m_maximumFps = m_min ? MicrosInSec / m_min : qreal(0);
+ m_jitterFps = m_count ? m_jitter / m_count : qreal(0);
+
+ // Start counting again for the next sampling period but keep m_timer running because
+ // we still need the diff between the last rendered frame and the upcoming one.
+ reset();
+
+ emit updated();
+}
+
+/*!
+ \qmlproperty bool FrameTimer::running
+
+ If \c true, update() will get called automatically every \l interval milliseconds.
+
+ When using FrameTimer as a MonitorModel data source, this property should be kept as \c false.
+
+ \sa update() interval
+*/
+bool FrameTimer::running() const
+{
+ return m_updateTimer.isActive();
+}
+
+void FrameTimer::setRunning(bool value)
+{
+ if (value && !m_updateTimer.isActive()) {
+ m_updateTimer.start();
+ emit runningChanged();
+ } else if (!value && m_updateTimer.isActive()) {
+ m_updateTimer.stop();
+ emit runningChanged();
+ }
+}
+
+/*!
+ \qmlproperty int FrameTimer::interval
+
+ The interval, in milliseconds, between update() calls while \l{FrameTimer::running}{running} is \c true.
+
+ \sa update() running
+*/
+int FrameTimer::interval() const
+{
+ return m_updateTimer.interval();
+}
+
+void FrameTimer::setInterval(int value)
+{
+ if (value != m_updateTimer.interval()) {
+ m_updateTimer.setInterval(value);
+ emit intervalChanged();
+ }
}
QT_END_NAMESPACE_AM
diff --git a/src/monitor-lib/frametimer.h b/src/monitor-lib/frametimer.h
index 17339e53..0a36a1b8 100644
--- a/src/monitor-lib/frametimer.h
+++ b/src/monitor-lib/frametimer.h
@@ -42,35 +42,92 @@
#pragma once
#include <QElapsedTimer>
+#include <QObject>
+#include <QPointer>
+#include <QTimer>
#include <QtAppManCommon/global.h>
#include <limits>
+#if defined(AM_MULTI_PROCESS)
+# include <QtWaylandCompositor/QWaylandQuickSurface>
+#endif
+
QT_BEGIN_NAMESPACE_AM
-class FrameTimer
+class FrameTimer : public QObject
{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal averageFps READ averageFps NOTIFY updated)
+ Q_PROPERTY(qreal minimumFps READ minimumFps NOTIFY updated)
+ Q_PROPERTY(qreal maximumFps READ maximumFps NOTIFY updated)
+ Q_PROPERTY(qreal jitterFps READ jitterFps NOTIFY updated)
+
+ Q_PROPERTY(QObject* window READ window WRITE setWindow NOTIFY windowChanged)
+
+ Q_PROPERTY(int interval READ interval WRITE setInterval NOTIFY intervalChanged)
+ Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged)
+
+ Q_PROPERTY(QStringList roleNames READ roleNames CONSTANT)
public:
- FrameTimer();
+ FrameTimer(QObject *parent = nullptr);
- void newFrame();
+ QStringList roleNames() const;
- void reset();
+ Q_INVOKABLE void update();
qreal averageFps() const;
qreal minimumFps() const;
qreal maximumFps() const;
qreal jitterFps() const;
+ QObject *window() const;
+ void setWindow(QObject *value);
+
+ bool running() const;
+ void setRunning(bool value);
+
+ int interval() const;
+ void setInterval(int value);
+
+signals:
+ void updated();
+ void intervalChanged();
+ void runningChanged();
+ void windowChanged();
+
+private slots:
+ void newFrame();
+
private:
+ void reset();
+ bool connectToQuickWindow();
+ bool connectToAppManWindow();
+
+#if defined(AM_MULTI_PROCESS)
+ void disconnectFromWaylandSurface();
+ void connectToWaylandSurface();
+ QPointer<QWaylandQuickSurface> m_waylandSurface;
+#endif
+
int m_count = 0;
int m_sum = 0;
int m_min = std::numeric_limits<int>::max();
int m_max = 0;
qreal m_jitter = 0.0;
+ QPointer<QObject> m_window;
+
QElapsedTimer m_timer;
+ QTimer m_updateTimer;
+
+ qreal m_averageFps;
+ qreal m_minimumFps;
+ qreal m_maximumFps;
+ qreal m_jitterFps;
+
static const int IdealFrameTime = 16667; // usec - could be made configurable via an env variable
static const qreal MicrosInSec;
};
diff --git a/src/monitor-lib/gpustatus.cpp b/src/monitor-lib/gpustatus.cpp
new file mode 100644
index 00000000..7e375917
--- /dev/null
+++ b/src/monitor-lib/gpustatus.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "gpustatus.h"
+
+/*!
+ \qmltype GpuStatus
+ \inqmlmodule QtApplicationManager
+ \ingroup common-instantiatable
+ \brief Provides information on the GPU status.
+
+ GpuStatus provides information on the status of the GPU. Its property values
+ are updated whenever the method update() is called.
+
+ You can use it alongside a Timer for instance to periodically query the status of the GPU:
+
+ \qml
+ import QtQuick 2.11
+ import QtApplicationManager 1.0
+ ...
+ GpuStatus { id: gpuStatus }
+ Timer {
+ interval: 500
+ running: true
+ repeat: true
+ onTriggered: gpuStatus.update()
+ }
+ Text {
+ property string loadPercent: Number(gpuStatus.gpuLoad * 100).toLocaleString(Qt.locale("en_US"), 'f', 1)
+ text: "GPU load: " + loadPercent + "%"
+ }
+ \endqml
+
+ You can also use this component as a MonitorModel data source if you want to plot its
+ previous values over time:
+
+ \qml
+ import QtQuick 2.11
+ import QtApplicationManager 1.0
+ ...
+ MonitorModel {
+ GpuStatus {}
+ }
+ \endqml
+
+*/
+
+QT_USE_NAMESPACE_AM
+
+GpuStatus::GpuStatus(QObject *parent)
+ : QObject(parent)
+ , m_gpuReader(new GpuReader)
+ , m_gpuLoad(0)
+{
+}
+
+/*!
+ \qmlproperty real GpuStatus::gpuLoad
+ \readonly
+
+ GPU utilization when update() was last called, as a value ranging from 0 (inclusive,
+ completely idle) to 1 (inclusive, fully busy).
+
+ \note This is dependent on tools from the graphics hardware vendor and might not work on
+ every system.
+
+ Currently, this only works on \e Linux with either \e Intel or \e NVIDIA chipsets, plus the
+ tools from the respective vendors have to be installed:
+
+ \table
+ \header
+ \li Hardware
+ \li Tool
+ \li Notes
+ \row
+ \li NVIDIA
+ \li \c nvidia-smi
+ \li The utilization will only be shown for the first GPU of the system, in case multiple GPUs
+ are installed.
+ \row
+ \li Intel
+ \li \c intel_gpu_top
+ \li The binary has to be made set-UID root, e.g. via \c{sudo chmod +s $(which intel_gpu_top)},
+ or the application-manager has to be run as the \c root user.
+ \endtable
+
+ \sa \l{GpuStatus::update}{update()}
+*/
+qreal GpuStatus::gpuLoad() const
+{
+ return m_gpuLoad;
+}
+
+/*!
+ \qmlmethod GpuStatus::update
+
+ Updates the gpuLoad property.
+
+ \sa gpuLoad
+*/
+void GpuStatus::update()
+{
+ qreal newLoad = m_gpuReader->readLoadValue();
+ if (newLoad != m_gpuLoad) {
+ m_gpuLoad = newLoad;
+ emit gpuLoadChanged();
+ }
+}
+
+/*!
+ \qmlproperty list<string> GpuStatus::roleNames
+ \readonly
+
+ Names of the roles provided by GpuStatus when used as a MonitorModel data source.
+
+ \sa MonitorModel
+*/
+QStringList GpuStatus::roleNames() const
+{
+ return { qSL("gpuLoad") };
+}
+
diff --git a/src/monitor-lib/gpustatus.h b/src/monitor-lib/gpustatus.h
new file mode 100644
index 00000000..e843bb72
--- /dev/null
+++ b/src/monitor-lib/gpustatus.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtAppManCommon/global.h>
+
+#include <QtAppManManager/systemreader.h>
+
+#include <QObject>
+#include <QScopedPointer>
+
+QT_BEGIN_NAMESPACE_AM
+
+class GpuStatus : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal gpuLoad READ gpuLoad NOTIFY gpuLoadChanged)
+
+ Q_PROPERTY(QStringList roleNames READ roleNames CONSTANT)
+
+public:
+ GpuStatus(QObject *parent = nullptr);
+
+ qreal gpuLoad() const;
+
+ QStringList roleNames() const;
+
+ Q_INVOKABLE void update();
+
+signals:
+ void gpuLoadChanged();
+
+private:
+ QScopedPointer<GpuReader> m_gpuReader;
+ qreal m_gpuLoad;
+};
+
+QT_END_NAMESPACE_AM
+
diff --git a/src/monitor-lib/iostatus.cpp b/src/monitor-lib/iostatus.cpp
new file mode 100644
index 00000000..1fada231
--- /dev/null
+++ b/src/monitor-lib/iostatus.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "iostatus.h"
+
+#include <QFile>
+
+/*!
+ \qmltype IoStatus
+ \inqmlmodule QtApplicationManager
+ \ingroup common-instantiatable
+ \brief Provides information on the status of I/O devices.
+
+ IoStatus provides information on the status of I/O devices.
+ Its property values are updated whenever the method update() is called.
+
+ You can use this component as a MonitorModel data source if you want to plot its
+ previous values over time.
+
+ \qml
+ import QtQuick 2.11
+ import QtApplicationManager 1.0
+ ...
+ MonitorModel {
+ IoStatus {
+ deviceNames: ["sda", "sdb"]
+ }
+ }
+ \endqml
+
+ You can also use it alongside a Timer for instance, when you're only interested in its current value.
+
+ \qml
+ import QtQuick 2.11
+ import QtApplicationManager 1.0
+ ...
+ IoStatus {
+ id: ioStatus
+ deviceNames: ["sda", "sdb"]
+ }
+ Timer {
+ interval: 500
+ running: true
+ repeat: true
+ onTriggered: ioStatus.update()
+ }
+ Text {
+ property string loadPercent: Number(ioStatus.ioLoad.sda * 100).toLocaleString(Qt.locale("en_US"), 'f', 1)
+ text: "sda load: " + loadPercent + "%"
+ }
+ \endqml
+*/
+
+QT_USE_NAMESPACE_AM
+
+IoStatus::IoStatus(QObject *parent)
+ : QObject(parent)
+{
+}
+
+IoStatus::~IoStatus()
+{
+ qDeleteAll(m_ioHash);
+}
+
+/*!
+ \qmlproperty list<string> IoStatus::deviceNames
+
+ Names of the I/O devices to be probed.
+
+ \note Currently this is only supported on Linux: device names have to match to filenames in
+ the \c /sys/block directory.
+*/
+QStringList IoStatus::deviceNames() const
+{
+ return m_deviceNames;
+}
+
+void IoStatus::setDeviceNames(const QStringList &value)
+{
+ qDeleteAll(m_ioHash);
+ m_ioHash.clear();
+
+ m_deviceNames = value;
+
+ for (auto it = m_deviceNames.cbegin(); it != m_deviceNames.cend(); ++it)
+ addIoReader(*it);
+
+ emit deviceNamesChanged();
+}
+
+/*!
+ \qmlproperty var IoStatus::ioLoad
+ \readonly
+
+ A map of devices registered in deviceNames and their corresponding I/O loads in the
+ range [0, 1]. For instance the load of a device named "sda" can be accessed through
+ \c ioLoad.sda.
+
+ Devices whose status could not be fetched won't be present in this property.
+
+ The value of this property is updated when update() is called.
+
+ \sa update
+*/
+QVariantMap IoStatus::ioLoad() const
+{
+ return m_ioLoad;
+}
+
+/*!
+ \qmlproperty list<string> IoStatus::roleNames
+ \readonly
+
+ Names of the roles provided by IoStatus when used as a MonitorModel data source.
+
+ \sa MonitorModel
+*/
+QStringList IoStatus::roleNames() const
+{
+ return { qSL("ioLoad") };
+}
+
+/*!
+ \qmlmethod IoStatus::update
+
+ Updates the ioLoad property.
+
+ \sa ioLoad
+*/
+void IoStatus::update()
+{
+ m_ioLoad.clear();
+ for (auto it = m_ioHash.cbegin(); it != m_ioHash.cend(); ++it) {
+ qreal ioVal = it.value()->readLoadValue();
+ m_ioLoad.insert(it.key(), ioVal);
+ }
+ emit ioLoadChanged();
+}
+
+void IoStatus::addIoReader(const QString &deviceName)
+{
+ if (!QFile::exists(qSL("/dev/") + deviceName))
+ return;
+ if (m_ioHash.contains(deviceName))
+ return;
+
+ IoReader *ior = new IoReader(deviceName.toLocal8Bit().constData());
+ m_ioHash.insert(deviceName, ior);
+}
diff --git a/src/monitor-lib/systemmonitor_p.h b/src/monitor-lib/iostatus.h
index 871216a6..26e0fe7e 100644
--- a/src/monitor-lib/systemmonitor_p.h
+++ b/src/monitor-lib/iostatus.h
@@ -41,94 +41,49 @@
#pragma once
-#include <QObject>
-#include <QHash>
+#include <QtAppManCommon/global.h>
-#include "frametimer.h"
-#include "global.h"
-#include "systemreader.h"
+#include <QHash>
+#include <QObject>
+#include <QStringList>
+#include <QVariant>
-QT_FORWARD_DECLARE_CLASS(QQuickWindow)
+#include <QtAppManManager/systemreader.h>
QT_BEGIN_NAMESPACE_AM
-class SystemMonitor;
-
-class SystemMonitorPrivate : public QObject // clazy:exclude=missing-qobject-macro
+class IoStatus : public QObject
{
+ Q_OBJECT
+ Q_PROPERTY(QStringList deviceNames READ deviceNames WRITE setDeviceNames NOTIFY deviceNamesChanged)
+ Q_PROPERTY(QVariantMap ioLoad READ ioLoad NOTIFY ioLoadChanged)
+
+ Q_PROPERTY(QStringList roleNames READ roleNames CONSTANT)
+
public:
- SystemMonitorPrivate(SystemMonitor *q)
- : q_ptr(q)
- { }
-
- static const SystemMonitorPrivate* get(const SystemMonitor *sysMon) { return sysMon->d_func(); }
-
- SystemMonitor *q_ptr;
- Q_DECLARE_PUBLIC(SystemMonitor)
-
- // idle
- qreal idleThreshold = 0.1;
- CpuReader *idleCpu = nullptr;
- int idleTimerId = 0;
- bool isIdle = false;
-
- // memory thresholds
- qreal memoryLowWarning = -1;
- qreal memoryCriticalWarning = -1;
- MemoryWatcher *memoryWatcher = nullptr;
-
- // fps
- QHash<QObject *, FrameTimer *> frameTimer;
-
- // reporting
- MemoryReader *memory = nullptr;
- CpuReader *cpu = nullptr;
- GpuReader *gpu = nullptr;
- QHash<QString, IoReader *> ioHash;
- int reportingInterval = 1000;
- int count = 10;
- int reportingTimerId = 0;
- bool reportCpu = false;
- bool reportGpu = false;
- bool reportMem = false;
- bool reportFps = false;
- bool windowManagerConnectionCreated = false;
-
- struct Report
- {
- qreal cpuLoad = 0;
- qreal gpuLoad = 0;
- qreal fpsAvg = 0;
- qreal fpsMin = 0;
- qreal fpsMax = 0;
- qreal fpsJitter = 0;
- quint64 memoryUsed = 0;
- QVariantMap ioLoad;
- };
- QVector<Report> reports;
- int reportPos = 0;
-
- // model
- QHash<int, QByteArray> roleNames;
-
- void makeNewReport();
-
- int latestReportPos() const;
-
-#if !defined(AM_HEADLESS)
- void registerNewView(QQuickWindow *view);
-#endif
-
- void setupFpsReporting();
- void setupTimer();
-
- void timerEvent(QTimerEvent *te) override;
-
- const Report &reportForRow(int row) const;
-
- void updateModel(bool clear);
-
- void setReportingInterval(int intervalInMSec);
+ IoStatus(QObject *parent = nullptr);
+ virtual ~IoStatus();
+
+ QStringList deviceNames() const;
+ void setDeviceNames(const QStringList &value);
+
+ QVariantMap ioLoad() const;
+
+ QStringList roleNames() const;
+
+ Q_INVOKABLE void update();
+
+signals:
+ void deviceNamesChanged();
+ void ioLoadChanged();
+
+private:
+ void addIoReader(const QString &deviceName);
+
+ QStringList m_deviceNames;
+ QHash<QString, IoReader *> m_ioHash;
+ QVariantMap m_ioLoad;
};
QT_END_NAMESPACE_AM
+
diff --git a/src/monitor-lib/memorystatus.cpp b/src/monitor-lib/memorystatus.cpp
new file mode 100644
index 00000000..3947bb0d
--- /dev/null
+++ b/src/monitor-lib/memorystatus.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "memorystatus.h"
+
+/*!
+ \qmltype MemoryStatus
+ \inqmlmodule QtApplicationManager
+ \ingroup common-instantiatable
+ \brief Provides information on the status of the RAM.
+
+ MemoryStatus provides information on the status of the system's RAM (random-access memory).
+ Its property values are updated whenever the method update() is called.
+
+ You can use this component as a MonitorModel data source if you want to plot its
+ previous values over time.
+
+ \qml
+ import QtQuick 2.11
+ import QtApplicationManager 1.0
+ ...
+ MonitorModel {
+ MemoryStatus {}
+ }
+ \endqml
+
+ You can also use it alongside a Timer for instance, when you're only interested in its current value.
+
+ \qml
+ import QtQuick 2.11
+ import QtApplicationManager 1.0
+ ...
+ MemoryStatus { id: memoryStatus }
+ Timer {
+ interval: 500
+ running: true
+ repeat: true
+ onTriggered: memoryStatus.update()
+ }
+ Text {
+ text: "memory used: " + (memoryStatus.memoryUsed / 1e6).toFixed(0) + " MB"
+ }
+ \endqml
+*/
+
+QT_USE_NAMESPACE_AM
+
+MemoryStatus::MemoryStatus(QObject *parent)
+ : QObject(parent)
+ , m_memoryReader(new MemoryReader)
+ , m_memoryUsed(0)
+{
+}
+
+/*!
+ \qmlproperty int MemoryStatus::totalMemory
+ \readonly
+
+ The total amount of physical memory (RAM) installed on the system in bytes.
+
+ \sa MemoryStatus::memoryUsed
+*/
+quint64 MemoryStatus::totalMemory() const
+{
+#if defined(Q_OS_LINUX)
+ auto limit = m_memoryReader->groupLimit();
+ if (limit > 0 && limit < m_memoryReader->totalValue())
+ return limit;
+ else
+ return m_memoryReader->totalValue();
+#else
+ return m_memoryReader->totalValue();
+#endif
+}
+
+/*!
+ \qmlproperty int MemoryStatus::memoryUsed
+ \readonly
+
+ The amount of physical memory (RAM) used in bytes.
+
+ The value of this property is updated when MemoryStatus::update is called.
+
+ \sa totalMemory
+*/
+quint64 MemoryStatus::memoryUsed() const
+{
+ return m_memoryUsed;
+}
+
+/*!
+ \qmlproperty list<string> MemoryStatus::roleNames
+ \readonly
+
+ Names of the roles provided by MemoryStatus when used as a MonitorModel data source.
+
+ \sa MonitorModel
+*/
+QStringList MemoryStatus::roleNames() const
+{
+ return { qSL("memoryUsed") };
+}
+
+/*!
+ \qmlmethod MemoryStatus::update
+
+ Updates the memoryUsed property.
+
+ \sa memoryUsed
+*/
+void MemoryStatus::update()
+{
+ quint64 newReading = m_memoryReader->readUsedValue();
+ if (m_memoryUsed != newReading) {
+ m_memoryUsed = newReading;
+ emit memoryUsedChanged();
+ }
+}
diff --git a/src/monitor-lib/memorystatus.h b/src/monitor-lib/memorystatus.h
new file mode 100644
index 00000000..95e40807
--- /dev/null
+++ b/src/monitor-lib/memorystatus.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtAppManCommon/global.h>
+
+#include <QtAppManManager/systemreader.h>
+
+#include <QObject>
+#include <QScopedPointer>
+
+QT_BEGIN_NAMESPACE_AM
+
+class MemoryStatus : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(quint64 totalMemory READ totalMemory CONSTANT)
+ Q_PROPERTY(quint64 memoryUsed READ memoryUsed NOTIFY memoryUsedChanged)
+
+ Q_PROPERTY(QStringList roleNames READ roleNames CONSTANT)
+
+public:
+ MemoryStatus(QObject *parent = nullptr);
+
+ quint64 totalMemory() const;
+ quint64 memoryUsed() const;
+
+ QStringList roleNames() const;
+
+ Q_INVOKABLE void update();
+
+signals:
+ void memoryUsedChanged();
+
+private:
+ QScopedPointer<MemoryReader> m_memoryReader;
+ quint64 m_memoryUsed;
+};
+
+QT_END_NAMESPACE_AM
+
diff --git a/src/monitor-lib/monitor-lib.pro b/src/monitor-lib/monitor-lib.pro
index 6bc837e5..792c85de 100644
--- a/src/monitor-lib/monitor-lib.pro
+++ b/src/monitor-lib/monitor-lib.pro
@@ -15,16 +15,23 @@ QT_FOR_PRIVATE *= \
CONFIG *= static internal_module
HEADERS += \
- systemmonitor.h \
- systemmonitor_p.h \
- processmonitor.h \
- processmonitor_p.h \
- frametimer.h
+ cpustatus.h \
+ frametimer.h \
+ gpustatus.h \
+ iostatus.h \
+ memorystatus.h \
+ monitormodel.h \
+ processreader.h \
+ processstatus.h \
SOURCES += \
- systemmonitor.cpp \
- processmonitor.cpp \
- processmonitor_p.cpp \
- frametimer.cpp
+ cpustatus.cpp \
+ frametimer.cpp \
+ gpustatus.cpp \
+ iostatus.cpp \
+ memorystatus.cpp \
+ monitormodel.cpp \
+ processreader.cpp \
+ processstatus.cpp \
load(qt_module)
diff --git a/src/monitor-lib/monitormodel.cpp b/src/monitor-lib/monitormodel.cpp
new file mode 100644
index 00000000..55fcd8b3
--- /dev/null
+++ b/src/monitor-lib/monitormodel.cpp
@@ -0,0 +1,473 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "monitormodel.h"
+
+#include <QMetaProperty>
+#include <qqmlinfo.h>
+
+#include <QDebug>
+#include <QQmlProperty>
+#include <QJSValue>
+#include <QQmlEngine>
+
+/*!
+ \qmltype MonitorModel
+ \inqmlmodule QtApplicationManager
+ \ingroup common-instantiatable
+ \brief A model that can fetch data from various sources and keep a history of their values.
+
+ MonitorModel can fetch data from various sources at regular intervals and keep a history of
+ their values. Its main use is having it as a model to plot historical data in a graph for
+ monitoring purposes, such as a CPU usage graph.
+
+ The snippet below shows how to use it for plotting a system's CPU load in a simple bar graph:
+
+ \qml
+ import QtQuick 2.11
+ import QtApplicationManager 1.0
+
+ ListView {
+ id: listView
+ width: 400
+ height: 100
+ orientation: ListView.Horizontal
+ spacing: (width / model.count) * 0.2
+ clip: true
+ interactive: false
+
+ model: MonitorModel {
+ id: monitorModel
+ running: listView.visible
+ CpuStatus {}
+ }
+
+ delegate: Rectangle {
+ width: (listView.width / monitorModel.count) * 0.8
+ height: model.cpuLoad * listView.height
+ y: listView.height - height
+ color: "blue"
+ }
+ }
+ \endqml
+
+ To add a data source to MonitorModel just declare it inside the model, as done in the example above with
+ the CpuStatus component. Alternatively (such as from imperative javscript code) you can add data sources
+ by assigning them to MonitorModel's dataSources property.
+
+ A data source can be any QtObject with the following characteristics:
+ \list
+ \li A \c roleNames property: it's a list of strings naming the roles that this data source provides. Those role
+ names will be available on each row created by MonitorModel.
+ \li Properties matching the names provided in the \c roleNames property: MonitorModel will query their values
+ when building each new model row.
+ \li An \c update() function: MonitorModel will call it before creating each new model row, so that the data source
+ can update the values of its properties.
+ \endlist
+
+ The following snippet shows MonitorModel using a custom data source written in QML:
+
+ \qml
+ MonitorModel {
+ running: true
+ QtObject {
+ property var roleNames: ["foo", "bar"]
+
+ function update() {
+ // foo will have ever increasing values
+ foo += 1;
+
+ // bar will keep oscillating between 0 and 10
+ if (up) {
+ bar += 1;
+ if (bar == 10)
+ up = false;
+ } else {
+ bar -= 1;
+ if (bar == 0)
+ up = true;
+ }
+ }
+
+ property int foo: 0
+ property int bar: 10
+ property bool up: false
+ }
+ }
+ \endqml
+
+ Thus, in the MonitorModel above, every row will have two roles: \c foo and \c bar. If plotted, you would see
+ an ever incresing foo and an oscillating bar.
+
+ QtApplicationManager comes with a number of components that are readily usable as data sources, namely:
+ \list
+ \li CpuStatus
+ \li FrameTimer
+ \li GpuStatus
+ \li IoStatus
+ \li MemoryStatus
+ \li ProcessStatus
+ \endlist
+
+ While \l{MonitorModel::running}{running} is true, MonitorModel will probe its data sources every
+ \l{MonitorModel::interval}{interval} milliseconds, creating a new row every time up to
+ \l{MonitorModel::maximumCount}{maximumCount}. Once that value is reached the oldest row (the first one)
+ is discarded whenever a new row comes in, so that \l{MonitorModel::count}{count} doesn't exceed
+ \l{MonitorModel::maximumCount}{maximumCount}. New rows are always appended to the model, so rows are
+ ordered chronologically from oldest (index 0) to newest (index count-1).
+*/
+
+QT_USE_NAMESPACE_AM
+
+MonitorModel::MonitorModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+ m_timer.setInterval(1000);
+ connect(&m_timer, &QTimer::timeout, this, &MonitorModel::readDataSourcesAndAddRow);
+}
+
+MonitorModel::~MonitorModel()
+{
+ qDeleteAll(m_rows);
+}
+
+/*!
+ \qmlproperty list<Object> MonitorModel::dataSources
+
+ List of data sources to be used by the MonitorModel. A data source can be any QtObject
+ containing at least a \c roleNames property and a \c update() function. See MonitorModel's description
+ for more information.
+*/
+QQmlListProperty<QObject> MonitorModel::dataSources()
+{
+ return QQmlListProperty<QObject>(this, nullptr, &MonitorModel::dataSources_append,
+ &MonitorModel::dataSources_count,
+ &MonitorModel::dataSources_at,
+ &MonitorModel::dataSources_clear);
+}
+
+void MonitorModel::dataSources_append(QQmlListProperty<QObject> *property, QObject *dataSource)
+{
+ auto *that = static_cast<MonitorModel*>(property->object);
+ that->appendDataSource(dataSource);
+}
+
+int MonitorModel::dataSources_count(QQmlListProperty<QObject> *property)
+{
+ auto *that = static_cast<MonitorModel*>(property->object);
+ return that->m_dataSources.count();
+}
+
+QObject *MonitorModel::dataSources_at(QQmlListProperty<QObject> *property, int index)
+{
+ auto *that = static_cast<MonitorModel*>(property->object);
+ return that && that->m_dataSources.count() > index && index >= 0 ? that->m_dataSources.at(index)->obj : nullptr;
+}
+
+void MonitorModel::dataSources_clear(QQmlListProperty<QObject> *property)
+{
+ auto *that = static_cast<MonitorModel*>(property->object);
+ that->clearDataSources();
+}
+
+void MonitorModel::clearDataSources()
+{
+ qDeleteAll(m_dataSources);
+ m_dataSources.clear();
+ m_roleNamesList.clear();
+ m_roleNameToIndex.clear();
+
+ clear();
+}
+
+void MonitorModel::appendDataSource(QObject *dataSourceObj)
+{
+ DataSource *dataSource = new DataSource;
+ dataSource->obj = dataSourceObj;
+ m_dataSources.append(dataSource);
+
+ if (!extractRoleNamesFromJsArray(dataSource)
+ && !extractRoleNamesFromStringList(dataSource))
+ qmlWarning(this) << "Could not find a roleNames property containing an array or list of strings.";
+}
+
+bool MonitorModel::extractRoleNamesFromJsArray(DataSource *dataSource)
+{
+ QQmlEngine *engine = qmlEngine(this);
+
+ QJSValue jsDataSource = engine->toScriptValue<QObject*>(dataSource->obj);
+
+ if (!jsDataSource.hasProperty(qSL("roleNames")))
+ return false;
+
+ QJSValue jsRoleNames = jsDataSource.property(qSL("roleNames"));
+ if (!jsRoleNames.isArray())
+ return false;
+
+ int length = jsRoleNames.property(qSL("length")).toInt();
+ for (int i = 0; i < length; i++)
+ addRoleName(jsRoleNames.property(i).toString().toLatin1(), dataSource);
+
+ return true;
+}
+
+bool MonitorModel::extractRoleNamesFromStringList(DataSource *dataSource)
+{
+ const QMetaObject *metaObj = dataSource->obj->metaObject();
+
+ int index = metaObj->indexOfProperty("roleNames");
+ if (index == -1)
+ return false;
+
+ QMetaProperty property = metaObj->property(index);
+
+ QVariant variant = property.read(dataSource->obj);
+
+ if (!variant.canConvert<QStringList>())
+ return false;
+
+ QList<QString> roleNames = variant.toStringList();
+ for (int i = 0; i < roleNames.count(); i++)
+ addRoleName(roleNames[i].toLatin1(), dataSource);
+
+ return true;
+}
+
+void MonitorModel::addRoleName(QByteArray roleName, DataSource *dataSource)
+{
+ dataSource->roleNames.append(roleName);
+
+ if (m_roleNamesList.contains(roleName))
+ qmlWarning(this) << "roleName" << roleName << "already exists. Model won't function correctly.";
+
+ m_roleNamesList.append(dataSource->roleNames.last());
+ m_roleNameToIndex[dataSource->roleNames.last()] = m_roleNamesList.count() - 1;
+}
+
+/*!
+ \qmlproperty int MonitorModel::count
+ \readonly
+
+ Number of rows in the model. It ranges from zero up to \l MonitorModel::maximumCount.
+
+ \sa MonitorModel::maximumCount, MonitorModel::clear
+*/
+int MonitorModel::count() const
+{
+ return m_rows.count();
+}
+
+int MonitorModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid()) {
+ // this model is not a tree
+ return 0;
+ }
+
+ return count();
+}
+
+QVariant MonitorModel::data(const QModelIndex &index, int role) const
+{
+ if (index.parent().isValid() || !index.isValid() || index.row() < 0 || index.row() >= m_rows.count())
+ return QVariant();
+
+ return m_rows.at(index.row())->dataFromRoleIndex[role];
+}
+
+QHash<int, QByteArray> MonitorModel::roleNames() const
+{
+ QHash<int, QByteArray> result;
+ for (int i = 0; i < m_roleNamesList.count(); i++) {
+ result[i] = m_roleNamesList.at(i);
+ }
+
+ return result;
+}
+
+/*!
+ \qmlproperty bool MonitorModel::running
+
+ While true, MonitorModel will keep probing its data sources and adding new rows every
+ \l MonitorModel::interval milliseconds.
+
+ Normally you have this property set to true only while the data is being displayed.
+
+ \sa MonitorModel::interval
+*/
+bool MonitorModel::running() const
+{
+ return m_timer.isActive();
+}
+
+void MonitorModel::setRunning(bool value)
+{
+ if (value && !m_timer.isActive()) {
+ m_timer.start();
+ emit runningChanged();
+ } else if (!value && m_timer.isActive()) {
+ m_timer.stop();
+ emit runningChanged();
+ }
+}
+
+/*!
+ \qmlproperty int MonitorModel::interval
+
+ Interval, in milliseconds, between each row addition while MonitorModel is \l MonitorModel::running.
+
+ \sa MonitorModel::running
+*/
+int MonitorModel::interval() const
+{
+ return m_timer.interval();
+}
+
+void MonitorModel::setInterval(int value)
+{
+ if (value != m_timer.interval()) {
+ m_timer.setInterval(value);
+ emit intervalChanged();
+ }
+}
+
+void MonitorModel::readDataSourcesAndAddRow()
+{
+ if (m_dataSources.count() == 0)
+ return;
+
+ if (m_rows.count() < m_maximumCount) {
+ // create a new row
+ DataRow *dataRow = new DataRow;
+ fillDataRow(dataRow);
+ beginInsertRows(QModelIndex(), /* first */ m_rows.count(), /* last */ m_rows.count());
+ m_rows.append(dataRow);
+ endInsertRows();
+ emit countChanged();
+ } else {
+ // recycle the oldest row
+ beginMoveRows(QModelIndex(), /* sourceFirst */ 0, /* sourceLast */ 0,
+ QModelIndex(), /* destination */ m_rows.count());
+ m_rows.append(m_rows.takeFirst());
+ endMoveRows();
+
+ {
+ fillDataRow(m_rows.last());
+ QModelIndex modelIndex = index(m_rows.count() - 1 /* row */, 0 /* column */);
+ emit dataChanged(modelIndex, modelIndex);
+ }
+ }
+}
+
+void MonitorModel::fillDataRow(DataRow *dataRow)
+{
+ for (int i = 0; i < m_dataSources.count(); ++i) {
+ readDataSource(m_dataSources[i], dataRow);
+ }
+}
+
+void MonitorModel::readDataSource(DataSource *dataSource, DataRow *dataRow)
+{
+ // TODO: check if successful
+ QMetaObject::invokeMethod(dataSource->obj, "update", Qt::DirectConnection);
+
+ for (int i = 0; i < dataSource->roleNames.count(); i++) {
+ // TODO: check index exists
+ int roleIndex = m_roleNameToIndex[dataSource->roleNames[i]];
+
+ QVariant variant = QQmlProperty::read(dataSource->obj, QLatin1String(dataSource->roleNames[i]));
+ dataRow->dataFromRoleIndex[roleIndex] = variant;
+ }
+}
+
+/*!
+ \qmlproperty int MonitorModel::maximumCount
+
+ The maximum number of rows that the MonitorModel will keep. After this limit is reached the oldest rows
+ start to get discarded to make room for the new ones coming in.
+
+ \sa MonitorModel::count, MonitorModel::clear
+*/
+int MonitorModel::maximumCount() const
+{
+ return m_maximumCount;
+}
+
+void MonitorModel::setMaximumCount(int value)
+{
+ if (m_maximumCount == value)
+ return;
+
+ m_maximumCount = value;
+ trimHistory();
+ emit maximumCountChanged();
+}
+
+void MonitorModel::trimHistory()
+{
+ int excess = m_rows.count() - m_maximumCount;
+ if (excess <= 0)
+ return;
+
+ beginRemoveRows(QModelIndex(), /* first */ 0, /* last */ excess - 1);
+
+ while (m_rows.count() > m_maximumCount)
+ delete m_rows.takeFirst();
+
+ endRemoveRows();
+}
+
+/*!
+ \qmlmethod MonitorModel::clear
+
+ Empties the model, removing all exising rows.
+
+ \sa MonitorModel::count
+*/
+void MonitorModel::clear()
+{
+ beginResetModel();
+ qDeleteAll(m_rows);
+ m_rows.clear();
+ endResetModel();
+
+ emit countChanged();
+}
diff --git a/src/monitor-lib/monitormodel.h b/src/monitor-lib/monitormodel.h
new file mode 100644
index 00000000..3dbadcf1
--- /dev/null
+++ b/src/monitor-lib/monitormodel.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QAbstractListModel>
+#include <QtAppManCommon/global.h>
+#include <QtQml/qqmllist.h>
+#include <QList>
+#include <QStringList>
+#include <QTimer>
+
+QT_BEGIN_NAMESPACE_AM
+
+class MonitorModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QQmlListProperty<QObject> dataSources READ dataSources)
+ Q_CLASSINFO("DefaultProperty", "dataSources")
+
+ Q_PROPERTY(int count READ count NOTIFY countChanged)
+ Q_PROPERTY(int maximumCount READ maximumCount WRITE setMaximumCount NOTIFY maximumCountChanged)
+
+ Q_PROPERTY(int interval READ interval WRITE setInterval NOTIFY intervalChanged)
+ Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged)
+
+public:
+ MonitorModel(QObject *parent = nullptr);
+ ~MonitorModel() override;
+
+ QQmlListProperty<QObject> dataSources();
+
+ static void dataSources_append(QQmlListProperty<QObject> *property, QObject *value);
+ static int dataSources_count(QQmlListProperty<QObject> *property);
+ static QObject *dataSources_at(QQmlListProperty<QObject> *property, int index);
+ static void dataSources_clear(QQmlListProperty<QObject> *property);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ QHash<int, QByteArray> roleNames() const override;
+
+ int count() const;
+
+ bool running() const;
+ void setRunning(bool value);
+
+ int interval() const;
+ void setInterval(int value);
+
+ int maximumCount() const;
+ void setMaximumCount(int value);
+
+ Q_INVOKABLE void clear();
+
+signals:
+ void countChanged();
+ void intervalChanged();
+ void runningChanged();
+ void maximumCountChanged();
+
+private slots:
+ void readDataSourcesAndAddRow();
+
+private:
+ struct DataRow {
+ QHash<int, QVariant> dataFromRoleIndex;
+ };
+
+ struct DataSource {
+ QObject *obj;
+ QVector<QByteArray> roleNames;
+ };
+
+ void clearDataSources();
+ void appendDataSource(QObject *dataSource);
+ void fillDataRow(DataRow *dataRow);
+ void readDataSource(DataSource *dataSource, DataRow *dataRow);
+ void trimHistory();
+ bool extractRoleNamesFromJsArray(DataSource *dataSource);
+ bool extractRoleNamesFromStringList(DataSource *dataSource);
+ void addRoleName(QByteArray roleName, DataSource *dataSource);
+
+ QList<DataSource*> m_dataSources;
+ QList<QByteArray> m_roleNamesList; // also maps a role index to its name
+ QHash<QByteArray, int> m_roleNameToIndex;
+
+ QList<DataRow*> m_rows;
+
+ QTimer m_timer;
+ int m_maximumCount = 10;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/monitor-lib/processmonitor.cpp b/src/monitor-lib/processmonitor.cpp
deleted file mode 100644
index bb978d85..00000000
--- a/src/monitor-lib/processmonitor.cpp
+++ /dev/null
@@ -1,552 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Pelagicore Application Manager.
-**
-** $QT_BEGIN_LICENSE:LGPL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite licenses may use
-** this file in accordance with the commercial license agreement provided
-** with the Software or, alternatively, in accordance with the terms
-** contained in a written agreement between you and The Qt Company. For
-** licensing terms and conditions see https://www.qt.io/terms-conditions.
-** For further information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: LGPL-3.0
-**
-****************************************************************************/
-
-#include "processmonitor.h"
-#include "processmonitor_p.h"
-#include "logging.h"
-
-#include <QtAppManManager/applicationmanager.h>
-
-
-/*!
- \qmltype ProcessMonitor
- \inqmlmodule QtApplicationManager.SystemUI
- \ingroup system-ui
- \brief A type for monitoring process resource usage.
-
- The ProcessMonitor type provides statistics about the resource usage and performance for a process known to the
- application-manager. Currently, CPU load, memory usage and frame rate can be monitored. This type is
- available in the System-UI only.
-
- The ProcessMonitor is dedicated to Linux in particular, since this is currently the only OS
- that supports multi-process mode. Other OS's are supported only rudimenatary.
-
- Here is an example, how the ProcessMonitor can be used:
-
- \qml
- import QtApplicationManager.SystemUI 1.0
-
- ProcessMonitor {
- applicationId: ""
- reportingInterval: 1000
- memoryReportingEnabled: true
-
- onMemoryReportingChanged: {
- console.log("Total PSS: " + (memoryPss.total / 1e6).toFixed(0) + " MB");
- }
- }
- \endqml
-
- The type is derived from \c QAbstractListModel, so it can be used directly as a model in an
- appropriate view.
-
- \target role-names
- Here is the list of roles that the model provides:
-
- \table
- \header
- \li Role name
- \li Type
- \li Description
- \row
- \li \c cpuLoad
- \target cpuLoad-role
- \li real
- \li The process's CPU utilization during the last reporting interval. A value of 0 means
- that the process was idle, a value of 1 means it fully used the equivalent of one core
- (which may be split over several ones).
- \row
- \li \c memoryVirtual
- \target memoryVirtual-role
- \li var
- \li A map of the process's virtual memory usage. See below for a list of supported keys.
- The total amount of virtual memory is provided through \c memoryVirtual.total for
- example.
- \row
- \li \c memoryRss
- \target memoryRss-role
- \li var
- \li A map of the process's RSS (Resident Set Size) memory usage. This is the amount of
- memory that is actually mapped to physical RAM. See below for a list of supported
- keys.
- \row
- \li \c memoryPss
- \target memoryPss-role
- \li var
- \li A map of the process's PSS (Proportional Set Size) memory usage. This is the
- proportional share of the RSS value above. For instance if two processes share 2 MB
- the RSS value will be 2 MB for each process and the PSS value 1 MB for each process.
- As the name implies, the code section of shared libraries is generally shared between
- processes. Memory may also be shared by other means provided by the OS (e.g. through
- \c mmap on Linux). See below for a list of supported keys.
-
- \row
- \li \c frameRate
- \target frameRate-role
- \li var
- \li A list of frame rate measurements where each entry corresponds to a window
- and is a map with the following keys: average, maximum, minimum and jitter.
- See below for a list of supported keys.
-
- \sa monitoredWindows
- \endtable
-
- These are the supported keys in the memory maps:
-
- \table
- \header
- \li Key
- \li Description
- \row
- \li total
- \li The amount of memory used in total in bytes.
- \row
- \li text
- \li The amount of memory used by the code section in bytes.
- \row
- \li heap
- \li The amount of memory used by the heap in bytes. This is private, dynamically allocated
- memory (for example through \c malloc or \c mmap on Linux).
- \endtable
-
- These are the supported keys in each entry of the frameRate list:
-
- \table
- \header
- \li Key
- \li Description
- \row
- \li average
- \li The average frame rate within the reporting interval.
- \row
- \li maximum
- \li The maximum frame rate within the reporting interval.
- \row
- \li minimum
- \li The minimum frame rate within the reporting interval.
- \row
- \li jitter
- \li The jitter within the reporting interval.
- \endtable
-
- \note The model will be updated each \l reportingInterval milliseconds. Note that the roles
- will only be populated, if the corresponding reporting parts have been enabled.
-*/
-
-/*!
- \qmlproperty int ProcessMonitor::count
-
- This property holds the number of reading points that will be kept in the model. The minimum
- value that can be set is 2 and the default value is 10.
-*/
-
-/*!
- \qmlproperty int ProcessMonitor::processId
- \readonly
-
- This property holds the OS specific process identifier (PID) that is monitored. This can be
- used by external tools for example. The property is 0, if there is no process associated with
- the \l applicationId. In particular, if the application-manager runs in single-process mode,
- only the System-UI (identified by an empty \l applicationId) will have an associated process.
-*/
-
-/*!
- \qmlproperty string ProcessMonitor::applicationId
-
- The ID of the application that will be monitored. It must be one of the ID's known to the
- application-manager (\l ApplicationManager::applicationIds provides a list of valid IDs). There
- is one exception: if the ID is set to an empty string, the System-UI process will be monitored.
- Setting a new value will reset the model.
-*/
-
-/*!
- \qmlproperty int ProcessMonitor::reportingInterval
-
- This property holds the interval in milliseconds between reporting updates. Note, that
- reporting will only start once this property is set. Setting a new value will reset the model.
- Valid values must be greater than zero.
-
- At least one of the reporting parts must be enabled to start the reporting.
-
- \sa cpuLoadReportingEnabled
- \sa memoryReportingEnabled
-*/
-
-/*!
- \qmlproperty bool ProcessMonitor::cpuLoadReportingEnabled
-
- A boolean value that determines whether periodic CPU load reporting is enabled.
-*/
-
-/*!
- \qmlproperty bool ProcessMonitor::memoryReportingEnabled
-
- A boolean value that determines whether periodic memory reporting is enabled.
-*/
-
-/*!
- \qmlproperty bool ProcessMonitor::frameRateReportingEnabled
-
- A boolean value that determines whether periodic frame rate reporting is enabled.
-
- \note In order to receive measurements, the \l {monitoredWindows} property needs to
- be set to windows which are going to be monitored.
-
- \sa monitoredWindows
-*/
-
-/*!
- \qmlproperty var ProcessMonitor::monitoredWindows
-
- This property holds a list of windows for which frame rate monitoring will be performed.
- Mapped windows are advertised through the \l {WindowManager::windowReady()}
- signal and the WindowManager type is itself a model which holds all windows of all
- application processes.
-
- \note It is possible to monitor server side (System-UI) views, as well,
- if the \l applicationId is empty (hence the System-UI process will be monitored).
-
- \sa frameRateReportingEnabled
-*/
-
-/*!
- \qmlsignal ProcessMonitor::cpuLoadReportingChanged(real load)
-
- This signal is emitted periodically when CPU load reporting is enabled. The frequency is
- defined by \l reportingInterval. The \a load parameter indicates the CPU utilization. Details
- can be found in the description of the \l {cpuLoad-role} {cpuLoad} model role above.
-
- \sa cpuLoadReportingEnabled
- \sa reportingInterval
-*/
-
-/*!
- \qmlsignal ProcessMonitor::memoryReportingChanged(var memoryVritual, var memoryRss
- , var memoryPss);
-
- This signal is emitted periodically when memory reporting is enabled. The frequency is defined
- by \l reportingInterval. The parameters provide the same information as the model roles with
- the same name described \l {memoryVirtual-role}{above}.
-
- \sa memoryReportingEnabled
- \sa reportingInterval
-*/
-
-/*!
- \qmlsignal ProcessMonitor::frameRateReportingChanged(var frameRate);
-
- This signal is emitted periodically when frame rate reporting is enabled and \l monitoredWindows
- is set. The frequency is defined by \l reportingInterval. The \a frameRate parameter provides
- the same information as described \l {frameRate-role}{above}.
-
- \sa frameRateReportingEnabled
- \sa reportingInterval
-*/
-
-
-QT_BEGIN_NAMESPACE_AM
-
-ProcessMonitor::ProcessMonitor(QObject *parent)
- : QAbstractListModel(parent)
- , d_ptr(new ProcessMonitorPrivate(this))
-{
- Q_D(ProcessMonitor);
-
- d->roles.insert(MemVirtual, "memoryVirtual");
- d->roles.insert(MemRss, "memoryRss");
- d->roles.insert(MemPss, "memoryPss");
- d->roles.insert(CpuLoad, "cpuLoad");
- d->roles.insert(FrameRate, "frameRate");
-
- d->resetModel();
-}
-
-ProcessMonitor::~ProcessMonitor()
-{
- Q_D(ProcessMonitor);
-
- delete d;
-}
-
-int ProcessMonitor::rowCount(const QModelIndex &parent) const
-{
- Q_UNUSED(parent)
- Q_D(const ProcessMonitor);
-
- return d->modelData.size();
-}
-
-void ProcessMonitor::setCount(int count)
-{
- Q_D(ProcessMonitor);
-
- if (count != d->count) {
- count = qMax(2, count);
- d->updateModelCount(count);
- emit d->newCount(count);
- emit countChanged(count);
- }
-}
-
-int ProcessMonitor::count() const
-{
- Q_D(const ProcessMonitor);
-
- return d->count;
-}
-
-qint64 ProcessMonitor::processId() const
-{
- Q_D(const ProcessMonitor);
-
- return d->pid;
-}
-
-
-QString ProcessMonitor::applicationId() const
-{
- Q_D(const ProcessMonitor);
-
- return d->appId;
-}
-
-void ProcessMonitor::setApplicationId(const QString &appId)
-{
- Q_D(ProcessMonitor);
-
- if (d->appId != appId || d->appId.isNull()) {
- d->appId = appId;
- d->resetModel();
- d->determinePid();
- d->setupFrameRateMonitoring();
- if (!appId.isEmpty() && ApplicationManager::instance()->indexOfApplication(appId) < 0)
- qCWarning(LogSystem) << "ProcessMonitor: invalid application ID:" << appId;
- emit applicationIdChanged(appId);
- }
-}
-
-void ProcessMonitor::setReportingInterval(int intervalInMSec)
-{
- Q_D(ProcessMonitor);
-
- if (d->reportingInterval != intervalInMSec && intervalInMSec > 0) {
- d->setupInterval(intervalInMSec);
- d->resetModel();
- emit reportingIntervalChanged(intervalInMSec);
- }
-}
-
-int ProcessMonitor::reportingInterval() const
-{
- Q_D(const ProcessMonitor);
-
- return d->reportingInterval;
-}
-
-bool ProcessMonitor::isMemoryReportingEnabled() const
-{
- Q_D(const ProcessMonitor);
-
- return d->reportMemory;
-}
-
-void ProcessMonitor::setMemoryReportingEnabled(bool enabled)
-{
- Q_D(ProcessMonitor);
-
- if (enabled != d->reportMemory) {
- d->reportMemory = enabled;
- d->memTail = enabled ? 0 : d->count;
- d->setupInterval();
- emit d->newReadMem(enabled);
- emit memoryReportingEnabledChanged();
- }
-}
-
-bool ProcessMonitor::isCpuLoadReportingEnabled() const
-{
- Q_D(const ProcessMonitor);
- return d->reportCpu;
-}
-
-void ProcessMonitor::setCpuLoadReportingEnabled(bool enabled)
-{
- Q_D(ProcessMonitor);
-
- if (enabled != d->reportCpu) {
- d->reportCpu = enabled;
- d->cpuTail = enabled ? 0: d->count;
- d->setupInterval();
- emit d->newReadCpu(enabled);
- emit cpuLoadReportingEnabledChanged();
- }
-}
-
-bool ProcessMonitor::isFrameRateReportingEnabled() const
-{
- Q_D(const ProcessMonitor);
- return d->reportFps;
-}
-
-void ProcessMonitor::setFrameRateReportingEnabled(bool enabled)
-{
- Q_D(ProcessMonitor);
-
- if (enabled != d->reportFps) {
- d->reportFps = enabled;
- d->fpsTail = enabled ? 0 : d->count;
- d->setupFrameRateMonitoring();
- emit frameRateReportingEnabledChanged();
- }
-}
-
-QVariant ProcessMonitor::data(const QModelIndex &index, int role) const
-{
- Q_D(const ProcessMonitor);
-
- if (!index.isValid() || index.row() < 0 || index.row() >= d->modelData.size())
- return QVariant();
-
- const ProcessMonitorPrivate::ModelData &reading = d->modelDataForRow(index.row());
-
- switch (role) {
- case MemVirtual:
- return reading.vm;
- case MemRss:
- return reading.rss;
- case MemPss:
- return reading.pss;
- case CpuLoad:
- return reading.cpuLoad;
- case FrameRate:
- return reading.frameRate;
- default:
- return QVariant();
- }
-}
-
-QHash<int, QByteArray> ProcessMonitor::roleNames() const
-{
- Q_D(const ProcessMonitor);
-
- return d->roles;
-}
-
-/*!
- \qmlmethod object ProcessMonitor::get(int index)
-
- Returns the model data for the reading point identified by \a index as a JavaScript object.
- See the \l {role-names} for the expected object elements. The \a index must be in the range
- [0, \l count), returns an empty object if it is invalid.
-*/
-QVariantMap ProcessMonitor::get(int row) const
-{
- if (row < 0 || row >= count()) {
- qCWarning(LogSystem) << "ProcessMonitor: invalid row:" << row;
- return QVariantMap();
- }
-
- QVariantMap map;
- QHash<int, QByteArray> roles = roleNames();
- for (auto it = roles.cbegin(); it != roles.cend(); ++it) {
- map.insert(qL1S(it.value()), data(index(row), it.key()));
- }
-
- return map;
-}
-
-QList<QObject *> ProcessMonitor::monitoredWindows() const
-{
- Q_D(const ProcessMonitor);
-
- return d->monitoredWindows();
-}
-
-void ProcessMonitor::setMonitoredWindows(QList<QObject *> windows)
-{
- Q_D(ProcessMonitor);
-
- d->updateMonitoredWindows(windows);
-}
-
-qreal ProcessMonitor::cpuLoad() const
-{
- Q_D(const ProcessMonitor);
- return d->modelData[d->latestReportPos()].cpuLoad;
-}
-
-/*!
- \qmlproperty QVariantMap ProcessMonitor::memoryVirtual
-
- A map of the process's virtual memory usage.
- \sa memoryVirtual-role
-*/
-QVariantMap ProcessMonitor::memoryVirtual() const
-{
- Q_D(const ProcessMonitor);
- return d->modelData[d->latestReportPos()].vm;
-}
-
-/*!
- \qmlproperty QVariantMap ProcessMonitor::memoryRss
-
- A map of the process's RSS (Resident Set Size) memory usage.
- \sa memoryRss-role
-*/
-QVariantMap ProcessMonitor::memoryRss() const
-{
- Q_D(const ProcessMonitor);
- return d->modelData[d->latestReportPos()].rss;
-}
-
-/*!
- \qmlproperty QVariantMap ProcessMonitor::memoryPss
-
- A map of the process's PSS (Proportional Set Size) memory usage.
- \sa memoryPss-role
-*/
-QVariantMap ProcessMonitor::memoryPss() const
-{
- Q_D(const ProcessMonitor);
- return d->modelData[d->latestReportPos()].pss;
-}
-
-QT_END_NAMESPACE_AM
diff --git a/src/monitor-lib/processmonitor_p.cpp b/src/monitor-lib/processmonitor_p.cpp
deleted file mode 100644
index 0f60b2cf..00000000
--- a/src/monitor-lib/processmonitor_p.cpp
+++ /dev/null
@@ -1,747 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Pelagicore Application Manager.
-**
-** $QT_BEGIN_LICENSE:LGPL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite licenses may use
-** this file in accordance with the commercial license agreement provided
-** with the Software or, alternatively, in accordance with the terms
-** contained in a written agreement between you and The Qt Company. For
-** licensing terms and conditions see https://www.qt.io/terms-conditions.
-** For further information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: LGPL-3.0
-**
-****************************************************************************/
-
-#include <QCoreApplication>
-#include <QtAppManWindow/windowmanager.h>
-#include "logging.h"
-#include "applicationmanager.h"
-#include "abstractruntime.h"
-#include "processmonitor_p.h"
-
-#if defined(Q_OS_MACOS)
-# include <mach/mach.h>
-#elif defined(Q_OS_LINUX)
-# include <unistd.h>
-#endif
-
-
-QT_BEGIN_NAMESPACE_AM
-
-
-ReadingTask::ReadingTask(QMutex &mutex, ReadingTask::Results &res)
- : m_mutex(mutex)
- , m_results(res)
-{}
-
-void ReadingTask::cancelTimer()
-{
- if (m_reportingTimerId) {
- killTimer(m_reportingTimerId);
- m_reportingTimerId = 0;
- }
-}
-
-void ReadingTask::setupTimer(bool enabled, int interval)
-{
- if (interval != -1)
- m_reportingInterval = interval;
-
- if (!enabled) {
- cancelTimer();
- } else {
- if (interval != -1)
- cancelTimer();
-
- if (!m_reportingTimerId && m_reportingInterval >= 0)
- m_reportingTimerId = startTimer(m_reportingInterval);
- }
-}
-
-void ReadingTask::setNewPid(qint64 pid)
-{
- m_pid = pid;
- if (pid) {
- openLoad();
- readLoad();
- }
-}
-
-void ReadingTask::setNewReadCpu(bool enabled)
-{
- m_readCpu = enabled;
- if (enabled)
- readLoad();
-}
-
-void ReadingTask::setNewReadMem(bool enabled)
-{
- m_readMem = enabled;
-}
-
-void ReadingTask::reset(int sync)
-{
- m_sync = sync;
-}
-
-void ReadingTask::timerEvent(QTimerEvent *event)
-{
- if (event && event->timerId() == m_reportingTimerId && m_pid) {
- ReadingTask::Results results;
-
- if (m_readMem) {
- const QByteArray file = "/proc/" + QByteArray::number(m_pid) + "/smaps";
- if (!readMemory(file, results.memory))
- results.memory = ReadingTask::Results::Memory();
- results.memory.read = true;
- }
-
- if (m_readCpu) {
- results.cpu.load = readLoad();
- results.cpu.read = true;
- }
-
- results.sync = m_sync;
-
- m_mutex.lock();
- m_results = results;
- m_mutex.unlock();
-
- emit newReadingAvailable();
- }
-}
-
-
-#if defined(Q_OS_LINUX)
-
-void ReadingTask::openLoad()
-{
- const QByteArray fileName = "/proc/" + QByteArray::number(m_pid) + "/stat";
- m_statReader.reset(new SysFsReader(fileName));
- if (!m_statReader->isOpen())
- qCWarning(LogSystem) << "Cannot read CPU load from" << fileName;
-}
-
-qreal ReadingTask::readLoad()
-{
- qint64 elapsed;
- if (m_elapsedTime.isValid()) {
- elapsed = m_elapsedTime.restart();
- } else {
- elapsed = 0;
- m_elapsedTime.start();
- }
-
- if (m_statReader.isNull() || !m_statReader->isOpen()) {
- m_lastCpuUsage = 0.0;
- return 0.0;
- }
-
- QByteArray str = m_statReader->readValue();
- int pos = 0;
- int blanks = 0;
- while (pos < str.size() && blanks < 13) {
- if (isblank(str.at(pos)))
- ++blanks;
- ++pos;
- }
-
- char *endPtr = nullptr;
- quint64 utime = strtoull(str.constData() + pos, &endPtr, 10); // check missing for overflow
- pos = int(endPtr - str.constData() + 1);
- quint64 stime = strtoull(str.constData() + pos, nullptr, 10); // check missing for overflow
-
- qreal load = elapsed != 0 ? (utime + stime - m_lastCpuUsage) * 1000.0 / sysconf(_SC_CLK_TCK) / elapsed : 0.0;
- m_lastCpuUsage = utime + stime;
- return load;
-}
-
-static uint parseValue(const char *pl)
-{
- while (*pl && (*pl < '0' || *pl > '9'))
- pl++;
- return static_cast<uint>(strtoul(pl, nullptr, 10));
-}
-
-bool ReadingTask::readMemory(const QByteArray &smapsFile, ReadingTask::Results::Memory &results)
-{
- struct ScopedFile {
- ~ScopedFile() { if (file) fclose(file); }
- FILE *file = nullptr;
- };
-
- ScopedFile sf;
- sf.file = fopen(smapsFile.constData(), "r");
-
- if (sf.file == nullptr)
- return false;
-
- const int lineLen = 100; // we are not interested in full library paths
- char line[lineLen + 5]; // padding for highly unlikely trailing perm flags below
- char *pl; // pointer to chars within line
- bool ok = true;
-
- if (fgets(line, lineLen, sf.file) == nullptr)
- return false;
-
- // sanity checks
- pl = line;
- for (pl = line; pl < (line + 4) && ok; ++pl)
- ok = ((*pl >= '0' && *pl <= '9') || (*pl >= 'a' && *pl <= 'f'));
- while (strlen(line) == lineLen - 1 && line[lineLen - 2] != '\n') {
- if (Q_UNLIKELY(!fgets(line, lineLen, sf.file)))
- break;
- }
- if (fgets(line, lineLen, sf.file) == nullptr)
- return false;
- static const char strSize[] = "Size: ";
- ok = ok && !qstrncmp(line, strSize, sizeof(strSize) - 1);
- if (!ok)
- return false;
-
- // Determine block size
- ok = false;
- int blockLen = 0;
- while (fgets(line, lineLen, sf.file) != nullptr && !ok) {
- if (!(line[0] < '0' || line[0] > '9') && (line[0] < 'a' || line[0] > 'f'))
- ok = true;
- ++blockLen;
- }
- if (!ok || blockLen < 12 || blockLen > 32)
- return false;
-
- fseek(sf.file, 0, SEEK_SET);
- bool wasPrivateOnly = false;
- ok = false;
-
- while (true) {
- if (Q_UNLIKELY(!(fgets(line, lineLen, sf.file) != nullptr))) {
- ok = feof(sf.file);
- break;
- }
-
- // Determine permission flags
- pl = line;
- while (*pl && *pl != ' ')
- ++pl;
- char permissions[4];
- memcpy(permissions, ++pl, sizeof(permissions));
-
- // Determine inode
- int spaceCount = 0;
- while (*pl && spaceCount < 3) {
- if (*pl == ' ')
- ++spaceCount;
- ++pl;
- }
- bool hasInode = (*pl != '0');
-
- // Determine library name
- while (*pl && *pl != ' ')
- ++pl;
- while (*pl && *pl == ' ')
- ++pl;
-
- static const char strStack[] = "stack]";
- bool isMainStack = (Q_UNLIKELY(*pl == '['
- && !qstrncmp(pl + 1, strStack, sizeof(strStack) - 1)));
- // Skip rest of library path
- while (strlen(line) == lineLen - 1 && line[lineLen - 2] != '\n') {
- if (Q_UNLIKELY(!fgets(line, lineLen, sf.file)))
- break;
- }
-
- int skipLen = blockLen;
- uint vm = 0;
- uint rss = 0;
- uint pss = 0;
- const int sizeTag = 0x01;
- const int rssTag = 0x02;
- const int pssTag = 0x04;
- const int allTags = sizeTag | rssTag | pssTag;
- int foundTags = 0;
-
- while (foundTags < allTags && skipLen > 0) {
- skipLen--;
- if (Q_UNLIKELY(!fgets(line, lineLen, sf.file)))
- break;
- pl = line;
-
- static const char strSize[] = "ize:";
- static const char strXss[] = "ss:";
-
- switch (*pl) {
- case 'S':
- if (!qstrncmp(pl + 1, strSize, sizeof(strSize) - 1)) {
- foundTags |= sizeTag;
- vm = parseValue(pl + sizeof(strSize));
- }
- break;
- case 'R':
- if (!qstrncmp(pl + 1, strXss, sizeof(strXss) - 1)) {
- foundTags |= rssTag;
- rss = parseValue(pl + sizeof(strXss));
- }
- break;
- case 'P':
- if (!qstrncmp(pl + 1, strXss, sizeof(strXss) - 1)) {
- foundTags |= pssTag;
- pss = parseValue(pl + sizeof(strXss));
- }
- break;
- }
- }
-
- if (foundTags < allTags)
- break;
-
- results.totalVm += vm;
- results.totalRss += rss;
- results.totalPss += pss;
-
- static const char permRXP[] = { 'r', '-', 'x', 'p' };
- static const char permRWP[] = { 'r', 'w', '-', 'p' };
- if (!memcmp(permissions, permRXP, sizeof(permissions))) {
- results.textVm += vm;
- results.textRss += rss;
- results.textPss += pss;
- } else if (!memcmp(permissions, permRWP, sizeof(permissions))
- && !isMainStack && (vm != 8192 || hasInode || !wasPrivateOnly) // try to exclude stack
- && !hasInode) {
- results.heapVm += vm;
- results.heapRss += rss;
- results.heapPss += pss;
- }
-
- static const char permP[] = { '-', '-', '-', 'p' };
- wasPrivateOnly = !memcmp(permissions, permP, sizeof(permissions));
-
- for (int skip = skipLen; skip; --skip) {
- if (Q_UNLIKELY(!fgets(line, lineLen, sf.file)))
- break;
- }
- }
-
- return ok;
-}
-
-#elif defined(Q_OS_MACOS)
-
-void ReadingTask::openLoad()
-{
-}
-
-qreal ReadingTask::readLoad()
-{
- return 0.0;
-}
-
-bool ReadingTask::readMemory(const QByteArray &smapsFile, ReadingTask::Results::Memory &results)
-{
- Q_UNUSED(smapsFile)
- struct task_basic_info t_info;
- mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
-
- if (KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count)) {
- qCWarning(LogSystem) << "Could not read memory data";
- return false;
- }
-
- results.totalRss = t_info.resident_size;
- results.totalVm = t_info.virtual_size;
-
- return true;
-}
-
-#else
-
-void ReadingTask::openLoad()
-{
-}
-
-qreal ReadingTask::readLoad()
-{
- return 0.0;
-}
-
-bool ReadingTask::readMemory(const QByteArray &smapsFile, ReadingTask::Results::Memory &results)
-{
- Q_UNUSED(smapsFile)
- Q_UNUSED(results)
- return false;
-}
-
-#endif
-
-
-ProcessMonitorPrivate::ProcessMonitorPrivate(ProcessMonitor *q)
- : q_ptr(q)
-{
- connect(ApplicationManager::instance(), &ApplicationManager::applicationRunStateChanged,
- this, &ProcessMonitorPrivate::appRuntimeChanged);
-
- readingTask = new ReadingTask(mutex, readResults);
- readingTask->moveToThread(&thread);
- connect(this, &ProcessMonitorPrivate::newPid, readingTask, &ReadingTask::setNewPid);
- connect(this, &ProcessMonitorPrivate::setupTimer, readingTask, &ReadingTask::setupTimer);
- connect(this, &ProcessMonitorPrivate::newReadCpu, readingTask, &ReadingTask::setNewReadCpu);
- connect(this, &ProcessMonitorPrivate::newReadMem, readingTask, &ReadingTask::setNewReadMem);
- connect(this, &ProcessMonitorPrivate::reset, readingTask, &ReadingTask::reset);
- connect(readingTask, &ReadingTask::newReadingAvailable, this, &ProcessMonitorPrivate::readingUpdate);
- connect(&thread, &QThread::finished, readingTask, &ReadingTask::deleteLater);
- thread.start();
-}
-
-ProcessMonitorPrivate::~ProcessMonitorPrivate()
-{
- thread.quit();
- thread.wait();
-}
-
-void ProcessMonitorPrivate::appRuntimeChanged(const QString &id, Am::RunState state)
-{
- if (id == appId && (state == Am::Running || state == Am::NotRunning))
- determinePid();
-}
-
-void ProcessMonitorPrivate::setupInterval(int interval)
-{
- bool shouldBeOn = pid && (reportCpu || reportMemory || reportFps || cpuTail || memTail || fpsTail);
- emit setupTimer(shouldBeOn, interval);
-}
-
-void ProcessMonitorPrivate::determinePid()
-{
- Q_Q(ProcessMonitor);
-
- qint64 newId;
- if (appId.isEmpty()) {
- newId = QCoreApplication::applicationPid();
- } else {
- if (ApplicationManager::instance()->isSingleProcess()) {
- newId = 0;
- } else {
- AbstractApplication *app = ApplicationManager::instance()->fromId(appId);
- newId = (app && app->currentRuntime()) ? app->currentRuntime()->applicationProcessId() : 0;
- }
- }
-
- if (newId != pid) {
- pid = newId;
- setupInterval();
- emit newPid(pid);
- emit q->processIdChanged(pid);
- }
-}
-
-const ProcessMonitorPrivate::ModelData &ProcessMonitorPrivate::modelDataForRow(int row) const
-{
- int pos = reportPos - row - 1;
- if (pos < 0)
- pos += modelData.size();
- if (pos < 0 || pos >= modelData.size())
- return modelData.first();
- return modelData.at(pos);
-}
-
-
-void ProcessMonitorPrivate::resetModel()
-{
- Q_Q(ProcessMonitor);
-
- q->beginResetModel();
- modelData.clear();
- modelData.resize(count);
- reportPos = 0;
- q->endResetModel();
-
- cpuTail = memTail = fpsTail = 0;
-
- emit reset(++sync);
-}
-
-void ProcessMonitorPrivate::updateModelCount(int newCount)
-{
- Q_Q(ProcessMonitor);
-
- int diff = newCount - count;
- q->beginResetModel();
- if (diff > 0) {
- modelData.insert(reportPos, diff, ModelData());
- } else {
- if (reportPos <= newCount) {
- modelData.remove(reportPos, -diff);
- if (reportPos == newCount)
- reportPos = 0;
- } else {
- modelData.remove(reportPos, count - reportPos);
- modelData.remove(0, reportPos - newCount);
- reportPos = 0;
- }
- }
- count = newCount;
- q->endResetModel();
-
- if (cpuTail > 0)
- cpuTail += diff;
- if (memTail > 0)
- memTail += diff;
- if (fpsTail > 0)
- fpsTail += diff;
-}
-
-void ProcessMonitorPrivate::readingUpdate()
-{
- Q_Q(ProcessMonitor);
-
- QVector<int> roles;
- ModelData data;
- ReadingTask::Results results;
-
- mutex.lock();
- results = readResults;
- mutex.unlock();
-
- if (sync != results.sync)
- return;
-
- if (cpuTail > 0) {
- if (--cpuTail == 0)
- setupInterval();
- roles.append(CpuLoad);
- } else if (results.cpu.read) {
- data.cpuLoad = results.cpu.load;
- roles.append(CpuLoad);
- }
-
- if (results.memory.read || memTail > 0) {
- if (memTail > 0) {
- if (--memTail == 0)
- setupInterval();
- results.memory = ReadingTask::Results::Memory();
- }
-
- // Although smaps claims to report kB it's actually KiB (2^10 = 1024 Bytes)
- data.vm.insert(qSL("total"), quint64(results.memory.totalVm) << 10);
- data.vm.insert(qSL("text"), quint64(results.memory.textRss) << 10);
- data.vm.insert(qSL("heap"), quint64(results.memory.heapPss) << 10);
- data.rss.insert(qSL("total"), quint64(results.memory.totalRss) << 10);
- data.rss.insert(qSL("text"), quint64(results.memory.textRss) << 10);
- data.rss.insert(qSL("heap"), quint64(results.memory.heapRss) << 10);
- data.pss.insert(qSL("total"), quint64(results.memory.totalPss) << 10);
- data.pss.insert(qSL("text"), quint64(results.memory.textPss) << 10);
- data.pss.insert(qSL("heap"), quint64(results.memory.heapPss) << 10);
-
- roles.append({ MemVirtual, MemRss, MemPss });
- }
-
- if (reportFps || fpsTail > 0) {
- if (fpsTail > 0 && --fpsTail == 0)
- setupInterval();
-
- for (auto it = frameCounters.begin(); it != frameCounters.end(); ++it) {
- QVariantMap frameMap;
- FrameTimer *frameTimer = frameCounters.value(it.key());
- frameMap.insert(qSL("average"), frameTimer->averageFps());
- frameMap.insert(qSL("maximum"), frameTimer->maximumFps());
- frameMap.insert(qSL("minimum"), frameTimer->minimumFps());
- frameMap.insert(qSL("jitter"), frameTimer->jitterFps());
- frameTimer->reset();
- data.frameRate.append(frameMap);
- }
-
- emit q->frameRateReportingChanged(data.frameRate);
-
- roles.append(FrameRate);
- }
-
- int last = modelData.size() - 1;
- q->beginMoveRows(QModelIndex(), last, last, QModelIndex(), 0);
- modelData[reportPos++] = data;
- if (reportPos > last)
- reportPos = 0;
- q->endMoveRows();
- q->dataChanged(q->index(0), q->index(0), roles);
-
- if (reportCpu)
- emit q->cpuLoadReportingChanged(data.cpuLoad);
-
- if (results.memory.read || memTail > 0)
- emit q->memoryReportingChanged(data.vm, data.rss, data.pss);
-}
-
-void ProcessMonitorPrivate::setupFrameRateMonitoring()
-{
- resetFrameRateMonitoring();
-#if !defined(AM_HEADLESS)
- if (reportFps) {
- if (ApplicationManager::instance()->isSingleProcess() || appId.isEmpty()) {
-
- for (auto it = frameCounters.begin(); it != frameCounters.end(); ++it) {
- QQuickWindow *win = qobject_cast<QQuickWindow *>(it.key());
- if (win) {
- connections << connect(win, &QQuickWindow::frameSwapped,
- this, &ProcessMonitorPrivate::frameUpdated);
- }
- }
- } else {
-# if defined(AM_MULTI_PROCESS)
-
- for (auto it = frameCounters.begin(); it != frameCounters.end(); ++it) {
- WaylandWindow *win = qobject_cast<WaylandWindow *>(it.key());
- if (win) {
- // Check if this is valid window for this application
- if (win->application() && win->application()->id() == appId) {
- connections << connect(win, &WaylandWindow::frameUpdated,
- this, &ProcessMonitorPrivate::frameUpdated);
- } else {
- qCWarning(LogSystem) << "Windows do not belong to this app";
- return;
- }
- }
- }
-
- connect(WindowManager::instance(), &WindowManager::windowContentStateChanged,
- this, &ProcessMonitorPrivate::onWindowContentStateChanged);
-# endif
- }
- } else {
-# if defined(AM_MULTI_PROCESS)
- disconnect(WindowManager::instance(), &WindowManager::windowContentStateChanged,
- this, &ProcessMonitorPrivate::onWindowContentStateChanged);
-# endif
- }
-#endif // !AM_HEADLESS
-}
-
-void ProcessMonitorPrivate::updateMonitoredWindows(const QList<QObject *> &windowObjs)
-{
-#if !defined(AM_HEADLESS)
- Q_Q(ProcessMonitor);
-
- clearMonitoredWindows();
-
- for (auto windowObj : windowObjs) {
- if (ApplicationManager::instance()->isSingleProcess() || appId.isEmpty()) {
- QQuickWindow *view = qobject_cast<QQuickWindow *>(windowObj);
- if (view) {
- FrameTimer *frameTimer = new FrameTimer();
- frameCounters.insert(view, frameTimer);
- } else
- qCWarning(LogSystem) << "In single process only QQuickWindow can be monitored";
- } else {
-# if defined(AM_MULTI_PROCESS)
- auto window = qobject_cast<Window*>(windowObj);
- if (window && window->application()->nonAliased()->id() == appId) {
- FrameTimer *frameTimer = new FrameTimer();
- frameCounters.insert(window, frameTimer);
- } else
- continue; // TODO: Complain in a warning message
-# endif
- }
- }
-
- emit q->monitoredWindowsChanged();
- setupFrameRateMonitoring();
-#else
- Q_UNUSED(windows)
-#endif
-}
-
-QList<QObject *> ProcessMonitorPrivate::monitoredWindows() const
-{
- QList<QObject *> list;
-
-#if !defined(AM_HEADLESS)
- if (ApplicationManager::instance()->isSingleProcess() || appId.isEmpty()) {
- for (auto it = frameCounters.begin(); it != frameCounters.end(); ++it) {
- list.append(it.key());
- }
-
- return list;
- }
-
-# if defined(AM_MULTI_PROCESS)
- // Return window items
- for (auto it = frameCounters.begin(); it != frameCounters.end(); ++it) {
- WaylandWindow *win = qobject_cast<WaylandWindow *>(it.key());
- if (win)
- list.append(win);
- }
-# endif
-#endif
- return list;
-}
-
-#if defined(AM_MULTI_PROCESS) && !defined(AM_HEADLESS)
-
-void ProcessMonitorPrivate::onWindowContentStateChanged(Window *window)
-{
- if (window->contentState() == Window::SurfaceWithContent)
- return;
-
- for (auto it = frameCounters.cbegin(); it != frameCounters.cend(); ++it) {
- auto win = qobject_cast<Window *>(it.key());
- if (win && win == window) {
- frameCounters.remove(win);
- break;
- }
- }
-}
-
-#endif
-
-void ProcessMonitorPrivate::frameUpdated()
-{
- FrameTimer *frameTimer = frameCounters.value(sender());
- if (!frameTimer) {
- frameTimer = new FrameTimer();
- frameCounters.insert(sender(), frameTimer);
- }
-
- frameTimer->newFrame();
-}
-
-void ProcessMonitorPrivate::resetFrameRateMonitoring()
-{
- for (auto connection : connections) {
- QObject::disconnect(connection);
- }
-
- connections.clear();
-}
-
-void ProcessMonitorPrivate::clearMonitoredWindows()
-{
- qDeleteAll(frameCounters);
- frameCounters.clear();
-}
-
-QT_END_NAMESPACE_AM
diff --git a/src/monitor-lib/processmonitor_p.h b/src/monitor-lib/processmonitor_p.h
deleted file mode 100644
index 6be04102..00000000
--- a/src/monitor-lib/processmonitor_p.h
+++ /dev/null
@@ -1,240 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Pelagicore Application Manager.
-**
-** $QT_BEGIN_LICENSE:LGPL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite licenses may use
-** this file in accordance with the commercial license agreement provided
-** with the Software or, alternatively, in accordance with the terms
-** contained in a written agreement between you and The Qt Company. For
-** licensing terms and conditions see https://www.qt.io/terms-conditions.
-** For further information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: LGPL-3.0
-**
-****************************************************************************/
-
-#pragma once
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the application manager API. It exists purely as an
-// implementation detail. This header file may change from version to version
-// without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QObject>
-#include <QElapsedTimer>
-#include <QThread>
-#include <QMutex>
-#include <QString>
-#include <QHash>
-#include <QVector>
-#if defined(Q_OS_LINUX)
-# include <QScopedPointer>
-# include "sysfsreader.h"
-#endif
-#if !defined(AM_HEADLESS)
-# include <QQuickWindow>
-# if defined(AM_MULTI_PROCESS)
-# include <QtAppManWindow/waylandwindow.h>
-# endif
-#endif
-#include "processmonitor.h"
-#include "frametimer.h"
-#include "applicationmanager.h"
-
-QT_BEGIN_NAMESPACE_AM
-
-class Window;
-
-class ReadingTask : public QObject
-{
- Q_OBJECT
-
-public:
- struct Results {
- int sync;
-
- struct Memory {
- bool read = false;
- quint32 totalVm = 0;
- quint32 totalRss = 0;
- quint32 totalPss = 0;
- quint32 textVm = 0;
- quint32 textRss = 0;
- quint32 textPss = 0;
- quint32 heapVm = 0;
- quint32 heapRss = 0;
- quint32 heapPss = 0;
- } memory;
-
- struct Cpu {
- bool read = false;
- qreal load = 0;
- } cpu;
- };
-
- ReadingTask(QMutex &mutex, Results &res);
-
-protected:
- void timerEvent(QTimerEvent *event) override;
- bool readMemory(const QByteArray &smapsFile, Results::Memory &results);
-
-public slots:
- void setupTimer(bool enabled, int interval);
- void setNewPid(qint64 pid);
- void setNewReadMem(bool enabled);
- void setNewReadCpu(bool enabled);
- void reset(int sync);
-
-signals:
- void newReadingAvailable();
-
-private:
- void cancelTimer();
- void openLoad();
- qreal readLoad();
-
- QMutex &m_mutex;
- Results &m_results;
- int m_sync = 0;
-
-#if defined(Q_OS_LINUX)
- QScopedPointer<SysFsReader> m_statReader;
-#endif
- QElapsedTimer m_elapsedTime;
- quint64 m_lastCpuUsage;
-
- qint64 m_pid;
-
- bool m_readCpu = false;
- bool m_readMem = false;
-
- int m_reportingInterval = -1;
- int m_reportingTimerId = 0;
-};
-
-
-namespace {
-enum Roles {
- MemVirtual = Qt::UserRole,
- MemRss,
- MemPss,
- CpuLoad,
- FrameRate
-};
-}
-
-class ProcessMonitorPrivate : public QObject
-{
- Q_OBJECT
-public:
- ProcessMonitor *q_ptr;
- Q_DECLARE_PUBLIC(ProcessMonitor)
-
- struct ModelData {
- QVariantMap vm;
- QVariantMap rss;
- QVariantMap pss;
- qreal cpuLoad = 0;
- QVariantList frameRate;
- };
-
- QString appId;
- qint64 pid = 0;
-
- int reportingInterval = -1;
- int count = 10;
-
- int reportPos = 0;
-
- bool reportMemory = false;
- bool reportCpu = false;
- bool reportFps = false;
- int cpuTail = 0;
- int memTail = 0;
- int fpsTail = 0;
-
- QHash<int, QByteArray> roles;
- QVector<ModelData> modelData;
-
- // fps
- QMap<QObject *, FrameTimer *> frameCounters;
-
- ReadingTask *readingTask;
- ReadingTask::Results readResults;
- QThread thread;
- QMutex mutex;
- int sync = 0;
-
- QList<QMetaObject::Connection> connections;
-
- ProcessMonitorPrivate(ProcessMonitor *q);
- ~ProcessMonitorPrivate();
-
- void setupInterval(int interval = -1);
- void determinePid();
- const ModelData &modelDataForRow(int row) const;
- void resetModel();
- void updateModelCount(int newCount);
- void setupFrameRateMonitoring();
- void updateMonitoredWindows(const QList<QObject *> &windows);
- QList<QObject *> monitoredWindows() const;
- void resetFrameRateMonitoring();
- void clearMonitoredWindows();
-
- int latestReportPos() const {
- // show the one before reportPos, wrapping around if reportPos
- // is already the very first index.
- return reportPos == 0 ? modelData.size() - 1 : reportPos - 1;
- }
-
-signals:
- void setupTimer(bool enabled, int interval);
- void newPid(qint64 pid);
- void newReadMem(bool enabled);
- void newReadCpu(bool enabled);
- void newCount(int count);
- void reset(int sync);
-
-public slots:
- void readingUpdate();
- void appRuntimeChanged(const QString &id, Am::RunState state);
-#if defined(AM_MULTI_PROCESS) && !defined(AM_HEADLESS)
- void onWindowContentStateChanged(Window *window);
-#endif
- void frameUpdated();
-};
-
-
-QT_END_NAMESPACE_AM
diff --git a/src/monitor-lib/processreader.cpp b/src/monitor-lib/processreader.cpp
new file mode 100644
index 00000000..fc73d000
--- /dev/null
+++ b/src/monitor-lib/processreader.cpp
@@ -0,0 +1,374 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "processreader.h"
+
+#include "logging.h"
+
+#if defined(Q_OS_MACOS)
+# include <mach/mach.h>
+#elif defined(Q_OS_LINUX)
+# include <unistd.h>
+#endif
+
+namespace {
+ static uint parseValue(const char *pl) {
+ while (*pl && (*pl < '0' || *pl > '9'))
+ pl++;
+ return static_cast<uint>(strtoul(pl, nullptr, 10));
+ }
+}
+
+QT_USE_NAMESPACE_AM
+
+void ProcessReader::setProcessId(qint64 pid)
+{
+ m_pid = pid;
+ if (pid)
+ openCpuLoad();
+}
+
+void ProcessReader::update()
+{
+ // read cpu
+ {
+ qreal cpuLoadFloat = readCpuLoad();
+ quint32 value = ((qreal)std::numeric_limits<quint32>::max()) * cpuLoadFloat;
+ cpuLoad.store(value);
+ }
+
+ {
+ if (!readMemory()) {
+ totalVm.store(0);
+ totalRss.store(0);
+ totalPss.store(0);
+ textVm.store(0);
+ textRss.store(0);
+ textPss.store(0);
+ heapVm.store(0);
+ heapRss.store(0);
+ heapPss.store(0);
+ }
+ }
+
+ emit updated();
+}
+
+#if defined(Q_OS_LINUX)
+
+void ProcessReader::openCpuLoad()
+{
+ const QByteArray fileName = "/proc/" + QByteArray::number(m_pid) + "/stat";
+ m_statReader.reset(new SysFsReader(fileName));
+ if (!m_statReader->isOpen())
+ qCWarning(LogSystem) << "Cannot read CPU load from" << fileName;
+}
+
+qreal ProcessReader::readCpuLoad()
+{
+ qint64 elapsed;
+ if (m_elapsedTime.isValid()) {
+ elapsed = m_elapsedTime.restart();
+ } else {
+ elapsed = 0;
+ m_elapsedTime.start();
+ }
+
+ if (m_statReader.isNull() || !m_statReader->isOpen()) {
+ m_lastCpuUsage = 0.0;
+ return 0.0;
+ }
+
+ QByteArray str = m_statReader->readValue();
+ int pos = 0;
+ int blanks = 0;
+ while (pos < str.size() && blanks < 13) {
+ if (isblank(str.at(pos)))
+ ++blanks;
+ ++pos;
+ }
+
+ char *endPtr = nullptr;
+ quint64 utime = strtoull(str.constData() + pos, &endPtr, 10); // check missing for overflow
+ pos = int(endPtr - str.constData() + 1);
+ quint64 stime = strtoull(str.constData() + pos, nullptr, 10); // check missing for overflow
+
+ qreal load = elapsed != 0 ? (utime + stime - m_lastCpuUsage) * 1000.0 / sysconf(_SC_CLK_TCK) / elapsed : 0.0;
+ m_lastCpuUsage = utime + stime;
+ return load;
+}
+
+
+bool ProcessReader::readMemory()
+{
+ QByteArray smapsFile = "/proc/" + QByteArray::number(m_pid) + "/smaps";
+ return readSmaps(smapsFile);
+}
+
+bool ProcessReader::readSmaps(const QByteArray &smapsFile)
+{
+ quint32 _totalVm = 0;
+ quint32 _totalRss = 0;
+ quint32 _totalPss = 0;
+ quint32 _textVm = 0;
+ quint32 _textRss = 0;
+ quint32 _textPss = 0;
+ quint32 _heapVm = 0;
+ quint32 _heapRss = 0;
+ quint32 _heapPss = 0;
+
+ struct ScopedFile {
+ ~ScopedFile() { if (file) fclose(file); }
+ FILE *file = nullptr;
+ };
+
+ ScopedFile sf;
+ sf.file = fopen(smapsFile.constData(), "r");
+
+ if (sf.file == nullptr)
+ return false;
+
+ const int lineLen = 100; // we are not interested in full library paths
+ char line[lineLen + 5]; // padding for highly unlikely trailing perm flags below
+ char *pl; // pointer to chars within line
+ bool ok = true;
+
+ if (fgets(line, lineLen, sf.file) == nullptr)
+ return false;
+
+ // sanity checks
+ pl = line;
+ for (pl = line; pl < (line + 4) && ok; ++pl)
+ ok = ((*pl >= '0' && *pl <= '9') || (*pl >= 'a' && *pl <= 'f'));
+ while (strlen(line) == lineLen - 1 && line[lineLen - 2] != '\n') {
+ if (Q_UNLIKELY(!fgets(line, lineLen, sf.file)))
+ break;
+ }
+ if (fgets(line, lineLen, sf.file) == nullptr)
+ return false;
+ static const char strSize[] = "Size: ";
+ ok = ok && !qstrncmp(line, strSize, sizeof(strSize) - 1);
+ if (!ok)
+ return false;
+
+ // Determine block size
+ ok = false;
+ int blockLen = 0;
+ while (fgets(line, lineLen, sf.file) != nullptr && !ok) {
+ if (!(line[0] < '0' || line[0] > '9') && (line[0] < 'a' || line[0] > 'f'))
+ ok = true;
+ ++blockLen;
+ }
+ if (!ok || blockLen < 12 || blockLen > 32)
+ return false;
+
+ fseek(sf.file, 0, SEEK_SET);
+ bool wasPrivateOnly = false;
+ ok = false;
+
+ while (true) {
+ if (Q_UNLIKELY(!(fgets(line, lineLen, sf.file) != nullptr))) {
+ ok = feof(sf.file);
+ break;
+ }
+
+ // Determine permission flags
+ pl = line;
+ while (*pl && *pl != ' ')
+ ++pl;
+ char permissions[4];
+ memcpy(permissions, ++pl, sizeof(permissions));
+
+ // Determine inode
+ int spaceCount = 0;
+ while (*pl && spaceCount < 3) {
+ if (*pl == ' ')
+ ++spaceCount;
+ ++pl;
+ }
+ bool hasInode = (*pl != '0');
+
+ // Determine library name
+ while (*pl && *pl != ' ')
+ ++pl;
+ while (*pl && *pl == ' ')
+ ++pl;
+
+ static const char strStack[] = "stack]";
+ bool isMainStack = (Q_UNLIKELY(*pl == '['
+ && !qstrncmp(pl + 1, strStack, sizeof(strStack) - 1)));
+ // Skip rest of library path
+ while (strlen(line) == lineLen - 1 && line[lineLen - 2] != '\n') {
+ if (Q_UNLIKELY(!fgets(line, lineLen, sf.file)))
+ break;
+ }
+
+ int skipLen = blockLen;
+ uint vm = 0;
+ uint rss = 0;
+ uint pss = 0;
+ const int sizeTag = 0x01;
+ const int rssTag = 0x02;
+ const int pssTag = 0x04;
+ const int allTags = sizeTag | rssTag | pssTag;
+ int foundTags = 0;
+
+ while (foundTags < allTags && skipLen > 0) {
+ skipLen--;
+ if (Q_UNLIKELY(!fgets(line, lineLen, sf.file)))
+ break;
+ pl = line;
+
+ static const char strSize[] = "ize:";
+ static const char strXss[] = "ss:";
+
+ switch (*pl) {
+ case 'S':
+ if (!qstrncmp(pl + 1, strSize, sizeof(strSize) - 1)) {
+ foundTags |= sizeTag;
+ vm = parseValue(pl + sizeof(strSize));
+ }
+ break;
+ case 'R':
+ if (!qstrncmp(pl + 1, strXss, sizeof(strXss) - 1)) {
+ foundTags |= rssTag;
+ rss = parseValue(pl + sizeof(strXss));
+ }
+ break;
+ case 'P':
+ if (!qstrncmp(pl + 1, strXss, sizeof(strXss) - 1)) {
+ foundTags |= pssTag;
+ pss = parseValue(pl + sizeof(strXss));
+ }
+ break;
+ }
+ }
+
+ if (foundTags < allTags)
+ break;
+
+ _totalVm += vm;
+ _totalRss += rss;
+ _totalPss += pss;
+
+ static const char permRXP[] = { 'r', '-', 'x', 'p' };
+ static const char permRWP[] = { 'r', 'w', '-', 'p' };
+ if (!memcmp(permissions, permRXP, sizeof(permissions))) {
+ _textVm += vm;
+ _textRss += rss;
+ _textPss += pss;
+ } else if (!memcmp(permissions, permRWP, sizeof(permissions))
+ && !isMainStack && (vm != 8192 || hasInode || !wasPrivateOnly) // try to exclude stack
+ && !hasInode) {
+ _heapVm += vm;
+ _heapRss += rss;
+ _heapPss += pss;
+ }
+
+ static const char permP[] = { '-', '-', '-', 'p' };
+ wasPrivateOnly = !memcmp(permissions, permP, sizeof(permissions));
+
+ for (int skip = skipLen; skip; --skip) {
+ if (Q_UNLIKELY(!fgets(line, lineLen, sf.file)))
+ break;
+ }
+ }
+
+ if (ok) {
+ // publish the readings
+ totalVm.store(_totalVm);
+ totalRss.store(_totalRss);
+ totalPss.store(_totalPss);
+ textVm.store(_textVm);
+ textRss.store(_textRss);
+ textPss.store(_textPss);
+ heapVm.store(_heapVm);
+ heapRss.store(_heapRss);
+ heapPss.store(_heapPss);
+ }
+
+ return ok;
+}
+
+#elif defined(Q_OS_MACOS)
+
+void ProcessReader::openCpuLoad()
+{
+}
+
+qreal ProcessReader::readCpuLoad()
+{
+ return 0.0;
+}
+
+bool ProcessReader::readMemory()
+{
+ struct task_basic_info t_info;
+ mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
+
+ if (KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count)) {
+ qCWarning(LogSystem) << "Could not read memory data";
+ return false;
+ }
+
+ totalRss.store(t_info.resident_size);
+ totalVm.store(t_info.virtual_size);
+
+ return true;
+}
+
+#else
+
+void ProcessReader::openCpuLoad()
+{
+}
+
+qreal ProcessReader::readCpuLoad()
+{
+ return 0.0;
+}
+
+bool ProcessReader::readMemory()
+{
+ return false;
+}
+
+#endif
diff --git a/src/monitor-lib/processreader.h b/src/monitor-lib/processreader.h
new file mode 100644
index 00000000..31b2f2f4
--- /dev/null
+++ b/src/monitor-lib/processreader.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QAtomicInteger>
+#include <QElapsedTimer>
+#include <QObject>
+
+#include <QtAppManCommon/global.h>
+
+#if defined(Q_OS_LINUX)
+# include <QScopedPointer>
+# include <QtAppManManager/sysfsreader.h>
+#endif
+
+QT_BEGIN_NAMESPACE_AM
+
+class ProcessReader : public QObject {
+ Q_OBJECT
+public slots:
+ void update();
+ void setProcessId(qint64 pid);
+
+signals:
+ void updated();
+
+public:
+ QAtomicInteger<quint32> cpuLoad;
+
+ QAtomicInteger<quint32> totalVm;
+ QAtomicInteger<quint32> totalRss;
+ QAtomicInteger<quint32> totalPss;
+ QAtomicInteger<quint32> textVm;
+ QAtomicInteger<quint32> textRss;
+ QAtomicInteger<quint32> textPss;
+ QAtomicInteger<quint32> heapVm;
+ QAtomicInteger<quint32> heapRss;
+ QAtomicInteger<quint32> heapPss;
+
+#if defined(Q_OS_LINUX)
+ // it's public solely for testing purposes
+ bool readSmaps(const QByteArray &smapsFile);
+#endif
+
+private:
+ void openCpuLoad();
+ qreal readCpuLoad();
+ bool readMemory();
+
+#if defined(Q_OS_LINUX)
+ QScopedPointer<SysFsReader> m_statReader;
+#endif
+ QElapsedTimer m_elapsedTime;
+ quint64 m_lastCpuUsage = 0.0;
+
+ qint64 m_pid = 0;
+};
+
+QT_END_NAMESPACE_AM
diff --git a/src/monitor-lib/processstatus.cpp b/src/monitor-lib/processstatus.cpp
new file mode 100644
index 00000000..47296657
--- /dev/null
+++ b/src/monitor-lib/processstatus.cpp
@@ -0,0 +1,329 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include "processstatus.h"
+
+#include <QCoreApplication>
+#include <QtQml/qqmlinfo.h>
+
+
+#include "abstractruntime.h"
+#include "applicationmanager.h"
+#include "logging.h"
+
+#include <limits>
+
+/*!
+ \qmltype ProcessStatus
+ \inqmlmodule QtApplicationManager.SystemUI
+ \ingroup system-ui
+ \brief Provides information on the status of an application process.
+
+ ProcessStatus provides information about the process of a given application.
+
+ You can use it alongside a Timer for instance to periodically query the status of an
+ application process.
+
+ \qml
+ import QtQuick 2.11
+ import QtApplicationManager 1.0
+ import QtApplicationManager.SystemUI 1.0
+
+ Item {
+ id: root
+ property var application: ApplicationManager.get(0)
+ ...
+ ProcessStatus {
+ id: processStatus
+ applicationId: root.application.id
+ }
+ Timer {
+ interval: 1000
+ running: root.visible && root.application.runState === Am.Running
+ repeat: true
+ onTriggered: processStatus.update()
+ }
+ Text {
+ text: "PSS.total: " + (processStatus.memoryPss.total / 1e6).toFixed(0) + " MB"
+ }
+ }
+ \endqml
+
+ You can also use this component as a MonitorModel data source if you want to plot its
+ previous values over time:
+
+ \qml
+ import QtQuick 2.11
+ import QtApplicationManager 1.0
+ import QtApplicationManager.SystemUI 1.0
+ ...
+ MonitorModel {
+ running: true
+ ProcessStatus {
+ applicationId: "some.app.id"
+ }
+ }
+ \endqml
+
+ These are the supported keys in the memory properties (\c memoryVirtual, \c memoryRss and \c memoryPss):
+
+ \table
+ \header
+ \li Key
+ \li Description
+ \row
+ \li \c total
+ \li The amount of memory used in total in bytes.
+ \row
+ \li \c text
+ \li The amount of memory used by the code section in bytes.
+ \row
+ \li \c heap
+ \li The amount of memory used by the heap in bytes. This is private, dynamically allocated
+ memory (for example through \c malloc or \c mmap on Linux).
+ \endtable
+*/
+
+QT_USE_NAMESPACE_AM
+
+QThread *ProcessStatus::m_workerThread = nullptr;
+
+ProcessStatus::ProcessStatus(QObject *parent)
+ : QObject(parent)
+{
+ if (!m_workerThread) {
+ m_workerThread = new QThread;
+ m_workerThread->start();
+ }
+
+ m_reader.reset(new ProcessReader);
+ connect(m_reader.data(), &ProcessReader::updated, this, [this]() {
+ emit cpuLoadChanged();
+ fetchMemoryReadings();
+ m_pendingUpdate = false;
+ });
+ connect(this, &ProcessStatus::processIdChanged, m_reader.data(), &ProcessReader::setProcessId);
+}
+
+/*!
+ \qmlmethod ProcessStatus::update
+
+ Updates the properties cpuLoad, memoryVirtual, memoryRss and memoryPss.
+*/
+void ProcessStatus::update()
+{
+ if (!m_pendingUpdate) {
+ m_pendingUpdate = true;
+ QMetaObject::invokeMethod(m_reader.data(), &ProcessReader::update);
+ }
+}
+
+/*!
+ \qmlproperty string ProcessStatus::applicationId
+
+ \l{ApplicationObject::id}{Id} of the \l{ApplicationObject}{application} whose process is to
+ be monitored.
+
+ \sa ApplicationObject
+*/
+QString ProcessStatus::applicationId() const
+{
+ return m_appId;
+}
+
+void ProcessStatus::setApplicationId(const QString &appId)
+{
+ if (m_appId != appId || m_appId.isNull()) {
+ if (m_application) {
+ disconnect(m_application, nullptr, this, nullptr);
+ m_application = nullptr;
+ }
+ m_appId = appId;
+ if (!appId.isEmpty()) {
+ int appIndex = ApplicationManager::instance()->indexOfApplication(appId);
+ if (appIndex < 0) {
+ qmlWarning(this) << "Invalid application ID:" << appId;
+ } else {
+ m_application = ApplicationManager::instance()->application(appIndex);
+ connect(m_application, &AbstractApplication::runStateChanged, this, &ProcessStatus::onRunStateChanged);
+ }
+ }
+ determinePid();
+ emit applicationIdChanged(appId);
+ }
+}
+
+void ProcessStatus::onRunStateChanged(Am::RunState state)
+{
+ if (state == Am::Running || state == Am::NotRunning)
+ determinePid();
+}
+
+void ProcessStatus::determinePid()
+{
+ qint64 newId;
+ if (m_appId.isEmpty()) {
+ newId = QCoreApplication::applicationPid();
+ } else {
+ Q_ASSERT(m_application);
+ if (ApplicationManager::instance()->isSingleProcess())
+ newId = 0;
+ else
+ newId = m_application->currentRuntime() ? m_application->currentRuntime()->applicationProcessId() : 0;
+ }
+
+ if (newId != m_pid) {
+ m_pid = newId;
+ emit processIdChanged(m_pid);
+ }
+}
+
+/*!
+ \qmlproperty int ProcessStatus::processId
+ \readonly
+
+ This property holds the OS specific process identifier (PID) that is monitored. This can be
+ used by external tools for example. The property is 0, if there is no process associated with
+ the \l applicationId. In particular, if the application-manager runs in single-process mode,
+ only the System-UI (identified by an empty \l applicationId) will have an associated process.
+*/
+qint64 ProcessStatus::processId() const
+{
+ return m_pid;
+}
+
+/*!
+ \qmlproperty real ProcessStatus::cpuLoad
+ \readonly
+
+ The process's CPU utilization when update() was last called. A value of 0 means
+ that the process was idle, a value of 1 means it fully used the equivalent of one core
+ (which may be split over several ones).
+
+ \sa ProcessStatus::update
+*/
+qreal ProcessStatus::cpuLoad()
+{
+ quint32 value = m_reader->cpuLoad.load();
+ return ((qreal)value) / ((qreal)std::numeric_limits<quint32>::max());
+}
+
+void ProcessStatus::fetchMemoryReadings()
+{
+ // Although smaps claims to report kB it's actually KiB (2^10 = 1024 Bytes)
+ m_memoryVirtual[qSL("total")] = quint64(m_reader->totalVm.load()) << 10;
+ m_memoryVirtual[qSL("text")] = quint64(m_reader->textVm.load()) << 10;
+ m_memoryVirtual[qSL("heap")] = quint64(m_reader->heapVm.load()) << 10;
+ m_memoryRss[qSL("total")] = quint64(m_reader->totalRss.load()) << 10;
+ m_memoryRss[qSL("text")] = quint64(m_reader->textRss.load()) << 10;
+ m_memoryRss[qSL("heap")] = quint64(m_reader->heapRss.load()) << 10;
+ m_memoryPss[qSL("total")] = quint64(m_reader->totalPss.load()) << 10;
+ m_memoryPss[qSL("text")] = quint64(m_reader->textPss.load()) << 10;
+ m_memoryPss[qSL("heap")] = quint64(m_reader->heapPss.load()) << 10;
+
+ emit memoryReportingChanged(m_memoryVirtual, m_memoryRss, m_memoryPss);
+}
+
+/*!
+ \qmlproperty var ProcessStatus::memoryVirtual
+ \readonly
+
+ A map of the process's virtual memory usage. See ProcessStatus description for a list of supported keys.
+ The total amount of virtual memory is provided through \c memoryVirtual.total for
+ example.
+
+ The value of this property is updated when ProcessStatus::update is called.
+
+ \sa ProcessStatus::update
+*/
+QVariantMap ProcessStatus::memoryVirtual() const
+{
+ return m_memoryVirtual;
+}
+
+/*!
+ \qmlproperty var ProcessStatus::memoryRss
+ \readonly
+
+ A map of the process's RSS (Resident Set Size) memory usage. This is the amount of memory that is
+ actually mapped to physical RAM. See ProcessStatus description for a list of supported keys.
+
+ The value of this property is updated when ProcessStatus::update is called.
+
+ \sa ProcessStatus::update
+*/
+QVariantMap ProcessStatus::memoryRss() const
+{
+ return m_memoryRss;
+}
+
+/*!
+ \qmlproperty var ProcessStatus::memoryPss
+ \readonly
+
+ A map of the process's PSS (Proportional Set Size) memory usage. This is the
+ proportional share of the RSS value above. For instance if two processes share 2 MB
+ the RSS value will be 2 MB for each process and the PSS value 1 MB for each process.
+ As the name implies, the code section of shared libraries is generally shared between
+ processes. Memory may also be shared by other means provided by the OS (e.g. through
+ \c mmap on Linux). See ProcessStatus description for a list of supported keys.
+
+ The value of this property is updated when ProcessStatus::update is called.
+
+ \sa ProcessStatus::update
+*/
+QVariantMap ProcessStatus::memoryPss() const
+{
+ return m_memoryPss;
+}
+
+/*!
+ \qmlproperty list<string> ProcessStatus::roleNames
+ \readonly
+
+ Names of the roles provided by ProcessStatus when used as a MonitorModel data source.
+
+ \sa MonitorModel
+*/
+QStringList ProcessStatus::roleNames() const
+{
+ return { qSL("cpuLoad"), qSL("memoryVirtual"), qSL("memoryRss"), qSL("memoryPss") };
+}
diff --git a/src/monitor-lib/processmonitor.h b/src/monitor-lib/processstatus.h
index 1123d870..a204b942 100644
--- a/src/monitor-lib/processmonitor.h
+++ b/src/monitor-lib/processstatus.h
@@ -41,90 +41,73 @@
#pragma once
-#include <QAbstractListModel>
-#include <QString>
-#include <QByteArray>
+#include <QAtomicInteger>
+#include <QObject>
+#include <QPointer>
+#include <QThread>
#include <QVariant>
-#include <QHash>
+
#include <QtAppManCommon/global.h>
+#include <QtAppManManager/amnamespace.h>
+#include <QtAppManManager/application.h>
+#include <QtAppManMonitor/processreader.h>
QT_BEGIN_NAMESPACE_AM
-class ProcessMonitorPrivate;
-
-class ProcessMonitor : public QAbstractListModel
+// It's assumed that all ProcessStatus instances are created from the same thread (most likely the main one).
+class ProcessStatus : public QObject
{
Q_OBJECT
- Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged)
- Q_PROPERTY(qint64 processId READ processId NOTIFY processIdChanged)
Q_PROPERTY(QString applicationId READ applicationId WRITE setApplicationId NOTIFY applicationIdChanged)
- Q_PROPERTY(int reportingInterval READ reportingInterval WRITE setReportingInterval NOTIFY reportingIntervalChanged)
- Q_PROPERTY(bool memoryReportingEnabled READ isMemoryReportingEnabled WRITE setMemoryReportingEnabled NOTIFY memoryReportingEnabledChanged)
+ Q_PROPERTY(qint64 processId READ processId NOTIFY processIdChanged)
+ Q_PROPERTY(qreal cpuLoad READ cpuLoad NOTIFY cpuLoadChanged)
Q_PROPERTY(QVariantMap memoryVirtual READ memoryVirtual NOTIFY memoryReportingChanged)
Q_PROPERTY(QVariantMap memoryRss READ memoryRss NOTIFY memoryReportingChanged)
Q_PROPERTY(QVariantMap memoryPss READ memoryPss NOTIFY memoryReportingChanged)
- Q_PROPERTY(bool cpuLoadReportingEnabled READ isCpuLoadReportingEnabled WRITE setCpuLoadReportingEnabled NOTIFY cpuLoadReportingEnabledChanged)
- Q_PROPERTY(qreal cpuLoad READ cpuLoad NOTIFY cpuLoadReportingChanged)
- Q_PROPERTY(bool frameRateReportingEnabled READ isFrameRateReportingEnabled WRITE setFrameRateReportingEnabled NOTIFY frameRateReportingEnabledChanged)
- Q_PROPERTY(QList<QObject *> monitoredWindows READ monitoredWindows WRITE setMonitoredWindows NOTIFY monitoredWindowsChanged)
-
+ Q_PROPERTY(QStringList roleNames READ roleNames CONSTANT)
public:
- ProcessMonitor(QObject *parent = nullptr);
- ~ProcessMonitor() override;
+ ProcessStatus(QObject *parent = nullptr);
- Q_INVOKABLE QVariantMap get(int index) const;
+ QStringList roleNames() const;
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- QVariant data(const QModelIndex &index, int role) const override;
- QHash<int, QByteArray> roleNames() const override;
-
- void setCount(int count);
- int count() const;
+ Q_INVOKABLE void update();
qint64 processId() const;
QString applicationId() const;
void setApplicationId(const QString &appId);
- void setReportingInterval(int intervalInMSec);
- int reportingInterval() const;
-
- bool isMemoryReportingEnabled() const;
- void setMemoryReportingEnabled(bool enabled);
-
- bool isCpuLoadReportingEnabled() const;
- void setCpuLoadReportingEnabled(bool enabled);
-
- bool isFrameRateReportingEnabled() const;
- void setFrameRateReportingEnabled(bool enabled);
-
- QList<QObject *> monitoredWindows() const;
- void setMonitoredWindows(QList<QObject *> windows);
-
- qreal cpuLoad() const;
+ qreal cpuLoad();
QVariantMap memoryVirtual() const;
QVariantMap memoryRss() const;
QVariantMap memoryPss() const;
signals:
- void countChanged(int count);
- void processIdChanged(qint64 processId);
void applicationIdChanged(const QString &applicationId);
- void reportingIntervalChanged(int reportingInterval);
-
- void memoryReportingEnabledChanged();
- void cpuLoadReportingEnabledChanged();
- void frameRateReportingEnabledChanged();
-
+ void processIdChanged(qint64 processId);
+ void cpuLoadChanged();
void memoryReportingChanged(const QVariantMap &memoryVirtual, const QVariantMap &memoryRss,
const QVariantMap &memoryPss);
- void cpuLoadReportingChanged(qreal load);
- void frameRateReportingChanged(QVariantList frameRate);
- void monitoredWindowsChanged();
+
+private slots:
+ void onRunStateChanged(Am::RunState state);
private:
- ProcessMonitorPrivate *d_ptr;
- Q_DECLARE_PRIVATE(ProcessMonitor)
+ void fetchMemoryReadings();
+ void determinePid();
+
+ QString m_appId;
+ qint64 m_pid = 0;
+
+ QVariantMap m_memoryVirtual;
+ QVariantMap m_memoryRss;
+ QVariantMap m_memoryPss;
+
+ QPointer<AbstractApplication> m_application;
+
+ bool m_pendingUpdate = false;
+ QScopedPointer<ProcessReader> m_reader;
+ static QThread *m_workerThread;
};
QT_END_NAMESPACE_AM
diff --git a/src/monitor-lib/systemmonitor.cpp b/src/monitor-lib/systemmonitor.cpp
deleted file mode 100644
index b2d695f4..00000000
--- a/src/monitor-lib/systemmonitor.cpp
+++ /dev/null
@@ -1,968 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Pelagicore Application Manager.
-**
-** $QT_BEGIN_LICENSE:LGPL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite licenses may use
-** this file in accordance with the commercial license agreement provided
-** with the Software or, alternatively, in accordance with the terms
-** contained in a written agreement between you and The Qt Company. For
-** licensing terms and conditions see https://www.qt.io/terms-conditions.
-** For further information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: LGPL-3.0
-**
-****************************************************************************/
-
-#include <QSysInfo>
-#include <QThread>
-#include <QFile>
-#include <QTimerEvent>
-#include <QElapsedTimer>
-#include <vector>
-#include <QtQml/qqmlinfo.h>
-#if !defined(AM_HEADLESS)
-# include <QGuiApplication>
-# include <QQuickView>
-#endif
-
-#include "global.h"
-#include "logging.h"
-#include "qml-utilities.h"
-#include "applicationmanager.h"
-#include "systemmonitor.h"
-#include "systemmonitor_p.h"
-#include <QtAppManWindow/windowmanager.h>
-
-
-/*!
- \qmltype SystemMonitor
- \inqmlmodule QtApplicationManager.SystemUI
- \ingroup system-ui
- \brief The system monitoring model, giving access to a range of measurements, e.g. CPU load,
- frame rate, etc.
-
- The SystemMonitor component provides information about system resources and performance,
- like CPU and memory usage, I/O load and frame rate.
-
- It's derived from \c QAbstractListModel, so it can be used directly as a model in an
- appropriate view.
-
- \target role names
-
- The following roles are available in this model:
-
- \table
- \header
- \li Role name
- \li Type
- \li Description
- \row
- \li \c cpuLoad
- \li real
- \li The current CPU utilization in the range 0 (completely idle) to 1 (fully busy).
- \row
- \li \c gpuLoad
- \li real
- \li The current GPU utilization in the range 0 (completely idle) to 1 (fully busy).
- This is dependent on tools from the graphics hardware vendor and might not work on
- every system.
- \row
- \li \c memoryUsed
- \li int
- \li The amount of physical system memory used in bytes.
- \row
- \li \c ioLoad
- \li var
- \li A map of devices registered with \l addIoLoadReporting() and their I/O load in the
- range [0, 1]. For instance the load of a registered device "sda" can be accessed
- through \c ioLoad.sda.
- \row
- \li \c averageFps
- \li real
- \li The average frame rate during the last \l reportingInterval in frames per second.
- \row
- \li \c minimumFps
- \li real
- \li The minimum frame rate during the last \l reportingInterval in frames per second.
- \row
- \li \c maximumFps
- \li real
- \li The maximum frame rate during the last \l reportingInterval in frames per second.
- \row
- \li \c fpsJitter
- \li real
- \li A measure for the average deviation from the ideal frame rate of 60 fps during the last
- \l reportingInterval.
- \endtable
-
- \note The model will be updated each \l reportingInterval milliseconds. The roles will only
- be populated, if the corresponding reporting parts (memory, CPU, etc.) have been enabled.
-
- After importing \c QtApplicationManager.SystemUI you could use the SystemMonitor component as follows:
-
- \qml
- import QtQuick 2.4
- import QtApplicationManager.SystemUI 1.0
-
- ListView {
- id: view
- width: 200; height: 200
-
- model: SystemMonitor {
- fpsReportingInterval: 1000
- fpsReportingEnabled: view.visible
- }
-
- delegate: Text { text: averageFps }
- }
- \endqml
-*/
-
-/*!
- \qmlproperty int SystemMonitor::count
-
- This property holds the number of reading points that will be kept in the model. The minimum
- value that can be set is 2 and the default value is 10.
-*/
-
-/*!
- \qmlproperty int SystemMonitor::reportingInterval
-
- This property holds the interval in milliseconds between reporting updates. Note, that
- reporting will only start once this property is set. Setting a new value will reset the model.
- Valid values must be greater than zero.
-
- At least one of the reporting parts (memory, CPU load etc.) must be enabled, respectively
- registered to start the reporting.
-*/
-
-/*!
- \qmlproperty real SystemMonitor::idleLoadThreshold
-
- A value in the range [0, 1]. If the CPU load is greater than this threshold the \l idle
- property will be \c false, otherwise \c true. This property also influences when the
- application manager quick-launches application processes.
-
- The default value is read from the \l {Configuration}{configuration YAML file}
- (\c quicklaunch/idleLoad), respectively 0.1, if this configuration option is not provided.
-
- \sa idle
-*/
-
-/*!
- \qmlproperty int SystemMonitor::totalMemory
- \readonly
-
- This property holds the total amount of physical memory (RAM) installed on the system in bytes.
-*/
-
-/*!
- \qmlproperty int SystemMonitor::memoryUsed
- \readonly
-
- This property holds the amount of physical memory (RAM) used in bytes.
-*/
-
-/*!
- \qmlproperty int SystemMonitor::cpuCores
- \readonly
-
- This property holds the number of physical CPU cores that are installed on the system.
-*/
-
-/*!
- \qmlproperty int SystemMonitor::cpuLoad
- \readonly
-
- This property holds the current CPU utilization as a value ranging from 0 (inclusive, completely
- idle) to 1 (inclusive, fully busy).
-*/
-
-/*!
- \qmlproperty int SystemMonitor::gpuLoad
- \readonly
-
- This property holds the current GPU utilization as a value ranging from 0 (inclusive, completely
- idle) to 1 (inclusive, fully busy).
-
- \note This is dependent on tools from the graphics hardware vendor and might not work on
- every system.
-
- Currently, this only works on \e Linux with either \e Intel or \e NVIDIA chipsets, plus the
- tools from the respective vendors have to be installed:
-
- \table
- \header
- \li Hardware
- \li Tool
- \li Notes
- \row
- \li NVIDIA
- \li \c nvidia-smi
- \li The utilization will only be shown for the first GPU of the system, in case multiple GPUs
- are installed.
- \row
- \li Intel
- \li \c intel_gpu_top
- \li The binary has to be made set-UID root, e.g. via \c{sudo chmod +s $(which intel_gpu_top)},
- or the application-manager has to be run as the \c root user.
- \endtable
-*/
-
-/*!
- \qmlproperty bool SystemMonitor::memoryReportingEnabled
-
- A boolean value that determines whether periodic memory reporting is enabled.
-*/
-
-/*!
- \qmlproperty bool SystemMonitor::cpuLoadReportingEnabled
-
- A boolean value that determines whether periodic CPU load reporting is enabled.
-*/
-
-/*!
- \qmlproperty bool SystemMonitor::gpuLoadReportingEnabled
-
- A boolean value that determines whether periodic GPU load reporting is enabled.
-
- GPU load reporting is only supported on selected hardware: please see gpuLoad for more
- information.
-*/
-
-/*!
- \qmlproperty bool SystemMonitor::fpsReportingEnabled
-
- A boolean value that determines whether periodic frame rate reporting is enabled.
-*/
-
-/*!
- \qmlproperty bool SystemMonitor::idle
- \readonly
-
- A boolean value that defines, whether the system is idle. If the CPU load is greater than
- \l idleLoadThreshold, this property will be set to \c false, otherwise to \c true. The value is
- evaluated every second and reflects whether the average load during the last second was below
- or above the threshold.
-
- \sa idleLoadThreshold
-*/
-
-
-/*!
- \qmlsignal SystemMonitor::memoryReportingChanged(int used);
-
- This signal is emitted periodically when memory reporting is enabled. The frequency is defined
- by \l reportingInterval. The \a used physical system memory in bytes is provided as argument.
-
- \sa memoryReportingEnabled
- \sa reportingInterval
-*/
-
-/*!
- \qmlsignal SystemMonitor::cpuLoadReportingChanged(real load)
-
- This signal is emitted periodically when CPU load reporting is enabled. The frequency is
- defined by \l reportingInterval. The \a load parameter indicates the CPU utilization in the
- range 0 (completely idle) to 1 (fully busy).
-
- \sa cpuLoadReportingEnabled
- \sa reportingInterval
-*/
-
-/*!
- \qmlsignal SystemMonitor::gpuLoadReportingChanged(real load)
-
- This signal is emitted periodically when GPU load reporting is enabled. The frequency is
- defined by \l reportingInterval. The \a load parameter indicates the GPU utilization in the
- range 0 (completely idle) to 1 (fully busy).
-
- \sa gpuLoadReportingEnabled
- \sa reportingInterval
-*/
-
-/*!
- \qmlsignal SystemMonitor::ioLoadReportingChanged(string device, real load);
-
- This signal is emitted periodically for each I/O device that has been registered with
- \l addIoLoadReporting. The frequency is defined by \l reportingInterval. The string \a device
- holds the name of the device that is monitored. The \a load parameter indicates the
- utilization of the \a device in the range 0 (completely idle) to 1 (fully busy).
-
- \sa addIoLoadReporting
- \sa removeIoLoadReporting
- \sa ioLoadReportingDevices
- \sa reportingInterval
-*/
-
-/*!
- \qmlsignal SystemMonitor::fpsReportingChanged(real average, real minimum, real maximum, real jitter);
-
- This signal is emitted periodically when frame rate reporting is enabled. The update frequency
- is defined by \l reportingInterval. The arguments denote the \a average, \a minimum and
- \a maximum frame rate during the last \l reportingInterval in frames per second. Additionally,
- \a jitter is a measure for the average deviation from the ideal frame rate of 60 fps.
-*/
-
-
-QT_BEGIN_NAMESPACE_AM
-
-namespace {
-enum Roles
-{
- CpuLoad = Qt::UserRole + 5000,
- MemoryUsed,
- IoLoad,
- GpuLoad,
-
- AverageFps = Qt::UserRole + 6000,
- MinimumFps,
- MaximumFps,
- FpsJitter
-};
-}
-
-
-
-int SystemMonitorPrivate::latestReportPos() const
-{
- if (reportPos == 0)
- return reports.size() - 1;
- else
- return reportPos - 1;
-}
-
-#if !defined(AM_HEADLESS)
-void SystemMonitorPrivate::registerNewView(QQuickWindow *view)
-{
- Q_Q(SystemMonitor);
- if (reportFps)
- connect(view, &QQuickWindow::frameSwapped, q, &SystemMonitor::reportFrameSwap);
-}
-#endif
-
-void SystemMonitorPrivate::setupFpsReporting()
-{
-#if !defined(AM_HEADLESS)
- Q_Q(SystemMonitor);
- if (!windowManagerConnectionCreated) {
- connect(WindowManager::instance(), &WindowManager::compositorViewRegistered, this, &SystemMonitorPrivate::registerNewView);
- windowManagerConnectionCreated = true;
- }
-
- for (const QQuickWindow *view : WindowManager::instance()->compositorViews()) {
- if (reportFps)
- connect(view, &QQuickWindow::frameSwapped, q, &SystemMonitor::reportFrameSwap);
- else
- disconnect(view, &QQuickWindow::frameSwapped, q, &SystemMonitor::reportFrameSwap);
- }
-#endif
-}
-
-void SystemMonitorPrivate::setupTimer()
-{
- bool shouldBeOn = reportCpu || reportGpu || reportMem || reportFps || !ioHash.isEmpty();
-
- if (!shouldBeOn && reportingTimerId) {
- killTimer(reportingTimerId);
- reportingTimerId = 0;
- } else if (shouldBeOn && !reportingTimerId) {
- updateModel(true /* clear */);
- reportingTimerId = startTimer(reportingInterval);
- }
-}
-
-void SystemMonitorPrivate::makeNewReport()
-{
- Q_Q(SystemMonitor);
-
- Report r;
- QVector<int> changedRoles;
- {
- const Report &currentReport = reports.at(reportPos);
-
- if (reportCpu)
- r.cpuLoad = cpu->readLoadValue();
- if (currentReport.cpuLoad != r.cpuLoad)
- changedRoles.append(CpuLoad);
-
- if (reportGpu)
- r.gpuLoad = gpu->readLoadValue();
- if (currentReport.gpuLoad != r.gpuLoad)
- changedRoles.append(GpuLoad);
-
- if (reportMem)
- r.memoryUsed = memory->readUsedValue();
- if (currentReport.memoryUsed != r.memoryUsed)
- changedRoles.append(MemoryUsed);
-
- for (auto it = ioHash.cbegin(); it != ioHash.cend(); ++it) {
- qreal ioVal = it.value()->readLoadValue();
- emit q->ioLoadReportingChanged(it.key(), ioVal);
- r.ioLoad.insert(it.key(), ioVal);
- }
- if (currentReport.ioLoad != r.ioLoad)
- changedRoles.append(IoLoad);
-
- if (reportFps) {
- if (FrameTimer *ft = frameTimer.value(nullptr)) {
- r.fpsAvg = ft->averageFps();
- r.fpsMin = ft->minimumFps();
- r.fpsMax = ft->maximumFps();
- r.fpsJitter = ft->jitterFps();
- ft->reset();
- emit q->fpsReportingChanged(r.fpsAvg, r.fpsMin, r.fpsMax, r.fpsJitter);
- }
- }
- if (currentReport.fpsAvg != r.fpsAvg)
- changedRoles.append(AverageFps);
- if (currentReport.fpsMin != r.fpsMin)
- changedRoles.append(MinimumFps);
- if (currentReport.fpsMax != r.fpsMax)
- changedRoles.append(MaximumFps);
- if (currentReport.fpsJitter != r.fpsJitter)
- changedRoles.append(FpsJitter);
- }
-
- // ring buffer handling
- // optimization: instead of sending a dataChanged for every item, we always move the
- // last item to the front and change its data only
- int last = reports.size() - 1;
- q->beginMoveRows(QModelIndex(), last, last, QModelIndex(), 0);
- reports[reportPos++] = r;
- if (reportPos > last)
- reportPos = 0;
- q->endMoveRows();
- q->dataChanged(q->index(0), q->index(0), changedRoles);
-
- if (reportMem)
- emit q->memoryReportingChanged(r.memoryUsed);
- if (reportCpu)
- emit q->cpuLoadReportingChanged(r.cpuLoad);
- if (reportGpu)
- emit q->gpuLoadReportingChanged(r.gpuLoad);
-}
-
-void SystemMonitorPrivate::timerEvent(QTimerEvent *te)
-{
- Q_Q(SystemMonitor);
-
- if (te && te->timerId() == reportingTimerId) {
- makeNewReport();
- } else if (te && te->timerId() == idleTimerId) {
- qreal idleVal = idleCpu->readLoadValue();
- bool nowIdle = (idleVal <= idleThreshold);
- if (nowIdle != isIdle) {
- isIdle = nowIdle;
- emit q->idleChanged(nowIdle);
- }
- }
-}
-
-auto SystemMonitorPrivate::reportForRow(int row) const -> const Report &
-{
- // convert a visual row position to an index into the internal ringbuffer
- int pos = reportPos - row - 1;
- if (pos < 0)
- pos += reports.size();
- if (pos < 0 || pos >= reports.size())
- return reports.first();
- return reports.at(pos);
-}
-
-void SystemMonitorPrivate::updateModel(bool clear)
-{
- Q_Q(SystemMonitor);
-
- q->beginResetModel();
-
- if (clear) {
- reports.clear();
- reports.resize(count);
- reportPos = 0;
- } else {
- int oldCount = reports.size();
- int diff = count - oldCount;
- if (diff > 0)
- reports.insert(reportPos, diff, Report());
- else {
- if (reportPos <= count) {
- reports.remove(reportPos, -diff);
- if (reportPos == count)
- reportPos = 0;
- } else {
- reports.remove(reportPos, oldCount - reportPos);
- reports.remove(0, reportPos - count);
- reportPos = 0;
- }
- }
- }
- q->endResetModel();
-}
-
-SystemMonitor::SystemMonitor()
- : d_ptr(new SystemMonitorPrivate(this))
-{
- Q_D(SystemMonitor);
-
- d->idleCpu = new CpuReader;
- d->cpu = new CpuReader;
- d->gpu = new GpuReader;
-
-#if defined(Q_OS_LINUX)
- QMap<QByteArray, QByteArray> cgroupInfo = fetchCGroupProcessInfo(QCoreApplication::applicationPid());
- d->memory = new MemoryReader(QString::fromLatin1(cgroupInfo["memory"]));
-#else
- d->memory = new MemoryReader;
-#endif
-
- d->idleTimerId = d->startTimer(1000);
-
- d->roleNames.insert(CpuLoad, "cpuLoad");
- d->roleNames.insert(GpuLoad, "gpuLoad");
- d->roleNames.insert(MemoryUsed, "memoryUsed");
- d->roleNames.insert(IoLoad, "ioLoad");
- d->roleNames.insert(AverageFps, "averageFps");
- d->roleNames.insert(MinimumFps, "minimumFps");
- d->roleNames.insert(MaximumFps, "maximumFps");
- d->roleNames.insert(FpsJitter, "fpsJitter");
-
- d->updateModel(true);
-}
-
-SystemMonitor::~SystemMonitor()
-{
- Q_D(SystemMonitor);
-
- delete d->idleCpu;
- delete d->memory;
- delete d->cpu;
- delete d->gpu;
- qDeleteAll(d->ioHash);
- delete d;
-}
-
-int SystemMonitor::rowCount(const QModelIndex &parent) const
-{
- Q_D(const SystemMonitor);
-
- if (parent.isValid())
- return 0;
- return d->reports.count();
-}
-
-QVariant SystemMonitor::data(const QModelIndex &index, int role) const
-{
- Q_D(const SystemMonitor);
-
- if (index.parent().isValid() || !index.isValid() || index.row() < 0 || index.row() >= d->reports.size())
- return QVariant();
-
- const SystemMonitorPrivate::Report &r = d->reportForRow(index.row());
-
- switch (role) {
- case CpuLoad:
- return r.cpuLoad;
- case GpuLoad:
- return r.gpuLoad;
- case MemoryUsed:
- return r.memoryUsed;
- case IoLoad:
- return r.ioLoad;
- case AverageFps:
- return r.fpsAvg;
- case MinimumFps:
- return r.fpsMin;
- case MaximumFps:
- return r.fpsMax;
- case FpsJitter:
- return r.fpsJitter;
- }
- return QVariant();
-}
-
-QHash<int, QByteArray> SystemMonitor::roleNames() const
-{
- Q_D(const SystemMonitor);
-
- return d->roleNames;
-}
-
-/*!
- \qmlmethod object SystemMonitor::get(int index)
-
- Returns the model data for the reading point identified by \a index as a JavaScript object.
- See the \l {role names} for the expected object elements. The \a index must be in the range
- [0, \l count), returns an empty object if it is invalid.
-*/
-QVariantMap SystemMonitor::get(int row) const
-{
- if (row < 0 || row >= count()) {
- qCWarning(LogSystem) << "invalid row:" << row;
- return QVariantMap();
- }
-
- QVariantMap map;
- QHash<int, QByteArray> roles = roleNames();
- for (auto it = roles.cbegin(); it != roles.cend(); ++it)
- map.insert(qL1S(it.value()), data(index(row), it.key()));
- return map;
-}
-
-
-quint64 SystemMonitor::totalMemory() const
-{
- Q_D(const SystemMonitor);
-
-#if defined(Q_OS_LINUX)
- auto limit = d->memory->groupLimit();
- if (limit > 0 && limit < d->memory->totalValue())
- return limit;
- else
- return d->memory->totalValue();
-#else
- return d->memory->totalValue();
-#endif
-}
-
-quint64 SystemMonitor::memoryUsed() const
-{
- Q_D(const SystemMonitor);
- return d->reports[d->latestReportPos()].memoryUsed;
-}
-
-int SystemMonitor::cpuCores() const
-{
- return QThread::idealThreadCount();
-}
-
-qreal SystemMonitor::cpuLoad() const
-{
- Q_D(const SystemMonitor);
- return d->reports[d->latestReportPos()].cpuLoad;
-}
-
-qreal SystemMonitor::gpuLoad() const
-{
- Q_D(const SystemMonitor);
- return d->reports[d->latestReportPos()].gpuLoad;
-}
-
-/*!
- \qmlmethod bool SystemMonitor::setMemoryWarningThresholds(real lowWarning, real criticalWarning);
-
- Activates monitoring of available system memory. The arguments must define percent values (in
- the range [0, 100]) of the \l totalMemory available. The \a lowWarning argument defines the
- threshold in percent, when applications get the \l ApplicationInterface::memoryLowWarning()
- signal. The \a criticalWarning argument defines the threshold, when applications get the
- \l ApplicationInterface::memoryCriticalWarning() signal.
-
- Returns true, if monitoring could be started, otherwise false (e.g. if arguments are out of
- range).
-
- \note This is only supported on Linux with the cgroups memory subsystem enabled.
-
- \sa totalMemory
- \sa ApplicationInterface::memoryLowWarning()
- \sa ApplicationInterface::memoryCriticalWarning()
-*/
-bool SystemMonitor::setMemoryWarningThresholds(qreal lowWarning, qreal criticalWarning)
-{
- Q_D(SystemMonitor);
-
- if (!qFuzzyCompare(lowWarning, d->memoryLowWarning) || !qFuzzyCompare(criticalWarning, d->memoryCriticalWarning)) {
- d->memoryLowWarning = lowWarning;
- d->memoryCriticalWarning = criticalWarning;
- if (!d->memoryWatcher) {
- d->memoryWatcher = new MemoryWatcher(this);
- connect(d->memoryWatcher, &MemoryWatcher::memoryLow,
- ApplicationManager::instance(), &ApplicationManager::memoryLowWarning);
- connect(d->memoryWatcher, &MemoryWatcher::memoryCritical,
- ApplicationManager::instance(), &ApplicationManager::memoryCriticalWarning);
- }
- d->memoryWatcher->setThresholds(lowWarning, criticalWarning);
- return d->memoryWatcher->startWatching();
- }
- return true;
-}
-
-/*!
- \qmlmethod real SystemMonitor::memoryLowWarningThreshold()
-
- Returns the current threshold in percent, when a low memory warning will be sent to
- applications.
-
- \sa setMemoryWarningThresholds()
-*/
-qreal SystemMonitor::memoryLowWarningThreshold() const
-{
- Q_D(const SystemMonitor);
-
- return d->memoryLowWarning;
-}
-
-/*!
- \qmlmethod real SystemMonitor::memoryCriticalWarningThreshold()
-
- Returns the current threshold in percent, when a critical memory warning will be sent to
- applications.
-
- \sa setMemoryWarningThresholds()
-*/
-qreal SystemMonitor::memoryCriticalWarningThreshold() const
-{
- Q_D(const SystemMonitor);
-
- return d->memoryCriticalWarning;
-}
-
-void SystemMonitor::setIdleLoadThreshold(qreal loadThreshold)
-{
- Q_D(SystemMonitor);
-
- if (!qFuzzyCompare(loadThreshold, d->idleThreshold)) {
- d->idleThreshold = loadThreshold;
- emit idleLoadThresholdChanged(loadThreshold);
- }
-}
-
-qreal SystemMonitor::idleLoadThreshold() const
-{
- Q_D(const SystemMonitor);
-
- return d->idleThreshold;
-}
-
-bool SystemMonitor::isIdle() const
-{
- Q_D(const SystemMonitor);
-
- return d->isIdle;
-}
-
-void SystemMonitor::setMemoryReportingEnabled(bool enabled)
-{
- Q_D(SystemMonitor);
-
- if (enabled != d->reportMem) {
- d->reportMem = enabled;
- d->setupTimer();
- emit memoryReportingEnabledChanged();
- }
-}
-
-bool SystemMonitor::isMemoryReportingEnabled() const
-{
- Q_D(const SystemMonitor);
-
- return d->reportMem;
-}
-
-void SystemMonitor::setCpuLoadReportingEnabled(bool enabled)
-{
- Q_D(SystemMonitor);
-
- if (enabled != d->reportCpu) {
- d->reportCpu = enabled;
- d->setupTimer();
- emit cpuLoadReportingEnabledChanged();
- }
-}
-
-bool SystemMonitor::isCpuLoadReportingEnabled() const
-{
- Q_D(const SystemMonitor);
-
- return d->reportCpu;
-}
-
-void SystemMonitor::setGpuLoadReportingEnabled(bool enabled)
-{
- Q_D(SystemMonitor);
-
- if (enabled != d->reportGpu) {
- d->reportGpu = enabled;
- d->setupTimer();
- d->gpu->setActive(enabled);
- emit gpuLoadReportingEnabledChanged();
- }
-}
-
-bool SystemMonitor::isGpuLoadReportingEnabled() const
-{
- Q_D(const SystemMonitor);
-
- return d->reportGpu;
-}
-
-/*!
- \qmlmethod bool SystemMonitor::addIoLoadReporting(string deviceName);
-
- Registers the device with the name \a deviceName for periodically reporting its I/O load.
-
- \note Currently this is only supported on Linux: the \a deviceName has to match one of the
- devices in the \c /sys/block directory.
-
- Returns true, if the device could be added, otherwise false (e.g. if it does not exist).
-*/
-bool SystemMonitor::addIoLoadReporting(const QString &deviceName)
-{
- Q_D(SystemMonitor);
-
- if (!QFile::exists(qSL("/dev/") + deviceName))
- return false;
- if (d->ioHash.contains(deviceName))
- return false;
-
- IoReader *ior = new IoReader(deviceName.toLocal8Bit().constData());
- d->ioHash.insert(deviceName, ior);
- if (d->reportingInterval >= 0)
- ior->readLoadValue(); // for initialization only
- d->setupTimer();
- return true;
-}
-
-/*!
- \qmlmethod SystemMonitor::removeIoLoadReporting(string deviceName);
-
- Remove the device with the name \a deviceName from the list of monitored devices.
-*/
-void SystemMonitor::removeIoLoadReporting(const QString &deviceName)
-{
- Q_D(SystemMonitor);
-
- delete d->ioHash.take(deviceName);
-}
-
-/*!
- \qmlmethod list<string> SystemMonitor::ioLoadReportingDevices()
-
- Returns a list of registered device names, that will report their I/O load.
-*/
-QStringList SystemMonitor::ioLoadReportingDevices() const
-{
- Q_D(const SystemMonitor);
-
- return d->ioHash.keys();
-}
-
-void SystemMonitor::setFpsReportingEnabled(bool enabled)
-{
- Q_D(SystemMonitor);
-
- if (enabled != d->reportFps) {
- d->reportFps = enabled;
- d->setupTimer();
- d->setupFpsReporting();
- emit fpsReportingEnabledChanged();
- }
-}
-
-bool SystemMonitor::isFpsReportingEnabled() const
-{
- Q_D(const SystemMonitor);
-
- return d->reportFps;
-}
-
-void SystemMonitor::setReportingInterval(int intervalInMSec)
-{
- Q_D(SystemMonitor);
- d->setReportingInterval(intervalInMSec);
-}
-
-void SystemMonitorPrivate::setReportingInterval(int intervalInMSec)
-{
- Q_Q(SystemMonitor);
-
- if (reportingInterval == intervalInMSec)
- return; // NOOP
-
- if (intervalInMSec <= 0) {
- qmlWarning(q) << "Cannot set a reportingInterval <= 0";
- return;
- }
-
- for (auto it = ioHash.cbegin(); it != ioHash.cend(); ++it)
- it.value()->readLoadValue(); // for initialization only
- updateModel(true);
- reportingInterval = intervalInMSec;
- if (reportingTimerId) {
- killTimer(reportingTimerId);
- reportingTimerId = 0;
- }
- setupTimer();
- emit q->reportingIntervalChanged(intervalInMSec);
-}
-
-int SystemMonitor::reportingInterval() const
-{
- Q_D(const SystemMonitor);
-
- return d->reportingInterval;
-}
-
-void SystemMonitor::setCount(int count)
-{
- Q_D(SystemMonitor);
-
- if (count != d->count) {
- d->count = count > 2 ? count : 2;
- d->updateModel(false);
- emit countChanged();
- }
-}
-
-int SystemMonitor::count() const
-{
- Q_D(const SystemMonitor);
-
- return d->count;
-}
-
-/*! \internal
- report a frame swap for any window. \a item is \c 0 for the System-UI
-*/
-void SystemMonitor::reportFrameSwap()
-{
- Q_D(SystemMonitor);
-
- if (!d->reportFps)
- return;
-
- FrameTimer *frameTimer = d->frameTimer.value(nullptr);
- if (!frameTimer) {
- frameTimer = new FrameTimer();
- d->frameTimer.insert(nullptr, frameTimer);
- }
-
- frameTimer->newFrame();
-}
-
-QT_END_NAMESPACE_AM
diff --git a/src/monitor-lib/systemmonitor.h b/src/monitor-lib/systemmonitor.h
deleted file mode 100644
index 67c5c7f4..00000000
--- a/src/monitor-lib/systemmonitor.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Pelagicore Application Manager.
-**
-** $QT_BEGIN_LICENSE:LGPL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite licenses may use
-** this file in accordance with the commercial license agreement provided
-** with the Software or, alternatively, in accordance with the terms
-** contained in a written agreement between you and The Qt Company. For
-** licensing terms and conditions see https://www.qt.io/terms-conditions.
-** For further information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: LGPL-3.0
-**
-****************************************************************************/
-
-#pragma once
-
-#include <QAbstractListModel>
-#include <QtAppManCommon/global.h>
-
-QT_FORWARD_DECLARE_CLASS(QQmlEngine)
-QT_FORWARD_DECLARE_CLASS(QJSEngine)
-
-QT_BEGIN_NAMESPACE_AM
-
-class SystemMonitorPrivate;
-class XProcessMonitor;
-
-class SystemMonitor : public QAbstractListModel
-{
- Q_OBJECT
- Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged)
- Q_PROPERTY(int reportingInterval READ reportingInterval WRITE setReportingInterval NOTIFY reportingIntervalChanged)
- Q_PROPERTY(qreal idleLoadThreshold READ idleLoadThreshold WRITE setIdleLoadThreshold NOTIFY idleLoadThresholdChanged)
- Q_PROPERTY(quint64 totalMemory READ totalMemory CONSTANT)
- Q_PROPERTY(quint64 memoryUsed READ memoryUsed NOTIFY memoryReportingChanged)
- Q_PROPERTY(int cpuCores READ cpuCores CONSTANT)
- Q_PROPERTY(qreal cpuLoad READ cpuLoad NOTIFY cpuLoadReportingChanged)
- Q_PROPERTY(qreal gpuLoad READ gpuLoad NOTIFY gpuLoadReportingChanged)
- Q_PROPERTY(bool memoryReportingEnabled READ isMemoryReportingEnabled WRITE setMemoryReportingEnabled NOTIFY memoryReportingEnabledChanged)
- Q_PROPERTY(bool cpuLoadReportingEnabled READ isCpuLoadReportingEnabled WRITE setCpuLoadReportingEnabled NOTIFY cpuLoadReportingEnabledChanged)
- Q_PROPERTY(bool gpuLoadReportingEnabled READ isGpuLoadReportingEnabled WRITE setGpuLoadReportingEnabled NOTIFY gpuLoadReportingEnabledChanged)
- Q_PROPERTY(bool fpsReportingEnabled READ isFpsReportingEnabled WRITE setFpsReportingEnabled NOTIFY fpsReportingEnabledChanged)
- Q_PROPERTY(bool idle READ isIdle NOTIFY idleChanged)
-
-public:
- SystemMonitor();
- ~SystemMonitor() override;
-
- // the item model part
- int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- QVariant data(const QModelIndex &index, int role) const override;
- QHash<int, QByteArray> roleNames() const override;
-
- void setCount(int count);
- int count() const;
-
- Q_INVOKABLE QVariantMap get(int index) const;
-
- quint64 totalMemory() const;
- quint64 memoryUsed() const;
- int cpuCores() const;
- qreal cpuLoad() const;
- qreal gpuLoad() const;
-
- void setIdleLoadThreshold(qreal loadThreshold);
- qreal idleLoadThreshold() const;
-
- bool isIdle() const;
-
- Q_INVOKABLE bool setMemoryWarningThresholds(qreal lowWarning, qreal criticalWarning);
- Q_INVOKABLE qreal memoryLowWarningThreshold() const;
- Q_INVOKABLE qreal memoryCriticalWarningThreshold() const;
-
- void setMemoryReportingEnabled(bool enabled);
- bool isMemoryReportingEnabled() const;
-
- void setCpuLoadReportingEnabled(bool enabled);
- bool isCpuLoadReportingEnabled() const;
-
- void setGpuLoadReportingEnabled(bool enabled);
- bool isGpuLoadReportingEnabled() const;
-
- Q_INVOKABLE bool addIoLoadReporting(const QString &deviceName);
- Q_INVOKABLE void removeIoLoadReporting(const QString &deviceName);
- Q_INVOKABLE QStringList ioLoadReportingDevices() const;
-
- void setFpsReportingEnabled(bool enabled);
- bool isFpsReportingEnabled() const;
-
- void setReportingInterval(int intervalInMSec);
- int reportingInterval() const;
-
- // semi-public API: used for the WindowManager to report FPS
- void reportFrameSwap();
-
-signals:
- void countChanged();
- void idleChanged(bool idle);
- void reportingIntervalChanged(int reportingInterval);
- void idleLoadThresholdChanged(qreal idleLoadThreshold);
-
- void memoryReportingChanged(quint64 used);
- void cpuLoadReportingChanged(qreal load);
- void gpuLoadReportingChanged(qreal load);
- void ioLoadReportingChanged(const QString &device, qreal load);
- void fpsReportingChanged(qreal average, qreal minimum, qreal maximum, qreal jitter);
-
- void memoryReportingEnabledChanged();
- void cpuLoadReportingEnabledChanged();
- void gpuLoadReportingEnabledChanged();
- void fpsReportingEnabledChanged();
-
-private:
- SystemMonitorPrivate *d_ptr;
- Q_DECLARE_PRIVATE(SystemMonitor)
-};
-
-QT_END_NAMESPACE_AM
diff --git a/src/src.pro b/src/src.pro
index 6c82b8e0..480a19ab 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -54,7 +54,7 @@ main_lib.depends = shared_main_lib manager_lib installer_lib window_lib monitor_
}
tools_launcher_qml.subdir = tools/launcher-qml
-tools_launcher_qml.depends = launcher_lib plugin_interfaces
+tools_launcher_qml.depends = launcher_lib plugin_interfaces monitor_lib
tools_appman.subdir = tools/appman
tools_appman.depends = main_lib
diff --git a/src/tools/launcher-qml/launcher-qml.cpp b/src/tools/launcher-qml/launcher-qml.cpp
index f71fe9c8..7fc88ac2 100644
--- a/src/tools/launcher-qml/launcher-qml.cpp
+++ b/src/tools/launcher-qml/launcher-qml.cpp
@@ -91,6 +91,14 @@
#include "qml-utilities.h"
#include "launcher-qml_p.h"
+// monitor-lib
+#include "cpustatus.h"
+#include "frametimer.h"
+#include "gpustatus.h"
+#include "iostatus.h"
+#include "memorystatus.h"
+#include "monitormodel.h"
+
QT_USE_NAMESPACE_AM
@@ -174,6 +182,14 @@ Controller::Controller(LauncherMain *a, bool quickLaunched, const QString &direc
qmlRegisterType<QmlNotification>("QtApplicationManager", 1, 0, "Notification");
qmlRegisterType<QmlApplicationInterfaceExtension>("QtApplicationManager.Application", 1, 0, "ApplicationInterfaceExtension");
+ // monitor-lib
+ qmlRegisterType<CpuStatus>("QtApplicationManager", 1, 0, "CpuStatus");
+ qmlRegisterType<FrameTimer>("QtApplicationManager", 1, 0, "FrameTimer");
+ qmlRegisterType<GpuStatus>("QtApplicationManager", 1, 0, "GpuStatus");
+ qmlRegisterType<IoStatus>("QtApplicationManager", 1, 0, "IoStatus");
+ qmlRegisterType<MemoryStatus>("QtApplicationManager", 1, 0, "MemoryStatus");
+ qmlRegisterType<MonitorModel>("QtApplicationManager", 1, 0, "MonitorModel");
+
m_configuration = a->runtimeConfiguration();
QString absolutePath;
diff --git a/src/tools/launcher-qml/launcher-qml.pro b/src/tools/launcher-qml/launcher-qml.pro
index 6053c5d8..dc246df2 100644
--- a/src/tools/launcher-qml/launcher-qml.pro
+++ b/src/tools/launcher-qml/launcher-qml.pro
@@ -7,6 +7,7 @@ QT = qml dbus core-private
!headless:QT += quick gui gui-private quick-private
QT *= \
appman_common-private \
+ appman_monitor-private \
appman_notification-private \
appman_application-private \
appman_plugininterfaces-private \
diff --git a/tests/manual/systemmonitor/PropertyField.qml b/tests/manual/monitormodel/PropertyField.qml
index cf1511f6..cf1511f6 100644
--- a/tests/manual/systemmonitor/PropertyField.qml
+++ b/tests/manual/monitormodel/PropertyField.qml
diff --git a/tests/manual/systemmonitor/README b/tests/manual/monitormodel/README
index 869b9538..8bc137f7 100644
--- a/tests/manual/systemmonitor/README
+++ b/tests/manual/monitormodel/README
@@ -1,4 +1,4 @@
-This is a playground for manually experimenting with the SystemMonitor component and seeing how it behaves.
+This is a playground for manually experimenting with the MonitorModel component and seeing how it behaves.
A good way to find bugs and doing some sanity checking.
TODO: It could probably later be used by qmlauto tests as a way to ensure it's always kept in a healthy state
diff --git a/tests/manual/systemmonitor/SystemMonitorChart.qml b/tests/manual/monitormodel/SystemMonitorChart.qml
index 59f7da5a..59f7da5a 100644
--- a/tests/manual/systemmonitor/SystemMonitorChart.qml
+++ b/tests/manual/monitormodel/SystemMonitorChart.qml
diff --git a/tests/manual/systemmonitor/main.qml b/tests/manual/monitormodel/main.qml
index 59af386d..50fedbb3 100644
--- a/tests/manual/systemmonitor/main.qml
+++ b/tests/manual/monitormodel/main.qml
@@ -53,12 +53,60 @@ Window {
Pane {
anchors.fill: parent
- SystemMonitor {
- id: systemMonitor
- cpuLoadReportingEnabled: cpuLoadReportingSwitch.checked
- memoryReportingEnabled: memoryReportingSwitch.checked
- gpuLoadReportingEnabled: gpuLoadReportingSwitch.checked
- fpsReportingEnabled: fpsReportingSwitch.checked
+ MonitorModel {
+ id: monitorModel
+
+ running: runningSwitch.checked
+
+ // Data sources from QtApplicationManager
+ CpuStatus { id: cpuStatus }
+ MemoryStatus { id: memoryStatus }
+ IoStatus {
+ id: ioStatus
+ deviceNames: "sda"
+ }
+
+ // A custom data source, with two roles
+ QtObject {
+ id: fooBarStatus
+ property var roleNames: ["foo", "bar"]
+
+ function update() {
+ foo += 1;
+
+ if (_up) {
+ bar += 1;
+ if (bar == 10)
+ _up = false;
+ } else {
+ bar -= 1;
+ if (bar == 0)
+ _up = true;
+ }
+ }
+ property int foo: 0
+ property int bar: 10
+ property bool _up: false
+ }
+
+ // Yet another custom data source
+ QtObject {
+ id: alphaStatus
+ property var roleNames: ["alpha"]
+ function update() {
+ if (_up) {
+ alpha *= 2;
+ if (alpha == 1024)
+ _up = false;
+ } else {
+ alpha /= 2;
+ if (alpha == 2)
+ _up = true;
+ }
+ }
+ property real alpha: 2
+ property bool _up: true
+ }
}
ScrollView {
@@ -69,17 +117,14 @@ Window {
anchors.left: parent.left
ColumnLayout {
- PropertyField { name: "count"; object: systemMonitor }
- PropertyField { name: "reportingInterval"; object: systemMonitor }
- PropertyField { name: "idleLoadThreshold"; object: systemMonitor }
+ PropertyField { name: "maximumCount"; object: monitorModel }
+ PropertyField { name: "interval"; object: monitorModel }
RowLayout {
ComboBox {
id: rolesCombo
- // TODO: ioLoad
Layout.fillWidth: true
- model: [ "cpuLoad", "gpuLoad", "memoryUsed", "averageFps", "minimumFps",
- "maximumFps", "fpsJitter" ]
+ model: [ "cpuLoad", "memoryUsed", "foo", "bar", "alpha" ]
}
Button {
@@ -91,36 +136,20 @@ Window {
}
Switch {
- id: cpuLoadReportingSwitch
- text: "cpuLoadReportingEnabled"
+ id: runningSwitch
+ text: "running"
checked: false
}
- Switch {
- id: memoryReportingSwitch
- text: "memoryReportingEnabled"
- checked: false
- }
-
- Switch {
- id: gpuLoadReportingSwitch
- text: "gpuLoadReportingEnabled"
- checked: false
- }
-
- Switch {
- id: fpsReportingSwitch
- text: "fpsReportingEnabled"
- checked: false
- }
+ Button { text: "Clear"; onClicked: monitorModel.clear() }
- Label { text: "cpuLoad: " + systemMonitor.cpuLoad }
- Label { text: "totalMemory: " + systemMonitor.totalMemory }
- Label { text: "memoryUsed: " + systemMonitor.memoryUsed }
- Label { text: "cpuCores: " + systemMonitor.cpuCores }
- Label { text: "cpuLoad: " + systemMonitor.cpuLoad }
- Label { text: "gpuLoad: " + systemMonitor.gpuLoad }
- Label { text: "idle: " + systemMonitor.idle }
+ Label { text: "cpuLoad: " + cpuStatus.cpuLoad }
+ Label { text: "totalMemory: " + memoryStatus.totalMemory }
+ Label { text: "memoryUsed: " + memoryStatus.memoryUsed }
+ Label { text: "ioLoad.sda: " + ioStatus.ioLoad.sda }
+ Label { text: "foo: " + fooBarStatus.foo }
+ Label { text: "bar: " + fooBarStatus.bar }
+ Label { text: "alpha: " + alphaStatus.alpha }
}
}
@@ -135,7 +164,7 @@ Window {
delegate: SystemMonitorChart {
Layout.fillWidth: true
Layout.fillHeight: true
- sourceModel: systemMonitor
+ sourceModel: monitorModel
role: model.role
onRemoveClicked: chartsModel.remove(model.index)
}
diff --git a/tests/processmonitor/processmonitor.pro b/tests/processmonitor/processmonitor.pro
deleted file mode 100644
index b7425e06..00000000
--- a/tests/processmonitor/processmonitor.pro
+++ /dev/null
@@ -1,11 +0,0 @@
-TARGET = tst_processmonitor
-
-include($$PWD/../tests.pri)
-
-QT *= appman_monitor-private \
- appman_manager-private \
- appman_window-private \
- appman_application-private \
- appman_common-private
-
-SOURCES += tst_processmonitor.cpp
diff --git a/tests/processmonitor/tst_processmonitor.cpp b/tests/processmonitor/tst_processmonitor.cpp
deleted file mode 100644
index 7696aeeb..00000000
--- a/tests/processmonitor/tst_processmonitor.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Pelagicore Application Manager.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite licenses may use
-** this file in accordance with the commercial license agreement provided
-** with the Software or, alternatively, in accordance with the terms
-** contained in a written agreement between you and The Qt Company. For
-** licensing terms and conditions see https://www.qt.io/terms-conditions.
-** For further information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtCore>
-#include <QtTest>
-#include "private/processmonitor_p.h"
-
-QT_USE_NAMESPACE_AM
-
-class ReadingTaskTester : public ReadingTask
-{
-public:
- using ReadingTask::readMemory;
-};
-
-class tst_ProcessMonitor : public QObject
-{
- Q_OBJECT
-
-public:
- tst_ProcessMonitor();
-
-private slots:
- void memInvalid_data();
- void memInvalid();
- void memTestProcess();
- void memBasic();
- void memAdvanced();
-
-private:
- void printMem(const ReadingTask::Results::Memory &memres);
-
- ReadingTask task;
- ReadingTask::Results readResults;
- QMutex mutex;
-};
-
-tst_ProcessMonitor::tst_ProcessMonitor() : task(mutex, readResults)
-{}
-
-void tst_ProcessMonitor::memInvalid_data()
-{
- QTest::addColumn<QString>("file");
-
- QTest::newRow("arbitrary") << QFINDTESTDATA("tst_processmonitor.cpp");
- QTest::newRow("binary") << QFINDTESTDATA("tst_processmonitor");
- QTest::newRow("missingvalue") << QFINDTESTDATA("invalid.smaps");
-}
-
-void tst_ProcessMonitor::memInvalid()
-{
- QFETCH(QString, file);
-
- ReadingTask::Results::Memory memres;
- QVERIFY(!static_cast<ReadingTaskTester*>(&task)->readMemory(file.toLocal8Bit(), memres));
- QCOMPARE(memres.totalVm, 0u);
- QCOMPARE(memres.totalRss, 0u);
- QCOMPARE(memres.totalPss, 0u);
- QCOMPARE(memres.textVm, 0u);
- QCOMPARE(memres.textRss, 0u);
- QCOMPARE(memres.textPss, 0u);
- QCOMPARE(memres.heapVm, 0u);
- QCOMPARE(memres.heapRss, 0u);
- QCOMPARE(memres.heapPss, 0u);
-}
-
-void tst_ProcessMonitor::memTestProcess()
-{
- ReadingTask::Results::Memory memres;
- const QByteArray file = "/proc/" + QByteArray::number(QCoreApplication::applicationPid()) + "/smaps";
- QVERIFY(static_cast<ReadingTaskTester*>(&task)->readMemory(file, memres));
- //printMem(memres);
- QVERIFY(memres.totalVm >= memres.totalRss);
- QVERIFY(memres.totalRss >= memres.totalPss);
- QVERIFY(memres.textVm >= memres.textRss);
- QVERIFY(memres.textRss >= memres.textPss);
- QVERIFY(memres.heapVm >= memres.heapRss);
- QVERIFY(memres.heapRss >= memres.heapPss);
-}
-
-void tst_ProcessMonitor::memBasic()
-{
- ReadingTask::Results::Memory memres;
- QVERIFY(static_cast<ReadingTaskTester*>(&task)->readMemory(QFINDTESTDATA("basic.smaps").toLocal8Bit(), memres));
- //printMem(memres);
- QCOMPARE(memres.totalVm, 107384u);
- QCOMPARE(memres.totalRss, 20352u);
- QCOMPARE(memres.totalPss, 13814u);
- QCOMPARE(memres.textVm, 7800u);
- QCOMPARE(memres.textRss, 5884u);
- QCOMPARE(memres.textPss, 2318u);
- QCOMPARE(memres.heapVm, 24376u);
- QCOMPARE(memres.heapRss, 7556u);
- QCOMPARE(memres.heapPss, 7556u);
-}
-
-void tst_ProcessMonitor::memAdvanced()
-{
- ReadingTask::Results::Memory memres;
- QVERIFY(static_cast<ReadingTaskTester*>(&task)->readMemory(QFINDTESTDATA("advanced.smaps").toLocal8Bit(), memres));
- //printMem(memres);
- QCOMPARE(memres.totalVm, 77728u);
- QCOMPARE(memres.totalRss, 17612u);
- QCOMPARE(memres.totalPss, 17547u);
- QCOMPARE(memres.textVm, 2104u);
- QCOMPARE(memres.textRss, 1772u);
- QCOMPARE(memres.textPss, 1707u);
- QCOMPARE(memres.heapVm, 16032u);
- QCOMPARE(memres.heapRss, 15740u);
- QCOMPARE(memres.heapPss, 15740u);
-}
-
-void tst_ProcessMonitor::printMem(const ReadingTask::Results::Memory &memres)
-{
- qDebug() << "totalVm:" << memres.totalVm;
- qDebug() << "totalRss:" << memres.totalRss;
- qDebug() << "totalPss:" << memres.totalPss;
- qDebug() << "textVm:" << memres.textVm;
- qDebug() << "textRss:" << memres.textRss;
- qDebug() << "textPss:" << memres.textPss;
- qDebug() << "heapVm:" << memres.heapVm;
- qDebug() << "heapRss:" << memres.heapRss;
- qDebug() << "heapPss:" << memres.heapPss;
-}
-
-QTEST_APPLESS_MAIN(tst_ProcessMonitor)
-
-#include "tst_processmonitor.moc"
diff --git a/tests/processmonitor/advanced.smaps b/tests/processreader/advanced.smaps
index 61212565..61212565 100644
--- a/tests/processmonitor/advanced.smaps
+++ b/tests/processreader/advanced.smaps
diff --git a/tests/processmonitor/basic.smaps b/tests/processreader/basic.smaps
index 00640230..00640230 100644
--- a/tests/processmonitor/basic.smaps
+++ b/tests/processreader/basic.smaps
diff --git a/tests/processmonitor/invalid.smaps b/tests/processreader/invalid.smaps
index 146a42b8..146a42b8 100644
--- a/tests/processmonitor/invalid.smaps
+++ b/tests/processreader/invalid.smaps
diff --git a/tests/systemmonitor/systemmonitor.pro b/tests/processreader/processreader.pro
index c3d6a914..c5caa674 100644
--- a/tests/systemmonitor/systemmonitor.pro
+++ b/tests/processreader/processreader.pro
@@ -1,4 +1,4 @@
-TARGET = tst_systemmonitor
+TARGET = tst_processreader
include($$PWD/../tests.pri)
@@ -8,4 +8,4 @@ QT *= appman_monitor-private \
appman_application-private \
appman_common-private
-SOURCES += tst_systemmonitor.cpp
+SOURCES += tst_processreader.cpp
diff --git a/tests/processreader/tst_processreader.cpp b/tests/processreader/tst_processreader.cpp
new file mode 100644
index 00000000..9cfa7df1
--- /dev/null
+++ b/tests/processreader/tst_processreader.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Pelagicore Application Manager.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+#include <QtTest>
+#include <QtAppManMonitor/processreader.h>
+
+QT_USE_NAMESPACE_AM
+
+class tst_ProcessReader : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_ProcessReader();
+
+private slots:
+ void memInvalid_data();
+ void memInvalid();
+ void memTestProcess();
+ void memBasic();
+ void memAdvanced();
+
+private:
+ void printMem(const ProcessReader &reader);
+ ProcessReader reader;
+};
+
+tst_ProcessReader::tst_ProcessReader()
+{}
+
+void tst_ProcessReader::memInvalid_data()
+{
+ QTest::addColumn<QString>("file");
+
+ QTest::newRow("arbitrary") << QFINDTESTDATA("tst_processreader.cpp");
+ QTest::newRow("binary") << QFINDTESTDATA("tst_processreader");
+ QTest::newRow("missingvalue") << QFINDTESTDATA("invalid.smaps");
+}
+
+void tst_ProcessReader::memInvalid()
+{
+ QFETCH(QString, file);
+
+ reader.readSmaps(file.toLocal8Bit());
+
+ QCOMPARE(reader.totalVm.load(), 0u);
+ QCOMPARE(reader.totalRss.load(), 0u);
+ QCOMPARE(reader.totalPss.load(), 0u);
+ QCOMPARE(reader.textVm.load(), 0u);
+ QCOMPARE(reader.textRss.load(), 0u);
+ QCOMPARE(reader.textPss.load(), 0u);
+ QCOMPARE(reader.heapVm.load(), 0u);
+ QCOMPARE(reader.heapRss.load(), 0u);
+ QCOMPARE(reader.heapPss.load(), 0u);
+}
+
+void tst_ProcessReader::memTestProcess()
+{
+ const QByteArray file = "/proc/" + QByteArray::number(QCoreApplication::applicationPid()) + "/smaps";
+
+ QVERIFY(reader.readSmaps(file));
+ //printMem(reader);
+ QVERIFY(reader.totalVm.load() >= reader.totalRss.load());
+ QVERIFY(reader.totalRss.load() >= reader.totalPss.load());
+ QVERIFY(reader.textVm.load() >= reader.textRss.load());
+ QVERIFY(reader.textRss.load() >= reader.textPss.load());
+ QVERIFY(reader.heapVm.load() >= reader.heapRss.load());
+ QVERIFY(reader.heapRss.load() >= reader.heapPss.load());
+}
+
+void tst_ProcessReader::memBasic()
+{
+ QVERIFY(reader.readSmaps(QFINDTESTDATA("basic.smaps").toLocal8Bit()));
+ //printMem(reader);
+ QCOMPARE(reader.totalVm.load(), 107384u);
+ QCOMPARE(reader.totalRss.load(), 20352u);
+ QCOMPARE(reader.totalPss.load(), 13814u);
+ QCOMPARE(reader.textVm.load(), 7800u);
+ QCOMPARE(reader.textRss.load(), 5884u);
+ QCOMPARE(reader.textPss.load(), 2318u);
+ QCOMPARE(reader.heapVm.load(), 24376u);
+ QCOMPARE(reader.heapRss.load(), 7556u);
+ QCOMPARE(reader.heapPss.load(), 7556u);
+}
+
+void tst_ProcessReader::memAdvanced()
+{
+ QVERIFY(reader.readSmaps(QFINDTESTDATA("advanced.smaps").toLocal8Bit()));
+ //printMem(reader);
+ QCOMPARE(reader.totalVm.load(), 77728u);
+ QCOMPARE(reader.totalRss.load(), 17612u);
+ QCOMPARE(reader.totalPss.load(), 17547u);
+ QCOMPARE(reader.textVm.load(), 2104u);
+ QCOMPARE(reader.textRss.load(), 1772u);
+ QCOMPARE(reader.textPss.load(), 1707u);
+ QCOMPARE(reader.heapVm.load(), 16032u);
+ QCOMPARE(reader.heapRss.load(), 15740u);
+ QCOMPARE(reader.heapPss.load(), 15740u);
+}
+
+void tst_ProcessReader::printMem(const ProcessReader &reader)
+{
+ qDebug() << "totalVm:" << reader.totalVm.load();
+ qDebug() << "totalRss:" << reader.totalRss.load();
+ qDebug() << "totalPss:" << reader.totalPss.load();
+ qDebug() << "textVm:" << reader.textVm.load();
+ qDebug() << "textRss:" << reader.textRss.load();
+ qDebug() << "textPss:" << reader.textPss.load();
+ qDebug() << "heapVm:" << reader.heapVm.load();
+ qDebug() << "heapRss:" << reader.heapRss.load();
+ qDebug() << "heapPss:" << reader.heapPss.load();
+}
+
+QTEST_APPLESS_MAIN(tst_ProcessReader)
+
+#include "tst_processreader.moc"
diff --git a/tests/systemmonitor/tst_systemmonitor.cpp b/tests/systemmonitor/tst_systemmonitor.cpp
deleted file mode 100644
index 48918bfb..00000000
--- a/tests/systemmonitor/tst_systemmonitor.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Pelagicore AG
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Pelagicore Application Manager.
-**
-** $QT_BEGIN_LICENSE:LGPL-QTAS$
-** Commercial License Usage
-** Licensees holding valid commercial Qt Automotive Suite licenses may use
-** this file in accordance with the commercial license agreement provided
-** with the Software or, alternatively, in accordance with the terms
-** contained in a written agreement between you and The Qt Company. For
-** licensing terms and conditions see https://www.qt.io/terms-conditions.
-** For further information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-** SPDX-License-Identifier: LGPL-3.0
-**
-****************************************************************************/
-
-#include <QQuickView>
-#include <QtCore>
-#include <QtTest>
-
-#include "windowmanager.h"
-#include "systemmonitor.h"
-#include <QtAppManMonitor/private/systemmonitor_p.h>
-
-QT_USE_NAMESPACE_AM
-
-class tst_SystemMonitor : public QObject
-{
- Q_OBJECT
-
-public:
- tst_SystemMonitor();
- virtual ~tst_SystemMonitor();
-
-private slots:
- void reportingTimer_data();
- void reportingTimer();
-private:
- static bool getBooleanProperty(QObject *obj, QString propName);
- static QMetaProperty getProperty(QObject *obj, QString propName);
- static void setBooleanProperty(QObject *obj, QString propName, bool value);
- QQuickView *view;
-};
-
-tst_SystemMonitor::tst_SystemMonitor()
-{
- view = new QQuickView;
- WindowManager::createInstance(view->engine(), QString("foo"));
-}
-
-tst_SystemMonitor::~tst_SystemMonitor()
-{
- delete view;
-}
-
-QMetaProperty tst_SystemMonitor::getProperty(QObject *obj, QString propName)
-{
- const QMetaObject *metaObj = obj->metaObject();
- int idx = metaObj->indexOfProperty(propName.toLocal8Bit());
- Q_ASSERT(idx != -1);
-
- return metaObj->property(idx);
-}
-
-bool tst_SystemMonitor::getBooleanProperty(QObject *obj, QString propName)
-{
- QMetaProperty property = getProperty(obj, propName);
- QVariant result = property.read(obj);
- Q_ASSERT(result.type() == QVariant::Bool);
- return result.toBool();
-}
-
-void tst_SystemMonitor::setBooleanProperty(QObject *obj, QString propName, bool value)
-{
- QMetaProperty property = getProperty(obj, propName);
- bool ok = property.write(obj, QVariant(value));
- Q_ASSERT(ok);
-}
-
-void tst_SystemMonitor::reportingTimer_data()
-{
- QTest::addColumn<QString>("reportingEnabled");
-
- QTest::newRow("memory") << QString("memoryReportingEnabled");
- QTest::newRow("cpuLoad") << QString("cpuLoadReportingEnabled");
- QTest::newRow("gpuLoad") << QString("gpuLoadReportingEnabled");
- QTest::newRow("fps") << QString("fpsReportingEnabled");
-}
-
-/*
- Tests that the reportingTimer is only active while there's at least
- one reporting category enabled.
- */
-void tst_SystemMonitor::reportingTimer()
-{
- QFETCH(QString, reportingEnabled);
-
- SystemMonitor sysMon;
- auto sysMonPriv = SystemMonitorPrivate::get(&sysMon);
-
- sysMon.setReportingInterval(50);
-
- QCOMPARE(getBooleanProperty(&sysMon, reportingEnabled), false);
- QCOMPARE(sysMonPriv->reportingTimerId, 0);
-
- setBooleanProperty(&sysMon, reportingEnabled, true);
-
- QVERIFY(sysMonPriv->reportingTimerId > 0);
-
- setBooleanProperty(&sysMon, reportingEnabled, false);
-
- QCOMPARE(sysMonPriv->reportingTimerId, 0);
-}
-
-QTEST_MAIN(tst_SystemMonitor)
-
-#include "tst_systemmonitor.moc"
diff --git a/tests/tests.pro b/tests/tests.pro
index c8e93636..75b7039e 100644
--- a/tests/tests.pro
+++ b/tests/tests.pro
@@ -18,8 +18,7 @@ SUBDIRS = \
linux*:SUBDIRS += \
sudo \
- processmonitor \
- systemmonitor \
+ processreader \
systemreader \
OTHER_FILES += \