summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/doxygen/other/thread_affinity.dox50
-rw-r--r--gnuradio-runtime/include/gnuradio/basic_block.h9
-rw-r--r--gnuradio-runtime/include/gnuradio/hier_block2.h23
-rw-r--r--gnuradio-runtime/lib/hier_block2.cc18
-rw-r--r--gnuradio-runtime/lib/hier_block2_detail.cc25
-rw-r--r--gnuradio-runtime/lib/hier_block2_detail.h4
-rw-r--r--gnuradio-runtime/swig/hier_block2.i4
-rwxr-xr-xgr-blocks/python/blocks/qa_hier_block2.py33
-rw-r--r--grc/base/Block.py12
-rw-r--r--grc/python/flow_graph.tmpl3
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
########################################################