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
=== modified file 'benchmarks/mir_perf_framework/client.py'
--- benchmarks/mir_perf_framework/client.py 2015-06-26 11:31:44 +0000
+++ benchmarks/mir_perf_framework/client.py 2015-07-01 11:34:29 +0000
@@ -1,10 +1,11 @@
1import os1import os
2import subprocess2import subprocess
3import shutil3import shutil
4import time
4from .common import env_variable_for_client_report5from .common import env_variable_for_client_report
56
6class Client:7class Client:
7 def __init__(self, executable=shutil.which("mir_demo_client_egltriangle"), server=None, reports=[], options=[]):8 def __init__(self, executable=shutil.which("mir_demo_client_egltriangle"), server=None, reports=[], options=[], env={}):
8 """ Creates a Client object.9 """ Creates a Client object.
910
10 The client is not run until it is passed to a PerformanceTest and the11 The client is not run until it is passed to a PerformanceTest and the
@@ -16,11 +17,13 @@
16 reports (list of str): The lttng reports to enable. Use the 'client-' prefix to17 reports (list of str): The lttng reports to enable. Use the 'client-' prefix to
17 enable a client report.18 enable a client report.
18 options (list of str): Command-line options to use when running the client.19 options (list of str): Command-line options to use when running the client.
20 env (dict of str=>str): Extra environment variables to set when running the client
19 """21 """
20 self.executable = executable22 self.executable = executable
21 self.server = server23 self.server = server
22 self.reports = reports24 self.reports = reports
23 self.options = options25 self.options = options
26 self.env = env
24 self.process = None27 self.process = None
2528
26 def start(self):29 def start(self):
@@ -31,8 +34,13 @@
31 env["LTTNG_UST_WITHOUT_BADDR_STATEDUMP"] = "1"34 env["LTTNG_UST_WITHOUT_BADDR_STATEDUMP"] = "1"
32 for report in self.reports:35 for report in self.reports:
33 env[env_variable_for_client_report(report)] = "lttng"36 env[env_variable_for_client_report(report)] = "lttng"
37 for name,value in self.env.items():
38 env[name] = value
3439
35 self.process = subprocess.Popen(cmdline, env=env)40 self.process = subprocess.Popen(cmdline, env=env)
41 # Wait for client to start
42 # TODO: Find a better way to wait for client readiness
43 time.sleep(0.25)
3644
37 def stop(self):45 def stop(self):
38 self.process.terminate()46 self.process.terminate()
3947
=== modified file 'benchmarks/mir_perf_framework/server.py'
--- benchmarks/mir_perf_framework/server.py 2015-06-26 11:31:44 +0000
+++ benchmarks/mir_perf_framework/server.py 2015-07-01 11:34:29 +0000
@@ -5,7 +5,7 @@
5from .common import env_variable_for_client_report, unique_server_socket_path5from .common import env_variable_for_client_report, unique_server_socket_path
66
7class Server:7class Server:
8 def __init__(self, executable=shutil.which("mir_demo_server"), host=None, reports=[], options=[]):8 def __init__(self, executable=shutil.which("mir_demo_server"), host=None, reports=[], options=[], env={}):
9 """ Creates a Server object.9 """ Creates a Server object.
1010
11 The server is not run until it is passed to a PerformanceTest and the11 The server is not run until it is passed to a PerformanceTest and the
@@ -17,12 +17,14 @@
17 reports (list of str): The lttng reports to enable. Use the 'client-' prefix to17 reports (list of str): The lttng reports to enable. Use the 'client-' prefix to
18 enable a client report.18 enable a client report.
19 options (list of str): Command-line options to use when running the server.19 options (list of str): Command-line options to use when running the server.
20 env (dict of str=>str): Extra environment variables to set when running the server
20 """21 """
21 self.executable = executable22 self.executable = executable
22 self.host = host23 self.host = host
23 self.reports = reports24 self.reports = reports
24 self.socket_path = unique_server_socket_path()25 self.socket_path = unique_server_socket_path()
25 self.options = options26 self.options = options
27 self.env = env
26 self.process = None28 self.process = None
2729
28 def start(self):30 def start(self):
@@ -32,6 +34,8 @@
3234
33 env = os.environ.copy()35 env = os.environ.copy()
34 env["LTTNG_UST_WITHOUT_BADDR_STATEDUMP"] = "1"36 env["LTTNG_UST_WITHOUT_BADDR_STATEDUMP"] = "1"
37 for name,value in self.env.items():
38 env[name] = value
3539
36 for report in self.reports:40 for report in self.reports:
37 if report.startswith("client-"):41 if report.startswith("client-"):
3842
=== 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-07-01 11:34:29 +0000
@@ -0,0 +1,113 @@
1from mir_perf_framework import PerformanceTest, Server, Client
2import time
3import evdev
4import statistics
5import subprocess
6
7###### Helper classes ######
8
9class TouchScreen:
10 def __init__(self):
11 res = self.get_resolution()
12
13 allowed_events = {
14 evdev.ecodes.EV_ABS : (
15 (evdev.ecodes.ABS_MT_POSITION_X, (0, res[0], 0, 0)),
16 (evdev.ecodes.ABS_MT_POSITION_Y, (0, res[1], 0, 0)),
17 (evdev.ecodes.ABS_MT_TOUCH_MAJOR, (0, 30, 0, 0)),
18 (evdev.ecodes.ABS_MT_TRACKING_ID, (0, 65535, 0, 0)),
19 (evdev.ecodes.ABS_MT_PRESSURE, (0, 255, 0, 0)),
20 (evdev.ecodes.ABS_MT_SLOT, (0, 9, 0, 0))
21 ),
22 evdev.ecodes.EV_KEY: [
23 evdev.ecodes.BTN_TOUCH,
24 ]
25 }
26
27 self.ui = evdev.UInput(events=allowed_events, name="autopilot-finger")
28
29 def get_resolution(self):
30 out = subprocess.check_output(["fbset", "-s"])
31 out_list = out.split()
32 geometry = out_list.index(b"geometry")
33 return (int(out_list[geometry + 1]), int(out_list[geometry + 2]))
34
35 def finger_down_at(self, xy):
36 self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_SLOT, 0)
37 self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_TRACKING_ID, 0)
38 self.ui.write(evdev.ecodes.EV_KEY, evdev.ecodes.BTN_TOUCH, 1)
39 self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_POSITION_X, xy[0])
40 self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_POSITION_Y, xy[1])
41 self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_PRESSURE, 50)
42 self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_TOUCH_MAJOR, 4)
43 self.ui.syn()
44
45 def finger_up(self):
46 self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_TRACKING_ID, -1)
47 self.ui.syn()
48
49 def finger_move_to(self, xy):
50 self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_SLOT, 0)
51 self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_POSITION_X, xy[0])
52 self.ui.write(evdev.ecodes.EV_ABS, evdev.ecodes.ABS_MT_POSITION_Y, xy[1])
53 self.ui.syn()
54
55
56####### TEST #######
57
58# Disable input resampling so that the event_time field of input events,
59# used to calculate latency, is accurate
60no_resampling_env = {"MIR_CLIENT_INPUT_RATE": "0"}
61
62host = Server(reports=["input"])
63nested = Server(host=host, reports=["client-input-receiver"], env=no_resampling_env)
64client = Client(server=nested, reports=["client-input-receiver"], options=["-f"], env=no_resampling_env)
65
66test = PerformanceTest([host, nested, client])
67touch_screen = TouchScreen()
68
69test.start()
70
71# Perform three 1-second drag movements
72for i in range(3):
73 xy = (100,100)
74 touch_screen.finger_down_at(xy)
75 for i in range(100):
76 touch_screen.finger_move_to(xy)
77 xy = (xy[0] + 5, xy[1] + 5)
78 time.sleep(0.01)
79 touch_screen.finger_up()
80
81test.stop()
82
83####### TRACE PARSING #######
84
85trace = test.babeltrace()
86
87pids = {}
88data = {}
89
90for event in trace.events:
91 if event.name == "mir_client_input_receiver:touch_event":
92 pid = event["vpid"]
93 if pid not in pids.values():
94 if "nested" not in pids:
95 pids["nested"] = pid
96 elif "client" not in pids:
97 pids["client"] = pid
98 if pid not in data: data[pid] = []
99
100 data[pid].append((event.timestamp - event["event_time"]) / 1000000.0)
101
102
103print("=== Results ===")
104
105nested_data = data[pids["nested"]]
106print("Nested server received %d events" % len(nested_data))
107print("Kernel to nested server mean: %f ms stdev: %f ms" %
108 (statistics.mean(nested_data), statistics.stdev(nested_data)))
109
110client_data = data[pids["client"]]
111print("Client received %d events" % len(client_data))
112print("Kernel to client mean: %f ms stdev: %f ms" %
113 (statistics.mean(client_data), statistics.stdev(client_data)))
0114
=== modified file 'doc/performance_framework.md'
--- doc/performance_framework.md 2015-06-26 11:31:44 +0000
+++ doc/performance_framework.md 2015-07-01 11:34:29 +0000
@@ -12,7 +12,7 @@
1212
13To run a test, just execute the python3 script containing it.13To run a test, just execute the python3 script containing it.
1414
15You need to ensure that the Mir performance framework can be found by python.15We need to ensure that the Mir performance framework can be found by python.
16To do so, add the directory containing the mir_perf_framework/ directory (i.e.,16To do so, add the directory containing the mir_perf_framework/ directory (i.e.,
17its parent directory) to the PYTHONPATH env. variable:17its parent directory) to the PYTHONPATH env. variable:
1818
@@ -35,12 +35,15 @@
35### Specifying the executable to run35### Specifying the executable to run
3636
37By default the servers use the 'mir_demo_server' executable and the clients the37By default the servers use the 'mir_demo_server' executable and the clients the
38'mir_demo_client_egltriangle' executable. You can override this by using the38'mir_demo_client_egltriangle' executable. We can override this by using the
39'executable' option. You can also set custom command line arguments to use when39'executable' option. We can also set custom command line arguments to use when
40invoking the executable (even the default ones):40invoking the executable (even the default ones). Finally we can set extra
41environment variables using the 'env' option, which is a dictionary of variable
42names and values.
4143
42 server = Server(executable=shutil.which("my_test_server"),44 server = Server(executable=shutil.which("my_test_server"),
43 options=["--window-manager", "fullscreen"])45 options=["--window-manager", "fullscreen"],
46 env = {"MIR_SERVER_MY_OPTION": "on"})
4447
45### Specifying the host server a server should connect to48### Specifying the host server a server should connect to
4649
@@ -139,4 +142,5 @@
139 print(events[i].name) # Random access is OK too!142 print(events[i].name) # Random access is OK too!
140143
141This is the recommend way of accessing the events, unless you need some144This is the recommend way of accessing the events, unless you need some
142functionality offered only by the babeltrace APIs.145functionality offered only by the babeltrace APIs. Note, however, that
146creating the list of events may incur a small delay.

Subscribers

People subscribed via source and target branches