//------------------------------------------------------------------------------ // @file LruBenchmark.cc // @author Elvin-Alin Sindrilaru - CERN //------------------------------------------------------------------------------ /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2020 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ #include "common/CLI11.hpp" #include "namespace/ns_quarkdb/LRU.hh" #include //! Global synchronization primitives std::mutex gMutex; std::condition_variable gCondVar; std::atomic gDoneWork {0}; uint64_t randint(uint64_t start, uint64_t end) { thread_local std::mt19937 engine(std::random_device{}()); std::uniform_int_distribution<> dist(start,end); return dist(engine); } //------------------------------------------------------------------------------ //! Dummy struct used to populate the LRU //------------------------------------------------------------------------------ struct Entry { explicit Entry(std::uint64_t id) : id_(id) {} ~Entry() = default; std::uint64_t getId() const { return id_; } std::uint64_t id_; }; //------------------------------------------------------------------------------ //! Populate LRU with the desired number of entries //------------------------------------------------------------------------------ void Populate(eos::LRU& lru, uint64_t size) { for (std::uint64_t id = 1; id <= size; ++id) { lru.put(id, std::make_shared(id)); } } //------------------------------------------------------------------------------ //! Work done by each individual thread //------------------------------------------------------------------------------ void WokerThread(eos::LRU& lru, std::uint64_t num_req, std::uint64_t max_size) { std::random_device rd; std::mt19937 gen(rd()); // Pick a random start location between [1, max_size] unsigned long long random_start = randint(1ull, (unsigned long long) max_size); // Wait for notification from the main thread std::unique_lock lock(gMutex); gCondVar.wait(lock); lock.unlock(); while (num_req) { lru.get(random_start); random_start = (random_start + 1) % max_size + 1; --num_req; } ++gDoneWork; gCondVar.notify_one(); } //------------------------------------------------------------------------------ // Main programm //------------------------------------------------------------------------------ int main(int argc, char* argv[]) { CLI::App app{"LRU benchmark tool"}; std::uint64_t max_size = 1000000; std::uint32_t num_threads = 1; std::uint64_t num_requests = max_size / 10; app.add_option("-s,--size", max_size, "max size of the LRU"); app.add_option("-t,--num_threads", num_threads, "number of threads for access operations"); app.add_option("-r,--num_requests", num_requests, "number of requests per thread"); CLI11_PARSE(app, argc, argv); eos::LRU lru{max_size + 10}; Populate(lru, max_size); std::list workers; for (auto i = 0ull; i < num_threads; ++i) { workers.emplace_back(WokerThread, std::ref(lru), num_requests, max_size); } // Sleep a bit to allow all threads to start std::this_thread::sleep_for(std::chrono::seconds(2)); auto start_ts = std::chrono::system_clock::now(); gCondVar.notify_all(); // Wait for all threads to finish { std::unique_lock lock(gMutex); gCondVar.wait(lock, [&] {return (gDoneWork == num_threads);}); } auto end_ts = std::chrono::system_clock::now(); auto duration = std::chrono::duration_cast (end_ts - start_ts); std::uint64_t total_req = num_threads * num_requests; std::cout << "Rate : " << ((total_req * 1000000) / duration.count()) / 100 << " kHz\n"; for (auto& thread : workers) { thread.join(); } return 0; }