mask_type decode_mapping_numanode(hwloc_topology const& t, mapping_type& m, std::size_t size, std::size_t thread_index, error_code& ec) { bounds_type b = extract_bounds(m[0], size, ec); if (ec) return 0; std::size_t index = std::size_t(-1); if (m[1].type_ == spec_type::unknown && m[2].type_ == spec_type::unknown && b.size() > 1) { index = thread_index; } mask_type mask = 0; std::size_t node_index = 0; for (bounds_type::const_iterator it = b.begin(); it != b.end(); ++it, ++node_index) { if (index == std::size_t(-1) || node_index == index) mask |= t.init_numa_node_affinity_mask_from_numa_node(*it); } std::size_t node_base_index = *b.begin(); if (thread_index != std::size_t(-1) && b.size() > 1) node_base_index += thread_index; std::size_t base_index = 0; for (std::size_t i = 0; i != node_base_index; ++i) base_index += t.get_number_of_numa_node_cores(i); return decode_mapping0_unknown(t, m, size, mask, base_index, thread_index, ec); }
mask_type decode_mapping_core(hwloc_topology const& t, mapping_type& m, std::size_t size, mask_type mask, std::size_t core_base_index, std::size_t thread_index, error_code& ec) { bounds_type b = extract_bounds(m[1], size, ec); if (ec) return 0; // We have to account for the thread index at this level if there are // no specifications related to processing units. std::size_t index = std::size_t(-1); if (m[2].type_ == spec_type::unknown && b.size() > 1) index = thread_index; mask_type core_mask = 0; std::size_t core_index = 0; for (bounds_type::const_iterator it = b.begin(); it != b.end(); ++it, ++core_index) { if (index == std::size_t(-1) || core_index == index) { core_mask |= t.init_core_affinity_mask_from_core( *it+core_base_index, 0); } } core_base_index += *b.begin(); if (thread_index != std::size_t(-1) && b.size() > 1) core_base_index += thread_index; std::size_t base_index = 0; for (std::size_t i = 0; i != core_base_index; ++i) base_index += t.get_number_of_core_pus(i); return decode_mapping1_unknown(t, m, size, mask & core_mask, base_index, thread_index, ec); }
std::vector<mask_info> extract_core_masks(hwloc_topology const& t, spec_type const& s, std::size_t socket, mask_cref_type socket_mask, error_code& ec) { std::vector<mask_info> masks; switch (s.type_) { case spec_type::core: { std::size_t base = 0; std::size_t num_cores = 0; if (socket != std::size_t(-1)) { for (std::size_t i = 0; i != socket; ++i) base += t.get_number_of_socket_cores(i); num_cores = t.get_number_of_socket_cores(socket); } else { num_cores = t.get_number_of_cores(); } bounds_type bounds = extract_bounds(s, num_cores, ec); if (ec) break; for (std::int64_t index : bounds) { mask_type mask = t.init_core_affinity_mask_from_core(index + base); masks.push_back(util::make_tuple(index, mask & socket_mask)); } } break; case spec_type::unknown: { mask_type mask = extract_machine_mask(t, ec); masks.push_back(util::make_tuple( std::size_t(-1), mask & socket_mask )); } break; default: HPX_THROWS_IF(ec, bad_parameter, "extract_core_mask", boost::str(boost::format( "unexpected specification type %s" ) % spec_type::type_name(s.type_))); break; } return masks; }
std::vector<mask_info> extract_socket_or_numanode_masks(hwloc_topology const& t, spec_type const& s, error_code& ec) { switch (s.type_) { case spec_type::socket: // requested top level is a socket { std::size_t num_sockets = t.get_number_of_sockets(); return extract_socket_masks( t, extract_bounds(s, num_sockets, ec)); } case spec_type::numanode: // requested top level is a NUMA node { std::size_t num_numanodes = t.get_number_of_numa_nodes(); return extract_numanode_masks( t, extract_bounds(s, num_numanodes, ec)); } case spec_type::unknown: { std::vector<mask_info> masks; masks.push_back(util::make_tuple( std::size_t(-1), extract_machine_mask(t, ec) )); return masks; } default: HPX_THROWS_IF(ec, bad_parameter, "extract_socket_or_numanode_mask", boost::str(boost::format( "unexpected specification type %s" ) % spec_type::type_name(s.type_))); break; } return std::vector<mask_info>(); }
/////////////////////////////////////////////////////////////////////////// // sanity checks void mappings_sanity_checks(mapping_type& m, std::size_t size, bounds_type const& b, error_code& ec) { if (m.size() != 3) { HPX_THROWS_IF(ec, bad_parameter, "decode_mapping", "bad size of mappings specification array"); return; } std::size_t count_ranges = 0; for (std::size_t i = 0; i != 3; ++i) { bounds_type bounds = extract_bounds(m[i], size, ec); if (ec) return; if (bounds.size() > 1) { ++count_ranges; // FIXME: replace this with proper counting of processing units specified by // the affinity desc // if (b.begin() != b.end()) { // // threads have bounds ranges as well // if (b.end() - b.begin() > bounds.second - bounds.first) { // HPX_THROWS_IF(ec, bad_parameter, "decode_mapping", // boost::str(boost::format("the thread index range " // "is larger than the index range specified for " // "the %s node") % spec_type::type_name( // m[i].type_))); // return; // } // } } } if (count_ranges > 1) { HPX_THROWS_IF(ec, bad_parameter, "decode_mapping", "index ranges can be specified only for one node type " "(socket/numanode, core, or pu)"); return; } if (&ec != &throws) ec = make_success_code(); }
mask_type decode_mapping_pu(hwloc_topology const& t, mapping_type& m, std::size_t size, mask_type mask, std::size_t pu_base_index, std::size_t thread_index, error_code& ec) { bounds_type b = extract_bounds(m[2], size, ec); if (ec) return 0; std::size_t index = std::size_t(-1); if (b.size() > 1) index = thread_index; mask_type pu_mask = 0; std::size_t pu_index = 0; for (bounds_type::const_iterator it = b.begin(); it != b.end(); ++it, ++pu_index) { if (index == std::size_t(-1) || pu_index == index) pu_mask |= t.init_thread_affinity_mask(*it+pu_base_index); } return mask & pu_mask; }
void decode_mappings(full_mapping_type& m, std::vector<mask_type>& affinities, error_code& ec) { // We need to instantiate a new topology object as the runtime has not // been initialized yet hwloc_topology t; // repeat for each of the threads in the affinity specification std::size_t size = affinities.size(); bounds_type b = extract_bounds(m.first, size, ec); if (ec) return; mappings_sanity_checks(m.second, size, b, ec); if (ec) return; // we need to keep track of the thread index if the bounds are different // (i.e. we need to bind more than one thread) std::size_t index = (b.begin() != b.end()) ? 0 : std::size_t(-1); for (bounds_type::const_iterator it = b.begin(); it != b.end(); ++it) { mask_type mask = decode_mapping(t, m.second, affinities, index, ec); if (ec) return; // set each thread affinity only once BOOST_ASSERT(*it < static_cast<boost::int64_t>(affinities.size())); if (0 != affinities[*it]) { HPX_THROWS_IF(ec, bad_parameter, "decode_mapping", boost::str(boost::format("affinity mask for thread %1% has " "already been set") % *it)); return; } // set result affinities[*it] = mask; if (index != std::size_t(-1)) ++index; } }
std::vector<mask_info> extract_pu_masks(hwloc_topology const& t, spec_type const& s, std::size_t socket, std::size_t core, mask_cref_type core_mask, error_code& ec) { std::vector<mask_info> masks; switch (s.type_) { case spec_type::pu: { std::size_t num_pus = 0; std::size_t socket_base = 0; if (std::size_t(-1) != socket) { // core number is relative to socket for (std::size_t i = 0; i != socket; ++i) socket_base += t.get_number_of_socket_cores(i); } if (std::size_t(-1) != core) { num_pus = t.get_number_of_core_pus(core); } else { num_pus = t.get_number_of_pus(); } bounds_type bounds = extract_bounds(s, num_pus, ec); if (ec) break; std::size_t num_cores = t.get_number_of_cores(); for (std::int64_t index : bounds) { std::size_t base_core = socket_base; if (std::size_t(-1) != core) { base_core += core; } else { // find core the given pu belongs to std::size_t base = 0; for (/**/; base_core < num_cores; ++base_core) { std::size_t num_core_pus = t.get_number_of_core_pus(base_core); if (base + num_core_pus > std::size_t(index)) break; base += num_core_pus; } } mask_type mask = t.init_thread_affinity_mask(base_core, index); masks.push_back(util::make_tuple(index, mask & core_mask)); } } break; case spec_type::unknown: { mask_type mask = extract_machine_mask(t, ec); masks.push_back(util::make_tuple( std::size_t(-1), mask & core_mask )); } break; default: HPX_THROWS_IF(ec, bad_parameter, "extract_pu_mask", boost::str(boost::format( "unexpected specification type %s" ) % spec_type::type_name(s.type_))); break; } return masks; }