123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- // Licensed to the Apache Software Foundation (ASF) under one
- // or more contributor license agreements. See the NOTICE file
- // distributed with this work for additional information
- // regarding copyright ownership. The ASF licenses this file
- // to you under the Apache License, Version 2.0 (the
- // "License"); you may not use this file except in compliance
- // with the License. You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing,
- // software distributed under the License is distributed on an
- // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- // KIND, either express or implied. See the License for the
- // specific language governing permissions and limitations
- // under the License.
- // Date: 2015/03/06 18:34:03
- #include <iostream>
- #if __cplusplus >= 201103L
- #include <condition_variable>
- #endif
- #include <gtest/gtest.h>
- #include "butil/gperftools_profiler.h"
- #include "bvar/utils/lock_timer.h"
- namespace {
- struct DummyMutex {};
- }
- namespace std {
- template <>
- class lock_guard<DummyMutex> {
- public:
- lock_guard(DummyMutex&) {}
- };
- template <>
- class unique_lock<DummyMutex> {
- public:
- unique_lock() {}
- unique_lock(DummyMutex&) {}
- template <typename T>
- unique_lock(DummyMutex&, T) {}
- bool try_lock() { return true; }
- void lock() {}
- void unlock() {}
- };
- } // namespace std
- namespace {
- using bvar::IntRecorder;
- using bvar::LatencyRecorder;
- using bvar::utils::MutexWithRecorder;
- using bvar::utils::MutexWithLatencyRecorder;
- class LockTimerTest : public testing::Test {
- };
- #if __cplusplus >= 201103L
- TEST_F(LockTimerTest, MutexWithRecorder) {
- IntRecorder recorder;
- MutexWithRecorder<std::mutex> mutex(recorder);
- {
- BAIDU_SCOPED_LOCK(mutex);
- }
- ASSERT_EQ(1u, recorder.get_value().num);
- LOG(INFO) << recorder;
- {
- std::unique_lock<decltype(mutex) > lck(mutex);
- lck.unlock();
- lck.lock();
- ASSERT_EQ(2u, recorder.get_value().num);
- LOG(INFO) << recorder;
- std::condition_variable cond;
- cond.wait_for(lck, std::chrono::milliseconds(10));
- }
- ASSERT_EQ(3u, recorder.get_value().num);
- }
- TEST_F(LockTimerTest, MutexWithLatencyRecorder) {
- LatencyRecorder recorder(10);
- MutexWithLatencyRecorder<std::mutex> mutex(recorder);
- {
- BAIDU_SCOPED_LOCK(mutex);
- }
- ASSERT_EQ(1u, recorder.count());
- {
- std::unique_lock<decltype(mutex) > lck(mutex);
- lck.unlock();
- lck.lock();
- ASSERT_EQ(2u, recorder.count());
- LOG(INFO) << recorder;
- std::condition_variable cond;
- cond.wait_for(lck, std::chrono::milliseconds(10));
- }
- ASSERT_EQ(3u, recorder.count());
- }
- #endif
- TEST_F(LockTimerTest, pthread_mutex_and_cond) {
- LatencyRecorder recorder(10);
- MutexWithLatencyRecorder<pthread_mutex_t> mutex(recorder);
- {
- BAIDU_SCOPED_LOCK(mutex);
- }
- ASSERT_EQ(1u, recorder.count());
- {
- std::unique_lock<MutexWithLatencyRecorder<pthread_mutex_t> > lck(mutex);
- ASSERT_EQ(1u, recorder.count());
- timespec due_time = butil::milliseconds_from_now(10);
- pthread_cond_t cond;
- ASSERT_EQ(0, pthread_cond_init(&cond, NULL));
- pthread_cond_timedwait(&cond, &(pthread_mutex_t&)mutex, &due_time);
- pthread_cond_timedwait(&cond, &mutex.mutex(), &due_time);
- ASSERT_EQ(0, pthread_cond_destroy(&cond));
- }
- ASSERT_EQ(2u, recorder.count());
- }
- const static size_t OPS_PER_THREAD = 1000;
- template <typename M>
- void *signal_lock_thread(void *arg) {
- M *m = (M*)arg;
- for (size_t i = 0; i < OPS_PER_THREAD; ++i) {
- {
- std::unique_lock<M> lck(*m);
- usleep(10);
- }
- }
- return NULL;
- }
- TEST_F(LockTimerTest, signal_lock_time) {
- IntRecorder r0;
- MutexWithRecorder<pthread_mutex_t> m0(r0);
- pthread_t threads[4];
- for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
- ASSERT_EQ(0, pthread_create(&threads[i], NULL,
- signal_lock_thread<MutexWithRecorder<pthread_mutex_t> >, &m0));
- }
- for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
- pthread_join(threads[i], NULL);
- }
- LOG(INFO) << r0;
- ASSERT_EQ(OPS_PER_THREAD * ARRAY_SIZE(threads), (size_t)r0.get_value().num);
- LatencyRecorder r1;
- MutexWithLatencyRecorder<pthread_mutex_t> m1(r1);
- for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
- ASSERT_EQ(0, pthread_create(&threads[i], NULL,
- signal_lock_thread<MutexWithLatencyRecorder<pthread_mutex_t> >, &m1));
- }
- for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
- pthread_join(threads[i], NULL);
- }
- LOG(INFO) << r1._latency;
- ASSERT_EQ(OPS_PER_THREAD * ARRAY_SIZE(threads), (size_t)r1.count());
- }
- template <typename M0, typename M1>
- struct DoubleLockArg {
- M0 m0;
- M1 m1;
- };
- template <typename M0, typename M1>
- void *double_lock_thread(void *arg) {
- DoubleLockArg<M0, M1>* dla = (DoubleLockArg<M0, M1>*)arg;
- for (size_t i = 0; i < OPS_PER_THREAD; ++i) {
- std::unique_lock<M0> lck0(dla->m0, std::defer_lock);
- std::unique_lock<M1> lck1(dla->m1, std::defer_lock);
- butil::double_lock(lck0, lck1);
- usleep(10);
- }
- return NULL;
- }
- TEST_F(LockTimerTest, double_lock_time) {
- typedef MutexWithRecorder<pthread_mutex_t> M0;
- typedef MutexWithLatencyRecorder<pthread_mutex_t> M1;
- DoubleLockArg<M0, M1> arg;
- IntRecorder r0;
- LatencyRecorder r1;
- arg.m0.set_recorder(r0);
- arg.m1.set_recorder(r1);
- pthread_t threads[4];
- for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
- ASSERT_EQ(0, pthread_create(&threads[i], NULL,
- double_lock_thread<M0, M1>, &arg));
- }
- for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
- pthread_join(threads[i], NULL);
- }
- ASSERT_EQ(OPS_PER_THREAD * ARRAY_SIZE(threads), (size_t)r0.get_value().num);
- ASSERT_EQ(OPS_PER_THREAD * ARRAY_SIZE(threads), (size_t)r1.count());
- LOG(INFO) << r0;
- LOG(INFO) << r1._latency;
- r0.reset();
- r1._latency.reset();
- DoubleLockArg<M1, M0> arg1;
- arg1.m0.set_recorder(r1);
- arg1.m1.set_recorder(r0);
- for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
- ASSERT_EQ(0, pthread_create(&threads[i], NULL,
- double_lock_thread<M1, M0>, &arg1));
- }
- for (size_t i = 0; i < ARRAY_SIZE(threads); ++i) {
- pthread_join(threads[i], NULL);
- }
- ASSERT_EQ(OPS_PER_THREAD * ARRAY_SIZE(threads), (size_t)r0.get_value().num);
- ASSERT_EQ(OPS_PER_THREAD * ARRAY_SIZE(threads), (size_t)r1.count());
- LOG(INFO) << r0;
- LOG(INFO) << r1._latency;
- }
- TEST_F(LockTimerTest, overhead) {
- LatencyRecorder r0;
- MutexWithLatencyRecorder<DummyMutex> m0(r0);
- butil::Timer timer;
- const size_t N = 1000 * 1000 * 10;
-
- ProfilerStart("mutex_with_latency_recorder.prof");
- timer.start();
- for (size_t i = 0; i < N; ++i) {
- BAIDU_SCOPED_LOCK(m0);
- }
- timer.stop();
- ProfilerStop();
- LOG(INFO) << "The overhead of MutexWithLatencyRecorder is "
- << timer.n_elapsed() / N << "ns";
- IntRecorder r1;
- MutexWithRecorder<DummyMutex> m1(r1);
- ProfilerStart("mutex_with_recorder.prof");
- timer.start();
- for (size_t i = 0; i < N; ++i) {
- BAIDU_SCOPED_LOCK(m1);
- }
- timer.stop();
- ProfilerStop();
- LOG(INFO) << "The overhead of MutexWithRecorder is "
- << timer.n_elapsed() / N << "ns";
- MutexWithRecorder<DummyMutex> m2;
- ProfilerStart("mutex_with_timer.prof");
- timer.start();
- for (size_t i = 0; i < N; ++i) {
- BAIDU_SCOPED_LOCK(m2);
- }
- timer.stop();
- ProfilerStop();
- LOG(INFO) << "The overhead of timer is "
- << timer.n_elapsed() / N << "ns";
- }
- } // namespace
|