Mir

Merge lp:~afrantzis/mir/touch-event-latency-benchmark into lp:mir

Proposed by Alexandros Frantzis
Status: Merged
Approved by: Daniel van Vugt
Approved revision: no longer in the source branch.
Merged at revision: 2724
Proposed branch: lp:~afrantzis/mir/touch-event-latency-benchmark
Merge into: lp:mir
Diff against target: 239 lines (+137/-8)
4 files modified
benchmarks/mir_perf_framework/client.py (+9/-1)
benchmarks/mir_perf_framework/server.py (+5/-1)
benchmarks/touch_event_latency.py (+113/-0)
doc/performance_framework.md (+10/-6)
To merge this branch: bzr merge lp:~afrantzis/mir/touch-event-latency-benchmark
Reviewer Review Type Date Requested Status
Andreas Pokorny (community) Approve
Kevin DuBois (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+263503@code.launchpad.net

Commit message

benchmarks: Add touch event latency benchmark

Also, enhance the perfomance framework to support the touch event latency benchmark.

Description of the change

benchmarks: Add touch event latency benchmark

Also, enhance the perfomance framework to support the touch event latency benchmark.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

41 + time.sleep(0.25)
could we monitor for some rpc startup lttng messages perhaps?

Revision history for this message
Kevin DuBois (kdub) :
review: Needs Information
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

> 41 + time.sleep(0.25)
> could we monitor for some rpc startup lttng messages perhaps?

That was my first thought, but I haven't found a reliable way to do that without stopping the session, which is problematic since we then may miss other interesting events (until we restart).

I am still investigating if there is reliable way to read information without stopping, but since the workaround seems to work reasonably well, I decided to propose this MP as is for now.

Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

FWIW, a possible solution I am investigating is using 'relayd' live tracing feature of LTTng, but need to experiment more with it.

Revision history for this message
Kevin DuBois (kdub) wrote :

I'm okay with the todo, lgtm

review: Approve
Revision history for this message
Andreas Pokorny (andreas-pokorny) wrote :

ok looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'benchmarks/mir_perf_framework/client.py'
2--- benchmarks/mir_perf_framework/client.py 2015-06-26 11:31:44 +0000
3+++ benchmarks/mir_perf_framework/client.py 2015-07-01 11:34:29 +0000
4@@ -1,10 +1,11 @@
5 import os
6 import subprocess
7 import shutil
8+import time
9 from .common import env_variable_for_client_report
10
11 class Client:
12- def __init__(self, executable=shutil.which("mir_demo_client_egltriangle"), server=None, reports=[], options=[]):
13+ def __init__(self, executable=shutil.which("mir_demo_client_egltriangle"), server=None, reports=[], options=[], env={}):
14 """ Creates a Client object.
15
16 The client is not run until it is passed to a PerformanceTest and the
17@@ -16,11 +17,13 @@
18 reports (list of str): The lttng reports to enable. Use the 'client-' prefix to
19 enable a client report.
20 options (list of str): Command-line options to use when running the client.
21+ env (dict of str=>str): Extra environment variables to set when running the client
22 """
23 self.executable = executable
24 self.server = server
25 self.reports = reports
26 self.options = options
27+ self.env = env
28 self.process = None
29
30 def start(self):
31@@ -31,8 +34,13 @@
32 env["LTTNG_UST_WITHOUT_BADDR_STATEDUMP"] = "1"
33 for report in self.reports:
34 env[env_variable_for_client_report(report)] = "lttng"
35+ for name,value in self.env.items():
36+ env[name] = value
37
38 self.process = subprocess.Popen(cmdline, env=env)
39+ # Wait for client to start
40+ # TODO: Find a better way to wait for client readiness
41+ time.sleep(0.25)
42
43 def stop(self):
44 self.process.terminate()
45
46=== modified file 'benchmarks/mir_perf_framework/server.py'
47--- benchmarks/mir_perf_framework/server.py 2015-06-26 11:31:44 +0000
48+++ benchmarks/mir_perf_framework/server.py 2015-07-01 11:34:29 +0000
49@@ -5,7 +5,7 @@
50 from .common import env_variable_for_client_report, unique_server_socket_path
51
52 class Server:
53- def __init__(self, executable=shutil.which("mir_demo_server"), host=None, reports=[], options=[]):
54+ def __init__(self, executable=shutil.which("mir_demo_server"), host=None, reports=[], options=[], env={}):
55 """ Creates a Server object.
56
57 The server is not run until it is passed to a PerformanceTest and the
58@@ -17,12 +17,14 @@
59 reports (list of str): The lttng reports to enable. Use the 'client-' prefix to
60 enable a client report.
61 options (list of str): Command-line options to use when running the server.
62+ env (dict of str=>str): Extra environment variables to set when running the server
63 """
64 self.executable = executable
65 self.host = host
66 self.reports = reports
67 self.socket_path = unique_server_socket_path()
68 self.options = options
69+ self.env = env
70 self.process = None
71
72 def start(self):
73@@ -32,6 +34,8 @@
74
75 env = os.environ.copy()
76 env["LTTNG_UST_WITHOUT_BADDR_STATEDUMP"] = "1"
77+ for name,value in self.env.items():
78+ env[name] = value
79
80 for report in self.reports:
81 if report.startswith("client-"):
82
83=== added file 'benchmarks/touch_event_latency.py'
84--- benchmarks/touch_event_latency.py 1970-01-01 00:00:00 +0000
85+++ benchmarks/touch_event_latency.py 2015-07-01 11:34:29 +0000
86@@ -0,0 +1,113 @@
87+from mir_perf_framework import PerformanceTest, Server, Client
88+import time
89+import evdev
90+import statistics
91+import subprocess
92+
93+###### Helper classes ######
94+
95+class TouchScreen:
96+ def __init__(self):
97+ res = self.get_resolution()
98+
99+ allowed_events = {
100+ evdev.ecodes.EV_ABS : (
101+ (evdev.ecodes.ABS_MT_POSITION_X, (0, res[0], 0, 0)),
102+ (evdev.ecodes.ABS_MT_POSITION_Y, (0, res[1], 0, 0)),
103+ (evdev.ecodes.ABS_MT_TOUCH_MAJOR, (0, 30, 0, 0)),
104+ (evdev.ecodes.ABS_MT_TRACKING_ID, (0, 65535, 0, 0)),
105+ (evdev.ecodes.ABS_MT_PRESSURE, (0, 255, 0, 0)),
106+ (evdev.ecodes.ABS_MT_SLOT, (0, 9, 0, 0))
107+ ),
108+ evdev.ecodes.EV_KEY: [
109+ evdev.ecodes.BTN_TOUCH,
110+ ]
111+ }
112+
113+ self.ui = evdev.UInput(events=allowed_events, name="autopilot-finger")
114+
115+ def get_resolution(self):
116+ out = subprocess.check_output(["fbset", "-s"])
117+ out_list = out.split()
118+ geometry = out_list.index(b"geometry")
119+ return (int(out_list[geometry + 1]), int(out_list[geometry + 2]))
120+
121+ def finger_down_at(self, xy):
122+ self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_SLOT, 0)
123+ self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_TRACKING_ID, 0)
124+ self.ui.write(evdev.ecodes.EV_KEY, evdev.ecodes.BTN_TOUCH, 1)
125+ self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_POSITION_X, xy[0])
126+ self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_POSITION_Y, xy[1])
127+ self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_PRESSURE, 50)
128+ self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_TOUCH_MAJOR, 4)
129+ self.ui.syn()
130+
131+ def finger_up(self):
132+ self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_TRACKING_ID, -1)
133+ self.ui.syn()
134+
135+ def finger_move_to(self, xy):
136+ self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_SLOT, 0)
137+ self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_POSITION_X, xy[0])
138+ self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_POSITION_Y, xy[1])
139+ self.ui.syn()
140+
141+
142+####### TEST #######
143+
144+# Disable input resampling so that the event_time field of input events,
145+# used to calculate latency, is accurate
146+no_resampling_env = {"MIR_CLIENT_INPUT_RATE": "0"}
147+
148+host = Server(reports=["input"])
149+nested = Server(host=host, reports=["client-input-receiver"], env=no_resampling_env)
150+client = Client(server=nested, reports=["client-input-receiver"], options=["-f"], env=no_resampling_env)
151+
152+test = PerformanceTest([host, nested, client])
153+touch_screen = TouchScreen()
154+
155+test.start()
156+
157+# Perform three 1-second drag movements
158+for i in range(3):
159+ xy = (100,100)
160+ touch_screen.finger_down_at(xy)
161+ for i in range(100):
162+ touch_screen.finger_move_to(xy)
163+ xy = (xy[0] + 5, xy[1] + 5)
164+ time.sleep(0.01)
165+ touch_screen.finger_up()
166+
167+test.stop()
168+
169+####### TRACE PARSING #######
170+
171+trace = test.babeltrace()
172+
173+pids = {}
174+data = {}
175+
176+for event in trace.events:
177+ if event.name == "mir_client_input_receiver:touch_event":
178+ pid = event["vpid"]
179+ if pid not in pids.values():
180+ if "nested" not in pids:
181+ pids["nested"] = pid
182+ elif "client" not in pids:
183+ pids["client"] = pid
184+ if pid not in data: data[pid] = []
185+
186+ data[pid].append((event.timestamp - event["event_time"]) / 1000000.0)
187+
188+
189+print("=== Results ===")
190+
191+nested_data = data[pids["nested"]]
192+print("Nested server received %d events" % len(nested_data))
193+print("Kernel to nested server mean: %f ms stdev: %f ms" %
194+ (statistics.mean(nested_data), statistics.stdev(nested_data)))
195+
196+client_data = data[pids["client"]]
197+print("Client received %d events" % len(client_data))
198+print("Kernel to client mean: %f ms stdev: %f ms" %
199+ (statistics.mean(client_data), statistics.stdev(client_data)))
200
201=== modified file 'doc/performance_framework.md'
202--- doc/performance_framework.md 2015-06-26 11:31:44 +0000
203+++ doc/performance_framework.md 2015-07-01 11:34:29 +0000
204@@ -12,7 +12,7 @@
205
206 To run a test, just execute the python3 script containing it.
207
208-You need to ensure that the Mir performance framework can be found by python.
209+We need to ensure that the Mir performance framework can be found by python.
210 To do so, add the directory containing the mir_perf_framework/ directory (i.e.,
211 its parent directory) to the PYTHONPATH env. variable:
212
213@@ -35,12 +35,15 @@
214 ### Specifying the executable to run
215
216 By default the servers use the 'mir_demo_server' executable and the clients the
217-'mir_demo_client_egltriangle' executable. You can override this by using the
218-'executable' option. You can also set custom command line arguments to use when
219-invoking the executable (even the default ones):
220+'mir_demo_client_egltriangle' executable. We can override this by using the
221+'executable' option. We can also set custom command line arguments to use when
222+invoking the executable (even the default ones). Finally we can set extra
223+environment variables using the 'env' option, which is a dictionary of variable
224+names and values.
225
226 server = Server(executable=shutil.which("my_test_server"),
227- options=["--window-manager", "fullscreen"])
228+ options=["--window-manager", "fullscreen"],
229+ env = {"MIR_SERVER_MY_OPTION": "on"})
230
231 ### Specifying the host server a server should connect to
232
233@@ -139,4 +142,5 @@
234 print(events[i].name) # Random access is OK too!
235
236 This is the recommend way of accessing the events, unless you need some
237-functionality offered only by the babeltrace APIs.
238+functionality offered only by the babeltrace APIs. Note, however, that
239+creating the list of events may incur a small delay.

Subscribers

People subscribed via source and target branches