~mterry/qtmir/warn-on-xapp

« back to all changes in this revision

Viewing changes to benchmarks/touch_event_latency.py

  • Committer: CI Train Bot
  • Author(s): Nick Dedekind
  • Date: 2015-10-21 11:46:54 UTC
  • mfrom: (369.4.13 qtmir)
  • Revision ID: ci-train-bot@canonical.com-20151021114654-zxs13246bxcdci9l
Added touch performance tracing and test.
Approved by: Gerry Boland

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
17
from mir_perf_framework import PerformanceTest, Server, Client
 
18
import time
 
19
import statistics
 
20
import shutil
 
21
import sys
 
22
from common import get_pointing_device
 
23
import report_types
 
24
 
 
25
####### TEST #######
 
26
 
 
27
 
 
28
def 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
 
 
268
if __name__ == "__main__":
 
269
    results = perform_test();
 
270
    f = open("touch_event_latency.xml", "w")
 
271
    f.write(results.to_string())