Mir

Merge lp:~andreas-pokorny/mir/use-monotonic-clock-for-input into lp:mir

Proposed by Andreas Pokorny
Status: Merged
Approved by: Andreas Pokorny
Approved revision: no longer in the source branch.
Merged at revision: 3104
Proposed branch: lp:~andreas-pokorny/mir/use-monotonic-clock-for-input
Merge into: lp:mir
Diff against target: 162 lines (+28/-48)
5 files modified
3rd_party/android-input/android/frameworks/native/libs/utils/Timers.cpp (+4/-30)
src/common/logging/input_timestamp.cpp (+6/-12)
src/platforms/evdev/libinput_ptr.cpp (+13/-1)
src/server/input/key_repeat_dispatcher.cpp (+1/-1)
tests/mir_test_framework/fake_input_device_impl.cpp (+4/-4)
To merge this branch: bzr merge lp:~andreas-pokorny/mir/use-monotonic-clock-for-input
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Alan Griffiths Approve
Chris Halse Rogers Approve
Review via email: mp+277635@code.launchpad.net

Commit message

Switch to monotonic clock for everything input related

sytemTime from android-input is used by client and server within the input receiver to calculate an assumed frame time, and to attach timestamps to input events. The evdev platform now ensures with EVIOCSCLOCKID(CLOCK_MONOTONIC) that for every device opened through libinput CLOCK_MONOTONIC is used. Note that EventHub.cpp does the same.
KeyRepeatDispatcher used to emit timer events from system_clock which uses CLOCK_REALTIME. Similar reports and fake event devices required adaptation too.

Before this change CLOCK_REALTIME was used because the default build configuration of android-input refrained from using any other clock (c.f. HAVE_POSIX_CLOCKS). Hence the input event timestamps were replaced by CLOCK_REALTIME timestamps. And everything else had to follow that setup.

Description of the change

As opposed to the previous attempt, this MP does not introduce the idea of a Clock passed to platforms. Instead it relies on the underlying system to come up with good timestamps. Especially for evdev events the timestamps from the device are more accurate than the ones generated when the system compositor gets to interpret the results from libinput.

So in the end this MP just changes the already spread time stamp related bits to use the monotonic clock.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

Seems reasonable.

review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

+ auto age =
+ std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now().time_since_epoch() - when);

1. A bit wordy.
2. could be const.

    using namespace std::chrono;
    ...
    duration<double, std::milli> const age{steady_clock::now().time_since_epoch() - when};

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '3rd_party/android-input/android/frameworks/native/libs/utils/Timers.cpp'
2--- 3rd_party/android-input/android/frameworks/native/libs/utils/Timers.cpp 2015-08-18 01:35:15 +0000
3+++ 3rd_party/android-input/android/frameworks/native/libs/utils/Timers.cpp 2015-11-18 09:58:11 +0000
4@@ -20,38 +20,12 @@
5 #include <utils/Timers.h>
6 #include <std/Log.h>
7
8-#include <stdlib.h>
9-#include <stdio.h>
10-#include <unistd.h>
11-#include <sys/time.h>
12-#include <time.h>
13-#include <errno.h>
14 #include <limits.h>
15-
16-#ifdef HAVE_WIN32_THREADS
17-#include <windows.h>
18-#endif
19-
20-std::chrono::nanoseconds systemTime(int clock)
21+#include <chrono>
22+
23+std::chrono::nanoseconds systemTime(int /*clock => always MONOTONIC*/)
24 {
25-#if defined(HAVE_POSIX_CLOCKS)
26- static const clockid_t clocks[] = {
27- CLOCK_REALTIME,
28- CLOCK_MONOTONIC,
29- CLOCK_PROCESS_CPUTIME_ID,
30- CLOCK_THREAD_CPUTIME_ID
31- };
32- struct timespec t;
33- t.tv_sec = t.tv_nsec = 0;
34- clock_gettime(clocks[clock], &t);
35- return std::chrono::nanoseconds(t.tv_sec)*1000000000LL + t.tv_nsec;
36-#else
37- // we don't support the clocks here.
38- struct timeval t;
39- t.tv_sec = t.tv_usec = 0;
40- gettimeofday(&t, NULL);
41- return std::chrono::nanoseconds(t.tv_sec)*1000000000LL + std::chrono::nanoseconds(t.tv_usec)*1000LL;
42-#endif
43+ return {std::chrono::steady_clock::now().time_since_epoch()};
44 }
45
46 int toMillisecondTimeoutDelay(std::chrono::nanoseconds referenceTime, std::chrono::nanoseconds timeoutTime)
47
48=== modified file 'src/common/logging/input_timestamp.cpp'
49--- src/common/logging/input_timestamp.cpp 2015-06-17 05:20:42 +0000
50+++ src/common/logging/input_timestamp.cpp 2015-11-18 09:58:11 +0000
51@@ -19,21 +19,15 @@
52 #include "mir/logging/input_timestamp.h"
53 #include <cstdio>
54
55-std::string mir::logging::input_timestamp(std::chrono::nanoseconds when)
56+using namespace std::chrono;
57+std::string mir::logging::input_timestamp(nanoseconds when)
58 {
59- // Input events use CLOCK_REALTIME, and so we must...
60- struct timespec ts;
61- clock_gettime(CLOCK_REALTIME, &ts);
62-
63- std::chrono::nanoseconds now = std::chrono::nanoseconds(ts.tv_sec * 1000000000LL + ts.tv_nsec);
64- std::chrono::nanoseconds age = now - when;
65+ // Input events use CLOCK_MONOTONIC, and so we must...
66+ duration<double, std::milli> const age = steady_clock::now().time_since_epoch() - when;
67
68 char str[64];
69- snprintf(str, sizeof str, "%lld (%ld.%06ld ms ago)",
70- static_cast<long long>(when.count()),
71- static_cast<long>(age.count() / 1000000LL),
72- static_cast<long>(age.count() % 1000000LL));
73+ snprintf(str, sizeof str, "%lld (%.6fms ago)",
74+ static_cast<long long>(when.count()),age.count());
75
76 return std::string(str);
77 }
78-
79
80=== modified file 'src/platforms/evdev/libinput_ptr.cpp'
81--- src/platforms/evdev/libinput_ptr.cpp 2015-08-07 16:51:20 +0000
82+++ src/platforms/evdev/libinput_ptr.cpp 2015-11-18 09:58:11 +0000
83@@ -23,14 +23,26 @@
84 #include <sys/stat.h>
85 #include <fcntl.h>
86 #include <unistd.h>
87+#include <linux/input.h>
88
89 namespace mie = mir::input::evdev;
90
91 namespace
92 {
93+int use_monotonic_clock(int evdev)
94+{
95+ if (evdev != -1)
96+ {
97+ int const clockId = CLOCK_MONOTONIC;
98+ // Switch each evdev 'client' to MONOTONIC
99+ ioctl(evdev, EVIOCSCLOCKID, &clockId);
100+ }
101+ return evdev;
102+}
103+
104 int fd_open(const char* path, int flags, void* /*userdata*/)
105 {
106- return ::open(path, flags);
107+ return use_monotonic_clock(::open(path, flags));
108 }
109
110 void fd_close(int fd, void* /*userdata*/)
111
112=== modified file 'src/server/input/key_repeat_dispatcher.cpp'
113--- src/server/input/key_repeat_dispatcher.cpp 2015-10-08 00:23:43 +0000
114+++ src/server/input/key_repeat_dispatcher.cpp 2015-11-18 09:58:11 +0000
115@@ -118,7 +118,7 @@
116 {
117 std::lock_guard<std::mutex> lg(repeat_state_mutex);
118
119- ev.key.event_time = std::chrono::high_resolution_clock::now().time_since_epoch();
120+ ev.key.event_time = std::chrono::steady_clock::now().time_since_epoch();
121 ev.key.mac = cookie_factory->timestamp_to_cookie(ev.key.event_time.count()).mac;
122 next_dispatcher->dispatch(ev);
123
124
125=== modified file 'tests/mir_test_framework/fake_input_device_impl.cpp'
126--- tests/mir_test_framework/fake_input_device_impl.cpp 2015-11-04 07:43:28 +0000
127+++ tests/mir_test_framework/fake_input_device_impl.cpp 2015-11-18 09:58:11 +0000
128@@ -97,7 +97,7 @@
129 xkb_keysym_t key_code = 0;
130
131 auto event_time = std::chrono::duration_cast<std::chrono::nanoseconds>(
132- std::chrono::system_clock::now().time_since_epoch());
133+ std::chrono::steady_clock::now().time_since_epoch());
134
135 auto input_action =
136 (key_params.action == synthesis::EventAction::Down) ? mir_keyboard_action_down : mir_keyboard_action_up;
137@@ -112,7 +112,7 @@
138 void mtf::FakeInputDeviceImpl::InputDevice::synthesize_events(synthesis::ButtonParameters const& button)
139 {
140 auto event_time = std::chrono::duration_cast<std::chrono::nanoseconds>(
141- std::chrono::system_clock::now().time_since_epoch());
142+ std::chrono::steady_clock::now().time_since_epoch());
143 auto action = update_buttons(button.action, mie::to_pointer_button(button.button, settings.handedness));
144 auto button_event = builder->pointer_event(event_time,
145 action,
146@@ -149,7 +149,7 @@
147 BOOST_THROW_EXCEPTION(std::runtime_error("Device is not started."));
148
149 auto event_time = std::chrono::duration_cast<std::chrono::nanoseconds>(
150- std::chrono::system_clock::now().time_since_epoch());
151+ std::chrono::steady_clock::now().time_since_epoch());
152 // constant scaling is used here to simplify checking for the
153 // expected results. Default settings of the device lead to no
154 // scaling at all.
155@@ -183,7 +183,7 @@
156 BOOST_THROW_EXCEPTION(std::runtime_error("Device is not started."));
157
158 auto event_time = std::chrono::duration_cast<std::chrono::nanoseconds>(
159- std::chrono::system_clock::now().time_since_epoch());
160+ std::chrono::steady_clock::now().time_since_epoch());
161
162 auto touch_event = builder->touch_event(event_time);
163

Subscribers

People subscribed via source and target branches