Skip to content

Instantly share code, notes, and snippets.

@isaachier
Last active July 16, 2018 21:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save isaachier/005647ff98fe30b71e37bf02fc97bc21 to your computer and use it in GitHub Desktop.
Save isaachier/005647ff98fe30b71e37bf02fc97bc21 to your computer and use it in GitHub Desktop.
#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