From b629a998bdf0ff88af6f113bd605059ebd61efc8 Mon Sep 17 00:00:00 2001 From: Tom Rondeau <trondeau@vt.edu> Date: Mon, 4 Jun 2012 18:24:52 -0400 Subject: docs: added a description of a basic flowgraph to the manual's main page. Also a brief discussion of throughput/latency and how to use the max_noutput_items methods to control them. --- docs/doxygen/other/main_page.dox | 101 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) (limited to 'docs/doxygen') diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox index 68b0989436..4912a5411e 100644 --- a/docs/doxygen/other/main_page.dox +++ b/docs/doxygen/other/main_page.dox @@ -39,6 +39,106 @@ More details on packages in GNU Radio: \li \ref page_vocoder \li \ref page_pfb + +\section flowgraph Operating a Flowgraph + +The basic data structure in GNU Radio is the flowgraph, which +represents the connections of the blocks through which a continuous +stream of samples flows. The concept of a flowgraph is an acyclic +directional graph with one or more source blocks (to insert samples +into the flowgraph), one or more sink blocks (to terminate or export +samples from the flowgraph), and any signal processing blocks in +between. + +A program must at least create a GNU Radio 'top_block', which +represents the top-most structure of the flowgraph. The top blocks +provide the overall control and hold methods such as 'start,' 'stop,' +and 'wait.' + +The general construction of a GNU Radio application is to create a top +block, instantiate the blocks, connect the blocks together, and then +start the top block. The following program shows how this is done. A +single source and sink are used with a FIR filter between them. + +\code + from gnuradio import gr, filter + + class my_topblock(gr.top_block): + def __init__(self): + gr.top_block.__init__(self) + + amp = 1 + taps = filter.firdes.low_pass(1, 1, 0.1, 0.01) + + self.src = gr.noise_source_c(gr.GR_GAUSSIAN, amp) + self.flt = filter.fir_filter_ccf(1, taps) + self.snk = gr.null_sink(gr.sizeof_gr_complex) + + self.connect(self.src, self.flt, self.snk) + + if __name__ == "__main__": + tb = my_topblock() + tb.start() + tb.wait() +\endcode + +The 'tb.start()' starts the data flowing through the flowgraph while +the 'tb.wait()' is the equivalent of a thread's 'join' operation and +blocks until the top block is done. + +An alternative to using the 'start' and 'wait' methods, a 'run' method is +also provided for convenience that is a blocking start call; +equivalent to the above 'start' followed by a 'wait.' + + +\subsection latency Latency and Throughput + +By default, GNU Radio runs a scheduler that attempts to optimize +throughput. Using a dynamic scheduler, blocks in a flowgraph pass +chunks of items from sources to sinks. The sizes of these chunks will +vary depending on the speed of processing. For each block, the number +of items is can process is dependent on how much space it has in its +output buffer(s) and how many items are available on the input +buffer(s). + +The consequence of this is that often a block may be called with a very +large number of items to process (several thousand). In terms of +speed, this is efficient since now the majority of the processing time +is taken up with processing samples. Smaller chunks mean more calls +into the scheduler to retrieve more data. The downside to this is that +it can lead to large latency while a block is processing a large chunk +of data. + +To combat this problem, the top block can be passed a limit on the +number of output items a block will ever receive. A block may get less +than this number, but never more, and so it serves as an upper limit +to the latency any block will exhibit. By limiting the number of items +per call to a block, though, we increase the overhead of the +scheduler, and so reduce the overall efficiency of the application. + +To set the maximum number of output items, we pass a value into the +'start' or 'run' method of the top block: + +\code + tb.start(1000) + tb.wait() +or + tb.run(1000) +\endcode + +Using this method, we place a global restriction on the size of items +to all blocks. Each block, though, has the ability to overwrite this +with its own limit. Using the 'set_max_noutput_items(m)' method for an +individual block will overwrite the global setting. For example, in +the following code, the global setting is 1000 items max, except for +the FIR filter, which can receive up to 2000 items. + +\code + tb.flt.set_max_noutput_items(2000) + tb.run(1000) +\endcode + + \section volk_main Using Volk in GNU Radio The \ref volk_guide page provides an overview of how to incorporate @@ -48,4 +148,5 @@ Many blocks have already been converted to use Volk in their calls, so they can also serve as examples. See the gr_complex_to_xxx.h file for examples of various blocks that make use of Volk. + */ -- cgit v1.2.3 From 9c5cd068c1414f1112ab41708833c0fbc267c4d0 Mon Sep 17 00:00:00 2001 From: Tom Rondeau <trondeau@vt.edu> Date: Mon, 4 Jun 2012 20:23:01 -0400 Subject: docs: added section explaining the basics of reconfiguring a flowgraph. --- docs/doxygen/other/main_page.dox | 138 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 131 insertions(+), 7 deletions(-) (limited to 'docs/doxygen') diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox index 4912a5411e..1c4a60b3a8 100644 --- a/docs/doxygen/other/main_page.dox +++ b/docs/doxygen/other/main_page.dox @@ -55,10 +55,11 @@ represents the top-most structure of the flowgraph. The top blocks provide the overall control and hold methods such as 'start,' 'stop,' and 'wait.' -The general construction of a GNU Radio application is to create a top -block, instantiate the blocks, connect the blocks together, and then -start the top block. The following program shows how this is done. A -single source and sink are used with a FIR filter between them. +The general construction of a GNU Radio application is to create a +gr_top_block, instantiate the blocks, connect the blocks together, and +then start the gr_top_block. The following program shows how this is +done. A single source and sink are used with a FIR filter between +them. \code from gnuradio import gr, filter @@ -84,7 +85,7 @@ single source and sink are used with a FIR filter between them. The 'tb.start()' starts the data flowing through the flowgraph while the 'tb.wait()' is the equivalent of a thread's 'join' operation and -blocks until the top block is done. +blocks until the gr_top_block is done. An alternative to using the 'start' and 'wait' methods, a 'run' method is also provided for convenience that is a blocking start call; @@ -109,7 +110,7 @@ into the scheduler to retrieve more data. The downside to this is that it can lead to large latency while a block is processing a large chunk of data. -To combat this problem, the top block can be passed a limit on the +To combat this problem, the gr_top_block can be passed a limit on the number of output items a block will ever receive. A block may get less than this number, but never more, and so it serves as an upper limit to the latency any block will exhibit. By limiting the number of items @@ -117,7 +118,7 @@ per call to a block, though, we increase the overhead of the scheduler, and so reduce the overall efficiency of the application. To set the maximum number of output items, we pass a value into the -'start' or 'run' method of the top block: +'start' or 'run' method of the gr_top_block: \code tb.start(1000) @@ -139,6 +140,129 @@ the FIR filter, which can receive up to 2000 items. \endcode +\section reconfigure Reconfiguring Flowgraphs + +It is possible to reconfigure the flowgraph at runtime. The +reconfiguration is meant for changes in the flowgraph structure, not +individual parameter settings of the blocks. For example, changing the +constant in a gr_add_const_cc block can be done while the flowgraph is +running using the 'set_k(k)' method. + +Reconfiguration is done by locking the flowgraph, which stops it from +running and processing data, performing the reconfiguration, and then +restarting the graph by unlocking it. + +The following example code shows a graph that first adds two +gr_noise_source_c blocks and then replaces the gr_add_cc block with a +gr_sub_cc block to then subtract the sources. + +\code +from gnuradio import gr +import time + +class mytb(gr.top_block): + def __init__(self): + gr.top_block.__init__(self) + + self.src0 = gr.noise_source_c(gr.GR_GAUSSIAN, 1) + self.src1 = gr.noise_source_c(gr.GR_GAUSSIAN, 1) + self.add = gr.add_cc() + self.sub = gr.sub_cc() + self.head = gr.head(gr.sizeof_gr_complex, 1000000) + self.snk = gr.file_sink(gr.sizeof_gr_complex, "output.32fc") + + self.connect(self.src0, (self.add,0)) + self.connect(self.src1, (self.add,1)) + self.connect(self.add, self.head) + self.connect(self.head, self.snk) + +def main(): + tb = mytb() + tb.start() + time.sleep(0.01) + + # Stop flowgraph and disconnect the add block + tb.lock() + tb.disconnect(tb.add, tb.head) + tb.disconnect(tb.src0, (tb.add,0)) + tb.disconnect(tb.src1, (tb.add,1)) + + # Connect the sub block and restart + tb.connect(tb.sub, tb.head) + tb.connect(tb.src0, (tb.sub,0)) + tb.connect(tb.src1, (tb.sub,1)) + tb.unlock() + + tb.wait() + +if __name__ == "__main__": + main() +\endcode + +During reconfiguration, the maximum noutput_items value can be changed +either globally using the 'set_max_noutput_items(m)' on the gr_top_block +object or locally using the 'set_max_noutput_items(m)' on any given +block object. + +A block also has a 'unset_max_noutput_items()' method that unsets the +local max noutput_items value so that block reverts back to using the +global value. + +The following example expands the previous example but sets and resets +the max noutput_items both locally and globally. + +\code +from gnuradio import gr +import time + +class mytb(gr.top_block): + def __init__(self): + gr.top_block.__init__(self) + + self.src0 = gr.noise_source_c(gr.GR_GAUSSIAN, 1) + self.src1 = gr.noise_source_c(gr.GR_GAUSSIAN, 1) + self.add = gr.add_cc() + self.sub = gr.sub_cc() + self.head = gr.head(gr.sizeof_gr_complex, 1000000) + self.snk = gr.file_sink(gr.sizeof_gr_complex, "output.32fc") + + self.connect(self.src0, (self.add,0)) + self.connect(self.src1, (self.add,1)) + self.connect(self.add, self.head) + self.connect(self.head, self.snk) + +def main(): + # Start the gr_top_block after setting some max noutput_items. + tb = mytb() + tb.src1.set_max_noutput_items(2000) + tb.start(100) + time.sleep(0.01) + + # Stop flowgraph and disconnect the add block + tb.lock() + + tb.disconnect(tb.add, tb.head) + tb.disconnect(tb.src0, (tb.add,0)) + tb.disconnect(tb.src1, (tb.add,1)) + + # Connect the sub block + tb.connect(tb.sub, tb.head) + tb.connect(tb.src0, (tb.sub,0)) + tb.connect(tb.src1, (tb.sub,1)) + + # Set new max_noutput_items for the gr_top_block + # and unset the local value for src1 + tb.set_max_noutput_items(1000) + tb.src1.unset_max_noutput_items() + tb.unlock() + + tb.wait() + +if __name__ == "__main__": + main() +\endcode + + \section volk_main Using Volk in GNU Radio The \ref volk_guide page provides an overview of how to incorporate -- cgit v1.2.3 From 5fcb7ebd473709fd9e4e99d542f21d3cee5aaf05 Mon Sep 17 00:00:00 2001 From: Tom Rondeau <trondeau@vt.edu> Date: Tue, 2 Oct 2012 13:08:11 -0400 Subject: docs: Adding notes discussing how to use new max_output_buffer feature. Also sneaking in a new analog group for gr-analog. --- docs/doxygen/other/group_defs.dox | 1 + docs/doxygen/other/main_page.dox | 50 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) (limited to 'docs/doxygen') diff --git a/docs/doxygen/other/group_defs.dox b/docs/doxygen/other/group_defs.dox index 213486b7a1..4aee49ec85 100644 --- a/docs/doxygen/other/group_defs.dox +++ b/docs/doxygen/other/group_defs.dox @@ -28,6 +28,7 @@ /*! \defgroup slicedice_blk Slicing and Dicing Streams */ /*! \defgroup vocoder_blk Voice Encoders and Decoders */ /*! \defgroup digital Digital Modulation Blocks */ +/*! \defgroup analog Analog Communications Blocks */ /*! \defgroup qtgui_blk QT Graphical Interfaces */ /*! \defgroup uhd_blk UHD Interface */ /*! \defgroup audio_blk Audio Interface */ diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox index c90ad883f6..f2ab2a4367 100644 --- a/docs/doxygen/other/main_page.dox +++ b/docs/doxygen/other/main_page.dox @@ -139,6 +139,56 @@ the FIR filter, which can receive up to 2000 items. tb.run(1000) \endcode +In some situations, you might actually want to restrict the size of +the buffer itself. This can help to prevent a buffer who is blocked +for data from just increasing the amount of items in its buffer, which +will then cause an increased latency for new samples. You can set the +size of an output buffer for each output port for every block. + +WARNING: This is an advanced feature in GNU Radio and should not be +used without a full understanding of this concept as explained below. + +To set the output buffer size of a block, you simply call: + +\code + tb.blk0.set_max_output_buffer(2000) + tb.blk1.set_max_output_buffer(2000,1) + tb.start() + print tb.blk1.max_output_buffer(0) + print tb.blk1.max_output_buffer(1) +\endcode + +In the above example, all ports of blk0 are set to a buffer size of +2000 in _items_ (not bytes), and blk1 only sets the size for output +port 1, any and all other ports use the default. The third and fourth +lines just print out the buffer sizes for ports 0 and 1 of blk1. This +is done after start() is called because the values are updated based +on what is actually allocated to the block's buffers. + +NOTES: + +1. Buffer length assignment is done once at runtime (i.e., when run() +or start() is called). So to set the max buffer lengths, the +set_max_output_buffer calls must be done before this. + +2. Once the flowgraph is started, the buffer lengths for a block are +set and cannot be dynamically changed, even during a +lock()/unlock(). If you need to change the buffer size, you will have +to delete the block and rebuild it, and therefore must disconnect and +reconnect the blocks. + +3. This can affect throughput. Large buffers are designed to improve +the efficiency and speed of the program at the expense of +latency. Limiting the size of the buffer may decrease performance. + +4. The real buffer size is actually based on a minimum granularity of +the system. Typically, this is a page size, which is typically 4096 +bytes. This means that any buffer size that is specified with this +command will get rounded up to the nearest granularity (e.g., page) +size. When calling max_output_buffer(port) after the flowgraph is +started, you will get how many items were actually allocated in the +buffer, which may be different than what was initially specified. + \section reconfigure Reconfiguring Flowgraphs -- cgit v1.2.3 From 1e528816fd70f3a61d7f00a370cb056f03ceb6a7 Mon Sep 17 00:00:00 2001 From: Tom Rondeau <trondeau@vt.edu> Date: Tue, 2 Oct 2012 14:52:07 -0400 Subject: core: fixed swig file for exporting max/min buffer sizes with port first. --- docs/doxygen/other/main_page.dox | 2 +- gnuradio-core/src/lib/runtime/gr_basic_block.i | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'docs/doxygen') diff --git a/docs/doxygen/other/main_page.dox b/docs/doxygen/other/main_page.dox index f2ab2a4367..2826824647 100644 --- a/docs/doxygen/other/main_page.dox +++ b/docs/doxygen/other/main_page.dox @@ -152,7 +152,7 @@ To set the output buffer size of a block, you simply call: \code tb.blk0.set_max_output_buffer(2000) - tb.blk1.set_max_output_buffer(2000,1) + tb.blk1.set_max_output_buffer(1, 2000) tb.start() print tb.blk1.max_output_buffer(0) print tb.blk1.max_output_buffer(1) diff --git a/gnuradio-core/src/lib/runtime/gr_basic_block.i b/gnuradio-core/src/lib/runtime/gr_basic_block.i index 848017dd86..7713f2fe15 100644 --- a/gnuradio-core/src/lib/runtime/gr_basic_block.i +++ b/gnuradio-core/src/lib/runtime/gr_basic_block.i @@ -44,10 +44,10 @@ public: bool check_topology (int ninputs, int noutputs); long max_output_buffer(int i); void set_max_output_buffer(long max_output_buffer); - void set_max_output_buffer(long max_output_buffer, int port); + void set_max_output_buffer(int port, long max_output_buffer); long min_output_buffer(int i); void set_min_output_buffer(long min_output_buffer); - void set_min_output_buffer(long min_output_buffer, int port); + void set_min_output_buffer(int port, long min_output_buffer); }; %rename(block_ncurrently_allocated) gr_basic_block_ncurrently_allocated; -- cgit v1.2.3