Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(60)

Side by Side Diff: mojo/common/message_pump_mojo.cc

Issue 1156923005: Cache vectors to avoid heap allocations on each message pump iteration. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "mojo/common/message_pump_mojo.h" 5 #include "mojo/common/message_pump_mojo.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/debug/alias.h" 10 #include "base/debug/alias.h"
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 RunState() : should_quit(false) { 46 RunState() : should_quit(false) {
47 CreateMessagePipe(NULL, &read_handle, &write_handle); 47 CreateMessagePipe(NULL, &read_handle, &write_handle);
48 } 48 }
49 49
50 base::TimeTicks delayed_work_time; 50 base::TimeTicks delayed_work_time;
51 51
52 // Used to wake up WaitForWork(). 52 // Used to wake up WaitForWork().
53 ScopedMessagePipeHandle read_handle; 53 ScopedMessagePipeHandle read_handle;
54 ScopedMessagePipeHandle write_handle; 54 ScopedMessagePipeHandle write_handle;
55 55
56 // Cached structures to avoid the heap allocation cost of std::vector<>.
57 scoped_ptr<WaitState> wait_state;
58 scoped_ptr<HandleToHandlerList> cloned_handlers;
59
56 bool should_quit; 60 bool should_quit;
57 }; 61 };
58 62
59 MessagePumpMojo::MessagePumpMojo() : run_state_(NULL), next_handler_id_(0) { 63 MessagePumpMojo::MessagePumpMojo() : run_state_(NULL), next_handler_id_(0) {
60 DCHECK(!current()) 64 DCHECK(!current())
61 << "There is already a MessagePumpMojo instance on this thread."; 65 << "There is already a MessagePumpMojo instance on this thread.";
62 g_tls_current_pump.Pointer()->Set(this); 66 g_tls_current_pump.Pointer()->Set(this);
63 } 67 }
64 68
65 MessagePumpMojo::~MessagePumpMojo() { 69 MessagePumpMojo::~MessagePumpMojo() {
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 continue; 169 continue;
166 170
167 more_work_is_plausible = delegate->DoIdleWork(); 171 more_work_is_plausible = delegate->DoIdleWork();
168 if (run_state->should_quit) 172 if (run_state->should_quit)
169 break; 173 break;
170 } 174 }
171 } 175 }
172 176
173 bool MessagePumpMojo::DoInternalWork(const RunState& run_state, bool block) { 177 bool MessagePumpMojo::DoInternalWork(const RunState& run_state, bool block) {
174 const MojoDeadline deadline = block ? GetDeadlineForWait(run_state) : 0; 178 const MojoDeadline deadline = block ? GetDeadlineForWait(run_state) : 0;
175 const WaitState wait_state = GetWaitState(run_state); 179 if (!run_state_->wait_state)
180 run_state_->wait_state.reset(new WaitState);
181 GetWaitState(run_state, run_state_->wait_state.get());
176 182
177 const WaitManyResult wait_many_result = 183 const WaitManyResult wait_many_result =
178 WaitMany(wait_state.handles, wait_state.wait_signals, deadline, nullptr); 184 WaitMany(run_state_->wait_state->handles,
185 run_state_->wait_state->wait_signals, deadline, nullptr);
179 const MojoResult result = wait_many_result.result; 186 const MojoResult result = wait_many_result.result;
180 bool did_work = true; 187 bool did_work = true;
181 if (result == MOJO_RESULT_OK) { 188 if (result == MOJO_RESULT_OK) {
182 if (wait_many_result.index == 0) { 189 if (wait_many_result.index == 0) {
183 // Control pipe was written to. 190 // Control pipe was written to.
184 ReadMessageRaw(run_state.read_handle.get(), NULL, NULL, NULL, NULL, 191 ReadMessageRaw(run_state.read_handle.get(), NULL, NULL, NULL, NULL,
185 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); 192 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
186 } else { 193 } else {
187 DCHECK(handlers_.find(wait_state.handles[wait_many_result.index]) != 194 DCHECK(handlers_.find(
195 run_state_->wait_state->handles[wait_many_result.index]) !=
188 handlers_.end()); 196 handlers_.end());
189 WillSignalHandler(); 197 WillSignalHandler();
190 handlers_[wait_state.handles[wait_many_result.index]] 198 handlers_[run_state_->wait_state->handles[wait_many_result.index]]
191 .handler->OnHandleReady(wait_state.handles[wait_many_result.index]); 199 .handler->OnHandleReady(
200 run_state_->wait_state->handles[wait_many_result.index]);
192 DidSignalHandler(); 201 DidSignalHandler();
193 } 202 }
194 } else { 203 } else {
195 switch (result) { 204 switch (result) {
196 case MOJO_RESULT_CANCELLED: 205 case MOJO_RESULT_CANCELLED:
197 case MOJO_RESULT_FAILED_PRECONDITION: 206 case MOJO_RESULT_FAILED_PRECONDITION:
198 RemoveInvalidHandle(wait_state, result, wait_many_result.index); 207 RemoveInvalidHandle(*run_state_->wait_state, result,
208 wait_many_result.index);
199 break; 209 break;
200 case MOJO_RESULT_DEADLINE_EXCEEDED: 210 case MOJO_RESULT_DEADLINE_EXCEEDED:
201 did_work = false; 211 did_work = false;
202 break; 212 break;
203 default: 213 default:
204 base::debug::Alias(&result); 214 base::debug::Alias(&result);
205 // Unexpected result is likely fatal, crash so we can determine cause. 215 // Unexpected result is likely fatal, crash so we can determine cause.
206 CHECK(false); 216 CHECK(false);
207 } 217 }
208 } 218 }
219 // To keep memory usage under control, delete the WaitState object at the end
220 // if it's vectors are too big by a factor of 2. Pre-C++11 doesn't have a way
221 // to shrink vectors, so just get rid of them and re-create on the next round.
222 if (run_state_->wait_state->handles.capacity() >
223 2 * run_state_->wait_state->handles.size() ||
224 run_state_->wait_state->wait_signals.capacity() >
225 2 * run_state_->wait_state->wait_signals.size()) {
qsr 2015/05/28 09:33:48 Not sure the || is needed here. The 2 vectors shou
Anand Mistry (off Chromium) 2015/05/28 23:27:45 Good point. They should be in sync.
226 run_state_->wait_state.reset();
227 }
209 228
210 // Notify and remove any handlers whose time has expired. Make a copy in case 229 // Notify and remove any handlers whose time has expired. Make a copy in case
211 // someone tries to add/remove new handlers from notification. 230 // someone tries to add/remove new handlers from notification.
212 const HandleToHandler cloned_handlers(handlers_); 231 if (!run_state_->cloned_handlers) {
232 run_state_->cloned_handlers.reset(new HandleToHandlerList);
233 run_state_->cloned_handlers->reserve(handlers_.size());
qsr 2015/05/28 09:33:48 Isn't the reserve always useful, whether the list
Anand Mistry (off Chromium) 2015/05/28 23:27:45 Done.
234 } else {
235 run_state_->cloned_handlers->clear();
236 }
237 for (const auto& handler : handlers_) {
238 run_state_->cloned_handlers->push_back(handler);
239 }
213 const base::TimeTicks now(internal::NowTicks()); 240 const base::TimeTicks now(internal::NowTicks());
214 for (HandleToHandler::const_iterator i = cloned_handlers.begin(); 241 for (HandleToHandlerList::const_iterator i =
215 i != cloned_handlers.end(); ++i) { 242 run_state_->cloned_handlers->begin();
243 i != run_state_->cloned_handlers->end(); ++i) {
216 // Since we're iterating over a clone of the handlers, verify the handler is 244 // Since we're iterating over a clone of the handlers, verify the handler is
217 // still valid before notifying. 245 // still valid before notifying.
218 if (!i->second.deadline.is_null() && i->second.deadline < now && 246 if (!i->second.deadline.is_null() && i->second.deadline < now &&
219 handlers_.find(i->first) != handlers_.end() && 247 handlers_.find(i->first) != handlers_.end() &&
220 handlers_[i->first].id == i->second.id) { 248 handlers_[i->first].id == i->second.id) {
221 WillSignalHandler(); 249 WillSignalHandler();
222 i->second.handler->OnHandleError(i->first, MOJO_RESULT_DEADLINE_EXCEEDED); 250 i->second.handler->OnHandleError(i->first, MOJO_RESULT_DEADLINE_EXCEEDED);
223 DidSignalHandler(); 251 DidSignalHandler();
224 handlers_.erase(i->first); 252 handlers_.erase(i->first);
225 did_work = true; 253 did_work = true;
226 } 254 }
227 } 255 }
256 if (run_state_->cloned_handlers->capacity() >
257 2 * run_state_->cloned_handlers->size()) {
258 run_state_->cloned_handlers.reset();
259 }
228 return did_work; 260 return did_work;
229 } 261 }
230 262
231 void MessagePumpMojo::RemoveInvalidHandle(const WaitState& wait_state, 263 void MessagePumpMojo::RemoveInvalidHandle(const WaitState& wait_state,
232 MojoResult result, 264 MojoResult result,
233 uint32_t index) { 265 uint32_t index) {
234 // TODO(sky): deal with control pipe going bad. 266 // TODO(sky): deal with control pipe going bad.
235 CHECK(result == MOJO_RESULT_FAILED_PRECONDITION || 267 CHECK(result == MOJO_RESULT_FAILED_PRECONDITION ||
236 result == MOJO_RESULT_CANCELLED); 268 result == MOJO_RESULT_CANCELLED);
237 CHECK_NE(index, 0u); // Indicates the control pipe went bad. 269 CHECK_NE(index, 0u); // Indicates the control pipe went bad.
(...skipping 11 matching lines...) Expand all
249 281
250 void MessagePumpMojo::SignalControlPipe(const RunState& run_state) { 282 void MessagePumpMojo::SignalControlPipe(const RunState& run_state) {
251 const MojoResult result = 283 const MojoResult result =
252 WriteMessageRaw(run_state.write_handle.get(), NULL, 0, NULL, 0, 284 WriteMessageRaw(run_state.write_handle.get(), NULL, 0, NULL, 0,
253 MOJO_WRITE_MESSAGE_FLAG_NONE); 285 MOJO_WRITE_MESSAGE_FLAG_NONE);
254 // If we can't write we likely won't wake up the thread and there is a strong 286 // If we can't write we likely won't wake up the thread and there is a strong
255 // chance we'll deadlock. 287 // chance we'll deadlock.
256 CHECK_EQ(MOJO_RESULT_OK, result); 288 CHECK_EQ(MOJO_RESULT_OK, result);
257 } 289 }
258 290
259 MessagePumpMojo::WaitState MessagePumpMojo::GetWaitState( 291 void MessagePumpMojo::GetWaitState(
260 const RunState& run_state) const { 292 const RunState& run_state,
261 WaitState wait_state; 293 MessagePumpMojo::WaitState* wait_state) const {
262 wait_state.handles.push_back(run_state.read_handle.get()); 294 wait_state->handles.clear();
263 wait_state.wait_signals.push_back(MOJO_HANDLE_SIGNAL_READABLE); 295 wait_state->wait_signals.clear();
qsr 2015/05/28 09:33:48 Do you want to use resize here?
Anand Mistry (off Chromium) 2015/05/28 23:27:45 Nah. That would change the logic here and I don't
qsr 2015/05/29 07:56:08 Sorry, I meant reserve, not resize. That will not
Anand Mistry (off Chromium) 2015/05/29 09:00:57 Done.
296 wait_state->handles.push_back(run_state.read_handle.get());
297 wait_state->wait_signals.push_back(MOJO_HANDLE_SIGNAL_READABLE);
264 298
265 for (HandleToHandler::const_iterator i = handlers_.begin(); 299 for (HandleToHandler::const_iterator i = handlers_.begin();
266 i != handlers_.end(); ++i) { 300 i != handlers_.end(); ++i) {
267 wait_state.handles.push_back(i->first); 301 wait_state->handles.push_back(i->first);
268 wait_state.wait_signals.push_back(i->second.wait_signals); 302 wait_state->wait_signals.push_back(i->second.wait_signals);
269 } 303 }
270 return wait_state;
271 } 304 }
272 305
273 MojoDeadline MessagePumpMojo::GetDeadlineForWait( 306 MojoDeadline MessagePumpMojo::GetDeadlineForWait(
274 const RunState& run_state) const { 307 const RunState& run_state) const {
275 const base::TimeTicks now(internal::NowTicks()); 308 const base::TimeTicks now(internal::NowTicks());
276 MojoDeadline deadline = TimeTicksToMojoDeadline(run_state.delayed_work_time, 309 MojoDeadline deadline = TimeTicksToMojoDeadline(run_state.delayed_work_time,
277 now); 310 now);
278 for (HandleToHandler::const_iterator i = handlers_.begin(); 311 for (HandleToHandler::const_iterator i = handlers_.begin();
279 i != handlers_.end(); ++i) { 312 i != handlers_.end(); ++i) {
280 deadline = std::min( 313 deadline = std::min(
281 TimeTicksToMojoDeadline(i->second.deadline, now), deadline); 314 TimeTicksToMojoDeadline(i->second.deadline, now), deadline);
282 } 315 }
283 return deadline; 316 return deadline;
284 } 317 }
285 318
286 void MessagePumpMojo::WillSignalHandler() { 319 void MessagePumpMojo::WillSignalHandler() {
287 FOR_EACH_OBSERVER(Observer, observers_, WillSignalHandler()); 320 FOR_EACH_OBSERVER(Observer, observers_, WillSignalHandler());
288 } 321 }
289 322
290 void MessagePumpMojo::DidSignalHandler() { 323 void MessagePumpMojo::DidSignalHandler() {
291 FOR_EACH_OBSERVER(Observer, observers_, DidSignalHandler()); 324 FOR_EACH_OBSERVER(Observer, observers_, DidSignalHandler());
292 } 325 }
293 326
294 } // namespace common 327 } // namespace common
295 } // namespace mojo 328 } // namespace mojo
OLDNEW
« mojo/common/message_pump_mojo.h ('K') | « mojo/common/message_pump_mojo.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698