Last active
July 16, 2018 21:31
-
-
Save isaachier/005647ff98fe30b71e37bf02fc97bc21 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <array> | |
#include <atomic> | |
#include <chrono> | |
#include <iostream> | |
#include <mutex> | |
#include <thread> | |
namespace { | |
class AtomicCounter { | |
public: | |
void inc(int64_t delta) { _current += delta; } | |
int64_t value() | |
{ | |
const auto currentValue = static_cast<int64_t>(_current); | |
auto previousValue = static_cast<int64_t>(_previous); | |
_previous.compare_exchange_strong(previousValue, currentValue); | |
return currentValue - previousValue; | |
} | |
private: | |
std::atomic<int64_t> _current; | |
std::atomic<int64_t> _previous; | |
}; | |
class MutexCounter { | |
public: | |
void inc(int64_t delta) | |
{ | |
std::lock_guard<std::mutex> lock(_mutex); | |
_current += delta; | |
} | |
int64_t value() | |
{ | |
std::lock_guard<std::mutex> lock(_mutex); | |
const auto result = _current - _previous; | |
_previous = _current; | |
return result; | |
} | |
private: | |
int64_t _current; | |
int64_t _previous; | |
std::mutex _mutex; | |
}; | |
template <typename Operation> | |
std::chrono::steady_clock::duration benchmark(Operation op) | |
{ | |
constexpr auto kNumIters = 1000; | |
const auto startTime = std::chrono::steady_clock::now(); | |
for (auto i = 0; i < kNumIters; ++i) { | |
op(); | |
} | |
return std::chrono::steady_clock::now() - startTime; | |
} | |
template <typename Counter> | |
void test(Counter& counter) | |
{ | |
constexpr auto kTimes = 100; | |
constexpr auto kNumThreads = 10; | |
std::array<std::thread, kNumThreads> threads; | |
for (auto&& thread : threads) { | |
thread = std::thread([&counter]() { | |
volatile int64_t dummy = 0; | |
for (auto i = 0; i < kTimes; ++i) { | |
counter.inc(rand()); | |
dummy += counter.value(); | |
} | |
}); | |
} | |
for (auto&& thread : threads) { | |
thread.join(); | |
} | |
} | |
void atomicTest() | |
{ | |
AtomicCounter counter; | |
test(counter); | |
} | |
void mutexTest() | |
{ | |
MutexCounter counter; | |
test(counter); | |
} | |
void printElapsedTime(const std::chrono::steady_clock::duration& d) | |
{ | |
std::cout << std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() | |
<< " ns"; | |
} | |
} // anonymous namespace | |
int main() | |
{ | |
srand(time(NULL)); | |
std::chrono::steady_clock::duration atomicElapsedTime; | |
std::chrono::steady_clock::duration mutexElapsedTime; | |
if (rand() % 2 != 0) { | |
mutexElapsedTime = benchmark(mutexTest); | |
atomicElapsedTime = benchmark(atomicTest); | |
} | |
else { | |
atomicElapsedTime = benchmark(atomicTest); | |
mutexElapsedTime = benchmark(mutexTest); | |
} | |
std::cout << "Atomic elapsed time: "; | |
printElapsedTime(atomicElapsedTime); | |
std::cout << '\n'; | |
std::cout << "Mutex elapsed time: "; | |
printElapsedTime(mutexElapsedTime); | |
std::cout << '\n'; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment