/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright 2018 Danny Robson */ #include "job/flag.hpp" #include "job/ticketlock.hpp" #include "tap.hpp" #include #include #include /////////////////////////////////////////////////////////////////////////////// using ffs_t = std::chrono::high_resolution_clock; //----------------------------------------------------------------------------- void fight (util::job::flag &start, util::job::ticketlock &l, int total, ffs_t::time_point &finish) { start.wait (); for (int count = 0; count < total; ++count) std::lock_guard g (l); finish = std::chrono::high_resolution_clock::now (); }; //----------------------------------------------------------------------------- int main () { util::TAP::logger tap; util::job::ticketlock l; l.lock (); tap.expect (true, "locked without contention"); l.unlock (); tap.expect (true, "unlocked without contention"); if (std::thread::hardware_concurrency () < 2) { tap.skip ("reasonably fair under contention"); } else { // measure fairness under contention is below some threshold // // * create two threads that will fight over a lock // * measure the start time // * fire an event to start the threads // * record the time the threads finish // * compare the difference in runtimes as a percentage // // we have to be reasonably generous with our test at the end because // there's liable to be a lot of noise in the measurement with a test // that runs in a short enough time period. constexpr int iterations = 1 << 16; util::job::flag start_flag; ffs_t::time_point a_finish, b_finish; std::thread a (fight, std::ref (start_flag), std::ref (l), iterations, std::ref (a_finish)); std::thread b (fight, std::ref (start_flag), std::ref (l), iterations, std::ref (b_finish)); auto start = std::chrono::high_resolution_clock::now (); start_flag.notify (); a.join (); b.join (); auto a_total = std::chrono::duration_cast (a_finish - start).count (); auto b_total = std::chrono::duration_cast (b_finish - start).count (); auto diff = util::max (a_total, b_total) / float (util::min (a_total, b_total)); auto rel = util::abs (1 - diff); std::cout << rel << '\n'; tap.expect_lt (rel, 0.1f, "reasonably fair under contention"); } }