3
* Copyright 2007 Free Software Foundation, Inc.
5
* This file is part of GNU Radio
7
* GNU Radio is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 3, or (at your option)
12
* GNU Radio is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with GNU Radio; see the file COPYING. If not, write to
19
* the Free Software Foundation, Inc., 51 Franklin Street,
20
* Boston, MA 02110-1301, USA.
27
#include <gr_flat_flowgraph.h>
28
#include <gr_block_detail.h>
29
#include <gr_io_signature.h>
30
#include <gr_buffer.h>
34
#define GR_FLAT_FLOWGRAPH_DEBUG 0
36
// 32Kbyte buffer size between blocks
37
#define GR_FIXED_BUFFER_SIZE (32*(1L<<10))
39
static const unsigned int s_fixed_buffer_size = GR_FIXED_BUFFER_SIZE;
41
gr_flat_flowgraph_sptr
42
gr_make_flat_flowgraph()
44
return gr_flat_flowgraph_sptr(new gr_flat_flowgraph());
47
gr_flat_flowgraph::gr_flat_flowgraph()
51
gr_flat_flowgraph::~gr_flat_flowgraph()
56
gr_flat_flowgraph::setup_connections()
58
gr_basic_block_vector_t blocks = calc_used_blocks();
60
// Assign block details to blocks
61
for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++)
62
cast_to_block_sptr(*p)->set_detail(allocate_block_detail(*p));
64
// Connect inputs to outputs for each block
65
for(gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++)
66
connect_block_inputs(*p);
70
gr_flat_flowgraph::allocate_block_detail(gr_basic_block_sptr block)
72
int ninputs = calc_used_ports(block, true).size();
73
int noutputs = calc_used_ports(block, false).size();
74
gr_block_detail_sptr detail = gr_make_block_detail(ninputs, noutputs);
76
if (GR_FLAT_FLOWGRAPH_DEBUG)
77
std::cout << "Creating block detail for " << block << std::endl;
79
for (int i = 0; i < noutputs; i++) {
80
gr_buffer_sptr buffer = allocate_buffer(block, i);
81
if (GR_FLAT_FLOWGRAPH_DEBUG)
82
std::cout << "Allocated buffer for output " << block << ":" << i << std::endl;
83
detail->set_output(i, buffer);
90
gr_flat_flowgraph::allocate_buffer(gr_basic_block_sptr block, int port)
92
gr_block_sptr grblock = cast_to_block_sptr(block);
94
throw std::runtime_error("allocate_buffer found non-gr_block");
95
int item_size = block->output_signature()->sizeof_stream_item(port);
97
// *2 because we're now only filling them 1/2 way in order to
98
// increase the available parallelism when using the TPB scheduler.
99
// (We're double buffering, where we used to single buffer)
100
int nitems = s_fixed_buffer_size * 2 / item_size;
102
// Make sure there are at least twice the output_multiple no. of items
103
if (nitems < 2*grblock->output_multiple()) // Note: this means output_multiple()
104
nitems = 2*grblock->output_multiple(); // can't be changed by block dynamically
106
// If any downstream blocks are decimators and/or have a large output_multiple,
107
// ensure we have a buffer at least twice their decimation factor*output_multiple
108
gr_basic_block_vector_t blocks = calc_downstream_blocks(block, port);
110
for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
111
gr_block_sptr dgrblock = cast_to_block_sptr(*p);
113
throw std::runtime_error("allocate_buffer found non-gr_block");
115
double decimation = (1.0/dgrblock->relative_rate());
116
int multiple = dgrblock->output_multiple();
117
int history = dgrblock->history();
118
nitems = std::max(nitems, static_cast<int>(2*(decimation*multiple+history)));
121
return gr_make_buffer(nitems, item_size, grblock);
125
gr_flat_flowgraph::connect_block_inputs(gr_basic_block_sptr block)
127
gr_block_sptr grblock = cast_to_block_sptr(block);
129
throw std::runtime_error("connect_block_inputs found non-gr_block");
131
// Get its detail and edges that feed into it
132
gr_block_detail_sptr detail = grblock->detail();
133
gr_edge_vector_t in_edges = calc_upstream_edges(block);
135
// For each edge that feeds into it
136
for (gr_edge_viter_t e = in_edges.begin(); e != in_edges.end(); e++) {
137
// Set the buffer reader on the destination port to the output
138
// buffer on the source port
139
int dst_port = e->dst().port();
140
int src_port = e->src().port();
141
gr_basic_block_sptr src_block = e->src().block();
142
gr_block_sptr src_grblock = cast_to_block_sptr(src_block);
144
throw std::runtime_error("connect_block_inputs found non-gr_block");
145
gr_buffer_sptr src_buffer = src_grblock->detail()->output(src_port);
147
if (GR_FLAT_FLOWGRAPH_DEBUG)
148
std::cout << "Setting input " << dst_port << " from edge " << (*e) << std::endl;
150
detail->set_input(dst_port, gr_buffer_add_reader(src_buffer, grblock->history()-1, grblock));
155
gr_flat_flowgraph::merge_connections(gr_flat_flowgraph_sptr old_ffg)
157
// Allocate block details if needed. Only new blocks that aren't pruned out
158
// by flattening will need one; existing blocks still in the new flowgraph will
160
for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) {
161
gr_block_sptr block = cast_to_block_sptr(*p);
163
if (!block->detail()) {
164
if (GR_FLAT_FLOWGRAPH_DEBUG)
165
std::cout << "merge: allocating new detail for block " << (*p) << std::endl;
166
block->set_detail(allocate_block_detail(block));
169
if (GR_FLAT_FLOWGRAPH_DEBUG)
170
std::cout << "merge: reusing original detail for block " << (*p) << std::endl;
173
// Calculate the old edges that will be going away, and clear the buffer readers
175
for (gr_edge_viter_t old_edge = old_ffg->d_edges.begin(); old_edge != old_ffg->d_edges.end(); old_edge++) {
176
if (GR_FLAT_FLOWGRAPH_DEBUG)
177
std::cout << "merge: testing old edge " << (*old_edge) << "...";
179
gr_edge_viter_t new_edge;
180
for (new_edge = d_edges.begin(); new_edge != d_edges.end(); new_edge++)
181
if (new_edge->src() == old_edge->src() &&
182
new_edge->dst() == old_edge->dst())
185
if (new_edge == d_edges.end()) { // not found in new edge list
186
if (GR_FLAT_FLOWGRAPH_DEBUG)
187
std::cout << "not in new edge list" << std::endl;
188
// zero the buffer reader on RHS of old edge
189
gr_block_sptr block(cast_to_block_sptr(old_edge->dst().block()));
190
int port = old_edge->dst().port();
191
block->detail()->set_input(port, gr_buffer_reader_sptr());
194
if (GR_FLAT_FLOWGRAPH_DEBUG)
195
std::cout << "found in new edge list" << std::endl;
199
// Now connect inputs to outputs, reusing old buffer readers if they exist
200
for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) {
201
gr_block_sptr block = cast_to_block_sptr(*p);
203
if (GR_FLAT_FLOWGRAPH_DEBUG)
204
std::cout << "merge: merging " << (*p) << "...";
206
if (old_ffg->has_block_p(*p)) {
207
// Block exists in old flow graph
208
if (GR_FLAT_FLOWGRAPH_DEBUG)
209
std::cout << "used in old flow graph" << std::endl;
210
gr_block_detail_sptr detail = block->detail();
212
// Iterate through the inputs and see what needs to be done
213
int ninputs = calc_used_ports(block, true).size(); // Might be different now
214
for (int i = 0; i < ninputs; i++) {
215
if (GR_FLAT_FLOWGRAPH_DEBUG)
216
std::cout << "Checking input " << block << ":" << i << "...";
217
gr_edge edge = calc_upstream_edge(*p, i);
219
// Fish out old buffer reader and see if it matches correct buffer from edge list
220
gr_block_sptr src_block = cast_to_block_sptr(edge.src().block());
221
gr_block_detail_sptr src_detail = src_block->detail();
222
gr_buffer_sptr src_buffer = src_detail->output(edge.src().port());
223
gr_buffer_reader_sptr old_reader;
224
if (i < detail->ninputs()) // Don't exceed what the original detail has
225
old_reader = detail->input(i);
227
// If there's a match, use it
228
if (old_reader && (src_buffer == old_reader->buffer())) {
229
if (GR_FLAT_FLOWGRAPH_DEBUG)
230
std::cout << "matched, reusing" << std::endl;
233
if (GR_FLAT_FLOWGRAPH_DEBUG)
234
std::cout << "needs a new reader" << std::endl;
236
// Create new buffer reader and assign
237
detail->set_input(i, gr_buffer_add_reader(src_buffer, block->history()-1, block));
242
// Block is new, it just needs buffer readers at this point
243
if (GR_FLAT_FLOWGRAPH_DEBUG)
244
std::cout << "new block" << std::endl;
245
connect_block_inputs(block);
248
// Now deal with the fact that the block details might have changed numbers of
249
// inputs and outputs vs. in the old flowgraph.
253
void gr_flat_flowgraph::dump()
255
for (gr_edge_viter_t e = d_edges.begin(); e != d_edges.end(); e++)
256
std::cout << " edge: " << (*e) << std::endl;
258
for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) {
259
std::cout << " block: " << (*p) << std::endl;
260
gr_block_detail_sptr detail = cast_to_block_sptr(*p)->detail();
261
std::cout << " detail @" << detail << ":" << std::endl;
263
int ni = detail->ninputs();
264
int no = detail->noutputs();
265
for (int i = 0; i < no; i++) {
266
gr_buffer_sptr buffer = detail->output(i);
267
std::cout << " output " << i << ": " << buffer
268
<< " space=" << buffer->space_available() << std::endl;
271
for (int i = 0; i < ni; i++) {
272
gr_buffer_reader_sptr reader = detail->input(i);
273
std::cout << " reader " << i << ": " << reader
274
<< " reading from buffer=" << reader->buffer()
275
<< " avail=" << reader->items_available() << " items"
283
gr_flat_flowgraph::make_block_vector(gr_basic_block_vector_t &blocks)
285
gr_block_vector_t result;
286
for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
287
result.push_back(cast_to_block_sptr(*p));