1 /*
2 Copyright (c) 2005-2020 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 ////// Test configuration ////////////////////////////////////////////////////
18 #define SECONDS_RATIO 1000000 // microseconds
19
20 #ifndef REPEAT_K
21 #define REPEAT_K 50 // repeat coefficient
22 #endif
23
24 int outer_work[] = {/*256,*/ 64, 16, 4, 0};
25 int inner_work[] = {32, 8, 0 };
26
27 // keep it to calibrate the time of work without synchronization
28 #define BOX1 "baseline"
29 #define BOX1TEST TimeTest< TBB_Mutex<tbb::null_mutex>, SECONDS_RATIO >
30
31 // enable/disable tests for:
32 #define BOX2 "spin_mutex"
33 #define BOX2TEST TimeTest< TBB_Mutex<tbb::spin_mutex>, SECONDS_RATIO >
34
35 // enable/disable tests for:
36 #define BOX3 "spin_rw_mutex"
37 #define BOX3TEST TimeTest< TBB_Mutex<tbb::spin_rw_mutex>, SECONDS_RATIO >
38
39 // enable/disable tests for:
40 #define BOX4 "queuing_mutex"
41 #define BOX4TEST TimeTest< TBB_Mutex<tbb::queuing_mutex>, SECONDS_RATIO >
42
43 // enable/disable tests for:
44 //#define BOX5 "queuing_rw_mutex"
45 #define BOX5TEST TimeTest< TBB_Mutex<tbb::queuing_rw_mutex>, SECONDS_RATIO >
46
47 //////////////////////////////////////////////////////////////////////////////
48
49 #include <cstdlib>
50 #include <math.h>
51 #include <algorithm> // Need std::swap
52 #include <utility> // Need std::pair
53 #include <sstream>
54 #include "tbb/tbb_stddef.h"
55 #include "tbb/null_mutex.h"
56 #include "tbb/spin_rw_mutex.h"
57 #include "tbb/spin_mutex.h"
58 #include "tbb/queuing_mutex.h"
59 #include "tbb/queuing_rw_mutex.h"
60 #include "tbb/mutex.h"
61
62 #if INTEL_TRIAL==2
63 #include "tbb/parallel_for.h" // enable threading by TBB scheduler
64 #include "tbb/task_scheduler_init.h"
65 #include "tbb/blocked_range.h"
66 #endif
67 // for test
68 #include "time_framework.h"
69
70 using namespace tbb;
71 using namespace tbb::internal;
72
73 /////////////////////////////////////////////////////////////////////////////////////////
74
75 //! base class for tests family
76 struct TestLocks : TesterBase {
77 // Inherits "value", "threads_count", and other variables
TestLocksTestLocks78 TestLocks() : TesterBase(/*number of modes*/sizeof(outer_work)/sizeof(int)) {}
79 //! returns name of test part/mode
get_nameTestLocks80 /*override*/std::string get_name(int testn) {
81 std::ostringstream buf;
82 buf.width(4); buf.fill('0');
83 buf << outer_work[testn]; // mode number
84 return buf.str();
85 }
86 //! enables results types and returns theirs suffixes
get_result_typeTestLocks87 /*override*/const char *get_result_type(int, result_t type) const {
88 switch(type) {
89 case MIN: return " min";
90 case MAX: return " max";
91 default: return 0;
92 }
93 }
94 //! repeats count
repeat_untilTestLocks95 int repeat_until(int /*test_n*/) const {
96 return REPEAT_K*100;//TODO: suggest better?
97 }
98 //! fake work
do_workTestLocks99 void do_work(int work) volatile {
100 for(int i = 0; i < work; i++) {
101 volatile int x = i;
102 __TBB_Pause(0); // just to call inline assembler
103 x *= work/threads_count;
104 }
105 }
106 };
107
108 //! template test unit for any of TBB mutexes
109 template<typename M>
110 struct TBB_Mutex : TestLocks {
111 M mutex;
112
testTBB_Mutex113 double test(int testn, int /*threadn*/)
114 {
115 for(int r = 0; r < repeat_until(testn); ++r) {
116 do_work(outer_work[testn]);
117 {
118 typename M::scoped_lock with(mutex);
119 do_work(/*inner work*/value);
120 }
121 }
122 return 0;
123 }
124 };
125
126 /////////////////////////////////////////////////////////////////////////////////////////
127
128 //Using BOX declarations
129 #include "time_sandbox.h"
130
131 // run tests for each of inner work value
RunLoops(test_sandbox & the_test,int thread)132 void RunLoops(test_sandbox &the_test, int thread) {
133 for( unsigned i=0; i<sizeof(inner_work)/sizeof(int); ++i )
134 the_test.factory(inner_work[i], thread);
135 }
136
main(int argc,char * argv[])137 int main(int argc, char* argv[]) {
138 if(argc>1) Verbose = true;
139 int DefThread = task_scheduler_init::default_num_threads();
140 MinThread = 1; MaxThread = DefThread+1;
141 ParseCommandLine( argc, argv );
142 ASSERT(MinThread <= MaxThread, 0);
143 #if INTEL_TRIAL && defined(__TBB_parallel_for_H)
144 task_scheduler_init me(MaxThread);
145 #endif
146 {
147 test_sandbox the_test("time_locked_work", StatisticsCollector::ByThreads);
148 //TODO: refactor this out as RunThreads(test&)
149 for( int t = MinThread; t < DefThread && t <= MaxThread; t *= 2)
150 RunLoops( the_test, t ); // execute undersubscribed threads
151 if( DefThread > MinThread && DefThread <= MaxThread )
152 RunLoops( the_test, DefThread ); // execute on all hw threads
153 if( DefThread < MaxThread)
154 RunLoops( the_test, MaxThread ); // execute requested oversubscribed threads
155
156 the_test.report.SetTitle("Time of lock/unlock for mutex Name with Outer and Inner work");
157 //the_test.report.SetStatisticFormula("1AVG per size", "=AVERAGE(ROUNDS)");
158 the_test.report.Print(StatisticsCollector::HTMLFile|StatisticsCollector::ExcelXML, /*ModeName*/ "Outer work");
159 }
160 return 0;
161 }
162
163