OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "base/base_switches.h" | 5 #include "base/base_switches.h" |
6 #include "base/bind.h" | 6 #include "base/bind.h" |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/format_macros.h" | |
8 #include "base/memory/scoped_vector.h" | 9 #include "base/memory/scoped_vector.h" |
10 #include "base/strings/stringprintf.h" | |
9 #include "base/synchronization/condition_variable.h" | 11 #include "base/synchronization/condition_variable.h" |
10 #include "base/synchronization/lock.h" | 12 #include "base/synchronization/lock.h" |
11 #include "base/synchronization/waitable_event.h" | 13 #include "base/synchronization/waitable_event.h" |
12 #include "base/threading/thread.h" | 14 #include "base/threading/thread.h" |
13 #include "base/time/time.h" | 15 #include "base/time/time.h" |
14 #include "build/build_config.h" | 16 #include "build/build_config.h" |
15 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
16 #include "testing/perf/perf_test.h" | 18 #include "testing/perf/perf_test.h" |
17 | 19 |
18 #if defined(OS_POSIX) | 20 #if defined(OS_POSIX) |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
253 bool signaled_; | 255 bool signaled_; |
254 }; | 256 }; |
255 | 257 |
256 // This is meant to test the absolute minimal context switching time | 258 // This is meant to test the absolute minimal context switching time |
257 // using our own base synchronization code. | 259 // using our own base synchronization code. |
258 typedef EventPerfTest<ConditionVariableEvent> ConditionVariablePerfTest; | 260 typedef EventPerfTest<ConditionVariableEvent> ConditionVariablePerfTest; |
259 TEST_F(ConditionVariablePerfTest, EventPingPong) { | 261 TEST_F(ConditionVariablePerfTest, EventPingPong) { |
260 RunPingPongTest("4_ConditionVariable_Threads", 4); | 262 RunPingPongTest("4_ConditionVariable_Threads", 4); |
261 } | 263 } |
262 | 264 |
265 class PostTaskTest : public testing::Test { | |
266 public: | |
267 PostTaskTest() : target_("target thread"), counter_(0) { | |
268 // Disable the task profiler as it adds significant cost! | |
269 CommandLine::Init(0, NULL); | |
270 CommandLine::ForCurrentProcess()->AppendSwitchASCII( | |
271 switches::kProfilerTiming, switches::kProfilerTimingDisabledValue); | |
272 } | |
273 | |
274 void Increment() { counter_++; } | |
275 | |
276 void PostTasks(int index) { | |
277 base::TimeTicks start = base::TimeTicks::HighResNow(); | |
278 base::TimeTicks thread_start; | |
279 if (TimeTicks::IsThreadNowSupported()) | |
280 thread_start = base::TimeTicks::ThreadNow(); | |
281 base::TimeDelta minimum = base::TimeDelta::Max(); | |
282 base::TimeDelta maximum = base::TimeDelta(); | |
283 base::TimeTicks now, lastnow = start; | |
284 do { | |
285 for (size_t i = 0; i < kBatchSize; ++i) { | |
286 target_.message_loop()->PostTask( | |
287 FROM_HERE, | |
288 base::Bind(&PostTaskTest::Increment, base::Unretained(this))); | |
289 } | |
290 now = base::TimeTicks::HighResNow(); | |
291 base::TimeDelta laptime = now - lastnow; | |
292 lastnow = now; | |
293 minimum = std::min(minimum, laptime); | |
294 maximum = std::max(maximum, laptime); | |
295 } while (now - start < base::TimeDelta::FromSeconds(kTargetTimeSec)); | |
296 posting_times_[index] = now - start; | |
297 if (TimeTicks::IsThreadNowSupported()) | |
298 posting_thread_times_[index] = | |
299 base::TimeTicks::ThreadNow() - thread_start; | |
300 min_batch_times_[index] = minimum; | |
301 max_batch_times_[index] = maximum; | |
302 } | |
303 | |
304 void PostTasksToThread(MessageLoop::Type target_type, int numPostingThreads) { | |
darin (slow to review)
2014/09/09 04:05:07
nit: numPostingThreads -> num_posting_threads
| |
305 counter_ = 0; | |
306 target_.StartWithOptions(Thread::Options(target_type, 0u)); | |
307 | |
308 ScopedVector<Thread> posting_threads; | |
309 posting_times_.reset(new base::TimeDelta[numPostingThreads]); | |
310 posting_thread_times_.reset(new base::TimeDelta[numPostingThreads]); | |
311 min_batch_times_.reset(new base::TimeDelta[numPostingThreads]); | |
312 max_batch_times_.reset(new base::TimeDelta[numPostingThreads]); | |
313 | |
314 for (int i = 0; i < numPostingThreads; ++i) { | |
315 posting_threads.push_back(new Thread("posting thread")); | |
316 posting_threads[i]->Start(); | |
darin (slow to review)
2014/09/09 04:05:06
Start() blocks the calling thread until the target
| |
317 posting_threads[i]->message_loop()->PostTask( | |
318 FROM_HERE, | |
319 base::Bind(&PostTaskTest::PostTasks, base::Unretained(this), i)); | |
320 } | |
321 | |
322 for (int i = 0; i < numPostingThreads; ++i) { | |
323 posting_threads[i]->Stop(); | |
324 } | |
325 target_.Stop(); | |
326 base::TimeDelta total_time; | |
327 base::TimeDelta total_thread_time; | |
328 base::TimeDelta min_batch_time = base::TimeDelta::Max(); | |
329 base::TimeDelta max_batch_time = base::TimeDelta(); | |
330 for (int i = 0; i < numPostingThreads; ++i) { | |
331 total_time += posting_times_[i]; | |
332 total_thread_time += posting_thread_times_[i]; | |
333 min_batch_time = std::min(min_batch_time, min_batch_times_[i]); | |
334 max_batch_time = std::max(max_batch_time, max_batch_times_[i]); | |
335 } | |
336 std::string trace = StringPrintf( | |
337 "%d_threads_posting_to_%s_pump", | |
338 numPostingThreads, | |
339 target_type == MessageLoop::TYPE_IO | |
340 ? "io" | |
341 : (target_type == MessageLoop::TYPE_UI ? "ui" : "default")); | |
342 perf_test::PrintResult( | |
343 "task", | |
344 "", | |
345 trace, | |
346 total_time.InMicroseconds() / static_cast<double>(counter_), | |
347 "us/task", | |
348 true); | |
349 perf_test::PrintResult( | |
350 "task", | |
351 "_min_batch_time", | |
352 trace, | |
353 min_batch_time.InMicroseconds() / static_cast<double>(kBatchSize), | |
354 "us/task", | |
355 false); | |
356 perf_test::PrintResult( | |
357 "task", | |
358 "_max_batch_time", | |
359 trace, | |
360 max_batch_time.InMicroseconds() / static_cast<double>(kBatchSize), | |
361 "us/task", | |
362 false); | |
363 if (TimeTicks::IsThreadNowSupported()) { | |
364 perf_test::PrintResult( | |
365 "task", | |
366 "_thread_time", | |
367 trace, | |
368 total_thread_time.InMicroseconds() / static_cast<double>(counter_), | |
369 "us/task", | |
370 true); | |
371 } | |
372 } | |
373 | |
374 private: | |
375 base::Thread target_; | |
376 scoped_ptr<base::TimeDelta[]> posting_times_; | |
377 scoped_ptr<base::TimeDelta[]> posting_thread_times_; | |
378 scoped_ptr<base::TimeDelta[]> min_batch_times_; | |
379 scoped_ptr<base::TimeDelta[]> max_batch_times_; | |
380 int counter_; | |
381 | |
382 static const size_t kTargetTimeSec = 5; | |
383 static const size_t kBatchSize = 100000; | |
384 }; | |
385 | |
386 TEST_F(PostTaskTest, ThreadTimeToIOFromOneThread) { | |
387 PostTasksToThread(MessageLoop::TYPE_IO, 1); | |
388 } | |
389 | |
390 TEST_F(PostTaskTest, ThreadTimeToIOFromTwoThreads) { | |
391 PostTasksToThread(MessageLoop::TYPE_IO, 2); | |
392 } | |
393 | |
394 TEST_F(PostTaskTest, ThreadTimeToIOFromFourThreads) { | |
395 PostTasksToThread(MessageLoop::TYPE_IO, 4); | |
396 } | |
397 | |
398 TEST_F(PostTaskTest, ThreadTimeToUIFromOneThread) { | |
399 PostTasksToThread(MessageLoop::TYPE_UI, 1); | |
400 } | |
401 | |
402 TEST_F(PostTaskTest, ThreadTimeToUIFromTwoThreads) { | |
403 PostTasksToThread(MessageLoop::TYPE_UI, 2); | |
404 } | |
405 | |
406 TEST_F(PostTaskTest, ThreadTimeToUIFromFourThreads) { | |
407 PostTasksToThread(MessageLoop::TYPE_UI, 4); | |
408 } | |
409 | |
410 TEST_F(PostTaskTest, ThreadTimeToDefaultFromOneThread) { | |
411 PostTasksToThread(MessageLoop::TYPE_DEFAULT, 1); | |
412 } | |
413 | |
414 TEST_F(PostTaskTest, ThreadTimeToDefaultFromTwoThreads) { | |
415 PostTasksToThread(MessageLoop::TYPE_DEFAULT, 2); | |
416 } | |
417 | |
418 TEST_F(PostTaskTest, ThreadTimeToDefaultFromFourThreads) { | |
419 PostTasksToThread(MessageLoop::TYPE_DEFAULT, 4); | |
420 } | |
421 | |
263 #if defined(OS_POSIX) | 422 #if defined(OS_POSIX) |
264 | 423 |
265 // Absolutely 100% minimal posix waitable event. If there is a better/faster | 424 // Absolutely 100% minimal posix waitable event. If there is a better/faster |
266 // way to force a context switch, we should use that instead. | 425 // way to force a context switch, we should use that instead. |
267 class PthreadEvent { | 426 class PthreadEvent { |
268 public: | 427 public: |
269 PthreadEvent(bool manual_reset, bool initially_signaled) { | 428 PthreadEvent(bool manual_reset, bool initially_signaled) { |
270 DCHECK(!manual_reset); | 429 DCHECK(!manual_reset); |
271 DCHECK(!initially_signaled); | 430 DCHECK(!initially_signaled); |
272 pthread_mutex_init(&mutex_, 0); | 431 pthread_mutex_init(&mutex_, 0); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
305 typedef EventPerfTest<PthreadEvent> PthreadEventPerfTest; | 464 typedef EventPerfTest<PthreadEvent> PthreadEventPerfTest; |
306 TEST_F(PthreadEventPerfTest, EventPingPong) { | 465 TEST_F(PthreadEventPerfTest, EventPingPong) { |
307 RunPingPongTest("4_PthreadCondVar_Threads", 4); | 466 RunPingPongTest("4_PthreadCondVar_Threads", 4); |
308 } | 467 } |
309 | 468 |
310 #endif | 469 #endif |
311 | 470 |
312 } // namespace | 471 } // namespace |
313 | 472 |
314 } // namespace base | 473 } // namespace base |
OLD | NEW |