diff options
author | Martin Braun <martin.braun@ettus.com> | 2018-01-05 18:08:07 -0800 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2018-01-08 17:38:29 -0800 |
commit | 33ddbbb25702cab0fb271367e4ffd9563a6c75f5 (patch) | |
tree | 556cbcf90c45d334b0c20595611f0a076748dcf9 /host | |
parent | 838b71902ff1b9cb556f5141de53ab6ee5ba1e75 (diff) | |
download | uhd-33ddbbb25702cab0fb271367e4ffd9563a6c75f5.tar.gz uhd-33ddbbb25702cab0fb271367e4ffd9563a6c75f5.tar.bz2 uhd-33ddbbb25702cab0fb271367e4ffd9563a6c75f5.zip |
mpmd: Refactor device initialization for better parallelizability
Note: This doesn't add any concurrency, rather, it changes the
structure of the code to allow that. Notable changes:
- All prop tree inits in one place
- No access to containers in methods that might be run in parallel
- Split initialization and claiming in mpmd_mboard_impl, calling ctor
will no longer run the full initialization.
- Added comments to identify parallelizable spots
Diffstat (limited to 'host')
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_impl.cpp | 130 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_impl.hpp | 53 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_mboard_impl.cpp | 34 |
3 files changed, 125 insertions, 92 deletions
diff --git a/host/lib/usrp/mpmd/mpmd_impl.cpp b/host/lib/usrp/mpmd/mpmd_impl.cpp index 3afa6dfc1..cb5dfa68d 100644 --- a/host/lib/usrp/mpmd/mpmd_impl.cpp +++ b/host/lib/usrp/mpmd/mpmd_impl.cpp @@ -85,16 +85,30 @@ namespace { } + /*! Initialize property tree for a single device. + * + * \param tree Property tree reference (to the whole tree) + * \param mb_path Subtree path for this device + * \param mb Reference to the actual device + */ void init_property_tree( uhd::property_tree::sptr tree, fs_path mb_path, mpmd_mboard_impl *mb ) { - if (not tree->exists(fs_path("/name"))) { + /*** Device info ****************************************************/ + if (not tree->exists("/name")) { tree->create<std::string>("/name") .set(mb->device_info.get("name", "Unknown MPM device")) ; } + tree->create<std::string>(mb_path / "name") + .set(mb->device_info.get("type", "UNKNOWN")); + tree->create<std::string>(mb_path / "serial") + .set(mb->device_info.get("serial", "n/a")); + tree->create<std::string>(mb_path / "connection") + .set(mb->device_info.get("connection", "UNKNOWN")); + tree->create<size_t>(mb_path / "link_max_rate").set(1e9 / 8); /*** Clocking *******************************************************/ tree->create<std::string>(mb_path / "clock_source/value") @@ -328,31 +342,59 @@ mpmd_impl::mpmd_impl(const device_addr_t& device_args) : usrp::device3_impl() , _device_args(device_args) { + const device_addrs_t mb_args = separate_device_addr(device_args); + const size_t num_mboards = mb_args.size(); + _mb.reserve(num_mboards); + const bool serialize_init = device_args.has_key("serialize_init"); + const bool skip_init = device_args.has_key("skip_init"); UHD_LOGGER_INFO("MPMD") - << "Initializing device with args: " << device_args.to_string(); + << "Initializing " << num_mboards << " device(s) " + << (serialize_init ? "serially " : "in parallel ") + << "with args: " << device_args.to_string(); + + // First, claim all the devices (so we own them and no one else can claim + // them). + // This can be parallelized as long as uptrs are stored in the right spot; + // they need to be correctly indexed. + for (size_t mb_i = 0; mb_i < num_mboards; ++mb_i) { + UHD_LOG_DEBUG("MPMD", "Claiming mboard " << mb_i); + _mb.push_back(claim_and_make(mb_args[mb_i])); + } - const device_addrs_t mb_args = separate_device_addr(device_args); - _mb.reserve(mb_args.size()); + // Next figure out the number of base xport addresses. This way, we + // can run _mb[*]->init() in parallel on all the _mb. + // This can *not* be parallelized. + std::vector<size_t> base_xport_addr(num_mboards, 2); // Starts at 2 [sic] + for (size_t mb_i = 0; mb_i < num_mboards-1; ++mb_i) { + base_xport_addr[mb_i+1] = base_xport_addr[mb_i] + _mb[mb_i]->num_xbars; + } - // This can theoretically be parallelized, but then we want to make sure - // we're distributing crossbar local addresses in some orderly fashion. - // At the very least, _xbar_local_addr_ctr needs to become atomic. - for (size_t mb_i = 0; mb_i < mb_args.size(); ++mb_i) { - _mb.push_back(setup_mb(mb_i, mb_args[mb_i])); + if (not skip_init) { + // Run the actual device initialization. This can run in parallel. + for (size_t mb_i = 0; mb_i < num_mboards; ++mb_i) { + // Note: This is the only place we do compat number checks. They're + // effectively disabled for skip_init=1 + setup_mb(_mb[mb_i].get(), mb_i, base_xport_addr[mb_i]); + } + } else { + UHD_LOG_DEBUG("MPMD", "Claimed device, but skipped init."); } // Init the prop tree before the blocks get set up -- they might need access // to some of the properties. This also means that the prop tree is pristine // at this point in time. + // This might be parallelized, need to verify the prop tree can handle the + // concurrent accesses. Would shave of milliseconds per device -- probably + // not worth it. for (size_t mb_i = 0; mb_i < mb_args.size(); ++mb_i) { init_property_tree(_tree, fs_path("/mboards") / mb_i, _mb[mb_i].get()); } - if (not device_args.has_key("skip_init")) { - // This might be parallelized. std::tasks would probably be a good way to - // do that if we want to. + if (not skip_init) { + // This can be parallelized, because the blocks of individual mboards + // live on different subtrees. for (size_t mb_i = 0; mb_i < mb_args.size(); ++mb_i) { - setup_rfnoc_blocks(mb_i, mb_args[mb_i]); + setup_rfnoc_blocks(_mb[mb_i].get(), mb_i, mb_args[mb_i]); } // FIXME this section only makes sense for when the time source is external. @@ -364,10 +406,10 @@ mpmd_impl::mpmd_impl(const device_addr_t& device_args) } auto filtered_block_args = device_args; // TODO actually filter - // Blocks will finalize their own setup in this function. They have (and - // might need) full access to the prop tree, the timekeepers, etc. - setup_rpc_blocks(filtered_block_args, - device_args.has_key("serialize_init")); + // Blocks will finalize their own setup in this function. They have + // (and might need) full access to the prop tree, the timekeepers, etc. + // This is already internally parallelized. + setup_rpc_blocks(filtered_block_args, serialize_init); } else { UHD_LOG_INFO("MPMD", "Claimed device without full initialization."); } @@ -381,14 +423,12 @@ mpmd_impl::~mpmd_impl() /***************************************************************************** * Private methods ****************************************************************************/ -mpmd_mboard_impl::uptr mpmd_impl::setup_mb( - const size_t mb_index, +mpmd_mboard_impl::uptr mpmd_impl::claim_and_make( const uhd::device_addr_t& device_args ) { const std::string rpc_addr = device_args.get(xport::MGMT_ADDR_KEY); UHD_LOGGER_DEBUG("MPMD") - << "Initializing mboard " << mb_index - << ". Device args: `" << device_args.to_string() + << "Device args: `" << device_args.to_string() << "'. RPC address: " << rpc_addr ; @@ -398,13 +438,21 @@ mpmd_mboard_impl::uptr mpmd_impl::setup_mb( << device_args.to_string()); throw uhd::runtime_error("Could not determine device RPC address."); } - auto mb = mpmd_mboard_impl::make(device_args, rpc_addr); + return mpmd_mboard_impl::make(device_args, rpc_addr); +} + +void mpmd_impl::setup_mb( + mpmd_mboard_impl *mb, + const size_t mb_index, + const size_t base_xport_addr +) { // Check the compatibility number UHD_LOGGER_TRACE("MPMD") << boost::format( "Checking MPM compat number against ours: %i.%i") % MPM_COMPAT_NUM[0] % MPM_COMPAT_NUM[1]; - const auto compat_num = mb->rpc->request<std::vector<size_t>>("get_mpm_compat_num"); + const auto compat_num = + mb->rpc->request<std::vector<size_t>>("get_mpm_compat_num"); UHD_LOGGER_TRACE("MPMD") << boost::format( "Compat number received: %d.%d") % compat_num[0] % compat_num[1]; @@ -425,34 +473,19 @@ mpmd_mboard_impl::uptr mpmd_impl::setup_mb( throw uhd::runtime_error("MPM compatibility number mismatch."); } - if (device_args.has_key("skip_init")) { - return mb; - } - + UHD_LOG_DEBUG("MPMD", "Initializing mboard " << mb_index); + mb->init(); for (size_t xbar_index = 0; xbar_index < mb->num_xbars; xbar_index++) { - mb->set_xbar_local_addr(xbar_index, allocate_xbar_local_addr()); + mb->set_xbar_local_addr(xbar_index, base_xport_addr + xbar_index); } - - const fs_path mb_path = fs_path("/mboards") / mb_index; - _tree->create<std::string>(mb_path / "name") - .set(mb->device_info.get("type", "UNKNOWN")); - _tree->create<std::string>(mb_path / "serial") - .set(mb->device_info.get("serial", "n/a")); - _tree->create<std::string>(mb_path / "connection") - .set(mb->device_info.get("connection", "remote")); - - _tree->create<size_t>(mb_path / "link_max_rate").set(1e9 / 8); - - return mb; } void mpmd_impl::setup_rfnoc_blocks( + mpmd_mboard_impl* mb, const size_t mb_index, const uhd::device_addr_t& ctrl_xport_args ) { - auto &mb = _mb[mb_index]; - mb->num_xbars = mb->rpc->request<size_t>("get_num_xbars"); - UHD_LOG_TRACE("MPM", + UHD_LOG_TRACE("MPMD", "Mboard " << mb_index << " reports " << mb->num_xbars << " crossbar(s)." ); @@ -523,17 +556,6 @@ void mpmd_impl::setup_rpc_blocks( } } -size_t mpmd_impl::allocate_xbar_local_addr() -{ - const size_t new_local_addr = _xbar_local_addr_ctr++; - if (new_local_addr > MPMD_CROSSBAR_MAX_LADDR) { - throw uhd::runtime_error("Too many crossbars."); - } - - return new_local_addr; -} - - /***************************************************************************** * Find, Factory & Registry ****************************************************************************/ diff --git a/host/lib/usrp/mpmd/mpmd_impl.hpp b/host/lib/usrp/mpmd/mpmd_impl.hpp index 6d7b93b10..e71e83af6 100644 --- a/host/lib/usrp/mpmd/mpmd_impl.hpp +++ b/host/lib/usrp/mpmd/mpmd_impl.hpp @@ -30,7 +30,10 @@ class mpmd_mboard_impl using dev_info = std::map<std::string, std::string>; /*** Structors ***********************************************************/ - /*! + /*! Ctor: Claim device or throw an exception on failure. + * + * Does not initialize the device. + * * \param mb_args Device args that pertain to this motherboard * \param ip_addr RPC client will attempt to connect to this IP address */ @@ -50,6 +53,9 @@ class mpmd_mboard_impl const std::string& addr ); + /*** Init ****************************************************************/ + void init(); + /*** Public attributes ***************************************************/ //! These are the args given by the user, with some filtering/preprocessing uhd::device_addr_t mb_args; @@ -62,9 +68,6 @@ class mpmd_mboard_impl // to be populated at all. std::vector<uhd::device_addr_t> dboard_info; - //! Number of RFNoC crossbars on this device - size_t num_xbars = 0; - /*! Reference to the RPC client for this motherboard * * We store a shared ptr, because we might share it with some of the RFNoC @@ -72,6 +75,8 @@ class mpmd_mboard_impl */ uhd::rpc_client::sptr rpc; + //! Number of RFNoC crossbars on this device + const size_t num_xbars; /************************************************************************* * API @@ -188,20 +193,35 @@ public: /************************************************************************* * Private methods/helpers ************************************************************************/ + /*! Claim a device and create a reference to the mpmd_mboard_impl object. + * + * Does not initialize the device (see setup_mb() for that). + */ + mpmd_mboard_impl::uptr claim_and_make( + const uhd::device_addr_t& dev_args + ); + /*! Initialize a single motherboard * - * - See mpmd_mboard_impl ctor for details - * - Also allocates the local crossbar addresses + * This is where mpmd_mboard_impl::init() is called. + * Also assigns the local crossbar addresses. + * + * \param mb Reference to the mboard class + * \param mb_index Index number of the mboard that's being initialized + * \param device_args Device args + * */ - mpmd_mboard_impl::uptr setup_mb( - const size_t mb_i, - const uhd::device_addr_t& dev_addr + void setup_mb( + mpmd_mboard_impl *mb, + const size_t mb_index, + const size_t base_xport_addr ); //! Setup all RFNoC blocks running on mboard \p mb_i void setup_rfnoc_blocks( - const size_t mb_i, - const uhd::device_addr_t& block_args + mpmd_mboard_impl* mb, + const size_t mb_i, + const uhd::device_addr_t& block_args ); //! Configure all blocks that require access to an RPC client @@ -210,13 +230,6 @@ public: const bool serialize_init ); - /*! Returns a valid local address for a crossbar - * - * \returns Valid local address - * \throws uhd::runtime_error if there are no more local addresses - */ - size_t allocate_xbar_local_addr(); - /*! Return the index of the motherboard given the local address of a * crossbar */ @@ -229,10 +242,6 @@ public: uhd::device_addr_t _device_args; //! Stores a list of mboard references std::vector<mpmd_mboard_impl::uptr> _mb; - - //! A counter for distributing local addresses to crossbars - // No-one touches this except allocate_xbar_local_addr(), gotcha? - size_t _xbar_local_addr_ctr = 2; }; }} /* namespace uhd::mpmd */ diff --git a/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp b/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp index 0ca996d28..59983414a 100644 --- a/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp +++ b/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp @@ -111,12 +111,16 @@ mpmd_mboard_impl::mpmd_mboard_impl( mpmd_impl::MPM_RPC_PORT ), mpmd_impl::MPM_RPC_GET_LAST_ERROR_CMD)) + , num_xbars(rpc->request<size_t>("get_num_xbars")) + // xbar_local_addrs is not yet valid after this! + , xbar_local_addrs(num_xbars, 0xFF) , _xport_mgr(xport::mpmd_xport_mgr::make(mb_args)) { UHD_LOGGER_TRACE("MPMD") << "Initializing mboard, connecting to RPC server address: " << rpc_server_addr << " mboard args: " << mb_args.to_string() + << " number of crossbars: " << num_xbars ; _claimer_task = claim_device_and_make_task(rpc, mb_args); @@ -124,22 +128,16 @@ mpmd_mboard_impl::mpmd_mboard_impl( measure_rpc_latency(rpc, MPMD_MEAS_LATENCY_DURATION); } - // No one else can now claim the device. - if (mb_args_.has_key("skip_init")) { - UHD_LOG_DEBUG("MPMD", "Claimed device, but skipped init."); - return; - } - - init_device(rpc, mb_args); - // RFNoC block clocks are now on. Noc-IDs can be read back. - - auto device_info_dict = rpc->request<dev_info>("get_device_info"); + /// Get device info + const auto device_info_dict = rpc->request<dev_info>("get_device_info"); for (const auto &info_pair : device_info_dict) { device_info[info_pair.first] = info_pair.second; } UHD_LOGGER_TRACE("MPMD") << "MPM reports device info: " << device_info.to_string(); - auto dboards_info = rpc->request<std::vector<dev_info>>("get_dboard_info"); + /// Get dboard info + const auto dboards_info = + rpc->request<std::vector<dev_info>>("get_dboard_info"); UHD_ASSERT_THROW(this->dboard_info.size() == 0); for (const auto &dboard_info_dict : dboards_info) { uhd::device_addr_t this_db_info; @@ -151,11 +149,6 @@ mpmd_mboard_impl::mpmd_mboard_impl( << ": " << this_db_info.to_string(); this->dboard_info.push_back(this_db_info); } - - // Initialize properties - this->num_xbars = rpc->request<size_t>("get_num_xbars"); - // xbar_local_addrs is not yet valid after this! - this->xbar_local_addrs.resize(this->num_xbars, 0xFF); } mpmd_mboard_impl::~mpmd_mboard_impl() @@ -168,6 +161,15 @@ mpmd_mboard_impl::~mpmd_mboard_impl() } /***************************************************************************** + * Init + ****************************************************************************/ +void mpmd_mboard_impl::init() +{ + init_device(rpc, mb_args); + // RFNoC block clocks are now on. Noc-IDs can be read back. +} + +/***************************************************************************** * API ****************************************************************************/ void mpmd_mboard_impl::set_xbar_local_addr( |