GNU Radio 3.3.0 C++ API
gc_job_manager.h
Go to the documentation of this file.
00001 /* -*- c++ -*- */
00002 /*
00003  * Copyright 2007,2008 Free Software Foundation, Inc.
00004  * 
00005  * This file is part of GNU Radio
00006  * 
00007  * GNU Radio is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 3, or (at your option)
00010  * any later version.
00011  * 
00012  * GNU Radio is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License along
00018  * with this program; if not, write to the Free Software Foundation, Inc.,
00019  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00020  */
00021 
00022 #ifndef INCLUDED_GC_JOB_MANAGER_H
00023 #define INCLUDED_GC_JOB_MANAGER_H
00024 
00025 #include <boost/utility.hpp>
00026 #include <boost/shared_ptr.hpp>
00027 #include <vector>
00028 #include <string>
00029 #include <stdexcept>
00030 #include <libspe2.h>
00031 #include "gc_job_desc.h"
00032 
00033 class gc_job_manager;
00034 typedef boost::shared_ptr<gc_job_manager> gc_job_manager_sptr;
00035 typedef boost::shared_ptr<spe_program_handle_t> spe_program_handle_sptr;
00036 typedef boost::shared_ptr<gc_job_desc> gc_job_desc_sptr;
00037 
00038 /*!
00039  * \brief Return a boost::shared_ptr to an spe_program_handle_t
00040  *
00041  * \param filename is the name of the SPE ELF executable to open.
00042  *
00043  * Calls spe_image_open to open the file.  If successful returns a
00044  * boost::shared_ptr that will call spe_image_close when it's time to
00045  * free the object.
00046  *
00047  * Returns the equivalent of the NULL pointer if the file cannot be
00048  * opened, or if it's not an SPE ELF object file.
00049  *
00050  * \sa gc_program_handle_from_address
00051  */
00052 spe_program_handle_sptr 
00053 gc_program_handle_from_filename(const std::string &filename);
00054 
00055 /*!
00056  * \brief Return a boost::shared_ptr to an spe_program_handle_t
00057  *
00058  * \param handle is a non-zero pointer to an embedded SPE image.
00059  *
00060  * If successful returns a boost::shared_ptr that does nothing when
00061  * it's time to free the object.
00062  *
00063  * \sa gc_program_handle_from_filename
00064  */
00065 spe_program_handle_sptr 
00066 gc_program_handle_from_address(spe_program_handle_t *handle);
00067 
00068 /*!
00069  * \brief map gc_job_status_t into a string
00070  */
00071 const std::string
00072 gc_job_status_string(gc_job_status_t status);
00073 
00074 /*
00075  * \brief Options that configure the job_manager.
00076  * The default values are reasonable.
00077  */
00078 struct gc_jm_options {
00079   unsigned int max_jobs;            // max # of job descriptors in system
00080   unsigned int max_client_threads;  // max # of client threads of job manager
00081   unsigned int nspes;               // how many SPEs shall we use? 0 -> all of them
00082   bool gang_schedule;               // shall we gang schedule?
00083   bool use_affinity;                // shall we try for affinity (FIXME not implmented)
00084   bool enable_logging;              // shall we log SPE events?
00085   uint32_t log2_nlog_entries;              // log2 of number of log entries (default is 12 == 4k)
00086   spe_program_handle_sptr program_handle;  // program to load into SPEs
00087 
00088   gc_jm_options() :
00089     max_jobs(0), max_client_threads(0), nspes(0),
00090     gang_schedule(false), use_affinity(false),
00091     enable_logging(false), log2_nlog_entries(12)
00092   {
00093   }
00094 
00095   gc_jm_options(spe_program_handle_sptr program_handle_,
00096                 unsigned int nspes_ = 0) :
00097     max_jobs(0), max_client_threads(0), nspes(nspes_),
00098     gang_schedule(false), use_affinity(false),
00099     enable_logging(false), log2_nlog_entries(12),
00100     program_handle(program_handle_)
00101   {
00102   }
00103 };
00104 
00105 enum gc_wait_mode {
00106   GC_WAIT_ANY,
00107   GC_WAIT_ALL,
00108 };
00109 
00110 /*
00111  * exception classes
00112  */
00113 class gc_exception : public std::runtime_error
00114 {
00115 public:
00116   gc_exception(const std::string &msg);
00117 };
00118 
00119 class gc_unknown_proc : public gc_exception
00120 {
00121 public:
00122   gc_unknown_proc(const std::string &msg);
00123 };
00124 
00125 class gc_bad_alloc : public gc_exception
00126 {
00127 public:
00128   gc_bad_alloc(const std::string &msg);
00129 };
00130 
00131 class gc_bad_align : public gc_exception
00132 {
00133 public:
00134   gc_bad_align(const std::string &msg);
00135 };
00136 
00137 class gc_bad_submit : public gc_exception
00138 {
00139 public:
00140   gc_bad_submit(const std::string &name, gc_job_status_t status);
00141 };
00142 
00143 /*
00144  * \brief Create an instance of the job manager
00145  */
00146 gc_job_manager_sptr
00147 gc_make_job_manager(const gc_jm_options *options = 0);
00148 
00149 
00150 /*!
00151  * \brief Abstract class that manages SPE jobs.
00152  * \ingroup gcell
00153  *
00154  * There is typically a single instance derived from this class.
00155  * It is safe to call its methods from any thread.
00156  */
00157 class gc_job_manager : boost::noncopyable
00158 {
00159 public:
00160   gc_job_manager(const gc_jm_options *options = 0); 
00161 
00162   virtual ~gc_job_manager();
00163 
00164   /*!
00165    * Stop accepting new jobs.  Wait for existing jobs to complete.
00166    * Return all managed SPE's to the system.
00167    */
00168   virtual bool shutdown() = 0;
00169 
00170   /*!
00171    * \brief Return number of SPE's currently allocated to job manager.
00172    */
00173   virtual int nspes() const = 0;
00174 
00175   /*!
00176    * \brief Return a pointer to a properly aligned job descriptor,
00177    * or throws gc_bad_alloc if there are none available.
00178    */
00179   virtual gc_job_desc *alloc_job_desc() = 0;
00180 
00181   /*
00182    *! Free a job descriptor previously allocated with alloc_job_desc()
00183    *
00184    * \param[in] jd pointer to job descriptor to free.
00185    */
00186   virtual void free_job_desc(gc_job_desc *jd) = 0;
00187 
00188   /*!
00189    * \brief Submit a job for asynchronous processing on an SPE.
00190    *
00191    * \param[in] jd pointer to job description
00192    *
00193    * The caller must not read or write the job description
00194    * or any of the memory associated with any indirect arguments
00195    * until after calling wait_job.
00196    *
00197    * \returns true iff the job was successfully enqueued.
00198    * If submit_job returns false, check jd->status for additional info.
00199    */
00200   virtual bool submit_job(gc_job_desc *jd) = 0;
00201 
00202   /*!
00203    * \brief Wait for job to complete.
00204    *
00205    * A thread may only wait for jobs which it submitted.
00206    *
00207    * \returns true if sucessful, else false.
00208    */
00209   virtual bool 
00210   wait_job(gc_job_desc *jd) = 0;
00211 
00212   /*!
00213    * \brief wait for 1 or more jobs to complete.
00214    *
00215    * \param[in] njobs is the length of arrays \p jd and \p done.
00216    * \param[in] jd are the jobs that are to be waited for.
00217    * \param[out] done indicates whether the corresponding job is complete.
00218    * \param[in] mode indicates whether to wait for ALL or ANY of the jobs
00219    *   in \p jd to complete.
00220    *
00221    * A thread may only wait for jobs which it submitted.
00222    *
00223    * \returns number of jobs completed, or -1 if error.
00224    * The caller must examine the status field of each job to confirm
00225    * successful completion of the job.
00226    */
00227   virtual int
00228   wait_jobs(unsigned int njobs,
00229             gc_job_desc *jd[], bool done[], gc_wait_mode mode) = 0;
00230 
00231   /*!
00232    * Return the maximum number of bytes of EA arguments that may be
00233    * copied to or from the SPE in a single job.  The limit applies
00234    * independently to the "get" and "put" args.  
00235    * \sa gc_job_desc_t, gc_job_ea_args_t
00236    */
00237   virtual int ea_args_maxsize() = 0;
00238 
00239   /*!
00240    * Return gc_proc_id_t associated with spu procedure \p proc_name if one
00241    * exists, otherwise throws gc_unknown_proc.
00242    */
00243   virtual gc_proc_id_t lookup_proc(const std::string &proc_name) = 0;
00244   
00245   /*!
00246    * Return a vector of all known spu procedure names.
00247    */
00248   virtual std::vector<std::string> proc_names() = 0;
00249 
00250   virtual void set_debug(int debug);
00251   virtual int debug();
00252 
00253   /* ----- static methods ----- */
00254 
00255   /*!
00256    * \brief Set the singleton gc_job_manager instance.
00257    * \param mgr is the job manager instance.
00258    *
00259    * The singleton is weakly held, thus the caller must maintain
00260    * a reference to the mgr for the duration.  (If we held the
00261    * manager strongly, the destructor would never be called, and the
00262    * resources (SPEs) would not be returned.)  Bottom line: the
00263    * caller is responsible for life-time management.
00264    */
00265   static void set_singleton(gc_job_manager_sptr mgr);
00266 
00267   /*!
00268    * \brief Retrieve the singleton gc_job_manager instance.
00269    *
00270    * Returns the singleton gc_job_manager instance or raises
00271    * boost::bad_weak_ptr if the singleton is empty.
00272    */
00273   static gc_job_manager_sptr singleton();
00274 
00275   /*!
00276    * \brief return a boost::shared_ptr to a job descriptor.
00277    */
00278   static gc_job_desc_sptr make_jd_sptr(gc_job_manager_sptr mgr, gc_job_desc *jd);
00279 
00280   /*!
00281    * \brief allocate a job descriptor and return a boost::shared_ptr to it.
00282    */
00283   static gc_job_desc_sptr alloc_job_desc(gc_job_manager_sptr mgr);
00284 };
00285 
00286 
00287 #endif /* INCLUDED_GC_JOB_MANAGER_H */