Committing TBB 2019 Update 9 source code
[platform/upstream/tbb.git] / examples / parallel_for / game_of_life / src / Evolution.cpp
1 /*
2     Copyright (c) 2005-2019 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 "Evolution.h"
24 #include "Board.h"
25 #include "../../../common/utility/get_default_num_threads.h"
26
27 #ifdef USE_SSE
28 #define GRAIN_SIZE 14
29 #else
30 #define GRAIN_SIZE 4000
31 #endif
32 #define TIME_SLICE 330
33
34 /*
35     Evolution
36 */
37
38 /**
39     Evolution::UpdateMatrix() - moves the calculated destination data
40     to the source data block. No destination zeroing is required since it will
41     be completely overwritten during the next calculation cycle.
42 **/
43 void Evolution::UpdateMatrix()
44 {
45     memcpy(m_matrix->data, m_dest, m_size);
46 }
47
48 /*
49     SequentialEvolution
50 */
51
52 //! SequentialEvolution::Run - begins looped evolution
53 #ifndef _CONSOLE
54 void SequentialEvolution::Run()
55 {
56 #else
57 void SequentialEvolution::Run(double execution_time, int nthread)
58 {
59     printf("Starting game (Sequential evolution)\n");
60 #endif
61
62     m_nIteration = 0;
63     m_serial_time = 0;
64     tbb::tick_count t0 = tbb::tick_count::now();
65     while (!m_done)
66     {
67         if( !is_paused )
68         {
69             tbb::tick_count t = tbb::tick_count::now();
70             Step();
71             tbb::tick_count t1 = tbb::tick_count::now();
72             ++m_nIteration;
73             double  work_time = (t1-t0).seconds();
74 #ifndef _CONSOLE
75             if ( work_time * 1000 < TIME_SLICE )
76                 continue;
77             m_serial_time += work_time;
78             m_board->draw(m_nIteration);
79 #else
80             m_serial_time += work_time;
81 #endif
82         }
83         //! Let the parallel algorithm work uncontended almost the same time
84         //! as the serial one. See ParallelEvolution::Run() as well.
85 #ifndef _CONSOLE
86         m_evt_start_parallel->Set();
87         m_evt_start_serial->WaitOne();
88         t0 = tbb::tick_count::now();
89 #else
90         t0 = tbb::tick_count::now();
91         if(m_serial_time > execution_time)
92         {
93             printf("iterations count = %d time = %g\n", m_nIteration, m_serial_time);
94             break;
95         }
96 #endif
97     }
98 }
99
100 //! SequentialEvolution::Step() - override of step method
101 void SequentialEvolution::Step()
102 {
103         if( !is_paused )
104     {
105 #ifdef USE_SSE
106     UpdateState(m_matrix, m_matrix->data, 0, m_matrix->height);
107 #else
108     UpdateState(m_matrix, m_dest, 0, (m_matrix->width * m_matrix->height)-1);
109     UpdateMatrix();
110 #endif
111         }
112 }
113
114 /*
115     ParallelEvolution
116 */
117
118 //! SequentialEvolution::Run - begins looped evolution
119 #ifndef _CONSOLE
120 void ParallelEvolution::Run()
121 {
122 #else
123 void ParallelEvolution::Run(double execution_time, int nthread)
124 {
125     if(nthread == utility::get_default_num_threads())
126         printf("Starting game (Parallel evolution for automatic number of thread(s))\n");
127     else
128         printf("Starting game (Parallel evolution for %d thread(s))\n", nthread);
129 #endif
130
131     m_nIteration = 0;
132     m_parallel_time = 0;
133
134 #ifndef _CONSOLE
135     //! start task scheduler as necessary
136     if (m_pGlobControl == NULL)
137     {
138         m_pGlobControl = new tbb::global_control(tbb::global_control::max_allowed_parallelism, utility::get_default_num_threads());
139     }
140     m_evt_start_parallel->WaitOne();
141 #else
142     tbb::global_control* pGlobControl = new tbb::global_control(tbb::global_control::max_allowed_parallelism, nthread);
143 #endif
144
145     double  work_time = m_serial_time;
146     tbb::tick_count t0 = tbb::tick_count::now();
147
148     while (!m_done)
149     {
150         if( !is_paused )
151         {
152             tbb::tick_count t = tbb::tick_count::now();
153             Step();
154             tbb::tick_count t1 = tbb::tick_count::now();
155             ++m_nIteration;
156             double real_work_time = (t1-t0).seconds();
157 #ifndef _CONSOLE
158             if ( real_work_time < work_time )
159                 continue;
160             m_parallel_time += real_work_time;
161             m_board->draw(m_nIteration);
162 #else
163             m_parallel_time += real_work_time;
164 #endif
165         }
166         //! Let the serial algorithm work the same time as the parallel one.
167 #ifndef _CONSOLE
168         m_evt_start_serial->Set();
169         m_evt_start_parallel->WaitOne();
170
171         work_time = m_serial_time - m_parallel_time;
172         t0 = tbb::tick_count::now();
173 #else
174         t0 = tbb::tick_count::now();
175         if(m_parallel_time > execution_time)
176         {
177             printf("iterations count = %d time = %g\n", m_nIteration, m_parallel_time);
178             delete pGlobControl; pGlobControl = NULL;
179             break;
180         }
181 #endif
182     }
183     if (pGlobControl)
184         delete pGlobControl;
185 }
186
187 /**
188     class tbb_parallel_task
189
190     TBB requires a class for parallel loop implementations. The actual
191     loop "chunks" are performed using the () operator of the class.
192     The blocked_range contains the range to calculate. Please see the
193     TBB documentation for more information.
194 **/
195 #ifndef _CONSOLE
196 public class tbb_parallel_task
197 #else
198 class tbb_parallel_task
199 #endif
200 {
201 public:
202     static void set_values (Matrix* source, char* dest)
203     {
204         m_source = source;
205         m_dest = dest;
206         return;
207     }
208
209     void operator()( const tbb::blocked_range<size_t>& r ) const
210     {
211         int begin = (int)r.begin();            //! capture lower range number for this chunk
212         int end = (int)r.end();                //! capture upper range number for this chunk
213         UpdateState(m_source, m_dest, begin, end);
214     }
215
216     tbb_parallel_task () {}
217
218 private:
219     static Matrix* m_source;
220     static char* m_dest;
221 };
222
223 Matrix* tbb_parallel_task::m_source;
224 char* tbb_parallel_task::m_dest;
225
226 //! ParallelEvolution::Step() - override of Step method
227 void ParallelEvolution::Step()
228 {
229     size_t begin = 0;                   //! beginning cell position
230 #ifdef USE_SSE
231     size_t end = m_matrix->height;      //! ending cell position
232 #else
233     size_t end = m_size-1;              //! ending cell position
234 #endif
235
236     //! set matrix pointers
237     tbb_parallel_task::set_values(m_matrix, m_dest);
238
239     //! do calculation loop
240     parallel_for (tbb::blocked_range<size_t> (begin, end, GRAIN_SIZE), tbb_parallel_task());
241     UpdateMatrix();
242 }