Created
October 10, 2016 19:32
-
-
Save imos/bc3e43a02ffa36a532b50fc02e4580f9 to your computer and use it in GitHub Desktop.
Benchmark for std::mutex
This file contains 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 <math.h> | |
#include <stdint.h> | |
#include <sys/time.h> | |
#include <atomic> | |
#include <functional> | |
#include <map> | |
#include <mutex> | |
#include <string> | |
#include <thread> | |
#include <vector> | |
using namespace std; | |
typedef int64_t int64; | |
const double kBenchmarkDuration = 0.7; | |
const int kShortWait = 1000; | |
class BenchmarkState { | |
public: | |
BenchmarkState(const string& name) : name_(name) {} | |
bool KeepRunning(); | |
private: | |
void PrintStats(); | |
static double GetTime(); | |
string name_; | |
double start_time_; | |
int64 iteration_ = 0; | |
int64 iteration_to_check_ = 1; | |
vector<pair<int64, double>> results_; | |
}; | |
bool BenchmarkState::KeepRunning() { | |
iteration_++; | |
if (iteration_to_check_ == iteration_) { | |
if (iteration_to_check_ == 1) { | |
iteration_to_check_ = 2; | |
start_time_ = GetTime(); | |
results_.reserve(100); | |
results_.emplace_back(iteration_, start_time_); | |
return true; | |
} | |
double current_time = GetTime(); | |
if (current_time - start_time_ < 0.1 && | |
current_time - start_time_ < kBenchmarkDuration) { | |
if (current_time - start_time_ < 0.01) { | |
iteration_to_check_ = iteration_ * 8; | |
} else { | |
iteration_to_check_ = iteration_ * 2; | |
} | |
} else { | |
results_.emplace_back(iteration_, current_time); | |
iteration_to_check_ = | |
iteration_ + round(iteration_ / (current_time - start_time_) / 10); | |
if (iteration_to_check_ <= iteration_) { | |
iteration_to_check_ = iteration_ + 1; | |
} | |
if (current_time - start_time_ > kBenchmarkDuration) { | |
PrintStats(); | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
void BenchmarkState::PrintStats() { | |
double best_qps = 0; | |
for (int i = 1; i < results_.size(); i++) { | |
best_qps = max(best_qps, (results_[i].first - results_[i - 1].first) / | |
(results_[i].second - results_[i - 1].second)); | |
} | |
printf("%32s: % 16.2f ns\n", name_.c_str(), 1e9 / best_qps); | |
} | |
double BenchmarkState::GetTime() { | |
struct timeval tv; | |
gettimeofday(&tv, nullptr); | |
return tv.tv_sec + tv.tv_usec * 1e-6; | |
} | |
void Benchmark(const string& name, std::function<void()> target) { | |
BenchmarkState state(name); | |
while (state.KeepRunning()) { | |
target(); | |
} | |
} | |
void ShortSleep() { | |
for (volatile int x = 0; x < kShortWait; x++); | |
} | |
int main() { | |
std::atomic<bool> b; | |
Benchmark("Atomic", [&]() { | |
b = true; | |
b = false; | |
}); | |
std::mutex m; | |
Benchmark("LockAndUnlock", [&]() { | |
m.lock(); | |
m.unlock(); | |
}); | |
Benchmark("ShortSleep", [&]() { | |
ShortSleep(); | |
}); | |
m.lock(); | |
std::atomic<bool> finished(false); | |
std::atomic<bool> waiting(false); | |
std::thread t([&]() { | |
while (!finished) { | |
while (waiting == false); | |
ShortSleep(); | |
m.unlock(); | |
m.lock(); | |
} | |
}); | |
Benchmark("LockAndUnlockWithContention", [&]() { | |
waiting = true; | |
m.lock(); | |
waiting = false; | |
ShortSleep(); | |
m.unlock(); | |
}); | |
waiting = true; | |
finished = true; | |
t.join(); | |
m.unlock(); | |
Benchmark("LockAndUnlockWithPenalty", [&]() { | |
waiting = true; | |
m.lock(); | |
ShortSleep(); | |
waiting = false; | |
ShortSleep(); | |
m.unlock(); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment