Mir

Merge lp:~albaguirre/mir/fix-1428402 into lp:mir

Proposed by Alberto Aguirre
Status: Merged
Approved by: Alan Griffiths
Approved revision: no longer in the source branch.
Merged at revision: 2373
Proposed branch: lp:~albaguirre/mir/fix-1428402
Merge into: lp:mir
Diff against target: 44 lines (+11/-5)
2 files modified
src/server/frontend/protobuf_responder.cpp (+9/-5)
src/server/frontend/protobuf_responder.h (+2/-0)
To merge this branch: bzr merge lp:~albaguirre/mir/fix-1428402
Reviewer Review Type Date Requested Status
Daniel van Vugt Approve
Alan Griffiths Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+251852@code.launchpad.net

Commit message

Fix data race in ProtobufResponder::send_response

Description of the change

Fix data race in ProtobufResponder::send_response

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
Daniel van Vugt (vanvugt) wrote :

Looks like send_response_result doesn't need to be a class member at all (?)

If not, then convert it to a local variable and no locking is required. Lock-less it might perform better, despite having to construct a local each time.

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

> Looks like send_response_result doesn't need to be a class member at all (?)

+1, it looks like this would work, and the MessageSender/ResourceCache have locks around their internals.

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

> Looks like send_response_result doesn't need to be a class member at all (?)
>
> If not, then convert it to a local variable and no locking is required. Lock-
> less it might perform better, despite having to construct a local each time.

IIRC this became a class member based on profiling a long time ago (it being "good practice to reuse protobuf objects"). I think in those days we only had one thread accessing it.

As contention free locks are fairly cheap I'm not convinced making it local would be a performance gain.

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

*Needs Discussion*

I wonder whether the better fix is to ensure there is only a single IPC thread running and dispatch all activity to that thread.

review: Needs Information
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

> *Needs Discussion*
>
> I wonder whether the better fix is to ensure there is only a single IPC thread
> running and dispatch all activity to that thread.

By default the IPC thread pool is set to 1 but it's configurable option (--ipc-thread-pool)

The other thread involved is the compositor thread, because of the completion given to surface.swap_buffers in SessionMediator::exchange_buffer (which we could make synchronous).

Revision history for this message
Alberto Aguirre (albaguirre) wrote :

So then we have three options:

1. Make send_response_result a local
2. Protect send_response_result
3. Make SessionMediator::exchange_buffer synchronous (i.e. don't execute done->Run() in the surface.swap_buffers completion function, instead wait for the completion to occur) and remove the --ipc-thread-pool option

Revision history for this message
Alberto Aguirre (albaguirre) wrote :

So option 3 is out of the question, since it would block the IPC thread.

Option 1 would potentially have performance impacts (protobuf objects could be heavy to construct).

So I rather keep the current optimization, protect it with a lock. When we re-profile IPC we can then revisit this decision.

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

OK, good enough for a bugfix.

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

It's not a blocker if we don't know the answer...

The only issue to consider is that CPU hogs (excessive construction) are easy to find because any profiler can find them. Real-time wasters (excessive locking or sleeping) are harder; only real-time profilers like Google Profiler or Rational Quantify will notice those.

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

We are presently assuming no thread does:
  send_response_result.set_events(...
If one did then the threads could interfere with each other.

Otherwise OK.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/server/frontend/protobuf_responder.cpp'
2--- src/server/frontend/protobuf_responder.cpp 2015-01-21 07:34:50 +0000
3+++ src/server/frontend/protobuf_responder.cpp 2015-03-05 01:06:08 +0000
4@@ -43,11 +43,15 @@
5
6 response->SerializeWithCachedSizesToArray(send_response_buffer.data());
7
8- send_response_result.set_id(id);
9- send_response_result.set_response(send_response_buffer.data(), send_response_buffer.size());
10-
11- send_response_buffer.resize(send_response_result.ByteSize());
12- send_response_result.SerializeWithCachedSizesToArray(send_response_buffer.data());
13+ {
14+ std::lock_guard<decltype(result_guard)> lock{result_guard};
15+
16+ send_response_result.set_id(id);
17+ send_response_result.set_response(send_response_buffer.data(), send_response_buffer.size());
18+
19+ send_response_buffer.resize(send_response_result.ByteSize());
20+ send_response_result.SerializeWithCachedSizesToArray(send_response_buffer.data());
21+ }
22
23 sender->send(reinterpret_cast<char*>(send_response_buffer.data()), send_response_buffer.size(), fd_sets);
24 resource_cache->free_resource(response);
25
26=== modified file 'src/server/frontend/protobuf_responder.h'
27--- src/server/frontend/protobuf_responder.h 2015-01-21 07:34:50 +0000
28+++ src/server/frontend/protobuf_responder.h 2015-03-05 01:06:08 +0000
29@@ -23,6 +23,7 @@
30 #include "mir_protobuf_wire.pb.h"
31
32 #include <memory>
33+#include <mutex>
34
35 namespace mir
36 {
37@@ -50,6 +51,7 @@
38 std::shared_ptr<MessageSender> const sender;
39 std::shared_ptr<ResourceCache> const resource_cache;
40
41+ std::mutex result_guard;
42 mir::protobuf::wire::Result send_response_result;
43 };
44 }

Subscribers

People subscribed via source and target branches