Merge lp:~unity-team/qtmir/touch_tracing into lp:qtmir

Proposed by Nick Dedekind
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
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

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
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/qml-demo-client/main.cpp'
I don't understand what this is useful for. Isn't the "qml" binary sufficient?

=== added file 'demos/qml-demo-shell/main.cpp'
same here.

=== added file 'src/common/utils.h'
file name "utils" as vague as possible:) Can you be more specific?

+++ src/common/utils.cpp
+qint64 resetStartTime(qint64 timestamp) {
+qint64 getStartTime_nsec(qint64 timestamp) {
please stick into an anonymous namespace

The indenting is inconsistent in the whole file.

+ QCoreApplication::instance()->setProperty("appStartTime", timestamp);
I suspect a static variable would do the job just as well.

+ qint64 startTime = getStartTime_nsec(timestamp.count())/1000000;
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 QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w,
    ulong timestamp, const QPointF & local, const QPointF & global,
    Qt::MouseButtons b, Qt::KeyboardModifiers mods,
    Qt::MouseEventSource source)

we could make our own handle*Event() methods. In the end, the above method simply does:

QWindowSystemInterfacePrivate::MouseEvent * e =
    new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp,
        QWindowSystemInterfacePrivate::FrameStrutMouse,
        QHighDpi::fromNativeLocalPosition(local, w),
        QHighDpi::fromNativePixels(global, w), b, mods, source);

QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);

If we subclassed QWindowSystemInterfacePrivate::MouseEvent, and added the 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.
====

std::chrono::milliseconds compressTimestamp(std::chrono::nanoseconds 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/decompression, for future souls.

=== modified file 'src/platforms/mirserver/tracepoints.tp'
Typos:
touchEventDisptach_start
touchEventDisptach_end
and these propagate throughout the whole of mirserver.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
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/qml-demo-client/main.cpp'
> I don't understand what this is useful for. Isn't the "qml" binary sufficient?
>
> === added file 'demos/qml-demo-shell/main.cpp'
> 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/utils.h'
> file name "utils" as vague as possible:) Can you be more specific?

timestamp.h

>
> +++ src/common/utils.cpp
> +qint64 resetStartTime(qint64 timestamp) {
> +qint64 getStartTime_nsec(qint64 timestamp) {
> please stick into an anonymous namespace
>
> The indenting is inconsistent in the whole file.
>
> + QCoreApplication::instance()->setProperty("appStartTime", timestamp);
> 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_nsec(timestamp.count())/1000000;
> 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 QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *w,
> ulong timestamp, const QPointF & local, const QPointF & global,
> Qt::MouseButtons b, Qt::KeyboardModifiers mods,
> Qt::MouseEventSource source)
>
> we could make our own handle*Event() methods. In the end, the above method
> simply does:
>
> QWindowSystemInterfacePrivate::MouseEvent * e =
> new QWindowSystemInterfacePrivate::MouseEvent(w, timestamp,
> QWindowSystemInterfacePrivate::FrameStrutMouse,
> QHighDpi::fromNativeLocalPosition(local, w),
> QHighDpi::fromNativePixels(global, w), b, mods, source);
>
> QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
>
> If we subclassed QWindowSystemInterfacePrivate::MouseEvent, and added the
> 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::milliseconds compressTimestamp(std::chrono::nanoseconds
> 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/decompression, for future souls.

Done. in the header.

>
>
> === modified file 'src/platforms/mirserver/tracepoints.tp'
> Typos:
> touchEventDisptach_start
> touchEventDisptach_end
> and these propagate throughout the whole of mirserver.

Fixed.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

+$ cd benchmarks
+$ sudo python3 touch_event_latency.py
I roughly followed this, but since I saw this script was installed by qtmir-tests in /usr/share/qtmir/benchmarks, I did

sudo python3 /usr/share/qtmir/benchmarks/touch_event_latency.py

but it doesn't fully work:

file:///build/qtmir-7Gjfwp/qtmir-0.4.6+15.04.20150827.1/demos/qtmir-demo-shell/qml-demo-shell.qml: File not found

review: Needs Fixing
lp:~unity-team/qtmir/touch_tracing updated
377. By Nick Dedekind

newline

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~unity-team/qtmir/touch_tracing updated
378. By Nick Dedekind

merged with trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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.

review: Approve
lp:~unity-team/qtmir/touch_tracing updated
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2015-10-14 13:06:12 +0000
+++ CMakeLists.txt 2015-10-14 13:06:12 +0000
@@ -120,6 +120,7 @@
120120
121# Set QML module install path121# Set QML module install path
122set(QML_MODULE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/qt5/qml")122set(QML_MODULE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/qt5/qml")
123set(QTMIR_DATA_DIR ${CMAKE_INSTALL_DATADIR}/qtmir)
123124
124125
125# Customisations for the build type126# Customisations for the build type
@@ -156,6 +157,7 @@
156 message(STATUS "Tests disabled")157 message(STATUS "Tests disabled")
157endif()158endif()
158159
159
160# add subdirectories to build160# add subdirectories to build
161add_subdirectory(src)161add_subdirectory(src)
162add_subdirectory(demos)
163add_subdirectory(benchmarks)
162164
=== added directory 'benchmarks'
=== added file 'benchmarks/CMakeLists.txt'
--- benchmarks/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ benchmarks/CMakeLists.txt 2015-10-14 13:06:12 +0000
@@ -0,0 +1,8 @@
1file(GLOB BENCHMARK_FILES
2 *.py
3 *.R
4)
5
6install(FILES ${BENCHMARK_FILES}
7 DESTINATION ${QTMIR_DATA_DIR}/benchmarks
8)
09
=== added file 'benchmarks/README'
--- benchmarks/README 1970-01-01 00:00:00 +0000
+++ benchmarks/README 2015-10-14 13:06:12 +0000
@@ -0,0 +1,12 @@
1To run performance tests on device:
2
3Firstly, you will need to install the qtmir-tests package. So either install the package using apt or build
4and install from source
5$ sudo apt-get install qtmir-tests
6
7Then you need to stop unity8 & unity-system compositor so that we can start out test in a controlled environment.
8$ sudo stop lightdm
9
10Next, start the test!
11$ cd benchmarks
12$ sudo python3 touch_event_latency.py
0\ No newline at end of file13\ No newline at end of file
114
=== added file 'benchmarks/common.py'
--- benchmarks/common.py 1970-01-01 00:00:00 +0000
+++ benchmarks/common.py 2015-10-14 13:06:12 +0000
@@ -0,0 +1,33 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Copyright (C) 2015 Canonical Ltd.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License as published by
7# the Free Software Foundation; version 3.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17from autopilot import (
18 input,
19 platform
20)
21
22def get_pointing_device():
23 """Return the pointing device depending on the platform.
24
25 If the platform is `Desktop`, the pointing device will be a `Mouse`.
26 If not, the pointing device will be `Touch`.
27
28 """
29 if platform.model() == 'Desktop':
30 input_device_class = input.Mouse
31 else:
32 input_device_class = input.Touch
33 return input.Pointer(device=input_device_class.create())
0\ No newline at end of file34\ No newline at end of file
135
=== added file 'benchmarks/report_types.py'
--- benchmarks/report_types.py 1970-01-01 00:00:00 +0000
+++ benchmarks/report_types.py 2015-10-14 13:06:12 +0000
@@ -0,0 +1,121 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Copyright (C) 2015 Canonical Ltd.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License as published by
7# the Free Software Foundation; version 3.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import subprocess
18import os
19import shutil
20
21class Node:
22 def __init__(self, name):
23 self.name = name
24 self.children = []
25
26 def add_child(self, child):
27 self.children.append(child)
28
29 def to_string(self):
30 output = "<%s>" % self.name
31 for child in self.children:
32 output += child.to_string()
33 output += "</%s>" % self.name
34 return output
35
36class Results(Node):
37 def __init__(self):
38 super().__init__("results")
39
40class Events(Node):
41 def __init__(self):
42 super().__init__("events")
43
44class Event:
45 def __init__(self, event):
46 self.pid = event["vpid"]
47 self.name = event.name
48 self.timestamp = event.timestamp
49
50 def to_string(self):
51 output = "<event "
52 output += "pid='{}' ".format(self.pid)
53 output += "name='{}' ".format(self.name)
54 output += "timestamp='{}' ".format(self.timestamp)
55 output += "/>"
56 return output
57
58class Processes(Node):
59 def __init__(self):
60 super().__init__("processes")
61
62class Process:
63 def __init__(self, name, pid):
64 self.name = name
65 self.pid = pid
66
67 def to_string(self):
68 output = "<process "
69 output += "name='{}' ".format(self.name)
70 output += "pid='{}' ".format(self.pid)
71 output += "/>"
72 return output
73
74class ResultsData:
75 def __init__(self, name, mean=0.0, deviation=0.0, comment=""):
76 self.data = []
77 self.name = name
78 self.mean = mean
79 self.deviation = deviation
80 self.comment = comment
81
82 def add_data(self, value):
83 self.data.append(value)
84
85 def to_string(self):
86 output = "<data name='{}' mean='{}' deviation='{}' comment='{}' count='{}'>".format(
87 self.name,
88 self.mean,
89 self.deviation,
90 self.comment,
91 len(self.data))
92 output += "<values>"
93 output += ",".join(map( lambda x: str(x), self.data))
94 output += "</values>"
95 output += "</data>"
96 return output;
97
98 def generate_histogram(self, filename):
99 cmdline = [
100 shutil.which("Rscript"),
101 os.path.split(os.path.abspath(__file__))[0] + "/touch_event_latency.R",
102 "data.csv",
103 "%s.png" % filename]
104 # Use R to generate a histogram plot
105 f = open("data.csv", "w")
106 f.write(",".join(map( lambda x: str(x), self.data)));
107 f.close()
108 process = subprocess.Popen(cmdline)
109 process.wait()
110 if process.returncode != 0:
111 print("Failed to generate histogram");
112 os.remove("data.csv")
113
114
115class Error:
116 def __init__(self, comment):
117 self.comment = comment
118
119 def to_string(self):
120 return "<error comment='{}' />".format(self.comment)
121 return output
0\ No newline at end of file122\ No newline at end of file
1123
=== added file 'benchmarks/touch_event_latency.R'
--- benchmarks/touch_event_latency.R 1970-01-01 00:00:00 +0000
+++ benchmarks/touch_event_latency.R 2015-10-14 13:06:12 +0000
@@ -0,0 +1,6 @@
1args <- commandArgs(trailingOnly = TRUE)
2data <- scan(args[1], numeric(), sep=",")
3colors = c("red", "yellow", "green", "violet", "orange", "pink", "blue")
4png(filename=args[2])
5hist(data, breaks=max(data), col=colors)
6dev.off()
07
=== added file 'benchmarks/touch_event_latency.py'
--- benchmarks/touch_event_latency.py 1970-01-01 00:00:00 +0000
+++ benchmarks/touch_event_latency.py 2015-10-14 13:06:12 +0000
@@ -0,0 +1,271 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Copyright (C) 2015 Canonical Ltd.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License as published by
7# the Free Software Foundation; version 3.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17from mir_perf_framework import PerformanceTest, Server, Client
18import time
19import statistics
20import shutil
21import sys
22from common import get_pointing_device
23import report_types
24
25####### TEST #######
26
27
28def perform_test():
29 host = Server(reports=["input"])
30 nested = Server(executable=shutil.which("qtmir-demo-shell"),
31 host=host,
32 reports=["input","client-input-receiver"],
33 env={"QT_QPA_PLATFORM": "mirserver", "QML_NO_TOUCH_COMPRESSION": "1"})
34 client = Client(executable=shutil.which("qtmir-demo-client"),
35 server=nested,
36 reports=["input","client-input-receiver"],
37 env={"QT_QPA_PLATFORM": "ubuntumirclient", "QML_NO_TOUCH_COMPRESSION": "1"},
38 options=["--", "--desktop_file_hint=/usr/share/applications/qtmir-demo-client.desktop"])
39
40 test = PerformanceTest([host, nested, client])
41 test.start()
42
43 results = report_types.Results()
44 processes = report_types.Processes()
45 processes.add_child(report_types.Process("Host", host.process.pid))
46 processes.add_child(report_types.Process("Nested Server", nested.process.pid))
47 processes.add_child(report_types.Process("Client", client.process.pid))
48 results.add_child(processes)
49
50 time.sleep(3) # wait for settle
51
52 host_pid = host.process.pid
53 nested_pid = nested.process.pid
54 client_pid = client.process.pid
55
56 touch = get_pointing_device()
57 time.sleep(1) # let mir pick up the new input device
58 touch.drag(100, 100, 1000, 100, 5, 0.006)
59 touch.drag(1000, 100, 1000, 1000, 5, 0.006)
60 touch.drag(1000, 1000, 100, 1000, 5, 0.006)
61 touch.drag(100, 1000, 100, 100, 5, 0.006)
62
63 # time.sleep(5) # wait for settle
64 time.sleep(2) # wait for settle
65 test.stop()
66
67 ####### TRACE PARSING #######
68
69 trace = test.babeltrace()
70
71 server_touch_data_timestamps = {}
72 client_touch_data_timestamps = {}
73 client_touch_data_latency = {}
74
75 qtmir_touch_dispatch_start = {}
76 qtmir_touch_dispatch_end = {}
77 qtmir_touch_consume_start = {}
78 qtmir_touch_consume_end = {}
79
80 events = report_types.Events()
81
82 for event in trace.events:
83 events.add_child(report_types.Event(event))
84 pid = event["vpid"]
85 if event.name == "mir_client_input_receiver:touch_event":
86 if pid not in client_touch_data_timestamps: client_touch_data_timestamps[pid] = []
87 if pid not in client_touch_data_latency: client_touch_data_latency[pid] = []
88 diff = (event.timestamp - event["event_time"]) / 1000000.0
89 if diff > 0:
90 client_touch_data_timestamps[pid].append(event.timestamp)
91 client_touch_data_latency[pid].append(diff)
92
93 elif event.name == "mir_server_input:published_motion_event":
94 if pid not in server_touch_data_timestamps: server_touch_data_timestamps[pid] = []
95 server_touch_data_timestamps[pid].append(event["event_time"])
96
97 elif event.name == "qtmirserver:touchEventDispatch_start":
98 if pid not in qtmir_touch_dispatch_start: qtmir_touch_dispatch_start[pid] = []
99 qtmir_touch_dispatch_start[pid].append(event.timestamp)
100
101 elif event.name == "qtmirserver:touchEventDispatch_end":
102 if pid not in qtmir_touch_dispatch_end: qtmir_touch_dispatch_end[pid] = []
103 qtmir_touch_dispatch_end[pid].append(event.timestamp)
104
105 elif event.name == "qtmir:touchEventConsume_start":
106 if pid not in qtmir_touch_consume_start: qtmir_touch_consume_start[pid] = []
107 qtmir_touch_consume_start[pid].append(event.timestamp)
108
109 elif event.name == "qtmir:touchEventConsume_end":
110 if pid not in qtmir_touch_consume_end: qtmir_touch_consume_end[pid] = []
111 qtmir_touch_consume_end[pid].append(event.timestamp)
112
113 # LATENCY MEANS
114
115 if nested_pid in client_touch_data_latency:
116 nested_data = client_touch_data_latency[nested_pid]
117 nested_latency_xml = report_types.ResultsData(
118 "nested_latency",
119 statistics.mean(nested_data),
120 statistics.stdev(nested_data),
121 "Kernel to nested server latency")
122 for value in nested_data:
123 nested_latency_xml.add_data(value)
124 results.add_child(nested_latency_xml)
125 nested_latency_xml.generate_histogram("nested_latency")
126 else:
127 results.add_child(report_types.Error("No nested server touch latency data"))
128
129 if client_pid in client_touch_data_latency:
130 client_data = client_touch_data_latency[client_pid]
131
132 client_latency_xml = report_types.ResultsData(
133 "client_latency",
134 statistics.mean(client_data),
135 statistics.stdev(client_data),
136 "Kernel to client latency")
137 for value in client_data:
138 client_latency_xml.add_data(value)
139 results.add_child(client_latency_xml)
140 client_latency_xml.generate_histogram("client_latency")
141 else:
142 results.add_child(report_types.Error("No client touch latency data"))
143
144 # EVENT RATES
145 if host_pid in server_touch_data_timestamps:
146 last_timestamp = -1
147 input_rate = []
148
149 for next_timestamp in server_touch_data_timestamps[host_pid]:
150 if last_timestamp != -1:
151 diff = (next_timestamp - last_timestamp) / 1000000.0
152 input_rate.append(diff)
153 last_timestamp = next_timestamp
154
155 input_rate_xml = report_types.ResultsData(
156 "host_input_ate",
157 statistics.mean(input_rate),
158 statistics.stdev(input_rate),
159 "Host input event rate")
160 for value in input_rate:
161 input_rate_xml.add_data(value)
162 results.add_child(input_rate_xml)
163 input_rate_xml.generate_histogram("host_input_rate")
164 else:
165 results.add_child(report_types.Error("No host server input event timestamp data"))
166
167 if nested_pid in client_touch_data_timestamps:
168 last_timestamp = -1
169 input_rate = []
170 for next_timestamp in client_touch_data_timestamps[nested_pid]:
171 if last_timestamp != -1:
172 diff = (next_timestamp - last_timestamp) / 1000000.0
173 input_rate.append(diff)
174 last_timestamp = next_timestamp
175
176 input_rate_xml = report_types.ResultsData(
177 "nested_input_rate",
178 statistics.mean(input_rate),
179 statistics.stdev(input_rate),
180 "Nested server event rate")
181 for value in input_rate:
182 input_rate_xml.add_data(value)
183 results.add_child(input_rate_xml)
184 input_rate_xml.generate_histogram("nested_input_rate")
185 else:
186 results.add_child(report_types.Error("No nested server input event timestamp data"))
187
188 if client_pid in client_touch_data_timestamps:
189 last_timestamp = -1
190 input_rate = []
191 for next_timestamp in client_touch_data_timestamps[client_pid]:
192 if last_timestamp != -1:
193 diff = (next_timestamp - last_timestamp) / 1000000.0
194 input_rate.append(diff)
195 last_timestamp = next_timestamp
196
197 input_rate_xml = report_types.ResultsData(
198 "client_input_rate",
199 statistics.mean(input_rate),
200 statistics.stdev(input_rate),
201 "Client event rate")
202 for value in input_rate:
203 input_rate_xml.add_data(value)
204 results.add_child(input_rate_xml)
205 input_rate_xml.generate_histogram("client_input_rate")
206 else:
207 results.add_child(report_types.Error("No client event timestamp data"))
208
209 qtmir_loop_data = []
210 dispatch_data = []
211 consume_data = []
212
213 # TIME BETWEEN TRACEPOINTS
214 dispatch_starts = qtmir_touch_dispatch_start[nested_pid] if nested_pid in qtmir_touch_dispatch_start else []
215 dispatch_ends = qtmir_touch_dispatch_end[nested_pid] if nested_pid in qtmir_touch_dispatch_end else []
216 consume_starts = qtmir_touch_consume_start[nested_pid] if nested_pid in qtmir_touch_consume_start else []
217 consume_ends = qtmir_touch_consume_end[nested_pid] if nested_pid in qtmir_touch_consume_end else []
218
219 # since there's no uniqueness to events, we need to assume all events are 1:1 through system
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):
221 i = 0
222
223 for start in dispatch_starts:
224 dispatch_diff = (dispatch_ends[i] - start) / 1000000.0
225 consume_diff = (consume_ends[i] - consume_starts[i]) / 1000000.0
226 loop_dif = (consume_starts[i] - dispatch_ends[i]) / 1000000.0
227 dispatch_data.append(dispatch_diff);
228 consume_data.append(consume_diff);
229 qtmir_loop_data.append(loop_dif);
230 i=i+1
231
232 qtmir_loop_xml = report_types.ResultsData(
233 "qtmir_eventloop",
234 statistics.mean(qtmir_loop_data),
235 statistics.stdev(qtmir_loop_data),
236 "Time spent in qtmir event loop")
237 for value in qtmir_loop_data:
238 qtmir_loop_xml.add_data(value)
239 results.add_child(qtmir_loop_xml)
240 qtmir_loop_xml.generate_histogram("qtmir_eventloop")
241
242 qtmir_dispatch_xml = report_types.ResultsData(
243 "qtmir_dispatch",
244 statistics.mean(dispatch_data),
245 statistics.stdev(dispatch_data),
246 "Time QteventFeeder spent dispatching event to qt")
247 for value in dispatch_data:
248 qtmir_dispatch_xml.add_data(value)
249 results.add_child(qtmir_dispatch_xml)
250 qtmir_dispatch_xml.generate_histogram("qtmir_dispatch")
251
252 qtmir_consume_xml = report_types.ResultsData(
253 "qtmir_consume",
254 statistics.mean(consume_data),
255 statistics.stdev(consume_data),
256 "Time MirSurfaceItem spent consiming event")
257 for value in consume_data:
258 qtmir_consume_xml.add_data(value)
259 results.add_child(qtmir_consume_xml)
260 qtmir_consume_xml.generate_histogram("qtmir_consume")
261
262 else:
263 results.add_child(report_types.Error("Cannot calculate QtMir loop data - Dispatch event count did not match surface consume event count"))
264
265 results.add_child(events)
266 return results
267
268if __name__ == "__main__":
269 results = perform_test();
270 f = open("touch_event_latency.xml", "w")
271 f.write(results.to_string())
0272
=== modified file 'debian/control'
--- debian/control 2015-10-14 13:06:12 +0000
+++ debian/control 2015-10-14 13:06:12 +0000
@@ -98,3 +98,23 @@
98 QtMir provides Qt/QML bindings for Mir features that are exposed through the98 QtMir provides Qt/QML bindings for Mir features that are exposed through the
99 qtmir-desktop or qtmir-android QPA plugin such as Application management99 qtmir-desktop or qtmir-android QPA plugin such as Application management
100 (start/stop/suspend/resume) and surface management.100 (start/stop/suspend/resume) and surface management.
101
102Package: qtmir-tests
103Architecture: any
104Multi-Arch: same
105Pre-Depends: ${misc:Pre-Depends},
106Depends: autopilot-qt5,
107 littler,
108 lttng-tools,
109 mir-test-tools,
110 python3-autopilot,
111 python3-babeltrace,
112 python3-evdev,
113 python3-mir-perf-framework,
114 qtmir-desktop (= ${source:Version}) | qtmir-android (= ${source:Version}),
115 qtdeclarative5-qtmir-plugin,
116 ${misc:Depends},
117 ${shlibs:Depends},
118Description: QtMir tests and demos
119 This package provides benchmark tests and a simple shell and client using the
120 QtMir QPA.
101121
=== added file 'debian/qtmir-tests.install'
--- debian/qtmir-tests.install 1970-01-01 00:00:00 +0000
+++ debian/qtmir-tests.install 2015-10-14 13:06:12 +0000
@@ -0,0 +1,6 @@
1usr/bin/qtmir-demo-shell
2usr/bin/qtmir-demo-client
3usr/share/applications/qtmir-demo-client.desktop
4usr/share/qtmir/qtmir-demo-shell/
5usr/share/qtmir/qtmir-demo-client/*
6usr/share/qtmir/benchmarks/*
07
=== modified file 'debian/rules'
--- debian/rules 2015-10-14 13:06:12 +0000
+++ debian/rules 2015-10-14 13:06:12 +0000
@@ -59,4 +59,4 @@
59endif59endif
60 dh_install --sourcedir=$(TMP2_DIR) -pqtmir-desktop60 dh_install --sourcedir=$(TMP2_DIR) -pqtmir-desktop
61 dh_install --sourcedir=$(TMP2_DIR) -pqtdeclarative5-qtmir-plugin61 dh_install --sourcedir=$(TMP2_DIR) -pqtdeclarative5-qtmir-plugin
6262 dh_install --sourcedir=$(TMP2_DIR) -pqtmir-tests
6363
=== added file 'demos/CMakeLists.txt'
--- demos/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ demos/CMakeLists.txt 2015-10-14 13:06:12 +0000
@@ -0,0 +1,4 @@
1configure_file(paths.h.in ${CMAKE_CURRENT_BINARY_DIR}/paths.h @ONLY)
2
3add_subdirectory(qml-demo-client)
4add_subdirectory(qml-demo-shell)
0\ No newline at end of file5\ No newline at end of file
16
=== added file 'demos/paths.h.in'
--- demos/paths.h.in 1970-01-01 00:00:00 +0000
+++ demos/paths.h.in 2015-10-14 13:06:12 +0000
@@ -0,0 +1,40 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef PATHS_H
18#define PATHS_H
19
20// Qt
21#include <QtCore/QCoreApplication>
22#include <QtCore/QDir>
23#include <QtGui/QIcon>
24#include <QtQml/QQmlEngine>
25#include <QStandardPaths>
26
27inline bool isRunningInstalled() {
28 static bool installed = (QCoreApplication::applicationDirPath() ==
29 QDir(("@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@")).canonicalPath());
30 return installed;
31}
32
33inline QString qmlDirectory() {
34 if (isRunningInstalled()) {
35 return QString("@CMAKE_INSTALL_PREFIX@/@QTMIR_DATA_DIR@/");
36 } else {
37 return QString("@CMAKE_SOURCE_DIR@/demos/");
38 }
39}
40#endif
0\ No newline at end of file41\ No newline at end of file
142
=== added file 'demos/qml-demo-client/CMakeLists.txt'
--- demos/qml-demo-client/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ demos/qml-demo-client/CMakeLists.txt 2015-10-14 13:06:12 +0000
@@ -0,0 +1,41 @@
1set(DEMO_CLIENT qtmir-demo-client)
2configure_file(${DEMO_CLIENT}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${DEMO_CLIENT}.desktop @ONLY)
3
4include_directories(
5 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
6)
7
8add_executable(${DEMO_CLIENT}
9 main.cpp
10)
11
12include_directories(
13 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
14 ${Qt5Qml_PRIVATE_INCLUDE_DIRS}
15 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
16)
17
18target_link_libraries(
19 ${DEMO_CLIENT}
20 Qt5::Core
21 Qt5::DBus
22 Qt5::Qml
23 Qt5::Quick
24)
25
26file(GLOB QML_JS_FILES *.qml *.js *.png)
27
28# install binaries
29install(TARGETS ${DEMO_CLIENT}
30 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
31 )
32
33install(FILES
34 ${QML_JS_FILES}
35 DESTINATION ${QTMIR_DATA_DIR}/${DEMO_CLIENT}
36)
37
38install(FILES
39 ${CMAKE_CURRENT_BINARY_DIR}/${DEMO_CLIENT}.desktop
40 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications
41)
0\ No newline at end of file42\ No newline at end of file
143
=== added file 'demos/qml-demo-client/main.cpp'
--- demos/qml-demo-client/main.cpp 1970-01-01 00:00:00 +0000
+++ demos/qml-demo-client/main.cpp 2015-10-14 13:06:12 +0000
@@ -0,0 +1,73 @@
1/*
2 * Copyright (C) 2012-2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17// Qt
18#include <QtQuick/QQuickView>
19#include <QtGui/QGuiApplication>
20#include <QDebug>
21#include <csignal>
22#include <libintl.h>
23#include <getopt.h>
24#include "../paths.h"
25
26// REMOVEME - Should be able to use qmlscene, but in order to use the mir benchmarking we need
27// to parse command line switches. Wait until MIR_SOCKET supported by the benchmark framework.
28
29int main(int argc, char **argv)
30{
31 int arg;
32 opterr = 0;
33 while ((arg = getopt (argc, argv, "hm:")) != -1)
34 {
35 switch (arg)
36 {
37 case 'm':
38 setenv("MIR_SOCKET", optarg, 1);
39 break;
40
41 case '?':
42 case 'h':
43 default:
44 puts(argv[0]);
45 puts("Usage:");
46 puts(" -m <Mir server socket>");
47 puts(" -h: this help text");
48 return -1;
49 }
50 }
51
52 QGuiApplication::setApplicationName("qml-demo-client");
53 QGuiApplication *application;
54
55 application = new QGuiApplication(argc, (char**)argv);
56 QQuickView* view = new QQuickView();
57 view->setResizeMode(QQuickView::SizeRootObjectToView);
58 view->setColor("black");
59 view->setTitle("Demo Client");
60
61 QUrl source(::qmlDirectory() + "qtmir-demo-client/qml-demo-client.qml");
62
63 view->setSource(source);
64 QObject::connect(view->engine(), SIGNAL(quit()), application, SLOT(quit()));
65
66 view->showFullScreen();
67 int result = application->exec();
68
69 delete view;
70 delete application;
71
72 return result;
73}
074
=== added file 'demos/qml-demo-client/qtmir-demo-client.desktop.in'
--- demos/qml-demo-client/qtmir-demo-client.desktop.in 1970-01-01 00:00:00 +0000
+++ demos/qml-demo-client/qtmir-demo-client.desktop.in 2015-10-14 13:06:12 +0000
@@ -0,0 +1,9 @@
1[Desktop Entry]
2Type=Application
3Name=QtMir Demo Client
4Comment=QtMir demo client
5Exec=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/qtmir-demo-client
6Terminal=false
7Icon=
8NoDisplay=false
9X-Ubuntu-Touch=true
010
=== added file 'demos/qml-demo-shell/CMakeLists.txt'
--- demos/qml-demo-shell/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ demos/qml-demo-shell/CMakeLists.txt 2015-10-14 13:06:12 +0000
@@ -0,0 +1,35 @@
1set(DEMO_SHELL qtmir-demo-shell)
2
3include_directories(
4 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
5)
6
7add_executable(${DEMO_SHELL}
8 main.cpp
9)
10
11include_directories(
12 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
13 ${Qt5Qml_PRIVATE_INCLUDE_DIRS}
14 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
15)
16
17target_link_libraries(
18 ${DEMO_SHELL}
19 Qt5::Core
20 Qt5::DBus
21 Qt5::Qml
22 Qt5::Quick
23)
24
25file(GLOB QML_JS_FILES *.qml *.js *.png)
26
27# install binaries
28install(TARGETS ${DEMO_SHELL}
29 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
30 )
31
32install(FILES
33 ${QML_JS_FILES}
34 DESTINATION ${QTMIR_DATA_DIR}/${DEMO_SHELL}
35)
036
=== added file 'demos/qml-demo-shell/main.cpp'
--- demos/qml-demo-shell/main.cpp 1970-01-01 00:00:00 +0000
+++ demos/qml-demo-shell/main.cpp 2015-10-14 13:06:12 +0000
@@ -0,0 +1,57 @@
1/*
2 * Copyright (C) 2012-2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17// Qt
18#include <QCommandLineParser>
19#include <QtQuick/QQuickView>
20#include <QtGui/QGuiApplication>
21#include <QtQml/QQmlEngine>
22#include <QtQml/QQmlContext>
23#include <QLibrary>
24#include <QDebug>
25#include <csignal>
26#include <libintl.h>
27#include "../paths.h"
28
29#include <private/qobject_p.h>
30
31// REMOVEME - Should be able to use qmlscene, but in order to use the mir benchmarking we need
32// to parse command line switches. Wait until MIR_SOCKET supported by the benchmark framework.
33
34int main(int argc, const char *argv[])
35{
36 QGuiApplication::setApplicationName("qml-demo-shell");
37 QGuiApplication *application;
38
39 application = new QGuiApplication(argc, (char**)argv);
40 QQuickView* view = new QQuickView();
41 view->setResizeMode(QQuickView::SizeRootObjectToView);
42 view->setColor("black");
43 view->setTitle("Demo Shell");
44
45 QUrl source(::qmlDirectory() + "qtmir-demo-shell/qml-demo-shell.qml");
46
47 view->setSource(source);
48 QObject::connect(view->engine(), SIGNAL(quit()), application, SLOT(quit()));
49
50 view->showFullScreen();
51 int result = application->exec();
52
53 delete view;
54 delete application;
55
56 return result;
57}
058
=== added file 'src/common/timestamp.cpp'
--- src/common/timestamp.cpp 1970-01-01 00:00:00 +0000
+++ src/common/timestamp.cpp 2015-10-14 13:06:12 +0000
@@ -0,0 +1,18 @@
1
2#include <chrono>
3#include "timestamp_impl.h"
4
5std::chrono::nanoseconds appStartTime(0);
6
7void resetStartTime(std::chrono::nanoseconds timestamp)
8{
9 appStartTime = timestamp;
10}
11
12std::chrono::nanoseconds getStartTime(std::chrono::nanoseconds timestamp, bool allowReset)
13{
14 if (allowReset && appStartTime.count() == 0) {
15 resetStartTime(timestamp);
16 }
17 return appStartTime;
18}
019
=== added file 'src/common/timestamp.h'
--- src/common/timestamp.h 1970-01-01 00:00:00 +0000
+++ src/common/timestamp.h 2015-10-14 13:06:12 +0000
@@ -0,0 +1,39 @@
1/*
2 * Copyright (C) 2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef QTMIR_TIMESTAMP_H
18#define QTMIR_TIMESTAMP_H
19
20#include <QtCore/qglobal.h>
21#include <chrono>
22
23namespace qtmir {
24
25// Converts a mir timestamp (in nanoseconds) to and from a timestamp in milliseconds.
26// Qt system events only work with ulong timestamps. On 32bit archs a ulong is 4 bytes long, so the 64 bit nanoseconds
27// will be truncated and skewed. In order to fix this, we truncate the result by using time since "first call"
28template<typename T>
29T compressTimestamp(std::chrono::nanoseconds timestamp);
30
31 // "Re-inflate" a truncated timestamp.
32template<typename T>
33std::chrono::nanoseconds uncompressTimestamp(T timestamp);
34
35}
36
37#include "timestamp_impl.h"
38
39#endif // QTMIR_TIMESTAMP_H
040
=== added file 'src/common/timestamp_impl.h'
--- src/common/timestamp_impl.h 1970-01-01 00:00:00 +0000
+++ src/common/timestamp_impl.h 2015-10-14 13:06:12 +0000
@@ -0,0 +1,34 @@
1#include <QCoreApplication>
2#include <QVariant>
3
4extern "C" {
5 void resetStartTime(std::chrono::nanoseconds timestamp);
6 std::chrono::nanoseconds getStartTime(std::chrono::nanoseconds timestamp, bool allowReset = true);
7}
8
9namespace qtmir {
10
11template<typename T>
12T compressTimestamp(std::chrono::nanoseconds timestamp)
13{
14 std::chrono::nanoseconds startTime = getStartTime(timestamp);
15 std::chrono::nanoseconds result = timestamp - startTime;
16
17 if (std::numeric_limits<std::chrono::nanoseconds::rep>::max() > std::numeric_limits<T>::max() &&
18 result > std::chrono::nanoseconds(std::numeric_limits<T>::max())) {
19 // we've overflowed the boundaries of the millisecond type.
20 resetStartTime(timestamp);
21 return 0;
22 }
23
24 return result.count();
25}
26
27template<typename T>
28std::chrono::nanoseconds uncompressTimestamp(T timestamp)
29{
30 auto tsNS = std::chrono::nanoseconds(timestamp);
31 return getStartTime(tsNS, false) + std::chrono::nanoseconds(tsNS);
32}
33
34}
0\ No newline at end of file35\ No newline at end of file
136
=== modified file 'src/modules/Unity/Application/mirsurface.cpp'
--- src/modules/Unity/Application/mirsurface.cpp 2015-10-14 13:06:12 +0000
+++ src/modules/Unity/Application/mirsurface.cpp 2015-10-14 13:06:12 +0000
@@ -15,6 +15,7 @@
15 */15 */
1616
17#include "mirsurface.h"17#include "mirsurface.h"
18#include "timestamp.h"
1819
19// mirserver20// mirserver
20#include <surfaceobserver.h>21#include <surfaceobserver.h>
@@ -51,7 +52,7 @@
5152
52mir::EventUPtr makeMirEvent(QMouseEvent *qtEvent, MirPointerAction action)53mir::EventUPtr makeMirEvent(QMouseEvent *qtEvent, MirPointerAction action)
53{54{
54 auto timestamp = std::chrono::milliseconds(qtEvent->timestamp());55 auto timestamp = uncompressTimestamp<ulong>(qtEvent->timestamp());
55 auto modifiers = getMirModifiersFromQt(qtEvent->modifiers());56 auto modifiers = getMirModifiersFromQt(qtEvent->modifiers());
5657
57 MirPointerButtons buttons = 0;58 MirPointerButtons buttons = 0;
@@ -68,7 +69,7 @@
6869
69mir::EventUPtr makeMirEvent(QHoverEvent *qtEvent, MirPointerAction action)70mir::EventUPtr makeMirEvent(QHoverEvent *qtEvent, MirPointerAction action)
70{71{
71 auto timestamp = std::chrono::milliseconds(qtEvent->timestamp());72 auto timestamp = uncompressTimestamp<ulong>(qtEvent->timestamp());
7273
73 MirPointerButtons buttons = 0;74 MirPointerButtons buttons = 0;
7475
@@ -93,7 +94,7 @@
93 if (qtEvent->isAutoRepeat())94 if (qtEvent->isAutoRepeat())
94 action = mir_keyboard_action_repeat;95 action = mir_keyboard_action_repeat;
9596
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()),
97 0 /* mac */, action, qtEvent->nativeVirtualKey(),98 0 /* mac */, action, qtEvent->nativeVirtualKey(),
98 qtEvent->nativeScanCode(),99 qtEvent->nativeScanCode(),
99 qtEvent->nativeModifiers());100 qtEvent->nativeModifiers());
@@ -105,7 +106,7 @@
105 ulong qtTimestamp)106 ulong qtTimestamp)
106{107{
107 auto modifiers = getMirModifiersFromQt(qmods);108 auto modifiers = getMirModifiersFromQt(qmods);
108 auto ev = mir::events::make_event(0, std::chrono::milliseconds(qtTimestamp),109 auto ev = mir::events::make_event(0, uncompressTimestamp<ulong>(qtTimestamp),
109 0 /* mac */, modifiers);110 0 /* mac */, modifiers);
110111
111 for (int i = 0; i < qtTouchPoints.count(); ++i) {112 for (int i = 0; i < qtTouchPoints.count(); ++i) {
112113
=== modified file 'src/modules/Unity/Application/mirsurfaceitem.cpp'
--- src/modules/Unity/Application/mirsurfaceitem.cpp 2015-10-14 13:06:12 +0000
+++ src/modules/Unity/Application/mirsurfaceitem.cpp 2015-10-14 13:06:12 +0000
@@ -20,6 +20,8 @@
20#include "mirsurfaceitem.h"20#include "mirsurfaceitem.h"
21#include "logging.h"21#include "logging.h"
22#include "ubuntukeyboardinfo.h"22#include "ubuntukeyboardinfo.h"
23#include "tracepoints.h" // generated from tracepoints.tp
24#include "timestamp.h"
2325
24// common26// common
25#include <debughelpers.h>27#include <debughelpers.h>
@@ -409,10 +411,14 @@
409 m_lastTouchEvent->timestamp = timestamp;411 m_lastTouchEvent->timestamp = timestamp;
410 m_lastTouchEvent->touchPoints = touchPoints;412 m_lastTouchEvent->touchPoints = touchPoints;
411 m_lastTouchEvent->touchPointStates = touchPointStates;413 m_lastTouchEvent->touchPointStates = touchPointStates;
414
415 tracepoint(qtmir, touchEventConsume_end, uncompressTimestamp<ulong>(timestamp).count());
412}416}
413417
414void MirSurfaceItem::touchEvent(QTouchEvent *event)418void MirSurfaceItem::touchEvent(QTouchEvent *event)
415{419{
420 tracepoint(qtmir, touchEventConsume_start, uncompressTimestamp<ulong>(event->timestamp()).count());
421
416 bool accepted = processTouchEvent(event->type(),422 bool accepted = processTouchEvent(event->type(),
417 event->timestamp(),423 event->timestamp(),
418 event->modifiers(),424 event->modifiers(),
419425
=== modified file 'src/modules/Unity/Application/tracepoints.tp'
--- src/modules/Unity/Application/tracepoints.tp 2014-09-04 11:11:26 +0000
+++ src/modules/Unity/Application/tracepoints.tp 2015-10-14 13:06:12 +0000
@@ -1,3 +1,5 @@
1#include <stdint.h>
2
1TRACEPOINT_EVENT(qtmir, startApplication, TP_ARGS(0), TP_FIELDS())3TRACEPOINT_EVENT(qtmir, startApplication, TP_ARGS(0), TP_FIELDS())
2TRACEPOINT_EVENT(qtmir, onProcessStarting, TP_ARGS(0), TP_FIELDS())4TRACEPOINT_EVENT(qtmir, onProcessStarting, TP_ARGS(0), TP_FIELDS())
3TRACEPOINT_EVENT(qtmir, authorizeSession, TP_ARGS(0), TP_FIELDS())5TRACEPOINT_EVENT(qtmir, authorizeSession, TP_ARGS(0), TP_FIELDS())
@@ -7,3 +9,6 @@
7TRACEPOINT_EVENT(qtmir, firstFrameDrawn, TP_ARGS(0), TP_FIELDS())9TRACEPOINT_EVENT(qtmir, firstFrameDrawn, TP_ARGS(0), TP_FIELDS())
8TRACEPOINT_EVENT(qtmir, appIdHasProcessId_start, TP_ARGS(0), TP_FIELDS())10TRACEPOINT_EVENT(qtmir, appIdHasProcessId_start, TP_ARGS(0), TP_FIELDS())
9TRACEPOINT_EVENT(qtmir, appIdHasProcessId_end, TP_ARGS(int, found), TP_FIELDS(ctf_integer(int, found, found)))11TRACEPOINT_EVENT(qtmir, appIdHasProcessId_end, TP_ARGS(int, found), TP_FIELDS(ctf_integer(int, found, found)))
12
13TRACEPOINT_EVENT(qtmir, touchEventConsume_start, TP_ARGS(int64_t, event_time), TP_FIELDS(ctf_integer(int64_t, event_time, event_time)))
14TRACEPOINT_EVENT(qtmir, touchEventConsume_end, TP_ARGS(int64_t, event_time), TP_FIELDS(ctf_integer(int64_t, event_time, event_time)))
1015
=== modified file 'src/platforms/mirserver/CMakeLists.txt'
--- src/platforms/mirserver/CMakeLists.txt 2015-10-14 13:06:12 +0000
+++ src/platforms/mirserver/CMakeLists.txt 2015-10-14 13:06:12 +0000
@@ -42,6 +42,7 @@
4242
43set(MIRSERVER_QPA_PLUGIN_SRC43set(MIRSERVER_QPA_PLUGIN_SRC
44 ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp44 ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp
45 ${CMAKE_SOURCE_DIR}/src/common/timestamp.cpp
45 cursor.cpp46 cursor.cpp
46 mirwindowmanager.cpp47 mirwindowmanager.cpp
47 mirsingleton.cpp48 mirsingleton.cpp
4849
=== modified file 'src/platforms/mirserver/qteventfeeder.cpp'
--- src/platforms/mirserver/qteventfeeder.cpp 2015-10-14 13:06:12 +0000
+++ src/platforms/mirserver/qteventfeeder.cpp 2015-10-14 13:06:12 +0000
@@ -17,6 +17,8 @@
17#include "qteventfeeder.h"17#include "qteventfeeder.h"
18#include "cursor.h"18#include "cursor.h"
19#include "logging.h"19#include "logging.h"
20#include "timestamp.h"
21#include "tracepoints.h" // generated from tracepoints.tp
20#include "screen.h" // NEEDED?22#include "screen.h" // NEEDED?
21#include "screencontroller.h"23#include "screencontroller.h"
2224
@@ -530,7 +532,7 @@
530532
531void QtEventFeeder::dispatchPointer(MirInputEvent const* ev)533void QtEventFeeder::dispatchPointer(MirInputEvent const* ev)
532{534{
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)));
534536
535 auto pev = mir_input_event_get_pointer_event(ev);537 auto pev = mir_input_event_get_pointer_event(ev);
536 qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirPointerEventToString(pev));538 qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirPointerEventToString(pev));
@@ -546,7 +548,7 @@
546548
547void QtEventFeeder::dispatchKey(MirInputEvent const* event)549void QtEventFeeder::dispatchKey(MirInputEvent const* event)
548{550{
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)));
550552
551 auto kev = mir_input_event_get_keyboard_event(event);553 auto kev = mir_input_event_get_keyboard_event(event);
552 xkb_keysym_t xk_sym = mir_keyboard_event_key_code(kev);554 xkb_keysym_t xk_sym = mir_keyboard_event_key_code(kev);
@@ -605,6 +607,10 @@
605607
606void QtEventFeeder::dispatchTouch(MirInputEvent const* event)608void QtEventFeeder::dispatchTouch(MirInputEvent const* event)
607{609{
610 auto timestamp = std::chrono::nanoseconds(mir_input_event_get_event_time(event));
611
612 tracepoint(qtmirserver, touchEventDispatch_start, timestamp.count());
613
608 auto tev = mir_input_event_get_touch_event(event);614 auto tev = mir_input_event_get_touch_event(event);
609 qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirTouchEventToString(tev));615 qCDebug(QTMIR_MIR_INPUT) << "Received" << qPrintable(mirTouchEventToString(tev));
610616
@@ -661,17 +667,21 @@
661 }667 }
662 }668 }
663669
670 auto compressedTimestamp = qtmir::compressTimestamp<ulong>(timestamp);
671
664 // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding672 // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding
665 // any insanity.673 // any insanity.
666 validateTouches(window, mir_input_event_get_event_time(event) / 1000000, touchPoints);674 validateTouches(window, compressedTimestamp, touchPoints);
667675
668 // Touch event propagation.676 // Touch event propagation.
669 qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints));677 qCDebug(QTMIR_MIR_INPUT) << "Sending to Qt" << qPrintable(touchesToString(touchPoints));
670 mQtWindowSystem->handleTouchEvent(window,678 mQtWindowSystem->handleTouchEvent(window,
671 //scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable679 //scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable
672 mir_input_event_get_event_time(event) / 1000000,680 compressedTimestamp,
673 mTouchDevice,681 mTouchDevice,
674 touchPoints);682 touchPoints);
683
684 tracepoint(qtmirserver, touchEventDispatch_end, timestamp.count());
675}685}
676686
677void QtEventFeeder::start()687void QtEventFeeder::start()
678688
=== modified file 'src/platforms/mirserver/tracepoints.tp'
--- src/platforms/mirserver/tracepoints.tp 2014-09-22 18:06:58 +0000
+++ src/platforms/mirserver/tracepoints.tp 2015-10-14 13:06:12 +0000
@@ -1,3 +1,5 @@
1#include <stdint.h>
2
1TRACEPOINT_EVENT(qtmirserver, starting, TP_ARGS(0), TP_FIELDS())3TRACEPOINT_EVENT(qtmirserver, starting, TP_ARGS(0), TP_FIELDS())
2TRACEPOINT_EVENT(qtmirserver, stopping, TP_ARGS(0), TP_FIELDS())4TRACEPOINT_EVENT(qtmirserver, stopping, TP_ARGS(0), TP_FIELDS())
3TRACEPOINT_EVENT(qtmirserver, surfaceCreated, TP_ARGS(0), TP_FIELDS())5TRACEPOINT_EVENT(qtmirserver, surfaceCreated, TP_ARGS(0), TP_FIELDS())
@@ -8,3 +10,6 @@
810
9TRACEPOINT_EVENT(qtmirserver, surfacePlacementStart, TP_ARGS(0), TP_FIELDS())11TRACEPOINT_EVENT(qtmirserver, surfacePlacementStart, TP_ARGS(0), TP_FIELDS())
10TRACEPOINT_EVENT(qtmirserver, surfacePlacementEnd, TP_ARGS(0), TP_FIELDS())12TRACEPOINT_EVENT(qtmirserver, surfacePlacementEnd, TP_ARGS(0), TP_FIELDS())
13
14TRACEPOINT_EVENT(qtmirserver, touchEventDispatch_start, TP_ARGS(int64_t, event_time), TP_FIELDS(ctf_integer(int64_t, event_time, event_time)))
15TRACEPOINT_EVENT(qtmirserver, touchEventDispatch_end, TP_ARGS(int64_t, event_time), TP_FIELDS(ctf_integer(int64_t, event_time, event_time)))
1116
=== modified file 'tests/modules/General/CMakeLists.txt'
--- tests/modules/General/CMakeLists.txt 2014-12-03 08:56:35 +0000
+++ tests/modules/General/CMakeLists.txt 2015-10-14 13:06:12 +0000
@@ -1,16 +1,13 @@
1set(1set(
2 GENERAL_TEST_SOURCES2 GENERAL_TEST_SOURCES
3 objectlistmodel_test.cpp3 objectlistmodel_test.cpp
4 ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp4 timestamp_test.cpp
5 ${CMAKE_SOURCE_DIR}/src/common/timestamp.cpp
5)6)
67
7include_directories(8include_directories(
8 ${CMAKE_SOURCE_DIR}/src/platforms/mirserver
9 ${CMAKE_SOURCE_DIR}/src/common9 ${CMAKE_SOURCE_DIR}/src/common
10 ${CMAKE_SOURCE_DIR}/src/modules10 ${CMAKE_SOURCE_DIR}/src/modules
11 ${CMAKE_SOURCE_DIR}/tests/modules/common
12 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
13 ${MIRSERVER_INCLUDE_DIRS}
14)11)
1512
16add_executable(general_test ${GENERAL_TEST_SOURCES})13add_executable(general_test ${GENERAL_TEST_SOURCES})
@@ -18,9 +15,6 @@
18target_link_libraries(15target_link_libraries(
19 general_test16 general_test
2017
21 qpa-mirserver
22 unityapplicationplugin
23
24 Qt5::Gui18 Qt5::Gui
2519
26 ${GTEST_BOTH_LIBRARIES}20 ${GTEST_BOTH_LIBRARIES}
2721
=== added file 'tests/modules/General/timestamp_test.cpp'
--- tests/modules/General/timestamp_test.cpp 1970-01-01 00:00:00 +0000
+++ tests/modules/General/timestamp_test.cpp 2015-10-14 13:06:12 +0000
@@ -0,0 +1,72 @@
1/*
2 * Copyright (C) 2014-2015 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "timestamp.h"
18
19#include <gtest/gtest.h>
20#include <gmock/gmock.h>
21
22#include <QCoreApplication>
23#include <QDebug>
24
25using namespace qtmir;
26
27TEST(TimestampTest, TestCompressAndUncompress)
28{
29 using namespace testing;
30
31 int argc = 0;
32 QCoreApplication app(argc, NULL);
33
34 std::chrono::time_point<std::chrono::system_clock> now;
35 now = std::chrono::system_clock::now();
36 auto original_timestamp = now.time_since_epoch();
37
38 std::chrono::nanoseconds addToTimestamp(0);
39 for (int i = 0; i < 100; i++) {
40 auto timestamp = original_timestamp + addToTimestamp;
41
42 ulong compressedTimestamp = qtmir::compressTimestamp<ulong>(timestamp);
43
44 EXPECT_EQ(addToTimestamp.count(), compressedTimestamp);
45 EXPECT_EQ(qtmir::uncompressTimestamp<ulong>(compressedTimestamp), timestamp);
46
47 addToTimestamp += std::chrono::milliseconds(1);
48 }
49}
50
51TEST(TimestampTest, TestOverflowWhenExceeding32bitCompression)
52{
53 using namespace testing;
54
55 int argc = 0;
56 QCoreApplication app(argc, NULL);
57
58 std::chrono::time_point<std::chrono::system_clock> now;
59 now = std::chrono::system_clock::now();
60 auto timestamp = now.time_since_epoch();
61
62 // Do first compression. This will result in qield of 0 as seen in TestCompressUncompress
63 quint32 compressedTimestamp = qtmir::compressTimestamp<quint32>(timestamp);
64
65 // Add the quint32 limit +1 to get an overflow when we compress the timestamp
66 timestamp += std::chrono::nanoseconds(std::numeric_limits<quint32>::max()) + std::chrono::nanoseconds(1);
67 compressedTimestamp = qtmir::compressTimestamp<quint32>(timestamp);
68
69 EXPECT_EQ(0, compressedTimestamp);
70 // ensure the uncompression will yields the original timestamp
71 EXPECT_EQ(qtmir::uncompressTimestamp<quint32>(compressedTimestamp), timestamp);
72}
0\ No newline at end of file73\ No newline at end of file

Subscribers

People subscribed via source and target branches