| /* |
| Copyright 2005-2010 Intel Corporation. All Rights Reserved. |
| |
| This file is part of Threading Building Blocks. |
| |
| Threading Building Blocks is free software; you can redistribute it |
| and/or modify it under the terms of the GNU General Public License |
| version 2 as published by the Free Software Foundation. |
| |
| Threading Building Blocks 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 Threading Building Blocks; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| |
| As a special exception, you may use this file as part of a free software |
| library without restriction. Specifically, if other files instantiate |
| templates or use macros or inline functions from this file, or you compile |
| this file and link it with other files to produce an executable, this |
| file does not by itself cause the resulting executable to be covered by |
| the GNU General Public License. This exception does not however |
| invalidate any other reasons why the executable file might be covered by |
| the GNU General Public License. |
| */ |
| |
| ////// Test configuration //////////////////////////////////////////////////// |
| #define SECONDS_RATIO 1000000 // microseconds |
| |
| #ifndef REPEAT_K |
| #define REPEAT_K 50 // repeat coefficient |
| #endif |
| |
| int outer_work[] = {/*256,*/ 64, 16, 4, 0}; |
| int inner_work[] = {32, 8, 0 }; |
| |
| // keep it to calibrate the time of work without synchronization |
| #define BOX1 "baseline" |
| #define BOX1TEST TimeTest< TBB_Mutex<tbb::null_mutex>, SECONDS_RATIO > |
| |
| // enable/disable tests for: |
| #define BOX2 "spin_mutex" |
| #define BOX2TEST TimeTest< TBB_Mutex<tbb::spin_mutex>, SECONDS_RATIO > |
| |
| // enable/disable tests for: |
| #define BOX3 "spin_rw_mutex" |
| #define BOX3TEST TimeTest< TBB_Mutex<tbb::spin_rw_mutex>, SECONDS_RATIO > |
| |
| // enable/disable tests for: |
| #define BOX4 "queuing_mutex" |
| #define BOX4TEST TimeTest< TBB_Mutex<tbb::queuing_mutex>, SECONDS_RATIO > |
| |
| // enable/disable tests for: |
| //#define BOX5 "queuing_rw_mutex" |
| #define BOX5TEST TimeTest< TBB_Mutex<tbb::queuing_rw_mutex>, SECONDS_RATIO > |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| #include <cstdlib> |
| #include <math.h> |
| #include <algorithm> // std::swap |
| #include <utility> // Need std::pair from here |
| #include <sstream> |
| #include "tbb/tbb_stddef.h" |
| #include "tbb/null_mutex.h" |
| #include "tbb/spin_rw_mutex.h" |
| #include "tbb/spin_mutex.h" |
| #include "tbb/queuing_mutex.h" |
| #include "tbb/queuing_rw_mutex.h" |
| #include "tbb/mutex.h" |
| |
| #if INTEL_TRIAL==2 |
| #include "tbb/parallel_for.h" // enable threading by TBB scheduler |
| #include "tbb/task_scheduler_init.h" |
| #include "tbb/blocked_range.h" |
| #endif |
| // for test |
| #include "time_framework.h" |
| |
| using namespace tbb; |
| using namespace tbb::internal; |
| |
| ///////////////////////////////////////////////////////////////////////////////////////// |
| |
| //! base class for tests family |
| struct TestLocks : TesterBase { |
| // Inherits "value", "threads_count", and other variables |
| TestLocks() : TesterBase(/*number of modes*/sizeof(outer_work)/sizeof(int)) {} |
| //! returns name of test part/mode |
| /*override*/std::string get_name(int testn) { |
| std::ostringstream buf; |
| buf.width(4); buf.fill('0'); |
| buf << outer_work[testn]; // mode number |
| return buf.str(); |
| } |
| //! enables results types and returns theirs suffixes |
| /*override*/const char *get_result_type(int, result_t type) const { |
| switch(type) { |
| case MIN: return " min"; |
| case MAX: return " max"; |
| default: return 0; |
| } |
| } |
| //! repeats count |
| int repeat_until(int /*test_n*/) const { |
| return REPEAT_K*100;//TODO: suggest better? |
| } |
| //! fake work |
| void do_work(int work) volatile { |
| for(int i = 0; i < work; i++) { |
| volatile int x = i; |
| __TBB_Pause(0); // just to call inline assembler |
| x *= work/threads_count; |
| } |
| } |
| }; |
| |
| //! template test unit for any of TBB mutexes |
| template<typename M> |
| struct TBB_Mutex : TestLocks { |
| M mutex; |
| |
| double test(int testn, int /*threadn*/) |
| { |
| for(int r = 0; r < repeat_until(testn); ++r) { |
| do_work(outer_work[testn]); |
| { |
| typename M::scoped_lock with(mutex); |
| do_work(/*inner work*/value); |
| } |
| } |
| return 0; |
| } |
| }; |
| |
| ///////////////////////////////////////////////////////////////////////////////////////// |
| |
| //Using BOX declarations |
| #include "time_sandbox.h" |
| |
| // run tests for each of inner work value |
| void RunLoops(test_sandbox &the_test, int thread) { |
| for( unsigned i=0; i<sizeof(inner_work)/sizeof(int); ++i ) |
| the_test.factory(inner_work[i], thread); |
| } |
| |
| int main(int argc, char* argv[]) { |
| if(argc>1) Verbose = true; |
| int DefThread = task_scheduler_init::default_num_threads(); |
| MinThread = 1; MaxThread = DefThread+1; |
| ParseCommandLine( argc, argv ); |
| ASSERT(MinThread <= MaxThread, 0); |
| #if INTEL_TRIAL && defined(__TBB_parallel_for_H) |
| task_scheduler_init me(MaxThread); |
| #endif |
| { |
| test_sandbox the_test("time_locked_work", StatisticsCollector::ByThreads); |
| //TODO: refactor this out as RunThreads(test&) |
| for( int t = MinThread; t < DefThread && t <= MaxThread; t *= 2) |
| RunLoops( the_test, t ); // execute undersubscribed threads |
| if( DefThread > MinThread && DefThread <= MaxThread ) |
| RunLoops( the_test, DefThread ); // execute on all hw threads |
| if( DefThread < MaxThread) |
| RunLoops( the_test, MaxThread ); // execute requested oversubscribed threads |
| |
| the_test.report.SetTitle("Time of lock/unlock for mutex Name with Outer and Inner work"); |
| //the_test.report.SetStatisticFormula("1AVG per size", "=AVERAGE(ROUNDS)"); |
| the_test.report.Print(StatisticsCollector::HTMLFile|StatisticsCollector::ExcelXML, /*ModeName*/ "Outer work"); |
| } |
| return 0; |
| } |
| |