📄 serialasync.h
字号:
// -*- C++ -*-
// ACL:license
// This software and ancillary information (herein called "SOFTWARE")
// called Tulip is made available under the terms described
// here. The SOFTWARE has been approved for release with associated
// LA-CC Number LA-CC-98-35.
//
// Unless otherwise indicated, this SOFTWARE has been authored by an
// employee or employees of the University of California, operator of the
// Los Alamos National Laboratory under Contract No. W-7405-ENG-36 with
// the U.S. Department of Energy. The U.S. Government has rights to use,
// reproduce, and distribute this SOFTWARE, and to allow others to do so.
// The public may copy, distribute, prepare derivative works and publicly
// display this SOFTWARE without charge, provided that this Notice and
// any statement of authorship are reproduced on all copies. Neither the
// Government nor the University makes any warranty, express or implied,
// or assumes any liability or responsibility for the use of this
// SOFTWARE.
//
// If SOFTWARE is modified to produce derivative works, such modified
// SOFTWARE should be clearly marked, so as not to confuse it with the
// version available from LANL
// ACL:license
//-----------------------------------------------------------------------------
// This program was prepared by the Regents of the University of California
// at Los Alamos National Laboratory (the University) under Contract No.
// W-7405-ENG-36 with the U.S. Department of Energy (DOE). The University has
// certain rights in the program pursuant to the contract and the program
// should not be copied or distributed outside your organization. All rights
// in the program are reserved by the DOE and the University. Neither the U.S.
// Government nor the University makes any warranty, express or implied, or
// assumes any liability or responsibility for the use of this software
//-----------------------------------------------------------------------------
// Class:
// IterateScheduler<SerialAsync>
// Iterate<SerialAsync>
// DataObject<SerialAsync>
//-----------------------------------------------------------------------------
#ifndef _SerialAsync_h_
#define _SerialAsync_h_
//////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
// Overview:
// Smarts classes for times when you want no threads but you do want
// dataflow evaluation.
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Typedefs:
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Includes:
//-----------------------------------------------------------------------------
#include <list>
#include <iostream.h>
#include "IterateScheduler.h"
//-----------------------------------------------------------------------------
// Forward Declarations:
//-----------------------------------------------------------------------------
inline ostream& lock(ostream& s) { return s; }
inline ostream& unlock(ostream& s) { return s; }
namespace Smarts {
//
// Tag class for specializing IterateScheduler, Iterate and DataObject.
//
struct SerialAsync
{
enum Action { Read, Write};
};
//-----------------------------------------------------------------------------
struct SystemContext
{
void addNCpus(int) {}
void wait() {}
};
extern SystemContext systemContext;
inline void concurrency(int){};
inline int concurrency() {return 1;}
inline void wait() {}
inline double StartTimer() { return 0; }
inline double StopTimer(double) { return 0; }
//-----------------------------------------------------------------------------
//
// The SerialAsync IterateScheduler, Iterate and DataObject implement a SMARTS
// scheduler that does dataflow without threads. What that means is that
// when you hand iterates to the IterateScheduler it stores them up until you call
// IterateScheduler::blockingEvaluate(), at which point it evaluates iterates until
// the queue is empty.
//
//-----------------------------------------------------------------------------
template<>
class IterateScheduler<SerialAsync>
{
friend class DataObject<SerialAsync>;
friend class Iterate<SerialAsync>;
public:
typedef DataObject<SerialAsync> DataObject_t;
typedef Iterate<SerialAsync> Iterate_t;
//---------------------------------------------------------------------------
// Constructors & Destructors;
//---------------------------------------------------------------------------
IterateScheduler() : generation_m(0) {}
~IterateScheduler() {}
void setConcurrency(int) {};
//---------------------------------------------------------------------------
// Mutators.
//---------------------------------------------------------------------------
// Tell the scheduler that we are beginning a new generation.
inline void beginGeneration() { ++generation_m; }
// Tell the scheduler that we are finishing the current generation.
inline void endGeneration() {}
// Evaluate all the currently outstanding iterates.
void blockingEvaluate();
// Return the current generation.
inline int generation() const { return generation_m; }
// Give a class to the scheduler for later evaluation and deletion.
inline void handOff(Iterate<SerialAsync>* it);
protected:
private:
typedef std::list<Iterate_t*> Container_t;
typedef Container_t::iterator Iterator_t;
// When an iterate becomes ready for evaluation because all
// of its data is ready, it calls this.
inline void executable(Iterate<SerialAsync>*);
// What generation are we in?
int generation_m;
// The execution queue. Used as a FIFO.
std::list< Iterate<SerialAsync>* > queue_m;
};
//-----------------------------------------------------------------------------
template<>
class Iterate<SerialAsync>
{
friend class IterateScheduler<SerialAsync>;
friend class DataObject<SerialAsync>;
public:
typedef DataObject<SerialAsync> DataObject_t;
typedef IterateScheduler<SerialAsync> IterateScheduler_t;
// Construct the Iterate with:
// The scheduler it will inform when it is ready.
// The number of notifications before it is ready.
// Its affinity.
inline Iterate(IterateScheduler<SerialAsync> & s, int n, int affinity=-1);
// The dtor is virtual because the subclasses will need to add to it.
virtual ~Iterate() {}
// The run method does the core work of the Iterate.
// It is supplied by the subclass.
virtual void run() = 0;
// Stub in all the affinities, because there is no such thing
// in serial.
inline int affinity() const {return 0;};
inline int hintAffinity() const {return 0;}
inline void affinity(int) {}
inline void hintAffinity(int) {}
// Receive a notification that a dependence is ready.
inline void notify();
// What generation is this in?
int generation() { return generation_m; }
// How many notifications remain?
int notifications() const { return notifications_m; }
protected:
// What scheduler are we working with?
IterateScheduler<SerialAsync> &scheduler_m;
// How many notifications should we receive before we can run?
int notifications_m;
// What generation is this in?
int generation_m;
};
//-----------------------------------------------------------------------------
template<>
class DataObject<SerialAsync>
{
friend class IterateScheduler<SerialAsync>;
friend class Iterate<SerialAsync>;
public:
typedef IterateScheduler<SerialAsync> IterateScheduler_t;
typedef Iterate<SerialAsync> Iterate_t;
// There are two ways data can be used: to read or to write.
// Don't change this to give more than two states:
// things inside depend on that.
// Construct the data object with an empty set of requests
// and the given affinity.
inline DataObject(int affinity=-1);
// Stub out affinity because there is no affinity in serial.
inline int affinity() const { return 0; }
inline void affinity(int) {}
// An iterate makes a request for a certain action in a certain
// generation.
void request(Iterate<SerialAsync>&, SerialAsync::Action, int gen);
// An iterate finishes and tells the DataObject it no longer needs
// it. If this is the last release for the current set of requests,
// have the IterateScheduler release some more.
inline void release(SerialAsync::Action);
protected:
private:
// If release needs to let more iterates go, it calls this.
void releaseIterates();
// The type for a request.
class Request
{
public:
Request() {}
Request(Iterate<SerialAsync>& it, SerialAsync::Action act)
: iterate_m(&it), act_m(act) {}
Iterate<SerialAsync>& iterate() const { return *iterate_m; }
SerialAsync::Action act() const { return act_m; }
private:
Iterate<SerialAsync>* iterate_m;
SerialAsync::Action act_m;
};
// The type of the queue and iterator.
typedef std::list<Request> Container_t;
typedef Container_t::iterator Iterator_t;
// The list of requests from various iterates.
// They're granted in FIFO order.
Container_t queue_m;
// Pointer to the last request that has been granted.
Iterator_t released_m;
// The number of outstanding notifications.
int notifications_m;
};
//////////////////////////////////////////////////////////////////////
//
// Inline implementation of the functions for IterateScheduler<SerialAsync>
//
//////////////////////////////////////////////////////////////////////
//
// IterateScheduler<SerialAsync>::handOff(Iterate<SerialAsync>*)
// No action needs to be taken here. Iterates will make their
// own way into the execution queue.
//
inline void
IterateScheduler<SerialAsync>::handOff(Iterate<SerialAsync>*)
{
}
//
// IterateScheduler::executable(Iterate*)
// Put an iterate in the executable queue.
//
inline void
IterateScheduler<SerialAsync>::executable(Iterate<SerialAsync>* it)
{
queue_m.push_front(it);
}
//////////////////////////////////////////////////////////////////////
//
// Inline implementation of the functions for Iterate<SerialAsync>
//
//////////////////////////////////////////////////////////////////////
//
// Iterate<SerialAsync>::Iterate
// Construct with the scheduler and the number of notifications.
// Ignore the affinity.
//
inline
Iterate<SerialAsync>::Iterate(IterateScheduler<SerialAsync>& s, int n, int)
: scheduler_m(s), notifications_m(n), generation_m(s.generation())
{
}
//
// Iterate<SerialAsync>::notify
// Notify the iterate that a DataObject is ready.
// Decrement the counter, and if it is zero, alert the scheduler.
//
inline void
Iterate<SerialAsync>::notify()
{
if ( -- notifications_m == 0 )
scheduler_m.executable(this);
}
//////////////////////////////////////////////////////////////////////
//
// Inline implementation of the functions for DataObject<SerialAsync>
//
//////////////////////////////////////////////////////////////////////
//
// DataObject::DataObject()
// Initialize:
// released_m to the end of the queue (which should) also be the beginning.
// notifications_m to zero, since nothing has been released yet.
//
inline
DataObject<SerialAsync>::DataObject(int)
: released_m(queue_m.end()), notifications_m(0)
{
}
//
// void DataObject::release(Action)
// An iterate has finished and is telling the DataObject that
// it is no longer needed.
//
inline void
DataObject<SerialAsync>::release(SerialAsync::Action)
{
if ( --notifications_m == 0 )
releaseIterates();
}
//----------------------------------------------------------------------
//
// End of Smarts namespace.
//
}
//////////////////////////////////////////////////////////////////////
//#include "IterateSchedulers/SerialAsync.cpp"
#endif // POOMA_PACKAGE_CLASS_H
/***************************************************************************
* $RCSfile: SerialAsync.h,v $ $Author: jac $
* $Revision: 1.2 $ $Date: 1999/07/28 17:43:07 $
***************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -