diff options
-rw-r--r-- | docs/doxygen/other/thread_affinity.dox | 50 | ||||
-rw-r--r-- | gnuradio-runtime/include/gnuradio/basic_block.h | 9 | ||||
-rw-r--r-- | gnuradio-runtime/include/gnuradio/hier_block2.h | 23 | ||||
-rw-r--r-- | gnuradio-runtime/lib/hier_block2.cc | 18 | ||||
-rw-r--r-- | gnuradio-runtime/lib/hier_block2_detail.cc | 25 | ||||
-rw-r--r-- | gnuradio-runtime/lib/hier_block2_detail.h | 4 | ||||
-rw-r--r-- | gnuradio-runtime/swig/hier_block2.i | 4 | ||||
-rwxr-xr-x | gr-blocks/python/blocks/qa_hier_block2.py | 33 | ||||
-rw-r--r-- | grc/base/Block.py | 12 | ||||
-rw-r--r-- | grc/python/flow_graph.tmpl | 3 |
10 files changed, 171 insertions, 10 deletions
diff --git a/docs/doxygen/other/thread_affinity.dox b/docs/doxygen/other/thread_affinity.dox index 2f31d9ce53..86634ffdf5 100644 --- a/docs/doxygen/other/thread_affinity.dox +++ b/docs/doxygen/other/thread_affinity.dox @@ -10,13 +10,13 @@ The implementation is done by adding new functions to the threading section of the gnuradio-runtime library: \code - gr_thread_t get_current_thread_id(); + gr::thread::gr_thread_t get_current_thread_id(); void thread_bind_to_processor(unsigned int n); void thread_bind_to_processor(const std::vector<unsigned int> &mask); - void thread_bind_to_processor(gr_thread_t thread, unsigned int n); - void thread_bind_to_processor(gr_thread_t thread, const std::vector<unsigned int> &mask); + void thread_bind_to_processor(gr::thread::gr_thread_t thread, unsigned int n); + void thread_bind_to_processor(gr::thread::gr_thread_t thread, const std::vector<unsigned int> &mask); void thread_unbind(); - void thread_unbind(gr_thread_t thread); + void thread_unbind(gr::thread::gr_thread_t thread); \endcode The ability to set a thread's affinity to a core or groups of cores is @@ -45,21 +45,55 @@ Each block has two new data members: thread. - thread: a gr::thread::gr_thread_t handle to the block's thread. -A block can set and unset it's affinity at any time using the +A block can set and unset its affinity at any time using the following member functions: -- gr_block::set_processor_affinity(const std::vector<unsigned int> &mask) -- gr_block::unset_processor_affinity() +- gr::block::set_processor_affinity(const std::vector<int> &mask) +- gr::block::unset_processor_affinity() Where \p mask is a vector of core numbers to set the thread's affinity to. The current core affinity can be retrieved using the member function: -- gr_block::processor_affinity() +- gr::block::processor_affinity() When set before the flowgraph is started, the scheduler will set the thread's affinity when it is started. When already running, the block's affinity will be immediately set. + +\subsection affinity_api_hier Setting Affinity for a gr::hier_block2 + +A hierarchical block (gr::hier_block2) also has a concept of setting +the block thread affinity. Because the hierarchical block itself does +no work and just encapsulates a set of blocks, setting the +hierarchical block's affinity individually sets all blocks inside it +to that affinity setting. + +The gr::hier_block2 class supports the same API interface to the block +thread affinity: + +- gr::hier_block2::set_processor_affinity(const std::vector<int> &mask) +- gr::hier_block2::unset_processor_affinity() +- gr::hier_block2::processor_affinity() + +Setting and unsetting the affinity does so recursively for every block +in the hierarchical block. It is of course possible to individually set +the affinity to any block underneath the hierarchical block. However, +in this case, note that when asking for the current affinity value +using 'processor_affinity()', the code returns the current processor +affinity value of only the first block. + + +\subsection affinity_api_grc GRC Access + +GRC supports the setting of the thread core affinity in a block's +options. Each block now has a field 'Core Affinity' that accepts a +vector (list) of integers and sets the affinity after the block is +constructed. + +Note that GRC does not provide a callback function for changing the +thread core affinity while the flowgraph is running. + */ diff --git a/gnuradio-runtime/include/gnuradio/basic_block.h b/gnuradio-runtime/include/gnuradio/basic_block.h index be385465d1..f1a4297eae 100644 --- a/gnuradio-runtime/include/gnuradio/basic_block.h +++ b/gnuradio-runtime/include/gnuradio/basic_block.h @@ -331,6 +331,15 @@ namespace gr { } d_msg_handlers[which_port] = msg_handler_t(msg_handler); } + + virtual void set_processor_affinity(const std::vector<int> &mask) + { throw std::runtime_error("set_processor_affinity not overloaded in child class."); } + + virtual void unset_processor_affinity() + { throw std::runtime_error("unset_processor_affinity not overloaded in child class."); } + + virtual std::vector<int> processor_affinity() + { throw std::runtime_error("processor_affinity not overloaded in child class."); } }; inline bool operator<(basic_block_sptr lhs, basic_block_sptr rhs) diff --git a/gnuradio-runtime/include/gnuradio/hier_block2.h b/gnuradio-runtime/include/gnuradio/hier_block2.h index ff09f9139d..0d7b138e4d 100644 --- a/gnuradio-runtime/include/gnuradio/hier_block2.h +++ b/gnuradio-runtime/include/gnuradio/hier_block2.h @@ -210,6 +210,29 @@ namespace gr { throw std::invalid_argument("block already has a primitive output port by this name"); hier_message_ports_out = pmt::list_add(hier_message_ports_out, port_id); } + + /*! + * \brief Set the affinity of all blocks in hier_block2 to processor core \p n. + * + * \param mask a vector of ints of the core numbers available to this block. + */ + void set_processor_affinity(const std::vector<int> &mask); + + /*! + * \brief Remove processor affinity for all blocks in hier_block2. + */ + void unset_processor_affinity(); + + /*! + * \brief Get the current processor affinity. + * + * \details This returns the processor affinity value for the first + * block in the hier_block2's list of blocks with the assumption + * that they have always only been set through the hier_block2's + * interface. If any block has been individually set, then this + * call could be misleading. + */ + std::vector<int> processor_affinity(); }; inline hier_block2_sptr cast_to_hier_block2_sptr(basic_block_sptr block) { diff --git a/gnuradio-runtime/lib/hier_block2.cc b/gnuradio-runtime/lib/hier_block2.cc index f26da18e54..e0acba30a0 100644 --- a/gnuradio-runtime/lib/hier_block2.cc +++ b/gnuradio-runtime/lib/hier_block2.cc @@ -157,4 +157,22 @@ namespace gr { return new_ffg; } + void + hier_block2::set_processor_affinity(const std::vector<int> &mask) + { + d_detail->set_processor_affinity(mask); + } + + void + hier_block2::unset_processor_affinity() + { + d_detail->unset_processor_affinity(); + } + + std::vector<int> + hier_block2::processor_affinity() + { + return d_detail->processor_affinity(); + } + } /* namespace gr */ diff --git a/gnuradio-runtime/lib/hier_block2_detail.cc b/gnuradio-runtime/lib/hier_block2_detail.cc index 83207d978c..85b848101c 100644 --- a/gnuradio-runtime/lib/hier_block2_detail.cc +++ b/gnuradio-runtime/lib/hier_block2_detail.cc @@ -654,4 +654,29 @@ namespace gr { d_owner->unlock(); } + void + hier_block2_detail::set_processor_affinity(const std::vector<int> &mask) + { + basic_block_vector_t tmp = d_fg->calc_used_blocks(); + for(basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) { + (*p)->set_processor_affinity(mask); + } + } + + void + hier_block2_detail::unset_processor_affinity() + { + basic_block_vector_t tmp = d_fg->calc_used_blocks(); + for(basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) { + (*p)->unset_processor_affinity(); + } + } + + std::vector<int> + hier_block2_detail::processor_affinity() + { + basic_block_vector_t tmp = d_fg->calc_used_blocks(); + return tmp[0]->processor_affinity(); + } + } /* namespace gr */ diff --git a/gnuradio-runtime/lib/hier_block2_detail.h b/gnuradio-runtime/lib/hier_block2_detail.h index 99bf6e8ef1..806738360f 100644 --- a/gnuradio-runtime/lib/hier_block2_detail.h +++ b/gnuradio-runtime/lib/hier_block2_detail.h @@ -54,6 +54,10 @@ namespace gr { void unlock(); void flatten_aux(flat_flowgraph_sptr sfg) const; + void set_processor_affinity(const std::vector<int> &mask); + void unset_processor_affinity(); + std::vector<int> processor_affinity(); + private: // Private implementation data hier_block2 *d_owner; diff --git a/gnuradio-runtime/swig/hier_block2.i b/gnuradio-runtime/swig/hier_block2.i index b455e02a7e..87c936544a 100644 --- a/gnuradio-runtime/swig/hier_block2.i +++ b/gnuradio-runtime/swig/hier_block2.i @@ -87,6 +87,10 @@ namespace gr { void message_port_register_hier_in(pmt::pmt_t port_id); void message_port_register_hier_out(pmt::pmt_t port_id); + void set_processor_affinity(const std::vector<int> &mask); + void unset_processor_affinity(); + std::vector<int> processor_affinity(); + gr::hier_block2_sptr to_hier_block2(); // Needed for Python type coercion }; } diff --git a/gr-blocks/python/blocks/qa_hier_block2.py b/gr-blocks/python/blocks/qa_hier_block2.py index 51f420e8eb..5a351f2b37 100755 --- a/gr-blocks/python/blocks/qa_hier_block2.py +++ b/gr-blocks/python/blocks/qa_hier_block2.py @@ -393,5 +393,38 @@ class test_hier_block2(gr_unittest.TestCase): self.assertEquals(dst.data(), (3.0,)) + def test_033a_set_affinity(self): + expected = (1.0, 2.0, 3.0, 4.0) + hblock = gr.top_block("test_block") + src = blocks.vector_source_f(expected, False) + snk = blocks.vector_sink_f() + hblock.connect(src, snk) + hblock.set_processor_affinity([0,]) + hblock.run() + actual = snk.data() + self.assertEquals(expected, actual) + + def test_033b_unset_affinity(self): + expected = (1.0, 2.0, 3.0, 4.0) + hblock = gr.top_block("test_block") + src = blocks.vector_source_f(expected, False) + snk = blocks.vector_sink_f() + hblock.connect(src, snk) + hblock.set_processor_affinity([0,]) + hblock.unset_processor_affinity() + hblock.run() + actual = snk.data() + self.assertEquals(expected, actual) + + def test_033c_get_affinity(self): + expected = (1.0, 2.0, 3.0, 4.0) + hblock = gr.top_block("test_block") + src = blocks.vector_source_f(expected, False) + snk = blocks.vector_sink_f() + hblock.connect(src, snk) + hblock.set_processor_affinity([0,]) + procs = hblock.processor_affinity() + self.assertEquals((0,), procs) + if __name__ == "__main__": gr_unittest.run(test_hier_block2, "test_hier_block2.xml") diff --git a/grc/base/Block.py b/grc/base/Block.py index 30b0ca2f60..453023e456 100644 --- a/grc/base/Block.py +++ b/grc/base/Block.py @@ -125,7 +125,16 @@ class Block(Element): self.get_sinks().append(sink) self.back_ofthe_bus(self.get_sinks()) self.current_bus_structure = {'source':'','sink':''}; - + + if len(sources) or len(sinks): + self.get_params().append(self.get_parent().get_parent().Param( + block=self, + n=odict({'name': 'Core Affinity', + 'key': 'affinity', + 'type': 'int_vector', + 'hide': 'part', + }) + )) def back_ofthe_bus(self, portlist): portlist.sort(key=lambda a: a.get_type() == 'bus'); @@ -374,7 +383,6 @@ class Block(Element): elif len(bussinks) > 0: self.bussify({'name':'bus','type':'bus'}, 'sink') self.bussify({'name':'bus','type':'bus'}, 'sink') - bussrcs = n.findall('bus_source'); if len(bussrcs) > 0 and not self._bussify_source: self.bussify({'name':'bus','type':'bus'}, 'source') diff --git a/grc/python/flow_graph.tmpl b/grc/python/flow_graph.tmpl index 550ecd78b5..2220e28ff7 100644 --- a/grc/python/flow_graph.tmpl +++ b/grc/python/flow_graph.tmpl @@ -161,6 +161,9 @@ gr.io_signaturev($(len($io_sigs)), $(len($io_sigs)), [$(', '.join($size_strs))]) $indent($blk.get_make()) #else self.$blk.get_id() = $indent($blk.get_make()) + #if $blk.get_param('affinity').get_value() + (self.$blk.get_id()).set_processor_affinity($blk.get_param('affinity').get_value()) + #end if #end if #end for ######################################################## |