Mir

Merge lp:~kdub/mir/nbs-overallocation into lp:mir

Proposed by Kevin DuBois
Status: Merged
Approved by: Kevin DuBois
Approved revision: no longer in the source branch.
Merged at revision: 3433
Proposed branch: lp:~kdub/mir/nbs-overallocation
Merge into: lp:mir
Diff against target: 280 lines (+136/-25)
4 files modified
src/client/buffer_stream.cpp (+21/-0)
src/client/buffer_vault.cpp (+45/-11)
src/client/buffer_vault.h (+5/-0)
tests/unit-tests/client/test_buffer_vault.cpp (+65/-14)
To merge this branch: bzr merge lp:~kdub/mir/nbs-overallocation
Reviewer Review Type Date Requested Status
Alan Griffiths Approve
Daniel van Vugt Abstain
Mir CI Bot continuous-integration Approve
Cemil Azizoglu (community) Approve
Review via email: mp+289912@code.launchpad.net

Commit message

nbs: add client-side overallocation when there's buffer pressure due to overlay/bypass scenarios and swapinterval is 0.

fixes: LP: #1557962

Description of the change

nbs: add client-side overallocation when there's buffer pressure due to overlay/bypass scenarios and swapinterval is 0.

fixes: LP: #1557962

note: thought we may not have needed, but turns out we do. I suppose this should land before lp:~kdub/mir/nbs-by-default lands.

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3421
https://mir-jenkins.ubuntu.com/job/mir-ci/638/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/574/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/610
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/602
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/602
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/584
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/584/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/584
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/584/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/584/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/584/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/584
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/584/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/584/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/638/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

^^ seems a problem with the devices

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3421
https://mir-jenkins.ubuntu.com/job/mir-ci/662/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/606
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/643
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/635
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/635
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/616
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/616/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/616
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/616/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/616
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/616/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/616
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/616/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/616
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/616/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/662/rebuild

review: Approve (continuous-integration)
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

Ok

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

+ if (current_swap_interval == interval)
+ return;

Should current_swap_interval be guarded by "mutex"?

If so, the lock is missing.

If not, then it is unclear which variables should be protected by "mutex".

review: Needs Fixing
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

This isn't a review, but I suggest more explicit logic to explain the reasons here. Something like:

// Calculate how many concurrent buffers are required to keep all our processes running smoothly in parallel:

int overlaid_buffers = (bypass||overlay) ? 1 : 0;
int compositing_buffers = 1;
int client_buffers = (swap_interval == 0) ? 2 : 1;
int total_buffers_required = client_buffers + compositing_buffers + overlaid_buffers;

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

'Needs Information' just to remind me to check this again later.

review: Needs Information
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Or even better:

// Calculate how many concurrent buffers are required to keep all our processes running smoothly in parallel:

int frames_visible_at_once = (nmonitors > 1) ? 2 : 1;
int overlaid_buffers = (bypass||overlay) ? frames_visible_at_once : 0;
int compositing_buffers = frames_visible_at_once;
int client_buffers = (swap_interval == 0) ? 2 : 1;
int min_buffers_required = client_buffers + compositing_buffers + overlaid_buffers;

Because holding an overlay/bypass buffer on the screen for scanout happens in parallel to compositing the next server frame, happens in parallel to the client preparing for the next frame after that.

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

@swapinterval, working on fixing.

@more explicit calculation
From the client's perspective, the client just really knows how many buffers the client has or how many the server has. It can increase its allocation count when it runs out (according to a policy), but it doesn't have to know why its increasing its count. In this MP, the policy is simplistic (increase when swapinterval==0), but sufficient for the bug. In the future, a better policy would be to detect periods of buffer pressure and adjust on the fly.

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3423
https://mir-jenkins.ubuntu.com/job/mir-ci/711/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/674
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/711
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/702
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/702
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/683
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/683/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/683
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/683/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/683
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/683/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/683
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/683/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/683
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/683/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/711/rebuild

review: Approve (continuous-integration)
Revision history for this message
Daniel van Vugt (vanvugt) :
review: Abstain
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

OK

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/client/buffer_stream.cpp'
2--- src/client/buffer_stream.cpp 2016-03-23 06:39:56 +0000
3+++ src/client/buffer_stream.cpp 2016-03-30 12:22:48 +0000
4@@ -63,6 +63,7 @@
5 virtual void lost_connection() = 0;
6 virtual void set_size(geom::Size) = 0;
7 virtual MirWaitHandle* set_scale(float, mf::BufferStreamId) = 0;
8+ virtual void set_interval(int interval) = 0;
9 virtual ~ServerBufferSemantics() = default;
10 ServerBufferSemantics() = default;
11 ServerBufferSemantics(ServerBufferSemantics const&) = delete;
12@@ -196,6 +197,10 @@
13 return &scale_wait_handle;
14 }
15
16+ void set_interval(int) override
17+ {
18+ }
19+
20 std::mutex mutex;
21 mcl::ClientBufferDepository wrapped;
22 mir::protobuf::DisplayServer& display_server;
23@@ -349,11 +354,25 @@
24 return &scale_wait_handle;
25 }
26
27+ void set_interval(int interval) override
28+ {
29+ std::unique_lock<decltype(mutex)> lk(mutex);
30+ interval = std::max(0, std::min(1, interval));
31+ if (current_swap_interval == interval)
32+ return;
33+ if (interval == 0)
34+ vault.increase_buffer_count();
35+ else
36+ vault.decrease_buffer_count();
37+ current_swap_interval = interval;
38+ }
39+
40 mcl::BufferVault vault;
41 std::mutex mutex;
42 mcl::BufferInfo current{nullptr, 0};
43 MirWaitHandle next_buffer_wait_handle;
44 MirWaitHandle scale_wait_handle;
45+ int current_swap_interval = 1;
46 };
47
48 }
49@@ -638,6 +657,8 @@
50 configuration.mutable_id()->set_value(protobuf_bs->id().value());
51 configuration.set_swapinterval(interval);
52
53+ buffer_depository->set_interval(interval);
54+
55 interval_wait_handle.expect_result();
56 display_server.configure_buffer_stream(&configuration, protobuf_void.get(),
57 google::protobuf::NewCallback(this, &mcl::BufferStream::on_swap_interval_set, interval));
58
59=== modified file 'src/client/buffer_vault.cpp'
60--- src/client/buffer_vault.cpp 2016-03-23 06:39:56 +0000
61+++ src/client/buffer_vault.cpp 2016-03-30 12:22:48 +0000
62@@ -32,8 +32,9 @@
63 enum class mcl::BufferVault::Owner
64 {
65 Server,
66+ Self,
67 ContentProducer,
68- Self
69+ SelfWithContent
70 };
71
72 mcl::BufferVault::BufferVault(
73@@ -45,9 +46,12 @@
74 format(format),
75 usage(usage),
76 size(size),
77- disconnected_(false)
78+ disconnected_(false),
79+ current_buffer_count(initial_nbuffers),
80+ needed_buffer_count(initial_nbuffers),
81+ initial_buffer_count(initial_nbuffers)
82 {
83- for (auto i = 0u; i < initial_nbuffers; i++)
84+ for (auto i = 0u; i < initial_buffer_count; i++)
85 server_requests->allocate_buffer(size, format, usage);
86 }
87
88@@ -95,7 +99,7 @@
89 if (it == buffers.end() || it->second.owner != Owner::ContentProducer)
90 BOOST_THROW_EXCEPTION(std::logic_error("buffer cannot be deposited"));
91
92- it->second.owner = Owner::Self;
93+ it->second.owner = Owner::SelfWithContent;
94 it->second.buffer->increment_age();
95 }
96
97@@ -106,7 +110,7 @@
98 std::unique_lock<std::mutex> lk(mutex);
99 auto it = std::find_if(buffers.begin(), buffers.end(),
100 [&buffer](std::pair<int, BufferEntry> const& entry) { return buffer == entry.second.buffer; });
101- if (it == buffers.end() || it->second.owner != Owner::Self)
102+ if (it == buffers.end() || it->second.owner != Owner::SelfWithContent)
103 BOOST_THROW_EXCEPTION(std::logic_error("buffer cannot be transferred"));
104
105 it->second.owner = Owner::Server;
106@@ -143,17 +147,18 @@
107 else
108 {
109 it->second.buffer->update_from(*package);
110- if (size == it->second.buffer->size())
111- {
112- it->second.owner = Owner::Self;
113- }
114- else
115+ it->second.owner = Owner::Self;
116+ auto should_decrease_count = (current_buffer_count > needed_buffer_count);
117+ if ((size != it->second.buffer->size()) || should_decrease_count)
118 {
119 int id = it->first;
120 buffers.erase(it);
121 lk.unlock();
122 server_requests->free_buffer(id);
123- server_requests->allocate_buffer(size, format, usage);
124+ if (should_decrease_count)
125+ current_buffer_count--;
126+ else
127+ server_requests->allocate_buffer(size, format, usage);
128 return;
129 }
130 }
131@@ -210,3 +215,32 @@
132 server_requests->free_buffer(id);
133 }
134 }
135+
136+void mcl::BufferVault::increase_buffer_count()
137+{
138+ std::unique_lock<std::mutex> lk(mutex);
139+ current_buffer_count++;
140+ needed_buffer_count++;
141+ lk.unlock();
142+
143+ server_requests->allocate_buffer(size, format, usage);
144+}
145+
146+void mcl::BufferVault::decrease_buffer_count()
147+{
148+ std::unique_lock<std::mutex> lk(mutex);
149+ if (current_buffer_count == initial_buffer_count)
150+ return;
151+ needed_buffer_count--;
152+
153+ auto it = std::find_if(buffers.begin(), buffers.end(),
154+ [](std::pair<int, BufferEntry> const& entry) { return entry.second.owner == Owner::Self; });
155+ if (it != buffers.end())
156+ {
157+ current_buffer_count--;
158+ int free_id = it->first;
159+ buffers.erase(it);
160+ lk.unlock();
161+ server_requests->free_buffer(free_id);
162+ }
163+}
164
165=== modified file 'src/client/buffer_vault.h'
166--- src/client/buffer_vault.h 2016-03-23 06:39:56 +0000
167+++ src/client/buffer_vault.h 2016-03-30 12:22:48 +0000
168@@ -71,6 +71,8 @@
169 void set_size(geometry::Size);
170 void disconnected();
171 void set_scale(float scale);
172+ void increase_buffer_count();
173+ void decrease_buffer_count();
174
175 private:
176 std::shared_ptr<ClientBufferFactory> const factory;
177@@ -90,6 +92,9 @@
178 std::deque<NoTLSPromise<BufferInfo>> promises;
179 geometry::Size size;
180 bool disconnected_;
181+ size_t current_buffer_count;
182+ size_t needed_buffer_count;
183+ size_t const initial_buffer_count;
184 };
185 }
186 }
187
188=== modified file 'tests/unit-tests/client/test_buffer_vault.cpp'
189--- tests/unit-tests/client/test_buffer_vault.cpp 2016-03-23 06:39:56 +0000
190+++ tests/unit-tests/client/test_buffer_vault.cpp 2016-03-30 12:22:48 +0000
191@@ -294,20 +294,6 @@
192 vault.wire_transfer_outbound(buffer);
193 }
194
195-//handy for android's cancelbuffer
196-TEST_F(StartedBufferVault, can_withdraw_and_deposit)
197-{
198- auto a_few_times = 5u;
199- std::vector<std::shared_ptr<mcl::ClientBuffer>> buffers(a_few_times);
200- for (auto i = 0u; i < a_few_times; i++)
201- {
202- buffers[i] = vault.withdraw().get().buffer;
203- vault.deposit(buffers[i]);
204- }
205- EXPECT_THAT(buffers, Each(buffers[0]));
206-}
207-
208-
209 TEST_F(StartedBufferVault, reallocates_incoming_buffers_of_incorrect_size_with_immediate_response)
210 {
211 mp::Buffer package4;
212@@ -484,3 +470,68 @@
213 vault.wire_transfer_inbound(package3);
214
215 }
216+
217+TEST_F(StartedBufferVault, can_increase_allocation_count)
218+{
219+ EXPECT_CALL(mock_requests, allocate_buffer(_,_,_))
220+ .Times(1);
221+ vault.increase_buffer_count();
222+
223+ Mock::VerifyAndClearExpectations(&mock_requests);
224+ //no buffers
225+}
226+
227+TEST_F(StartedBufferVault, cannot_decrease_allocation_count_below_initial)
228+{
229+ EXPECT_CALL(mock_requests, free_buffer(_))
230+ .Times(0);
231+ vault.decrease_buffer_count();
232+ Mock::VerifyAndClearExpectations(&mock_requests);
233+}
234+
235+TEST_F(StartedBufferVault, can_decrease_allocation_count)
236+{
237+ EXPECT_CALL(mock_requests, allocate_buffer(_,_,_))
238+ .Times(1);
239+ EXPECT_CALL(mock_requests, free_buffer(_))
240+ .Times(1);
241+ vault.increase_buffer_count();
242+ vault.decrease_buffer_count();
243+ Mock::VerifyAndClearExpectations(&mock_requests);
244+}
245+
246+TEST_F(StartedBufferVault, delayed_decrease_allocation_count)
247+{
248+ mp::Buffer requested_buffer;
249+ requested_buffer.set_width(size.width.as_int());
250+ requested_buffer.set_height(size.height.as_int());
251+ requested_buffer.set_buffer_id(4);
252+
253+ EXPECT_CALL(mock_requests, allocate_buffer(_,_,_))
254+ .Times(1);
255+ EXPECT_CALL(mock_requests, free_buffer(package.buffer_id()))
256+ .Times(1);
257+
258+ vault.increase_buffer_count();
259+ vault.wire_transfer_inbound(requested_buffer);
260+ auto b = vault.withdraw().get().buffer;
261+ vault.deposit(b);
262+ vault.wire_transfer_outbound(b);
263+
264+ b = vault.withdraw().get().buffer;
265+ vault.deposit(b);
266+ vault.wire_transfer_outbound(b);
267+
268+ b = vault.withdraw().get().buffer;
269+ vault.deposit(b);
270+ vault.wire_transfer_outbound(b);
271+
272+ b = vault.withdraw().get().buffer;
273+ vault.deposit(b);
274+ vault.wire_transfer_outbound(b);
275+
276+ vault.decrease_buffer_count();
277+ vault.wire_transfer_inbound(package);
278+ vault.wire_transfer_inbound(package2);
279+ Mock::VerifyAndClearExpectations(&mock_requests);
280+}

Subscribers

People subscribed via source and target branches