Merge lp:~vanvugt/mir/fix-StaleFrames-test-race into lp:mir
- fix-StaleFrames-test-race
- Merge into development-branch
Status: | Superseded |
---|---|
Proposed branch: | lp:~vanvugt/mir/fix-StaleFrames-test-race |
Merge into: | lp:mir |
Diff against target: |
211 lines (+117/-3) 1 file modified
tests/integration-tests/test_stale_frames.cpp (+117/-3) |
To merge this branch: | bzr merge lp:~vanvugt/mir/fix-StaleFrames-test-race |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mir CI Bot | continuous-integration | Needs Fixing | |
Mir development team | Pending | ||
Review via email: mp+313751@code.launchpad.net |
Commit message
Fix a race in the StaleFrames integration tests and expand the tests
to cover both swap intervals (since zero exploits the problem most
easily).
Description of the change
Mir CI Bot (mir-ci-bot) wrote : | # |
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3903
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3904
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:3905
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:3906
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Mir CI Bot (mir-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:3907
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | === modified file 'tests/integration-tests/test_stale_frames.cpp' | |||
2 | --- tests/integration-tests/test_stale_frames.cpp 2017-01-09 06:48:47 +0000 | |||
3 | +++ tests/integration-tests/test_stale_frames.cpp 2017-01-11 11:51:00 +0000 | |||
4 | @@ -20,6 +20,9 @@ | |||
5 | 20 | #include "mir_toolkit/debug/surface.h" | 20 | #include "mir_toolkit/debug/surface.h" |
6 | 21 | 21 | ||
7 | 22 | #include "mir/compositor/compositor.h" | 22 | #include "mir/compositor/compositor.h" |
8 | 23 | #include "mir/scene/surface.h" | ||
9 | 24 | #include "mir/scene/surface_factory.h" | ||
10 | 25 | #include "mir/scene/null_surface_observer.h" | ||
11 | 23 | #include "mir/renderer/renderer_factory.h" | 26 | #include "mir/renderer/renderer_factory.h" |
12 | 24 | #include "mir/graphics/renderable.h" | 27 | #include "mir/graphics/renderable.h" |
13 | 25 | #include "mir/graphics/buffer.h" | 28 | #include "mir/graphics/buffer.h" |
14 | @@ -36,6 +39,7 @@ | |||
15 | 36 | #include <mutex> | 39 | #include <mutex> |
16 | 37 | #include <condition_variable> | 40 | #include <condition_variable> |
17 | 38 | 41 | ||
18 | 42 | using namespace std::chrono_literals; | ||
19 | 39 | namespace mtf = mir_test_framework; | 43 | namespace mtf = mir_test_framework; |
20 | 40 | namespace mtd = mir::test::doubles; | 44 | namespace mtd = mir::test::doubles; |
21 | 41 | namespace mc = mir::compositor; | 45 | namespace mc = mir::compositor; |
22 | @@ -114,8 +118,66 @@ | |||
23 | 114 | StubRenderer* renderer_ = nullptr; | 118 | StubRenderer* renderer_ = nullptr; |
24 | 115 | }; | 119 | }; |
25 | 116 | 120 | ||
26 | 121 | class PostObserver : public mir::scene::NullSurfaceObserver | ||
27 | 122 | { | ||
28 | 123 | public: | ||
29 | 124 | PostObserver(std::function<void(int)> cb) : cb{cb} | ||
30 | 125 | { | ||
31 | 126 | } | ||
32 | 127 | |||
33 | 128 | void frame_posted(int count, geom::Size const&) override | ||
34 | 129 | { | ||
35 | 130 | cb(count); | ||
36 | 131 | } | ||
37 | 132 | |||
38 | 133 | private: | ||
39 | 134 | std::function<void(int)> const cb; | ||
40 | 135 | }; | ||
41 | 136 | |||
42 | 137 | class PublicSurfaceFactory : public mir::scene::SurfaceFactory | ||
43 | 138 | { | ||
44 | 139 | public: | ||
45 | 140 | using Surface = mir::scene::Surface; | ||
46 | 141 | |||
47 | 142 | PublicSurfaceFactory(std::shared_ptr<mir::scene::SurfaceFactory> const& real) : real_surface_factory{real} {} | ||
48 | 143 | |||
49 | 144 | std::shared_ptr<Surface> create_surface( | ||
50 | 145 | std::list<mir::scene::StreamInfo> const& streams, | ||
51 | 146 | mir::scene::SurfaceCreationParameters const& params) override | ||
52 | 147 | { | ||
53 | 148 | latest_surface = real_surface_factory->create_surface(streams, params); | ||
54 | 149 | return latest_surface; | ||
55 | 150 | } | ||
56 | 151 | |||
57 | 152 | std::shared_ptr<Surface> const latest() const | ||
58 | 153 | { | ||
59 | 154 | return latest_surface; | ||
60 | 155 | } | ||
61 | 156 | |||
62 | 157 | void forget_latest() | ||
63 | 158 | { | ||
64 | 159 | latest_surface.reset(); | ||
65 | 160 | } | ||
66 | 161 | |||
67 | 162 | private: | ||
68 | 163 | std::shared_ptr<mir::scene::SurfaceFactory> const real_surface_factory; | ||
69 | 164 | std::shared_ptr<Surface> latest_surface; | ||
70 | 165 | }; | ||
71 | 166 | |||
72 | 117 | struct StubServerConfig : mtf::StubbedServerConfiguration | 167 | struct StubServerConfig : mtf::StubbedServerConfiguration |
73 | 118 | { | 168 | { |
74 | 169 | std::shared_ptr<PublicSurfaceFactory> the_public_surface_factory() | ||
75 | 170 | { | ||
76 | 171 | return public_surface_factory( | ||
77 | 172 | [this]{ return std::make_shared<PublicSurfaceFactory>( | ||
78 | 173 | mtf::StubbedServerConfiguration::the_surface_factory()); }); | ||
79 | 174 | } | ||
80 | 175 | |||
81 | 176 | std::shared_ptr<mir::scene::SurfaceFactory> the_surface_factory() override | ||
82 | 177 | { | ||
83 | 178 | return the_public_surface_factory(); | ||
84 | 179 | } | ||
85 | 180 | |||
86 | 119 | std::shared_ptr<StubRendererFactory> the_stub_renderer_factory() | 181 | std::shared_ptr<StubRendererFactory> the_stub_renderer_factory() |
87 | 120 | { | 182 | { |
88 | 121 | return stub_renderer_factory( | 183 | return stub_renderer_factory( |
89 | @@ -128,17 +190,30 @@ | |||
90 | 128 | } | 190 | } |
91 | 129 | 191 | ||
92 | 130 | mir::CachedPtr<StubRendererFactory> stub_renderer_factory; | 192 | mir::CachedPtr<StubRendererFactory> stub_renderer_factory; |
93 | 193 | mir::CachedPtr<PublicSurfaceFactory> public_surface_factory; | ||
94 | 131 | }; | 194 | }; |
95 | 132 | 195 | ||
96 | 133 | using BasicFixture = mtf::BasicClientServerFixture<StubServerConfig>; | 196 | using BasicFixture = mtf::BasicClientServerFixture<StubServerConfig>; |
97 | 134 | 197 | ||
99 | 135 | struct StaleFrames : BasicFixture | 198 | struct StaleFrames : BasicFixture, |
100 | 199 | ::testing::WithParamInterface<int> | ||
101 | 136 | { | 200 | { |
102 | 201 | StaleFrames() | ||
103 | 202 | : post_observer(std::make_shared<PostObserver>( | ||
104 | 203 | [this](int n){frame_posted(n);})) | ||
105 | 204 | { | ||
106 | 205 | } | ||
107 | 206 | |||
108 | 137 | void SetUp() | 207 | void SetUp() |
109 | 138 | { | 208 | { |
110 | 139 | BasicFixture::SetUp(); | 209 | BasicFixture::SetUp(); |
111 | 140 | 210 | ||
112 | 141 | client_create_surface(); | 211 | client_create_surface(); |
113 | 212 | auto pub = server_configuration.the_public_surface_factory(); | ||
114 | 213 | auto surface = pub->latest(); | ||
115 | 214 | ASSERT_TRUE(surface); | ||
116 | 215 | surface->add_observer(post_observer); | ||
117 | 216 | pub->forget_latest(); | ||
118 | 142 | } | 217 | } |
119 | 143 | 218 | ||
120 | 144 | void TearDown() | 219 | void TearDown() |
121 | @@ -170,12 +245,45 @@ | |||
122 | 170 | server_configuration.the_compositor()->start(); | 245 | server_configuration.the_compositor()->start(); |
123 | 171 | } | 246 | } |
124 | 172 | 247 | ||
125 | 248 | /* | ||
126 | 249 | * NOTE that we wait for surface buffer posts as opposed to display posts. | ||
127 | 250 | * The difference is that surface buffer posts will precisely match the | ||
128 | 251 | * number of client swaps for any swap interval, but display posts may be | ||
129 | 252 | * fewer than the number of swaps if the client was quick and using | ||
130 | 253 | * interval zero. | ||
131 | 254 | */ | ||
132 | 255 | void frame_posted(int count) | ||
133 | 256 | { | ||
134 | 257 | std::unique_lock<std::mutex> lock(mutex); | ||
135 | 258 | posts += count; | ||
136 | 259 | posted.notify_all(); | ||
137 | 260 | } | ||
138 | 261 | |||
139 | 262 | bool wait_for_posts(int count, std::chrono::seconds timeout) | ||
140 | 263 | { | ||
141 | 264 | std::unique_lock<std::mutex> lock(mutex); | ||
142 | 265 | auto const deadline = std::chrono::steady_clock::now() + timeout; | ||
143 | 266 | while (posts < count) | ||
144 | 267 | { | ||
145 | 268 | if (posted.wait_until(lock, deadline) == std::cv_status::timeout) | ||
146 | 269 | return false; | ||
147 | 270 | } | ||
148 | 271 | posts -= count; | ||
149 | 272 | return true; | ||
150 | 273 | } | ||
151 | 274 | |||
152 | 173 | MirWindow* window; | 275 | MirWindow* window; |
153 | 276 | |||
154 | 277 | private: | ||
155 | 278 | std::shared_ptr<PostObserver> post_observer; | ||
156 | 279 | std::mutex mutex; | ||
157 | 280 | std::condition_variable posted; | ||
158 | 281 | int posts = 0; | ||
159 | 174 | }; | 282 | }; |
160 | 175 | 283 | ||
161 | 176 | } | 284 | } |
162 | 177 | 285 | ||
164 | 178 | TEST_F(StaleFrames, are_dropped_when_restarting_compositor) | 286 | TEST_P(StaleFrames, are_dropped_when_restarting_compositor) |
165 | 179 | { | 287 | { |
166 | 180 | using namespace testing; | 288 | using namespace testing; |
167 | 181 | 289 | ||
168 | @@ -186,6 +294,7 @@ | |||
169 | 186 | stale_buffers.emplace(mir_debug_surface_current_buffer_id(window)); | 294 | stale_buffers.emplace(mir_debug_surface_current_buffer_id(window)); |
170 | 187 | 295 | ||
171 | 188 | auto bs = mir_window_get_buffer_stream(window); | 296 | auto bs = mir_window_get_buffer_stream(window); |
172 | 297 | mir_buffer_stream_set_swapinterval(bs, GetParam()); | ||
173 | 189 | mir_buffer_stream_swap_buffers_sync(bs); | 298 | mir_buffer_stream_swap_buffers_sync(bs); |
174 | 190 | 299 | ||
175 | 191 | stale_buffers.emplace(mir_debug_surface_current_buffer_id(window)); | 300 | stale_buffers.emplace(mir_debug_surface_current_buffer_id(window)); |
176 | @@ -196,6 +305,7 @@ | |||
177 | 196 | auto const fresh_buffer = mg::BufferID{mir_debug_surface_current_buffer_id(window)}; | 305 | auto const fresh_buffer = mg::BufferID{mir_debug_surface_current_buffer_id(window)}; |
178 | 197 | mir_buffer_stream_swap_buffers_sync(bs); | 306 | mir_buffer_stream_swap_buffers_sync(bs); |
179 | 198 | 307 | ||
180 | 308 | ASSERT_TRUE(wait_for_posts(3, 60s)); | ||
181 | 199 | start_compositor(); | 309 | start_compositor(); |
182 | 200 | 310 | ||
183 | 201 | // Note first stale buffer and fresh_buffer may be equal when defaulting to double buffers | 311 | // Note first stale buffer and fresh_buffer may be equal when defaulting to double buffers |
184 | @@ -206,22 +316,26 @@ | |||
185 | 206 | EXPECT_THAT(stale_buffers, Not(Contains(new_buffers[0]))); | 316 | EXPECT_THAT(stale_buffers, Not(Contains(new_buffers[0]))); |
186 | 207 | } | 317 | } |
187 | 208 | 318 | ||
189 | 209 | TEST_F(StaleFrames, only_fresh_frames_are_used_after_restarting_compositor) | 319 | TEST_P(StaleFrames, only_fresh_frames_are_used_after_restarting_compositor) |
190 | 210 | { | 320 | { |
191 | 211 | using namespace testing; | 321 | using namespace testing; |
192 | 212 | 322 | ||
193 | 213 | stop_compositor(); | 323 | stop_compositor(); |
194 | 214 | 324 | ||
195 | 215 | auto bs = mir_window_get_buffer_stream(window); | 325 | auto bs = mir_window_get_buffer_stream(window); |
196 | 326 | mir_buffer_stream_set_swapinterval(bs, GetParam()); | ||
197 | 216 | mir_buffer_stream_swap_buffers_sync(bs); | 327 | mir_buffer_stream_swap_buffers_sync(bs); |
198 | 217 | mir_buffer_stream_swap_buffers_sync(bs); | 328 | mir_buffer_stream_swap_buffers_sync(bs); |
199 | 218 | 329 | ||
200 | 219 | auto const fresh_buffer = mg::BufferID{mir_debug_surface_current_buffer_id(window)}; | 330 | auto const fresh_buffer = mg::BufferID{mir_debug_surface_current_buffer_id(window)}; |
201 | 220 | mir_buffer_stream_swap_buffers_sync(bs); | 331 | mir_buffer_stream_swap_buffers_sync(bs); |
202 | 221 | 332 | ||
203 | 333 | ASSERT_TRUE(wait_for_posts(3, 60s)); | ||
204 | 222 | start_compositor(); | 334 | start_compositor(); |
205 | 223 | 335 | ||
206 | 224 | auto const new_buffers = wait_for_new_rendered_buffers(); | 336 | auto const new_buffers = wait_for_new_rendered_buffers(); |
207 | 225 | ASSERT_THAT(new_buffers.size(), Eq(1u)); | 337 | ASSERT_THAT(new_buffers.size(), Eq(1u)); |
208 | 226 | EXPECT_THAT(new_buffers[0], Eq(fresh_buffer)); | 338 | EXPECT_THAT(new_buffers[0], Eq(fresh_buffer)); |
209 | 227 | } | 339 | } |
210 | 340 | |||
211 | 341 | INSTANTIATE_TEST_CASE_P(PerSwapInterval, StaleFrames, ::testing::Values(0,1)); |
PASSED: Continuous integration, rev:3902 /mir-jenkins. ubuntu. com/job/ mir-ci/ 2479/ /mir-jenkins. ubuntu. com/job/ build-mir/ 3233 /mir-jenkins. ubuntu. com/job/ build-0- fetch/3300 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= vivid+overlay/ 3292 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= xenial+ overlay/ 3292 /mir-jenkins. ubuntu. com/job/ build-1- sourcepkg/ release= yakkety/ 3292 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= yakkety/ 3262 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= clang,platform= mesa,release= yakkety/ 3262/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial+ overlay/ 3262 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= xenial+ overlay/ 3262/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= yakkety/ 3262 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= amd64,compiler= gcc,platform= mesa,release= yakkety/ 3262/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 3262 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= cross-armhf, compiler= gcc,platform= android, release= vivid+overlay/ 3262/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 3262 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= android, release= vivid+overlay/ 3262/artifact/ output/ *zip*/output. zip /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial+ overlay/ 3262 /mir-jenkins. ubuntu. com/job/ build-2- binpkg- mir/arch= i386,compiler= gcc,platform= mesa,release= xenial+ overlay/ 3262/artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild: /mir-jenkins. ubuntu. com/job/ mir-ci/ 2479/rebuild
https:/