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