Chromium Code Reviews| 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 |