Skip to content

Instantly share code, notes, and snippets.

@abcdabcd987
Last active April 1, 2019 10:04
Show Gist options
  • Save abcdabcd987/f0d99b2f21567654276ca14d7d1338db to your computer and use it in GitHub Desktop.
Save abcdabcd987/f0d99b2f21567654276ca14d7d1338db to your computer and use it in GitHub Desktop.
// g++ cache-prefetching.cc -Wall -std=c++11 -g -pthread -O2
#include <string>
#include <vector>
#include <mutex>
#include <random>
#include <chrono>
#include <thread>
#include <iomanip>
#include <iostream>
#include <unordered_map>
class Foo {
std::mutex m_mutex;
std::unordered_map<std::string, int> m_map;
public:
void pass_by_reference(const std::string &key, int value) {
std::lock_guard<std::mutex> lock(m_mutex);
m_map.emplace(key, value);
}
void pass_by_value(const std::string key, int value) {
std::lock_guard<std::mutex> lock(m_mutex);
m_map.emplace(key, value);
}
void useless_copy(const std::string &key, int value) {
std::string copy(key);
std::lock_guard<std::mutex> lock(m_mutex);
m_map.emplace(copy, value);
}
void useless_hash(const std::string &key, int value) {
std::hash<std::string> hash_fn;
(void) hash_fn(key);
std::lock_guard<std::mutex> lock(m_mutex);
m_map.emplace(key, value);
}
void builtin_prefetch(const std::string &key, int value) {
__builtin_prefetch(key.data());
std::lock_guard<std::mutex> lock(m_mutex);
m_map.emplace(key, value);
}
};
std::string random_string(int len) {
static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static std::mt19937 gen(123);
static std::uniform_int_distribution<int> dist(0, sizeof(alphanum) - 1);
std::string s(len, 0);
for (int i = 0; i < len; ++i)
s[i] = alphanum[dist(gen)];
return s;
}
template <typename F>
void run(size_t num_workers, size_t num_keys, size_t num_ops, const std::vector<std::string> &key_set, F func) {
auto do_worker = [num_workers, num_keys, num_ops, &key_set, func] (size_t seed, Foo &foo) {
std::mt19937 gen(seed);
std::uniform_int_distribution<int> dist_key(0, key_set.size()-1), dist_value;
for (size_t i = 0; i < num_ops; ++i) {
auto &key = key_set[dist_key(gen)];
(foo.*func)(key, dist_value(gen));
}
};
for (size_t i = 0; i < 16; ++i) {
Foo foo;
std::vector<std::thread> workers;
for (size_t i = 0; i < num_workers; ++i)
workers.emplace_back(do_worker, i+1, std::ref(foo));
auto st = std::chrono::high_resolution_clock::now();
for (auto &worker : workers)
worker.join();
auto ed = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> diff = ed-st;
double time = diff.count();
std::cout << ' ' << std::fixed << std::setprecision(6) << time << std::flush;
}
std::cout << std::endl;
}
int main(int argc, char** argv) {
const size_t num_workers = std::stoi(argv[1]);
const size_t key_size = std::stoi(argv[2]);
const size_t num_keys = 1000000 * 32 / key_size;
const size_t num_ops = 1000000;
std::vector<std::string> key_set;
for (size_t i = 0; i < num_keys; ++i)
key_set.emplace_back(random_string(key_size));
std::cout << "pass by reference:";
run(num_workers, num_keys, num_ops, key_set, &Foo::pass_by_reference);
std::cout << "pass by value :";
run(num_workers, num_keys, num_ops, key_set, &Foo::pass_by_value);
std::cout << "useless copy :";
run(num_workers, num_keys, num_ops, key_set, &Foo::useless_copy);
std::cout << "useless hash :";
run(num_workers, num_keys, num_ops, key_set, &Foo::useless_hash);
std::cout << "builtin prefetch :";
run(num_workers, num_keys, num_ops, key_set, &Foo::builtin_prefetch);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment