1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
|
/* -*- c++ -*- */
/*
* Copyright 2007,2008 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* GNU Radio 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef INCLUDED_GC_JOB_MANAGER_H
#define INCLUDED_GC_JOB_MANAGER_H
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>
#include <string>
#include <stdexcept>
#include <libspe2.h>
#include "gc_job_desc.h"
class gc_job_manager;
typedef boost::shared_ptr<gc_job_manager> gc_job_manager_sptr;
typedef boost::shared_ptr<spe_program_handle_t> spe_program_handle_sptr;
typedef boost::shared_ptr<gc_job_desc> gc_job_desc_sptr;
/*!
* \brief Return a boost::shared_ptr to an spe_program_handle_t
*
* \param filename is the name of the SPE ELF executable to open.
*
* Calls spe_image_open to open the file. If successful returns a
* boost::shared_ptr that will call spe_image_close when it's time to
* free the object.
*
* Returns the equivalent of the NULL pointer if the file cannot be
* opened, or if it's not an SPE ELF object file.
*
* \sa gc_program_handle_from_address
*/
spe_program_handle_sptr
gc_program_handle_from_filename(const std::string &filename);
/*!
* \brief Return a boost::shared_ptr to an spe_program_handle_t
*
* \param handle is a non-zero pointer to an embedded SPE image.
*
* If successful returns a boost::shared_ptr that does nothing when
* it's time to free the object.
*
* \sa gc_program_handle_from_filename
*/
spe_program_handle_sptr
gc_program_handle_from_address(spe_program_handle_t *handle);
/*!
* \brief map gc_job_status_t into a string
*/
const std::string
gc_job_status_string(gc_job_status_t status);
/*
* \brief Options that configure the job_manager.
* The default values are reasonable.
*/
struct gc_jm_options {
unsigned int max_jobs; // max # of job descriptors in system
unsigned int max_client_threads; // max # of client threads of job manager
unsigned int nspes; // how many SPEs shall we use? 0 -> all of them
bool gang_schedule; // shall we gang schedule?
bool use_affinity; // shall we try for affinity (FIXME not implmented)
bool enable_logging; // shall we log SPE events?
uint32_t log2_nlog_entries; // log2 of number of log entries (default is 12 == 4k)
spe_program_handle_sptr program_handle; // program to load into SPEs
gc_jm_options() :
max_jobs(0), max_client_threads(0), nspes(0),
gang_schedule(false), use_affinity(false),
enable_logging(false), log2_nlog_entries(12)
{
}
gc_jm_options(spe_program_handle_sptr program_handle_,
unsigned int nspes_ = 0) :
max_jobs(0), max_client_threads(0), nspes(nspes_),
gang_schedule(false), use_affinity(false),
enable_logging(false), log2_nlog_entries(12),
program_handle(program_handle_)
{
}
};
enum gc_wait_mode {
GC_WAIT_ANY,
GC_WAIT_ALL,
};
/*
* exception classes
*/
class gc_exception : public std::runtime_error
{
public:
gc_exception(const std::string &msg);
};
class gc_unknown_proc : public gc_exception
{
public:
gc_unknown_proc(const std::string &msg);
};
class gc_bad_alloc : public gc_exception
{
public:
gc_bad_alloc(const std::string &msg);
};
class gc_bad_align : public gc_exception
{
public:
gc_bad_align(const std::string &msg);
};
class gc_bad_submit : public gc_exception
{
public:
gc_bad_submit(const std::string &name, gc_job_status_t status);
};
/*
* \brief Create an instance of the job manager
*/
gc_job_manager_sptr
gc_make_job_manager(const gc_jm_options *options = 0);
/*!
* \brief Abstract class that manages SPE jobs.
*
* There is typically a single instance derived from this class.
* It is safe to call its methods from any thread.
*/
class gc_job_manager : boost::noncopyable
{
public:
gc_job_manager(const gc_jm_options *options = 0);
virtual ~gc_job_manager();
/*!
* Stop accepting new jobs. Wait for existing jobs to complete.
* Return all managed SPE's to the system.
*/
virtual bool shutdown() = 0;
/*!
* \brief Return number of SPE's currently allocated to job manager.
*/
virtual int nspes() const = 0;
/*!
* \brief Return a pointer to a properly aligned job descriptor,
* or throws gc_bad_alloc if there are none available.
*/
virtual gc_job_desc *alloc_job_desc() = 0;
/*
*! Free a job descriptor previously allocated with alloc_job_desc()
*
* \param[in] jd pointer to job descriptor to free.
*/
virtual void free_job_desc(gc_job_desc *jd) = 0;
/*!
* \brief Submit a job for asynchronous processing on an SPE.
*
* \param[in] jd pointer to job description
*
* The caller must not read or write the job description
* or any of the memory associated with any indirect arguments
* until after calling wait_job.
*
* \returns true iff the job was successfully enqueued.
* If submit_job returns false, check jd->status for additional info.
*/
virtual bool submit_job(gc_job_desc *jd) = 0;
/*!
* \brief Wait for job to complete.
*
* A thread may only wait for jobs which it submitted.
*
* \returns true if sucessful, else false.
*/
virtual bool
wait_job(gc_job_desc *jd) = 0;
/*!
* \brief wait for 1 or more jobs to complete.
*
* \param[input] njobs is the length of arrays \p jd and \p done.
* \param[input] jd are the jobs that are to be waited for.
* \param[output] done indicates whether the corresponding job is complete.
* \param[input] mode indicates whether to wait for ALL or ANY of the jobs
* in \p jd to complete.
*
* A thread may only wait for jobs which it submitted.
*
* \returns number of jobs completed, or -1 if error.
* The caller must examine the status field of each job to confirm
* successful completion of the job.
*/
virtual int
wait_jobs(unsigned int njobs,
gc_job_desc *jd[], bool done[], gc_wait_mode mode) = 0;
/*!
* Return the maximum number of bytes of EA arguments that may be
* copied to or from the SPE in a single job. The limit applies
* independently to the "get" and "put" args.
* \sa gc_job_desc_t, gc_job_ea_args_t
*/
virtual int ea_args_maxsize() = 0;
/*!
* Return gc_proc_id_t associated with spu procedure \p proc_name if one
* exists, otherwise throws gc_unknown_proc.
*/
virtual gc_proc_id_t lookup_proc(const std::string &proc_name) = 0;
/*!
* Return a vector of all known spu procedure names.
*/
virtual std::vector<std::string> proc_names() = 0;
virtual void set_debug(int debug);
virtual int debug();
/* ----- static methods ----- */
/*!
* \brief Set the singleton gc_job_manager instance.
* \param mgr is the job manager instance.
*
* The singleton is weakly held, thus the caller must maintain
* a reference to the mgr for the duration. (If we held the
* manager strongly, the destructor would never be called, and the
* resources (SPEs) would not be returned.) Bottom line: the
* caller is responsible for life-time management.
*/
static void set_singleton(gc_job_manager_sptr mgr);
/*!
* \brief Retrieve the singleton gc_job_manager instance.
*
* Returns the singleton gc_job_manager instance or raises
* boost::bad_weak_ptr if the singleton is empty.
*/
static gc_job_manager_sptr singleton();
/*!
* \brief return a boost::shared_ptr to a job descriptor.
*/
static gc_job_desc_sptr make_jd_sptr(gc_job_manager_sptr mgr, gc_job_desc *jd);
/*!
* \brief allocate a job descriptor and return a boost::shared_ptr to it.
*/
static gc_job_desc_sptr alloc_job_desc(gc_job_manager_sptr mgr);
};
#endif /* INCLUDED_GC_JOB_MANAGER_H */
|