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 /* 18 Evolution.cpp: implementation file for evolution classes; evolution 19 classes do looped evolution of patterns in a defined 20 2 dimensional space 21 */ 22 23 #include "common/utility/get_default_num_threads.hpp" 24 25 #include "Evolution.hpp" 26 #include "Board.hpp" 27 28 #ifdef USE_SSE 29 #define GRAIN_SIZE 14 30 #else 31 #define GRAIN_SIZE 4000 32 #endif 33 #define TIME_SLICE 330 34 35 /* 36 Evolution 37 */ 38 39 /** 40 Evolution::UpdateMatrix() - moves the calculated destination data 41 to the source data block. No destination zeroing is required since it will 42 be completely overwritten during the next calculation cycle. 43 **/ 44 void Evolution::UpdateMatrix() { 45 memcpy(m_matrix->data, m_dest, m_size); 46 } 47 48 /* 49 SequentialEvolution 50 */ 51 52 //! SequentialEvolution::Run - begins looped evolution 53 void SequentialEvolution::Run(double execution_time, int nthread) { 54 printf("Starting game (Sequential evolution)\n"); 55 56 m_nIteration = 0; 57 m_serial_time = 0; 58 oneapi::tbb::tick_count t0 = oneapi::tbb::tick_count::now(); 59 while (!m_done) { 60 if (!is_paused) { 61 oneapi::tbb::tick_count t = oneapi::tbb::tick_count::now(); 62 Step(); 63 oneapi::tbb::tick_count t1 = oneapi::tbb::tick_count::now(); 64 ++m_nIteration; 65 double work_time = (t1 - t0).seconds(); 66 m_serial_time += work_time; 67 } 68 //! Let the parallel algorithm work uncontended almost the same time 69 //! as the serial one. See ParallelEvolution::Run() as well. 70 t0 = oneapi::tbb::tick_count::now(); 71 if (m_serial_time > execution_time) { 72 printf("iterations count = %d time = %g\n", m_nIteration, m_serial_time); 73 break; 74 } 75 } 76 } 77 78 //! SequentialEvolution::Step() - override of step method 79 void SequentialEvolution::Step() { 80 if (!is_paused) { 81 #ifdef USE_SSE 82 UpdateState(m_matrix, m_matrix->data, 0, m_matrix->height); 83 #else 84 UpdateState(m_matrix, m_dest, 0, (m_matrix->width * m_matrix->height) - 1); 85 UpdateMatrix(); 86 #endif 87 } 88 } 89 90 /* 91 ParallelEvolution 92 */ 93 94 //! SequentialEvolution::Run - begins looped evolution 95 void ParallelEvolution::Run(double execution_time, int nthread) { 96 if (nthread == utility::get_default_num_threads()) 97 printf("Starting game (Parallel evolution for automatic number of thread(s))\n"); 98 else 99 printf("Starting game (Parallel evolution for %d thread(s))\n", nthread); 100 101 m_nIteration = 0; 102 m_parallel_time = 0; 103 104 oneapi::tbb::global_control* pGlobControl = new oneapi::tbb::global_control( 105 oneapi::tbb::global_control::max_allowed_parallelism, nthread); 106 107 double work_time = m_serial_time; 108 oneapi::tbb::tick_count t0 = oneapi::tbb::tick_count::now(); 109 110 while (!m_done) { 111 if (!is_paused) { 112 oneapi::tbb::tick_count t = oneapi::tbb::tick_count::now(); 113 Step(); 114 oneapi::tbb::tick_count t1 = oneapi::tbb::tick_count::now(); 115 ++m_nIteration; 116 double real_work_time = (t1 - t0).seconds(); 117 m_parallel_time += real_work_time; 118 } 119 //! Let the serial algorithm work the same time as the parallel one. 120 t0 = oneapi::tbb::tick_count::now(); 121 if (m_parallel_time > execution_time) { 122 printf("iterations count = %d time = %g\n", m_nIteration, m_parallel_time); 123 delete pGlobControl; 124 pGlobControl = nullptr; 125 break; 126 } 127 } 128 if (pGlobControl) 129 delete pGlobControl; 130 } 131 132 /** 133 class tbb_parallel_task 134 135 TBB requires a class for parallel loop implementations. The actual 136 loop "chunks" are performed using the () operator of the class. 137 The blocked_range contains the range to calculate. Please see the 138 TBB documentation for more information. 139 **/ 140 class tbb_parallel_task { 141 public: 142 static void set_values(Matrix* source, char* dest) { 143 m_source = source; 144 m_dest = dest; 145 return; 146 } 147 148 void operator()(const oneapi::tbb::blocked_range<std::size_t>& r) const { 149 int begin = (int)r.begin(); //! capture lower range number for this chunk 150 int end = (int)r.end(); //! capture upper range number for this chunk 151 UpdateState(m_source, m_dest, begin, end); 152 } 153 154 tbb_parallel_task() {} 155 156 private: 157 static Matrix* m_source; 158 static char* m_dest; 159 }; 160 161 Matrix* tbb_parallel_task::m_source; 162 char* tbb_parallel_task::m_dest; 163 164 //! ParallelEvolution::Step() - override of Step method 165 void ParallelEvolution::Step() { 166 std::size_t begin = 0; //! beginning cell position 167 #ifdef USE_SSE 168 std::size_t end = m_matrix->height; //! ending cell position 169 #else 170 std::size_t end = m_size - 1; //! ending cell position 171 #endif 172 173 //! set matrix pointers 174 tbb_parallel_task::set_values(m_matrix, m_dest); 175 176 //! do calculation loop 177 parallel_for(oneapi::tbb::blocked_range<std::size_t>(begin, end, GRAIN_SIZE), 178 tbb_parallel_task()); 179 UpdateMatrix(); 180 } 181