3 * Copyright 2006 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 2, 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_simple_flowgraph.h>
28 #include <gr_simple_flowgraph_detail.h>
29 #include <gr_io_signature.h>
30 #include <gr_block_detail.h>
31 #include <gr_buffer.h>
35 #define GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG 0
38 gr_make_edge(const std::string &src_name, int src_port,
39 const std::string &dst_name, int dst_port)
41 return gr_edge_sptr(new gr_edge(src_name, src_port, dst_name, dst_port));
44 gr_edge::gr_edge(const std::string &src_name, int src_port, const std::string &dst_name, int dst_port)
45 : d_src(src_name, src_port),
46 d_dst(dst_name, dst_port)
54 gr_simple_flowgraph_detail::gr_simple_flowgraph_detail() :
60 gr_simple_flowgraph_detail::~gr_simple_flowgraph_detail()
65 gr_simple_flowgraph_detail::reset()
67 // Boost shared pointers will deallocate as needed
73 gr_simple_flowgraph_detail::lookup_block(const std::string &name)
75 gr_component_miter_t p = d_components.find(name);
76 if (p != d_components.end())
79 return gr_block_sptr();
83 gr_simple_flowgraph_detail::lookup_name(gr_block_sptr block)
85 for (gr_component_miter_t p = d_components.begin(); p != d_components.end(); p++) {
86 if (p->second == block)
90 return std::string(""); // Not found
94 gr_simple_flowgraph_detail::define_component(const std::string &name, gr_block_sptr block)
97 throw std::invalid_argument("null block passed");
99 if (!lookup_block(name))
100 d_components[name] = block;
102 throw std::invalid_argument("name already in use");
106 gr_simple_flowgraph_detail::connect(const std::string &src_name, int src_port,
107 const std::string &dst_name, int dst_port)
109 gr_block_sptr src_block = lookup_block(src_name);
110 gr_block_sptr dst_block = lookup_block(dst_name);
112 if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
113 std::cout << "Connecting " << src_name << ":" << src_port << "->"
114 << dst_name << ":" << dst_port << std::endl;
117 throw std::invalid_argument("unknown src name");
119 throw std::invalid_argument("unknown dst name");
121 check_valid_port(src_block->output_signature(), src_port);
122 check_valid_port(dst_block->input_signature(), dst_port);
123 check_dst_not_used(dst_name, dst_port);
124 check_type_match(src_block, src_port, dst_block, dst_port);
126 d_edges.push_back(gr_make_edge(src_name, src_port, dst_name, dst_port));
130 gr_simple_flowgraph_detail::check_valid_port(gr_io_signature_sptr sig, int port)
133 throw std::invalid_argument("negative port number");
134 if (sig->max_streams() >= 0 && port >= sig->max_streams())
135 throw std::invalid_argument("port number exceeds max");
139 gr_simple_flowgraph_detail::check_dst_not_used(const std::string &name, int port)
141 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
142 if ((*p)->dst_name() == name && (*p)->dst_port() == port)
143 throw std::invalid_argument("dst already in use");
147 gr_simple_flowgraph_detail::check_type_match(gr_block_sptr src_block, int src_port,
148 gr_block_sptr dst_block, int dst_port)
150 int src_size = src_block->output_signature()->sizeof_stream_item(src_port);
151 int dst_size = dst_block->input_signature()->sizeof_stream_item(dst_port);
153 if (src_size != dst_size)
154 throw std::invalid_argument("type size mismatch");
158 gr_simple_flowgraph_detail::validate()
160 for (gr_component_miter_t p = d_components.begin(); p != d_components.end(); p++) {
161 std::vector<int> used_ports;
162 int ninputs, noutputs;
164 used_ports = calc_used_ports(p->first, true); // inputs
165 ninputs = used_ports.size();
166 check_contiguity(p->second, used_ports, true); // inputs
168 used_ports = calc_used_ports(p->first, false); // outputs
169 noutputs = used_ports.size();
170 check_contiguity(p->second, used_ports, false); // outputs
172 if (!(p->second->check_topology(ninputs, noutputs)))
173 throw std::runtime_error("check topology failed");
178 gr_simple_flowgraph_detail::calc_used_ports(const std::string &name, bool check_inputs)
180 if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
181 std::cout << "Calculating used " << (check_inputs ? "input " : "output ")
184 std::vector<int> tmp, result;
185 std::insert_iterator<std::vector<int> > inserter(result, result.begin());
187 gr_edge_vector_t edges = calc_connections(name, check_inputs);
189 for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) {
190 if (check_inputs == true)
191 tmp.push_back((*p)->dst_port());
193 tmp.push_back((*p)->src_port());
197 std::sort(tmp.begin(), tmp.end());
198 std::unique_copy(tmp.begin(), tmp.end(), inserter);
200 if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
201 std::cout << result.size() << std::endl;
207 gr_simple_flowgraph_detail::calc_connections(const std::string &name, bool check_inputs)
209 gr_edge_vector_t result;
211 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
213 if ((*p)->dst_name() == name)
214 result.push_back(*p);
217 if ((*p)->src_name() == name)
218 result.push_back(*p);
222 return result; // assumes no duplicates
226 gr_simple_flowgraph_detail::check_contiguity(gr_block_sptr block,
227 const std::vector<int> &used_ports,
230 if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
231 std::cout << "Checking " << (check_inputs ? "input " : "output ")
234 gr_io_signature_sptr sig =
235 check_inputs ? block->input_signature() : block->output_signature();
237 int nports = used_ports.size();
238 int min_ports = sig->min_streams();
241 if (min_ports == 0) {
242 if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
243 std::cout << "ok." << std::endl;
247 if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
248 std::cout << "needs " << min_ports << ", only has "
249 << nports << std::endl;
251 throw std::runtime_error("insufficient ports");
255 if (used_ports[nports-1]+1 != nports) {
256 for (int i = 0; i < nports; i++) {
257 if (used_ports[i] != i) {
258 if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
259 std::cout << "missing " << (check_inputs ? "input ":"output ")
262 throw std::runtime_error("missing input assignment");
267 if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
268 std::cout << "ok." << std::endl;
272 gr_simple_flowgraph_detail::setup_connections()
274 // Assign block details to component blocks
275 for (gr_component_miter_t p = d_components.begin(); p != d_components.end(); p++) {
276 if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
277 std::cout << "Allocating output buffers for " << p->first << "..." << std::endl;
279 int ninputs = calc_used_ports(p->first, true).size();
280 int noutputs = calc_used_ports(p->first, false).size();
281 gr_block_detail_sptr detail = gr_make_block_detail(ninputs, noutputs);
282 for (int i = 0; i < noutputs; i++)
283 detail->set_output(i, allocate_buffer(p->first, i));
284 p->second->set_detail(detail);
287 // Connect inputs to outputs for each block
288 for(gr_component_miter_t p = d_components.begin(); p != d_components.end(); p++) {
289 // Get its detail and edges that feed into it
290 gr_block_detail_sptr detail = p->second->detail();
291 gr_edge_vector_t in_edges = calc_upstream_edges(p->first);
293 if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
294 if (in_edges.size() > 0)
295 std::cout << "Connecting inputs to " << p->first << "..." << std::endl;
297 // For each edge that feeds into it
298 for (gr_edge_viter_t e = in_edges.begin(); e != in_edges.end(); e++) {
299 // Set the input buffer on the destination port to the output
300 // buffer on the source port
301 int dst_port = (*e)->dst_port();
302 int src_port = (*e)->src_port();
303 gr_block_sptr src_block = lookup_block((*e)->src_name());
304 gr_buffer_sptr src_buffer = src_block->detail()->output(src_port);
306 if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
307 std::cout << "Setting input on " << (*e)->dst_name()
308 << ":" << dst_port << std::endl;
310 detail->set_input(dst_port, gr_buffer_add_reader(src_buffer, p->second->history()-1));
316 gr_simple_flowgraph_detail::allocate_buffer(const std::string &name, int port)
318 gr_block_sptr block = lookup_block(name);
319 int item_size = block->output_signature()->sizeof_stream_item(port);
320 int nitems = s_fixed_buffer_size/item_size;
322 // Make sure there are at least twice the output_multiple no. of items
323 if (nitems < 2*block->output_multiple()) // Note: this means output_multiple()
324 nitems = 2*block->output_multiple(); // can't be changed by block dynamically
326 // If any downstream blocks are decimators and/or have a large output_multiple,
327 // ensure we have a buffer at least twice their decimation factor*output_multiple
328 gr_block_vector_t blocks = calc_downstream_blocks(name, port);
329 for (gr_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
330 int decimation = (int)(1.0/(*p)->relative_rate());
331 int multiple = (*p)->output_multiple();
332 int history = (*p)->history();
333 nitems = std::max(nitems, 2*(decimation*multiple+history));
336 if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
337 std::cout << "Allocating buffer for port " << port << " with "
338 << nitems << " items of size " << item_size << std::endl;
340 return gr_make_buffer(nitems, item_size);
344 gr_simple_flowgraph_detail::calc_downstream_blocks(const std::string &name, int port)
346 gr_block_vector_t tmp, result;
347 std::insert_iterator<gr_block_vector_t> inserter(result, result.begin());
349 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
350 if ((*p)->src_name() == name && (*p)->src_port() == port)
351 tmp.push_back(lookup_block((*p)->dst_name()));
354 sort(tmp.begin(), tmp.end());
355 unique_copy(tmp.begin(), tmp.end(), inserter);
360 gr_simple_flowgraph_detail::calc_downstream_blocks(const std::string &name)
362 gr_block_vector_t tmp, result;
363 std::insert_iterator<gr_block_vector_t> inserter(result, result.begin());
365 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
366 if ((*p)->src_name() == name)
367 tmp.push_back(lookup_block((*p)->dst_name()));
370 sort(tmp.begin(), tmp.end());
371 unique_copy(tmp.begin(), tmp.end(), inserter);
376 gr_simple_flowgraph_detail::calc_upstream_edges(const std::string &name)
378 gr_edge_vector_t result;
380 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
381 if ((*p)->dst_name() == name)
382 result.push_back(*p);
384 return result; // Assume no duplicates
388 gr_simple_flowgraph_detail::calc_used_blocks()
390 std::vector<std::string> tmp, tmp_unique;
391 std::insert_iterator<std::vector<std::string> > inserter(tmp_unique, tmp_unique.begin());
392 gr_block_vector_t result;
394 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
395 tmp.push_back((*p)->src_name());
396 tmp.push_back((*p)->dst_name());
399 sort(tmp.begin(), tmp.end());
400 unique_copy(tmp.begin(), tmp.end(), inserter);
402 for (std::vector<std::string>::iterator p = tmp_unique.begin();
403 p != tmp_unique.end(); p++)
404 result.push_back(lookup_block(*p));
406 if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
407 std::cout << "Flowgraph uses " << result.size()
408 << " distinct blocks." << std::endl;
413 std::vector<gr_block_vector_t>
414 gr_simple_flowgraph_detail::partition()
416 std::vector<gr_block_vector_t> result;
417 gr_block_vector_t blocks = calc_used_blocks();
418 gr_block_vector_t graph;
420 while (blocks.size() > 0) {
421 graph = calc_reachable_blocks(blocks[0], blocks);
422 assert(graph.size());
423 result.push_back(topological_sort(graph));
425 for (gr_block_viter_t p = graph.begin(); p != graph.end(); p++)
426 blocks.erase(find(blocks.begin(), blocks.end(), *p));
433 gr_simple_flowgraph_detail::calc_reachable_blocks(gr_block_sptr block, gr_block_vector_t &blocks)
435 gr_block_vector_t result;
437 // Mark all blocks as unvisited
438 for (gr_block_viter_t p = blocks.begin(); p != blocks.end(); p++)
439 (*p)->detail()->set_color(gr_block_detail::WHITE);
441 // Recursively mark all reachable blocks
442 reachable_dfs_visit(block, blocks);
444 // Collect all the blocks that have been visited
445 for (gr_block_viter_t p = blocks.begin(); p != blocks.end(); p++)
446 if ((*p)->detail()->color() == gr_block_detail::BLACK)
447 result.push_back(*p);
452 // Recursively mark all reachable blocks from given block and block list
454 gr_simple_flowgraph_detail::reachable_dfs_visit(gr_block_sptr block, gr_block_vector_t &blocks)
456 // Mark the current one as visited
457 block->detail()->set_color(gr_block_detail::BLACK);
459 // Recurse into adjacent vertices
460 gr_block_vector_t adjacent = calc_adjacent_blocks(block, blocks);
462 for (gr_block_viter_t p = adjacent.begin(); p != adjacent.end(); p++)
463 if ((*p)->detail()->color() == gr_block_detail::WHITE)
464 reachable_dfs_visit(*p, blocks);
467 // Return a list of block adjacent to a given block along any edge
469 gr_simple_flowgraph_detail::calc_adjacent_blocks(gr_block_sptr block, gr_block_vector_t &blocks)
471 gr_block_vector_t tmp, result;
472 std::insert_iterator<gr_block_vector_t> inserter(result, result.begin());
474 // Find any blocks that are inputs or outputs
475 for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
476 if (lookup_block((*p)->src_name()) == block)
477 tmp.push_back(lookup_block((*p)->dst_name()));
478 if (lookup_block((*p)->dst_name()) == block)
479 tmp.push_back(lookup_block((*p)->src_name()));
483 sort(tmp.begin(), tmp.end());
484 unique_copy(tmp.begin(), tmp.end(), inserter);
489 gr_simple_flowgraph_detail::dump_block_vector(gr_block_vector_t blocks)
491 for (gr_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
492 std::cout << (*p) << std::endl;
497 gr_simple_flowgraph_detail::topological_sort(gr_block_vector_t &blocks)
499 gr_block_vector_t result, tmp;
500 std::cout << "Before source sort: " << std::endl;
501 dump_block_vector(blocks);
502 std::cout << std::endl;
504 tmp = sort_sources_first(blocks);
506 std::cout << "After source sort: " << std::endl;
507 dump_block_vector(tmp);
508 std::cout << std::endl;
510 // Start 'em all white
511 for (gr_block_viter_t p = tmp.begin(); p != tmp.end(); p++)
512 (*p)->detail()->set_color(gr_block_detail::WHITE);
514 for (gr_block_viter_t p = tmp.begin(); p != tmp.end(); p++) {
515 if ((*p)->detail()->color() == gr_block_detail::WHITE)
516 topological_dfs_visit(*p, result);
519 reverse(result.begin(), result.end());
521 std::cout << "After dfs: " << std::endl;
522 dump_block_vector(result);
523 std::cout << std::endl;
529 gr_simple_flowgraph_detail::source_p(gr_block_sptr block)
531 return (calc_upstream_edges(lookup_name(block)).size() == 0);
535 gr_simple_flowgraph_detail::sort_sources_first(gr_block_vector_t &blocks)
537 gr_block_vector_t sources, nonsources, result;
539 for (gr_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
541 sources.push_back(*p);
543 nonsources.push_back(*p);
546 for (gr_block_viter_t p = sources.begin(); p != sources.end(); p++)
547 result.push_back(*p);
549 for (gr_block_viter_t p = nonsources.begin(); p != nonsources.end(); p++)
550 result.push_back(*p);
556 gr_simple_flowgraph_detail::topological_dfs_visit(gr_block_sptr block, gr_block_vector_t &output)
558 block->detail()->set_color(gr_block_detail::GREY);
560 gr_block_vector_t ds_blocks = calc_downstream_blocks(lookup_name(block));
561 std::cout << "Downstream blocks of " << block << ":" << std::endl;
562 dump_block_vector(ds_blocks);
564 gr_block_vector_t blocks(ds_blocks);
565 for (gr_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
566 switch ((*p)->detail()->color()) {
567 case gr_block_detail::WHITE: // (u, v) is a tree edge
568 topological_dfs_visit(*p, output);
571 case gr_block_detail::GREY: // (u, v) is a back edge - not a DAG
572 throw std::runtime_error("flow graph has loops!");
574 case gr_block_detail::BLACK:
578 throw std::runtime_error("invalid color on block!");
583 block->detail()->set_color(gr_block_detail::BLACK);
584 output.push_back(block);