Merge lp:~unity-team/qtmir/touch_tracing into lp:qtmir
- touch_tracing
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Gerry Boland |
Approved revision: | 378 |
Merged at revision: | 395 |
Proposed branch: | lp:~unity-team/qtmir/touch_tracing |
Merge into: | lp:qtmir |
Prerequisite: | lp:~nick-dedekind/qtmir/remove-dpkg-CMAK_INSTALL_PREFIX |
Diff against target: |
1257 lines (+941/-18) 28 files modified
CMakeLists.txt (+3/-1) benchmarks/CMakeLists.txt (+8/-0) benchmarks/README (+12/-0) benchmarks/common.py (+33/-0) benchmarks/report_types.py (+121/-0) benchmarks/touch_event_latency.R (+6/-0) benchmarks/touch_event_latency.py (+271/-0) debian/control (+20/-0) debian/qtmir-tests.install (+6/-0) debian/rules (+1/-1) demos/CMakeLists.txt (+4/-0) demos/paths.h.in (+40/-0) demos/qml-demo-client/CMakeLists.txt (+41/-0) demos/qml-demo-client/main.cpp (+73/-0) demos/qml-demo-client/qtmir-demo-client.desktop.in (+9/-0) demos/qml-demo-shell/CMakeLists.txt (+35/-0) demos/qml-demo-shell/main.cpp (+57/-0) src/common/timestamp.cpp (+18/-0) src/common/timestamp.h (+39/-0) src/common/timestamp_impl.h (+34/-0) src/modules/Unity/Application/mirsurface.cpp (+5/-4) src/modules/Unity/Application/mirsurfaceitem.cpp (+6/-0) src/modules/Unity/Application/tracepoints.tp (+5/-0) src/platforms/mirserver/CMakeLists.txt (+1/-0) src/platforms/mirserver/qteventfeeder.cpp (+14/-4) src/platforms/mirserver/tracepoints.tp (+5/-0) tests/modules/General/CMakeLists.txt (+2/-8) tests/modules/General/timestamp_test.cpp (+72/-0) |
To merge this branch: | bzr merge lp:~unity-team/qtmir/touch_tracing |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gerry Boland (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Review via email: mp+271655@code.launchpad.net |
This proposal supersedes a proposal from 2015-08-05.
Commit message
Added touch performance tracing and test.
Description of the change
Added touch performance tracing and test.
* Are there any related MPs required for this MP to build/function as expected? Please list.
Yes
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:351
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
=== modified file 'debian/rules'
-DNO_TESTS=1 - please undo, we want tests!
=== added file 'demos/
I don't understand what this is useful for. Isn't the "qml" binary sufficient?
=== added file 'demos/
same here.
=== added file 'src/common/
file name "utils" as vague as possible:) Can you be more specific?
+++ src/common/
+qint64 resetStartTime(
+qint64 getStartTime_
please stick into an anonymous namespace
The indenting is inconsistent in the whole file.
+ QCoreApplicatio
I suspect a static variable would do the job just as well.
+ qint64 startTime = getStartTime_
std::chrono has nanosecond to milisecond conversion abilities built in, I think you can just cast and it works. It would be safer than dividing by 1000000. I suspect you can avoid all usages of qint64 as a result.
====
This compression is a clever idea to work around the difference in timestamp units Qt & Mir uses. I'm still curious if instead of tying ourselves to the event APIs Qt has, e.g.
void QWindowSystemIn
ulong timestamp, const QPointF & local, const QPointF & global,
Qt:
Qt:
we could make our own handle*Event() methods. In the end, the above method simply does:
QWindowSystemIn
new QWindowSystemIn
QWindowSystemIn
If we subclassed QWindowSystemIn
To be investigated. For now, your approach is good.
====
std::chrono:
Do you need the milliseconds anywhere, as I only see you calling .count() on this everywhere it's used. Why not just return ulong?
Also, would be good to document *why* you've done the timestamp compression/
=== modified file 'src/platforms/
Typos:
touchEventDispt
touchEventDispt
and these propagate throughout the whole of mirserver.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:352
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:370
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:372
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:373
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Nick Dedekind (nick-dedekind) wrote : Posted in a previous version of this proposal | # |
> === modified file 'debian/rules'
> -DNO_TESTS=1 - please undo, we want tests!
>
> === added file 'demos/
> I don't understand what this is useful for. Isn't the "qml" binary sufficient?
>
> === added file 'demos/
> same here.
>
It's so we can get them to work with the benchmark util. The client needs to parse the command line parameters for the socket.
>
> === added file 'src/common/
> file name "utils" as vague as possible:) Can you be more specific?
timestamp.h
>
> +++ src/common/
> +qint64 resetStartTime(
> +qint64 getStartTime_
> please stick into an anonymous namespace
>
> The indenting is inconsistent in the whole file.
>
> + QCoreApplicatio
> I suspect a static variable would do the job just as well.
Used extern functions with a variable. Needs to be shared by the different modules.
>
> + qint64 startTime = getStartTime_
> std::chrono has nanosecond to milisecond conversion abilities built in, I
> think you can just cast and it works. It would be safer than dividing by
> 1000000. I suspect you can avoid all usages of qint64 as a result.
>
>
> ====
> This compression is a clever idea to work around the difference in timestamp
> units Qt & Mir uses. I'm still curious if instead of tying ourselves to the
> event APIs Qt has, e.g.
>
> void QWindowSystemIn
> ulong timestamp, const QPointF & local, const QPointF & global,
> Qt::MouseButtons b, Qt::KeyboardMod
> Qt::MouseEventS
>
> we could make our own handle*Event() methods. In the end, the above method
> simply does:
>
> QWindowSystemIn
> new QWindowSystemIn
> QWindowSystemIn
> QHighDpi:
> QHighDpi:
>
> QWindowSystemIn
>
> If we subclassed QWindowSystemIn
> timestamp type we want, that event might pass through Qt safely. This would be
> especially usesful for Mir events which have more detail that Qt events have.
>
> To be investigated. For now, your approach is good.
I'll take a look into it when i get a minute.
> ====
>
>
> std::chrono:
> timestamp);
> Do you need the milliseconds anywhere, as I only see you calling .count() on
> this everywhere it's used. Why not just return ulong?
>
> Also, would be good to document *why* you've done the timestamp
> compression/
Done. in the header.
>
>
> === modified file 'src/platforms/
> Typos:
> touchEventDispt
> touchEventDispt
> and these propagate throughout the whole of mirserver.
Fixed.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:374
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:375
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:376
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
+$ cd benchmarks
+$ sudo python3 touch_event_
I roughly followed this, but since I saw this script was installed by qtmir-tests in /usr/share/
sudo python3 /usr/share/
but it doesn't fully work:
file://
- 377. By Nick Dedekind
-
newline
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:376
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:377
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 378. By Nick Dedekind
-
merged with trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:378
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : | # |
We're having mild CI issues. Testing locally, all is good. We've a bunch of landings coming up, so I expect conflicts before this appears at the top of the queue unfortunately.
- 379. By Nick Dedekind
-
fixed debian/control for qtmir-tests
- 380. By Nick Dedekind
-
merged with lp:~dandrader/qtmir/multimonitorNext
- 381. By Nick Dedekind
-
merged with cmake branch
- 382. By Nick Dedekind
-
merged parent
Preview Diff
1 | === modified file 'CMakeLists.txt' | |||
2 | --- CMakeLists.txt 2015-10-14 13:06:12 +0000 | |||
3 | +++ CMakeLists.txt 2015-10-14 13:06:12 +0000 | |||
4 | @@ -120,6 +120,7 @@ | |||
5 | 120 | 120 | ||
6 | 121 | # Set QML module install path | 121 | # Set QML module install path |
7 | 122 | set(QML_MODULE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/qt5/qml") | 122 | set(QML_MODULE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/qt5/qml") |
8 | 123 | set(QTMIR_DATA_DIR ${CMAKE_INSTALL_DATADIR}/qtmir) | ||
9 | 123 | 124 | ||
10 | 124 | 125 | ||
11 | 125 | # Customisations for the build type | 126 | # Customisations for the build type |
12 | @@ -156,6 +157,7 @@ | |||
13 | 156 | message(STATUS "Tests disabled") | 157 | message(STATUS "Tests disabled") |
14 | 157 | endif() | 158 | endif() |
15 | 158 | 159 | ||
16 | 159 | |||
17 | 160 | # add subdirectories to build | 160 | # add subdirectories to build |
18 | 161 | add_subdirectory(src) | 161 | add_subdirectory(src) |
19 | 162 | add_subdirectory(demos) | ||
20 | 163 | add_subdirectory(benchmarks) | ||
21 | 162 | 164 | ||
22 | === added directory 'benchmarks' | |||
23 | === added file 'benchmarks/CMakeLists.txt' | |||
24 | --- benchmarks/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
25 | +++ benchmarks/CMakeLists.txt 2015-10-14 13:06:12 +0000 | |||
26 | @@ -0,0 +1,8 @@ | |||
27 | 1 | file(GLOB BENCHMARK_FILES | ||
28 | 2 | *.py | ||
29 | 3 | *.R | ||
30 | 4 | ) | ||
31 | 5 | |||
32 | 6 | install(FILES ${BENCHMARK_FILES} | ||
33 | 7 | DESTINATION ${QTMIR_DATA_DIR}/benchmarks | ||
34 | 8 | ) | ||
35 | 0 | 9 | ||
36 | === added file 'benchmarks/README' | |||
37 | --- benchmarks/README 1970-01-01 00:00:00 +0000 | |||
38 | +++ benchmarks/README 2015-10-14 13:06:12 +0000 | |||
39 | @@ -0,0 +1,12 @@ | |||
40 | 1 | To run performance tests on device: | ||
41 | 2 | |||
42 | 3 | Firstly, you will need to install the qtmir-tests package. So either install the package using apt or build | ||
43 | 4 | and install from source | ||
44 | 5 | $ sudo apt-get install qtmir-tests | ||
45 | 6 | |||
46 | 7 | Then you need to stop unity8 & unity-system compositor so that we can start out test in a controlled environment. | ||
47 | 8 | $ sudo stop lightdm | ||
48 | 9 | |||
49 | 10 | Next, start the test! | ||
50 | 11 | $ cd benchmarks | ||
51 | 12 | $ sudo python3 touch_event_latency.py | ||
52 | 0 | \ No newline at end of file | 13 | \ No newline at end of file |
53 | 1 | 14 | ||
54 | === added file 'benchmarks/common.py' | |||
55 | --- benchmarks/common.py 1970-01-01 00:00:00 +0000 | |||
56 | +++ benchmarks/common.py 2015-10-14 13:06:12 +0000 | |||
57 | @@ -0,0 +1,33 @@ | |||
58 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
59 | 2 | # | ||
60 | 3 | # Copyright (C) 2015 Canonical Ltd. | ||
61 | 4 | # | ||
62 | 5 | # This program is free software; you can redistribute it and/or modify | ||
63 | 6 | # it under the terms of the GNU Lesser General Public License as published by | ||
64 | 7 | # the Free Software Foundation; version 3. | ||
65 | 8 | # | ||
66 | 9 | # This program is distributed in the hope that it will be useful, | ||
67 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
68 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
69 | 12 | # GNU Lesser General Public License for more details. | ||
70 | 13 | # | ||
71 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
72 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
73 | 16 | |||
74 | 17 | from autopilot import ( | ||
75 | 18 | input, | ||
76 | 19 | platform | ||
77 | 20 | ) | ||
78 | 21 | |||
79 | 22 | def get_pointing_device(): | ||
80 | 23 | """Return the pointing device depending on the platform. | ||
81 | 24 | |||
82 | 25 | If the platform is `Desktop`, the pointing device will be a `Mouse`. | ||
83 | 26 | If not, the pointing device will be `Touch`. | ||
84 | 27 | |||
85 | 28 | """ | ||
86 | 29 | if platform.model() == 'Desktop': | ||
87 | 30 | input_device_class = input.Mouse | ||
88 | 31 | else: | ||
89 | 32 | input_device_class = input.Touch | ||
90 | 33 | return input.Pointer(device=input_device_class.create()) | ||
91 | 0 | \ No newline at end of file | 34 | \ No newline at end of file |
92 | 1 | 35 | ||
93 | === added file 'benchmarks/report_types.py' | |||
94 | --- benchmarks/report_types.py 1970-01-01 00:00:00 +0000 | |||
95 | +++ benchmarks/report_types.py 2015-10-14 13:06:12 +0000 | |||
96 | @@ -0,0 +1,121 @@ | |||
97 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
98 | 2 | # | ||
99 | 3 | # Copyright (C) 2015 Canonical Ltd. | ||
100 | 4 | # | ||
101 | 5 | # This program is free software; you can redistribute it and/or modify | ||
102 | 6 | # it under the terms of the GNU Lesser General Public License as published by | ||
103 | 7 | # the Free Software Foundation; version 3. | ||
104 | 8 | # | ||
105 | 9 | # This program is distributed in the hope that it will be useful, | ||
106 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
107 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
108 | 12 | # GNU Lesser General Public License for more details. | ||
109 | 13 | # | ||
110 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
111 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
112 | 16 | |||
113 | 17 | import subprocess | ||
114 | 18 | import os | ||
115 | 19 | import shutil | ||
116 | 20 | |||
117 | 21 | class Node: | ||
118 | 22 | def __init__(self, name): | ||
119 | 23 | self.name = name | ||
120 | 24 | self.children = [] | ||
121 | 25 | |||
122 | 26 | def add_child(self, child): | ||
123 | 27 | self.children.append(child) | ||
124 | 28 | |||
125 | 29 | def to_string(self): | ||
126 | 30 | output = "<%s>" % self.name | ||
127 | 31 | for child in self.children: | ||
128 | 32 | output += child.to_string() | ||
129 | 33 | output += "</%s>" % self.name | ||
130 | 34 | return output | ||
131 | 35 | |||
132 | 36 | class Results(Node): | ||
133 | 37 | def __init__(self): | ||
134 | 38 | super().__init__("results") | ||
135 | 39 | |||
136 | 40 | class Events(Node): | ||
137 | 41 | def __init__(self): | ||
138 | 42 | super().__init__("events") | ||
139 | 43 | |||
140 | 44 | class Event: | ||
141 | 45 | def __init__(self, event): | ||
142 | 46 | self.pid = event["vpid"] | ||
143 | 47 | self.name = event.name | ||
144 | 48 | self.timestamp = event.timestamp | ||
145 | 49 | |||
146 | 50 | def to_string(self): | ||
147 | 51 | output = "<event " | ||
148 | 52 | output += "pid='{}' ".format(self.pid) | ||
149 | 53 | output += "name='{}' ".format(self.name) | ||
150 | 54 | output += "timestamp='{}' ".format(self.timestamp) | ||
151 | 55 | output += "/>" | ||
152 | 56 | return output | ||
153 | 57 | |||
154 | 58 | class Processes(Node): | ||
155 | 59 | def __init__(self): | ||
156 | 60 | super().__init__("processes") | ||
157 | 61 | |||
158 | 62 | class Process: | ||
159 | 63 | def __init__(self, name, pid): | ||
160 | 64 | self.name = name | ||
161 | 65 | self.pid = pid | ||
162 | 66 | |||
163 | 67 | def to_string(self): | ||
164 | 68 | output = "<process " | ||
165 | 69 | output += "name='{}' ".format(self.name) | ||
166 | 70 | output += "pid='{}' ".format(self.pid) | ||
167 | 71 | output += "/>" | ||
168 | 72 | return output | ||
169 | 73 | |||
170 | 74 | class ResultsData: | ||
171 | 75 | def __init__(self, name, mean=0.0, deviation=0.0, comment=""): | ||
172 | 76 | self.data = [] | ||
173 | 77 | self.name = name | ||
174 | 78 | self.mean = mean | ||
175 | 79 | self.deviation = deviation | ||
176 | 80 | self.comment = comment | ||
177 | 81 | |||
178 | 82 | def add_data(self, value): | ||
179 | 83 | self.data.append(value) | ||
180 | 84 | |||
181 | 85 | def to_string(self): | ||
182 | 86 | output = "<data name='{}' mean='{}' deviation='{}' comment='{}' count='{}'>".format( | ||
183 | 87 | self.name, | ||
184 | 88 | self.mean, | ||
185 | 89 | self.deviation, | ||
186 | 90 | self.comment, | ||
187 | 91 | len(self.data)) | ||
188 | 92 | output += "<values>" | ||
189 | 93 | output += ",".join(map( lambda x: str(x), self.data)) | ||
190 | 94 | output += "</values>" | ||
191 | 95 | output += "</data>" | ||
192 | 96 | return output; | ||
193 | 97 | |||
194 | 98 | def generate_histogram(self, filename): | ||
195 | 99 | cmdline = [ | ||
196 | 100 | shutil.which("Rscript"), | ||
197 | 101 | os.path.split(os.path.abspath(__file__))[0] + "/touch_event_latency.R", | ||
198 | 102 | "data.csv", | ||
199 | 103 | "%s.png" % filename] | ||
200 | 104 | # Use R to generate a histogram plot | ||
201 | 105 | f = open("data.csv", "w") | ||
202 | 106 | f.write(",".join(map( lambda x: str(x), self.data))); | ||
203 | 107 | f.close() | ||
204 | 108 | process = subprocess.Popen(cmdline) | ||
205 | 109 | process.wait() | ||
206 | 110 | if process.returncode != 0: | ||
207 | 111 | print("Failed to generate histogram"); | ||
208 | 112 | os.remove("data.csv") | ||
209 | 113 | |||
210 | 114 | |||
211 | 115 | class Error: | ||
212 | 116 | def __init__(self, comment): | ||
213 | 117 | self.comment = comment | ||
214 | 118 | |||
215 | 119 | def to_string(self): | ||
216 | 120 | return "<error comment='{}' />".format(self.comment) | ||
217 | 121 | return output | ||
218 | 0 | \ No newline at end of file | 122 | \ No newline at end of file |
219 | 1 | 123 | ||
220 | === added file 'benchmarks/touch_event_latency.R' | |||
221 | --- benchmarks/touch_event_latency.R 1970-01-01 00:00:00 +0000 | |||
222 | +++ benchmarks/touch_event_latency.R 2015-10-14 13:06:12 +0000 | |||
223 | @@ -0,0 +1,6 @@ | |||
224 | 1 | args <- commandArgs(trailingOnly = TRUE) | ||
225 | 2 | data <- scan(args[1], numeric(), sep=",") | ||
226 | 3 | colors = c("red", "yellow", "green", "violet", "orange", "pink", "blue") | ||
227 | 4 | png(filename=args[2]) | ||
228 | 5 | hist(data, breaks=max(data), col=colors) | ||
229 | 6 | dev.off() | ||
230 | 0 | 7 | ||
231 | === added file 'benchmarks/touch_event_latency.py' | |||
232 | --- benchmarks/touch_event_latency.py 1970-01-01 00:00:00 +0000 | |||
233 | +++ benchmarks/touch_event_latency.py 2015-10-14 13:06:12 +0000 | |||
234 | @@ -0,0 +1,271 @@ | |||
235 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
236 | 2 | # | ||
237 | 3 | # Copyright (C) 2015 Canonical Ltd. | ||
238 | 4 | # | ||
239 | 5 | # This program is free software; you can redistribute it and/or modify | ||
240 | 6 | # it under the terms of the GNU Lesser General Public License as published by | ||
241 | 7 | # the Free Software Foundation; version 3. | ||
242 | 8 | # | ||
243 | 9 | # This program is distributed in the hope that it will be useful, | ||
244 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
245 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
246 | 12 | # GNU Lesser General Public License for more details. | ||
247 | 13 | # | ||
248 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
249 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
250 | 16 | |||
251 | 17 | from mir_perf_framework import PerformanceTest, Server, Client | ||
252 | 18 | import time | ||
253 | 19 | import statistics | ||
254 | 20 | import shutil | ||
255 | 21 | import sys | ||
256 | 22 | from common import get_pointing_device | ||
257 | 23 | import report_types | ||
258 | 24 | |||
259 | 25 | ####### TEST ####### | ||
260 | 26 | |||
261 | 27 | |||
262 | 28 | def perform_test(): | ||
263 | 29 | host = Server(reports=["input"]) | ||
264 | 30 | nested = Server(executable=shutil.which("qtmir-demo-shell"), | ||
265 | 31 | host=host, | ||
266 | 32 | reports=["input","client-input-receiver"], | ||
267 | 33 | env={"QT_QPA_PLATFORM": "mirserver", "QML_NO_TOUCH_COMPRESSION": "1"}) | ||
268 | 34 | client = Client(executable=shutil.which("qtmir-demo-client"), | ||
269 | 35 | server=nested, | ||
270 | 36 | reports=["input","client-input-receiver"], | ||
271 | 37 | env={"QT_QPA_PLATFORM": "ubuntumirclient", "QML_NO_TOUCH_COMPRESSION": "1"}, | ||
272 | 38 | options=["--", "--desktop_file_hint=/usr/share/applications/qtmir-demo-client.desktop"]) | ||
273 | 39 | |||
274 | 40 | test = PerformanceTest([host, nested, client]) | ||
275 | 41 | test.start() | ||
276 | 42 | |||
277 | 43 | results = report_types.Results() | ||
278 | 44 | processes = report_types.Processes() | ||
279 | 45 | processes.add_child(report_types.Process("Host", host.process.pid)) | ||
280 | 46 | processes.add_child(report_types.Process("Nested Server", nested.process.pid)) | ||
281 | 47 | processes.add_child(report_types.Process("Client", client.process.pid)) | ||
282 | 48 | results.add_child(processes) | ||
283 | 49 | |||
284 | 50 | time.sleep(3) # wait for settle | ||
285 | 51 | |||
286 | 52 | host_pid = host.process.pid | ||
287 | 53 | nested_pid = nested.process.pid | ||
288 | 54 | client_pid = client.process.pid | ||
289 | 55 | |||
290 | 56 | touch = get_pointing_device() | ||
291 | 57 | time.sleep(1) # let mir pick up the new input device | ||
292 | 58 | touch.drag(100, 100, 1000, 100, 5, 0.006) | ||
293 | 59 | touch.drag(1000, 100, 1000, 1000, 5, 0.006) | ||
294 | 60 | touch.drag(1000, 1000, 100, 1000, 5, 0.006) | ||
295 | 61 | touch.drag(100, 1000, 100, 100, 5, 0.006) | ||
296 | 62 | |||
297 | 63 | # time.sleep(5) # wait for settle | ||
298 | 64 | time.sleep(2) # wait for settle | ||
299 | 65 | test.stop() | ||
300 | 66 | |||
301 | 67 | ####### TRACE PARSING ####### | ||
302 | 68 | |||
303 | 69 | trace = test.babeltrace() | ||
304 | 70 | |||
305 | 71 | server_touch_data_timestamps = {} | ||
306 | 72 | client_touch_data_timestamps = {} | ||
307 | 73 | client_touch_data_latency = {} | ||
308 | 74 | |||
309 | 75 | qtmir_touch_dispatch_start = {} | ||
310 | 76 | qtmir_touch_dispatch_end = {} | ||
311 | 77 | qtmir_touch_consume_start = {} | ||
312 | 78 | qtmir_touch_consume_end = {} | ||
313 | 79 | |||
314 | 80 | events = report_types.Events() | ||
315 | 81 | |||
316 | 82 | for event in trace.events: | ||
317 | 83 | events.add_child(report_types.Event(event)) | ||
318 | 84 | pid = event["vpid"] | ||
319 | 85 | if event.name == "mir_client_input_receiver:touch_event": | ||
320 | 86 | if pid not in client_touch_data_timestamps: client_touch_data_timestamps[pid] = [] | ||
321 | 87 | if pid not in client_touch_data_latency: client_touch_data_latency[pid] = [] | ||
322 | 88 | diff = (event.timestamp - event["event_time"]) / 1000000.0 | ||
323 | 89 | if diff > 0: | ||
324 | 90 | client_touch_data_timestamps[pid].append(event.timestamp) | ||
325 | 91 | client_touch_data_latency[pid].append(diff) | ||
326 | 92 | |||
327 | 93 | elif event.name == "mir_server_input:published_motion_event": | ||
328 | 94 | if pid not in server_touch_data_timestamps: server_touch_data_timestamps[pid] = [] | ||
329 | 95 | server_touch_data_timestamps[pid].append(event["event_time"]) | ||
330 | 96 | |||
331 | 97 | elif event.name == "qtmirserver:touchEventDispatch_start": | ||
332 | 98 | if pid not in qtmir_touch_dispatch_start: qtmir_touch_dispatch_start[pid] = [] | ||
333 | 99 | qtmir_touch_dispatch_start[pid].append(event.timestamp) | ||
334 | 100 | |||
335 | 101 | elif event.name == "qtmirserver:touchEventDispatch_end": | ||
336 | 102 | if pid not in qtmir_touch_dispatch_end: qtmir_touch_dispatch_end[pid] = [] | ||
337 | 103 | qtmir_touch_dispatch_end[pid].append(event.timestamp) | ||
338 | 104 | |||
339 | 105 | elif event.name == "qtmir:touchEventConsume_start": | ||
340 | 106 | if pid not in qtmir_touch_consume_start: qtmir_touch_consume_start[pid] = [] | ||
341 | 107 | qtmir_touch_consume_start[pid].append(event.timestamp) | ||
342 | 108 | |||
343 | 109 | elif event.name == "qtmir:touchEventConsume_end": | ||
344 | 110 | if pid not in qtmir_touch_consume_end: qtmir_touch_consume_end[pid] = [] | ||
345 | 111 | qtmir_touch_consume_end[pid].append(event.timestamp) | ||
346 | 112 | |||
347 | 113 | # LATENCY MEANS | ||
348 | 114 | |||
349 | 115 | if nested_pid in client_touch_data_latency: | ||
350 | 116 | nested_data = client_touch_data_latency[nested_pid] | ||
351 | 117 | nested_latency_xml = report_types.ResultsData( | ||
352 | 118 | "nested_latency", | ||
353 | 119 | statistics.mean(nested_data), | ||
354 | 120 | statistics.stdev(nested_data), | ||
355 | 121 | "Kernel to nested server latency") | ||
356 | 122 | for value in nested_data: | ||
357 | 123 | nested_latency_xml.add_data(value) | ||
358 | 124 | results.add_child(nested_latency_xml) | ||
359 | 125 | nested_latency_xml.generate_histogram("nested_latency") | ||
360 | 126 | else: | ||
361 | 127 | results.add_child(report_types.Error("No nested server touch latency data")) | ||
362 | 128 | |||
363 | 129 | if client_pid in client_touch_data_latency: | ||
364 | 130 | client_data = client_touch_data_latency[client_pid] | ||
365 | 131 | |||
366 | 132 | client_latency_xml = report_types.ResultsData( | ||
367 | 133 | "client_latency", | ||
368 | 134 | statistics.mean(client_data), | ||
369 | 135 | statistics.stdev(client_data), | ||
370 | 136 | "Kernel to client latency") | ||
371 | 137 | for value in client_data: | ||
372 | 138 | client_latency_xml.add_data(value) | ||
373 | 139 | results.add_child(client_latency_xml) | ||
374 | 140 | client_latency_xml.generate_histogram("client_latency") | ||
375 | 141 | else: | ||
376 | 142 | results.add_child(report_types.Error("No client touch latency data")) | ||
377 | 143 | |||
378 | 144 | # EVENT RATES | ||
379 | 145 | if host_pid in server_touch_data_timestamps: | ||
380 | 146 | last_timestamp = -1 | ||
381 | 147 | input_rate = [] | ||
382 | 148 | |||
383 | 149 | for next_timestamp in server_touch_data_timestamps[host_pid]: | ||
384 | 150 | if last_timestamp != -1: | ||
385 | 151 | diff = (next_timestamp - last_timestamp) / 1000000.0 | ||
386 | 152 | input_rate.append(diff) | ||
387 | 153 | last_timestamp = next_timestamp | ||
388 | 154 | |||
389 | 155 | input_rate_xml = report_types.ResultsData( | ||
390 | 156 | "host_input_ate", | ||
391 | 157 | statistics.mean(input_rate), | ||
392 | 158 | statistics.stdev(input_rate), | ||
393 | 159 | "Host input event rate") | ||
394 | 160 | for value in input_rate: | ||
395 | 161 | input_rate_xml.add_data(value) | ||
396 | 162 | results.add_child(input_rate_xml) | ||
397 | 163 | input_rate_xml.generate_histogram("host_input_rate") | ||
398 | 164 | else: | ||
399 | 165 | results.add_child(report_types.Error("No host server input event timestamp data")) | ||
400 | 166 | |||
401 | 167 | if nested_pid in client_touch_data_timestamps: | ||
402 | 168 | last_timestamp = -1 | ||
403 | 169 | input_rate = [] | ||
404 | 170 | for next_timestamp in client_touch_data_timestamps[nested_pid]: | ||
405 | 171 | if last_timestamp != -1: | ||
406 | 172 | diff = (next_timestamp - last_timestamp) / 1000000.0 | ||
407 | 173 | input_rate.append(diff) | ||
408 | 174 | last_timestamp = next_timestamp | ||
409 | 175 | |||
410 | 176 | input_rate_xml = report_types.ResultsData( | ||
411 | 177 | "nested_input_rate", | ||
412 | 178 | statistics.mean(input_rate), | ||
413 | 179 | statistics.stdev(input_rate), | ||
414 | 180 | "Nested server event rate") | ||
415 | 181 | for value in input_rate: | ||
416 | 182 | input_rate_xml.add_data(value) | ||
417 | 183 | results.add_child(input_rate_xml) | ||
418 | 184 | input_rate_xml.generate_histogram("nested_input_rate") | ||
419 | 185 | else: | ||
420 | 186 | results.add_child(report_types.Error("No nested server input event timestamp data")) | ||
421 | 187 | |||
422 | 188 | if client_pid in client_touch_data_timestamps: | ||
423 | 189 | last_timestamp = -1 | ||
424 | 190 | input_rate = [] | ||
425 | 191 | for next_timestamp in client_touch_data_timestamps[client_pid]: | ||
426 | 192 | if last_timestamp != -1: | ||
427 | 193 | diff = (next_timestamp - last_timestamp) / 1000000.0 | ||
428 | 194 | input_rate.append(diff) | ||
429 | 195 | last_timestamp = next_timestamp | ||
430 | 196 | |||
431 | 197 | input_rate_xml = report_types.ResultsData( | ||
432 | 198 | "client_input_rate", | ||
433 | 199 | statistics.mean(input_rate), | ||
434 | 200 | statistics.stdev(input_rate), | ||
435 | 201 | "Client event rate") | ||
436 | 202 | for value in input_rate: | ||
437 | 203 | input_rate_xml.add_data(value) | ||
438 | 204 | results.add_child(input_rate_xml) | ||
439 | 205 | input_rate_xml.generate_histogram("client_input_rate") | ||
440 | 206 | else: | ||
441 | 207 | results.add_child(report_types.Error("No client event timestamp data")) | ||
442 | 208 | |||
443 | 209 | qtmir_loop_data = [] | ||
444 | 210 | dispatch_data = [] | ||
445 | 211 | consume_data = [] | ||
446 | 212 | |||
447 | 213 | # TIME BETWEEN TRACEPOINTS | ||
448 | 214 | dispatch_starts = qtmir_touch_dispatch_start[nested_pid] if nested_pid in qtmir_touch_dispatch_start else [] | ||
449 | 215 | dispatch_ends = qtmir_touch_dispatch_end[nested_pid] if nested_pid in qtmir_touch_dispatch_end else [] | ||
450 | 216 | consume_starts = qtmir_touch_consume_start[nested_pid] if nested_pid in qtmir_touch_consume_start else [] | ||
451 | 217 | consume_ends = qtmir_touch_consume_end[nested_pid] if nested_pid in qtmir_touch_consume_end else [] | ||
452 | 218 | |||
453 | 219 | # since there's no uniqueness to events, we need to assume all events are 1:1 through system | ||
454 | 220 | if len(dispatch_starts) > 0 and len(dispatch_starts) == len(dispatch_ends) and len(dispatch_starts) == len(consume_starts) and len(consume_starts) == len(consume_ends): | ||
455 | 221 | i = 0 | ||
456 | 222 | |||
457 | 223 | for start in dispatch_starts: | ||
458 | 224 | dispatch_diff = (dispatch_ends[i] - start) / 1000000.0 | ||
459 | 225 | consume_diff = (consume_ends[i] - consume_starts[i]) / 1000000.0 | ||
460 | 226 | loop_dif = (consume_starts[i] - dispatch_ends[i]) / 1000000.0 | ||
461 | 227 | dispatch_data.append(dispatch_diff); | ||
462 | 228 | consume_data.append(consume_diff); | ||
463 | 229 | qtmir_loop_data.append(loop_dif); | ||
464 | 230 | i=i+1 | ||
465 | 231 | |||
466 | 232 | qtmir_loop_xml = report_types.ResultsData( | ||
467 | 233 | "qtmir_eventloop", | ||
468 | 234 | statistics.mean(qtmir_loop_data), | ||
469 | 235 | statistics.stdev(qtmir_loop_data), | ||
470 | 236 | "Time spent in qtmir event loop") | ||
471 | 237 | for value in qtmir_loop_data: | ||
472 | 238 | qtmir_loop_xml.add_data(value) | ||
473 | 239 | results.add_child(qtmir_loop_xml) | ||
474 | 240 | qtmir_loop_xml.generate_histogram("qtmir_eventloop") | ||
475 | 241 | |||
476 | 242 | qtmir_dispatch_xml = report_types.ResultsData( | ||
477 | 243 | "qtmir_dispatch", | ||
478 | 244 | statistics.mean(dispatch_data), | ||
479 | 245 | statistics.stdev(dispatch_data), | ||
480 | 246 | "Time QteventFeeder spent dispatching event to qt") | ||
481 | 247 | for value in dispatch_data: | ||
482 | 248 | qtmir_dispatch_xml.add_data(value) | ||
483 | 249 | results.add_child(qtmir_dispatch_xml) | ||
484 | 250 | qtmir_dispatch_xml.generate_histogram("qtmir_dispatch") | ||
485 | 251 | |||
486 | 252 | qtmir_consume_xml = report_types.ResultsData( | ||
487 | 253 | "qtmir_consume", | ||
488 | 254 | statistics.mean(consume_data), | ||
489 | 255 | statistics.stdev(consume_data), | ||
490 | 256 | "Time MirSurfaceItem spent consiming event") | ||
491 | 257 | for value in consume_data: | ||
492 | 258 | qtmir_consume_xml.add_data(value) | ||
493 | 259 | results.add_child(qtmir_consume_xml) | ||
494 | 260 | qtmir_consume_xml.generate_histogram("qtmir_consume") | ||
495 | 261 | |||
496 | 262 | else: | ||
497 | 263 | results.add_child(report_types.Error("Cannot calculate QtMir loop data - Dispatch event count did not match surface consume event count")) | ||
498 | 264 | |||
499 | 265 | results.add_child(events) | ||
500 | 266 | return results | ||
501 | 267 | |||
502 | 268 | if __name__ == "__main__": | ||
503 | 269 | results = perform_test(); | ||
504 | 270 | f = open("touch_event_latency.xml", "w") | ||
505 | 271 | f.write(results.to_string()) | ||
506 | 0 | 272 | ||
507 | === modified file 'debian/control' | |||
508 | --- debian/control 2015-10-14 13:06:12 +0000 | |||
509 | +++ debian/control 2015-10-14 13:06:12 +0000 | |||
510 | @@ -98,3 +98,23 @@ | |||
511 | 98 | QtMir provides Qt/QML bindings for Mir features that are exposed through the | 98 | QtMir provides Qt/QML bindings for Mir features that are exposed through the |
512 | 99 | qtmir-desktop or qtmir-android QPA plugin such as Application management | 99 | qtmir-desktop or qtmir-android QPA plugin such as Application management |
513 | 100 | (start/stop/suspend/resume) and surface management. | 100 | (start/stop/suspend/resume) and surface management. |
514 | 101 | |||
515 | 102 | Package: qtmir-tests | ||
516 | 103 | Architecture: any | ||
517 | 104 | Multi-Arch: same | ||
518 | 105 | Pre-Depends: ${misc:Pre-Depends}, | ||
519 | 106 | Depends: autopilot-qt5, | ||
520 | 107 | littler, | ||
521 | 108 | lttng-tools, | ||
522 | 109 | mir-test-tools, | ||
523 | 110 | python3-autopilot, | ||
524 | 111 | python3-babeltrace, | ||
525 | 112 | python3-evdev, | ||
526 | 113 | python3-mir-perf-framework, | ||
527 | 114 | qtmir-desktop (= ${source:Version}) | qtmir-android (= ${source:Version}), | ||
528 | 115 | qtdeclarative5-qtmir-plugin, | ||
529 | 116 | ${misc:Depends}, | ||
530 | 117 | ${shlibs:Depends}, | ||
531 | 118 | Description: QtMir tests and demos | ||
532 | 119 | This package provides benchmark tests and a simple shell and client using the | ||
533 | 120 | QtMir QPA. | ||
534 | 101 | 121 | ||
535 | === added file 'debian/qtmir-tests.install' | |||
536 | --- debian/qtmir-tests.install 1970-01-01 00:00:00 +0000 | |||
537 | +++ debian/qtmir-tests.install 2015-10-14 13:06:12 +0000 | |||
538 | @@ -0,0 +1,6 @@ | |||
539 | 1 | usr/bin/qtmir-demo-shell | ||
540 | 2 | usr/bin/qtmir-demo-client | ||
541 | 3 | usr/share/applications/qtmir-demo-client.desktop | ||
542 | 4 | usr/share/qtmir/qtmir-demo-shell/ | ||
543 | 5 | usr/share/qtmir/qtmir-demo-client/* | ||
544 | 6 | usr/share/qtmir/benchmarks/* | ||
545 | 0 | 7 | ||
546 | === modified file 'debian/rules' | |||
547 | --- debian/rules 2015-10-14 13:06:12 +0000 | |||
548 | +++ debian/rules 2015-10-14 13:06:12 +0000 | |||
549 | @@ -59,4 +59,4 @@ | |||
550 | 59 | endif | 59 | endif |
551 | 60 | dh_install --sourcedir=$(TMP2_DIR) -pqtmir-desktop | 60 | dh_install --sourcedir=$(TMP2_DIR) -pqtmir-desktop |
552 | 61 | dh_install --sourcedir=$(TMP2_DIR) -pqtdeclarative5-qtmir-plugin | 61 | dh_install --sourcedir=$(TMP2_DIR) -pqtdeclarative5-qtmir-plugin |
554 | 62 | 62 | dh_install --sourcedir=$(TMP2_DIR) -pqtmir-tests | |
555 | 63 | 63 | ||
556 | === added file 'demos/CMakeLists.txt' | |||
557 | --- demos/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
558 | +++ demos/CMakeLists.txt 2015-10-14 13:06:12 +0000 | |||
559 | @@ -0,0 +1,4 @@ | |||
560 | 1 | configure_file(paths.h.in ${CMAKE_CURRENT_BINARY_DIR}/paths.h @ONLY) | ||
561 | 2 | |||
562 | 3 | add_subdirectory(qml-demo-client) | ||
563 | 4 | add_subdirectory(qml-demo-shell) | ||
564 | 0 | \ No newline at end of file | 5 | \ No newline at end of file |
565 | 1 | 6 | ||
566 | === added file 'demos/paths.h.in' | |||
567 | --- demos/paths.h.in 1970-01-01 00:00:00 +0000 | |||
568 | +++ demos/paths.h.in 2015-10-14 13:06:12 +0000 | |||
569 | @@ -0,0 +1,40 @@ | |||
570 | 1 | /* | ||
571 | 2 | * Copyright (C) 2015 Canonical, Ltd. | ||
572 | 3 | * | ||
573 | 4 | * This program is free software; you can redistribute it and/or modify | ||
574 | 5 | * it under the terms of the GNU General Public License as published by | ||
575 | 6 | * the Free Software Foundation; version 3. | ||
576 | 7 | * | ||
577 | 8 | * This program is distributed in the hope that it will be useful, | ||
578 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
579 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
580 | 11 | * GNU General Public License for more details. | ||
581 | 12 | * | ||
582 | 13 | * You should have received a copy of the GNU General Public License | ||
583 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
584 | 15 | */ | ||
585 | 16 | |||
586 | 17 | #ifndef PATHS_H | ||
587 | 18 | #define PATHS_H | ||
588 | 19 | |||
589 | 20 | // Qt | ||
590 | 21 | #include <QtCore/QCoreApplication> | ||
591 | 22 | #include <QtCore/QDir> | ||
592 | 23 | #include <QtGui/QIcon> | ||
593 | 24 | #include <QtQml/QQmlEngine> | ||
594 | 25 | #include <QStandardPaths> | ||
595 | 26 | |||
596 | 27 | inline bool isRunningInstalled() { | ||
597 | 28 | static bool installed = (QCoreApplication::applicationDirPath() == | ||
598 | 29 | QDir(("@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@")).canonicalPath()); | ||
599 | 30 | return installed; | ||
600 | 31 | } | ||
601 | 32 | |||
602 | 33 | inline QString qmlDirectory() { | ||
603 | 34 | if (isRunningInstalled()) { | ||
604 | 35 | return QString("@CMAKE_INSTALL_PREFIX@/@QTMIR_DATA_DIR@/"); | ||
605 | 36 | } else { | ||
606 | 37 | return QString("@CMAKE_SOURCE_DIR@/demos/"); | ||
607 | 38 | } | ||
608 | 39 | } | ||
609 | 40 | #endif | ||
610 | 0 | \ No newline at end of file | 41 | \ No newline at end of file |
611 | 1 | 42 | ||
612 | === added file 'demos/qml-demo-client/CMakeLists.txt' | |||
613 | --- demos/qml-demo-client/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
614 | +++ demos/qml-demo-client/CMakeLists.txt 2015-10-14 13:06:12 +0000 | |||
615 | @@ -0,0 +1,41 @@ | |||
616 | 1 | set(DEMO_CLIENT qtmir-demo-client) | ||
617 | 2 | configure_file(${DEMO_CLIENT}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${DEMO_CLIENT}.desktop @ONLY) | ||
618 | 3 | |||
619 | 4 | include_directories( | ||
620 | 5 | ${Qt5Gui_PRIVATE_INCLUDE_DIRS} | ||
621 | 6 | ) | ||
622 | 7 | |||
623 | 8 | add_executable(${DEMO_CLIENT} | ||
624 | 9 | main.cpp | ||
625 | 10 | ) | ||
626 | 11 | |||
627 | 12 | include_directories( | ||
628 | 13 | ${Qt5Gui_PRIVATE_INCLUDE_DIRS} | ||
629 | 14 | ${Qt5Qml_PRIVATE_INCLUDE_DIRS} | ||
630 | 15 | ${Qt5Quick_PRIVATE_INCLUDE_DIRS} | ||
631 | 16 | ) | ||
632 | 17 | |||
633 | 18 | target_link_libraries( | ||
634 | 19 | ${DEMO_CLIENT} | ||
635 | 20 | Qt5::Core | ||
636 | 21 | Qt5::DBus | ||
637 | 22 | Qt5::Qml | ||
638 | 23 | Qt5::Quick | ||
639 | 24 | ) | ||
640 | 25 | |||
641 | 26 | file(GLOB QML_JS_FILES *.qml *.js *.png) | ||
642 | 27 | |||
643 | 28 | # install binaries | ||
644 | 29 | install(TARGETS ${DEMO_CLIENT} | ||
645 | 30 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} | ||
646 | 31 | ) | ||
647 | 32 | |||
648 | 33 | install(FILES | ||
649 | 34 | ${QML_JS_FILES} | ||
650 | 35 | DESTINATION ${QTMIR_DATA_DIR}/${DEMO_CLIENT} | ||
651 | 36 | ) | ||
652 | 37 | |||
653 | 38 | install(FILES | ||
654 | 39 | ${CMAKE_CURRENT_BINARY_DIR}/${DEMO_CLIENT}.desktop | ||
655 | 40 | DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications | ||
656 | 41 | ) | ||
657 | 0 | \ No newline at end of file | 42 | \ No newline at end of file |
658 | 1 | 43 | ||
659 | === added file 'demos/qml-demo-client/main.cpp' | |||
660 | --- demos/qml-demo-client/main.cpp 1970-01-01 00:00:00 +0000 | |||
661 | +++ demos/qml-demo-client/main.cpp 2015-10-14 13:06:12 +0000 | |||
662 | @@ -0,0 +1,73 @@ | |||
663 | 1 | /* | ||
664 | 2 | * Copyright (C) 2012-2015 Canonical, Ltd. | ||
665 | 3 | * | ||
666 | 4 | * This program is free software; you can redistribute it and/or modify | ||
667 | 5 | * it under the terms of the GNU General Public License as published by | ||
668 | 6 | * the Free Software Foundation; version 3. | ||
669 | 7 | * | ||
670 | 8 | * This program is distributed in the hope that it will be useful, | ||
671 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
672 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
673 | 11 | * GNU General Public License for more details. | ||
674 | 12 | * | ||
675 | 13 | * You should have received a copy of the GNU General Public License | ||
676 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
677 | 15 | */ | ||
678 | 16 | |||
679 | 17 | // Qt | ||
680 | 18 | #include <QtQuick/QQuickView> | ||
681 | 19 | #include <QtGui/QGuiApplication> | ||
682 | 20 | #include <QDebug> | ||
683 | 21 | #include <csignal> | ||
684 | 22 | #include <libintl.h> | ||
685 | 23 | #include <getopt.h> | ||
686 | 24 | #include "../paths.h" | ||
687 | 25 | |||
688 | 26 | // REMOVEME - Should be able to use qmlscene, but in order to use the mir benchmarking we need | ||
689 | 27 | // to parse command line switches. Wait until MIR_SOCKET supported by the benchmark framework. | ||
690 | 28 | |||
691 | 29 | int main(int argc, char **argv) | ||
692 | 30 | { | ||
693 | 31 | int arg; | ||
694 | 32 | opterr = 0; | ||
695 | 33 | while ((arg = getopt (argc, argv, "hm:")) != -1) | ||
696 | 34 | { | ||
697 | 35 | switch (arg) | ||
698 | 36 | { | ||
699 | 37 | case 'm': | ||
700 | 38 | setenv("MIR_SOCKET", optarg, 1); | ||
701 | 39 | break; | ||
702 | 40 | |||
703 | 41 | case '?': | ||
704 | 42 | case 'h': | ||
705 | 43 | default: | ||
706 | 44 | puts(argv[0]); | ||
707 | 45 | puts("Usage:"); | ||
708 | 46 | puts(" -m <Mir server socket>"); | ||
709 | 47 | puts(" -h: this help text"); | ||
710 | 48 | return -1; | ||
711 | 49 | } | ||
712 | 50 | } | ||
713 | 51 | |||
714 | 52 | QGuiApplication::setApplicationName("qml-demo-client"); | ||
715 | 53 | QGuiApplication *application; | ||
716 | 54 | |||
717 | 55 | application = new QGuiApplication(argc, (char**)argv); | ||
718 | 56 | QQuickView* view = new QQuickView(); | ||
719 | 57 | view->setResizeMode(QQuickView::SizeRootObjectToView); | ||
720 | 58 | view->setColor("black"); | ||
721 | 59 | view->setTitle("Demo Client"); | ||
722 | 60 | |||
723 | 61 | QUrl source(::qmlDirectory() + "qtmir-demo-client/qml-demo-client.qml"); | ||
724 | 62 | |||
725 | 63 | view->setSource(source); | ||
726 | 64 | QObject::connect(view->engine(), SIGNAL(quit()), application, SLOT(quit())); | ||
727 | 65 | |||
728 | 66 | view->showFullScreen(); | ||
729 | 67 | int result = application->exec(); | ||
730 | 68 | |||
731 | 69 | delete view; | ||
732 | 70 | delete application; | ||
733 | 71 | |||
734 | 72 | return result; | ||
735 | 73 | } | ||
736 | 0 | 74 | ||
737 | === added file 'demos/qml-demo-client/qtmir-demo-client.desktop.in' | |||
738 | --- demos/qml-demo-client/qtmir-demo-client.desktop.in 1970-01-01 00:00:00 +0000 | |||
739 | +++ demos/qml-demo-client/qtmir-demo-client.desktop.in 2015-10-14 13:06:12 +0000 | |||
740 | @@ -0,0 +1,9 @@ | |||
741 | 1 | [Desktop Entry] | ||
742 | 2 | Type=Application | ||
743 | 3 | Name=QtMir Demo Client | ||
744 | 4 | Comment=QtMir demo client | ||
745 | 5 | Exec=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/qtmir-demo-client | ||
746 | 6 | Terminal=false | ||
747 | 7 | Icon= | ||
748 | 8 | NoDisplay=false | ||
749 | 9 | X-Ubuntu-Touch=true | ||
750 | 0 | 10 | ||
751 | === added file 'demos/qml-demo-shell/CMakeLists.txt' | |||
752 | --- demos/qml-demo-shell/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
753 | +++ demos/qml-demo-shell/CMakeLists.txt 2015-10-14 13:06:12 +0000 | |||
754 | @@ -0,0 +1,35 @@ | |||
755 | 1 | set(DEMO_SHELL qtmir-demo-shell) | ||
756 | 2 | |||
757 | 3 | include_directories( | ||
758 | 4 | ${Qt5Gui_PRIVATE_INCLUDE_DIRS} | ||
759 | 5 | ) | ||
760 | 6 | |||
761 | 7 | add_executable(${DEMO_SHELL} | ||
762 | 8 | main.cpp | ||
763 | 9 | ) | ||
764 | 10 | |||
765 | 11 | include_directories( | ||
766 | 12 | ${Qt5Gui_PRIVATE_INCLUDE_DIRS} | ||
767 | 13 | ${Qt5Qml_PRIVATE_INCLUDE_DIRS} | ||
768 | 14 | ${Qt5Quick_PRIVATE_INCLUDE_DIRS} | ||
769 | 15 | ) | ||
770 | 16 | |||
771 | 17 | target_link_libraries( | ||
772 | 18 | ${DEMO_SHELL} | ||
773 | 19 | Qt5::Core | ||
774 | 20 | Qt5::DBus | ||
775 | 21 | Qt5::Qml | ||
776 | 22 | Qt5::Quick | ||
777 | 23 | ) | ||
778 | 24 | |||
779 | 25 | file(GLOB QML_JS_FILES *.qml *.js *.png) | ||
780 | 26 | |||
781 | 27 | # install binaries | ||
782 | 28 | install(TARGETS ${DEMO_SHELL} | ||
783 | 29 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} | ||
784 | 30 | ) | ||
785 | 31 | |||
786 | 32 | install(FILES | ||
787 | 33 | ${QML_JS_FILES} | ||
788 | 34 | DESTINATION ${QTMIR_DATA_DIR}/${DEMO_SHELL} | ||
789 | 35 | ) | ||
790 | 0 | 36 | ||
791 | === added file 'demos/qml-demo-shell/main.cpp' | |||
792 | --- demos/qml-demo-shell/main.cpp 1970-01-01 00:00:00 +0000 | |||
793 | +++ demos/qml-demo-shell/main.cpp 2015-10-14 13:06:12 +0000 | |||
794 | @@ -0,0 +1,57 @@ | |||
795 | 1 | /* | ||
796 | 2 | * Copyright (C) 2012-2015 Canonical, Ltd. | ||
797 | 3 | * | ||
798 | 4 | * This program is free software; you can redistribute it and/or modify | ||
799 | 5 | * it under the terms of the GNU General Public License as published by | ||
800 | 6 | * the Free Software Foundation; version 3. | ||
801 | 7 | * | ||
802 | 8 | * This program is distributed in the hope that it will be useful, | ||
803 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
804 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
805 | 11 | * GNU General Public License for more details. | ||
806 | 12 | * | ||
807 | 13 | * You should have received a copy of the GNU General Public License | ||
808 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
809 | 15 | */ | ||
810 | 16 | |||
811 | 17 | // Qt | ||
812 | 18 | #include <QCommandLineParser> | ||
813 | 19 | #include <QtQuick/QQuickView> | ||
814 | 20 | #include <QtGui/QGuiApplication> | ||
815 | 21 | #include <QtQml/QQmlEngine> | ||
816 | 22 | #include <QtQml/QQmlContext> | ||
817 | 23 | #include <QLibrary> | ||
818 | 24 | #include <QDebug> | ||
819 | 25 | #include <csignal> | ||
820 | 26 | #include <libintl.h> | ||
821 | 27 | #include "../paths.h" | ||
822 | 28 | |||
823 | 29 | #include <private/qobject_p.h> | ||
824 | 30 | |||
825 | 31 | // REMOVEME - Should be able to use qmlscene, but in order to use the mir benchmarking we need | ||
826 | 32 | // to parse command line switches. Wait until MIR_SOCKET supported by the benchmark framework. | ||
827 | 33 | |||
828 | 34 | int main(int argc, const char *argv[]) | ||
829 | 35 | { | ||
830 | 36 | QGuiApplication::setApplicationName("qml-demo-shell"); | ||
831 | 37 | QGuiApplication *application; | ||
832 | 38 | |||
833 | 39 | application = new QGuiApplication(argc, (char**)argv); | ||
834 | 40 | QQuickView* view = new QQuickView(); | ||
835 | 41 | view->setResizeMode(QQuickView::SizeRootObjectToView); | ||
836 | 42 | view->setColor("black"); | ||
837 | 43 | view->setTitle("Demo Shell"); | ||
838 | 44 | |||
839 | 45 | QUrl source(::qmlDirectory() + "qtmir-demo-shell/qml-demo-shell.qml"); | ||
840 | 46 | |||
841 | 47 | view->setSource(source); | ||
842 | 48 | QObject::connect(view->engine(), SIGNAL(quit()), application, SLOT(quit())); | ||
843 | 49 | |||
844 | 50 | view->showFullScreen(); | ||
845 | 51 | int result = application->exec(); | ||
846 | 52 | |||
847 | 53 | delete view; | ||
848 | 54 | delete application; | ||
849 | 55 | |||
850 | 56 | return result; | ||
851 | 57 | } | ||
852 | 0 | 58 | ||
853 | === added file 'src/common/timestamp.cpp' | |||
854 | --- src/common/timestamp.cpp 1970-01-01 00:00:00 +0000 | |||
855 | +++ src/common/timestamp.cpp 2015-10-14 13:06:12 +0000 | |||
856 | @@ -0,0 +1,18 @@ | |||
857 | 1 | |||
858 | 2 | #include <chrono> | ||
859 | 3 | #include "timestamp_impl.h" | ||
860 | 4 | |||
861 | 5 | std::chrono::nanoseconds appStartTime(0); | ||
862 | 6 | |||
863 | 7 | void resetStartTime(std::chrono::nanoseconds timestamp) | ||
864 | 8 | { | ||
865 | 9 | appStartTime = timestamp; | ||
866 | 10 | } | ||
867 | 11 | |||
868 | 12 | std::chrono::nanoseconds getStartTime(std::chrono::nanoseconds timestamp, bool allowReset) | ||
869 | 13 | { | ||
870 | 14 | if (allowReset && appStartTime.count() == 0) { | ||
871 | 15 | resetStartTime(timestamp); | ||
872 | 16 | } | ||
873 | 17 | return appStartTime; | ||
874 | 18 | } | ||
875 | 0 | 19 | ||
876 | === added file 'src/common/timestamp.h' | |||
877 | --- src/common/timestamp.h 1970-01-01 00:00:00 +0000 | |||
878 | +++ src/common/timestamp.h 2015-10-14 13:06:12 +0000 | |||
879 | @@ -0,0 +1,39 @@ | |||
880 | 1 | /* | ||
881 | 2 | * Copyright (C) 2015 Canonical, Ltd. | ||
882 | 3 | * | ||
883 | 4 | * This program is free software: you can redistribute it and/or modify it under | ||
884 | 5 | * the terms of the GNU Lesser General Public License version 3, as published by | ||
885 | 6 | * the Free Software Foundation. | ||
886 | 7 | * | ||
887 | 8 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
888 | 9 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, | ||
889 | 10 | * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
890 | 11 | * Lesser General Public License for more details. | ||
891 | 12 | * | ||
892 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
893 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
894 | 15 | */ | ||
895 | 16 | |||
896 | 17 | #ifndef QTMIR_TIMESTAMP_H | ||
897 | 18 | #define QTMIR_TIMESTAMP_H | ||
898 | 19 | |||
899 | 20 | #include <QtCore/qglobal.h> | ||
900 | 21 | #include <chrono> | ||
901 | 22 | |||
902 | 23 | namespace qtmir { | ||
903 | 24 | |||
904 | 25 | // Converts a mir timestamp (in nanoseconds) to and from a timestamp in milliseconds. | ||
905 | 26 | // Qt system events only work with ulong timestamps. On 32bit archs a ulong is 4 bytes long, so the 64 bit nanoseconds | ||
906 | 27 | // will be truncated and skewed. In order to fix this, we truncate the result by using time since "first call" | ||
907 | 28 | template<typename T> | ||
908 | 29 | T compressTimestamp(std::chrono::nanoseconds timestamp); | ||
909 | 30 | |||
910 | 31 | // "Re-inflate" a truncated timestamp. | ||
911 | 32 | template<typename T> | ||
912 | 33 | std::chrono::nanoseconds uncompressTimestamp(T timestamp); | ||
913 | 34 | |||
914 | 35 | } | ||
915 | 36 | |||
916 | 37 | #include "timestamp_impl.h" | ||
917 | 38 | |||
918 | 39 | #endif // QTMIR_TIMESTAMP_H | ||
919 | 0 | 40 | ||
920 | === added file 'src/common/timestamp_impl.h' | |||
921 | --- src/common/timestamp_impl.h 1970-01-01 00:00:00 +0000 | |||
922 | +++ src/common/timestamp_impl.h 2015-10-14 13:06:12 +0000 | |||
923 | @@ -0,0 +1,34 @@ | |||
924 | 1 | #include <QCoreApplication> | ||
925 | 2 | #include <QVariant> | ||
926 | 3 | |||
927 | 4 | extern "C" { | ||
928 | 5 | void resetStartTime(std::chrono::nanoseconds timestamp); | ||
929 | 6 | std::chrono::nanoseconds getStartTime(std::chrono::nanoseconds timestamp, bool allowReset = true); | ||
930 | 7 | } | ||
931 | 8 | |||
932 | 9 | namespace qtmir { | ||
933 | 10 | |||
934 | 11 | template<typename T> | ||
935 | 12 | T compressTimestamp(std::chrono::nanoseconds timestamp) | ||
936 | 13 | { | ||
937 | 14 | std::chrono::nanoseconds startTime = getStartTime(timestamp); | ||
938 | 15 | std::chrono::nanoseconds result = timestamp - startTime; | ||
939 | 16 | |||
940 | 17 | if (std::numeric_limits<std::chrono::nanoseconds::rep>::max() > std::numeric_limits<T>::max() && | ||
941 | 18 | result > std::chrono::nanoseconds(std::numeric_limits<T>::max())) { | ||
942 | 19 | // we've overflowed the boundaries of the millisecond type. | ||
943 | 20 | resetStartTime(timestamp); | ||
944 | 21 | return 0; | ||
945 | 22 | } | ||
946 | 23 | |||
947 | 24 | return result.count(); | ||
948 | 25 | } | ||
949 | 26 | |||
950 | 27 | template<typename T> | ||
951 | 28 | std::chrono::nanoseconds uncompressTimestamp(T timestamp) | ||
952 | 29 | { | ||
953 | 30 | auto tsNS = std::chrono::nanoseconds(timestamp); | ||
954 | 31 | return getStartTime(tsNS, false) + std::chrono::nanoseconds(tsNS); | ||
955 | 32 | } | ||
956 | 33 | |||
957 | 34 | } | ||
958 | 0 | \ No newline at end of file | 35 | \ No newline at end of file |
959 | 1 | 36 | ||
960 | === modified file 'src/modules/Unity/Application/mirsurface.cpp' | |||
961 | --- src/modules/Unity/Application/mirsurface.cpp 2015-10-14 13:06:12 +0000 | |||
962 | +++ src/modules/Unity/Application/mirsurface.cpp 2015-10-14 13:06:12 +0000 | |||
963 | @@ -15,6 +15,7 @@ | |||
964 | 15 | */ | 15 | */ |
965 | 16 | 16 | ||
966 | 17 | #include "mirsurface.h" | 17 | #include "mirsurface.h" |
967 | 18 | #include "timestamp.h" | ||
968 | 18 | 19 | ||
969 | 19 | // mirserver | 20 | // mirserver |
970 | 20 | #include <surfaceobserver.h> | 21 | #include <surfaceobserver.h> |
971 | @@ -51,7 +52,7 @@ | |||
972 | 51 | 52 | ||
973 | 52 | mir::EventUPtr makeMirEvent(QMouseEvent *qtEvent, MirPointerAction action) | 53 | mir::EventUPtr makeMirEvent(QMouseEvent *qtEvent, MirPointerAction action) |
974 | 53 | { | 54 | { |
976 | 54 | auto timestamp = std::chrono::milliseconds(qtEvent->timestamp()); | 55 | auto timestamp = uncompressTimestamp<ulong>(qtEvent->timestamp()); |
977 | 55 | auto modifiers = getMirModifiersFromQt(qtEvent->modifiers()); | 56 | auto modifiers = getMirModifiersFromQt(qtEvent->modifiers()); |
978 | 56 | 57 | ||
979 | 57 | MirPointerButtons buttons = 0; | 58 | MirPointerButtons buttons = 0; |
980 | @@ -68,7 +69,7 @@ | |||
981 | 68 | 69 | ||
982 | 69 | mir::EventUPtr makeMirEvent(QHoverEvent *qtEvent, MirPointerAction action) | 70 | mir::EventUPtr makeMirEvent(QHoverEvent *qtEvent, MirPointerAction action) |
983 | 70 | { | 71 | { |
985 | 71 | auto timestamp = std::chrono::milliseconds(qtEvent->timestamp()); | 72 | auto timestamp = uncompressTimestamp<ulong>(qtEvent->timestamp()); |
986 | 72 | 73 | ||
987 | 73 | MirPointerButtons buttons = 0; | 74 | MirPointerButtons buttons = 0; |
988 | 74 | 75 | ||
989 | @@ -93,7 +94,7 @@ | |||
990 | 93 | if (qtEvent->isAutoRepeat()) | 94 | if (qtEvent->isAutoRepeat()) |
991 | 94 | action = mir_keyboard_action_repeat; | 95 | action = mir_keyboard_action_repeat; |
992 | 95 | 96 | ||
994 | 96 | return mir::events::make_event(0 /* DeviceID */, std::chrono::milliseconds(qtEvent->timestamp()), | 97 | return mir::events::make_event(0 /* DeviceID */, uncompressTimestamp<ulong>(qtEvent->timestamp()), |
995 | 97 | 0 /* mac */, action, qtEvent->nativeVirtualKey(), | 98 | 0 /* mac */, action, qtEvent->nativeVirtualKey(), |
996 | 98 | qtEvent->nativeScanCode(), | 99 | qtEvent->nativeScanCode(), |
997 | 99 | qtEvent->nativeModifiers()); | 100 | qtEvent->nativeModifiers()); |
998 | @@ -105,7 +106,7 @@ | |||
999 | 105 | ulong qtTimestamp) | 106 | ulong qtTimestamp) |
1000 | 106 | { | 107 | { |
1001 | 107 | auto modifiers = getMirModifiersFromQt(qmods); | 108 | auto modifiers = getMirModifiersFromQt(qmods); |
1003 | 108 | auto ev = mir::events::make_event(0, std::chrono::milliseconds(qtTimestamp), | 109 | auto ev = mir::events::make_event(0, uncompressTimestamp<ulong>(qtTimestamp), |
1004 | 109 | 0 /* mac */, modifiers); | 110 | 0 /* mac */, modifiers); |
1005 | 110 | 111 | ||
1006 | 111 | for (int i = 0; i < qtTouchPoints.count(); ++i) { | 112 | for (int i = 0; i < qtTouchPoints.count(); ++i) { |
1007 | 112 | 113 | ||
1008 | === modified file 'src/modules/Unity/Application/mirsurfaceitem.cpp' | |||
1009 | --- src/modules/Unity/Application/mirsurfaceitem.cpp 2015-10-14 13:06:12 +0000 | |||
1010 | +++ src/modules/Unity/Application/mirsurfaceitem.cpp 2015-10-14 13:06:12 +0000 | |||
1011 | @@ -20,6 +20,8 @@ | |||
1012 | 20 | #include "mirsurfaceitem.h" | 20 | #include "mirsurfaceitem.h" |
1013 | 21 | #include "logging.h" | 21 | #include "logging.h" |
1014 | 22 | #include "ubuntukeyboardinfo.h" | 22 | #include "ubuntukeyboardinfo.h" |
1015 | 23 | #include "tracepoints.h" // generated from tracepoints.tp | ||
1016 | 24 | #include "timestamp.h" | ||
1017 | 23 | 25 | ||
1018 | 24 | // common | 26 | // common |
1019 | 25 | #include <debughelpers.h> | 27 | #include <debughelpers.h> |
1020 | @@ -409,10 +411,14 @@ | |||
1021 | 409 | m_lastTouchEvent->timestamp = timestamp; | 411 | m_lastTouchEvent->timestamp = timestamp; |
1022 | 410 | m_lastTouchEvent->touchPoints = touchPoints; | 412 | m_lastTouchEvent->touchPoints = touchPoints; |
1023 | 411 | m_lastTouchEvent->touchPointStates = touchPointStates; | 413 | m_lastTouchEvent->touchPointStates = touchPointStates; |
1024 | 414 | |||
1025 | 415 | tracepoint(qtmir, touchEventConsume_end, uncompressTimestamp<ulong>(timestamp).count()); | ||
1026 | 412 | } | 416 | } |
1027 | 413 | 417 | ||
1028 | 414 | void MirSurfaceItem::touchEvent(QTouchEvent *event) | 418 | void MirSurfaceItem::touchEvent(QTouchEvent *event) |
1029 | 415 | { | 419 | { |
1030 | 420 | tracepoint(qtmir, touchEventConsume_start, uncompressTimestamp<ulong>(event->timestamp()).count()); | ||
1031 | 421 | |||
1032 | 416 | bool accepted = processTouchEvent(event->type(), | 422 | bool accepted = processTouchEvent(event->type(), |
1033 | 417 | event->timestamp(), | 423 | event->timestamp(), |
1034 | 418 | event->modifiers(), | 424 | event->modifiers(), |
1035 | 419 | 425 | ||
1036 | === modified file 'src/modules/Unity/Application/tracepoints.tp' | |||
1037 | --- src/modules/Unity/Application/tracepoints.tp 2014-09-04 11:11:26 +0000 | |||
1038 | +++ src/modules/Unity/Application/tracepoints.tp 2015-10-14 13:06:12 +0000 | |||
1039 | @@ -1,3 +1,5 @@ | |||
1040 | 1 | #include <stdint.h> | ||
1041 | 2 | |||
1042 | 1 | TRACEPOINT_EVENT(qtmir, startApplication, TP_ARGS(0), TP_FIELDS()) | 3 | TRACEPOINT_EVENT(qtmir, startApplication, TP_ARGS(0), TP_FIELDS()) |
1043 | 2 | TRACEPOINT_EVENT(qtmir, onProcessStarting, TP_ARGS(0), TP_FIELDS()) | 4 | TRACEPOINT_EVENT(qtmir, onProcessStarting, TP_ARGS(0), TP_FIELDS()) |
1044 | 3 | TRACEPOINT_EVENT(qtmir, authorizeSession, TP_ARGS(0), TP_FIELDS()) | 5 | TRACEPOINT_EVENT(qtmir, authorizeSession, TP_ARGS(0), TP_FIELDS()) |
1045 | @@ -7,3 +9,6 @@ | |||
1046 | 7 | TRACEPOINT_EVENT(qtmir, firstFrameDrawn, TP_ARGS(0), TP_FIELDS()) | 9 | TRACEPOINT_EVENT(qtmir, firstFrameDrawn, TP_ARGS(0), TP_FIELDS()) |
1047 | 8 | TRACEPOINT_EVENT(qtmir, appIdHasProcessId_start, TP_ARGS(0), TP_FIELDS()) | 10 | TRACEPOINT_EVENT(qtmir, appIdHasProcessId_start, TP_ARGS(0), TP_FIELDS()) |
1048 | 9 | TRACEPOINT_EVENT(qtmir, appIdHasProcessId_end, TP_ARGS(int, found), TP_FIELDS(ctf_integer(int, found, found))) | 11 | TRACEPOINT_EVENT(qtmir, appIdHasProcessId_end, TP_ARGS(int, found), TP_FIELDS(ctf_integer(int, found, found))) |
1049 | 12 | |||
1050 | 13 | TRACEPOINT_EVENT(qtmir, touchEventConsume_start, TP_ARGS(int64_t, event_time), TP_FIELDS(ctf_integer(int64_t, event_time, event_time))) | ||
1051 | 14 | TRACEPOINT_EVENT(qtmir, touchEventConsume_end, TP_ARGS(int64_t, event_time), TP_FIELDS(ctf_integer(int64_t, event_time, event_time))) | ||
1052 | 10 | 15 | ||
1053 | === modified file 'src/platforms/mirserver/CMakeLists.txt' | |||
1054 | --- src/platforms/mirserver/CMakeLists.txt 2015-10-14 13:06:12 +0000 | |||
1055 | +++ src/platforms/mirserver/CMakeLists.txt 2015-10-14 13:06:12 +0000 | |||
1056 | @@ -42,6 +42,7 @@ | |||
1057 | 42 | 42 | ||
1058 | 43 | set(MIRSERVER_QPA_PLUGIN_SRC | 43 | set(MIRSERVER_QPA_PLUGIN_SRC |
1059 | 44 | ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp | 44 | ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp |
1060 | 45 | ${CMAKE_SOURCE_DIR}/src/common/timestamp.cpp | ||
1061 | 45 | cursor.cpp | 46 | cursor.cpp |
1062 | 46 | mirwindowmanager.cpp | 47 | mirwindowmanager.cpp |
1063 | 47 | mirsingleton.cpp | 48 | mirsingleton.cpp |
1064 | 48 | 49 | ||
1065 | === modified file 'src/platforms/mirserver/qteventfeeder.cpp' | |||
1066 | --- src/platforms/mirserver/qteventfeeder.cpp 2015-10-14 13:06:12 +0000 | |||
1067 | +++ src/platforms/mirserver/qteventfeeder.cpp 2015-10-14 13:06:12 +0000 | |||
1068 | @@ -17,6 +17,8 @@ | |||
1069 | 17 | #include "qteventfeeder.h" | 17 | #include "qteventfeeder.h" |
1070 | 18 | #include "cursor.h" | 18 | #include "cursor.h" |
1071 | 19 | #include "logging.h" | 19 | #include "logging.h" |
1072 | 20 | #include "timestamp.h" | ||
1073 | 21 | #include "tracepoints.h" // generated from tracepoints.tp | ||
1074 | 20 | #include "screen.h" // NEEDED? | 22 | #include "screen.h" // NEEDED? |
1075 | 21 | #include "screencontroller.h" | 23 | #include "screencontroller.h" |
1076 | 22 | 24 | ||
1077 | @@ -530,7 +532,7 @@ | |||
1078 | 530 | 532 | ||
1079 | 531 | void QtEventFeeder::dispatchPointer(MirInputEvent const* ev) | 533 | void QtEventFeeder::dispatchPointer(MirInputEvent const* ev) |
1080 | 532 | { | 534 | { |
1082 | 533 | auto timestamp = mir_input_event_get_event_time(ev) / 1000000; | 535 | auto timestamp = qtmir::compressTimestamp<ulong>(std::chrono::nanoseconds(mir_input_event_get_event_time(ev))); |
1083 | 534 | 536 | ||
1084 | 535 | auto pev = mir_input_event_get_pointer_event(ev); | 537 | auto pev = mir_input_event_get_pointer_event(ev); |
1085 | 536 | qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirPointerEventToString(pev)); | 538 | qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirPointerEventToString(pev)); |
1086 | @@ -546,7 +548,7 @@ | |||
1087 | 546 | 548 | ||
1088 | 547 | void QtEventFeeder::dispatchKey(MirInputEvent const* event) | 549 | void QtEventFeeder::dispatchKey(MirInputEvent const* event) |
1089 | 548 | { | 550 | { |
1091 | 549 | ulong timestamp = mir_input_event_get_event_time(event) / 1000000; | 551 | auto timestamp = qtmir::compressTimestamp<ulong>(std::chrono::nanoseconds(mir_input_event_get_event_time(event))); |
1092 | 550 | 552 | ||
1093 | 551 | auto kev = mir_input_event_get_keyboard_event(event); | 553 | auto kev = mir_input_event_get_keyboard_event(event); |
1094 | 552 | xkb_keysym_t xk_sym = mir_keyboard_event_key_code(kev); | 554 | xkb_keysym_t xk_sym = mir_keyboard_event_key_code(kev); |
1095 | @@ -605,6 +607,10 @@ | |||
1096 | 605 | 607 | ||
1097 | 606 | void QtEventFeeder::dispatchTouch(MirInputEvent const* event) | 608 | void QtEventFeeder::dispatchTouch(MirInputEvent const* event) |
1098 | 607 | { | 609 | { |
1099 | 610 | auto timestamp = std::chrono::nanoseconds(mir_input_event_get_event_time(event)); | ||
1100 | 611 | |||
1101 | 612 | tracepoint(qtmirserver, touchEventDispatch_start, timestamp.count()); | ||
1102 | 613 | |||
1103 | 608 | auto tev = mir_input_event_get_touch_event(event); | 614 | auto tev = mir_input_event_get_touch_event(event); |
1104 | 609 | qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirTouchEventToString(tev)); | 615 | qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirTouchEventToString(tev)); |
1105 | 610 | 616 | ||
1106 | @@ -661,17 +667,21 @@ | |||
1107 | 661 | } | 667 | } |
1108 | 662 | } | 668 | } |
1109 | 663 | 669 | ||
1110 | 670 | auto compressedTimestamp = qtmir::compressTimestamp<ulong>(timestamp); | ||
1111 | 671 | |||
1112 | 664 | // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding | 672 | // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding |
1113 | 665 | // any insanity. | 673 | // any insanity. |
1115 | 666 | validateTouches(window, mir_input_event_get_event_time(event) / 1000000, touchPoints); | 674 | validateTouches(window, compressedTimestamp, touchPoints); |
1116 | 667 | 675 | ||
1117 | 668 | // Touch event propagation. | 676 | // Touch event propagation. |
1118 | 669 | qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints)); | 677 | qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints)); |
1119 | 670 | mQtWindowSystem->handleTouchEvent(window, | 678 | mQtWindowSystem->handleTouchEvent(window, |
1120 | 671 | //scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable | 679 | //scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable |
1122 | 672 | mir_input_event_get_event_time(event) / 1000000, | 680 | compressedTimestamp, |
1123 | 673 | mTouchDevice, | 681 | mTouchDevice, |
1124 | 674 | touchPoints); | 682 | touchPoints); |
1125 | 683 | |||
1126 | 684 | tracepoint(qtmirserver, touchEventDispatch_end, timestamp.count()); | ||
1127 | 675 | } | 685 | } |
1128 | 676 | 686 | ||
1129 | 677 | void QtEventFeeder::start() | 687 | void QtEventFeeder::start() |
1130 | 678 | 688 | ||
1131 | === modified file 'src/platforms/mirserver/tracepoints.tp' | |||
1132 | --- src/platforms/mirserver/tracepoints.tp 2014-09-22 18:06:58 +0000 | |||
1133 | +++ src/platforms/mirserver/tracepoints.tp 2015-10-14 13:06:12 +0000 | |||
1134 | @@ -1,3 +1,5 @@ | |||
1135 | 1 | #include <stdint.h> | ||
1136 | 2 | |||
1137 | 1 | TRACEPOINT_EVENT(qtmirserver, starting, TP_ARGS(0), TP_FIELDS()) | 3 | TRACEPOINT_EVENT(qtmirserver, starting, TP_ARGS(0), TP_FIELDS()) |
1138 | 2 | TRACEPOINT_EVENT(qtmirserver, stopping, TP_ARGS(0), TP_FIELDS()) | 4 | TRACEPOINT_EVENT(qtmirserver, stopping, TP_ARGS(0), TP_FIELDS()) |
1139 | 3 | TRACEPOINT_EVENT(qtmirserver, surfaceCreated, TP_ARGS(0), TP_FIELDS()) | 5 | TRACEPOINT_EVENT(qtmirserver, surfaceCreated, TP_ARGS(0), TP_FIELDS()) |
1140 | @@ -8,3 +10,6 @@ | |||
1141 | 8 | 10 | ||
1142 | 9 | TRACEPOINT_EVENT(qtmirserver, surfacePlacementStart, TP_ARGS(0), TP_FIELDS()) | 11 | TRACEPOINT_EVENT(qtmirserver, surfacePlacementStart, TP_ARGS(0), TP_FIELDS()) |
1143 | 10 | TRACEPOINT_EVENT(qtmirserver, surfacePlacementEnd, TP_ARGS(0), TP_FIELDS()) | 12 | TRACEPOINT_EVENT(qtmirserver, surfacePlacementEnd, TP_ARGS(0), TP_FIELDS()) |
1144 | 13 | |||
1145 | 14 | TRACEPOINT_EVENT(qtmirserver, touchEventDispatch_start, TP_ARGS(int64_t, event_time), TP_FIELDS(ctf_integer(int64_t, event_time, event_time))) | ||
1146 | 15 | TRACEPOINT_EVENT(qtmirserver, touchEventDispatch_end, TP_ARGS(int64_t, event_time), TP_FIELDS(ctf_integer(int64_t, event_time, event_time))) | ||
1147 | 11 | 16 | ||
1148 | === modified file 'tests/modules/General/CMakeLists.txt' | |||
1149 | --- tests/modules/General/CMakeLists.txt 2014-12-03 08:56:35 +0000 | |||
1150 | +++ tests/modules/General/CMakeLists.txt 2015-10-14 13:06:12 +0000 | |||
1151 | @@ -1,16 +1,13 @@ | |||
1152 | 1 | set( | 1 | set( |
1153 | 2 | GENERAL_TEST_SOURCES | 2 | GENERAL_TEST_SOURCES |
1154 | 3 | objectlistmodel_test.cpp | 3 | objectlistmodel_test.cpp |
1156 | 4 | ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp | 4 | timestamp_test.cpp |
1157 | 5 | ${CMAKE_SOURCE_DIR}/src/common/timestamp.cpp | ||
1158 | 5 | ) | 6 | ) |
1159 | 6 | 7 | ||
1160 | 7 | include_directories( | 8 | include_directories( |
1161 | 8 | ${CMAKE_SOURCE_DIR}/src/platforms/mirserver | ||
1162 | 9 | ${CMAKE_SOURCE_DIR}/src/common | 9 | ${CMAKE_SOURCE_DIR}/src/common |
1163 | 10 | ${CMAKE_SOURCE_DIR}/src/modules | 10 | ${CMAKE_SOURCE_DIR}/src/modules |
1164 | 11 | ${CMAKE_SOURCE_DIR}/tests/modules/common | ||
1165 | 12 | ${Qt5Gui_PRIVATE_INCLUDE_DIRS} | ||
1166 | 13 | ${MIRSERVER_INCLUDE_DIRS} | ||
1167 | 14 | ) | 11 | ) |
1168 | 15 | 12 | ||
1169 | 16 | add_executable(general_test ${GENERAL_TEST_SOURCES}) | 13 | add_executable(general_test ${GENERAL_TEST_SOURCES}) |
1170 | @@ -18,9 +15,6 @@ | |||
1171 | 18 | target_link_libraries( | 15 | target_link_libraries( |
1172 | 19 | general_test | 16 | general_test |
1173 | 20 | 17 | ||
1174 | 21 | qpa-mirserver | ||
1175 | 22 | unityapplicationplugin | ||
1176 | 23 | |||
1177 | 24 | Qt5::Gui | 18 | Qt5::Gui |
1178 | 25 | 19 | ||
1179 | 26 | ${GTEST_BOTH_LIBRARIES} | 20 | ${GTEST_BOTH_LIBRARIES} |
1180 | 27 | 21 | ||
1181 | === added file 'tests/modules/General/timestamp_test.cpp' | |||
1182 | --- tests/modules/General/timestamp_test.cpp 1970-01-01 00:00:00 +0000 | |||
1183 | +++ tests/modules/General/timestamp_test.cpp 2015-10-14 13:06:12 +0000 | |||
1184 | @@ -0,0 +1,72 @@ | |||
1185 | 1 | /* | ||
1186 | 2 | * Copyright (C) 2014-2015 Canonical, Ltd. | ||
1187 | 3 | * | ||
1188 | 4 | * This program is free software: you can redistribute it and/or modify it under | ||
1189 | 5 | * the terms of the GNU Lesser General Public License version 3, as published by | ||
1190 | 6 | * the Free Software Foundation. | ||
1191 | 7 | * | ||
1192 | 8 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
1193 | 9 | * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, | ||
1194 | 10 | * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
1195 | 11 | * Lesser General Public License for more details. | ||
1196 | 12 | * | ||
1197 | 13 | * You should have received a copy of the GNU Lesser General Public License | ||
1198 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1199 | 15 | */ | ||
1200 | 16 | |||
1201 | 17 | #include "timestamp.h" | ||
1202 | 18 | |||
1203 | 19 | #include <gtest/gtest.h> | ||
1204 | 20 | #include <gmock/gmock.h> | ||
1205 | 21 | |||
1206 | 22 | #include <QCoreApplication> | ||
1207 | 23 | #include <QDebug> | ||
1208 | 24 | |||
1209 | 25 | using namespace qtmir; | ||
1210 | 26 | |||
1211 | 27 | TEST(TimestampTest, TestCompressAndUncompress) | ||
1212 | 28 | { | ||
1213 | 29 | using namespace testing; | ||
1214 | 30 | |||
1215 | 31 | int argc = 0; | ||
1216 | 32 | QCoreApplication app(argc, NULL); | ||
1217 | 33 | |||
1218 | 34 | std::chrono::time_point<std::chrono::system_clock> now; | ||
1219 | 35 | now = std::chrono::system_clock::now(); | ||
1220 | 36 | auto original_timestamp = now.time_since_epoch(); | ||
1221 | 37 | |||
1222 | 38 | std::chrono::nanoseconds addToTimestamp(0); | ||
1223 | 39 | for (int i = 0; i < 100; i++) { | ||
1224 | 40 | auto timestamp = original_timestamp + addToTimestamp; | ||
1225 | 41 | |||
1226 | 42 | ulong compressedTimestamp = qtmir::compressTimestamp<ulong>(timestamp); | ||
1227 | 43 | |||
1228 | 44 | EXPECT_EQ(addToTimestamp.count(), compressedTimestamp); | ||
1229 | 45 | EXPECT_EQ(qtmir::uncompressTimestamp<ulong>(compressedTimestamp), timestamp); | ||
1230 | 46 | |||
1231 | 47 | addToTimestamp += std::chrono::milliseconds(1); | ||
1232 | 48 | } | ||
1233 | 49 | } | ||
1234 | 50 | |||
1235 | 51 | TEST(TimestampTest, TestOverflowWhenExceeding32bitCompression) | ||
1236 | 52 | { | ||
1237 | 53 | using namespace testing; | ||
1238 | 54 | |||
1239 | 55 | int argc = 0; | ||
1240 | 56 | QCoreApplication app(argc, NULL); | ||
1241 | 57 | |||
1242 | 58 | std::chrono::time_point<std::chrono::system_clock> now; | ||
1243 | 59 | now = std::chrono::system_clock::now(); | ||
1244 | 60 | auto timestamp = now.time_since_epoch(); | ||
1245 | 61 | |||
1246 | 62 | // Do first compression. This will result in qield of 0 as seen in TestCompressUncompress | ||
1247 | 63 | quint32 compressedTimestamp = qtmir::compressTimestamp<quint32>(timestamp); | ||
1248 | 64 | |||
1249 | 65 | // Add the quint32 limit +1 to get an overflow when we compress the timestamp | ||
1250 | 66 | timestamp += std::chrono::nanoseconds(std::numeric_limits<quint32>::max()) + std::chrono::nanoseconds(1); | ||
1251 | 67 | compressedTimestamp = qtmir::compressTimestamp<quint32>(timestamp); | ||
1252 | 68 | |||
1253 | 69 | EXPECT_EQ(0, compressedTimestamp); | ||
1254 | 70 | // ensure the uncompression will yields the original timestamp | ||
1255 | 71 | EXPECT_EQ(qtmir::uncompressTimestamp<quint32>(compressedTimestamp), timestamp); | ||
1256 | 72 | } | ||
1257 | 0 | \ No newline at end of file | 73 | \ No newline at end of file |
PASSED: Continuous integration, rev:350 jenkins. qa.ubuntu. com/job/ qtmir-ci/ 343/ jenkins. qa.ubuntu. com/job/ qtmir-wily- amd64-ci/ 76 jenkins. qa.ubuntu. com/job/ qtmir-wily- armhf-ci/ 76 jenkins. qa.ubuntu. com/job/ qtmir-wily- armhf-ci/ 76/artifact/ work/output/ *zip*/output. zip
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/qtmir- ci/343/ rebuild
http://