blob: 13a939129b99920717b6dc16c95a8a9888734ed1 [file] [log] [blame]
/*
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;
}