1
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
3
# Copyright (C) 2015 Canonical Ltd.
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.
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.
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/>.
17
from mir_perf_framework import PerformanceTest, Server, Client
22
from common import get_pointing_device
29
host = Server(reports=["input"])
30
nested = Server(executable=shutil.which("qtmir-demo-shell"),
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"),
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"])
40
test = PerformanceTest([host, nested, client])
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)
50
time.sleep(3) # wait for settle
52
host_pid = host.process.pid
53
nested_pid = nested.process.pid
54
client_pid = client.process.pid
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)
63
# time.sleep(5) # wait for settle
64
time.sleep(2) # wait for settle
67
####### TRACE PARSING #######
69
trace = test.babeltrace()
71
server_touch_data_timestamps = {}
72
client_touch_data_timestamps = {}
73
client_touch_data_latency = {}
75
qtmir_touch_dispatch_start = {}
76
qtmir_touch_dispatch_end = {}
77
qtmir_touch_consume_start = {}
78
qtmir_touch_consume_end = {}
80
events = report_types.Events()
82
for event in trace.events:
83
events.add_child(report_types.Event(event))
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
90
client_touch_data_timestamps[pid].append(event.timestamp)
91
client_touch_data_latency[pid].append(diff)
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"])
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)
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)
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)
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)
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(
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")
127
results.add_child(report_types.Error("No nested server touch latency data"))
129
if client_pid in client_touch_data_latency:
130
client_data = client_touch_data_latency[client_pid]
132
client_latency_xml = report_types.ResultsData(
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")
142
results.add_child(report_types.Error("No client touch latency data"))
145
if host_pid in server_touch_data_timestamps:
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
155
input_rate_xml = report_types.ResultsData(
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")
165
results.add_child(report_types.Error("No host server input event timestamp data"))
167
if nested_pid in client_touch_data_timestamps:
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
176
input_rate_xml = report_types.ResultsData(
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")
186
results.add_child(report_types.Error("No nested server input event timestamp data"))
188
if client_pid in client_touch_data_timestamps:
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
197
input_rate_xml = report_types.ResultsData(
199
statistics.mean(input_rate),
200
statistics.stdev(input_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")
207
results.add_child(report_types.Error("No client event timestamp data"))
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 []
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):
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);
232
qtmir_loop_xml = report_types.ResultsData(
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")
242
qtmir_dispatch_xml = report_types.ResultsData(
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")
252
qtmir_consume_xml = report_types.ResultsData(
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")
263
results.add_child(report_types.Error("Cannot calculate QtMir loop data - Dispatch event count did not match surface consume event count"))
265
results.add_child(events)
268
if __name__ == "__main__":
269
results = perform_test();
270
f = open("touch_event_latency.xml", "w")
271
f.write(results.to_string())