blob: dff5cdb92f0df789462925f68fba70a047366244 [file] [log] [blame]
/*
Copyright 2005-2010 Intel Corporation. All Rights Reserved.
This file is part of Threading Building Blocks.
Threading Building Blocks is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
Threading Building Blocks is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Threading Building Blocks; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
As a special exception, you may use this file as part of a free software
library without restriction. Specifically, if other files instantiate
templates or use macros or inline functions from this file, or you compile
this file and link it with other files to produce an executable, this
file does not by itself cause the resulting executable to be covered by
the GNU General Public License. This exception does not however
invalidate any other reasons why the executable file might be covered by
the GNU General Public License.
*/
/*
Evolution.cpp: implementation file for evolution classes; evolution
classes do looped evolution of patterns in a defined
2 dimensional space
*/
#include "Evolution.h"
#include "Board.h"
#ifdef USE_SSE
#define GRAIN_SIZE 14
#else
#define GRAIN_SIZE 4000
#endif
#define TIME_SLICE 330
/*
Evolution
*/
/**
Evolution::UpdateMatrix() - moves the calculated destination data
to the source data block. No destination zeroing is required since it will
be completely overwritten during the next calculation cycle.
**/
void Evolution::UpdateMatrix()
{
memcpy(m_matrix->data, m_dest, m_size);
}
/*
SequentialEvolution
*/
//! SequentialEvolution::Run - begins looped evolution
#ifndef _CONSOLE
void SequentialEvolution::Run()
{
#else
void SequentialEvolution::Run(double execution_time, int nthread)
{
printf("Starting game (Sequential evolution)\n");
#endif
m_nIteration = 0;
m_serial_time = 0;
tbb::tick_count t0 = tbb::tick_count::now();
while (!m_done)
{
if( !is_paused )
{
tbb::tick_count t = tbb::tick_count::now();
Step();
tbb::tick_count t1 = tbb::tick_count::now();
++m_nIteration;
double work_time = (t1-t0).seconds();
#ifndef _CONSOLE
if ( work_time * 1000 < TIME_SLICE )
continue;
m_serial_time += work_time;
m_board->draw(m_nIteration);
#else
m_serial_time += work_time;
#endif
}
//! Let the parallel algorithm work uncontended almost the same time
//! as the serial one. See ParallelEvolution::Run() as well.
#ifndef _CONSOLE
m_evt_start_parallel->Set();
m_evt_start_serial->WaitOne();
t0 = tbb::tick_count::now();
#else
t0 = tbb::tick_count::now();
if(m_serial_time > execution_time)
{
printf("iterations count = %d time = %g\n", m_nIteration, m_serial_time);
break;
}
#endif
}
}
//! SequentialEvolution::Step() - override of step method
void SequentialEvolution::Step()
{
if( !is_paused )
{
#ifdef USE_SSE
UpdateState(m_matrix, m_matrix->data, 0, m_matrix->height);
#else
UpdateState(m_matrix, m_dest, 0, (m_matrix->width * m_matrix->height)-1);
UpdateMatrix();
#endif
}
}
/*
ParallelEvolution
*/
//! SequentialEvolution::Run - begins looped evolution
#ifndef _CONSOLE
void ParallelEvolution::Run()
{
#else
void ParallelEvolution::Run(double execution_time, int nthread)
{
if(nthread == tbb::task_scheduler_init::automatic)
printf("Starting game (Parallel evolution for automatic number of thread(s))\n");
else
printf("Starting game (Parallel evolution for %d thread(s))\n", nthread);
#endif
m_nIteration = 0;
m_parallel_time = 0;
#ifndef _CONSOLE
//! start task scheduler as necessary
if (m_pInit == NULL)
{
m_pInit = new tbb::task_scheduler_init();
}
m_evt_start_parallel->WaitOne();
#else
tbb::task_scheduler_init init(nthread);
#endif
double work_time = m_serial_time;
tbb::tick_count t0 = tbb::tick_count::now();
while (!m_done)
{
if( !is_paused )
{
tbb::tick_count t = tbb::tick_count::now();
Step();
tbb::tick_count t1 = tbb::tick_count::now();
++m_nIteration;
double real_work_time = (t1-t0).seconds();
#ifndef _CONSOLE
if ( real_work_time < work_time )
continue;
m_parallel_time += real_work_time;
m_board->draw(m_nIteration);
#else
m_parallel_time += real_work_time;
#endif
}
//! Let the serial algorithm work the same time as the parallel one.
#ifndef _CONSOLE
m_evt_start_serial->Set();
m_evt_start_parallel->WaitOne();
work_time = m_serial_time - m_parallel_time;
t0 = tbb::tick_count::now();
#else
t0 = tbb::tick_count::now();
if(m_parallel_time > execution_time)
{
printf("iterations count = %d time = %g\n", m_nIteration, m_parallel_time);
init.terminate();
break;
}
#endif
}
}
/**
class tbb_parallel_task
TBB requires a class for parallel loop implementations. The actual
loop "chunks" are performed using the () operator of the class.
The blocked_range contains the range to calculate. Please see the
TBB documentation for more information.
**/
#ifndef _CONSOLE
public class tbb_parallel_task
#else
class tbb_parallel_task
#endif
{
public:
static void set_values (Matrix* source, char* dest)
{
m_source = source;
m_dest = dest;
return;
}
void operator()( const tbb::blocked_range<size_t>& r ) const
{
int begin = (int)r.begin(); //! capture lower range number for this chunk
int end = (int)r.end(); //! capture upper range number for this chunk
UpdateState(m_source, m_dest, begin, end);
}
tbb_parallel_task () {}
private:
static Matrix* m_source;
static char* m_dest;
};
Matrix* tbb_parallel_task::m_source;
char* tbb_parallel_task::m_dest;
//! ParallelEvolution::Step() - override of Step method
void ParallelEvolution::Step()
{
size_t begin = 0; //! beginning cell position
#ifdef USE_SSE
size_t end = m_matrix->height; //! ending cell position
#else
size_t end = m_size-1; //! ending cell position
#endif
//! set matrix pointers
tbb_parallel_task::set_values(m_matrix, m_dest);
//! do calculation loop
parallel_for (tbb::blocked_range<size_t> (begin, end, GRAIN_SIZE), tbb_parallel_task());
UpdateMatrix();
}