1 /*
2 Copyright (c) 2005-2021 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 **/
UpdateMatrix()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
Run(double execution_time,int nthread)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
Step()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
Run(double execution_time,int nthread)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 delete pGlobControl;
129 pGlobControl = nullptr;
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:
set_values(Matrix * source,char * dest)142 static void set_values(Matrix* source, char* dest) {
143 m_source = source;
144 m_dest = dest;
145 return;
146 }
147
operator ()(const oneapi::tbb::blocked_range<std::size_t> & r) const148 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
tbb_parallel_task()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
Step()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