FIXME (trb 08/03/2019): Setting thread affinity is not a portable pthread operation (hence the _np suffix); indeed, OSX does not support it. Unfortunately the case on OSX is even more dire -- they seem to want to prevent you from messing with their scheduler at all. The MACH kernel API for doing this is marked "deprecated" and its use is not advised for code that is not tied to a specific OSX vers
| 107 | // As a result of the above, this will, in fact, *not* launch pinned |
| 108 | // threads when the locally-supported pthread API does not support it. |
| 109 | void thread_pool::launch_pinned_threads(size_type num_threads, int PU_offset) |
| 110 | { |
| 111 | |
| 112 | #if defined(LBANN_TOPO_AWARE) |
| 113 | threads_.reserve(num_threads); |
| 114 | m_work_group.reserve(num_threads); |
| 115 | m_thread_id_to_local_id_map.reserve(num_threads); |
| 116 | |
| 117 | hwloc_topology_t topo; |
| 118 | int err; |
| 119 | /* initialize a topology context */ |
| 120 | err = hwloc_topology_init(&topo); |
| 121 | if (err) { |
| 122 | LBANN_ERROR("hwloc_topology_init failed"); |
| 123 | } |
| 124 | /* build the topology created and configured above */ |
| 125 | err = hwloc_topology_load(topo); |
| 126 | if (err) { |
| 127 | LBANN_ERROR("hwloc_topology_load failed"); |
| 128 | } |
| 129 | // Get the number of PUs per core |
| 130 | // hwloc_obj_t core = hwloc_get_obj_by_type(topo, HWLOC_OBJ_CORE, 0); |
| 131 | m_threads_offset = PU_offset; |
| 132 | |
| 133 | check_hwloc_api_version(); |
| 134 | // hwloc_cpuset_t current_cpuset = get_local_cpuset_for_current_thread(topo); |
| 135 | int i; |
| 136 | // hwloc_obj_t obj; |
| 137 | // Try to launch each worker thread and pin it to a single core |
| 138 | try { |
| 139 | hwloc_cpuset_t allocated_cpuset = get_local_cpuset_for_current_thread(topo); |
| 140 | hwloc_cpuset_t excluded_cpuset = hwloc_bitmap_alloc(); |
| 141 | // int cpuset_idx = 0; |
| 142 | int skipped_indices = 0; |
| 143 | // Skip PUs to match the thread offset |
| 144 | hwloc_bitmap_foreach_begin(i, allocated_cpuset) |
| 145 | { |
| 146 | if (skipped_indices < m_threads_offset) { |
| 147 | skipped_indices++; |
| 148 | hwloc_bitmap_set(excluded_cpuset, i); |
| 149 | } |
| 150 | } |
| 151 | hwloc_bitmap_foreach_end(); |
| 152 | |
| 153 | hwloc_cpuset_t iot_cpuset = hwloc_bitmap_dup(allocated_cpuset); |
| 154 | hwloc_bitmap_andnot(iot_cpuset, iot_cpuset, excluded_cpuset); |
| 155 | if (hwloc_bitmap_iszero(iot_cpuset)) { |
| 156 | LBANN_WARNING( |
| 157 | "Insufficient number of allocated cores to respect I/O CPU offset"); |
| 158 | hwloc_bitmap_free(iot_cpuset); |
| 159 | // Reset the cpuset back to all of the allowed cores |
| 160 | iot_cpuset = hwloc_bitmap_dup(allocated_cpuset); |
| 161 | } |
| 162 | |
| 163 | for (size_type cnt = 0; cnt < num_threads; ++cnt) { |
| 164 | hwloc_cpuset_t ht_cpuset = hwloc_bitmap_dup(iot_cpuset); |
| 165 | hwloc_topology_t ht_topo; |
| 166 | err = hwloc_topology_dup(&ht_topo, topo); |
no test coverage detected